Version 1.19.0-dev.6.0
Merge 1196cf5276662af7816fff5bdd1a0e553013d1f6 into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 35da026..03f3ecb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -30,7 +30,7 @@
* Breaking change - infer generic type arguments from the
constructor invocation arguments
- (SDK issue [25220](https://github.com/dart-lang/sdk/issues/25220))
+ (SDK issue [25220](https://github.com/dart-lang/sdk/issues/25220)).
```dart
var map = new Map<String, String>();
@@ -40,7 +40,7 @@
```
* Breaking change - infer local function return type
- (SDK issue [26414](https://github.com/dart-lang/sdk/issues/26414))
+ (SDK issue [26414](https://github.com/dart-lang/sdk/issues/26414)).
```dart
void main() {
@@ -52,7 +52,7 @@
```
* Breaking change - allow type promotion from a generic type parameter
- (SDK issue [26414](https://github.com/dart-lang/sdk/issues/26965))
+ (SDK issue [26414](https://github.com/dart-lang/sdk/issues/26965)).
```dart
void fn/*<T>*/(/*=T*/ object) {
@@ -64,6 +64,31 @@
}
```
+* Breaking change - smarter inference for Future.then
+ (SDK issue [25944](https://github.com/dart-lang/sdk/issues/25944)).
+ Previous workarounds that use async/await or `.then/*<Future<SomeType>>*/`
+ should no longer be necessary.
+
+ ```dart
+ // This will now infer correctly.
+ Future<List<int>> t2 = f.then((_) => [3]);
+ // This infers too.
+ Future<int> t2 = f.then((_) => new Future.value(42));
+ ```
+
+* Breaking change - smarter inference for async functions
+ (SDK issue [25322](https://github.com/dart-lang/sdk/issues/25322)).
+
+ ```dart
+ void test() async {
+ List<int> x = await [4]; // was previously inferred
+ List<int> y = await new Future.value([4]); // now inferred too
+ }
+ ```
+
+* Breaking change - sideways casts are no longer allowed
+ (SDK issue [26120](https://github.com/dart-lang/sdk/issues/26120)).
+
### Dart VM
* The dependency on BoringSSL has been rolled forward. Going forward, builds
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 3b41a24..307ed65 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -40,6 +40,7 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/summary/pub_summary.dart';
import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/src/util/glob.dart';
@@ -1544,6 +1545,7 @@
class AnalysisServerOptions {
bool enableIncrementalResolutionApi = false;
bool enableIncrementalResolutionValidation = false;
+ bool enablePubSummaryManager = false;
bool finerGrainedInvalidation = false;
bool noErrorNotification = false;
bool noIndex = false;
@@ -1603,8 +1605,19 @@
_createSourceFactory(context, options, disposition, folder);
context.analysisOptions = options;
- // TODO(scheglov) use linked bundles
-// analysisServer.pubSummaryManager.getLinkedBundles(context);
+ if (analysisServer.options.enablePubSummaryManager) {
+ List<LinkedPubPackage> linkedBundles =
+ analysisServer.pubSummaryManager.getLinkedBundles(context);
+ if (linkedBundles.isNotEmpty) {
+ SummaryDataStore store = new SummaryDataStore([]);
+ for (LinkedPubPackage package in linkedBundles) {
+ store.addBundle(null, package.unlinked);
+ store.addBundle(null, package.linked);
+ }
+ context.resultProvider =
+ new InputPackagesResultProvider(context, store);
+ }
+ }
analysisServer._onContextsChangedController
.add(new ContextsChangedEvent(added: [context]));
diff --git a/pkg/analysis_server/lib/src/search/type_hierarchy.dart b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
index 29af16e..fad37c4 100644
--- a/pkg/analysis_server/lib/src/search/type_hierarchy.dart
+++ b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
@@ -76,42 +76,41 @@
}
Future _createSubclasses(
- TypeHierarchyItem item, int itemId, InterfaceType type) {
- var future = getDirectSubClasses(_searchEngine, type.element);
- return future.then((Set<ClassElement> subElements) {
- List<int> subItemIds = <int>[];
- for (ClassElement subElement in subElements) {
- // check for recursion
- TypeHierarchyItem subItem = _elementItemMap[subElement];
- if (subItem != null) {
- int id = _items.indexOf(subItem);
- item.subclasses.add(id);
- continue;
- }
- // create a subclass item
- ExecutableElement subMemberElement = _findMemberElement(subElement);
- subItem = new TypeHierarchyItem(convertElement(subElement),
- memberElement: subMemberElement != null
- ? convertElement(subMemberElement)
- : null,
- superclass: itemId);
- int subItemId = _items.length;
- // remember
- _elementItemMap[subElement] = subItem;
- _items.add(subItem);
- _itemClassElements.add(subElement);
- // add to hierarchy
- item.subclasses.add(subItemId);
- subItemIds.add(subItemId);
+ TypeHierarchyItem item, int itemId, InterfaceType type) async {
+ Set<ClassElement> subElements =
+ await getDirectSubClasses(_searchEngine, type.element);
+ List<int> subItemIds = <int>[];
+ for (ClassElement subElement in subElements) {
+ // check for recursion
+ TypeHierarchyItem subItem = _elementItemMap[subElement];
+ if (subItem != null) {
+ int id = _items.indexOf(subItem);
+ item.subclasses.add(id);
+ continue;
}
- // compute subclasses of subclasses
- return Future.forEach(subItemIds, (int subItemId) {
- TypeHierarchyItem subItem = _items[subItemId];
- ClassElement subItemElement = _itemClassElements[subItemId];
- InterfaceType subType = subItemElement.type;
- return _createSubclasses(subItem, subItemId, subType);
- });
- });
+ // create a subclass item
+ ExecutableElement subMemberElement = _findMemberElement(subElement);
+ subItem = new TypeHierarchyItem(convertElement(subElement),
+ memberElement: subMemberElement != null
+ ? convertElement(subMemberElement)
+ : null,
+ superclass: itemId);
+ int subItemId = _items.length;
+ // remember
+ _elementItemMap[subElement] = subItem;
+ _items.add(subItem);
+ _itemClassElements.add(subElement);
+ // add to hierarchy
+ item.subclasses.add(subItemId);
+ subItemIds.add(subItemId);
+ }
+ // compute subclasses of subclasses
+ for (int subItemId in subItemIds) {
+ TypeHierarchyItem subItem = _items[subItemId];
+ ClassElement subItemElement = _itemClassElements[subItemId];
+ InterfaceType subType = subItemElement.type;
+ await _createSubclasses(subItem, subItemId, subType);
+ }
}
int _createSuperItem(InterfaceType type) {
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index b6c878f..28deb09 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -20,11 +20,10 @@
import 'package:analyzer/instrumentation/file_instrumentation.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/plugin/resolver_provider.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/incremental_logger.dart';
-import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:args/args.dart';
import 'package:linter/src/plugin/linter_plugin.dart';
import 'package:plugin/manager.dart';
@@ -244,6 +243,11 @@
"incremental-resolution-validation";
/**
+ * The name of the option used to enable using pub summary manager.
+ */
+ static const String ENABLE_PUB_SUMMARY_MANAGER = 'enable-pub-summary-manager';
+
+ /**
* The name of the option used to enable fined grained invalidation.
*/
static const String FINER_GRAINED_INVALIDATION = 'finer-grained-invalidation';
@@ -379,6 +383,8 @@
results[ENABLE_INCREMENTAL_RESOLUTION_API];
analysisServerOptions.enableIncrementalResolutionValidation =
results[INCREMENTAL_RESOLUTION_VALIDATION];
+ analysisServerOptions.enablePubSummaryManager =
+ results[ENABLE_PUB_SUMMARY_MANAGER];
analysisServerOptions.finerGrainedInvalidation =
results[FINER_GRAINED_INVALIDATION];
analysisServerOptions.noErrorNotification = results[NO_ERROR_NOTIFICATION];
@@ -405,18 +411,22 @@
ExtensionManager manager = new ExtensionManager();
manager.processPlugins(plugins);
- JavaFile defaultSdkDirectory;
+ String defaultSdkPath;
if (results[SDK_OPTION] != null) {
- defaultSdkDirectory = new JavaFile(results[SDK_OPTION]);
+ defaultSdkPath = results[SDK_OPTION];
} else {
// No path to the SDK was provided.
// Use DirectoryBasedDartSdk.defaultSdkDirectory, which will make a guess.
- defaultSdkDirectory = DirectoryBasedDartSdk.defaultSdkDirectory;
+ defaultSdkPath = FolderBasedDartSdk
+ .defaultSdkDirectory(PhysicalResourceProvider.INSTANCE)
+ .path;
}
bool useSummaries = analysisServerOptions.fileReadMode == 'as-is';
SdkCreator defaultSdkCreator = (AnalysisOptions options) {
- DirectoryBasedDartSdk sdk =
- new DirectoryBasedDartSdk(defaultSdkDirectory);
+ PhysicalResourceProvider resourceProvider =
+ PhysicalResourceProvider.INSTANCE;
+ FolderBasedDartSdk sdk = new FolderBasedDartSdk(resourceProvider,
+ FolderBasedDartSdk.defaultSdkDirectory(resourceProvider));
sdk.analysisOptions = options;
sdk.useSummary = useSummaries;
return sdk;
@@ -424,7 +434,7 @@
// TODO(brianwilkerson) It would be nice to avoid creating an SDK that
// cannot be re-used, but the SDK is needed to create a package map provider
// in the case where we need to run `pub` in order to get the package map.
- DirectoryBasedDartSdk defaultSdk = defaultSdkCreator(null);
+ DartSdk defaultSdk = defaultSdkCreator(null);
//
// Initialize the instrumentation service.
//
@@ -448,8 +458,7 @@
//
socketServer = new SocketServer(
analysisServerOptions,
- new DartSdkManager(defaultSdkDirectory.getAbsolutePath(), useSummaries,
- defaultSdkCreator),
+ new DartSdkManager(defaultSdkPath, useSummaries, defaultSdkCreator),
defaultSdk,
service,
serverPlugin,
@@ -532,6 +541,10 @@
help: "enable validation of incremental resolution results (slow)",
defaultsTo: false,
negatable: false);
+ parser.addFlag(ENABLE_PUB_SUMMARY_MANAGER,
+ help: "enable using summaries for pub cache packages",
+ defaultsTo: false,
+ negatable: false);
parser.addFlag(FINER_GRAINED_INVALIDATION,
help: "enable finer grained invalidation",
defaultsTo: false,
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 20ca00f..e25f0b4 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -80,6 +80,7 @@
errorCode ==
CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT ||
errorCode == CompileTimeErrorCode.URI_DOES_NOT_EXIST ||
+ errorCode == CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED ||
errorCode == HintCode.CAN_BE_NULL_AFTER_NULL_AWARE ||
errorCode == HintCode.DEAD_CODE ||
errorCode == HintCode.DIVISION_OPTIMIZATION ||
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 27f33c8..17c7822 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -190,6 +190,9 @@
_addFix_createPartUri();
_addFix_replaceImportUri();
}
+ if (errorCode == CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED) {
+ _addFix_replaceImportUri();
+ }
if (errorCode == HintCode.CAN_BE_NULL_AFTER_NULL_AWARE) {
_addFix_canBeNullAfterNullAware();
}
diff --git a/pkg/analysis_server/lib/src/services/correction/organize_directives.dart b/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
index 0d35566..56d4bb0 100644
--- a/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
+++ b/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
@@ -47,7 +47,9 @@
bool _isUnresolvedUri(UriBasedDirective directive) {
for (AnalysisError error in errors) {
- if (error.errorCode == CompileTimeErrorCode.URI_DOES_NOT_EXIST &&
+ ErrorCode errorCode = error.errorCode;
+ if ((errorCode == CompileTimeErrorCode.URI_DOES_NOT_EXIST ||
+ errorCode == CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED) &&
directive.uri.offset == error.offset) {
return true;
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index 106684a..88e0d86 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -70,7 +70,7 @@
implements ExtractMethodRefactoring {
static const ERROR_EXITS =
'Selected statements contain a return statement, but not all possible '
- 'execuion flows exit. Semantics may not be preserved.';
+ 'execution flows exit. Semantics may not be preserved.';
final SearchEngine searchEngine;
final CompilationUnit unit;
diff --git a/pkg/analysis_server/lib/src/services/search/hierarchy.dart b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
index b6e1c9e..1822f1b 100644
--- a/pkg/analysis_server/lib/src/services/search/hierarchy.dart
+++ b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
@@ -58,15 +58,9 @@
* Returns a [Set] with direct subclasses of [seed].
*/
Future<Set<ClassElement>> getDirectSubClasses(
- SearchEngine searchEngine, ClassElement seed) {
- return searchEngine.searchSubtypes(seed).then((List<SearchMatch> matches) {
- Set<ClassElement> subClasses = new HashSet<ClassElement>();
- for (SearchMatch match in matches) {
- ClassElement subClass = match.element;
- subClasses.add(subClass);
- }
- return subClasses;
- });
+ SearchEngine searchEngine, ClassElement seed) async {
+ List<SearchMatch> matches = await searchEngine.searchSubtypes(seed);
+ return matches.map((match) => match.element).toSet();
}
/**
@@ -74,7 +68,7 @@
* their subclasses.
*/
Future<Set<ClassMemberElement>> getHierarchyMembers(
- SearchEngine searchEngine, ClassMemberElement member) {
+ SearchEngine searchEngine, ClassMemberElement member) async {
Set<ClassMemberElement> result = new HashSet<ClassMemberElement>();
// static elements
if (member.isStatic || member is ConstructorElement) {
@@ -84,7 +78,6 @@
// method, field, etc
String name = member.displayName;
ClassElement memberClass = member.enclosingElement;
- List<Future> futures = <Future>[];
Set<ClassElement> searchClasses = getSuperClasses(memberClass);
searchClasses.add(memberClass);
for (ClassElement superClass in searchClasses) {
@@ -93,23 +86,19 @@
continue;
}
// check all sub- classes
- var subClassFuture = getSubClasses(searchEngine, superClass);
- var membersFuture = subClassFuture.then((Set<ClassElement> subClasses) {
- subClasses.add(superClass);
- for (ClassElement subClass in subClasses) {
- List<Element> subClassMembers = getChildren(subClass, name);
- for (Element member in subClassMembers) {
- if (member is ClassMemberElement) {
- result.add(member);
- }
+ Set<ClassElement> subClasses =
+ await getSubClasses(searchEngine, superClass);
+ subClasses.add(superClass);
+ for (ClassElement subClass in subClasses) {
+ List<Element> subClassMembers = getChildren(subClass, name);
+ for (Element member in subClassMembers) {
+ if (member is ClassMemberElement) {
+ result.add(member);
}
}
- });
- futures.add(membersFuture);
+ }
}
- return Future.wait(futures).then((_) {
- return result;
- });
+ return result;
}
/**
@@ -133,15 +122,9 @@
* Returns a [Set] with all direct and indirect subclasses of [seed].
*/
Future<Set<ClassElement>> getSubClasses(
- SearchEngine searchEngine, ClassElement seed) {
- return searchEngine.searchAllSubtypes(seed).then((List<SearchMatch> matches) {
- Set<ClassElement> ancestors = new HashSet<ClassElement>();
- for (SearchMatch match in matches) {
- ClassElement ancestor = match.element;
- ancestors.add(ancestor);
- }
- return ancestors;
- });
+ SearchEngine searchEngine, ClassElement seed) async {
+ List<SearchMatch> matches = await searchEngine.searchAllSubtypes(seed);
+ return matches.map((match) => match.element).toSet();
}
/**
@@ -167,8 +150,8 @@
}
}
// append interfaces
- for (InterfaceType intf in current.interfaces) {
- queue.add(intf.element);
+ for (InterfaceType interface in current.interfaces) {
+ queue.add(interface.element);
}
}
// we don't need "seed" itself
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index bce9dc8..887e1b7 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -14,7 +14,6 @@
import 'package:analyzer/plugin/resolver_provider.dart';
import 'package:analyzer/source/pub_package_map_provider.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:plugin/plugin.dart';
/**
@@ -31,7 +30,7 @@
*/
final DartSdkManager sdkManager;
- final DirectoryBasedDartSdk defaultSdk;
+ final DartSdk defaultSdk;
final InstrumentationService instrumentationService;
final ServerPlugin serverPlugin;
final ResolverProvider fileResolverProvider;
diff --git a/pkg/analysis_server/lib/src/source/caching_pub_package_map_provider.dart b/pkg/analysis_server/lib/src/source/caching_pub_package_map_provider.dart
index 1997bff..48abf8e 100644
--- a/pkg/analysis_server/lib/src/source/caching_pub_package_map_provider.dart
+++ b/pkg/analysis_server/lib/src/source/caching_pub_package_map_provider.dart
@@ -11,8 +11,8 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/source/package_map_provider.dart';
import 'package:analyzer/source/pub_package_map_provider.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
/**
@@ -80,7 +80,7 @@
* [RunPubList] and [WriteFile] implementations may be injected for testing
*/
CachingPubPackageMapProvider(
- ResourceProvider resourceProvider, DirectoryBasedDartSdk sdk,
+ ResourceProvider resourceProvider, FolderBasedDartSdk sdk,
[RunPubList runPubList, this._writeFile])
: super(resourceProvider, sdk, runPubList) {
if (_writeFile == null) {
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 11cccff..d3a8cdf 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -39,7 +39,6 @@
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
@@ -1453,7 +1452,7 @@
DartSdk sdk = context?.sourceFactory?.dartSdk;
writeOptions(buffer, sdk?.context?.analysisOptions,
writeAdditionalOptions: (StringBuffer buffer) {
- if (sdk is DirectoryBasedDartSdk) {
+ if (sdk is FolderBasedDartSdk) {
_writeOption(buffer, 'Use summaries', sdk.useSummary);
}
});
@@ -1490,9 +1489,9 @@
DartSdk sdk = resolver.dartSdk;
buffer.write(' (sdk = ');
buffer.write(sdk.runtimeType);
- if (sdk is DirectoryBasedDartSdk) {
+ if (sdk is FolderBasedDartSdk) {
buffer.write(' (path = ');
- buffer.write(sdk.directory.getAbsolutePath());
+ buffer.write(sdk.directory.path);
buffer.write(')');
} else if (sdk is EmbedderSdk) {
buffer.write(' (map = ');
diff --git a/pkg/analysis_server/test/edit/refactoring_test.dart b/pkg/analysis_server/test/edit/refactoring_test.dart
index 7c9223a..eaaadc8 100644
--- a/pkg/analysis_server/test/edit/refactoring_test.dart
+++ b/pkg/analysis_server/test/edit/refactoring_test.dart
@@ -659,13 +659,11 @@
return _sendExtractRequest();
}
- Future<ExtractMethodFeedback> _computeInitialFeedback() {
- return waitForTasksFinished().then((_) {
- return _sendExtractRequest();
- }).then((Response response) {
- var result = new EditGetRefactoringResult.fromResponse(response);
- return result.feedback;
- });
+ Future<ExtractMethodFeedback> _computeInitialFeedback() async {
+ await waitForTasksFinished();
+ Response response = await _sendExtractRequest();
+ var result = new EditGetRefactoringResult.fromResponse(response);
+ return result.feedback;
}
Future _prepareOptions() {
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index 1fbdd7e..20b8891 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -36,12 +36,10 @@
*
* The version number of the analysis server.
*/
- Future<ServerGetVersionResult> sendServerGetVersion() {
- return server.send("server.getVersion", null)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new ServerGetVersionResult.fromJson(decoder, 'result', result);
- });
+ Future<ServerGetVersionResult> sendServerGetVersion() async {
+ var result = await server.send("server.getVersion", null);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new ServerGetVersionResult.fromJson(decoder, 'result', result);
}
/**
@@ -51,12 +49,10 @@
* responded to. No further responses or notifications will be sent after the
* response to this request has been sent.
*/
- Future sendServerShutdown() {
- return server.send("server.shutdown", null)
- .then((result) {
- expect(result, isNull);
- return null;
- });
+ Future sendServerShutdown() async {
+ var result = await server.send("server.shutdown", null);
+ expect(result, isNull);
+ return null;
}
/**
@@ -73,13 +69,11 @@
*
* A list of the services being subscribed to.
*/
- Future sendServerSetSubscriptions(List<ServerService> subscriptions) {
+ Future sendServerSetSubscriptions(List<ServerService> subscriptions) async {
var params = new ServerSetSubscriptionsParams(subscriptions).toJson();
- return server.send("server.setSubscriptions", params)
- .then((result) {
- expect(result, isNull);
- return null;
- });
+ var result = await server.send("server.setSubscriptions", params);
+ expect(result, isNull);
+ return null;
}
/**
@@ -198,13 +192,11 @@
*
* The errors associated with the file.
*/
- Future<AnalysisGetErrorsResult> sendAnalysisGetErrors(String file) {
+ Future<AnalysisGetErrorsResult> sendAnalysisGetErrors(String file) async {
var params = new AnalysisGetErrorsParams(file).toJson();
- return server.send("analysis.getErrors", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new AnalysisGetErrorsResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("analysis.getErrors", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new AnalysisGetErrorsResult.fromJson(decoder, 'result', result);
}
/**
@@ -232,13 +224,11 @@
* contexts in conflicting ways (such as a part that is included in
* multiple libraries).
*/
- Future<AnalysisGetHoverResult> sendAnalysisGetHover(String file, int offset) {
+ Future<AnalysisGetHoverResult> sendAnalysisGetHover(String file, int offset) async {
var params = new AnalysisGetHoverParams(file, offset).toJson();
- return server.send("analysis.getHover", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new AnalysisGetHoverResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("analysis.getHover", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new AnalysisGetHoverResult.fromJson(decoder, 'result', result);
}
/**
@@ -267,13 +257,11 @@
* reachable from a given file, clients can check for its presence in the
* resulting key set.
*/
- Future<AnalysisGetReachableSourcesResult> sendAnalysisGetReachableSources(String file) {
+ Future<AnalysisGetReachableSourcesResult> sendAnalysisGetReachableSources(String file) async {
var params = new AnalysisGetReachableSourcesParams(file).toJson();
- return server.send("analysis.getReachableSources", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new AnalysisGetReachableSourcesResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("analysis.getReachableSources", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new AnalysisGetReachableSourcesResult.fromJson(decoder, 'result', result);
}
/**
@@ -296,12 +284,10 @@
* names to source directories for use in client-side package URI
* resolution.
*/
- Future<AnalysisGetLibraryDependenciesResult> sendAnalysisGetLibraryDependencies() {
- return server.send("analysis.getLibraryDependencies", null)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new AnalysisGetLibraryDependenciesResult.fromJson(decoder, 'result', result);
- });
+ Future<AnalysisGetLibraryDependenciesResult> sendAnalysisGetLibraryDependencies() async {
+ var result = await server.send("analysis.getLibraryDependencies", null);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new AnalysisGetLibraryDependenciesResult.fromJson(decoder, 'result', result);
}
/**
@@ -358,13 +344,11 @@
* A list of the navigation regions within the requested region of the
* file.
*/
- Future<AnalysisGetNavigationResult> sendAnalysisGetNavigation(String file, int offset, int length) {
+ Future<AnalysisGetNavigationResult> sendAnalysisGetNavigation(String file, int offset, int length) async {
var params = new AnalysisGetNavigationParams(file, offset, length).toJson();
- return server.send("analysis.getNavigation", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new AnalysisGetNavigationResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("analysis.getNavigation", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new AnalysisGetNavigationResult.fromJson(decoder, 'result', result);
}
/**
@@ -385,13 +369,11 @@
*
* A list of the analysis roots that are to be re-analyzed.
*/
- Future sendAnalysisReanalyze({List<String> roots}) {
+ Future sendAnalysisReanalyze({List<String> roots}) async {
var params = new AnalysisReanalyzeParams(roots: roots).toJson();
- return server.send("analysis.reanalyze", params)
- .then((result) {
- expect(result, isNull);
- return null;
- });
+ var result = await server.send("analysis.reanalyze", params);
+ expect(result, isNull);
+ return null;
}
/**
@@ -453,13 +435,11 @@
* If this field is absent, or the empty map is specified, that indicates
* that the normal pubspec.yaml mechanism should always be used.
*/
- Future sendAnalysisSetAnalysisRoots(List<String> included, List<String> excluded, {Map<String, String> packageRoots}) {
+ Future sendAnalysisSetAnalysisRoots(List<String> included, List<String> excluded, {Map<String, String> packageRoots}) async {
var params = new AnalysisSetAnalysisRootsParams(included, excluded, packageRoots: packageRoots).toJson();
- return server.send("analysis.setAnalysisRoots", params)
- .then((result) {
- expect(result, isNull);
- return null;
- });
+ var result = await server.send("analysis.setAnalysisRoots", params);
+ expect(result, isNull);
+ return null;
}
/**
@@ -477,13 +457,11 @@
*
* A list of the services being subscribed to.
*/
- Future sendAnalysisSetGeneralSubscriptions(List<GeneralAnalysisService> subscriptions) {
+ Future sendAnalysisSetGeneralSubscriptions(List<GeneralAnalysisService> subscriptions) async {
var params = new AnalysisSetGeneralSubscriptionsParams(subscriptions).toJson();
- return server.send("analysis.setGeneralSubscriptions", params)
- .then((result) {
- expect(result, isNull);
- return null;
- });
+ var result = await server.send("analysis.setGeneralSubscriptions", params);
+ expect(result, isNull);
+ return null;
}
/**
@@ -511,13 +489,11 @@
*
* The files that are to be a priority for analysis.
*/
- Future sendAnalysisSetPriorityFiles(List<String> files) {
+ Future sendAnalysisSetPriorityFiles(List<String> files) async {
var params = new AnalysisSetPriorityFilesParams(files).toJson();
- return server.send("analysis.setPriorityFiles", params)
- .then((result) {
- expect(result, isNull);
- return null;
- });
+ var result = await server.send("analysis.setPriorityFiles", params);
+ expect(result, isNull);
+ return null;
}
/**
@@ -552,13 +528,11 @@
* A table mapping services to a list of the files being subscribed to the
* service.
*/
- Future sendAnalysisSetSubscriptions(Map<AnalysisService, List<String>> subscriptions) {
+ Future sendAnalysisSetSubscriptions(Map<AnalysisService, List<String>> subscriptions) async {
var params = new AnalysisSetSubscriptionsParams(subscriptions).toJson();
- return server.send("analysis.setSubscriptions", params)
- .then((result) {
- expect(result, isNull);
- return null;
- });
+ var result = await server.send("analysis.setSubscriptions", params);
+ expect(result, isNull);
+ return null;
}
/**
@@ -579,13 +553,11 @@
*
* Returns
*/
- Future<AnalysisUpdateContentResult> sendAnalysisUpdateContent(Map<String, dynamic> files) {
+ Future<AnalysisUpdateContentResult> sendAnalysisUpdateContent(Map<String, dynamic> files) async {
var params = new AnalysisUpdateContentParams(files).toJson();
- return server.send("analysis.updateContent", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new AnalysisUpdateContentResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("analysis.updateContent", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new AnalysisUpdateContentResult.fromJson(decoder, 'result', result);
}
/**
@@ -600,13 +572,11 @@
*
* The options that are to be used to control analysis.
*/
- Future sendAnalysisUpdateOptions(AnalysisOptions options) {
+ Future sendAnalysisUpdateOptions(AnalysisOptions options) async {
var params = new AnalysisUpdateOptionsParams(options).toJson();
- return server.send("analysis.updateOptions", params)
- .then((result) {
- expect(result, isNull);
- return null;
- });
+ var result = await server.send("analysis.updateOptions", params);
+ expect(result, isNull);
+ return null;
}
/**
@@ -943,13 +913,11 @@
*
* The identifier used to associate results with this completion request.
*/
- Future<CompletionGetSuggestionsResult> sendCompletionGetSuggestions(String file, int offset) {
+ Future<CompletionGetSuggestionsResult> sendCompletionGetSuggestions(String file, int offset) async {
var params = new CompletionGetSuggestionsParams(file, offset).toJson();
- return server.send("completion.getSuggestions", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new CompletionGetSuggestionsResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("completion.getSuggestions", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new CompletionGetSuggestionsResult.fromJson(decoder, 'result', result);
}
/**
@@ -1038,13 +1006,11 @@
* If no element was found at the given location, this field will be
* absent.
*/
- Future<SearchFindElementReferencesResult> sendSearchFindElementReferences(String file, int offset, bool includePotential) {
+ Future<SearchFindElementReferencesResult> sendSearchFindElementReferences(String file, int offset, bool includePotential) async {
var params = new SearchFindElementReferencesParams(file, offset, includePotential).toJson();
- return server.send("search.findElementReferences", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new SearchFindElementReferencesResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("search.findElementReferences", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new SearchFindElementReferencesResult.fromJson(decoder, 'result', result);
}
/**
@@ -1066,13 +1032,11 @@
*
* The identifier used to associate results with this search request.
*/
- Future<SearchFindMemberDeclarationsResult> sendSearchFindMemberDeclarations(String name) {
+ Future<SearchFindMemberDeclarationsResult> sendSearchFindMemberDeclarations(String name) async {
var params = new SearchFindMemberDeclarationsParams(name).toJson();
- return server.send("search.findMemberDeclarations", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new SearchFindMemberDeclarationsResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("search.findMemberDeclarations", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new SearchFindMemberDeclarationsResult.fromJson(decoder, 'result', result);
}
/**
@@ -1096,13 +1060,11 @@
*
* The identifier used to associate results with this search request.
*/
- Future<SearchFindMemberReferencesResult> sendSearchFindMemberReferences(String name) {
+ Future<SearchFindMemberReferencesResult> sendSearchFindMemberReferences(String name) async {
var params = new SearchFindMemberReferencesParams(name).toJson();
- return server.send("search.findMemberReferences", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new SearchFindMemberReferencesResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("search.findMemberReferences", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new SearchFindMemberReferencesResult.fromJson(decoder, 'result', result);
}
/**
@@ -1126,13 +1088,11 @@
*
* The identifier used to associate results with this search request.
*/
- Future<SearchFindTopLevelDeclarationsResult> sendSearchFindTopLevelDeclarations(String pattern) {
+ Future<SearchFindTopLevelDeclarationsResult> sendSearchFindTopLevelDeclarations(String pattern) async {
var params = new SearchFindTopLevelDeclarationsParams(pattern).toJson();
- return server.send("search.findTopLevelDeclarations", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new SearchFindTopLevelDeclarationsResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("search.findTopLevelDeclarations", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new SearchFindTopLevelDeclarationsResult.fromJson(decoder, 'result', result);
}
/**
@@ -1169,13 +1129,11 @@
* not represent a type, or if the file has not been sufficiently analyzed
* to allow a type hierarchy to be produced.
*/
- Future<SearchGetTypeHierarchyResult> sendSearchGetTypeHierarchy(String file, int offset, {bool superOnly}) {
+ Future<SearchGetTypeHierarchyResult> sendSearchGetTypeHierarchy(String file, int offset, {bool superOnly}) async {
var params = new SearchGetTypeHierarchyParams(file, offset, superOnly: superOnly).toJson();
- return server.send("search.getTypeHierarchy", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new SearchGetTypeHierarchyResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("search.getTypeHierarchy", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new SearchGetTypeHierarchyResult.fromJson(decoder, 'result', result);
}
/**
@@ -1254,13 +1212,11 @@
*
* The length of the selection after formatting the code.
*/
- Future<EditFormatResult> sendEditFormat(String file, int selectionOffset, int selectionLength, {int lineLength}) {
+ Future<EditFormatResult> sendEditFormat(String file, int selectionOffset, int selectionLength, {int lineLength}) async {
var params = new EditFormatParams(file, selectionOffset, selectionLength, lineLength: lineLength).toJson();
- return server.send("edit.format", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new EditFormatResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("edit.format", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new EditFormatResult.fromJson(decoder, 'result', result);
}
/**
@@ -1289,13 +1245,11 @@
*
* The assists that are available at the given location.
*/
- Future<EditGetAssistsResult> sendEditGetAssists(String file, int offset, int length) {
+ Future<EditGetAssistsResult> sendEditGetAssists(String file, int offset, int length) async {
var params = new EditGetAssistsParams(file, offset, length).toJson();
- return server.send("edit.getAssists", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new EditGetAssistsResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("edit.getAssists", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new EditGetAssistsResult.fromJson(decoder, 'result', result);
}
/**
@@ -1322,13 +1276,11 @@
*
* The kinds of refactorings that are valid for the given selection.
*/
- Future<EditGetAvailableRefactoringsResult> sendEditGetAvailableRefactorings(String file, int offset, int length) {
+ Future<EditGetAvailableRefactoringsResult> sendEditGetAvailableRefactorings(String file, int offset, int length) async {
var params = new EditGetAvailableRefactoringsParams(file, offset, length).toJson();
- return server.send("edit.getAvailableRefactorings", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new EditGetAvailableRefactoringsResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("edit.getAvailableRefactorings", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new EditGetAvailableRefactoringsResult.fromJson(decoder, 'result', result);
}
/**
@@ -1351,13 +1303,11 @@
*
* The fixes that are available for the errors at the given offset.
*/
- Future<EditGetFixesResult> sendEditGetFixes(String file, int offset) {
+ Future<EditGetFixesResult> sendEditGetFixes(String file, int offset) async {
var params = new EditGetFixesParams(file, offset).toJson();
- return server.send("edit.getFixes", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new EditGetFixesResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("edit.getFixes", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new EditGetFixesResult.fromJson(decoder, 'result', result);
}
/**
@@ -1441,13 +1391,11 @@
* if the change field is omitted or if there are no potential edits for
* the refactoring.
*/
- Future<EditGetRefactoringResult> sendEditGetRefactoring(RefactoringKind kind, String file, int offset, int length, bool validateOnly, {RefactoringOptions options}) {
+ Future<EditGetRefactoringResult> sendEditGetRefactoring(RefactoringKind kind, String file, int offset, int length, bool validateOnly, {RefactoringOptions options}) async {
var params = new EditGetRefactoringParams(kind, file, offset, length, validateOnly, options: options).toJson();
- return server.send("edit.getRefactoring", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(kind);
- return new EditGetRefactoringResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("edit.getRefactoring", params);
+ ResponseDecoder decoder = new ResponseDecoder(kind);
+ return new EditGetRefactoringResult.fromJson(decoder, 'result', result);
}
/**
@@ -1473,13 +1421,11 @@
* The file edit that is to be applied to the given file to effect the
* sorting.
*/
- Future<EditSortMembersResult> sendEditSortMembers(String file) {
+ Future<EditSortMembersResult> sendEditSortMembers(String file) async {
var params = new EditSortMembersParams(file).toJson();
- return server.send("edit.sortMembers", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new EditSortMembersResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("edit.sortMembers", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new EditSortMembersResult.fromJson(decoder, 'result', result);
}
/**
@@ -1506,13 +1452,11 @@
* The file edit that is to be applied to the given file to effect the
* organizing.
*/
- Future<EditOrganizeDirectivesResult> sendEditOrganizeDirectives(String file) {
+ Future<EditOrganizeDirectivesResult> sendEditOrganizeDirectives(String file) async {
var params = new EditOrganizeDirectivesParams(file).toJson();
- return server.send("edit.organizeDirectives", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new EditOrganizeDirectivesResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("edit.organizeDirectives", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new EditOrganizeDirectivesResult.fromJson(decoder, 'result', result);
}
/**
@@ -1534,13 +1478,11 @@
*
* The identifier used to refer to the execution context that was created.
*/
- Future<ExecutionCreateContextResult> sendExecutionCreateContext(String contextRoot) {
+ Future<ExecutionCreateContextResult> sendExecutionCreateContext(String contextRoot) async {
var params = new ExecutionCreateContextParams(contextRoot).toJson();
- return server.send("execution.createContext", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new ExecutionCreateContextResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("execution.createContext", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new ExecutionCreateContextResult.fromJson(decoder, 'result', result);
}
/**
@@ -1554,13 +1496,11 @@
*
* The identifier of the execution context that is to be deleted.
*/
- Future sendExecutionDeleteContext(String id) {
+ Future sendExecutionDeleteContext(String id) async {
var params = new ExecutionDeleteContextParams(id).toJson();
- return server.send("execution.deleteContext", params)
- .then((result) {
- expect(result, isNull);
- return null;
- });
+ var result = await server.send("execution.deleteContext", params);
+ expect(result, isNull);
+ return null;
}
/**
@@ -1611,13 +1551,11 @@
* The URI to which the file path was mapped. This field is omitted if the
* file field was not given in the request.
*/
- Future<ExecutionMapUriResult> sendExecutionMapUri(String id, {String file, String uri}) {
+ Future<ExecutionMapUriResult> sendExecutionMapUri(String id, {String file, String uri}) async {
var params = new ExecutionMapUriParams(id, file: file, uri: uri).toJson();
- return server.send("execution.mapUri", params)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new ExecutionMapUriResult.fromJson(decoder, 'result', result);
- });
+ var result = await server.send("execution.mapUri", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new ExecutionMapUriResult.fromJson(decoder, 'result', result);
}
/**
@@ -1634,13 +1572,11 @@
*
* A list of the services being subscribed to.
*/
- Future sendExecutionSetSubscriptions(List<ExecutionService> subscriptions) {
+ Future sendExecutionSetSubscriptions(List<ExecutionService> subscriptions) async {
var params = new ExecutionSetSubscriptionsParams(subscriptions).toJson();
- return server.send("execution.setSubscriptions", params)
- .then((result) {
- expect(result, isNull);
- return null;
- });
+ var result = await server.send("execution.setSubscriptions", params);
+ expect(result, isNull);
+ return null;
}
/**
@@ -1683,12 +1619,10 @@
*
* The list of analysis contexts.
*/
- Future<DiagnosticGetDiagnosticsResult> sendDiagnosticGetDiagnostics() {
- return server.send("diagnostic.getDiagnostics", null)
- .then((result) {
- ResponseDecoder decoder = new ResponseDecoder(null);
- return new DiagnosticGetDiagnosticsResult.fromJson(decoder, 'result', result);
- });
+ Future<DiagnosticGetDiagnosticsResult> sendDiagnosticGetDiagnostics() async {
+ var result = await server.send("diagnostic.getDiagnostics", null);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new DiagnosticGetDiagnosticsResult.fromJson(decoder, 'result', result);
}
/**
diff --git a/pkg/analysis_server/test/integration/search/get_type_hierarchy_test.dart b/pkg/analysis_server/test/integration/search/get_type_hierarchy_test.dart
index a4ab04e..5cd0820 100644
--- a/pkg/analysis_server/test/integration/search/get_type_hierarchy_test.dart
+++ b/pkg/analysis_server/test/integration/search/get_type_hierarchy_test.dart
@@ -103,6 +103,7 @@
equals(text.indexOf('class $name') + 'class '.length));
}
}
+
checkElement('Object');
checkElement('Base');
checkElement('Pivot');
@@ -261,17 +262,15 @@
return Future.forEach(tests, (test) => test());
}
- Future<HierarchyResults> typeHierarchyTest(String text) {
+ Future<HierarchyResults> typeHierarchyTest(String text) async {
int offset = text.indexOf(' /* target */') - 1;
sendAnalysisUpdateContent({pathname: new AddContentOverlay(text)});
- return analysisFinished
- .then((_) => sendSearchGetTypeHierarchy(pathname, offset))
- .then((result) {
- if (result.hierarchyItems == null) {
- return null;
- } else {
- return new HierarchyResults(result.hierarchyItems);
- }
- });
+ await analysisFinished;
+ var result = await sendSearchGetTypeHierarchy(pathname, offset);
+ if (result.hierarchyItems == null) {
+ return null;
+ } else {
+ return new HierarchyResults(result.hierarchyItems);
+ }
}
}
diff --git a/pkg/analysis_server/test/mock_sdk.dart b/pkg/analysis_server/test/mock_sdk.dart
index 504d536..18d5316 100644
--- a/pkg/analysis_server/test/mock_sdk.dart
+++ b/pkg/analysis_server/test/mock_sdk.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
class MockSdk implements DartSdk {
static const _MockSdkLibrary LIB_CORE = const _MockSdkLibrary(
@@ -316,6 +317,9 @@
}
@override
+ PackageBundle getLinkedBundle() => null;
+
+ @override
SdkLibrary getSdkLibrary(String dartUri) {
// getSdkLibrary() is only used to determine whether a library is internal
// to the SDK. The mock SDK doesn't have any internals, so it's safe to
diff --git a/pkg/analysis_server/test/search/type_hierarchy_test.dart b/pkg/analysis_server/test/search/type_hierarchy_test.dart
index 6f9c273..0dfc892 100644
--- a/pkg/analysis_server/test/search/type_hierarchy_test.dart
+++ b/pkg/analysis_server/test/search/type_hierarchy_test.dart
@@ -142,6 +142,18 @@
{
'classElement': {
'kind': 'CLASS',
+ 'name': 'BBB',
+ 'location': anything,
+ 'flags': 0
+ },
+ 'superclass': 0,
+ 'interfaces': [],
+ 'mixins': [],
+ 'subclasses': [3]
+ },
+ {
+ 'classElement': {
+ 'kind': 'CLASS',
'name': 'CCC',
'location': anything,
'flags': 0
@@ -151,18 +163,6 @@
'mixins': [],
'subclasses': []
},
- {
- 'classElement': {
- 'kind': 'CLASS',
- 'name': 'BBB',
- 'location': anything,
- 'flags': 0
- },
- 'superclass': 0,
- 'interfaces': [],
- 'mixins': [],
- 'subclasses': [2]
- }
]);
}
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index a3279d2..948bf43 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -11,9 +11,10 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
import 'package:analysis_server/src/socket_server.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:plugin/manager.dart';
import 'package:unittest/unittest.dart';
@@ -109,11 +110,13 @@
}
static SocketServer _createSocketServer() {
+ PhysicalResourceProvider resourceProvider =
+ PhysicalResourceProvider.INSTANCE;
ServerPlugin serverPlugin = new ServerPlugin();
ExtensionManager manager = new ExtensionManager();
manager.processPlugins([serverPlugin]);
- SdkCreator sdkCreator = (_) =>
- new DirectoryBasedDartSdk(DirectoryBasedDartSdk.defaultSdkDirectory);
+ SdkCreator sdkCreator = (_) => new FolderBasedDartSdk(resourceProvider,
+ FolderBasedDartSdk.defaultSdkDirectory(resourceProvider));
return new SocketServer(
new AnalysisServerOptions(),
new DartSdkManager('', false, sdkCreator),
diff --git a/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart b/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart
index 98f1165..de239de 100644
--- a/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart
+++ b/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart
@@ -12,8 +12,8 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/source/package_map_provider.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:unittest/unittest.dart';
import '../utils.dart';
@@ -74,7 +74,8 @@
CachingPubPackageMapProvider newPkgProvider() {
return new CachingPubPackageMapProvider(
resProvider,
- DirectoryBasedDartSdk.defaultSdk,
+ new FolderBasedDartSdk(
+ resProvider, FolderBasedDartSdk.defaultSdkDirectory(resProvider)),
mockRunner.runPubList,
mockWriteFile);
}
diff --git a/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart b/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
index 5819e20..b34cca3 100644
--- a/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
+++ b/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
@@ -225,7 +225,7 @@
doCapitalize: true);
futureClass = 'Future<$resultClass>';
}
- writeln('$futureClass $methodName(${args.join(', ')}) {');
+ writeln('$futureClass $methodName(${args.join(', ')}) async {');
indent(() {
String requestClass = camelJoin(
[request.domainName, request.method, 'params'],
@@ -245,24 +245,19 @@
args.addAll(optionalArgs);
writeln('var params = new $requestClass(${args.join(', ')}).toJson();');
}
- writeln(
- 'return server.send(${JSON.encode(request.longMethod)}, $paramsVar)');
- indent(() {
- writeln(' .then((result) {');
- if (request.result != null) {
- String kind = 'null';
- if (requestClass == 'EditGetRefactoringParams') {
- kind = 'kind';
- }
- writeln('ResponseDecoder decoder = new ResponseDecoder($kind);');
- writeln(
- "return new $resultClass.fromJson(decoder, 'result', result);");
- } else {
- writeln('expect(result, isNull);');
- writeln('return null;');
+ String methodJson = JSON.encode(request.longMethod);
+ writeln('var result = await server.send($methodJson, $paramsVar);');
+ if (request.result != null) {
+ String kind = 'null';
+ if (requestClass == 'EditGetRefactoringParams') {
+ kind = 'kind';
}
- });
- writeln('});');
+ writeln('ResponseDecoder decoder = new ResponseDecoder($kind);');
+ writeln("return new $resultClass.fromJson(decoder, 'result', result);");
+ } else {
+ writeln('expect(result, isNull);');
+ writeln('return null;');
+ }
});
writeln('}');
}
diff --git a/pkg/analyzer/benchmark/errors_in_all_libraries.dart b/pkg/analyzer/benchmark/errors_in_all_libraries.dart
index 6f02534..da419d9 100644
--- a/pkg/analyzer/benchmark/errors_in_all_libraries.dart
+++ b/pkg/analyzer/benchmark/errors_in_all_libraries.dart
@@ -10,21 +10,17 @@
import 'dart:io';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/java_io.dart';
-import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk;
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
import 'package:path/path.dart' as p;
void main(List<String> args) {
- JavaSystemIO.setProperty(
- "com.google.dart.sdk",
- p.normalize(
- p.join(p.dirname(p.fromUri(Platform.script)), "../../../sdk")));
-
// Assumes you have run "pub get" in the analyzer directory itself and uses
// that "packages" directory as its package root.
var packageRoot =
@@ -35,10 +31,14 @@
var start = new DateTime.now();
AnalysisEngine.instance.clearCaches();
- var context = AnalysisEngine.instance.createAnalysisContext();
+ PhysicalResourceProvider resourceProvider =
+ PhysicalResourceProvider.INSTANCE;
+ DartSdk sdk = new FolderBasedDartSdk(
+ resourceProvider, resourceProvider.getFolder(args[0]));
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
context.sourceFactory = new SourceFactory([
- new DartUriResolver(DirectoryBasedDartSdk.defaultSdk),
- new ResourceUriResolver(PhysicalResourceProvider.INSTANCE),
+ new DartUriResolver(sdk),
+ new ResourceUriResolver(resourceProvider),
new PackageUriResolver([new JavaFile(packageRoot)])
]);
@@ -86,6 +86,7 @@
lib.importedLibraries.forEach(find);
lib.exportedLibraries.forEach(find);
}
+
find(start);
return results;
}
diff --git a/pkg/analyzer/doc/tasks.html b/pkg/analyzer/doc/tasks.html
index b5a88d0..3129e1a 100644
--- a/pkg/analyzer/doc/tasks.html
+++ b/pkg/analyzer/doc/tasks.html
@@ -127,8 +127,10 @@
InferInstanceMembersInUnitTask -> CREATED_RESOLVED_UNIT11
InferInstanceMembersInUnitTask -> RESOLVED_UNIT11
InferStaticVariableTypeTask -> INFERRED_STATIC_VARIABLE
+ InferStaticVariableTypeTask -> STATIC_VARIABLE_RESOLUTION_ERRORS
InferStaticVariableTypesInUnitTask -> CREATED_RESOLVED_UNIT9
InferStaticVariableTypesInUnitTask -> RESOLVED_UNIT9
+ InferStaticVariableTypesInUnitTask -> STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT
LIBRARY_CYCLE [shape=box]
LIBRARY_CYCLE_DEPENDENCIES -> InferInstanceMembersInUnitTask
LIBRARY_CYCLE_DEPENDENCIES -> InferStaticVariableTypeTask
@@ -192,6 +194,7 @@
LibraryErrorsReadyTask -> LIBRARY_ERRORS_READY
LibraryUnitErrorsTask -> LIBRARY_UNIT_ERRORS
MODIFICATION_TIME -> BuildDirectiveElementsTask
+ MODIFICATION_TIME -> BuildLibraryElementTask
MODIFICATION_TIME -> ParseDartTask
MODIFICATION_TIME -> ScanDartTask
MODIFICATION_TIME -> VerifyUnitTask
@@ -327,6 +330,10 @@
SCAN_ERRORS [shape=box]
SOURCE_KIND -> BuildDirectiveElementsTask
SOURCE_KIND [shape=box]
+ STATIC_VARIABLE_RESOLUTION_ERRORS -> InferStaticVariableTypesInUnitTask
+ STATIC_VARIABLE_RESOLUTION_ERRORS [shape=box]
+ STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT -> LibraryUnitErrorsTask
+ STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT [shape=box]
STRONG_MODE_ERRORS -> LibraryUnitErrorsTask
STRONG_MODE_ERRORS [shape=box]
ScanDartTask -> IGNORE_INFO
diff --git a/pkg/analyzer/example/resolver_driver.dart b/pkg/analyzer/example/resolver_driver.dart
index 885a5225..7a72abf 100755
--- a/pkg/analyzer/example/resolver_driver.dart
+++ b/pkg/analyzer/example/resolver_driver.dart
@@ -8,14 +8,14 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/file_system/file_system.dart' hide File;
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
-import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/file_system/file_system.dart' hide File;
-import 'package:analyzer/file_system/physical_file_system.dart';
void main(List<String> args) {
print('working dir ${new File('.').resolveSymbolicLinksSync()}');
@@ -30,12 +30,13 @@
packageRoot = args[2];
}
- JavaSystemIO.setProperty("com.google.dart.sdk", args[0]);
- DartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
+ PhysicalResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
+ DartSdk sdk = new FolderBasedDartSdk(
+ resourceProvider, resourceProvider.getFolder(args[0]));
var resolvers = [
new DartUriResolver(sdk),
- new ResourceUriResolver(PhysicalResourceProvider.INSTANCE)
+ new ResourceUriResolver(resourceProvider)
];
if (packageRoot != null) {
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 57fcdea..b829bee 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -1156,11 +1156,6 @@
* directive.
*/
LibraryElement get exportedLibrary;
-
- /**
- * Return `true` if the file referenced by the import's URI exists.
- */
- bool get uriExists;
}
/**
@@ -1346,11 +1341,6 @@
* prefix, or otherwise does not have an offset.
*/
int get prefixOffset;
-
- /**
- * Return `true` if the file referenced by the import's URI exists.
- */
- bool get uriExists;
}
/**
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index 8b8618e..b37fd72 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -72,10 +72,16 @@
Context get pathContext => io.Platform.isWindows ? windows : posix;
@override
- File getFile(String path) => new _PhysicalFile(new io.File(path));
+ File getFile(String path) {
+ path = normalize(path);
+ return new _PhysicalFile(new io.File(path));
+ }
@override
- Folder getFolder(String path) => new _PhysicalFolder(new io.Directory(path));
+ Folder getFolder(String path) {
+ path = normalize(path);
+ return new _PhysicalFolder(new io.Directory(path));
+ }
@override
Future<List<int>> getModificationTimes(List<Source> sources) async {
diff --git a/pkg/analyzer/lib/source/embedder.dart b/pkg/analyzer/lib/source/embedder.dart
index 94a72a8..ffcbfed 100644
--- a/pkg/analyzer/lib/source/embedder.dart
+++ b/pkg/analyzer/lib/source/embedder.dart
@@ -17,7 +17,7 @@
import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource;
-import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
import 'package:yaml/yaml.dart';
export 'package:analyzer/src/context/builder.dart' show EmbedderYamlLocator;
@@ -46,6 +46,9 @@
Map<String, String> get urlMappings => _urlMappings;
@override
+ PackageBundle getLinkedBundle() => null;
+
+ @override
String getRelativePathFromFile(JavaFile file) => file.getAbsolutePath();
@override
diff --git a/pkg/analyzer/lib/source/pub_package_map_provider.dart b/pkg/analyzer/lib/source/pub_package_map_provider.dart
index a7b2c42..c562232 100644
--- a/pkg/analyzer/lib/source/pub_package_map_provider.dart
+++ b/pkg/analyzer/lib/source/pub_package_map_provider.dart
@@ -11,8 +11,8 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/source/package_map_provider.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
/**
* The function used to run pub list.
@@ -40,7 +40,7 @@
/**
* Sdk that we use to find the pub executable.
*/
- final DirectoryBasedDartSdk sdk;
+ final FolderBasedDartSdk sdk;
/**
* The function used to run pub list.
@@ -146,6 +146,7 @@
packageMap[packageName] = folders;
}
}
+
packages.forEach((key, value) {
if (value is String) {
processPaths(key, [value]);
@@ -169,7 +170,7 @@
* Run pub list to determine the packages and input files.
*/
io.ProcessResult _runPubListDefault(Folder folder) {
- String executablePath = sdk.pubExecutable.getAbsolutePath();
+ String executablePath = sdk.pubExecutable.path;
List<String> arguments = [PUB_LIST_COMMAND];
String workingDirectory = folder.path;
int subprocessId = AnalysisEngine.instance.instrumentationService
diff --git a/pkg/analyzer/lib/src/cancelable_future.dart b/pkg/analyzer/lib/src/cancelable_future.dart
index 307e1d9..43eb00c 100644
--- a/pkg/analyzer/lib/src/cancelable_future.dart
+++ b/pkg/analyzer/lib/src/cancelable_future.dart
@@ -252,7 +252,7 @@
_completer._outerCompleter.future.catchError(onError, test: test);
@override
- Future/*<S>*/ then/*<S>*/(/*=S*/ onValue(T value), {Function onError}) =>
+ Future/*<S>*/ then/*<S>*/(onValue(T value), {Function onError}) =>
_completer._outerCompleter.future.then(onValue, onError: onError);
@override
@@ -288,7 +288,7 @@
_future.catchError(onError, test: test);
@override
- Future/*<S>*/ then/*<S>*/(/*=S*/ onValue(T value), {Function onError}) =>
+ Future/*<S>*/ then/*<S>*/(onValue(T value), {Function onError}) =>
_future.then(onValue, onError: onError);
@override
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 729fa65..6364199 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -16,11 +16,8 @@
import 'package:analyzer/source/sdk_ext.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/task/options.dart';
import 'package:package_config/discovery.dart';
import 'package:package_config/packages.dart';
@@ -147,9 +144,6 @@
Map<String, List<Folder>> folderMap = new HashMap<String, List<Folder>>();
packages.asMap().forEach((String packagePath, Uri uri) {
String path = resourceProvider.pathContext.fromUri(uri);
- if (path.endsWith(resourceProvider.pathContext.separator)) {
- path = path.substring(0, path.length - 1);
- }
folderMap[packagePath] = [resourceProvider.getFolder(path)];
});
return folderMap;
@@ -298,10 +292,10 @@
paths.addAll(extFilePaths);
SdkDescription description = new SdkDescription(paths, options);
return sdkManager.getSdk(description, () {
- DirectoryBasedDartSdk sdk =
- new DirectoryBasedDartSdk(new JavaFile(sdkPath));
+ FolderBasedDartSdk sdk = new FolderBasedDartSdk(
+ resourceProvider, resourceProvider.getFolder(sdkPath));
if (extFilePaths.isNotEmpty) {
- embedderSdk.addExtensions(extResolver.urlMappings);
+ sdk.addExtensions(extResolver.urlMappings);
}
sdk.analysisOptions = options;
sdk.useSummary = sdkManager.canUseSummaries;
@@ -312,8 +306,8 @@
String sdkPath = sdkManager.defaultSdkDirectory;
SdkDescription description = new SdkDescription(<String>[sdkPath], options);
return sdkManager.getSdk(description, () {
- DirectoryBasedDartSdk sdk =
- new DirectoryBasedDartSdk(new JavaFile(sdkPath));
+ FolderBasedDartSdk sdk = new FolderBasedDartSdk(
+ resourceProvider, resourceProvider.getFolder(sdkPath));
sdk.analysisOptions = options;
sdk.useSummary = sdkManager.canUseSummaries;
return sdk;
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index 668d4fc..6f06b5c 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -154,7 +154,6 @@
ImportElementImpl importElement = new ImportElementImpl(-1);
importElement.importedLibrary = importLibraryMap[coreLibrarySource];
importElement.synthetic = true;
- importElement.uriExists = true;
imports.add(importElement);
}
//
@@ -183,7 +182,6 @@
exportElement.uriEnd = uriLiteral.end;
}
exportElement.uri = node.uriContent;
- exportElement.uriExists = exportedTime >= 0;
exportElement.combinators = _buildCombinators(node);
exportElement.exportedLibrary = exportedLibrary;
setElementDocumentationComment(exportElement, node);
@@ -229,7 +227,6 @@
importElement.uriEnd = uriLiteral.end;
}
importElement.uri = node.uriContent;
- importElement.uriExists = importedTime >= 0;
importElement.deferred = node.deferredKeyword != null;
importElement.combinators = _buildCombinators(node);
importElement.importedLibrary = importedLibrary;
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 0ac63cf..491025e 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4157,23 +4157,6 @@
}
@override
- bool get uriExists {
- if (_unlinkedExportNonPublic != null) {
- return true;
- }
- return hasModifier(Modifier.URI_EXISTS);
- }
-
- /**
- * Set whether the file referenced by the import's URI exists to match the
- * given flag.
- */
- void set uriExists(bool exists) {
- assert(_unlinkedExportNonPublic == null);
- setModifier(Modifier.URI_EXISTS, exists);
- }
-
- @override
int get uriOffset {
if (_unlinkedExportNonPublic != null) {
return _unlinkedExportNonPublic.uriOffset;
@@ -5117,23 +5100,6 @@
}
@override
- bool get uriExists {
- if (_unlinkedImport != null) {
- return true;
- }
- return hasModifier(Modifier.URI_EXISTS);
- }
-
- /**
- * Set whether the file referenced by the import's URI exists to match the
- * given flag.
- */
- void set uriExists(bool exists) {
- assert(_unlinkedImport == null);
- setModifier(Modifier.URI_EXISTS, exists);
- }
-
- @override
int get uriOffset {
if (_unlinkedImport != null) {
if (_unlinkedImport.isImplicit) {
@@ -6433,12 +6399,6 @@
*/
static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 16);
- /**
- * A flag used for import and export elements that indicates whether the URI
- * in the corresponding directive referenced a file that exists.
- */
- static const Modifier URI_EXISTS = const Modifier('URI_EXISTS', 17);
-
static const List<Modifier> values = const [
ABSTRACT,
ASYNCHRONOUS,
@@ -6456,8 +6416,7 @@
REFERENCES_SUPER,
SETTER,
STATIC,
- SYNTHETIC,
- URI_EXISTS
+ SYNTHETIC
];
const Modifier(String name, int ordinal) : super(name, ordinal);
diff --git a/pkg/analyzer/lib/src/dart/element/handle.dart b/pkg/analyzer/lib/src/dart/element/handle.dart
index dae8fa2..6823b99 100644
--- a/pkg/analyzer/lib/src/dart/element/handle.dart
+++ b/pkg/analyzer/lib/src/dart/element/handle.dart
@@ -562,9 +562,6 @@
int get uriEnd => actualElement.uriEnd;
@override
- bool get uriExists => actualElement.uriExists;
-
- @override
int get uriOffset => actualElement.uriOffset;
}
@@ -710,9 +707,6 @@
int get uriEnd => actualElement.uriEnd;
@override
- bool get uriExists => actualElement.uriExists;
-
- @override
int get uriOffset => actualElement.uriOffset;
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/scope.dart b/pkg/analyzer/lib/src/dart/resolver/scope.dart
index 0537269..ba5b275 100644
--- a/pkg/analyzer/lib/src/dart/resolver/scope.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/scope.dart
@@ -452,7 +452,8 @@
int count = imports.length;
for (int i = 0; i < count; i++) {
ImportElement importElement = imports[i];
- if (importElement.prefix?.name == prefix && !importElement.uriExists) {
+ if (importElement.prefix?.name == prefix &&
+ importElement.importedLibrary?.isSynthetic != false) {
Iterable<NamespaceCombinator> showCombinators =
getShowCombinators(importElement);
if (showCombinators.isEmpty) {
@@ -471,7 +472,8 @@
int count = imports.length;
for (int i = 0; i < count; i++) {
ImportElement importElement = imports[i];
- if (importElement.prefix == null && !importElement.uriExists) {
+ if (importElement.prefix == null &&
+ importElement.importedLibrary?.isSynthetic != false) {
for (ShowElementCombinator combinator
in getShowCombinators(importElement)) {
if (combinator.shownNames.contains(name)) {
diff --git a/pkg/analyzer/lib/src/dart/sdk/sdk.dart b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
index 27e5549..453e6d1 100644
--- a/pkg/analyzer/lib/src/dart/sdk/sdk.dart
+++ b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
@@ -62,6 +62,8 @@
*/
Map<String, Source> _uriToSourceMap = new HashMap<String, Source>();
+ PackageBundle _sdkBundle;
+
/**
* Set the [options] for this SDK analysis context. Throw [StateError] if the
* context has been already created.
@@ -82,7 +84,7 @@
_analysisContext.sourceFactory = factory;
if (_useSummary) {
bool strongMode = _analysisOptions?.strongMode ?? false;
- PackageBundle sdkBundle = getSummarySdkBundle(strongMode);
+ PackageBundle sdkBundle = getLinkedBundle();
if (sdkBundle != null) {
_analysisContext.resultProvider = new SdkSummaryResultProvider(
_analysisContext, sdkBundle, strongMode);
@@ -151,6 +153,13 @@
return null;
}
+ @override
+ PackageBundle getLinkedBundle() {
+ bool strongMode = _analysisOptions?.strongMode ?? false;
+ _sdkBundle ??= getSummarySdkBundle(strongMode);
+ return _sdkBundle;
+ }
+
String getRelativePathFromFile(File file);
@override
@@ -272,6 +281,9 @@
Map<String, String> get urlMappings => _urlMappings;
@override
+ PackageBundle getLinkedBundle() => null;
+
+ @override
String getRelativePathFromFile(File file) => file.path;
@override
@@ -638,7 +650,7 @@
}
static String getSdkProperty(ResourceProvider resourceProvider) {
- String exec = io.Platform.executable;
+ String exec = io.Platform.resolvedExecutable;
if (exec.length == 0) {
return null;
}
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 87d3fd2..b10e4a0 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -643,7 +643,9 @@
}
staticElement = _resolveElement(typeReference, methodName);
} else {
- DartType staticType = _getStaticType(target);
+ DartType staticType = _resolver.strongMode
+ ? _getStaticTypeOrFunctionType(target)
+ : _getStaticType(target);
DartType propagatedType = _getPropagatedType(target);
staticElement = _resolveInvokedElementWithTarget(
target, staticType, methodName, isConditional);
@@ -1544,10 +1546,7 @@
* type analysis.
*/
DartType _getStaticType(Expression expression) {
- if (expression is NullLiteral) {
- return _resolver.typeProvider.bottomType;
- }
- DartType staticType = _resolveTypeParameter(expression.staticType);
+ DartType staticType = _getStaticTypeOrFunctionType(expression);
if (staticType is FunctionType) {
//
// All function types are subtypes of 'Function', which is itself a
@@ -1558,6 +1557,13 @@
return staticType;
}
+ DartType _getStaticTypeOrFunctionType(Expression expression) {
+ if (expression is NullLiteral) {
+ return _resolver.typeProvider.bottomType;
+ }
+ return _resolveTypeParameter(expression.staticType);
+ }
+
/**
* Check for a generic method & apply type arguments if any were passed.
*/
@@ -2224,6 +2230,10 @@
return element;
} else if (target is SimpleIdentifier) {
Element targetElement = target.staticElement;
+ if (targetType is FunctionType &&
+ methodName.name == FunctionElement.CALL_METHOD_NAME) {
+ return targetElement;
+ }
if (targetElement is PrefixElement) {
if (isConditional) {
_resolver.errorReporter.reportErrorForNode(
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index bedfdd8..fd71772 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -2373,13 +2373,26 @@
* Parameters:
* 0: the URI pointing to a non-existent file
*
- * See [INVALID_URI].
+ * See [INVALID_URI], [URI_HAS_NOT_BEEN_GENERATED].
*/
static const CompileTimeErrorCode URI_DOES_NOT_EXIST =
const CompileTimeErrorCode(
'URI_DOES_NOT_EXIST', "Target of URI does not exist: '{0}'");
/**
+ * Just like [URI_DOES_NOT_EXIST], but used when the URI refers to a file that
+ * is expected to be generated.
+ *
+ * Parameters:
+ * 0: the URI pointing to a non-existent file
+ *
+ * See [INVALID_URI], [URI_DOES_NOT_EXIST].
+ */
+ static const CompileTimeErrorCode URI_HAS_NOT_BEEN_GENERATED =
+ const CompileTimeErrorCode('URI_HAS_NOT_BEEN_GENERATED',
+ "Target of URI has not been generated: '{0}'");
+
+ /**
* 14.1 Imports: It is a compile-time error if <i>x</i> is not a compile-time
* constant, or if <i>x</i> involves string interpolation.
*
@@ -4286,8 +4299,7 @@
*
*/
static const StaticTypeWarningCode NON_NULLABLE_FIELD_NOT_INITIALIZED =
- const StaticTypeWarningCode(
- 'NON_NULLABLE_FIELD_NOT_INITIALIZED',
+ const StaticTypeWarningCode('NON_NULLABLE_FIELD_NOT_INITIALIZED',
"Variable '{0}' of non-nullable type '{1}' must be initialized");
/**
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index e3cf73c7..a9f2f6c 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -497,8 +497,10 @@
_initialFieldElementsMap = new HashMap<FieldElement, INIT_STATE>();
for (FieldElement fieldElement in fieldElements) {
if (!fieldElement.isSynthetic) {
- _initialFieldElementsMap[fieldElement] = fieldElement.initializer ==
- null ? INIT_STATE.NOT_INIT : INIT_STATE.INIT_IN_DECLARATION;
+ _initialFieldElementsMap[fieldElement] =
+ fieldElement.initializer == null
+ ? INIT_STATE.NOT_INIT
+ : INIT_STATE.INIT_IN_DECLARATION;
}
}
}
@@ -1305,6 +1307,7 @@
}
return parameter;
}
+
FormalParameter parameter = baseParameter(formalParameter);
if (parameter is FieldFormalParameter) {
FieldElement fieldElement =
@@ -1413,8 +1416,8 @@
}
/**
- * Check the given [executableElement] against override-error codes. The
- * [overriddenExecutable] is the element that the executable element is
+ * Check the given [derivedElement] against override-error codes. The
+ * [baseElement] is the element that the executable element is
* overriding. The [parameters] is the parameters of the executable element.
* The [errorNameTarget] is the node to report problems on.
*
@@ -1431,25 +1434,24 @@
* [StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES].
*/
bool _checkForAllInvalidOverrideErrorCodes(
- ExecutableElement executableElement,
- ExecutableElement overriddenExecutable,
+ ExecutableElement derivedElement,
+ ExecutableElement baseElement,
List<ParameterElement> parameters,
List<AstNode> parameterLocations,
SimpleIdentifier errorNameTarget) {
bool isGetter = false;
bool isSetter = false;
- if (executableElement is PropertyAccessorElement) {
- isGetter = executableElement.isGetter;
- isSetter = executableElement.isSetter;
+ if (derivedElement is PropertyAccessorElement) {
+ isGetter = derivedElement.isGetter;
+ isSetter = derivedElement.isSetter;
}
- String executableElementName = executableElement.name;
- FunctionType overridingFT = executableElement.type;
- FunctionType overriddenFT = overriddenExecutable.type;
+ String executableElementName = derivedElement.name;
+ FunctionType derivedFT = derivedElement.type;
+ FunctionType baseFT = baseElement.type;
InterfaceType enclosingType = _enclosingClass.type;
- overriddenFT =
- _inheritanceManager.substituteTypeArgumentsInMemberFromInheritance(
- overriddenFT, executableElementName, enclosingType);
- if (overridingFT == null || overriddenFT == null) {
+ baseFT = _inheritanceManager.substituteTypeArgumentsInMemberFromInheritance(
+ baseFT, executableElementName, enclosingType);
+ if (derivedFT == null || baseFT == null) {
return false;
}
@@ -1457,12 +1459,12 @@
// TODO(jmesserly): this duplicates some code in isSubtypeOf and most of
// _isGenericFunctionSubtypeOf. Ideally, we'd let TypeSystem produce
// an error message once it's ready to "return false".
- if (!overridingFT.typeFormals.isEmpty) {
- if (overriddenFT.typeFormals.isEmpty) {
- overridingFT = _typeSystem.instantiateToBounds(overridingFT);
+ if (!derivedFT.typeFormals.isEmpty) {
+ if (baseFT.typeFormals.isEmpty) {
+ derivedFT = _typeSystem.instantiateToBounds(derivedFT);
} else {
- List<TypeParameterElement> params1 = overridingFT.typeFormals;
- List<TypeParameterElement> params2 = overriddenFT.typeFormals;
+ List<TypeParameterElement> params1 = derivedFT.typeFormals;
+ List<TypeParameterElement> params2 = baseFT.typeFormals;
int count = params1.length;
if (params2.length != count) {
_errorReporter.reportErrorForNode(
@@ -1470,7 +1472,7 @@
errorNameTarget, [
count,
params2.length,
- overriddenExecutable.enclosingElement.displayName
+ baseElement.enclosingElement.displayName
]);
return true;
}
@@ -1506,74 +1508,73 @@
p1.bound,
p2.displayName,
p2.bound,
- overriddenExecutable.enclosingElement.displayName
+ baseElement.enclosingElement.displayName
]);
return true;
}
}
// Proceed with the rest of the checks, using instantiated types.
- overridingFT = overridingFT.instantiate(variablesFresh);
- overriddenFT = overriddenFT.instantiate(variablesFresh);
+ derivedFT = derivedFT.instantiate(variablesFresh);
+ baseFT = baseFT.instantiate(variablesFresh);
}
}
- DartType overridingFTReturnType = overridingFT.returnType;
- DartType overriddenFTReturnType = overriddenFT.returnType;
- List<DartType> overridingNormalPT = overridingFT.normalParameterTypes;
- List<DartType> overriddenNormalPT = overriddenFT.normalParameterTypes;
- List<DartType> overridingPositionalPT = overridingFT.optionalParameterTypes;
- List<DartType> overriddenPositionalPT = overriddenFT.optionalParameterTypes;
- Map<String, DartType> overridingNamedPT = overridingFT.namedParameterTypes;
- Map<String, DartType> overriddenNamedPT = overriddenFT.namedParameterTypes;
+ DartType derivedFTReturnType = derivedFT.returnType;
+ DartType baseFTReturnType = baseFT.returnType;
+ List<DartType> derivedNormalPT = derivedFT.normalParameterTypes;
+ List<DartType> baseNormalPT = baseFT.normalParameterTypes;
+ List<DartType> derivedPositionalPT = derivedFT.optionalParameterTypes;
+ List<DartType> basePositionalPT = baseFT.optionalParameterTypes;
+ Map<String, DartType> derivedNamedPT = derivedFT.namedParameterTypes;
+ Map<String, DartType> baseNamedPT = baseFT.namedParameterTypes;
// CTEC.INVALID_OVERRIDE_REQUIRED, CTEC.INVALID_OVERRIDE_POSITIONAL and
// CTEC.INVALID_OVERRIDE_NAMED
- if (overridingNormalPT.length > overriddenNormalPT.length) {
+ if (derivedNormalPT.length > baseNormalPT.length) {
_errorReporter.reportErrorForNode(
StaticWarningCode.INVALID_OVERRIDE_REQUIRED, errorNameTarget, [
- overriddenNormalPT.length,
- overriddenExecutable,
- overriddenExecutable.enclosingElement.displayName
+ baseNormalPT.length,
+ baseElement,
+ baseElement.enclosingElement.displayName
]);
return true;
}
- if (overridingNormalPT.length + overridingPositionalPT.length <
- overriddenPositionalPT.length + overriddenNormalPT.length) {
+ if (derivedNormalPT.length + derivedPositionalPT.length <
+ basePositionalPT.length + baseNormalPT.length) {
_errorReporter.reportErrorForNode(
StaticWarningCode.INVALID_OVERRIDE_POSITIONAL, errorNameTarget, [
- overriddenPositionalPT.length + overriddenNormalPT.length,
- overriddenExecutable,
- overriddenExecutable.enclosingElement.displayName
+ basePositionalPT.length + baseNormalPT.length,
+ baseElement,
+ baseElement.enclosingElement.displayName
]);
return true;
}
// For each named parameter in the overridden method, verify that there is
// the same name in the overriding method.
- for (String overriddenParamName in overriddenNamedPT.keys) {
- if (!overridingNamedPT.containsKey(overriddenParamName)) {
+ for (String overriddenParamName in baseNamedPT.keys) {
+ if (!derivedNamedPT.containsKey(overriddenParamName)) {
// The overridden method expected the overriding method to have
// overridingParamName, but it does not.
_errorReporter.reportErrorForNode(
StaticWarningCode.INVALID_OVERRIDE_NAMED, errorNameTarget, [
overriddenParamName,
- overriddenExecutable,
- overriddenExecutable.enclosingElement.displayName
+ baseElement,
+ baseElement.enclosingElement.displayName
]);
return true;
}
}
// SWC.INVALID_METHOD_OVERRIDE_RETURN_TYPE
- if (overriddenFTReturnType != VoidTypeImpl.instance &&
- !_typeSystem.isAssignableTo(
- overridingFTReturnType, overriddenFTReturnType)) {
+ if (baseFTReturnType != VoidTypeImpl.instance &&
+ !_typeSystem.isAssignableTo(derivedFTReturnType, baseFTReturnType)) {
_errorReporter.reportTypeErrorForNode(
!isGetter
? StaticWarningCode.INVALID_METHOD_OVERRIDE_RETURN_TYPE
: StaticWarningCode.INVALID_GETTER_OVERRIDE_RETURN_TYPE,
errorNameTarget,
[
- overridingFTReturnType,
- overriddenFTReturnType,
- overriddenExecutable.enclosingElement.displayName
+ derivedFTReturnType,
+ baseFTReturnType,
+ baseElement.enclosingElement.displayName
]);
return true;
}
@@ -1582,33 +1583,32 @@
return false;
}
int parameterIndex = 0;
- for (int i = 0; i < overridingNormalPT.length; i++) {
- if (!_typeSystem.isAssignableTo(
- overridingNormalPT[i], overriddenNormalPT[i])) {
+ for (int i = 0; i < derivedNormalPT.length; i++) {
+ if (!_typeSystem.isAssignableTo(baseNormalPT[i], derivedNormalPT[i])) {
_errorReporter.reportTypeErrorForNode(
!isSetter
? StaticWarningCode.INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE
: StaticWarningCode.INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE,
parameterLocations[parameterIndex],
[
- overridingNormalPT[i],
- overriddenNormalPT[i],
- overriddenExecutable.enclosingElement.displayName
+ derivedNormalPT[i],
+ baseNormalPT[i],
+ baseElement.enclosingElement.displayName
]);
return true;
}
parameterIndex++;
}
// SWC.INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE
- for (int i = 0; i < overriddenPositionalPT.length; i++) {
+ for (int i = 0; i < basePositionalPT.length; i++) {
if (!_typeSystem.isAssignableTo(
- overridingPositionalPT[i], overriddenPositionalPT[i])) {
+ basePositionalPT[i], derivedPositionalPT[i])) {
_errorReporter.reportTypeErrorForNode(
StaticWarningCode.INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE,
parameterLocations[parameterIndex], [
- overridingPositionalPT[i],
- overriddenPositionalPT[i],
- overriddenExecutable.enclosingElement.displayName
+ derivedPositionalPT[i],
+ basePositionalPT[i],
+ baseElement.enclosingElement.displayName
]);
return true;
}
@@ -1616,15 +1616,15 @@
}
// SWC.INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE &
// SWC.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES
- for (String overriddenName in overriddenNamedPT.keys) {
- DartType overridingType = overridingNamedPT[overriddenName];
- if (overridingType == null) {
+ for (String overriddenName in baseNamedPT.keys) {
+ DartType derivedType = derivedNamedPT[overriddenName];
+ if (derivedType == null) {
// Error, this is never reached- INVALID_OVERRIDE_NAMED would have been
// created above if this could be reached.
continue;
}
- DartType overriddenType = overriddenNamedPT[overriddenName];
- if (!_typeSystem.isAssignableTo(overriddenType, overridingType)) {
+ DartType baseType = baseNamedPT[overriddenName];
+ if (!_typeSystem.isAssignableTo(baseType, derivedType)) {
// lookup the parameter for the error to select
ParameterElement parameterToSelect = null;
AstNode parameterLocationToSelect = null;
@@ -1641,9 +1641,9 @@
_errorReporter.reportTypeErrorForNode(
StaticWarningCode.INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE,
parameterLocationToSelect, [
- overridingType,
- overriddenType,
- overriddenExecutable.enclosingElement.displayName
+ derivedType,
+ baseType,
+ baseElement.enclosingElement.displayName
]);
return true;
}
@@ -1661,7 +1661,7 @@
List<ParameterElementImpl> parameterElts = new List<ParameterElementImpl>();
List<ParameterElementImpl> overriddenParameterElts =
new List<ParameterElementImpl>();
- List<ParameterElement> overriddenPEs = overriddenExecutable.parameters;
+ List<ParameterElement> overriddenPEs = baseElement.parameters;
for (int i = 0; i < parameters.length; i++) {
ParameterElement parameter = parameters[i];
if (parameter.parameterKind.isOptional) {
@@ -1714,8 +1714,8 @@
.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
formalParameters[i],
[
- overriddenExecutable.enclosingElement.displayName,
- overriddenExecutable.displayName,
+ baseElement.enclosingElement.displayName,
+ baseElement.displayName,
parameterName
]);
foundError = true;
@@ -1753,8 +1753,8 @@
.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
formalParameters[i],
[
- overriddenExecutable.enclosingElement.displayName,
- overriddenExecutable.displayName
+ baseElement.enclosingElement.displayName,
+ baseElement.displayName
]);
foundError = true;
}
@@ -2202,6 +2202,7 @@
Element toVariable(Element element) {
return element is PropertyAccessorElement ? element.variable : element;
}
+
element = toVariable(element);
if (element is VariableElement) {
if (element.isConst) {
@@ -5813,6 +5814,7 @@
argument,
[argumentType, parameterType]);
}
+
if (element is FunctionTypedElement) {
_checkTypeArgumentsAgainstBounds(
element.typeParameters, typeArguments, targetType, reportError);
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 274b7a1..9e2a1d4 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -385,6 +385,7 @@
_shiftErrors_NEW(RESOLVE_TYPE_NAMES_ERRORS);
_shiftErrors_NEW(RESOLVE_TYPE_BOUNDS_ERRORS);
_shiftErrors_NEW(RESOLVE_UNIT_ERRORS);
+ _shiftErrors_NEW(STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT);
_shiftErrors_NEW(STRONG_MODE_ERRORS);
_shiftErrors_NEW(VARIABLE_REFERENCE_ERRORS);
_shiftErrors_NEW(VERIFY_ERRORS);
@@ -800,16 +801,21 @@
{
AstNode parent = newComment.parent;
if (parent is AnnotatedNode) {
+ setElementDocumentationForVariables(VariableDeclarationList list) {
+ for (VariableDeclaration variable in list.variables) {
+ Element variableElement = variable.element;
+ if (variableElement is ElementImpl) {
+ setElementDocumentationComment(variableElement, parent);
+ }
+ }
+ }
Element parentElement = ElementLocator.locate(newComment.parent);
if (parentElement is ElementImpl) {
setElementDocumentationComment(parentElement, parent);
- } else if (parentElement == null && parent is FieldDeclaration) {
- for (VariableDeclaration field in parent.fields.variables) {
- Element fieldElement = field.element;
- if (fieldElement is ElementImpl) {
- setElementDocumentationComment(fieldElement, parent);
- }
- }
+ } else if (parent is FieldDeclaration) {
+ setElementDocumentationForVariables(parent.fields);
+ } else if (parent is TopLevelVariableDeclaration) {
+ setElementDocumentationForVariables(parent.variables);
}
}
}
diff --git a/pkg/analyzer/lib/src/generated/package.dart b/pkg/analyzer/lib/src/generated/package.dart
new file mode 100644
index 0000000..a9576d1
--- /dev/null
+++ b/pkg/analyzer/lib/src/generated/package.dart
@@ -0,0 +1,239 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.src.generated.package;
+
+import 'dart:collection';
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_general.dart';
+import 'package:package_config/packages.dart';
+import 'package:yaml/yaml.dart';
+
+/**
+ * Traverses the package structure to determine the transitive dependencies for
+ * a given package.
+ */
+class DependencyFinder {
+ /**
+ * The name of the pubspec.yaml file.
+ */
+ static const String pubspecName = 'pubspec.yaml';
+
+ /**
+ * The resource provider used to access the file system.
+ */
+ final ResourceProvider resourceProvider;
+
+ /**
+ * A table mapping the absolute paths of packages to a list of the names of
+ * the packages on which those packages depend.
+ */
+ final Map<String, List<String>> dependencyMap =
+ new HashMap<String, List<String>>();
+
+ /**
+ * Initialize a newly created dependency finder to use the given
+ * [resourceProvider] to access the file system.
+ */
+ DependencyFinder(this.resourceProvider);
+
+ /**
+ * Return a sorted list of the directories containing all of the packages on
+ * which the package at the given [packagePath] depends. The [packageMap]
+ * maps the names of packages to the directories in which they are contained.
+ *
+ * Throws an [AnalysisException] if any of the packages are missing their
+ * 'pubspec.yaml' file.
+ */
+ List<String> transitiveDependenciesFor(
+ Map<String, List<Folder>> packageMap, String packagePath) {
+ Set<String> processedPackages = new HashSet<String>();
+ Set<String> processedPaths = new HashSet<String>();
+ void process(String packageName) {
+ if (processedPackages.add(packageName)) {
+ List<Folder> folderList = packageMap[packageName];
+ if (folderList == null || folderList.isEmpty) {
+ throw new StateError('No mapping for package "$packageName"');
+ }
+ String packagePath = folderList[0].path;
+ processedPaths.add(packagePath);
+ List<String> dependencies = _dependenciesFor(packagePath);
+ for (String dependency in dependencies) {
+ process(dependency);
+ }
+ }
+ }
+
+ List<String> dependencies = _dependenciesFor(packagePath);
+ dependencies.forEach(process);
+ processedPaths.remove(packagePath);
+ List<String> transitiveDependencies = processedPaths.toList();
+ transitiveDependencies.sort();
+ return transitiveDependencies;
+ }
+
+ /**
+ * Add to the given set of [dependecies] all of the package names used as keys
+ * in the given [yamlMap].
+ */
+ void _collectDependencies(HashSet<String> dependencies, YamlMap yamlMap) {
+ if (yamlMap is Map) {
+ for (var key in yamlMap.keys) {
+ if (key is String) {
+ dependencies.add(key);
+ }
+ }
+ }
+ }
+
+ /**
+ * Return a list of the names of the packages on which the package at the
+ * [packagePath] depends.
+ */
+ List<String> _dependenciesFor(String packagePath) {
+ return dependencyMap.putIfAbsent(packagePath, () {
+ Set<String> dependencies = new HashSet<String>();
+ YamlNode yamlNode = _readPubspec(packagePath);
+ if (yamlNode is YamlMap) {
+ _collectDependencies(dependencies, yamlNode['dependencies']);
+ }
+ return dependencies.toList();
+ });
+ }
+
+ /**
+ * Read the content of the pubspec file in the directory at the given
+ * [directoryPath]. Return `null` if the file does not exist, cannot be read,
+ * or has content that is not valid YAML.
+ */
+ YamlNode _readPubspec(String directoryPath) {
+ try {
+ File yamlFile = resourceProvider
+ .getFolder(directoryPath)
+ .getChildAssumingFile(pubspecName);
+ String yamlContent = yamlFile.readAsStringSync();
+ return loadYamlNode(yamlContent);
+ } catch (exception, stackTrace) {
+ throw new AnalysisException('Missing $pubspecName in $directoryPath',
+ new CaughtException(exception, stackTrace));
+ }
+ }
+}
+
+/**
+ * A description of the context in which a package will be analyzed.
+ */
+class PackageDescription {
+ /**
+ * The id of the package being described. The id encodes the actual locations
+ * of the package itself and all of the packages on which it depends.
+ */
+ final String id;
+
+ /**
+ * The SDK against which the package will be analyzed.
+ */
+ final DartSdk sdk;
+
+ /**
+ * The analysis options that will be used when analyzing the package.
+ */
+ final AnalysisOptions options;
+
+ /**
+ * Initialize a newly create package description to describe the package with
+ * the given [id] that is being analyzed against the given [sdk] using the
+ * given [options].
+ */
+ PackageDescription(this.id, this.sdk, this.options);
+
+ @override
+ int get hashCode {
+ int hashCode = options.encodeCrossContextOptions();
+ hashCode = JenkinsSmiHash.combine(hashCode, id.hashCode);
+ hashCode = JenkinsSmiHash.combine(hashCode, sdk.hashCode);
+ return JenkinsSmiHash.finish(hashCode);
+ }
+
+ @override
+ bool operator ==(Object other) {
+ return other is PackageDescription &&
+ other.sdk == sdk &&
+ other.options.encodeCrossContextOptions() ==
+ options.encodeCrossContextOptions() &&
+ other.id == id;
+ }
+}
+
+/**
+ * Manages the contexts in which each package is analyzed.
+ */
+class PackageManager {
+ /**
+ * The resource provider used to access the file system.
+ */
+ final ResourceProvider resourceProvider;
+
+ /**
+ * A table mapping the id's of packages to the context in which the package is
+ * analyzed.
+ */
+ final Map<PackageDescription, AnalysisContext> contextMap =
+ new HashMap<PackageDescription, AnalysisContext>();
+
+ /**
+ * Initialize a newly created package manager.
+ */
+ PackageManager(this.resourceProvider);
+
+ /**
+ * Return the context in which the package at the given [packagePath] should
+ * be analyzed when the given [packages] object is used to resolve package
+ * names, the given [resolver] will be used to resolve 'dart:' URI's, and the
+ * given [options] will control the analysis.
+ */
+ AnalysisContext getContext(String packagePath, Packages packages,
+ DartUriResolver resolver, AnalysisOptions options) {
+ DartSdk sdk = resolver.dartSdk;
+ Map<String, List<Folder>> packageMap =
+ new ContextBuilder(resourceProvider, null, null)
+ .convertPackagesToMap(packages);
+ PackageDescription description =
+ new PackageDescription(_buildId(packagePath, packageMap), sdk, options);
+ return contextMap.putIfAbsent(description, () {
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ resolver,
+ new PackageMapUriResolver(resourceProvider, packageMap),
+ new ResourceUriResolver(resourceProvider)
+ ], packages, resourceProvider);
+ context.analysisOptions = options;
+ return context;
+ });
+ }
+
+ /**
+ * Return the id associated with the package at the given [packagePath] when
+ * the given [packageMap] is used to resolve package names.
+ */
+ String _buildId(String packagePath, Map<String, List<Folder>> packageMap) {
+ DependencyFinder finder = new DependencyFinder(resourceProvider);
+ List<String> dependencies =
+ finder.transitiveDependenciesFor(packageMap, packagePath);
+ StringBuffer buffer = new StringBuffer();
+ buffer.write(packagePath);
+ for (String dependency in dependencies) {
+ buffer.write(';');
+ buffer.write(dependency);
+ }
+ return buffer.toString();
+ }
+}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 3f9d3d8..cec8354 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1918,10 +1918,10 @@
@override
Object visitExportDirective(ExportDirective node) {
ExportElement exportElement = node.element;
- if (exportElement != null && exportElement.uriExists) {
+ if (exportElement != null) {
// The element is null when the URI is invalid
LibraryElement library = exportElement.exportedLibrary;
- if (library != null) {
+ if (library != null && !library.isSynthetic) {
for (Combinator combinator in node.combinators) {
_checkCombinator(exportElement.exportedLibrary, combinator);
}
@@ -1962,11 +1962,11 @@
@override
Object visitImportDirective(ImportDirective node) {
ImportElement importElement = node.element;
- if (importElement != null && importElement.uriExists) {
+ if (importElement != null) {
// The element is null when the URI is invalid, but not when the URI is
// valid but refers to a non-existent file.
LibraryElement library = importElement.importedLibrary;
- if (library != null) {
+ if (library != null && !library.isSynthetic) {
for (Combinator combinator in node.combinators) {
_checkCombinator(library, combinator);
}
@@ -4452,7 +4452,7 @@
LibraryElement libraryElement = importElement.importedLibrary;
if (libraryElement == null ||
libraryElement.isDartCore ||
- !importElement.uriExists) {
+ libraryElement.isSynthetic) {
continue;
}
}
@@ -4910,6 +4910,15 @@
}
/**
+ * Look for contextual type information attached to [node]. Returns
+ * the type if found, otherwise null.
+ *
+ * If [node] has a contextual union type like `T | Future<T>` this will be
+ * returned. You can use [getType] if you prefer to only get the `T`.
+ */
+ static DartType getContext(AstNode node) => node?.getProperty(_typeProperty);
+
+ /**
* Look for a single contextual type attached to [node], and returns the type
* if found, otherwise null.
*
@@ -4926,15 +4935,6 @@
}
/**
- * Look for contextual type information attached to [node]. Returns
- * the type if found, otherwise null.
- *
- * If [node] has a contextual union type like `T | Future<T>` this will be
- * returned. You can use [getType] if you prefer to only get the `T`.
- */
- static DartType getContext(AstNode node) => node?.getProperty(_typeProperty);
-
- /**
* Like [getContext] but expands a union type into a list of types.
*/
static Iterable<DartType> getTypes(AstNode node) {
diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart
index e46b644..7e86d8d 100644
--- a/pkg/analyzer/lib/src/generated/sdk.dart
+++ b/pkg/analyzer/lib/src/generated/sdk.dart
@@ -12,6 +12,7 @@
show AnalysisContext, AnalysisOptions, AnalysisOptionsImpl;
import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:analyzer/src/generated/utilities_general.dart';
+import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
/**
* A function used to create a new DartSdk with the given [options]. If the
@@ -78,6 +79,14 @@
Source fromFileUri(Uri uri);
/**
+ * Return the linked [PackageBundle] for this SDK, if it can be provided, or
+ * `null` otherwise.
+ *
+ * This is a temporary API, don't use it.
+ */
+ PackageBundle getLinkedBundle();
+
+ /**
* Return the library representing the library with the given 'dart:' [uri],
* or `null` if the given URI does not denote a library in this SDK.
*/
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index 50cb9d0..d9dbcbc 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -2,6 +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.sdk_io;
import 'dart:collection';
@@ -29,6 +30,7 @@
* stored in a library map. Subclasses are responsible for populating the
* library map.
*/
+@deprecated
abstract class AbstractDartSdk implements DartSdk {
/**
* A mapping from Dart library URI's to the library represented by that URI.
@@ -252,7 +254,10 @@
* util/
* ... Dart utilities ...
* Chromium/ <-- Dartium typically exists in a sibling directory
+ *
+ * This class is deprecated. Please use FolderBasedDartSdk instead.
*/
+@deprecated
class DirectoryBasedDartSdk extends AbstractDartSdk {
/**
* The default SDK, or `null` if the default SDK either has not yet been
@@ -633,6 +638,9 @@
}
@override
+ PackageBundle getLinkedBundle() => null;
+
+ @override
String getRelativePathFromFile(JavaFile file) {
String filePath = file.getAbsolutePath();
String libPath = libraryDirectory.getAbsolutePath();
@@ -750,6 +758,7 @@
* platforms: 0),
* };
*/
+@deprecated
class SdkLibrariesReader {
/**
* A flag indicating whether the dart2js path should be used when it is
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 6875c97..5f08998 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -17,6 +17,7 @@
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/task/strong/checker.dart' show getDefiniteType;
/**
* Instances of the class `StaticTypeAnalyzer` perform two type-related tasks. First, they
@@ -481,50 +482,6 @@
}
/**
- * Infers the return type of a local function, either a lambda or
- * (in strong mode) a local function declaration.
- */
- void _inferLocalFunctionReturnType(FunctionExpression node) {
- bool recordInference = false;
- ExecutableElementImpl functionElement =
- node.element as ExecutableElementImpl;
-
- 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)) {
- DartType contextType = InferenceContext.getContext(body);
- if (contextType is FutureUnionType) {
- // TODO(jmesserly): can we do something better here?
- computedType = body.isAsynchronous ? contextType.type : _dynamicType;
- } else {
- computedType = contextType ?? _dynamicType;
- }
- recordInference = !computedType.isDynamic;
- }
-
- computedType = _computeReturnTypeOfFunction(body, computedType);
-
- functionElement.returnType = computedType;
- _recordPropagatedTypeOfFunction(functionElement, node.body);
- _recordStaticType(node, functionElement.type);
- if (recordInference) {
- _resolver.inferenceContext.recordInference(node, functionElement.type);
- }
- }
-
- /**
* The Dart Language Specification, 12.14.4: <blockquote>A function expression invocation <i>i</i>
* has the form <i>e<sub>f</sub>(a<sub>1</sub>, …, a<sub>n</sub>, x<sub>n+1</sub>:
* a<sub>n+1</sub>, …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>, where <i>e<sub>f</sub></i> is
@@ -1467,8 +1424,8 @@
*/
void _analyzeLeastUpperBound(
Expression node, Expression expr1, Expression expr2) {
- DartType staticType1 = _getStaticType(expr1);
- DartType staticType2 = _getStaticType(expr2);
+ DartType staticType1 = _getDefiniteType(expr1);
+ DartType staticType2 = _getDefiniteType(expr2);
if (staticType1 == null) {
// TODO(brianwilkerson) Determine whether this can still happen.
staticType1 = _dynamicType;
@@ -1697,6 +1654,17 @@
}
/**
+ * Gets the definite type of expression, which can be used in cases where
+ * the most precise type is desired, for example computing the least upper
+ * bound.
+ *
+ * See [getDefiniteType] for more information. Without strong mode, this is
+ * equivalent to [_getStaticType].
+ */
+ DartType _getDefiniteType(Expression expr) =>
+ getDefiniteType(expr, _typeSystem, _typeProvider);
+
+ /**
* If the given element name can be mapped to the name of a class defined within the given
* library, return the type specified by the argument.
*
@@ -1983,7 +1951,7 @@
? returnContext.futureOfType
: returnContext.type;
} else {
- returnType = returnContext as DartType;
+ returnType = returnContext;
}
return ts.inferGenericFunctionCall(
_typeProvider, fnType, paramTypes, argTypes, returnType);
@@ -2034,6 +2002,50 @@
}
/**
+ * Infers the return type of a local function, either a lambda or
+ * (in strong mode) a local function declaration.
+ */
+ void _inferLocalFunctionReturnType(FunctionExpression node) {
+ bool recordInference = false;
+ ExecutableElementImpl functionElement =
+ node.element as ExecutableElementImpl;
+
+ 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)) {
+ DartType contextType = InferenceContext.getContext(body);
+ if (contextType is FutureUnionType) {
+ // TODO(jmesserly): can we do something better here?
+ computedType = body.isAsynchronous ? contextType.type : _dynamicType;
+ } else {
+ computedType = contextType ?? _dynamicType;
+ }
+ recordInference = !computedType.isDynamic;
+ }
+
+ computedType = _computeReturnTypeOfFunction(body, computedType);
+
+ functionElement.returnType = computedType;
+ _recordPropagatedTypeOfFunction(functionElement, node.body);
+ _recordStaticType(node, functionElement.type);
+ if (recordInference) {
+ _resolver.inferenceContext.recordInference(node, functionElement.type);
+ }
+ }
+
+ /**
* Given a local variable declaration and its initializer, attempt to infer
* a type for the local variable declaration based on the initializer.
* Inference is only done if an explicit type is not present, and if
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 6fcb63b..c32e5c5 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -354,8 +354,7 @@
// Don't allow implicit downcasts between function types
// and call method objects, as these will almost always fail.
- if ((fromType is FunctionType && getCallMethodType(toType) != null) ||
- (toType is FunctionType && getCallMethodType(fromType) != null)) {
+ if (fromType is FunctionType && getCallMethodType(toType) != null) {
return false;
}
@@ -373,7 +372,7 @@
// If the subtype relation goes the other way, allow the implicit
// downcast.
- if (isSubtypeOf(toType, fromType) || toType.isAssignableTo(fromType)) {
+ if (isSubtypeOf(toType, fromType)) {
// TODO(leafp,jmesserly): we emit warnings/hints for these in
// src/task/strong/checker.dart, which is a bit inconsistent. That
// code should be handled into places that use isAssignableTo, such as
diff --git a/pkg/analyzer/lib/src/generated/utilities_dart.dart b/pkg/analyzer/lib/src/generated/utilities_dart.dart
index 1409cd5..d244dce 100644
--- a/pkg/analyzer/lib/src/generated/utilities_dart.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_dart.dart
@@ -27,21 +27,14 @@
}
Uri origBaseUri = baseUri;
try {
- bool isOpaque = baseUri.isAbsolute && !baseUri.path.startsWith('/');
- if (isOpaque) {
- String scheme = baseUri.scheme;
+ String scheme = baseUri.scheme;
+ if (scheme == DartUriResolver.DART_SCHEME) {
String part = baseUri.path;
- if (scheme == DartUriResolver.DART_SCHEME && part.indexOf('/') < 0) {
- part = "$part/$part.dart";
+ if (part.indexOf('/') < 0) {
+ baseUri = FastUri.parse('$scheme:$part/$part.dart');
}
- baseUri = FastUri.parse("$scheme:/$part");
}
- Uri result = baseUri.resolveUri(containedUri);
- if (isOpaque) {
- result =
- FastUri.parse("${result.scheme}:${result.path.substring(1)}");
- }
- return result;
+ return baseUri.resolveUri(containedUri);
} catch (exception, stackTrace) {
throw new AnalysisException(
"Could not resolve URI ($containedUri) relative to source ($origBaseUri)",
diff --git a/pkg/analyzer/lib/src/summary/index_unit.dart b/pkg/analyzer/lib/src/summary/index_unit.dart
index c1bbae5..5a9cb47 100644
--- a/pkg/analyzer/lib/src/summary/index_unit.dart
+++ b/pkg/analyzer/lib/src/summary/index_unit.dart
@@ -23,7 +23,9 @@
factory IndexElementInfo(Element element) {
IndexSyntheticElementKind kind = IndexSyntheticElementKind.notSynthetic;
- if (element.isSynthetic) {
+ if (element is LibraryElement || element is CompilationUnitElement) {
+ kind = IndexSyntheticElementKind.unit;
+ } else if (element.isSynthetic) {
if (element is ConstructorElement) {
kind = IndexSyntheticElementKind.constructor;
element = element.enclosingElement;
@@ -60,8 +62,6 @@
throw new ArgumentError(
'Unsupported synthetic element ${element.runtimeType}');
}
- } else if (element is LibraryElement || element is CompilationUnitElement) {
- kind = IndexSyntheticElementKind.unit;
}
return new IndexElementInfo._(element, kind);
}
diff --git a/pkg/analyzer/lib/src/summary/pub_summary.dart b/pkg/analyzer/lib/src/summary/pub_summary.dart
index 21c074d..ef66af4 100644
--- a/pkg/analyzer/lib/src/summary/pub_summary.dart
+++ b/pkg/analyzer/lib/src/summary/pub_summary.dart
@@ -9,12 +9,14 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/source/sdk_ext.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/parser.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/link.dart';
@@ -28,6 +30,20 @@
import 'package:path/path.dart' as pathos;
/**
+ * Unlinked and linked information about a [PubPackage].
+ */
+class LinkedPubPackage {
+ final PubPackage package;
+ final PackageBundle unlinked;
+ final PackageBundle linked;
+
+ LinkedPubPackage(this.package, this.unlinked, this.linked);
+
+ @override
+ String toString() => package.toString();
+}
+
+/**
* A package in the pub cache.
*/
class PubPackage {
@@ -51,16 +67,6 @@
}
/**
- * Unlinked and linked information about a [PubPackage].
- */
-class LinkedPubPackage {
- final PubPackage package;
- final PackageBundle unlinked;
- final PackageBundle linked;
- LinkedPubPackage(this.package, this.unlinked, this.linked);
-}
-
-/**
* Class that manages summaries for pub packages.
*
* The client should call [getLinkedBundles] after creating a new
@@ -69,7 +75,8 @@
* configure [ResynthesizerResultProvider] for the context.
*/
class PubSummaryManager {
- static const UNLINKED_BUNDLE_FILE_NAME = 'unlinked.ds';
+ static const UNLINKED_NAME = 'unlinked.ds';
+ static const UNLINKED_SPEC_NAME = 'unlinked_spec.ds';
final ResourceProvider resourceProvider;
@@ -122,46 +129,155 @@
pathos.Context get pathContext => resourceProvider.pathContext;
/**
+ * Compute and return the linked bundle for the SDK extension for the given
+ * [context], or `null` if none of the packages has an SDK extension. At most
+ * one extension library is supported, if more than one is found, then an
+ * error will be logged, and `null` returned.
+ */
+ PackageBundle computeSdkExtension(
+ AnalysisContext context, PackageBundle sdkBundle) {
+ // Prepare SDK extension library files.
+ String libUriStr;
+ String libPath;
+ {
+ Map<String, List<Folder>> packageMap = context.sourceFactory.packageMap;
+ SdkExtUriResolver sdkExtUriResolver = new SdkExtUriResolver(packageMap);
+ Map<String, String> sdkExtMappings = sdkExtUriResolver.urlMappings;
+ if (sdkExtMappings.length == 1) {
+ libUriStr = sdkExtMappings.keys.first;
+ libPath = sdkExtMappings.values.first;
+ } else if (sdkExtMappings.length > 1) {
+ AnalysisEngine.instance.logger
+ .logError('At most one _sdkext file is supported, '
+ 'with at most one extension library. $sdkExtMappings found.');
+ return null;
+ } else {
+ return null;
+ }
+ }
+ // Compute the extension unlinked bundle.
+ bool strong = context.analysisOptions.strongMode;
+ PackageBundleAssembler assembler = new PackageBundleAssembler();
+ try {
+ File libFile = resourceProvider.getFile(libPath);
+ Uri libUri = FastUri.parse(libUriStr);
+ Source libSource = libFile.createSource(libUri);
+ CompilationUnit libraryUnit = _parse(libSource, strong);
+ // Add the library unit.
+ assembler.addUnlinkedUnit(libSource, serializeAstUnlinked(libraryUnit));
+ // Add part units.
+ for (Directive directive in libraryUnit.directives) {
+ if (directive is PartDirective) {
+ Source partSource;
+ {
+ String partUriStr = directive.uri.stringValue;
+ Uri partUri = resolveRelativeUri(libUri, FastUri.parse(partUriStr));
+ pathos.Context pathContext = resourceProvider.pathContext;
+ String partPath =
+ pathContext.join(pathContext.dirname(libPath), partUriStr);
+ File partFile = resourceProvider.getFile(partPath);
+ partSource = partFile.createSource(partUri);
+ }
+ CompilationUnit partUnit = _parse(partSource, strong);
+ assembler.addUnlinkedUnit(partSource, serializeAstUnlinked(partUnit));
+ }
+ }
+ // Add the SDK and the unlinked extension bundle.
+ PackageBundleBuilder unlinkedBuilder = assembler.assemble();
+ SummaryDataStore store = new SummaryDataStore(const <String>[]);
+ store.addBundle(null, sdkBundle);
+ store.addBundle(null, unlinkedBuilder);
+ // Link the extension bundle.
+ Map<String, LinkedLibraryBuilder> linkedLibraries;
+ try {
+ linkedLibraries = link([libUriStr].toSet(), (String absoluteUri) {
+ LinkedLibrary dependencyLibrary = store.linkedMap[absoluteUri];
+ if (dependencyLibrary == null) {
+ throw new _LinkException();
+ }
+ return dependencyLibrary;
+ }, (String absoluteUri) {
+ UnlinkedUnit unlinkedUnit = store.unlinkedMap[absoluteUri];
+ if (unlinkedUnit == null) {
+ throw new _LinkException();
+ }
+ return unlinkedUnit;
+ }, strong);
+ } on _LinkException {
+ return null;
+ }
+ if (linkedLibraries.length != 1) {
+ return null;
+ }
+ // Append linked libraries into the assembler.
+ linkedLibraries.forEach((uri, library) {
+ assembler.addLinkedLibrary(uri, library);
+ });
+ List<int> bytes = assembler.assemble().toBuffer();
+ return new PackageBundle.fromBuffer(bytes);
+ } on FileSystemException {
+ return null;
+ }
+ }
+
+ /**
* Return the list of linked [LinkedPubPackage]s that can be provided at this
* time for a subset of the packages used by the given [context]. If
* information about some of the used packages is not available yet, schedule
* its computation, so that it might be available later for other contexts
* referencing the same packages.
*/
- List<LinkedPubPackage> getLinkedBundles(
- AnalysisContext context, PackageBundle sdkBundle) {
+ List<LinkedPubPackage> getLinkedBundles(AnalysisContext context) {
+ PackageBundle sdkBundle = context.sourceFactory.dartSdk.getLinkedBundle();
+ if (sdkBundle == null) {
+ return const <LinkedPubPackage>[];
+ }
+
Map<PubPackage, PackageBundle> unlinkedBundles =
getUnlinkedBundles(context);
// If no unlinked bundles, there is nothing we can try to link.
if (unlinkedBundles.isEmpty) {
- return <LinkedPubPackage>[];
+ return const <LinkedPubPackage>[];
}
// Create graph nodes for packages.
List<_LinkedNode> nodes = <_LinkedNode>[];
- Map<String, _LinkedNode> uriToNode = <String, _LinkedNode>{};
+ Map<String, _LinkedNode> packageToNode = <String, _LinkedNode>{};
unlinkedBundles.forEach((package, unlinked) {
- _LinkedNode node = new _LinkedNode(package, unlinked, uriToNode);
+ _LinkedNode node = new _LinkedNode(package, unlinked, packageToNode);
nodes.add(node);
- for (String uri in unlinked.unlinkedUnitUris) {
- uriToNode[uri] = node;
- }
+ packageToNode[package.name] = node;
});
- // Fill the store with unlinked bundles.
+ // Fill the store with the linked SDK and unlinked package bundles.
SummaryDataStore store = new SummaryDataStore(const <String>[]);
store.addBundle(null, sdkBundle);
+ {
+ PackageBundle extension = computeSdkExtension(context, sdkBundle);
+ if (extension != null) {
+ store.addBundle(null, extension);
+ }
+ }
for (PackageBundle unlinked in unlinkedBundles.values) {
store.addBundle(null, unlinked);
}
// Link each package node.
+// Stopwatch linkTimer = new Stopwatch()..start();
for (_LinkedNode node in nodes) {
if (!node.isEvaluated) {
- new _LinkedWalker(store).walk(node);
+ try {
+ bool strong = context.analysisOptions.strongMode;
+ new _LinkedWalker(store, strong).walk(node);
+ } on _LinkException {
+ // Linking of the node failed.
+ }
}
}
+ // TODO(scheglov) remove debug output after optimizing
+// print('LINKED ${unlinkedBundles.length} bundles'
+// ' in ${linkTimer.elapsedMilliseconds} ms');
// Create successfully linked packages.
List<LinkedPubPackage> linkedPackages = <LinkedPubPackage>[];
@@ -175,6 +291,7 @@
}
// TODO(scheglov) compute dependency hashes and write linked bundles.
+ // TODO(scheglov) don't forget to include the SDK API signature.
// Done.
return linkedPackages;
@@ -185,6 +302,7 @@
* maybe an empty map, but not `null`.
*/
Map<PubPackage, PackageBundle> getUnlinkedBundles(AnalysisContext context) {
+ bool strong = context.analysisOptions.strongMode;
Map<PubPackage, PackageBundle> unlinkedBundles =
new HashMap<PubPackage, PackageBundle>();
Map<String, List<Folder>> packageMap = context.sourceFactory.packageMap;
@@ -192,12 +310,11 @@
packageMap.forEach((String packageName, List<Folder> libFolders) {
if (libFolders.length == 1) {
Folder libFolder = libFolders.first;
- if (isPathInPubCache(pathContext, libFolder.path)) {
- PubPackage package = new PubPackage(packageName, libFolder);
- PackageBundle unlinkedBundle = _getUnlinkedOrSchedule(package);
- if (unlinkedBundle != null) {
- unlinkedBundles[package] = unlinkedBundle;
- }
+ PubPackage package = new PubPackage(packageName, libFolder);
+ PackageBundle unlinkedBundle =
+ _getUnlinkedOrSchedule(package, strong);
+ if (unlinkedBundle != null) {
+ unlinkedBundles[package] = unlinkedBundle;
}
}
});
@@ -212,7 +329,8 @@
void _computeNextUnlinked() {
if (packagesToComputeUnlinked.isNotEmpty) {
PubPackage package = packagesToComputeUnlinked.first;
- _computeUnlinked(package);
+ _computeUnlinked(package, false);
+ _computeUnlinked(package, true);
packagesToComputeUnlinked.remove(package);
_scheduleNextUnlinked();
} else {
@@ -229,7 +347,7 @@
*
* TODO(scheglov) Consider moving into separate isolate(s).
*/
- void _computeUnlinked(PubPackage package) {
+ void _computeUnlinked(PubPackage package, bool strong) {
Folder libFolder = package.libFolder;
String libPath = libFolder.path + pathContext.separator;
PackageBundleAssembler assembler = new PackageBundleAssembler();
@@ -253,7 +371,7 @@
if (AnalysisEngine.isDartFileName(path)) {
Uri uri = getUri(path);
Source source = file.createSource(uri);
- CompilationUnit unit = _parse(source);
+ CompilationUnit unit = _parse(source, strong);
UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
assembler.addUnlinkedUnit(source, unlinkedUnit);
}
@@ -279,41 +397,56 @@
try {
addDartFiles(libFolder);
List<int> bytes = assembler.assemble().toBuffer();
- _writeAtomic(package.folder, UNLINKED_BUNDLE_FILE_NAME, bytes);
+ String fileName = _getUnlinkedName(strong);
+ _writeAtomic(package.folder, fileName, bytes);
} on FileSystemException {
// Ignore file system exceptions.
}
}
/**
+ * Return the name of the file for an unlinked bundle, in strong or spec mode.
+ */
+ String _getUnlinkedName(bool strong) {
+ if (strong) {
+ return UNLINKED_NAME;
+ } else {
+ return UNLINKED_SPEC_NAME;
+ }
+ }
+
+ /**
* Return the unlinked [PackageBundle] for the given [package]. If the bundle
* has not been compute yet, return `null` and schedule its computation.
*/
- PackageBundle _getUnlinkedOrSchedule(PubPackage package) {
+ PackageBundle _getUnlinkedOrSchedule(PubPackage package, bool strong) {
// Try to find in the cache.
PackageBundle bundle = unlinkedBundleMap[package];
if (bundle != null) {
return bundle;
}
// Try to read from the file system.
- File unlinkedFile =
- package.folder.getChildAssumingFile(UNLINKED_BUNDLE_FILE_NAME);
+ String fileName = _getUnlinkedName(strong);
+ File unlinkedFile = package.folder.getChildAssumingFile(fileName);
if (unlinkedFile.exists) {
try {
List<int> bytes = unlinkedFile.readAsBytesSync();
bundle = new PackageBundle.fromBuffer(bytes);
unlinkedBundleMap[package] = bundle;
+ // TODO(scheglov) if not in the pub cache, check for consistency
return bundle;
} on FileSystemException {
// Ignore file system exceptions.
}
}
- // Schedule computation in the background.
- if (package != null && seenPackages.add(package)) {
- if (packagesToComputeUnlinked.isEmpty) {
- _scheduleNextUnlinked();
+ // Schedule computation in the background, if in the pub cache.
+ if (isPathInPubCache(pathContext, package.folder.path)) {
+ if (seenPackages.add(package)) {
+ if (packagesToComputeUnlinked.isEmpty) {
+ _scheduleNextUnlinked();
+ }
+ packagesToComputeUnlinked.add(package);
}
- packagesToComputeUnlinked.add(package);
}
// The bundle is for available.
return null;
@@ -322,14 +455,16 @@
/**
* Parse the given [source] into AST.
*/
- CompilationUnit _parse(Source source) {
+ CompilationUnit _parse(Source source, bool strong) {
String code = source.contents.data;
AnalysisErrorListener errorListener = AnalysisErrorListener.NULL_LISTENER;
CharSequenceReader reader = new CharSequenceReader(code);
Scanner scanner = new Scanner(source, reader, errorListener);
+ scanner.scanGenericMethodComments = strong;
Token token = scanner.tokenize();
LineInfo lineInfo = new LineInfo(scanner.lineStarts);
Parser parser = new Parser(source, errorListener);
+ parser.parseGenericMethodComments = strong;
CompilationUnit unit = parser.parseCompilationUnit(token);
unit.lineInfo = lineInfo;
return unit;
@@ -356,6 +491,23 @@
}
/**
+ * If the given [uri] has the `package` scheme, return the name of the
+ * package that contains the referenced resource. Otherwise return `null`.
+ *
+ * For example `package:foo/bar.dart` => `foo`.
+ */
+ static String getPackageName(String uri) {
+ const String PACKAGE_SCHEME = 'package:';
+ if (uri.startsWith(PACKAGE_SCHEME)) {
+ int index = uri.indexOf('/');
+ if (index != -1) {
+ return uri.substring(PACKAGE_SCHEME.length, index);
+ }
+ }
+ return null;
+ }
+
+ /**
* Return `true` if the given absolute [path] is in the pub cache.
*/
static bool isPathInPubCache(pathos.Context pathContext, String path) {
@@ -378,34 +530,57 @@
class _LinkedNode extends Node<_LinkedNode> {
final PubPackage package;
final PackageBundle unlinked;
- final Map<String, _LinkedNode> uriToNode;
+ final Map<String, _LinkedNode> packageToNode;
PackageBundleBuilder linkedBuilder;
bool failed = false;
- _LinkedNode(this.package, this.unlinked, this.uriToNode);
+ _LinkedNode(this.package, this.unlinked, this.packageToNode);
@override
bool get isEvaluated => linkedBuilder != null || failed;
@override
List<_LinkedNode> computeDependencies() {
- Set<String> referencedUris = new Set<String>();
- for (UnlinkedUnit unit in unlinked.unlinkedUnits) {
- for (UnlinkedImport import in unit.imports) {
- String uri = import.isImplicit ? 'dart:core' : import.uri;
- if (uri.startsWith('dart:')) {
- // Ignore SDK imports.
- } else if (uri.startsWith('package:')) {
- referencedUris.add(uri);
- } else {
+ if (failed) {
+ return const <_LinkedNode>[];
+ }
+
+ Set<_LinkedNode> dependencies = new Set<_LinkedNode>();
+
+ void appendDependency(String uriStr) {
+ Uri uri = FastUri.parse(uriStr);
+ if (!uri.hasScheme) {
+ // A relative path in this package, skip it.
+ } else if (uri.scheme == 'dart') {
+ // Dependency on the SDK is implicit and always added.
+ // The SDK linked bundle is precomputed before linking packages.
+ } else if (uriStr.startsWith('package:')) {
+ String package = PubSummaryManager.getPackageName(uriStr);
+ _LinkedNode packageNode = packageToNode[package];
+ if (packageNode == null) {
failed = true;
- return const <_LinkedNode>[];
+ throw new _LinkException();
}
+ dependencies.add(packageNode);
+ } else {
+ failed = true;
+ throw new _LinkException();
}
}
- // TODO(scheglov) fail if no corresponding node
- return referencedUris.map((uri) => uriToNode[uri]).toSet().toList();
+
+ for (UnlinkedUnit unit in unlinked.unlinkedUnits) {
+ for (UnlinkedImport import in unit.imports) {
+ if (!import.isImplicit) {
+ appendDependency(import.uri);
+ }
+ }
+ for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
+ appendDependency(export.uri);
+ }
+ }
+
+ return dependencies.toList();
}
@override
@@ -417,40 +592,57 @@
*/
class _LinkedWalker extends DependencyWalker<_LinkedNode> {
final SummaryDataStore store;
+ final bool strong;
- _LinkedWalker(this.store);
+ _LinkedWalker(this.store, this.strong);
@override
- void evaluate(_LinkedNode v) {
- Set<String> libraryUris = v.unlinked.unlinkedUnitUris.toSet();
- Map<String, LinkedLibraryBuilder> map = link(libraryUris, (String absUri) {
- LinkedLibrary dependencyLibrary = store.linkedMap[absUri];
- if (dependencyLibrary == null) {
- // TODO(scheglov) add test
- v.failed = true;
- }
- return dependencyLibrary;
- }, (String absUri) {
- UnlinkedUnit unlinkedUnit = store.unlinkedMap[absUri];
- if (unlinkedUnit == null) {
- // TODO(scheglov) add test
- v.failed = true;
- }
- return unlinkedUnit;
- }, false);
- if (!v.failed) {
- PackageBundleAssembler assembler = new PackageBundleAssembler();
- map.forEach((uri, linkedLibrary) {
- assembler.addLinkedLibrary(uri, linkedLibrary);
- });
- v.linkedBuilder = assembler.assemble();
- store.addBundle(null, v.linkedBuilder);
- }
+ void evaluate(_LinkedNode node) {
+ evaluateScc([node]);
}
@override
void evaluateScc(List<_LinkedNode> scc) {
- print('evaluateScc: $scc');
- // TODO(scheglov): implement evaluateScc
+ Map<String, _LinkedNode> uriToNode = <String, _LinkedNode>{};
+ for (_LinkedNode node in scc) {
+ for (String uri in node.unlinked.unlinkedUnitUris) {
+ uriToNode[uri] = node;
+ }
+ }
+ Set<String> libraryUris = uriToNode.keys.toSet();
+ // Perform linking.
+ Map<String, LinkedLibraryBuilder> linkedLibraries =
+ link(libraryUris, (String absoluteUri) {
+ LinkedLibrary dependencyLibrary = store.linkedMap[absoluteUri];
+ if (dependencyLibrary == null) {
+ scc.forEach((node) => node.failed = true);
+ throw new _LinkException();
+ }
+ return dependencyLibrary;
+ }, (String absoluteUri) {
+ UnlinkedUnit unlinkedUnit = store.unlinkedMap[absoluteUri];
+ if (unlinkedUnit == null) {
+ scc.forEach((node) => node.failed = true);
+ throw new _LinkException();
+ }
+ return unlinkedUnit;
+ }, strong);
+ // Assemble linked bundles and put them into the store.
+ for (_LinkedNode node in scc) {
+ PackageBundleAssembler assembler = new PackageBundleAssembler();
+ linkedLibraries.forEach((uri, linkedLibrary) {
+ if (identical(uriToNode[uri], node)) {
+ assembler.addLinkedLibrary(uri, linkedLibrary);
+ }
+ });
+ node.linkedBuilder = assembler.assemble();
+ store.addBundle(null, node.linkedBuilder);
+ }
}
}
+
+/**
+ * This exception is thrown during linking as a signal that linking of the
+ * current bundle cannot be performed, e.g. when a dependency cannot be found.
+ */
+class _LinkException {}
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index e929b67..2df51d4 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -19,6 +19,7 @@
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/testing/ast_factory.dart';
import 'package:analyzer/src/generated/testing/token_factory.dart';
+import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
/**
@@ -151,6 +152,7 @@
e is PropertyAccessorElementImpl ? e.identifier : e.name;
elementsInUnit[id] = e;
}
+
unitElement.accessors.forEach(putElement);
unitElement.enums.forEach(putElement);
unitElement.functions.forEach(putElement);
@@ -204,15 +206,29 @@
return parent.getLibraryElement(uri);
}
return _resynthesizedLibraries.putIfAbsent(uri, () {
- LinkedLibrary serializedLibrary = _getLinkedSummaryOrThrow(uri);
- List<UnlinkedUnit> serializedUnits = <UnlinkedUnit>[
- _getUnlinkedSummaryOrThrow(uri)
- ];
+ LinkedLibrary serializedLibrary = _getLinkedSummaryOrNull(uri);
Source librarySource = _getSource(uri);
+ if (serializedLibrary == null) {
+ LibraryElementImpl libraryElement =
+ new LibraryElementImpl(context, '', -1, 0);
+ libraryElement.synthetic = true;
+ CompilationUnitElementImpl unitElement =
+ new CompilationUnitElementImpl(librarySource.shortName);
+ libraryElement.definingCompilationUnit = unitElement;
+ unitElement.source = librarySource;
+ unitElement.librarySource = librarySource;
+ return libraryElement..synthetic = true;
+ }
+ UnlinkedUnit unlinkedSummary = _getUnlinkedSummaryOrNull(uri);
+ if (unlinkedSummary == null) {
+ throw new StateError('Unable to find unlinked summary: $uri');
+ }
+ List<UnlinkedUnit> serializedUnits = <UnlinkedUnit>[unlinkedSummary];
for (String part in serializedUnits[0].publicNamespace.parts) {
Source partSource = sourceFactory.resolveUri(librarySource, part);
String partAbsUri = partSource.uri.toString();
- serializedUnits.add(_getUnlinkedSummaryOrThrow(partAbsUri));
+ serializedUnits.add(_getUnlinkedSummaryOrNull(partAbsUri) ??
+ new UnlinkedUnitBuilder(codeRange: new CodeRangeBuilder()));
}
_LibraryResynthesizer libraryResynthesizer = new _LibraryResynthesizer(
this, serializedLibrary, serializedUnits, librarySource);
@@ -244,18 +260,14 @@
bool hasLibrarySummary(String uri);
/**
- * Return the [LinkedLibrary] for the given [uri] or throw [StateError] if it
+ * Return the [LinkedLibrary] for the given [uri] or return `null` if it
* could not be found.
*/
- LinkedLibrary _getLinkedSummaryOrThrow(String uri) {
+ LinkedLibrary _getLinkedSummaryOrNull(String uri) {
if (parent != null && parent._hasLibrarySummary(uri)) {
- return parent._getLinkedSummaryOrThrow(uri);
+ return parent._getLinkedSummaryOrNull(uri);
}
- LinkedLibrary summary = getLinkedSummary(uri);
- if (summary != null) {
- return summary;
- }
- throw new StateError('Unable to find linked summary: $uri');
+ return getLinkedSummary(uri);
}
/**
@@ -266,18 +278,14 @@
}
/**
- * Return the [UnlinkedUnit] for the given [uri] or throw [StateError] if it
+ * Return the [UnlinkedUnit] for the given [uri] or return `null` if it
* could not be found.
*/
- UnlinkedUnit _getUnlinkedSummaryOrThrow(String uri) {
+ UnlinkedUnit _getUnlinkedSummaryOrNull(String uri) {
if (parent != null && parent._hasLibrarySummary(uri)) {
- return parent._getUnlinkedSummaryOrThrow(uri);
+ return parent._getUnlinkedSummaryOrNull(uri);
}
- UnlinkedUnit summary = getUnlinkedSummary(uri);
- if (summary != null) {
- return summary;
- }
- throw new StateError('Unable to find unlinked summary: $uri');
+ return getUnlinkedSummary(uri);
}
/**
@@ -1277,12 +1285,23 @@
InterfaceTypeImpl type =
new InterfaceTypeImpl.elementWithNameAndArgs(element, name, () {
if (typeArguments == null) {
- typeArguments = element.typeParameters.map((typeParameter) {
- DartType bound = typeParameter.bound;
- return libraryResynthesizer.summaryResynthesizer.strongMode &&
- instantiateToBoundsAllowed &&
- bound != null ? bound : DynamicTypeImpl.instance;
- }).toList();
+ typeArguments = element.typeParameters
+ .map/*<DartType>*/((_) => DynamicTypeImpl.instance)
+ .toList();
+ if (libraryResynthesizer.summaryResynthesizer.strongMode &&
+ instantiateToBoundsAllowed) {
+ List<DartType> typeParameterTypes;
+ for (int i = 0; i < typeArguments.length; i++) {
+ DartType bound = element.typeParameters[i].bound;
+ if (bound != null) {
+ typeParameterTypes ??= element.typeParameters
+ .map/*<DartType>*/((TypeParameterElement e) => e.type)
+ .toList();
+ typeArguments[i] =
+ bound.substitute2(typeArguments, typeParameterTypes);
+ }
+ }
+ }
}
return typeArguments;
});
@@ -1573,6 +1592,7 @@
return DynamicTypeImpl.instance;
}
}
+
_ReferenceInfo referenceInfo = getReferenceInfo(type.reference);
return referenceInfo.buildType(
instantiateToBoundsAllowed,
diff --git a/pkg/analyzer/lib/src/summary/summary_file_builder.dart b/pkg/analyzer/lib/src/summary/summary_file_builder.dart
index 3cd21f1..682973c 100644
--- a/pkg/analyzer/lib/src/summary/summary_file_builder.dart
+++ b/pkg/analyzer/lib/src/summary/summary_file_builder.dart
@@ -5,14 +5,15 @@
library analyzer.src.summary.summary_file_builder;
import 'dart:collection';
-import 'dart:io';
+import 'dart:io' as io;
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/flat_buffers.dart' as fb;
import 'package:analyzer/src/summary/index_unit.dart';
@@ -34,14 +35,14 @@
// Write summary.
{
String outputPath = join(outputDirectoryPath, '$modeName.sum');
- File file = new File(outputPath);
- file.writeAsBytesSync(sum, mode: FileMode.WRITE_ONLY);
+ io.File file = new io.File(outputPath);
+ file.writeAsBytesSync(sum, mode: io.FileMode.WRITE_ONLY);
}
// Write index.
{
String outputPath = join(outputDirectoryPath, '$modeName.index');
- File file = new File(outputPath);
- file.writeAsBytesSync(index, mode: FileMode.WRITE_ONLY);
+ io.File file = new io.File(outputPath);
+ file.writeAsBytesSync(index, mode: io.FileMode.WRITE_ONLY);
}
}
}
@@ -50,7 +51,6 @@
* Summary build configuration.
*/
class SummaryBuildConfig {
-
/**
* Whether to use exclude informative data from created summaries.
*/
@@ -115,8 +115,9 @@
//
// Prepare SDK.
//
- DirectoryBasedDartSdk sdk =
- new DirectoryBasedDartSdk(new JavaFile(sdkPath), strongMode);
+ ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
+ FolderBasedDartSdk sdk = new FolderBasedDartSdk(resourceProvider,
+ FolderBasedDartSdk.defaultSdkDirectory(resourceProvider), strongMode);
sdk.useSummary = false;
sdk.analysisOptions = new AnalysisOptionsImpl()..strongMode = strongMode;
@@ -153,7 +154,7 @@
* Write this summary output to the given [outputPath] and return the
* created file.
*/
- File write(String outputPath) {
+ io.File write(String outputPath) {
fb.Builder builder = new fb.Builder();
fb.Offset specSumOffset = builder.writeListUint8(spec.sum);
fb.Offset specIndexOffset = builder.writeListUint8(spec.index);
@@ -165,8 +166,8 @@
builder.addOffset(FIELD_STRONG_SUM, strongSumOffset);
builder.addOffset(FIELD_STRONG_INDEX, strongIndexOffset);
fb.Offset offset = builder.endTable();
- return new File(outputPath)
- ..writeAsBytesSync(builder.finish(offset), mode: FileMode.WRITE_ONLY);
+ return new io.File(outputPath)
+ ..writeAsBytesSync(builder.finish(offset), mode: io.FileMode.WRITE_ONLY);
}
}
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 1ac305e..1ed904c 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -6,6 +6,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/file_system/file_system.dart' show ResourceProvider;
import 'package:analyzer/src/context/cache.dart' show CacheEntry;
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/element/type.dart';
@@ -20,7 +21,6 @@
import 'package:analyzer/src/summary/resynthesize.dart';
import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/task/model.dart' show ResultDescriptor, TargetedResult;
-import 'package:analyzer/file_system/file_system.dart' show ResourceProvider;
class SdkSummaryResultProvider extends ResynthesizerResultProvider {
final SummaryTypeProvider typeProvider = new SummaryTypeProvider();
@@ -169,6 +169,9 @@
}
@override
+ PackageBundle getLinkedBundle() => _bundle;
+
+ @override
SdkLibrary getSdkLibrary(String uri) {
// This is not quite correct, but currently it's used only in
// to report errors on importing or exporting of internal libraries.
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index c8b108b..da8fcec 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -956,6 +956,28 @@
'SCAN_ERRORS', AnalysisError.NO_ERRORS);
/**
+ * The errors produced while resolving a static [VariableElement] initializer.
+ *
+ * The result is only available for [VariableElement]s, and only when strong
+ * mode is enabled.
+ */
+final ListResultDescriptor<AnalysisError> STATIC_VARIABLE_RESOLUTION_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'STATIC_VARIABLE_RESOLUTION_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
+ * A list of the [AnalysisError]s reported while resolving static
+ * [INFERABLE_STATIC_VARIABLES_IN_UNIT] defined in a unit.
+ *
+ * The result is only available for [LibrarySpecificUnit]s, and only when strong
+ * mode is enabled.
+ */
+final ListResultDescriptor<AnalysisError>
+ STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT =
+ new ListResultDescriptor<AnalysisError>(
+ 'STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT', null);
+
+/**
* The additional strong mode errors produced while verifying a
* compilation unit.
*
@@ -1470,6 +1492,11 @@
static const String PARTS_UNIT_INPUT = 'PARTS_UNIT_INPUT';
/**
+ * The name of the input whose value is the modification time of the source.
+ */
+ static const String MODIFICATION_TIME_INPUT = 'MODIFICATION_TIME_INPUT';
+
+ /**
* The task descriptor describing this kind of task.
*/
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
@@ -1505,6 +1532,7 @@
CompilationUnit definingCompilationUnit =
getRequiredInput(DEFINING_UNIT_INPUT);
List<CompilationUnit> partUnits = getRequiredInput(PARTS_UNIT_INPUT);
+ int modificationTime = getRequiredInput(MODIFICATION_TIME_INPUT);
//
// Process inputs.
//
@@ -1625,6 +1653,7 @@
if (libraryElement == null) {
libraryElement =
new LibraryElementImpl.forNode(owningContext, libraryNameNode);
+ libraryElement.synthetic = modificationTime < 0;
libraryElement.definingCompilationUnit = definingCompilationUnitElement;
libraryElement.entryPoint = entryPoint;
libraryElement.parts = sourcedCompilationUnits;
@@ -1723,7 +1752,8 @@
RESOLVED_UNIT1.of(new LibrarySpecificUnit(source, source)),
PARTS_UNIT_INPUT: INCLUDED_PARTS.of(source).toList((Source unit) {
return RESOLVED_UNIT1.of(new LibrarySpecificUnit(source, unit));
- })
+ }),
+ MODIFICATION_TIME_INPUT: MODIFICATION_TIME.of(source)
};
}
@@ -3627,10 +3657,10 @@
static const String UNIT_INPUT = 'UNIT_INPUT';
/**
- * The name of the input whose value is a list of the inferable static
- * variables whose types have been computed.
+ * The name of the [STATIC_VARIABLE_RESOLUTION_ERRORS] for all static
+ * variables in the compilation unit.
*/
- static const String INFERRED_VARIABLES_INPUT = 'INFERRED_VARIABLES_INPUT';
+ static const String ERRORS_LIST_INPUT = 'INFERRED_VARIABLES_INPUT';
/**
* The task descriptor describing this kind of task.
@@ -3638,8 +3668,11 @@
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
'InferStaticVariableTypesInUnitTask',
createTask,
- buildInputs,
- <ResultDescriptor>[CREATED_RESOLVED_UNIT9, RESOLVED_UNIT9]);
+ buildInputs, <ResultDescriptor>[
+ CREATED_RESOLVED_UNIT9,
+ RESOLVED_UNIT9,
+ STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT
+ ]);
/**
* Initialize a newly created task to build a library element for the given
@@ -3658,6 +3691,7 @@
// Prepare inputs.
//
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ List<List<AnalysisError>> errorLists = getRequiredInput(ERRORS_LIST_INPUT);
//
// Record outputs. There is no additional work to be done at this time
// because the work has implicitly been done by virtue of the task model
@@ -3665,6 +3699,8 @@
//
outputs[RESOLVED_UNIT9] = unit;
outputs[CREATED_RESOLVED_UNIT9] = true;
+ outputs[STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT] =
+ AnalysisError.mergeLists(errorLists);
}
/**
@@ -3675,9 +3711,12 @@
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
LibrarySpecificUnit unit = target;
return <String, TaskInput>{
- INFERRED_VARIABLES_INPUT: INFERABLE_STATIC_VARIABLES_IN_UNIT
+ 'inferredTypes': INFERABLE_STATIC_VARIABLES_IN_UNIT
.of(unit)
.toListOf(INFERRED_STATIC_VARIABLE),
+ ERRORS_LIST_INPUT: INFERABLE_STATIC_VARIABLES_IN_UNIT
+ .of(unit)
+ .toListOf(STATIC_VARIABLE_RESOLUTION_ERRORS),
UNIT_INPUT: RESOLVED_UNIT8.of(unit)
};
}
@@ -3716,8 +3755,10 @@
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
'InferStaticVariableTypeTask',
createTask,
- buildInputs,
- <ResultDescriptor>[INFERRED_STATIC_VARIABLE]);
+ buildInputs, <ResultDescriptor>[
+ INFERRED_STATIC_VARIABLE,
+ STATIC_VARIABLE_RESOLUTION_ERRORS
+ ]);
InferStaticVariableTypeTask(
InternalAnalysisContext context, VariableElement variable)
@@ -3745,17 +3786,19 @@
// If we're not in a dependency cycle, and we have no type annotation,
// re-resolve the right hand side and do inference.
+ List<AnalysisError> errors = AnalysisError.NO_ERRORS;
if (dependencyCycle == null && variable.hasImplicitType) {
VariableDeclaration declaration = getDeclaration(unit);
//
// Re-resolve the variable's initializer so that the inferred types
// of other variables will be propagated.
//
+ RecordingErrorListener errorListener = new RecordingErrorListener();
Expression initializer = declaration.initializer;
ResolutionContext resolutionContext = ResolutionContextBuilder.contextFor(
initializer, AnalysisErrorListener.NULL_LISTENER);
- ResolverVisitor visitor = new ResolverVisitor(variable.library,
- variable.source, typeProvider, AnalysisErrorListener.NULL_LISTENER,
+ ResolverVisitor visitor = new ResolverVisitor(
+ variable.library, variable.source, typeProvider, errorListener,
nameScope: resolutionContext.scope);
if (resolutionContext.enclosingClassDeclaration != null) {
visitor.prepareToResolveMembersInClass(
@@ -3772,6 +3815,7 @@
newType = typeProvider.dynamicType;
}
setFieldType(variable, newType);
+ errors = getUniqueErrors(errorListener.errors);
} else {
// TODO(brianwilkerson) For now we simply don't infer any type for
// variables or fields involved in a cycle. We could try to be smarter
@@ -3784,6 +3828,7 @@
// Record outputs.
//
outputs[INFERRED_STATIC_VARIABLE] = variable;
+ outputs[STATIC_VARIABLE_RESOLUTION_ERRORS] = errors;
}
/**
@@ -3898,6 +3943,12 @@
static const String LINTS_INPUT = 'LINTS';
/**
+ * The name of the [STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT] input.
+ */
+ static const String STATIC_VARIABLE_RESOLUTION_ERRORS_INPUT =
+ 'STATIC_VARIABLE_RESOLUTION_ERRORS_INPUT';
+
+ /**
* The name of the [STRONG_MODE_ERRORS] input.
*/
static const String STRONG_MODE_ERRORS_INPUT = 'STRONG_MODE_ERRORS';
@@ -3958,6 +4009,7 @@
errorLists.add(getRequiredInput(RESOLVE_TYPE_NAMES_ERRORS_INPUT));
errorLists.add(getRequiredInput(RESOLVE_TYPE_NAMES_ERRORS2_INPUT));
errorLists.add(getRequiredInput(RESOLVE_UNIT_ERRORS_INPUT));
+ errorLists.add(getRequiredInput(STATIC_VARIABLE_RESOLUTION_ERRORS_INPUT));
errorLists.add(getRequiredInput(STRONG_MODE_ERRORS_INPUT));
errorLists.add(getRequiredInput(VARIABLE_REFERENCE_ERRORS_INPUT));
errorLists.add(getRequiredInput(VERIFY_ERRORS_INPUT));
@@ -3980,6 +4032,8 @@
RESOLVE_TYPE_NAMES_ERRORS_INPUT: RESOLVE_TYPE_NAMES_ERRORS.of(unit),
RESOLVE_TYPE_NAMES_ERRORS2_INPUT: RESOLVE_TYPE_BOUNDS_ERRORS.of(unit),
RESOLVE_UNIT_ERRORS_INPUT: RESOLVE_UNIT_ERRORS.of(unit),
+ STATIC_VARIABLE_RESOLUTION_ERRORS_INPUT:
+ STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT.of(unit),
STRONG_MODE_ERRORS_INPUT: STRONG_MODE_ERRORS.of(unit),
VARIABLE_REFERENCE_ERRORS_INPUT: VARIABLE_REFERENCE_ERRORS.of(unit),
VERIFY_ERRORS_INPUT: VERIFY_ERRORS.of(unit)
@@ -6443,8 +6497,38 @@
}
}
StringLiteral uriLiteral = directive.uri;
- errorReporter.reportErrorForNode(CompileTimeErrorCode.URI_DOES_NOT_EXIST,
- uriLiteral, [directive.uriContent]);
+ CompileTimeErrorCode errorCode = CompileTimeErrorCode.URI_DOES_NOT_EXIST;
+ if (_isGenerated(source)) {
+ errorCode = CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED;
+ }
+ errorReporter
+ .reportErrorForNode(errorCode, uriLiteral, [directive.uriContent]);
+ }
+
+ /**
+ * Return `true` if the given [source] refers to a file that is assumed to be
+ * generated.
+ */
+ bool _isGenerated(Source source) {
+ if (source == null) {
+ return false;
+ }
+ // TODO(brianwilkerson) Generalize this mechanism.
+ const List<String> suffixes = const <String>[
+ '.g.dart',
+ '.pb.dart',
+ '.pbenum.dart',
+ '.pbserver.dart',
+ '.pbjson.dart',
+ '.template.dart'
+ ];
+ String fullName = source.fullName;
+ for (String suffix in suffixes) {
+ if (fullName.endsWith(suffix)) {
+ return true;
+ }
+ }
+ return false;
}
/**
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index ab1922f..57b1cc2 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -29,6 +29,27 @@
element is MethodElement && element.isStatic;
}
+/// Given an [expression] and a corresponding [typeSystem] and [typeProvider],
+/// gets the known static type of the expression.
+///
+/// Normally when we ask for an expression's type, we get the type of the
+/// storage slot that would contain it. For function types, this is necessarily
+/// a "fuzzy arrow" that treats `dynamic` as bottom. However, if we're
+/// interested in the expression's own type, it can often be a "strict arrow"
+/// because we know it evaluates to a specific, concrete function, and we can
+/// treat "dynamic" as top for that case, which is more permissive.
+DartType getDefiniteType(
+ Expression expression, TypeSystem typeSystem, TypeProvider typeProvider) {
+ DartType type = expression.staticType ?? DynamicTypeImpl.instance;
+ if (typeSystem is StrongTypeSystemImpl &&
+ type is FunctionType &&
+ _hasStrictArrow(expression)) {
+ // Remove fuzzy arrow if possible.
+ return typeSystem.functionTypeToConcreteType(typeProvider, type);
+ }
+ return type;
+}
+
bool _hasStrictArrow(Expression expression) {
var element = _getKnownElement(expression);
return element is FunctionElement || element is MethodElement;
@@ -187,14 +208,15 @@
void checkBoolean(Expression expr) =>
checkAssignment(expr, typeProvider.boolType);
- void checkFunctionApplication(
- Expression node, Expression f, ArgumentList list) {
- if (_isDynamicCall(f)) {
+ void checkFunctionApplication(InvocationExpression node) {
+ var ft = _getTypeAsCaller(node);
+
+ if (_isDynamicCall(node, ft)) {
// If f is Function and this is a method invocation, we should have
// gotten an analyzer error, so no need to issue another error.
- _recordDynamicInvoke(node, f);
+ _recordDynamicInvoke(node, node.function);
} else {
- checkArgumentList(list, _getTypeAsCaller(f));
+ checkArgumentList(node.argumentList, ft);
}
}
@@ -220,7 +242,7 @@
TokenType operatorType = operator.type;
if (operatorType == TokenType.EQ ||
operatorType == TokenType.QUESTION_QUESTION_EQ) {
- DartType staticType = _getStaticType(node.leftHandSide);
+ DartType staticType = _getDefiniteType(node.leftHandSide);
checkAssignment(node.rightHandSide, staticType);
} else if (operatorType == TokenType.AMPERSAND_AMPERSAND_EQ ||
operatorType == TokenType.BAR_BAR_EQ) {
@@ -377,7 +399,7 @@
var sequenceInterface = node.awaitKeyword != null
? typeProvider.streamType
: typeProvider.iterableType;
- var iterableType = _getStaticType(node.iterable);
+ var iterableType = _getDefiniteType(node.iterable);
var elementType =
rules.mostSpecificTypeArgument(iterableType, sequenceInterface);
@@ -399,7 +421,7 @@
if (elementType != null) {
// Insert a cast from the sequence's element type to the loop variable's
// if needed.
- _checkDowncast(loopVariable, _getStaticType(loopVariable),
+ _checkDowncast(loopVariable, _getDefiniteType(loopVariable),
from: elementType);
}
}
@@ -423,7 +445,7 @@
@override
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
- checkFunctionApplication(node, node.function, node.argumentList);
+ checkFunctionApplication(node);
node.visitChildren(this);
}
@@ -550,7 +572,7 @@
// we call [checkFunctionApplication].
setIsDynamicInvoke(node.methodName, true);
} else {
- checkFunctionApplication(node, node.methodName, node.argumentList);
+ checkFunctionApplication(node);
}
node.visitChildren(this);
}
@@ -680,8 +702,8 @@
assert(functionType.optionalParameterTypes.isEmpty);
// Check the LHS type.
- var rhsType = _getStaticType(expr.rightHandSide);
- var lhsType = _getStaticType(expr.leftHandSide);
+ var rhsType = _getDefiniteType(expr.rightHandSide);
+ var lhsType = _getDefiniteType(expr.leftHandSide);
var returnType = rules.refineBinaryExpressionType(
typeProvider, lhsType, op, rhsType, functionType.returnType);
@@ -718,7 +740,7 @@
/// or is already a subtype of it, does nothing.
void _checkDowncast(Expression expr, DartType to, {DartType from}) {
if (from == null) {
- from = _getStaticType(expr);
+ from = _getDefiniteType(expr);
}
// We can use anything as void.
@@ -727,14 +749,10 @@
// fromT <: toT, no coercion needed.
if (rules.isSubtypeOf(from, to)) return;
- // TODO(vsm): We can get rid of the second clause if we disallow
- // all sideways casts - see TODO below.
- // -------
// Note: a function type is never assignable to a class per the Dart
// spec - even if it has a compatible call method. We disallow as
// well for consistency.
- if ((from is FunctionType && rules.getCallMethodType(to) != null) ||
- (to is FunctionType && rules.getCallMethodType(from) != null)) {
+ if (from is FunctionType && rules.getCallMethodType(to) != null) {
return;
}
@@ -744,19 +762,9 @@
return;
}
- // TODO(vsm): Once we have generic methods, we should delete this
- // workaround. These sideways casts are always ones we warn about
- // - i.e., we think they are likely to fail at runtime.
- // -------
- // Downcast if toT <===> fromT
- // The intention here is to allow casts that are sideways in the restricted
- // type system, but allowed in the regular dart type system, since these
- // are likely to succeed. The canonical example is List<dynamic> and
- // Iterable<T> for some concrete T (e.g. Object). These are unrelated
- // in the restricted system, but List<dynamic> <: Iterable<T> in dart.
- if (from.isAssignableTo(to)) {
- _recordImplicitCast(expr, from, to);
- }
+ // Anything else is an illegal sideways cast.
+ // However, these will have been reported already in error_verifier, so we
+ // don't need to report them again.
}
void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) {
@@ -968,42 +976,26 @@
}
}
- DartType _getStaticType(Expression expr) {
- DartType t = expr.staticType ?? DynamicTypeImpl.instance;
-
- // Remove fuzzy arrow if possible.
- if (t is FunctionType && _hasStrictArrow(expr)) {
- t = rules.functionTypeToConcreteType(typeProvider, t);
- }
-
- return t;
- }
+ DartType _getDefiniteType(Expression expr) =>
+ getDefiniteType(expr, rules, typeProvider);
/// Given an expression, return its type assuming it is
/// in the caller position of a call (that is, accounting
/// for the possibility of a call method). Returns null
/// if expression is not statically callable.
- FunctionType _getTypeAsCaller(Expression node) {
- DartType t = _getStaticType(node);
- if (node is SimpleIdentifier) {
- Expression parent = node.parent;
- if (parent is MethodInvocation) {
- t = parent.staticInvokeType;
- }
- }
- if (t is InterfaceType) {
- return rules.getCallMethodType(t);
- }
- if (t is FunctionType) {
- return t;
+ FunctionType _getTypeAsCaller(InvocationExpression node) {
+ DartType type = node.staticInvokeType;
+ if (type is FunctionType) {
+ return type;
+ } else if (type is InterfaceType) {
+ return rules.getCallMethodType(type);
}
return null;
}
/// Returns `true` if the expression is a dynamic function call or method
/// invocation.
- bool _isDynamicCall(Expression call) {
- var ft = _getTypeAsCaller(call);
+ bool _isDynamicCall(InvocationExpression call, FunctionType ft) {
// TODO(leafp): This will currently return true if t is Function
// This is probably the most correct thing to do for now, since
// this code is also used by the back end. Maybe revisit at some
@@ -1013,7 +1005,7 @@
// a dynamic parameter type requires a dynamic call in general.
// However, as an optimization, if we have an original definition, we know
// dynamic is reified as Object - in this case a regular call is fine.
- if (_hasStrictArrow(call)) {
+ if (_hasStrictArrow(call.function)) {
return false;
}
return rules.anyParameterType(ft, (pt) => pt.isDynamic);
@@ -1051,7 +1043,7 @@
// toT <:_R fromT => to <: fromT
// NB: classes with call methods are subtypes of function
// types, but the function type is not assignable to the class
- assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
+ assert(toType.isSubtypeOf(fromType));
// Inference "casts":
if (expression is Literal || expression is FunctionExpression) {
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 1988ae1..22d0910 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.27.5-alpha.0
+version: 0.28.0-alpha.0
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
diff --git a/pkg/analyzer/test/file_system/physical_resource_provider_test.dart b/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
index e1f4a00..a7c7c1f 100644
--- a/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
+++ b/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
@@ -180,12 +180,6 @@
expect(file.exists, isTrue);
}
- void test_toUri() {
- String path = '/foo/file.txt';
- File file = PhysicalResourceProvider.INSTANCE.getFile(path);
- expect(file.toUri(), new Uri.file(path));
- }
-
void test_shortName() {
expect(file.shortName, 'file.txt');
}
@@ -194,6 +188,12 @@
expect(file.toString(), path);
}
+ void test_toUri() {
+ String path = '/foo/file.txt';
+ File file = PhysicalResourceProvider.INSTANCE.getFile(path);
+ expect(file.toUri(), new Uri.file(path));
+ }
+
void test_writeAsBytesSync() {
new io.File(path).writeAsBytesSync(<int>[1, 2]);
expect(file.readAsBytesSync(), <int>[1, 2]);
@@ -389,6 +389,13 @@
@reflectiveTest
class PhysicalResourceProviderTest extends _BaseTest {
+ test_getFolder_trailingSeparator() {
+ String path = tempPath;
+ PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE;
+ Folder folder = provider.getFolder('$path$separator');
+ expect(folder.path, path);
+ }
+
test_getModificationTimes() async {
PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE;
String path = join(tempPath, 'file1.txt');
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 63fdd85..0f06f13 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -14,6 +14,7 @@
import 'package:analyzer/src/dart/ast/utilities.dart' hide ConstantEvaluator;
import 'package:analyzer/src/dart/element/builder.dart';
import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart' hide SdkLibrariesReader;
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_core.dart';
@@ -44,6 +45,7 @@
runReflectiveTests(ContentCacheTest);
runReflectiveTests(CustomUriResolverTest);
runReflectiveTests(DartUriResolverTest);
+ // ignore: deprecated_member_use
runReflectiveTests(DirectoryBasedDartSdkTest);
runReflectiveTests(DirectoryBasedSourceContainerTest);
runReflectiveTests(ElementBuilderTest);
@@ -55,6 +57,7 @@
runReflectiveTests(ExitDetectorTest2);
runReflectiveTests(FileBasedSourceTest);
runReflectiveTests(ResolveRelativeUriTest);
+ // ignore: deprecated_member_use
runReflectiveTests(SDKLibrariesReaderTest);
runReflectiveTests(UriKindTest);
}
@@ -85,8 +88,9 @@
}
void test_resolve_unknown_uri() {
- UriResolver resolver =
- new CustomUriResolver({'custom:library': '/path/to/library.dart',});
+ UriResolver resolver = new CustomUriResolver({
+ 'custom:library': '/path/to/library.dart',
+ });
Source result =
resolver.resolveAbsolute(parseUriWithException("custom:non_library"));
expect(result, isNull);
@@ -95,7 +99,9 @@
void test_resolve_uri() {
String path =
FileUtilities2.createFile("/path/to/library.dart").getAbsolutePath();
- UriResolver resolver = new CustomUriResolver({'custom:library': path,});
+ UriResolver resolver = new CustomUriResolver({
+ 'custom:library': path,
+ });
Source result =
resolver.resolveAbsolute(parseUriWithException("custom:library"));
expect(result, isNotNull);
@@ -106,9 +112,7 @@
@reflectiveTest
class DartUriResolverTest {
void test_creation() {
- JavaFile sdkDirectory = DirectoryBasedDartSdk.defaultSdkDirectory;
- expect(sdkDirectory, isNotNull);
- DartSdk sdk = new DirectoryBasedDartSdk(sdkDirectory);
+ DartSdk sdk = _createSdk();
expect(new DartUriResolver(sdk), isNotNull);
}
@@ -119,9 +123,7 @@
}
void test_resolve_dart() {
- JavaFile sdkDirectory = DirectoryBasedDartSdk.defaultSdkDirectory;
- expect(sdkDirectory, isNotNull);
- DartSdk sdk = new DirectoryBasedDartSdk(sdkDirectory);
+ DartSdk sdk = _createSdk();
UriResolver resolver = new DartUriResolver(sdk);
Source result =
resolver.resolveAbsolute(parseUriWithException("dart:core"));
@@ -129,25 +131,29 @@
}
void test_resolve_dart_nonExistingLibrary() {
- JavaFile sdkDirectory = DirectoryBasedDartSdk.defaultSdkDirectory;
- expect(sdkDirectory, isNotNull);
- DartSdk sdk = new DirectoryBasedDartSdk(sdkDirectory);
+ DartSdk sdk = _createSdk();
UriResolver resolver = new DartUriResolver(sdk);
Source result = resolver.resolveAbsolute(parseUriWithException("dart:cor"));
expect(result, isNull);
}
void test_resolve_nonDart() {
- JavaFile sdkDirectory = DirectoryBasedDartSdk.defaultSdkDirectory;
- expect(sdkDirectory, isNotNull);
- DartSdk sdk = new DirectoryBasedDartSdk(sdkDirectory);
+ DartSdk sdk = _createSdk();
UriResolver resolver = new DartUriResolver(sdk);
Source result = resolver
.resolveAbsolute(parseUriWithException("package:some/file.dart"));
expect(result, isNull);
}
+
+ DartSdk _createSdk() {
+ ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
+ Folder sdkFolder = FolderBasedDartSdk.defaultSdkDirectory(resourceProvider);
+ expect(sdkFolder, isNotNull);
+ return new FolderBasedDartSdk(resourceProvider, sdkFolder);
+ }
}
+@deprecated
@reflectiveTest
class DirectoryBasedDartSdkTest {
void fail_getDocFileFor() {
@@ -4310,9 +4316,7 @@
}
void test_isInSystemLibrary_contagious() {
- JavaFile sdkDirectory = DirectoryBasedDartSdk.defaultSdkDirectory;
- expect(sdkDirectory, isNotNull);
- DartSdk sdk = new DirectoryBasedDartSdk(sdkDirectory);
+ DartSdk sdk = _createSdk();
UriResolver resolver = new DartUriResolver(sdk);
SourceFactory factory = new SourceFactory([resolver]);
// resolve dart:core
@@ -4397,76 +4401,69 @@
expect(source.fullName, file.getAbsolutePath());
expect(source.isInSystemLibrary, isTrue);
}
+
+ DartSdk _createSdk() {
+ ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
+ Folder sdkFolder = FolderBasedDartSdk.defaultSdkDirectory(resourceProvider);
+ expect(sdkFolder, isNotNull);
+ return new FolderBasedDartSdk(resourceProvider, sdkFolder);
+ }
}
@reflectiveTest
class ResolveRelativeUriTest {
void test_resolveRelative_dart_dartUri() {
- Uri uri = parseUriWithException('dart:foo');
- Uri relative = resolveRelativeUri(uri, parseUriWithException('dart:bar'));
- expect(relative, isNotNull);
- expect(relative.toString(), 'dart:bar');
+ _assertResolve('dart:foo', 'dart:bar', 'dart:bar');
}
void test_resolveRelative_dart_fileName() {
- Uri uri = parseUriWithException("dart:test");
- Uri relative = resolveRelativeUri(uri, parseUriWithException("lib.dart"));
- expect(relative, isNotNull);
- expect(relative.toString(), "dart:test/lib.dart");
+ _assertResolve('dart:test', 'lib.dart', 'dart:test/lib.dart');
}
void test_resolveRelative_dart_filePath() {
- Uri uri = parseUriWithException("dart:test");
- Uri relative = resolveRelativeUri(uri, parseUriWithException("c/lib.dart"));
- expect(relative, isNotNull);
- expect(relative.toString(), "dart:test/c/lib.dart");
+ _assertResolve('dart:test', 'c/lib.dart', 'dart:test/c/lib.dart');
}
void test_resolveRelative_dart_filePathWithParent() {
- Uri uri = parseUriWithException("dart:test/b/test.dart");
- Uri relative =
- resolveRelativeUri(uri, parseUriWithException("../c/lib.dart"));
- expect(relative, isNotNull);
- expect(relative.toString(), "dart:test/c/lib.dart");
+ _assertResolve(
+ 'dart:test/b/test.dart', '../c/lib.dart', 'dart:test/c/lib.dart');
}
void test_resolveRelative_package_dartUri() {
- Uri uri = parseUriWithException('package:foo/bar.dart');
- Uri relative = resolveRelativeUri(uri, parseUriWithException('dart:test'));
- expect(relative, isNotNull);
- expect(relative.toString(), 'dart:test');
+ _assertResolve('package:foo/bar.dart', 'dart:test', 'dart:test');
+ }
+
+ void test_resolveRelative_package_emptyPath() {
+ _assertResolve('package:foo/bar.dart', '', 'package:foo/bar.dart');
}
void test_resolveRelative_package_fileName() {
- Uri uri = parseUriWithException("package:b/test.dart");
- Uri relative = resolveRelativeUri(uri, parseUriWithException("lib.dart"));
- expect(relative, isNotNull);
- expect(relative.toString(), "package:b/lib.dart");
+ _assertResolve('package:b/test.dart', 'lib.dart', 'package:b/lib.dart');
}
void test_resolveRelative_package_fileNameWithoutPackageName() {
- Uri uri = parseUriWithException("package:test.dart");
- Uri relative = resolveRelativeUri(uri, parseUriWithException("lib.dart"));
- expect(relative, isNotNull);
- expect(relative.toString(), "package:lib.dart");
+ _assertResolve('package:test.dart', 'lib.dart', 'package:lib.dart');
}
void test_resolveRelative_package_filePath() {
- Uri uri = parseUriWithException("package:b/test.dart");
- Uri relative = resolveRelativeUri(uri, parseUriWithException("c/lib.dart"));
- expect(relative, isNotNull);
- expect(relative.toString(), "package:b/c/lib.dart");
+ _assertResolve('package:b/test.dart', 'c/lib.dart', 'package:b/c/lib.dart');
}
void test_resolveRelative_package_filePathWithParent() {
- Uri uri = parseUriWithException("package:a/b/test.dart");
- Uri relative =
- resolveRelativeUri(uri, parseUriWithException("../c/lib.dart"));
- expect(relative, isNotNull);
- expect(relative.toString(), "package:a/c/lib.dart");
+ _assertResolve(
+ 'package:a/b/test.dart', '../c/lib.dart', 'package:a/c/lib.dart');
+ }
+
+ void _assertResolve(String baseStr, String containedStr, String expectedStr) {
+ Uri base = Uri.parse(baseStr);
+ Uri contained = Uri.parse(containedStr);
+ Uri result = resolveRelativeUri(base, contained);
+ expect(result, isNotNull);
+ expect(result.toString(), expectedStr);
}
}
+@deprecated
@reflectiveTest
class SDKLibrariesReaderTest extends EngineTestCase {
void test_readFrom_dart2js() {
diff --git a/pkg/analyzer/test/generated/analysis_context_factory.dart b/pkg/analyzer/test/generated/analysis_context_factory.dart
index f311756..f5cb195 100644
--- a/pkg/analyzer/test/generated/analysis_context_factory.dart
+++ b/pkg/analyzer/test/generated/analysis_context_factory.dart
@@ -10,15 +10,16 @@
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine_io.dart';
-import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk;
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/testing/ast_factory.dart';
import 'package:analyzer/src/generated/testing/element_factory.dart';
@@ -39,46 +40,60 @@
static String _DART_JS_HELPER = "dart:_js_helper";
/**
- * Create an analysis context that has a fake core library already resolved.
- * Return the context that was created.
+ * Create and return an analysis context that has a fake core library already
+ * resolved. The given [resourceProvider] will be used when accessing the file
+ * system.
*/
- static InternalAnalysisContext contextWithCore() {
+ static InternalAnalysisContext contextWithCore(
+ {ResourceProvider resourceProvider}) {
AnalysisContextForTests context = new AnalysisContextForTests();
- return initContextWithCore(context);
+ return initContextWithCore(context, null, resourceProvider);
}
/**
- * Create an analysis context that uses the given [options] and has a fake
- * core library already resolved. Return the context that was created.
+ * Create and return an analysis context that uses the given [options] and has
+ * a fake core library already resolved. The given [resourceProvider] will be
+ * used when accessing the file system.
*/
static InternalAnalysisContext contextWithCoreAndOptions(
- AnalysisOptions options) {
+ AnalysisOptions options,
+ {ResourceProvider resourceProvider}) {
AnalysisContextForTests context = new AnalysisContextForTests();
context._internalSetAnalysisOptions(options);
- return initContextWithCore(context);
- }
-
- static InternalAnalysisContext contextWithCoreAndPackages(
- Map<String, String> packages) {
- AnalysisContextForTests context = new AnalysisContextForTests();
- return initContextWithCore(context, new TestPackageUriResolver(packages));
+ return initContextWithCore(context, null, resourceProvider);
}
/**
- * Initialize the given analysis context with a fake core library already resolved.
- *
- * @param context the context to be initialized (not `null`)
- * @return the analysis context that was created
+ * Create and return an analysis context that has a fake core library already
+ * resolved. If not `null`, the given [packages] map will be used to create a
+ * package URI resolver. The given [resourceProvider] will be used when
+ * accessing the file system.
+ */
+ static InternalAnalysisContext contextWithCoreAndPackages(
+ Map<String, String> packages,
+ {ResourceProvider resourceProvider}) {
+ AnalysisContextForTests context = new AnalysisContextForTests();
+ return initContextWithCore(
+ context, new TestPackageUriResolver(packages), resourceProvider);
+ }
+
+ /**
+ * Initialize the given analysis [context] with a fake core library that has
+ * already been resolved. If not `null`, the given [contributedResolver] will
+ * be added to the context's source factory. The given [resourceProvider] will
+ * be used when accessing the file system.
*/
static InternalAnalysisContext initContextWithCore(
InternalAnalysisContext context,
- [UriResolver contributedResolver]) {
- DirectoryBasedDartSdk sdk = new _AnalysisContextFactory_initContextWithCore(
- new JavaFile("/fake/sdk"),
+ [UriResolver contributedResolver,
+ ResourceProvider resourceProvider]) {
+ resourceProvider ??= PhysicalResourceProvider.INSTANCE;
+ DartSdk sdk = new _AnalysisContextFactory_initContextWithCore(
+ resourceProvider, '/fake/sdk',
enableAsync: context.analysisOptions.enableAsync);
List<UriResolver> resolvers = <UriResolver>[
new DartUriResolver(sdk),
- new FileUriResolver()
+ new ResourceUriResolver(resourceProvider)
];
if (contributedResolver != null) {
resolvers.add(contributedResolver);
@@ -540,12 +555,12 @@
Uri restoreAbsolute(Source source) => throw new UnimplementedError();
}
-class _AnalysisContextFactory_initContextWithCore
- extends DirectoryBasedDartSdk {
+class _AnalysisContextFactory_initContextWithCore extends FolderBasedDartSdk {
final bool enableAsync;
- _AnalysisContextFactory_initContextWithCore(JavaFile arg0,
+ _AnalysisContextFactory_initContextWithCore(
+ ResourceProvider resourceProvider, String sdkPath,
{this.enableAsync: true})
- : super(arg0);
+ : super(resourceProvider, resourceProvider.getFolder(sdkPath));
@override
LibraryMap initialLibraryMap(bool useDart2jsPaths) {
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 3a06df4..10c227e 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -578,6 +578,22 @@
''');
}
+ void test_dartDoc_beforeTopLevelVariable() {
+ _resolveUnit(r'''
+/**
+ * Variables [V1] and [V2] of type [int].
+ */
+int V1, V2;
+''');
+ _updateAndValidate(r'''
+/**
+ * Variables [V1] and [V2] of type [int].
+ * Updated, with a reference to the [String] type.
+ */
+int V1, V2;
+''');
+ }
+
void test_dartDoc_clumsy_addReference() {
_resolveUnit(r'''
/**
diff --git a/pkg/analyzer/test/generated/package_test.dart b/pkg/analyzer/test/generated/package_test.dart
new file mode 100644
index 0000000..dadb9fc
--- /dev/null
+++ b/pkg/analyzer/test/generated/package_test.dart
@@ -0,0 +1,294 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.generated.package_test;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/package.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:package_config/packages.dart';
+import 'package:unittest/unittest.dart';
+
+import '../reflective_tests.dart';
+import '../src/context/mock_sdk.dart';
+import '../utils.dart';
+import 'resolver_test_case.dart';
+
+main() {
+ initializeTestEnvironment();
+ runReflectiveTests(DependencyFinderTest);
+ runReflectiveTests(PackageDescriptionTest);
+ runReflectiveTests(PackageManagerTest);
+}
+
+/**
+ * The name of the pubspec.yaml file.
+ */
+const String pubspecName = 'pubspec.yaml';
+
+@reflectiveTest
+class DependencyFinderTest extends ResolverTestCase {
+ /**
+ * The resource provider to be used by tests.
+ */
+ MemoryResourceProvider resourceProvider;
+
+ @override
+ void setUp() {
+ resourceProvider = new MemoryResourceProvider();
+ }
+
+ void test_transitiveDependenciesFor_circularDependencies() {
+ String packageA = '/pub-cache/a-1.0';
+ String packageB = '/pub-cache/b-1.0';
+ String packageC = '/pub-cache/c-1.0';
+ resourceProvider.newFile(
+ '$packageA/$pubspecName',
+ '''
+ dependencies:
+ b: any
+ ''');
+ resourceProvider.newFile(
+ '$packageB/$pubspecName',
+ '''
+ dependencies:
+ c: any
+ ''');
+ resourceProvider.newFile(
+ '$packageC/$pubspecName',
+ '''
+ dependencies:
+ a: any
+ ''');
+ Map<String, List<Folder>> packageMap = <String, List<Folder>>{
+ 'a': <Folder>[resourceProvider.getFolder(packageA)],
+ 'b': <Folder>[resourceProvider.getFolder(packageB)],
+ 'c': <Folder>[resourceProvider.getFolder(packageC)],
+ };
+
+ DependencyFinder finder = new DependencyFinder(resourceProvider);
+ List<String> result =
+ finder.transitiveDependenciesFor(packageMap, packageA);
+ expect(result, unorderedEquals([packageB, packageC]));
+ }
+
+ void test_transitiveDependenciesFor_missingPubspec() {
+ String packagePath = '/pub-cache/a-1.0';
+ Map<String, List<Folder>> packageMap = <String, List<Folder>>{
+ 'a': <Folder>[resourceProvider.getFolder(packagePath)]
+ };
+
+ DependencyFinder finder = new DependencyFinder(resourceProvider);
+ expect(() => finder.transitiveDependenciesFor(packageMap, packagePath),
+ throws);
+ }
+
+ void test_transitiveDependenciesFor_noDependencies() {
+ String packagePath = '/pub-cache/a-1.0';
+ resourceProvider.newFile('$packagePath/$pubspecName', '');
+ Map<String, List<Folder>> packageMap = <String, List<Folder>>{
+ 'a': <Folder>[resourceProvider.getFolder(packagePath)]
+ };
+
+ DependencyFinder finder = new DependencyFinder(resourceProvider);
+ List<String> result =
+ finder.transitiveDependenciesFor(packageMap, packagePath);
+ expect(result, hasLength(0));
+ }
+
+ void test_transitiveDependenciesFor_overlappingDependencies() {
+ String packageA = '/pub-cache/a-1.0';
+ String packageB = '/pub-cache/b-1.0';
+ String packageC = '/pub-cache/c-1.0';
+ String packageD = '/pub-cache/d-1.0';
+ resourceProvider.newFile(
+ '$packageA/$pubspecName',
+ '''
+ dependencies:
+ b: any
+ c: any
+ ''');
+ resourceProvider.newFile(
+ '$packageB/$pubspecName',
+ '''
+ dependencies:
+ d: any
+ ''');
+ resourceProvider.newFile(
+ '$packageC/$pubspecName',
+ '''
+ dependencies:
+ d: any
+ ''');
+ resourceProvider.newFile('$packageD/$pubspecName', '');
+ Map<String, List<Folder>> packageMap = <String, List<Folder>>{
+ 'a': <Folder>[resourceProvider.getFolder(packageA)],
+ 'b': <Folder>[resourceProvider.getFolder(packageB)],
+ 'c': <Folder>[resourceProvider.getFolder(packageC)],
+ 'd': <Folder>[resourceProvider.getFolder(packageD)],
+ };
+
+ DependencyFinder finder = new DependencyFinder(resourceProvider);
+ List<String> result =
+ finder.transitiveDependenciesFor(packageMap, packageA);
+ expect(result, unorderedEquals([packageB, packageC, packageD]));
+ }
+
+ void test_transitiveDependenciesFor_simpleDependencies() {
+ String packageA = '/pub-cache/a-1.0';
+ String packageB = '/pub-cache/b-1.0';
+ String packageC = '/pub-cache/c-1.0';
+ resourceProvider.newFile(
+ '$packageA/$pubspecName',
+ '''
+ dependencies:
+ b: any
+ c: any
+ ''');
+ resourceProvider.newFile('$packageB/$pubspecName', '');
+ resourceProvider.newFile('$packageC/$pubspecName', '');
+ Map<String, List<Folder>> packageMap = <String, List<Folder>>{
+ 'a': <Folder>[resourceProvider.getFolder(packageA)],
+ 'b': <Folder>[resourceProvider.getFolder(packageB)],
+ 'c': <Folder>[resourceProvider.getFolder(packageC)],
+ };
+
+ DependencyFinder finder = new DependencyFinder(resourceProvider);
+ List<String> result =
+ finder.transitiveDependenciesFor(packageMap, packageA);
+ expect(result, unorderedEquals([packageB, packageC]));
+ }
+}
+
+@reflectiveTest
+class PackageDescriptionTest extends ResolverTestCase {
+ void test_equal_false_differentOptions() {
+ String packageId = 'path1;path2';
+ DartSdk sdk = new MockSdk();
+ AnalysisOptionsImpl options1 = new AnalysisOptionsImpl();
+ AnalysisOptionsImpl options2 = new AnalysisOptionsImpl();
+ options2.enableAsync = !options1.enableAsync;
+ PackageDescription first = new PackageDescription(packageId, sdk, options1);
+ PackageDescription second =
+ new PackageDescription(packageId, sdk, options2);
+ expect(first == second, isFalse);
+ }
+
+ void test_equal_false_differentPaths() {
+ String packageId1 = 'path1;path2';
+ String packageId2 = 'path1;path3';
+ DartSdk sdk = new MockSdk();
+ AnalysisOptions options = new AnalysisOptionsImpl();
+ PackageDescription first = new PackageDescription(packageId1, sdk, options);
+ PackageDescription second =
+ new PackageDescription(packageId2, sdk, options);
+ expect(first == second, isFalse);
+ }
+
+ void test_equal_false_differentSdks() {
+ String packageId = 'path1;path2';
+ DartSdk sdk1 = new MockSdk();
+ DartSdk sdk2 = new MockSdk();
+ AnalysisOptions options = new AnalysisOptionsImpl();
+ PackageDescription first = new PackageDescription(packageId, sdk1, options);
+ PackageDescription second =
+ new PackageDescription(packageId, sdk2, options);
+ expect(first == second, isFalse);
+ }
+
+ void test_equal_true() {
+ String packageId = 'path1;path2';
+ DartSdk sdk = new MockSdk();
+ AnalysisOptions options = new AnalysisOptionsImpl();
+ PackageDescription first = new PackageDescription(packageId, sdk, options);
+ PackageDescription second = new PackageDescription(packageId, sdk, options);
+ expect(first == second, isTrue);
+ }
+}
+
+@reflectiveTest
+class PackageManagerTest extends ResolverTestCase {
+ /**
+ * The resource provider to be used by tests.
+ */
+ MemoryResourceProvider resourceProvider;
+
+ @override
+ void setUp() {
+ resourceProvider = new MemoryResourceProvider();
+ }
+
+ void test_getContext() {
+ String packageA = '/pub-cache/a-1.0';
+ String packageB1 = '/pub-cache/b-1.0';
+ String packageB2 = '/pub-cache/b-2.0';
+ String packageC = '/pub-cache/c-1.0';
+ resourceProvider.newFile(
+ '$packageA/$pubspecName',
+ '''
+ dependencies:
+ b: any
+ c: any
+ ''');
+ resourceProvider.newFile('$packageB1/$pubspecName', '');
+ resourceProvider.newFile('$packageB2/$pubspecName', '');
+ resourceProvider.newFile('$packageC/$pubspecName', '');
+
+ Packages packages1 = new _MockPackages(<String, Uri>{
+ 'a': new Uri.file(packageA),
+ 'b': new Uri.file(packageB1),
+ 'c': new Uri.file(packageC),
+ });
+ DartUriResolver resolver = new DartUriResolver(new MockSdk());
+ AnalysisOptions options = new AnalysisOptionsImpl();
+ //
+ // Verify that we can compute a context for a package.
+ //
+ PackageManager manager = new PackageManager(resourceProvider);
+ AnalysisContext context1 =
+ manager.getContext(packageA, packages1, resolver, options);
+ expect(context1, isNotNull);
+ //
+ // Verify that if we have the same package map we get the same context.
+ //
+ AnalysisContext context2 =
+ manager.getContext(packageA, packages1, resolver, options);
+ expect(context2, same(context1));
+ //
+ // Verify that if we have a different package map we get a different context.
+ //
+ Packages packages3 = new _MockPackages(<String, Uri>{
+ 'a': new Uri.file(packageA),
+ 'b': new Uri.file(packageB2),
+ 'c': new Uri.file(packageC),
+ });
+ AnalysisContext context3 =
+ manager.getContext(packageA, packages3, resolver, options);
+ expect(context3, isNot(same(context1)));
+ }
+}
+
+/**
+ * An implementation of [Packages] used for testing.
+ */
+class _MockPackages implements Packages {
+ final Map<String, Uri> map;
+
+ _MockPackages(this.map);
+
+ @override
+ Iterable<String> get packages => map.keys;
+
+ @override
+ Map<String, Uri> asMap() => map;
+
+ @override
+ Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) {
+ fail('Unexpected invocation of resolve');
+ return null;
+ }
+}
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index c62f985..d7d72f8 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -164,6 +164,7 @@
FunctionType expected = _functionType([objectType, numType, numType]);
_checkLeastUpperBound(type1, type2, expected);
}
+
void test_nestedNestedFunctionsLubInnermostParamTypes() {
FunctionType type1 = _functionType([
_functionType([
@@ -620,7 +621,11 @@
numType,
bottomType
];
- List<DartType> unrelated = <DartType>[intType, stringType, interfaceType,];
+ List<DartType> unrelated = <DartType>[
+ intType,
+ stringType,
+ interfaceType,
+ ];
_checkGroups(doubleType,
interassignable: interassignable, unrelated: unrelated);
@@ -750,7 +755,10 @@
doubleType,
bottomType
];
- List<DartType> unrelated = <DartType>[stringType, interfaceType,];
+ List<DartType> unrelated = <DartType>[
+ stringType,
+ interfaceType,
+ ];
_checkGroups(numType,
interassignable: interassignable, unrelated: unrelated);
@@ -780,10 +788,12 @@
void _checkCrossLattice(
DartType top, DartType left, DartType right, DartType bottom) {
- _checkGroups(top, interassignable: <DartType>[top, left, right, bottom]);
- _checkGroups(left, interassignable: <DartType>[top, left, right, bottom]);
- _checkGroups(right, interassignable: <DartType>[top, left, right, bottom]);
- _checkGroups(bottom, interassignable: <DartType>[top, left, right, bottom]);
+ _checkGroups(top, interassignable: [top, left, right, bottom]);
+ _checkGroups(left,
+ interassignable: [top, left, bottom], unrelated: [right]);
+ _checkGroups(right,
+ interassignable: [top, right, bottom], unrelated: [left]);
+ _checkGroups(bottom, interassignable: [top, left, right, bottom]);
}
void _checkEquivalent(DartType type1, DartType type2) {
diff --git a/pkg/analyzer/test/source/package_map_provider_test.dart b/pkg/analyzer/test/source/package_map_provider_test.dart
index f02b60a..bb0e142 100644
--- a/pkg/analyzer/test/source/package_map_provider_test.dart
+++ b/pkg/analyzer/test/source/package_map_provider_test.dart
@@ -8,8 +8,8 @@
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/source/package_map_provider.dart';
import 'package:analyzer/source/pub_package_map_provider.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:unittest/unittest.dart';
import '../reflective_tests.dart';
@@ -24,7 +24,7 @@
class PubPackageMapProviderTest {
static const String projectPath = '/path/to/project';
- DartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
+ DartSdk sdk;
MemoryResourceProvider resourceProvider;
PubPackageMapProvider packageMapProvider;
Folder projectFolder;
@@ -35,6 +35,8 @@
void setUp() {
resourceProvider = new MemoryResourceProvider();
+ sdk = new FolderBasedDartSdk(resourceProvider,
+ FolderBasedDartSdk.defaultSdkDirectory(resourceProvider));
packageMapProvider = new PubPackageMapProvider(resourceProvider, sdk);
projectFolder = resourceProvider.newFolder(projectPath);
}
diff --git a/pkg/analyzer/test/source/sdk_ext_test.dart b/pkg/analyzer/test/source/sdk_ext_test.dart
index dbb7425..e46ed7d 100644
--- a/pkg/analyzer/test/source/sdk_ext_test.dart
+++ b/pkg/analyzer/test/source/sdk_ext_test.dart
@@ -8,79 +8,77 @@
import 'package:analyzer/source/sdk_ext.dart';
import 'package:unittest/unittest.dart';
+import '../reflective_tests.dart';
import '../utils.dart';
main() {
initializeTestEnvironment();
- group('SdkExtUriResolverTest', () {
- setUp(() {
- buildResourceProvider();
- });
- tearDown(() {
- clearResourceProvider();
- });
- test('test_NullPackageMap', () {
- var resolver = new SdkExtUriResolver(null);
- expect(resolver.length, equals(0));
- });
- test('test_NoSdkExtPackageMap', () {
- var resolver = new SdkExtUriResolver({
- 'fox': [resourceProvider.getResource('/empty')]
- });
- expect(resolver.length, equals(0));
- });
- test('test_SdkExtPackageMap', () {
- var resolver = new SdkExtUriResolver({
- 'fox': [resourceProvider.getResource('/tmp')]
- });
- // We have four mappings.
- expect(resolver.length, equals(4));
- // Check that they map to the correct paths.
- expect(resolver['dart:fox'], equals("/tmp/slippy.dart"));
- expect(resolver['dart:bear'], equals("/tmp/grizzly.dart"));
- expect(resolver['dart:relative'], equals("/relative.dart"));
- expect(resolver['dart:deep'], equals("/tmp/deep/directory/file.dart"));
- });
- test('test_BadJSON', () {
- var resolver = new SdkExtUriResolver(null);
- resolver.addSdkExt(r'''{{{,{{}}},}}''', null);
- expect(resolver.length, equals(0));
- });
- test('test_restoreAbsolute', () {
- var resolver = new SdkExtUriResolver({
- 'fox': [resourceProvider.getResource('/tmp')]
- });
- var source = resolver.resolveAbsolute(Uri.parse('dart:fox'));
- expect(source, isNotNull);
- // Restore source's uri.
- var restoreUri = resolver.restoreAbsolute(source);
- expect(restoreUri, isNotNull);
- // Verify that it is 'dart:fox'.
- expect(restoreUri.toString(), equals('dart:fox'));
- expect(restoreUri.scheme, equals('dart'));
- expect(restoreUri.path, equals('fox'));
- });
- });
+ runReflectiveTests(SdkExtUriResolverTest);
}
-MemoryResourceProvider resourceProvider;
+@reflectiveTest
+class SdkExtUriResolverTest {
+ MemoryResourceProvider resourceProvider;
-buildResourceProvider() {
- resourceProvider = new MemoryResourceProvider();
- resourceProvider.newFolder('/empty');
- resourceProvider.newFolder('/tmp');
- resourceProvider.newFile(
- '/tmp/_sdkext',
- r'''
- {
- "dart:fox": "slippy.dart",
- "dart:bear": "grizzly.dart",
- "dart:relative": "../relative.dart",
- "dart:deep": "deep/directory/file.dart",
- "fart:loudly": "nomatter.dart"
- }''');
-}
+ void setUp() {
+ resourceProvider = new MemoryResourceProvider();
+ resourceProvider.newFolder('/empty');
+ resourceProvider.newFolder('/tmp');
+ resourceProvider.newFile(
+ '/tmp/_sdkext',
+ r'''
+{
+ "dart:fox": "slippy.dart",
+ "dart:bear": "grizzly.dart",
+ "dart:relative": "../relative.dart",
+ "dart:deep": "deep/directory/file.dart",
+ "fart:loudly": "nomatter.dart"
+}''');
+ }
-clearResourceProvider() {
- resourceProvider = null;
+ test_create_badJSON() {
+ var resolver = new SdkExtUriResolver(null);
+ resolver.addSdkExt(r'''{{{,{{}}},}}''', null);
+ expect(resolver.length, equals(0));
+ }
+
+ test_create_noSdkExtPackageMap() {
+ var resolver = new SdkExtUriResolver({
+ 'fox': [resourceProvider.getResource('/empty')]
+ });
+ expect(resolver.length, equals(0));
+ }
+
+ test_create_nullPackageMap() {
+ var resolver = new SdkExtUriResolver(null);
+ expect(resolver.length, equals(0));
+ }
+
+ test_create_sdkExtPackageMap() {
+ var resolver = new SdkExtUriResolver({
+ 'fox': [resourceProvider.getResource('/tmp')]
+ });
+ // We have four mappings.
+ expect(resolver.length, equals(4));
+ // Check that they map to the correct paths.
+ expect(resolver['dart:fox'], equals("/tmp/slippy.dart"));
+ expect(resolver['dart:bear'], equals("/tmp/grizzly.dart"));
+ expect(resolver['dart:relative'], equals("/relative.dart"));
+ expect(resolver['dart:deep'], equals("/tmp/deep/directory/file.dart"));
+ }
+
+ test_restoreAbsolute() {
+ var resolver = new SdkExtUriResolver({
+ 'fox': [resourceProvider.getResource('/tmp')]
+ });
+ var source = resolver.resolveAbsolute(Uri.parse('dart:fox'));
+ expect(source, isNotNull);
+ // Restore source's uri.
+ var restoreUri = resolver.restoreAbsolute(source);
+ expect(restoreUri, isNotNull);
+ // Verify that it is 'dart:fox'.
+ expect(restoreUri.toString(), equals('dart:fox'));
+ expect(restoreUri.scheme, equals('dart'));
+ expect(restoreUri.path, equals('fox'));
+ }
}
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index e6ed76f..cba70fa 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -457,7 +457,10 @@
@override
void setUp() {
resourceProvider = new MemoryResourceProvider();
- sdkManager = new DartSdkManager('', false, (_) => new MockSdk());
+ new MockSdk(resourceProvider: resourceProvider);
+ sdkManager = new DartSdkManager('/', false, (_) {
+ fail('Should not be used to create an SDK');
+ });
contentCache = new ContentCache();
builder = new ContextBuilder(resourceProvider, sdkManager, contentCache);
}
diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart
index dc09c80..bc8342a 100644
--- a/pkg/analyzer/test/src/context/cache_test.dart
+++ b/pkg/analyzer/test/src/context/cache_test.dart
@@ -6,11 +6,12 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_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/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/task/model.dart';
@@ -1177,8 +1178,10 @@
void test_contains_true() {
SdkCachePartition partition = new SdkCachePartition(null);
- SourceFactory factory = new SourceFactory(
- [new DartUriResolver(DirectoryBasedDartSdk.defaultSdk)]);
+ ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
+ FolderBasedDartSdk sdk = new FolderBasedDartSdk(resourceProvider,
+ FolderBasedDartSdk.defaultSdkDirectory(resourceProvider));
+ SourceFactory factory = new SourceFactory([new DartUriResolver(sdk)]);
AnalysisTarget target = factory.forUri("dart:core");
expect(partition.isResponsibleFor(target), isTrue);
}
diff --git a/pkg/analyzer/test/src/context/mock_sdk.dart b/pkg/analyzer/test/src/context/mock_sdk.dart
index 0ebc01f..0c50736 100644
--- a/pkg/analyzer/test/src/context/mock_sdk.dart
+++ b/pkg/analyzer/test/src/context/mock_sdk.dart
@@ -4,6 +4,7 @@
library analyzer.test.src.context.mock_sdk;
+import 'package:analyzer/dart/element/element.dart' show LibraryElement;
import 'package:analyzer/file_system/file_system.dart' as resource;
import 'package:analyzer/file_system/memory_file_system.dart' as resource;
import 'package:analyzer/src/context/cache.dart';
@@ -11,10 +12,27 @@
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
+import 'package:analyzer/src/summary/summarize_elements.dart'
+ show PackageBundleAssembler;
+
+const String librariesContent = r'''
+const Map<String, LibraryInfo> libraries = const {
+ "async": const LibraryInfo("async/async.dart"),
+ "collection": const LibraryInfo("collection/collection.dart"),
+ "convert": const LibraryInfo("convert/convert.dart"),
+ "core": const LibraryInfo("core/core.dart"),
+ "html": const LibraryInfo("html/dartium/html_dartium.dart"),
+ "math": const LibraryInfo("math/math.dart"),
+ "_foreign_helper": const LibraryInfo("_internal/js_runtime/lib/foreign_helper.dart"),
+};
+''';
+
+const String sdkRoot = '/sdk';
const _MockSdkLibrary _LIB_ASYNC = const _MockSdkLibrary(
'dart:async',
- '/lib/async/async.dart',
+ '$sdkRoot/lib/async/async.dart',
'''
library dart.async;
@@ -42,7 +60,7 @@
}
''',
const <String, String>{
- '/lib/async/stream.dart': r'''
+ '$sdkRoot/lib/async/stream.dart': r'''
part of dart.async;
class Stream<T> {
Future<T> get first;
@@ -53,7 +71,7 @@
const _MockSdkLibrary _LIB_COLLECTION = const _MockSdkLibrary(
'dart:collection',
- '/lib/collection/collection.dart',
+ '$sdkRoot/lib/collection/collection.dart',
'''
library dart.collection;
@@ -62,7 +80,7 @@
const _MockSdkLibrary _LIB_CONVERT = const _MockSdkLibrary(
'dart:convert',
- '/lib/convert/convert.dart',
+ '$sdkRoot/lib/convert/convert.dart',
'''
library dart.convert;
@@ -74,7 +92,7 @@
const _MockSdkLibrary _LIB_CORE = const _MockSdkLibrary(
'dart:core',
- '/lib/core/core.dart',
+ '$sdkRoot/lib/core/core.dart',
'''
library dart.core;
@@ -239,7 +257,7 @@
const _MockSdkLibrary _LIB_FOREIGN_HELPER = const _MockSdkLibrary(
'dart:_foreign_helper',
- '/lib/_foreign_helper/_foreign_helper.dart',
+ '$sdkRoot/lib/_foreign_helper/_foreign_helper.dart',
'''
library dart._foreign_helper;
@@ -250,7 +268,7 @@
const _MockSdkLibrary _LIB_HTML = const _MockSdkLibrary(
'dart:html',
- '/lib/html/dartium/html_dartium.dart',
+ '$sdkRoot/lib/html/dartium/html_dartium.dart',
'''
library dart.html;
class HtmlElement {}
@@ -258,7 +276,7 @@
const _MockSdkLibrary _LIB_MATH = const _MockSdkLibrary(
'dart:math',
- '/lib/math/math.dart',
+ '$sdkRoot/lib/math/math.dart',
'''
library dart.math;
@@ -291,18 +309,18 @@
class MockSdk implements DartSdk {
static const Map<String, String> FULL_URI_MAP = const {
- "dart:core": "/lib/core/core.dart",
- "dart:html": "/lib/html/dartium/html_dartium.dart",
- "dart:async": "/lib/async/async.dart",
- "dart:async/stream.dart": "/lib/async/stream.dart",
- "dart:collection": "/lib/collection/collection.dart",
- "dart:convert": "/lib/convert/convert.dart",
- "dart:_foreign_helper": "/lib/_foreign_helper/_foreign_helper.dart",
- "dart:math": "/lib/math/math.dart"
+ "dart:core": "$sdkRoot/lib/core/core.dart",
+ "dart:html": "$sdkRoot/lib/html/dartium/html_dartium.dart",
+ "dart:async": "$sdkRoot/lib/async/async.dart",
+ "dart:async/stream.dart": "$sdkRoot/lib/async/stream.dart",
+ "dart:collection": "$sdkRoot/lib/collection/collection.dart",
+ "dart:convert": "$sdkRoot/lib/convert/convert.dart",
+ "dart:_foreign_helper": "$sdkRoot/lib/_foreign_helper/_foreign_helper.dart",
+ "dart:math": "$sdkRoot/lib/math/math.dart"
};
static const Map<String, String> NO_ASYNC_URI_MAP = const {
- "dart:core": "/lib/core/core.dart",
+ "dart:core": "$sdkRoot/lib/core/core.dart",
};
final resource.MemoryResourceProvider provider;
@@ -317,6 +335,11 @@
@override
final List<SdkLibrary> sdkLibraries;
+ /**
+ * The cached linked bundle of the SDK.
+ */
+ PackageBundle _bundle;
+
MockSdk({bool dartAsync: true, resource.ResourceProvider resourceProvider})
: provider = resourceProvider ?? new resource.MemoryResourceProvider(),
sdkLibraries = dartAsync ? _LIBRARIES : [_LIB_CORE],
@@ -327,6 +350,8 @@
provider.newFile(path, content);
});
}
+ provider.newFile(
+ '/_internal/sdk_library_metadata/lib/libraries.dart', librariesContent);
}
@override
@@ -349,7 +374,7 @@
@override
Source fromFileUri(Uri uri) {
String filePath = uri.path;
- String libPath = '/lib';
+ String libPath = '$sdkRoot/lib';
if (!filePath.startsWith("$libPath/")) {
return null;
}
@@ -380,6 +405,22 @@
}
@override
+ PackageBundle getLinkedBundle() {
+ if (_bundle == null) {
+ PackageBundleAssembler assembler = new PackageBundleAssembler();
+ for (SdkLibrary sdkLibrary in sdkLibraries) {
+ String uriStr = sdkLibrary.shortName;
+ Source source = mapDartUri(uriStr);
+ LibraryElement libraryElement = context.computeLibraryElement(source);
+ assembler.serializeLibraryElement(libraryElement);
+ }
+ List<int> bytes = assembler.assemble().toBuffer();
+ _bundle = new PackageBundle.fromBuffer(bytes);
+ }
+ return _bundle;
+ }
+
+ @override
SdkLibrary getSdkLibrary(String dartUri) {
// getSdkLibrary() is only used to determine whether a library is internal
// to the SDK. The mock SDK doesn't have any internals, so it's safe to
diff --git a/pkg/analyzer/test/src/summary/linker_test.dart b/pkg/analyzer/test/src/summary/linker_test.dart
index eb9e407..b93a39f 100644
--- a/pkg/analyzer/test/src/summary/linker_test.dart
+++ b/pkg/analyzer/test/src/summary/linker_test.dart
@@ -235,6 +235,25 @@
expect(classC.unnamedConstructor.isCycleFree, false);
}
+ void test_createPackageBundle_withPackageUri() {
+ PackageBundle bundle = createPackageBundle(
+ '''
+class B {
+ void f(int i) {}
+}
+class C extends B {
+ f(i) {} // Inferred param type: int
+}
+''',
+ uri: 'package:foo/bar.dart');
+ UnlinkedExecutable cf = bundle.unlinkedUnits[0].classes[1].executables[0];
+ UnlinkedParam cfi = cf.parameters[0];
+ expect(cfi.inferredTypeSlot, isNot(0));
+ EntityRef typeRef =
+ bundle.linkedLibraries[0].units[0].types[cfi.inferredTypeSlot];
+ expect(bundle.unlinkedUnits[0].references[typeRef.reference].name, 'int');
+ }
+
void test_getContainedName_nonStaticField() {
createLinker('class C { var f; }');
LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
diff --git a/pkg/analyzer/test/src/summary/pub_summary_test.dart b/pkg/analyzer/test/src/summary/pub_summary_test.dart
index acc22cc..fc1eb7c 100644
--- a/pkg/analyzer/test/src/summary/pub_summary_test.dart
+++ b/pkg/analyzer/test/src/summary/pub_summary_test.dart
@@ -2,14 +2,14 @@
// 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/element/element.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/source/package_map_resolver.dart';
-import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/pub_summary.dart';
import 'package:analyzer/src/summary/summarize_elements.dart';
+import 'package:analyzer/src/util/fast_uri.dart';
import 'package:path/path.dart' as pathos;
import 'package:unittest/unittest.dart' hide ERROR;
@@ -26,8 +26,6 @@
class PubSummaryManagerTest extends AbstractContextTest {
static const String CACHE = '/home/.pub-cache/hosted/pub.dartlang.org';
- static Map<DartSdk, PackageBundle> sdkBundleMap = <DartSdk, PackageBundle>{};
-
PubSummaryManager manager;
void setUp() {
@@ -35,7 +33,389 @@
manager = new PubSummaryManager(resourceProvider, '_.temp');
}
- test_getLinkedBundles_noCycles() async {
+ test_computeSdkExtension() async {
+ // Create package files.
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/a.dart',
+ '''
+class A {}
+''');
+ resourceProvider.newFile(
+ '$CACHE/aaa/sdk_ext/extA.dart',
+ '''
+library test.a;
+import 'dart:async';
+part 'src/p1.dart';
+part 'src/p2.dart';
+class ExtA {}
+int V0;
+''');
+ resourceProvider.newFile(
+ '$CACHE/aaa/sdk_ext/src/p1.dart',
+ '''
+part of test.a;
+class ExtAA {}
+double V1;
+''');
+ resourceProvider.newFile(
+ '$CACHE/aaa/sdk_ext/src/p2.dart',
+ '''
+part of test.a;
+class ExtAB {}
+Future V2;
+''');
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/_sdkext',
+ '''
+{
+ "dart:aaa.internal": "../sdk_ext/extA.dart"
+}
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/b.dart',
+ '''
+class B {}
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+ Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ 'bbb': [libFolderB],
+ })
+ ]);
+
+ PackageBundle sdkBundle = sdk.getLinkedBundle();
+ PackageBundle bundle = manager.computeSdkExtension(context, sdkBundle);
+ expect(bundle, isNotNull);
+ expect(bundle.linkedLibraryUris, ['dart:aaa.internal']);
+ expect(bundle.unlinkedUnitUris, [
+ 'dart:aaa.internal',
+ 'dart:aaa.internal/src/p1.dart',
+ 'dart:aaa.internal/src/p2.dart'
+ ]);
+ expect(bundle.unlinkedUnits, hasLength(3));
+ expect(bundle.unlinkedUnits[0].classes.map((c) => c.name), ['ExtA']);
+ expect(bundle.unlinkedUnits[1].classes.map((c) => c.name), ['ExtAA']);
+ expect(bundle.unlinkedUnits[2].classes.map((c) => c.name), ['ExtAB']);
+ // The library is linked.
+ expect(bundle.linkedLibraries, hasLength(1));
+ LinkedLibrary linkedLibrary = bundle.linkedLibraries[0];
+ // V0 is linked
+ {
+ UnlinkedUnit unlinkedUnit = bundle.unlinkedUnits[0];
+ LinkedUnit linkedUnit = linkedLibrary.units[0];
+ expect(unlinkedUnit.variables, hasLength(1));
+ UnlinkedVariable variable = unlinkedUnit.variables[0];
+ expect(variable.name, 'V0');
+ int typeRef = variable.type.reference;
+ expect(unlinkedUnit.references[typeRef].name, 'int');
+ LinkedReference linkedReference = linkedUnit.references[typeRef];
+ expect(linkedLibrary.dependencies[linkedReference.dependency].uri,
+ 'dart:core');
+ }
+ // V1 is linked
+ {
+ UnlinkedUnit unlinkedUnit = bundle.unlinkedUnits[1];
+ LinkedUnit linkedUnit = linkedLibrary.units[1];
+ expect(unlinkedUnit.variables, hasLength(1));
+ UnlinkedVariable variable = unlinkedUnit.variables[0];
+ expect(variable.name, 'V1');
+ int typeRef = variable.type.reference;
+ expect(unlinkedUnit.references[typeRef].name, 'double');
+ LinkedReference linkedReference = linkedUnit.references[typeRef];
+ expect(linkedLibrary.dependencies[linkedReference.dependency].uri,
+ 'dart:core');
+ }
+ // V2 is linked
+ {
+ UnlinkedUnit unlinkedUnit = bundle.unlinkedUnits[2];
+ LinkedUnit linkedUnit = linkedLibrary.units[2];
+ expect(unlinkedUnit.variables, hasLength(1));
+ UnlinkedVariable variable = unlinkedUnit.variables[0];
+ expect(variable.name, 'V2');
+ int typeRef = variable.type.reference;
+ expect(unlinkedUnit.references[typeRef].name, 'Future');
+ LinkedReference linkedReference = linkedUnit.references[typeRef];
+ expect(linkedLibrary.dependencies[linkedReference.dependency].uri,
+ 'dart:async');
+ }
+ }
+
+ test_getLinkedBundles_hasCycle() async {
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/a.dart',
+ '''
+import 'package:bbb/b.dart';
+class A {}
+int a1;
+B a2;
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/b.dart',
+ '''
+import 'package:ccc/c.dart';
+class B {}
+C b;
+''');
+ resourceProvider.newFile(
+ '$CACHE/ccc/lib/c.dart',
+ '''
+import 'package:aaa/a.dart';
+import 'package:ddd/d.dart';
+class C {}
+A c1;
+D c2;
+''');
+ resourceProvider.newFile(
+ '$CACHE/ddd/lib/d.dart',
+ '''
+class D {}
+String d;
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+ Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+ Folder libFolderC = resourceProvider.newFolder('$CACHE/ccc/lib');
+ Folder libFolderD = resourceProvider.newFolder('$CACHE/ddd/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ 'bbb': [libFolderB],
+ 'ccc': [libFolderC],
+ 'ddd': [libFolderD],
+ })
+ ]);
+
+ // Ensure unlinked bundles.
+ manager.getUnlinkedBundles(context);
+ await manager.onUnlinkedComplete;
+
+ // Now we should be able to get linked bundles.
+ List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+ expect(linkedPackages, hasLength(4));
+
+ // package:aaa
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'aaa');
+ expect(linkedPackage.linked.linkedLibraryUris, ['package:aaa/a.dart']);
+ _assertHasLinkedVariable(linkedPackage, 'a1', 'int', 'dart:core');
+ _assertHasLinkedVariable(linkedPackage, 'a2', 'B', 'package:bbb/b.dart');
+ }
+
+ // package:bbb
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'bbb');
+ expect(linkedPackage.linked.linkedLibraryUris, ['package:bbb/b.dart']);
+ _assertHasLinkedVariable(linkedPackage, 'b', 'C', 'package:ccc/c.dart');
+ }
+
+ // package:ccc
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'ccc');
+ expect(linkedPackage.linked.linkedLibraryUris, ['package:ccc/c.dart']);
+ _assertHasLinkedVariable(linkedPackage, 'c1', 'A', 'package:aaa/a.dart');
+ _assertHasLinkedVariable(linkedPackage, 'c2', 'D', 'package:ddd/d.dart');
+ }
+
+ // package:ddd
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'ddd');
+ expect(linkedPackage.linked.linkedLibraryUris, ['package:ddd/d.dart']);
+ _assertHasLinkedVariable(linkedPackage, 'd', 'String', 'dart:core');
+ }
+ }
+
+ test_getLinkedBundles_missingBundle() async {
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/a.dart',
+ '''
+int a;
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/b.dart',
+ '''
+import 'package:ccc/c.dart';
+C b;
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+ Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ 'bbb': [libFolderB],
+ })
+ ]);
+
+ // Ensure unlinked bundles.
+ manager.getUnlinkedBundles(context);
+ await manager.onUnlinkedComplete;
+
+ // Try to link.
+ // Only 'aaa' can be linked, because 'bbb' references not available 'ccc'.
+ List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+ expect(linkedPackages, hasLength(1));
+
+ // package:aaa
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'aaa');
+ _assertHasLinkedVariable(linkedPackage, 'a', 'int', 'dart:core');
+ }
+ }
+
+ test_getLinkedBundles_missingBundle_chained() async {
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/a.dart',
+ '''
+import 'package:bbb/b.dart';
+int a;
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/b.dart',
+ '''
+import 'package:ccc/c.dart';
+int b;
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+ Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ 'bbb': [libFolderB],
+ })
+ ]);
+
+ // Ensure unlinked bundles.
+ manager.getUnlinkedBundles(context);
+ await manager.onUnlinkedComplete;
+
+ // Try to link.
+ // No linked libraries, because 'aaa' needs 'bbb', and 'bbb' needs 'ccc'.
+ // But 'ccc' is not available, so the whole chain cannot be linked.
+ List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+ expect(linkedPackages, isEmpty);
+ }
+
+ test_getLinkedBundles_missingLibrary() async {
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/a.dart',
+ '''
+import 'package:bbb/b2.dart';
+int a;
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/b.dart',
+ '''
+class B {}
+int b = 42;
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+ Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ 'bbb': [libFolderB],
+ })
+ ]);
+
+ // Ensure unlinked bundles.
+ manager.getUnlinkedBundles(context);
+ await manager.onUnlinkedComplete;
+
+ // Try to link.
+ // Only 'bbb', because 'aaa' references 'package:bbb/b2.dart', which does
+ // not exist in the bundle 'bbb'.
+ List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+ expect(linkedPackages, hasLength(1));
+
+ // package:bbb
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'bbb');
+ _assertHasLinkedVariable(linkedPackage, 'b', 'int', 'dart:core');
+ }
+ }
+
+ test_getLinkedBundles_missingLibrary_hasCycle() async {
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/a.dart',
+ '''
+import 'package:bbb/b.dart';
+int a;
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/b.dart',
+ '''
+import 'package:aaa/a.dart';
+import 'package:ccc/c2.dart';
+class B {}
+int b;
+''');
+ resourceProvider.newFile(
+ '$CACHE/ccc/lib/c.dart',
+ '''
+class C {}
+int c;
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+ Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+ Folder libFolderC = resourceProvider.newFolder('$CACHE/ccc/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ 'bbb': [libFolderB],
+ 'ccc': [libFolderC],
+ })
+ ]);
+
+ // Ensure unlinked bundles.
+ manager.getUnlinkedBundles(context);
+ await manager.onUnlinkedComplete;
+
+ // Try to link.
+ // Only 'ccc' is linked.
+ // The 'aaa' + 'bbb' cycle cannot be linked because 'bbb' references
+ // 'package:ccc/c2.dart', which does not exist in the bundle 'ccc'.
+ List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+ expect(linkedPackages, hasLength(1));
+
+ // package:ccc
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'ccc');
+ _assertHasLinkedVariable(linkedPackage, 'c', 'int', 'dart:core');
+ }
+ }
+
+ test_getLinkedBundles_noCycle() async {
resourceProvider.newFile(
'$CACHE/aaa/lib/a.dart',
'''
@@ -66,58 +446,211 @@
await manager.onUnlinkedComplete;
// Now we should be able to get linked bundles.
- PackageBundle sdkBundle = getSdkBundle(sdk);
- List<LinkedPubPackage> linkedPackages =
- manager.getLinkedBundles(context, sdkBundle);
+ List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
expect(linkedPackages, hasLength(2));
// package:aaa
{
LinkedPubPackage linkedPackage = linkedPackages
.singleWhere((linkedPackage) => linkedPackage.package.name == 'aaa');
- PackageBundle unlinked = linkedPackage.unlinked;
- PackageBundle linked = linkedPackage.linked;
- expect(unlinked, isNotNull);
- expect(linked, isNotNull);
- expect(unlinked.unlinkedUnitUris, ['package:aaa/a.dart']);
- expect(linked.linkedLibraryUris, ['package:aaa/a.dart']);
- // Prepare linked `package:aaa/a.dart`.
- UnlinkedUnit unlinkedUnitA = unlinked.unlinkedUnits[0];
- LinkedLibrary linkedLibraryA = linked.linkedLibraries[0];
- LinkedUnit linkedUnitA = linkedLibraryA.units[0];
- // int a;
- {
- UnlinkedVariable a = unlinkedUnitA.variables[0];
- expect(a.name, 'a');
- _assertLinkedNameReference(unlinkedUnitA, linkedLibraryA, linkedUnitA,
- a.type.reference, 'int', 'dart:core');
- }
+ _assertHasLinkedVariable(linkedPackage, 'a', 'int', 'dart:core');
}
// package:bbb
{
LinkedPubPackage linkedPackage = linkedPackages
.singleWhere((linkedPackage) => linkedPackage.package.name == 'bbb');
- PackageBundle unlinked = linkedPackage.unlinked;
- PackageBundle linked = linkedPackage.linked;
- expect(unlinked, isNotNull);
- expect(linked, isNotNull);
- expect(unlinked.unlinkedUnitUris, ['package:bbb/b.dart']);
- expect(linked.linkedLibraryUris, ['package:bbb/b.dart']);
- // Prepare linked `package:bbb/b.dart`.
- UnlinkedUnit unlinkedUnit = unlinked.unlinkedUnits[0];
- LinkedLibrary linkedLibrary = linked.linkedLibraries[0];
- LinkedUnit linkedUnit = linkedLibrary.units[0];
- // A b;
- {
- UnlinkedVariable b = unlinkedUnit.variables[0];
- expect(b.name, 'b');
- _assertLinkedNameReference(unlinkedUnit, linkedLibrary, linkedUnit,
- b.type.reference, 'A', 'package:aaa/a.dart');
- }
+ _assertHasLinkedVariable(linkedPackage, 'b', 'A', 'package:aaa/a.dart');
}
}
+ test_getLinkedBundles_noCycle_relativeUri() async {
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/a.dart',
+ '''
+import 'src/a2.dart';
+A a;
+''');
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/src/a2.dart',
+ '''
+class A {}
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ })
+ ]);
+
+ // Ensure unlinked bundles.
+ manager.getUnlinkedBundles(context);
+ await manager.onUnlinkedComplete;
+
+ // Link.
+ List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+ expect(linkedPackages, hasLength(1));
+
+ // package:aaa
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'aaa');
+ _assertHasLinkedVariable(linkedPackage, 'a', 'A', 'src/a2.dart');
+ }
+ }
+
+ test_getLinkedBundles_noCycle_withExport() async {
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/a.dart',
+ '''
+import 'package:bbb/b.dart';
+C a;
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/b.dart',
+ '''
+export 'package:ccc/c.dart';
+''');
+ resourceProvider.newFile(
+ '$CACHE/ccc/lib/c.dart',
+ '''
+class C {}
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+ Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+ Folder libFolderC = resourceProvider.newFolder('$CACHE/ccc/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ 'bbb': [libFolderB],
+ 'ccc': [libFolderC],
+ })
+ ]);
+
+ // Ensure unlinked bundles.
+ manager.getUnlinkedBundles(context);
+ await manager.onUnlinkedComplete;
+
+ // Now we should be able to get linked bundles.
+ List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+ expect(linkedPackages, hasLength(3));
+
+ // package:aaa
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'aaa');
+ _assertHasLinkedVariable(linkedPackage, 'a', 'C', 'package:ccc/c.dart');
+ }
+ }
+
+ test_getLinkedBundles_useSdkExtension() async {
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/a.dart',
+ '''
+import 'dart:bbb';
+ExtB a;
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/b.dart',
+ '''
+import 'dart:bbb';
+ExtB b;
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/sdk_ext/extB.dart',
+ '''
+class ExtB {}
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/_sdkext',
+ '''
+{
+ "dart:bbb": "../sdk_ext/extB.dart"
+}
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+ Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ 'bbb': [libFolderB],
+ })
+ ]);
+
+ // Ensure unlinked bundles.
+ manager.getUnlinkedBundles(context);
+ await manager.onUnlinkedComplete;
+
+ // Now we should be able to get linked bundles.
+ List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+ expect(linkedPackages, hasLength(2));
+
+ // package:aaa
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'aaa');
+ _assertHasLinkedVariable(linkedPackage, 'a', 'ExtB', 'dart:bbb');
+ }
+
+ // package:bbb
+ {
+ LinkedPubPackage linkedPackage = linkedPackages
+ .singleWhere((linkedPackage) => linkedPackage.package.name == 'bbb');
+ _assertHasLinkedVariable(linkedPackage, 'b', 'ExtB', 'dart:bbb');
+ }
+ }
+
+ test_getLinkedBundles_wrongScheme() async {
+ resourceProvider.newFile(
+ '$CACHE/aaa/lib/a.dart',
+ '''
+import 'xxx:yyy/zzz.dart';
+Z a;
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ })
+ ]);
+
+ // Ensure unlinked bundles.
+ manager.getUnlinkedBundles(context);
+ await manager.onUnlinkedComplete;
+
+ // Try to link.
+ // The package 'aaa' cannot be linked because it uses not 'dart' or
+ // 'package' import URI scheme.
+ List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+ expect(linkedPackages, hasLength(0));
+ }
+
+ test_getPackageName() {
+ String getPackageName(String uriStr) {
+ return PubSummaryManager.getPackageName(uriStr);
+ }
+ expect(getPackageName('package:foo/bar.dart'), 'foo');
+ expect(getPackageName('package:foo/bar/baz.dart'), 'foo');
+ expect(getPackageName('wrong:foo/bar.dart'), isNull);
+ expect(getPackageName('package:foo'), isNull);
+ }
+
test_getUnlinkedBundles() async {
// Create package files.
resourceProvider.newFile(
@@ -180,10 +713,134 @@
}
// The files must be created.
- File fileA = libFolderA.parent.getChildAssumingFile('unlinked.ds');
- File fileB = libFolderB.parent.getChildAssumingFile('unlinked.ds');
- expect(fileA.exists, isTrue);
- expect(fileB.exists, isTrue);
+ _assertFileExists(libFolderA.parent, PubSummaryManager.UNLINKED_NAME);
+ _assertFileExists(libFolderA.parent, PubSummaryManager.UNLINKED_SPEC_NAME);
+ _assertFileExists(libFolderB.parent, PubSummaryManager.UNLINKED_NAME);
+ _assertFileExists(libFolderB.parent, PubSummaryManager.UNLINKED_SPEC_NAME);
+ }
+
+ test_getUnlinkedBundles_notPubCache_dontCreate() async {
+ String aaaPath = '/Users/user/projects/aaa';
+ // Create package files.
+ resourceProvider.newFile(
+ '$aaaPath/lib/a.dart',
+ '''
+class A {}
+''');
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/b.dart',
+ '''
+class B {}
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.getFolder('$aaaPath/lib');
+ Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ 'bbb': [libFolderB],
+ })
+ ]);
+
+ // No unlinked bundles initially.
+ {
+ Map<PubPackage, PackageBundle> bundles =
+ manager.getUnlinkedBundles(context);
+ expect(bundles, isEmpty);
+ }
+
+ // Wait for unlinked bundles to be computed.
+ await manager.onUnlinkedComplete;
+ Map<PubPackage, PackageBundle> bundles =
+ manager.getUnlinkedBundles(context);
+ // We have just one bundle - for 'bbb'.
+ expect(bundles, hasLength(1));
+ // We computed the unlinked bundle for 'bbb'.
+ {
+ PackageBundle bundle = _getBundleByPackageName(bundles, 'bbb');
+ expect(bundle.linkedLibraryUris, isEmpty);
+ expect(bundle.unlinkedUnitUris, ['package:bbb/b.dart']);
+ expect(bundle.unlinkedUnits, hasLength(1));
+ expect(bundle.unlinkedUnits[0].classes.map((c) => c.name), ['B']);
+ }
+
+ // The files must be created.
+ _assertFileExists(libFolderB.parent, PubSummaryManager.UNLINKED_NAME);
+ _assertFileExists(libFolderB.parent, PubSummaryManager.UNLINKED_SPEC_NAME);
+ }
+
+ test_getUnlinkedBundles_notPubCache_useExisting() async {
+ String aaaPath = '/Users/user/projects/aaa';
+ // Create package files.
+ {
+ File file = resourceProvider.newFile(
+ '$aaaPath/lib/a.dart',
+ '''
+class A {}
+''');
+ PackageBundleAssembler assembler = new PackageBundleAssembler()
+ ..addUnlinkedUnit(
+ file.createSource(FastUri.parse('package:aaa/a.dart')),
+ new UnlinkedUnitBuilder());
+ resourceProvider.newFileWithBytes(
+ '$aaaPath/${PubSummaryManager.UNLINKED_SPEC_NAME}',
+ assembler.assemble().toBuffer());
+ }
+ resourceProvider.newFile(
+ '$CACHE/bbb/lib/b.dart',
+ '''
+class B {}
+''');
+
+ // Configure packages resolution.
+ Folder libFolderA = resourceProvider.getFolder('$aaaPath/lib');
+ Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'aaa': [libFolderA],
+ 'bbb': [libFolderB],
+ })
+ ]);
+
+ // Request already available unlinked bundles.
+ {
+ Map<PubPackage, PackageBundle> bundles =
+ manager.getUnlinkedBundles(context);
+ expect(bundles, hasLength(1));
+ // We get the unlinked bundle for 'aaa' because it already exists.
+ {
+ PackageBundle bundle = _getBundleByPackageName(bundles, 'aaa');
+ expect(bundle, isNotNull);
+ }
+ }
+
+ // Wait for unlinked bundles to be computed.
+ await manager.onUnlinkedComplete;
+ Map<PubPackage, PackageBundle> bundles =
+ manager.getUnlinkedBundles(context);
+ expect(bundles, hasLength(2));
+ // We still have the unlinked bundle for 'aaa'.
+ {
+ PackageBundle bundle = _getBundleByPackageName(bundles, 'aaa');
+ expect(bundle, isNotNull);
+ }
+ // We computed the unlinked bundle for 'bbb'.
+ {
+ PackageBundle bundle = _getBundleByPackageName(bundles, 'bbb');
+ expect(bundle.linkedLibraryUris, isEmpty);
+ expect(bundle.unlinkedUnitUris, ['package:bbb/b.dart']);
+ expect(bundle.unlinkedUnits, hasLength(1));
+ expect(bundle.unlinkedUnits[0].classes.map((c) => c.name), ['B']);
+ }
+
+ // The files must be created.
+ _assertFileExists(libFolderB.parent, PubSummaryManager.UNLINKED_NAME);
+ _assertFileExists(libFolderB.parent, PubSummaryManager.UNLINKED_SPEC_NAME);
}
test_getUnlinkedBundles_nullPackageMap() async {
@@ -220,36 +877,44 @@
isFalse);
}
- void _assertLinkedNameReference(
- UnlinkedUnit unlinkedUnit,
- LinkedLibrary linkedLibrary,
- LinkedUnit linkedUnit,
- int typeNameReference,
- String expectedName,
- String expectedDependencyUri) {
- expect(unlinkedUnit.references[typeNameReference].name, expectedName);
- int typeNameDependency =
- linkedUnit.references[typeNameReference].dependency;
- expect(linkedLibrary.dependencies[typeNameDependency].uri,
- expectedDependencyUri);
+ void _assertFileExists(Folder folder, String fileName) {
+ expect(folder.getChildAssumingFile(fileName).exists, isTrue);
}
- /**
- * Compute element based summary bundle for the given [sdk].
- */
- static PackageBundle getSdkBundle(DartSdk sdk) {
- return sdkBundleMap.putIfAbsent(sdk, () {
- PackageBundleAssembler assembler = new PackageBundleAssembler();
- for (SdkLibrary sdkLibrary in sdk.sdkLibraries) {
- String uriStr = sdkLibrary.shortName;
- Source source = sdk.mapDartUri(uriStr);
- LibraryElement libraryElement =
- sdk.context.computeLibraryElement(source);
- assembler.serializeLibraryElement(libraryElement);
+ void _assertHasLinkedVariable(
+ LinkedPubPackage linkedPackage,
+ String variableName,
+ String expectedTypeName,
+ String expectedTypeNameUri) {
+ PackageBundle unlinked = linkedPackage.unlinked;
+ PackageBundle linked = linkedPackage.linked;
+ expect(unlinked, isNotNull);
+ expect(linked, isNotNull);
+ for (int i = 0; i < unlinked.unlinkedUnitUris.length; i++) {
+ String unlinkedUnitUri = unlinked.unlinkedUnitUris[i];
+ UnlinkedUnit unlinkedUnit = unlinked.unlinkedUnits[i];
+ for (UnlinkedVariable v in unlinkedUnit.variables) {
+ if (v.name == variableName) {
+ int typeNameReference = v.type.reference;
+ expect(unlinkedUnit.references[typeNameReference].name,
+ expectedTypeName);
+ for (int j = 0; j < linked.linkedLibraryUris.length; j++) {
+ String linkedLibraryUri = linked.linkedLibraryUris[j];
+ if (linkedLibraryUri == unlinkedUnitUri) {
+ LinkedLibrary linkedLibrary = linked.linkedLibraries[j];
+ LinkedUnit linkedUnit = linkedLibrary.units.single;
+ int typeNameDependency =
+ linkedUnit.references[typeNameReference].dependency;
+ expect(linkedLibrary.dependencies[typeNameDependency].uri,
+ expectedTypeNameUri);
+ return;
+ }
+ }
+ fail('Cannot find linked unit for $variableName in $linkedPackage');
+ }
}
- List<int> bytes = assembler.assemble().toBuffer();
- return new PackageBundle.fromBuffer(bytes);
- });
+ }
+ fail('Cannot find variable $variableName in $linkedPackage');
}
static PackageBundle _getBundleByPackageName(
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index cb6cfeb..bca5068 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -20,6 +20,7 @@
import 'package:analyzer/src/summary/summarize_elements.dart'
show PackageBundleAssembler;
import 'package:analyzer/task/dart.dart' show PARSED_UNIT;
+import 'package:analyzer/task/general.dart';
import 'package:unittest/unittest.dart';
import '../../reflective_tests.dart';
@@ -714,7 +715,8 @@
/**
* Abstract mixin for serializing ASTs and resynthesizing elements from it.
*/
-abstract class _AstResynthesizeTestMixin {
+abstract class _AstResynthesizeTestMixin
+ implements _AstResynthesizeTestMixinInterface {
final Set<Source> serializedSources = new Set<Source>();
final PackageBundleAssembler bundleAssembler = new PackageBundleAssembler();
final Map<String, UnlinkedUnitBuilder> uriToUnit =
@@ -743,7 +745,7 @@
Map<String, LinkedLibrary> sdkLibraries =
SerializedMockSdk.instance.uriToLinkedLibrary;
LinkedLibrary linkedLibrary = sdkLibraries[absoluteUri];
- if (linkedLibrary == null) {
+ if (linkedLibrary == null && !allowMissingFiles) {
fail('Linker unexpectedly requested LinkedLibrary for "$absoluteUri".'
' Libraries available: ${sdkLibraries.keys}');
}
@@ -753,7 +755,7 @@
UnlinkedUnit getUnit(String absoluteUri) {
UnlinkedUnit unit = uriToUnit[absoluteUri] ??
SerializedMockSdk.instance.uriToUnlinkedUnit[absoluteUri];
- if (unit == null) {
+ if (unit == null && !allowMissingFiles) {
fail('Linker unexpectedly requested unit for "$absoluteUri".');
}
return unit;
@@ -777,7 +779,8 @@
..addAll(unlinkedSummaries),
new Map<String, LinkedLibrary>()
..addAll(SerializedMockSdk.instance.uriToLinkedLibrary)
- ..addAll(linkedSummaries));
+ ..addAll(linkedSummaries),
+ allowMissingFiles);
}
UnlinkedUnit _getUnlinkedUnit(Source source) {
@@ -790,6 +793,14 @@
}
}
return uriToUnit.putIfAbsent(uriStr, () {
+ int modificationTime = context.computeResult(source, MODIFICATION_TIME);
+ if (modificationTime < 0) {
+ // Source does not exist.
+ if (!allowMissingFiles) {
+ fail('Unexpectedly tried to get unlinked summary for $source');
+ }
+ return null;
+ }
CompilationUnit unit = context.computeResult(source, PARSED_UNIT);
UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
bundleAssembler.addUnlinkedUnit(source, unlinkedUnit);
@@ -820,14 +831,30 @@
}
UnlinkedPublicNamespace getImport(String relativeUri) {
- return getPart(relativeUri).publicNamespace;
+ return getPart(relativeUri)?.publicNamespace;
}
UnlinkedUnit definingUnit = _getUnlinkedUnit(librarySource);
- LinkedLibraryBuilder linkedLibrary =
- prelink(definingUnit, getPart, getImport);
- linkedLibrary.dependencies.skip(1).forEach((LinkedDependency d) {
- _serializeLibrary(resolveRelativeUri(d.uri));
- });
+ if (definingUnit != null) {
+ LinkedLibraryBuilder linkedLibrary =
+ prelink(definingUnit, getPart, getImport);
+ linkedLibrary.dependencies.skip(1).forEach((LinkedDependency d) {
+ _serializeLibrary(resolveRelativeUri(d.uri));
+ });
+ }
}
}
+
+/**
+ * Interface that [_AstResynthesizeTestMixin] requires of classes it's mixed
+ * into. We can't place the getter below into [_AstResynthesizeTestMixin]
+ * directly, because then it would be overriding a field at the site where the
+ * mixin is instantiated.
+ */
+abstract class _AstResynthesizeTestMixinInterface {
+ /**
+ * A test should return `true` to indicate that a missing file at the time of
+ * summary resynthesis shouldn't trigger an error.
+ */
+ bool get allowMissingFiles;
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart b/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
index d337de7..63b8c2c 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
@@ -25,4 +25,11 @@
@override
AnalysisOptionsImpl createOptions() =>
super.createOptions()..strongMode = true;
+
+ @override
+ @failingTest
+ test_instantiateToBounds_boundRefersToLaterTypeArgument() {
+ // TODO(paulberry): this is failing due to dartbug.com/27072.
+ super.test_instantiateToBounds_boundRefersToLaterTypeArgument();
+ }
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index 679741d..f08366b8 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -49,6 +49,12 @@
*/
Set<String> variablesWithNotConstInitializers = new Set<String>();
+ /**
+ * Tests may set this to `true` to indicate that a missing file at the time of
+ * summary resynthesis shouldn't trigger an error.
+ */
+ bool allowMissingFiles = false;
+
bool get checkPropagatedTypes => true;
void addLibrary(String uri) {
@@ -1184,7 +1190,7 @@
});
}
return new TestSummaryResynthesizer(
- null, context, unlinkedSummaries, linkedSummaries);
+ null, context, unlinkedSummaries, linkedSummaries, allowMissingFiles);
}
ElementImpl getActualElement(Element element, String desc) {
@@ -1331,13 +1337,6 @@
return false;
} else if (modifier == Modifier.SYNTHETIC) {
return element.isSynthetic;
- } else if (modifier == Modifier.URI_EXISTS) {
- if (element is ExportElement) {
- return element.uriExists;
- } else if (element is ImportElement) {
- return element.uriExists;
- }
- return false;
}
throw new UnimplementedError(
'Modifier $modifier for ${element?.runtimeType}');
@@ -1422,7 +1421,7 @@
});
}
return new TestSummaryResynthesizer(
- null, context, unlinkedSummaries, linkedSummaries);
+ null, context, unlinkedSummaries, linkedSummaries, allowMissingFiles);
}
/**
@@ -3607,6 +3606,34 @@
''');
}
+ test_instantiateToBounds_boundRefersToEarlierTypeArgument() {
+ checkLibrary('''
+class C<S extends num, T extends C<S, T>> {}
+C c;
+''');
+ }
+
+ test_instantiateToBounds_boundRefersToItself() {
+ checkLibrary('''
+class C<T extends C<T>> {}
+C c;
+''');
+ }
+
+ test_instantiateToBounds_boundRefersToLaterTypeArgument() {
+ checkLibrary('''
+class C<T extends C<T, U>, U extends num> {}
+C c;
+''');
+ }
+
+ test_instantiateToBounds_simple() {
+ checkLibrary('''
+class C<T extends num> {}
+C c;
+''');
+ }
+
test_library() {
checkLibrary('');
}
@@ -4476,6 +4503,21 @@
checkLibrary('f() {} g() {}');
}
+ test_unresolved_export() {
+ allowMissingFiles = true;
+ checkLibrary("export 'foo.dart';", allowErrors: true);
+ }
+
+ test_unresolved_import() {
+ allowMissingFiles = true;
+ checkLibrary("import 'foo.dart';", allowErrors: true);
+ }
+
+ test_unresolved_part() {
+ allowMissingFiles = true;
+ checkLibrary("part 'foo.dart';", allowErrors: true);
+ }
+
test_unused_type_parameter() {
checkLibrary('''
class C<T> {
@@ -4588,6 +4630,7 @@
class TestSummaryResynthesizer extends SummaryResynthesizer {
final Map<String, UnlinkedUnit> unlinkedSummaries;
final Map<String, LinkedLibrary> linkedSummaries;
+ final bool allowMissingFiles;
/**
* The set of uris for which unlinked summaries have been requested using
@@ -4602,7 +4645,7 @@
final Set<String> linkedSummariesRequested = new Set<String>();
TestSummaryResynthesizer(SummaryResynthesizer parent, AnalysisContext context,
- this.unlinkedSummaries, this.linkedSummaries)
+ this.unlinkedSummaries, this.linkedSummaries, this.allowMissingFiles)
: super(parent, context, context.typeProvider, context.sourceFactory,
context.analysisOptions.strongMode);
@@ -4610,7 +4653,7 @@
LinkedLibrary getLinkedSummary(String uri) {
linkedSummariesRequested.add(uri);
LinkedLibrary serializedLibrary = linkedSummaries[uri];
- if (serializedLibrary == null) {
+ if (serializedLibrary == null && !allowMissingFiles) {
fail('Unexpectedly tried to get linked summary for $uri');
}
return serializedLibrary;
@@ -4620,7 +4663,7 @@
UnlinkedUnit getUnlinkedSummary(String uri) {
unlinkedSummariesRequested.add(uri);
UnlinkedUnit serializedUnit = unlinkedSummaries[uri];
- if (serializedUnit == null) {
+ if (serializedUnit == null && !allowMissingFiles) {
fail('Unexpectedly tried to get unlinked summary for $uri');
}
return serializedUnit;
diff --git a/pkg/analyzer/test/src/summary/summarize_ast_test.dart b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
index e3c7f52..b24daf9 100644
--- a/pkg/analyzer/test/src/summary/summarize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
@@ -319,8 +319,9 @@
return null;
}
- LinkerInputs createLinkerInputs(String text, {String path: '/test.dart'}) {
- Uri testDartUri = Uri.parse(absUri(path));
+ LinkerInputs createLinkerInputs(String text, {String path: '/test.dart', String uri}) {
+ uri ??= absUri(path);
+ Uri testDartUri = Uri.parse(uri);
CompilationUnit unit = _parseText(text);
UnlinkedUnitBuilder unlinkedDefiningUnit = serializeAstUnlinked(unit);
_filesToLink.uriToUnit[testDartUri.toString()] = unlinkedDefiningUnit;
@@ -343,10 +344,10 @@
* can be created.
*/
PackageBundleBuilder createPackageBundle(String text,
- {String path: '/test.dart'}) {
+ {String path: '/test.dart', String uri}) {
PackageBundleAssembler assembler = new PackageBundleAssembler();
assembler.recordDependencies(_filesToLink.summaryDataStore);
- LinkerInputs linkerInputs = createLinkerInputs(text, path: path);
+ LinkerInputs linkerInputs = createLinkerInputs(text, path: path, uri: uri);
Map<String, LinkedLibraryBuilder> linkedLibraries = link(
linkerInputs.linkedLibraries,
linkerInputs.getDependency,
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index d5f2876..09af948 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -1309,6 +1309,35 @@
expect(cls.interfaces, isEmpty);
}
+ test_unresolved_import() {
+ allowMissingFiles = true;
+ serializeLibraryText("import 'foo.dart';", allowErrors: true);
+ expect(unlinkedUnits[0].imports, hasLength(2));
+ expect(unlinkedUnits[0].imports[0].uri, 'foo.dart');
+ // Note: imports[1] is the implicit import of dart:core.
+ expect(unlinkedUnits[0].imports[1].isImplicit, true);
+ expect(linked.importDependencies, hasLength(2));
+ checkDependency(
+ linked.importDependencies[0], absUri('/foo.dart'), 'foo.dart');
+ }
+
+ test_unresolved_export() {
+ allowMissingFiles = true;
+ serializeLibraryText("export 'foo.dart';", allowErrors: true);
+ expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.exports[0].uri, 'foo.dart');
+ expect(linked.exportDependencies, hasLength(1));
+ checkDependency(
+ linked.exportDependencies[0], absUri('/foo.dart'), 'foo.dart');
+ }
+
+ test_unresolved_part() {
+ allowMissingFiles = true;
+ serializeLibraryText("part 'foo.dart';", allowErrors: true);
+ expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.parts[0], 'foo.dart');
+ }
+
test_class_no_mixins() {
UnlinkedClass cls = serializeClassText('class C {}');
expect(cls.mixins, isEmpty);
@@ -2702,8 +2731,11 @@
test_constExpr_pushInt_max() {
UnlinkedVariable variable = serializeVariableText('const v = 0xFFFFFFFF;');
- _assertUnlinkedConst(variable.initializer.bodyExpr,
- operators: [UnlinkedConstOperation.pushInt,], ints: [0xFFFFFFFF]);
+ _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
+ UnlinkedConstOperation.pushInt,
+ ], ints: [
+ 0xFFFFFFFF
+ ]);
}
test_constExpr_pushInt_negative() {
@@ -2726,15 +2758,26 @@
test_constExpr_pushLongInt_min2() {
UnlinkedVariable variable = serializeVariableText('const v = 0x100000000;');
- _assertUnlinkedConst(variable.initializer.bodyExpr,
- operators: [UnlinkedConstOperation.pushLongInt], ints: [2, 1, 0,]);
+ _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
+ UnlinkedConstOperation.pushLongInt
+ ], ints: [
+ 2,
+ 1,
+ 0,
+ ]);
}
test_constExpr_pushLongInt_min3() {
UnlinkedVariable variable =
serializeVariableText('const v = 0x10000000000000000;');
- _assertUnlinkedConst(variable.initializer.bodyExpr,
- operators: [UnlinkedConstOperation.pushLongInt], ints: [3, 1, 0, 0,]);
+ _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
+ UnlinkedConstOperation.pushLongInt
+ ], ints: [
+ 3,
+ 1,
+ 0,
+ 0,
+ ]);
}
test_constExpr_pushNull() {
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index c274834..c01223c 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -2999,6 +2999,26 @@
InterfaceType intType = context.typeProvider.intType;
expect(expression.staticType, intType);
}
+
+ test_staticModeHints_forStaticVariableInference() {
+ context.analysisOptions =
+ new AnalysisOptionsImpl.from(context.analysisOptions)
+ ..strongModeHints = true;
+ Source source = newSource(
+ '/test.dart',
+ r'''
+var V = [42];
+''');
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+ computeResult(target, RESOLVED_UNIT9);
+ expect(outputs[RESOLVED_UNIT9], isNotNull);
+ expect(outputs[CREATED_RESOLVED_UNIT9], isTrue);
+ // An INFERRED_TYPE_LITERAL error should be generated.
+ List<AnalysisError> errors = outputs[
+ STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT] as List<AnalysisError>;
+ expect(errors, hasLength(1));
+ expect(errors[0].errorCode, StrongModeCode.INFERRED_TYPE_LITERAL);
+ }
}
@reflectiveTest
@@ -3544,6 +3564,7 @@
SimpleIdentifier reference = statement.expression;
expect(reference.staticElement, isResolved ? isNotNull : isNull);
}
+
//
// The reference to 'A' in 'f1' should not be resolved.
//
@@ -5682,7 +5703,21 @@
]);
}
- test_perform_directiveError() {
+ test_perform_directiveError_generated() {
+ Source source = newSource(
+ '/test.dart',
+ '''
+import 'generated-file.g.dart';
+''');
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+ computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask);
+ // validate
+ _fillErrorListener(VERIFY_ERRORS);
+ errorListener.assertErrorsWithCodes(
+ <ErrorCode>[CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED]);
+ }
+
+ test_perform_directiveError_nonGenerated() {
Source source = newSource(
'/test.dart',
'''
@@ -5785,6 +5820,7 @@
matcher: matcher);
return outputs[result];
}
+
return sources.map(compute).toList();
}
@@ -5795,6 +5831,7 @@
computeResult(source, result, matcher: matcher);
return outputs;
}
+
return sources.map(compute).toList();
}
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index ab82982..1f34f61 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -113,6 +113,15 @@
''');
}
+ void test_callMethodOnFunctions() {
+ checkFile(r'''
+void f(int x) => print(x);
+main() {
+ f.call(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi');
+}
+ ''');
+ }
+
void test_castsInConditions() {
checkFile('''
main() {
@@ -798,13 +807,13 @@
Left f;
f = /*error:STATIC_TYPE_ERROR*/top;
f = left;
- f = /*error:STATIC_TYPE_ERROR*/right;
+ f = /*error:INVALID_ASSIGNMENT*/right;
f = bot;
}
{
Right f;
f = /*error:STATIC_TYPE_ERROR*/top;
- f = /*error:STATIC_TYPE_ERROR*/left;
+ f = /*error:INVALID_ASSIGNMENT*/left;
f = right;
f = bot;
}
@@ -844,13 +853,13 @@
Left f;
f = /*warning:DOWN_CAST_COMPOSITE*/top;
f = left;
- f = /*warning:DOWN_CAST_COMPOSITE*/right;
+ f = /*error:INVALID_ASSIGNMENT*/right;
f = bot;
}
{
Right f;
f = /*warning:DOWN_CAST_COMPOSITE*/top;
- f = /*warning:DOWN_CAST_COMPOSITE*/left;
+ f = /*error:INVALID_ASSIGNMENT*/left;
f = right;
f = bot;
}
@@ -931,14 +940,14 @@
f = topTop;
f = aa;
f = aTop;
- f = /*warning:DOWN_CAST_COMPOSITE should be error:STATIC_TYPE_ERROR*/botA;
+ f = /*error:INVALID_ASSIGNMENT*/botA;
f = /*warning:DOWN_CAST_COMPOSITE*/botTop;
apply/*<ATop>*/(
topA,
topTop,
aa,
aTop,
- /*warning:DOWN_CAST_COMPOSITE should be error:STATIC_TYPE_ERROR*/botA,
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA,
/*warning:DOWN_CAST_COMPOSITE*/botTop
);
apply/*<ATop>*/(
@@ -946,31 +955,31 @@
(dynamic x) => (x as Object),
(A x) => x,
(A x) => null,
- /*warning:DOWN_CAST_COMPOSITE should be error:STATIC_TYPE_ERROR*/botA,
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA,
/*warning:DOWN_CAST_COMPOSITE*/botTop
);
}
{
BotA f;
f = topA;
- f = /*error:STATIC_TYPE_ERROR*/topTop;
+ f = /*error:INVALID_ASSIGNMENT*/topTop;
f = aa;
- f = /*error:STATIC_TYPE_ERROR*/aTop;
+ f = /*error:INVALID_ASSIGNMENT*/aTop;
f = botA;
f = /*warning:DOWN_CAST_COMPOSITE*/botTop;
apply/*<BotA>*/(
topA,
- /*error:STATIC_TYPE_ERROR*/topTop,
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/topTop,
aa,
- /*error:STATIC_TYPE_ERROR*/aTop,
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/aTop,
botA,
/*warning:DOWN_CAST_COMPOSITE*/botTop
);
apply/*<BotA>*/(
(dynamic x) => new A(),
- /*error:STATIC_TYPE_ERROR*/(dynamic x) => (x as Object),
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(dynamic x) => (x as Object),
(A x) => x,
- /*error:STATIC_TYPE_ERROR*/(A x) => (x as Object),
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(A x) => (x as Object),
botA,
/*warning:DOWN_CAST_COMPOSITE*/botTop
);
@@ -978,14 +987,14 @@
{
AA f;
f = topA;
- f = /*error:STATIC_TYPE_ERROR*/topTop;
+ f = /*error:INVALID_ASSIGNMENT*/topTop;
f = aa;
f = /*error:STATIC_TYPE_ERROR*/aTop; // known function
f = /*warning:DOWN_CAST_COMPOSITE*/botA;
f = /*warning:DOWN_CAST_COMPOSITE*/botTop;
apply/*<AA>*/(
topA,
- /*error:STATIC_TYPE_ERROR*/topTop,
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/topTop,
aa,
/*error:STATIC_TYPE_ERROR*/aTop, // known function
/*warning:DOWN_CAST_COMPOSITE*/botA,
@@ -993,7 +1002,7 @@
);
apply/*<AA>*/(
(dynamic x) => new A(),
- /*error:STATIC_TYPE_ERROR*/(dynamic x) => (x as Object),
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(dynamic x) => (x as Object),
(A x) => x,
/*error:STATIC_TYPE_ERROR*/(A x) => (x as Object), // known function
/*warning:DOWN_CAST_COMPOSITE*/botA,
@@ -1004,24 +1013,24 @@
TopTop f;
f = topA;
f = topTop;
- f = /*error:STATIC_TYPE_ERROR*/aa;
+ f = /*error:INVALID_ASSIGNMENT*/aa;
f = /*error:STATIC_TYPE_ERROR*/aTop; // known function
- f = /*warning:DOWN_CAST_COMPOSITE should be error:STATIC_TYPE_ERROR*/botA;
+ f = /*error:INVALID_ASSIGNMENT*/botA;
f = /*warning:DOWN_CAST_COMPOSITE*/botTop;
apply/*<TopTop>*/(
topA,
topTop,
- /*error:STATIC_TYPE_ERROR*/aa,
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/aa,
/*error:STATIC_TYPE_ERROR*/aTop, // known function
- /*warning:DOWN_CAST_COMPOSITE should be error:STATIC_TYPE_ERROR*/botA,
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA,
/*warning:DOWN_CAST_COMPOSITE*/botTop
);
apply/*<TopTop>*/(
(dynamic x) => new A(),
(dynamic x) => (x as Object),
- /*error:STATIC_TYPE_ERROR*/(A x) => x,
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(A x) => x,
/*error:STATIC_TYPE_ERROR*/(A x) => (x as Object), // known function
- /*warning:DOWN_CAST_COMPOSITE should be error:STATIC_TYPE_ERROR*/botA,
+ /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA,
/*warning:DOWN_CAST_COMPOSITE*/botTop
);
}
@@ -1132,16 +1141,16 @@
f = bot;
}
{
- Function2<B, B> f;
+ Function2<B, B> f; // left
f = /*error:STATIC_TYPE_ERROR*/top;
f = left;
- f = /*error:STATIC_TYPE_ERROR*/right;
+ f = /*error:INVALID_ASSIGNMENT*/right;
f = bot;
}
{
- Function2<A, A> f;
+ Function2<A, A> f; // right
f = /*error:STATIC_TYPE_ERROR*/top;
- f = /*error:STATIC_TYPE_ERROR*/left;
+ f = /*error:INVALID_ASSIGNMENT*/left;
f = right;
f = bot;
}
@@ -1177,12 +1186,12 @@
left = /*warning:DOWN_CAST_COMPOSITE*/top;
left = left;
- left = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
+ left = /*error:INVALID_ASSIGNMENT*/right;
left = bot;
- right = /*warning:DOWN_CAST_COMPOSITE*/top;
- right = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
- right = right;
+ right = /*info:INVALID_ASSIGNMENT,warning:DOWN_CAST_COMPOSITE*/top;
+ right = /*error:INVALID_ASSIGNMENT*/left;
+ right = /*info:INVALID_ASSIGNMENT*/right;
right = bot;
bot = /*warning:DOWN_CAST_COMPOSITE*/top;
@@ -1222,13 +1231,13 @@
Function2<AToB, AToB> f; // Left
f = /*error:STATIC_TYPE_ERROR*/top;
f = left;
- f = /*error:STATIC_TYPE_ERROR*/right;
+ f = /*error:INVALID_ASSIGNMENT*/right;
f = bot;
}
{
Function2<BToA, BToA> f; // Right
f = /*error:STATIC_TYPE_ERROR*/top;
- f = /*error:STATIC_TYPE_ERROR*/left;
+ f = /*error:INVALID_ASSIGNMENT*/left;
f = right;
f = bot;
}
@@ -1237,7 +1246,7 @@
f = bot;
f = /*error:STATIC_TYPE_ERROR*/left;
f = /*error:STATIC_TYPE_ERROR*/top;
- f = /*error:STATIC_TYPE_ERROR*/left;
+ f = /*error:STATIC_TYPE_ERROR*/right;
}
}
''');
@@ -1271,13 +1280,13 @@
Function2<AToB, AToB> f; // Left
f = /*error:STATIC_TYPE_ERROR*/top;
f = left;
- f = /*error:STATIC_TYPE_ERROR*/right;
+ f = /*error:INVALID_ASSIGNMENT*/right;
f = bot;
}
{
Function2<BToA, BToA> f; // Right
f = /*error:STATIC_TYPE_ERROR*/top;
- f = /*error:STATIC_TYPE_ERROR*/left;
+ f = /*error:INVALID_ASSIGNMENT*/left;
f = right;
f = bot;
}
@@ -1286,7 +1295,7 @@
f = bot;
f = /*error:STATIC_TYPE_ERROR*/left;
f = /*error:STATIC_TYPE_ERROR*/top;
- f = /*error:STATIC_TYPE_ERROR*/left;
+ f = /*error:STATIC_TYPE_ERROR*/right;
}
}
''');
@@ -1320,13 +1329,13 @@
Function2<AToB, AToB> f; // Left
f = /*error:STATIC_TYPE_ERROR*/top;
f = left;
- f = /*error:STATIC_TYPE_ERROR*/right;
+ f = /*error:INVALID_ASSIGNMENT*/right;
f = bot;
}
{
Function2<BToA, BToA> f; // Right
f = /*error:STATIC_TYPE_ERROR*/top;
- f = /*error:STATIC_TYPE_ERROR*/left;
+ f = /*error:INVALID_ASSIGNMENT*/left;
f = right;
f = bot;
}
@@ -1335,7 +1344,7 @@
f = bot;
f = /*error:STATIC_TYPE_ERROR*/left;
f = /*error:STATIC_TYPE_ERROR*/top;
- f = /*error:STATIC_TYPE_ERROR*/left;
+ f = /*error:STATIC_TYPE_ERROR*/right;
}
}
''');
@@ -1363,12 +1372,12 @@
left = /*warning:DOWN_CAST_COMPOSITE*/top;
left = left;
left =
- /*warning:DOWN_CAST_COMPOSITE should be error:STATIC_TYPE_ERROR*/right;
+ /*error:INVALID_ASSIGNMENT*/right;
left = bot;
right = /*warning:DOWN_CAST_COMPOSITE*/top;
right =
- /*warning:DOWN_CAST_COMPOSITE should be error:STATIC_TYPE_ERROR*/left;
+ /*error:INVALID_ASSIGNMENT*/left;
right = right;
right = bot;
@@ -1408,13 +1417,13 @@
Function2<B, B> f;
f = /*warning:DOWN_CAST_COMPOSITE*/c.top;
f = c.left;
- f = /*warning:DOWN_CAST_COMPOSITE*/c.right;
+ f = /*error:INVALID_ASSIGNMENT*/c.right;
f = c.bot;
}
{
Function2<A, A> f;
f = /*warning:DOWN_CAST_COMPOSITE*/c.top;
- f = /*warning:DOWN_CAST_COMPOSITE*/c.left;
+ f = /*error:INVALID_ASSIGNMENT*/c.left;
f = c.right;
f = c.bot;
}
@@ -1466,13 +1475,13 @@
Left f;
f = /*warning:DOWN_CAST_COMPOSITE*/top;
f = left;
- f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
+ f = /*error:INVALID_ASSIGNMENT*/right;
f = bot;
}
{
Right f;
f = /*warning:DOWN_CAST_COMPOSITE*/top;
- f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
+ f = /*error:INVALID_ASSIGNMENT*/left;
f = right;
f = bot;
}
@@ -1623,7 +1632,7 @@
f = new A();
f = /*error:INVALID_ASSIGNMENT*/new B();
f = i2i;
- f = /*error:STATIC_TYPE_ERROR*/n2n;
+ f = /*error:INVALID_ASSIGNMENT*/n2n;
f = /*warning:DOWN_CAST_COMPOSITE*/i2i as Object;
f = /*warning:DOWN_CAST_COMPOSITE*/n2n as Function;
}
@@ -1631,7 +1640,7 @@
N2N f;
f = /*error:INVALID_ASSIGNMENT*/new A();
f = new B();
- f = /*error:STATIC_TYPE_ERROR*/i2i;
+ f = /*error:INVALID_ASSIGNMENT*/i2i;
f = n2n;
f = /*warning:DOWN_CAST_COMPOSITE*/i2i as Object;
f = /*warning:DOWN_CAST_COMPOSITE*/n2n as Function;
@@ -1693,13 +1702,13 @@
Function2<B, B> f;
f = /*error:STATIC_TYPE_ERROR*/C.top;
f = C.left;
- f = /*error:STATIC_TYPE_ERROR*/C.right;
+ f = /*error:INVALID_ASSIGNMENT*/C.right;
f = C.bot;
}
{
Function2<A, A> f;
f = /*error:STATIC_TYPE_ERROR*/C.top;
- f = /*error:STATIC_TYPE_ERROR*/C.left;
+ f = /*error:INVALID_ASSIGNMENT*/C.left;
f = C.right;
f = C.bot;
}
@@ -1753,7 +1762,7 @@
checkFile('''
typedef num Num2Num(num x);
void main() {
- Num2Num g = /*info:INFERRED_TYPE_CLOSURE,error:STATIC_TYPE_ERROR*/(int x) { return x; };
+ Num2Num g = /*info:INFERRED_TYPE_CLOSURE,error:INVALID_ASSIGNMENT*/(int x) { return x; };
print(g(42));
}
''');
@@ -2977,6 +2986,19 @@
''');
}
+ void test_nullCoalescingStrictArrow() {
+ checkFile(r'''
+bool _alwaysTrue(x) => true;
+typedef bool TakesA<T>(T t);
+class C<T> {
+ TakesA<T> g;
+ C(TakesA<T> f)
+ : g = f ?? _alwaysTrue;
+ C.a() : g = _alwaysTrue;
+}
+ ''');
+ }
+
void test_optionalParams() {
// Regression test for https://github.com/dart-lang/sdk/issues/26155
checkFile(r'''
@@ -2987,6 +3009,23 @@
''');
}
+ void test_overrideNarrowsType() {
+ addFile(r'''
+class A {}
+class B extends A {}
+
+abstract class C {
+ m(A a);
+ n(B b);
+}
+abstract class D extends C {
+ /*error:INVALID_METHOD_OVERRIDE*/m(/*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B b);
+ n(A a);
+}
+ ''');
+ check(implicitCasts: false);
+ }
+
void test_privateOverride() {
addFile(
'''
@@ -3114,7 +3153,7 @@
lOfOs = new L<Object>(); // Reset type propagation.
}
{
- lOfAs = /*warning:DOWN_CAST_COMPOSITE*/mOfDs;
+ lOfAs = /*error:INVALID_ASSIGNMENT*/mOfDs;
lOfAs = /*error:INVALID_ASSIGNMENT*/mOfOs;
lOfAs = mOfAs;
lOfAs = /*warning:DOWN_CAST_COMPOSITE*/lOfDs;
@@ -3128,7 +3167,7 @@
mOfDs = mOfAs;
mOfDs = /*info:DOWN_CAST_IMPLICIT*/lOfDs;
mOfDs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
- mOfDs = /*warning:DOWN_CAST_COMPOSITE*/lOfAs;
+ mOfDs = /*error:INVALID_ASSIGNMENT*/lOfAs;
mOfDs = new M(); // Reset type propagation.
}
{
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 816d2d6..c8f2e01 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -1237,8 +1237,8 @@
A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new B.named("hello", 3);
A<int, String> a2 = new B<String, int>("hello", 3);
A<int, String> a3 = new B<String, int>.named("hello", 3);
- A<int, String> a4 = /*error:STATIC_TYPE_ERROR*/new B<String, dynamic>("hello", 3);
- A<int, String> a5 = /*error:STATIC_TYPE_ERROR*/new B<dynamic, dynamic>.named("hello", 3);
+ A<int, String> a4 = /*error:INVALID_ASSIGNMENT*/new B<String, dynamic>("hello", 3);
+ A<int, String> a5 = /*error:INVALID_ASSIGNMENT*/new B<dynamic, dynamic>.named("hello", 3);
}
{
A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new B(
@@ -1253,8 +1253,8 @@
A<int, int> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new C.named(3);
A<int, int> a2 = new C<int>(3);
A<int, int> a3 = new C<int>.named(3);
- A<int, int> a4 = /*error:STATIC_TYPE_ERROR*/new C<dynamic>(3);
- A<int, int> a5 = /*error:STATIC_TYPE_ERROR*/new C<dynamic>.named(3);
+ A<int, int> a4 = /*error:INVALID_ASSIGNMENT*/new C<dynamic>(3);
+ A<int, int> a5 = /*error:INVALID_ASSIGNMENT*/new C<dynamic>.named(3);
}
{
A<int, int> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new C(
@@ -1267,8 +1267,8 @@
A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new D.named("hello");
A<int, String> a2 = new D<int, String>("hello");
A<int, String> a3 = new D<String, String>.named("hello");
- A<int, String> a4 = /*error:STATIC_TYPE_ERROR*/new D<num, dynamic>("hello");
- A<int, String> a5 = /*error:STATIC_TYPE_ERROR*/new D<dynamic, dynamic>.named("hello");
+ A<int, String> a4 = /*error:INVALID_ASSIGNMENT*/new D<num, dynamic>("hello");
+ A<int, String> a5 = /*error:INVALID_ASSIGNMENT*/new D<dynamic, dynamic>.named("hello");
}
{
A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new D(
@@ -1761,11 +1761,11 @@
takeIIO(math.max);
takeDDO(math.max);
-takeOOI(/*error:STATIC_TYPE_ERROR,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
-takeIDI(/*error:STATIC_TYPE_ERROR,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
-takeDID(/*error:STATIC_TYPE_ERROR,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
-takeOON(/*error:STATIC_TYPE_ERROR,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
-takeOOO(/*error:STATIC_TYPE_ERROR,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
+takeOOI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
+takeIDI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
+takeDID(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
+takeOON(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
+takeOOO(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
// Also test SimpleIdentifier
takeIII(min);
@@ -1778,11 +1778,11 @@
takeIIO(min);
takeDDO(min);
-takeOOI(/*error:STATIC_TYPE_ERROR,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
-takeIDI(/*error:STATIC_TYPE_ERROR,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
-takeDID(/*error:STATIC_TYPE_ERROR,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
-takeOON(/*error:STATIC_TYPE_ERROR,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
-takeOOO(/*error:STATIC_TYPE_ERROR,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
+takeOOI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
+takeIDI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
+takeDID(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
+takeOON(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
+takeOOO(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
// Also PropertyAccess
takeIII(new C().m);
@@ -1804,14 +1804,14 @@
//
// That's legal because we're loosening parameter types.
//
-takeOON(/*warning:DOWN_CAST_COMPOSITE,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
-takeOOO(/*warning:DOWN_CAST_COMPOSITE,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
+takeOON(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
+takeOOO(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
// Note: this is a warning because a downcast of a method tear-off could work
// in "normal" Dart, due to bivariance.
-takeOOI(/*warning:DOWN_CAST_COMPOSITE,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
-takeIDI(/*warning:DOWN_CAST_COMPOSITE,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
-takeDID(/*warning:DOWN_CAST_COMPOSITE,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
+takeOOI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
+takeIDI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
+takeDID(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
}
void takeIII(int fn(int a, int b)) {}
diff --git a/pkg/analyzer/test/stress/for_git_repository.dart b/pkg/analyzer/test/stress/for_git_repository.dart
index ee8dab2..2ee3929 100644
--- a/pkg/analyzer/test/stress/for_git_repository.dart
+++ b/pkg/analyzer/test/stress/for_git_repository.dart
@@ -17,10 +17,10 @@
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/task/dart.dart';
@@ -99,6 +99,7 @@
});
return map;
}
+
Map<String, FileInfo> newFiles = toMap(this);
Map<String, FileInfo> oldFiles = toMap(oldFolder);
Set<String> addedPaths = newFiles.keys.toSet()..removeAll(oldFiles.keys);
@@ -241,10 +242,10 @@
assert(actualContext == null);
resourceProvider = PhysicalResourceProvider.INSTANCE;
pathContext = resourceProvider.pathContext;
- sdkManager = new DartSdkManager(
- DirectoryBasedDartSdk.defaultSdkDirectory.getAbsolutePath(),
- false,
- (_) => DirectoryBasedDartSdk.defaultSdk);
+ fs.Folder sdkDirectory =
+ FolderBasedDartSdk.defaultSdkDirectory(resourceProvider);
+ sdkManager = new DartSdkManager(sdkDirectory.path, false,
+ (_) => new FolderBasedDartSdk(resourceProvider, sdkDirectory));
contentCache = new ContentCache();
ContextBuilder builder =
new ContextBuilder(resourceProvider, sdkManager, contentCache);
@@ -409,6 +410,7 @@
});
return elements;
}
+
void validateSortedElements(
List<Element> actualElements, List<Element> expectedElements) {
expect(actualElements, hasLength(expectedElements.length));
@@ -418,6 +420,7 @@
_validateElements(actualElements[i], expectedElements[i], visited);
}
}
+
expect(actualValue?.runtimeType, expectedValue?.runtimeType);
expect(actualValue.nameOffset, expectedValue.nameOffset);
expect(actualValue.name, expectedValue.name);
diff --git a/pkg/analyzer/tool/summary/build_sdk_summaries.dart b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
index bf6d8b5..8a6645d 100644
--- a/pkg/analyzer/tool/summary/build_sdk_summaries.dart
+++ b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
@@ -1,6 +1,7 @@
import 'dart:io';
-import 'package:analyzer/src/generated/sdk_io.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/summary/flat_buffers.dart' as fb;
import 'package:analyzer/src/summary/summary_file_builder.dart';
@@ -98,7 +99,9 @@
return null;
}
} else {
- sdkPath = DirectoryBasedDartSdk.defaultSdkDirectory.getAbsolutePath();
+ sdkPath = FolderBasedDartSdk
+ .defaultSdkDirectory(PhysicalResourceProvider.INSTANCE)
+ .path;
}
//
diff --git a/pkg/analyzer/tool/task_dependency_graph/generate.dart b/pkg/analyzer/tool/task_dependency_graph/generate.dart
index fc88511..0caa453 100644
--- a/pkg/analyzer/tool/task_dependency_graph/generate.dart
+++ b/pkg/analyzer/tool/task_dependency_graph/generate.dart
@@ -26,11 +26,11 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/codegen/tools.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:path/path.dart' as path;
@@ -150,7 +150,8 @@
}
List<String> lines = <String>[];
resourceProvider = PhysicalResourceProvider.INSTANCE;
- DartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
+ DartSdk sdk = new FolderBasedDartSdk(resourceProvider,
+ FolderBasedDartSdk.defaultSdkDirectory(resourceProvider));
context = AnalysisEngine.instance.createAnalysisContext();
String packageRootPath;
if (Platform.packageRoot != null) {
diff --git a/pkg/analyzer/tool/task_dependency_graph/tasks.dot b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
index feb61eb..7cf3d9d 100644
--- a/pkg/analyzer/tool/task_dependency_graph/tasks.dot
+++ b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
@@ -122,8 +122,10 @@
InferInstanceMembersInUnitTask -> CREATED_RESOLVED_UNIT11
InferInstanceMembersInUnitTask -> RESOLVED_UNIT11
InferStaticVariableTypeTask -> INFERRED_STATIC_VARIABLE
+ InferStaticVariableTypeTask -> STATIC_VARIABLE_RESOLUTION_ERRORS
InferStaticVariableTypesInUnitTask -> CREATED_RESOLVED_UNIT9
InferStaticVariableTypesInUnitTask -> RESOLVED_UNIT9
+ InferStaticVariableTypesInUnitTask -> STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT
LIBRARY_CYCLE [shape=box]
LIBRARY_CYCLE_DEPENDENCIES -> InferInstanceMembersInUnitTask
LIBRARY_CYCLE_DEPENDENCIES -> InferStaticVariableTypeTask
@@ -187,6 +189,7 @@
LibraryErrorsReadyTask -> LIBRARY_ERRORS_READY
LibraryUnitErrorsTask -> LIBRARY_UNIT_ERRORS
MODIFICATION_TIME -> BuildDirectiveElementsTask
+ MODIFICATION_TIME -> BuildLibraryElementTask
MODIFICATION_TIME -> ParseDartTask
MODIFICATION_TIME -> ScanDartTask
MODIFICATION_TIME -> VerifyUnitTask
@@ -322,6 +325,10 @@
SCAN_ERRORS [shape=box]
SOURCE_KIND -> BuildDirectiveElementsTask
SOURCE_KIND [shape=box]
+ STATIC_VARIABLE_RESOLUTION_ERRORS -> InferStaticVariableTypesInUnitTask
+ STATIC_VARIABLE_RESOLUTION_ERRORS [shape=box]
+ STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT -> LibraryUnitErrorsTask
+ STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT [shape=box]
STRONG_MODE_ERRORS -> LibraryUnitErrorsTask
STRONG_MODE_ERRORS [shape=box]
ScanDartTask -> IGNORE_INFO
diff --git a/pkg/analyzer_cli/lib/src/build_mode.dart b/pkg/analyzer_cli/lib/src/build_mode.dart
index 5b9ec2c..b69669d 100644
--- a/pkg/analyzer_cli/lib/src/build_mode.dart
+++ b/pkg/analyzer_cli/lib/src/build_mode.dart
@@ -10,11 +10,11 @@
import 'package:analyzer/dart/ast/ast.dart' show CompilationUnit;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/summary/format.dart';
@@ -273,13 +273,13 @@
sdk = summarySdk;
sdkBundle = summarySdk.bundle;
} else {
- DirectoryBasedDartSdk directorySdk =
- new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
- directorySdk.analysisOptions =
+ FolderBasedDartSdk dartSdk = new FolderBasedDartSdk(resourceProvider,
+ resourceProvider.getFolder(options.dartSdkPath), options.strongMode);
+ dartSdk.analysisOptions =
Driver.createAnalysisOptionsForCommandLineOptions(options);
- directorySdk.useSummary = !options.buildSummaryOnlyAst;
- sdk = directorySdk;
- sdkBundle = directorySdk.getSummarySdkBundle(options.strongMode);
+ dartSdk.useSummary = !options.buildSummaryOnlyAst;
+ sdk = dartSdk;
+ sdkBundle = dartSdk.getSummarySdkBundle(options.strongMode);
}
// In AST mode include SDK bundle to avoid parsing SDK sources.
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 9cddf0d..68c9b25 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -26,7 +26,6 @@
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/utilities_general.dart'
@@ -625,17 +624,17 @@
options.dartSdkSummaryPath, options.strongMode);
} else {
String dartSdkPath = options.dartSdkPath;
- DirectoryBasedDartSdk directorySdk = new DirectoryBasedDartSdk(
- new JavaFile(dartSdkPath), options.strongMode);
- directorySdk.useSummary = useSummaries &&
+ FolderBasedDartSdk dartSdk = new FolderBasedDartSdk(resourceProvider,
+ resourceProvider.getFolder(dartSdkPath), options.strongMode);
+ dartSdk.useSummary = useSummaries &&
options.sourceFiles.every((String sourcePath) {
sourcePath = path.absolute(sourcePath);
sourcePath = path.normalize(sourcePath);
return !path.isWithin(dartSdkPath, sourcePath);
});
- directorySdk.analysisOptions = context.analysisOptions;
- sdk = directorySdk;
+ dartSdk.analysisOptions = context.analysisOptions;
+ sdk = dartSdk;
}
}
}
diff --git a/pkg/analyzer_cli/lib/src/incremental_analyzer.dart b/pkg/analyzer_cli/lib/src/incremental_analyzer.dart
index d57327a..d7e9084 100644
--- a/pkg/analyzer_cli/lib/src/incremental_analyzer.dart
+++ b/pkg/analyzer_cli/lib/src/incremental_analyzer.dart
@@ -10,10 +10,10 @@
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/incremental_cache.dart';
import 'package:analyzer/src/summary/package_bundle_reader.dart';
@@ -35,7 +35,7 @@
// If supported implementations, configure for incremental analysis.
if (cachePath != null &&
context is InternalAnalysisContext &&
- sdk is DirectoryBasedDartSdk) {
+ sdk is FolderBasedDartSdk) {
context.typeProvider = sdk.context.typeProvider;
// Set the result provide from the cache.
CacheStorage storage = new FolderCacheStorage(
diff --git a/pkg/analyzer_cli/test/embedder_test.dart b/pkg/analyzer_cli/test/embedder_test.dart
index 5a57c2d..93bbaf5 100644
--- a/pkg/analyzer_cli/test/embedder_test.dart
+++ b/pkg/analyzer_cli/test/embedder_test.dart
@@ -4,7 +4,8 @@
import 'dart:io';
-import 'package:analyzer/src/generated/sdk_io.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
+import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
import 'package:path/path.dart' as path;
import 'package:unittest/unittest.dart';
@@ -52,8 +53,9 @@
path.join(testDir, 'embedder_yaml_user.dart')
]);
- DirectoryBasedDartSdk sdk = driver.sdk;
- expect(sdk.useSummary, false);
+ DartSdk sdk = driver.sdk;
+ expect(sdk, new isInstanceOf<FolderBasedDartSdk>());
+ expect((sdk as FolderBasedDartSdk).useSummary, isFalse);
}));
});
}
diff --git a/pkg/analyzer_cli/test/sdk_ext_test.dart b/pkg/analyzer_cli/test/sdk_ext_test.dart
index 1376d46..3eb5c62 100644
--- a/pkg/analyzer_cli/test/sdk_ext_test.dart
+++ b/pkg/analyzer_cli/test/sdk_ext_test.dart
@@ -7,7 +7,8 @@
import 'dart:io';
-import 'package:analyzer/src/generated/sdk_io.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
+import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
import 'package:analyzer_cli/src/options.dart';
import 'package:path/path.dart' as path;
@@ -46,8 +47,9 @@
path.join(testDir, 'sdk_ext_user.dart')
]);
- DirectoryBasedDartSdk sdk = driver.sdk;
- expect(sdk.useSummary, isFalse);
+ DartSdk sdk = driver.sdk;
+ expect(sdk, new isInstanceOf<FolderBasedDartSdk>());
+ expect((sdk as FolderBasedDartSdk).useSummary, isFalse);
expect(exitCode, 0);
});
diff --git a/pkg/compiler/bin/resolver.dart b/pkg/compiler/bin/resolver.dart
index 054ba50..d5b56da 100644
--- a/pkg/compiler/bin/resolver.dart
+++ b/pkg/compiler/bin/resolver.dart
@@ -19,7 +19,7 @@
parser.addOption('out', abbr: 'o');
parser.addOption('library-root', abbr: 'l');
parser.addOption('packages', abbr: 'p');
- parser.addOption('bazel-config');
+ parser.addOption('bazel-paths', abbr: 'I', allowMultiple: true);
var args = parser.parse(argv);
var resolutionInputs = args['deps']
@@ -39,13 +39,14 @@
resolutionInputs: resolutionInputs,
packagesDiscoveryProvider: findPackages);
- var bazelConfigPath = args['bazel-config'];
- var inputProvider = bazelConfigPath != null
- ? new BazelInputProvider(bazelConfigPath)
+ var bazelSearchPaths = args['bazel-paths'];
+ var inputProvider = bazelSearchPaths != null
+ ? new BazelInputProvider(bazelSearchPaths)
: new CompilerSourceFileProvider();
var outputProvider = const NullCompilerOutput();
- var diagnostics = new FormattingDiagnosticHandler(inputProvider);
+ var diagnostics = new FormattingDiagnosticHandler(inputProvider)
+ ..enableColors = true;
var compiler =
new CompilerImpl(inputProvider, outputProvider, diagnostics, options);
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index bf08051..9472479 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -44,7 +44,6 @@
static const String trustJSInteropTypeAnnotations =
'--experimental-trust-js-interop-type-annotations';
static const String useContentSecurityPolicy = '--csp';
- static const String useCpsIr = '--use-cps-ir';
static const String useNewSourceInfo = '--use-new-source-info';
static const String verbose = '--verbose';
static const String version = '--version';
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index 8853b2f..35cc2b86 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -860,6 +860,7 @@
return new AstConstant.fromDefaultValue(
element, constant, handler.getConstantValue(constant));
}
+
target.computeType(resolution);
FunctionSignature signature = target.functionSignature;
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 762e315..2edfb81 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -608,6 +608,7 @@
}
return result;
}
+
_coreTypes.objectClass = lookupCoreClass('Object');
_coreTypes.boolClass = lookupCoreClass('bool');
_coreTypes.numClass = lookupCoreClass('num');
@@ -901,6 +902,7 @@
void enqueueAll(Element element) {
fullyEnqueueTopLevelElement(element, world);
}
+
library.implementation.forEachLocalMember(enqueueAll);
library.imports.forEach((ImportElement import) {
if (import.isDeferred) {
@@ -1156,6 +1158,7 @@
}
}
}
+
libraryLoader.libraries.forEach((LibraryElement library) {
// TODO(ahe): Implement better heuristics to discover entry points of
// packages and use that to discover unused implementation details in
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
deleted file mode 100644
index 57621fb..0000000
--- a/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
+++ /dev/null
@@ -1,128 +0,0 @@
-library dart2js.cps_ir.backward_null_check_remover;
-
-import 'cps_fragment.dart';
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart';
-import 'type_mask_system.dart';
-
-/// Removes null checks that are follwed by another instruction that will
-/// perform the same check.
-///
-/// For example:
-///
-/// x.toString; // NullCheck instruction
-/// print(x.length);
-///
-/// ==>
-///
-/// print(x.length);
-///
-/// `x.length` will throw when x is null, so the original [ReceiverCheck] is not
-/// needed. This changes the error message, but at least for now we are
-/// willing to accept this.
-///
-/// Note that code motion may not occur after this pass, since the [ReceiverCheck]
-/// nodes are not there to restrict it.
-//
-// TODO(asgerf): It would be nice with a clear specification of when we allow
-// the wording of error message to change. E.g. "toString" is already pretty
-// bad so changing that should be ok, but changing a field access is not as
-// clear.
-//
-class BackwardNullCheckRemover extends BlockVisitor implements Pass {
- String get passName => 'Backward null-check remover';
-
- final TypeMaskSystem typeSystem;
-
- /// When the analysis of an expression completes, [nullCheckValue] refers to
- /// a value that is checked in the beginning of that expression.
- Primitive nullCheckedValue;
-
- /// The [nullCheckedValue] at the entry point of a continuation.
- final Map<Continuation, Primitive> nullCheckedValueAt =
- <Continuation, Primitive>{};
-
- BackwardNullCheckRemover(this.typeSystem);
-
- void rewrite(FunctionDefinition node) {
- BlockVisitor.traverseInPostOrder(node, this);
- }
-
- /// 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;
- if (prim is GetIndex) return prim.object;
- if (prim is SetField) return prim.object;
- if (prim is SetIndex) return prim.object;
- if (prim is InvokeMethod && !selectorsOnNull.contains(prim.selector)) {
- return prim.receiver;
- }
- if (prim is ForeignCode) {
- return prim.isNullGuardOnNullFirstArgument() ? prim.argument(0) : null;
- }
- return null;
- }
-
- /// It has been determined that the null check in [prim] made redundant by
- /// [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;
- LetPrim let = prim.parent;
- prim
- ..replaceUsesWith(value)
- ..destroy();
- let.remove();
- } else if (prim is GetLength || prim is GetField || prim is GetIndex) {
- if (prim.hasNoRefinedUses) {
- destroyRefinementsOfDeadPrimitive(prim);
- LetPrim let = prim.parent;
- prim..destroy();
- let.remove();
- }
- }
- }
-
- /// True if [prim] can be moved above a null check. This is safe if [prim]
- /// cannot throw or have side effects and does not carry any path-sensitive
- /// type information, such as [Refinement] nodes do.
- //
- // TODO(asgerf): This prevents elimination of the .length created for a bounds
- // check, because there is a refinement node below it. To handle this, we
- // would have to relocate the [Refinement] node below the new null check.
- bool canMoveAboveNullCheck(Primitive prim) {
- return prim.isSafeForReordering;
- }
-
- void visitLetPrim(LetPrim node) {
- Primitive prim = node.primitive;
- Primitive receiver = getNullCheckedOperand(prim);
- if (receiver != null) {
- if (nullCheckedValue != null && receiver.sameValue(nullCheckedValue)) {
- tryEliminateRedundantNullCheck(prim, nullCheckedValue);
- }
- nullCheckedValue = receiver;
- } else if (!canMoveAboveNullCheck(prim)) {
- nullCheckedValue = null;
- }
- }
-
- void visitContinuation(Continuation cont) {
- if (nullCheckedValue != null) {
- nullCheckedValueAt[cont] = nullCheckedValue;
- nullCheckedValue = null;
- }
- }
-
- void visitLetHandler(LetHandler node) {
- nullCheckedValue = null;
- }
-
- visitInvokeContinuation(InvokeContinuation node) {
- if (!node.isRecursive) {
- 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
deleted file mode 100644
index ee5adec..0000000
--- a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
+++ /dev/null
@@ -1,710 +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 dart2js.cps_ir.bounds_checker;
-
-import '../constants/values.dart';
-import '../types/types.dart';
-import '../world.dart';
-import 'cps_fragment.dart';
-import 'cps_ir_nodes.dart';
-import 'effects.dart';
-import 'loop_effects.dart';
-import 'octagon.dart';
-import 'optimizers.dart' show Pass;
-import 'type_mask_system.dart';
-
-/// Eliminates bounds checks when they can be proven safe.
-///
-/// In general, this pass will try to eliminate any branch with arithmetic
-/// in the condition, i.e. `x < y`, `x <= y`, `x == y` etc.
-///
-/// The analysis uses an [Octagon] abstract domain. Unlike traditional octagon
-/// analyzers, we do not use a closed matrix representation, but just maintain
-/// a bucket of constraints. Constraints can therefore be added and removed
-/// on-the-fly without significant overhead.
-///
-/// We never copy the constraint system. While traversing the IR, the
-/// constraint system is mutated to take into account the knowledge that is
-/// valid for the current location. Constraints are added when entering a
-/// branch, for instance, and removed again after the branch has been processed.
-///
-/// Loops are analyzed in two passes. The first pass establishes monotonicity
-/// of loop variables, which the second pass uses to compute upper/lower bounds.
-///
-/// The two-pass scheme is suboptimal compared to a least fixed-point
-/// computation, but does not require repeated iteration. Repeated iteration
-/// would be expensive, since we cannot perform a sparse analysis with our
-/// mutable octagon representation.
-class BoundsChecker extends TrampolineRecursiveVisitor implements Pass {
- String get passName => 'Bounds checker';
-
- static const int MAX_UINT32 = (1 << 32) - 1;
-
- /// All integers of this magnitude or less are representable as JS numbers.
- static const int MAX_SAFE_INT = (1 << 53) - 1;
-
- /// Marker to indicate that a continuation should get a unique effect number.
- static const int NEW_EFFECT = -1;
-
- final TypeMaskSystem types;
- final World world;
-
- /// Fields for the constraint system and its variables.
- final Octagon octagon = new Octagon();
- final Map<Primitive, SignedVariable> valueOf = {};
- final Map<Primitive, Map<int, SignedVariable>> lengthOf = {};
-
- /// Fields for the two-pass handling of loops.
- final Map<Parameter, Monotonicity> monotonicity = <Parameter, Monotonicity>{};
- bool isStrongLoopPass;
- bool foundLoop = false;
-
- /// Fields for tracking side effects.
- ///
- /// The IR is divided into regions wherein the lengths of indexable objects
- /// are known not to change. Regions are identified by their "effect number".
- LoopSideEffects loopEffects;
- final Map<Continuation, int> effectNumberAt = <Continuation, int>{};
- int currentEffectNumber = 0;
- int effectNumberCounter = 0;
-
- BoundsChecker(this.types, this.world);
-
- void rewrite(FunctionDefinition node) {
- loopEffects = new LoopSideEffects(node, world);
- isStrongLoopPass = false;
- visit(node);
- if (foundLoop) {
- isStrongLoopPass = true;
- effectNumberAt.clear();
- visit(node);
- }
- }
-
- // ------------- VARIABLES -----------------
-
- int makeNewEffect() => ++effectNumberCounter;
-
- bool isInt(Primitive prim) {
- return types.isDefinitelyInt(prim.type);
- }
-
- bool isUInt32(Primitive prim) {
- return types.isDefinitelyUint32(prim.type);
- }
-
- bool isNonNegativeInt(Primitive prim) {
- return types.isDefinitelyNonNegativeInt(prim.type);
- }
-
- /// Get a constraint variable representing the numeric value of [number].
- SignedVariable getValue(Primitive number) {
- number = number.effectiveDefinition;
- int min, max;
- if (isUInt32(number)) {
- min = 0;
- max = MAX_UINT32;
- } else if (isNonNegativeInt(number)) {
- min = 0;
- }
- return valueOf.putIfAbsent(number, () => octagon.makeVariable(min, max));
- }
-
- /// Get a constraint variable representing the length of [indexableObject] at
- /// program locations with the given [effectNumber].
- SignedVariable getLength(Primitive indexableObject, int effectNumber) {
- indexableObject = indexableObject.effectiveDefinition;
- TypeMask type = indexableObject.type.nonNullable();
- if (types.isDefinitelyFixedLengthIndexable(type)) {
- // Always use the same effect number if the length is immutable.
- effectNumber = 0;
- }
- return lengthOf
- .putIfAbsent(indexableObject, () => <int, SignedVariable>{})
- .putIfAbsent(effectNumber, () {
- int length = types.getContainerLength(type);
- if (length != null) {
- return octagon.makeVariable(length, length);
- } else {
- return octagon.makeVariable(0, MAX_UINT32);
- }
- });
- }
-
- // ------------- CONSTRAINT HELPERS -----------------
-
- /// Puts the given constraint "in scope" by adding it to the octagon, and
- /// pushing a stack action that will remove it again.
- void applyConstraint(SignedVariable v1, SignedVariable v2, int k) {
- Constraint constraint = new Constraint(v1, v2, k);
- octagon.pushConstraint(constraint);
- pushAction(() => octagon.popConstraint(constraint));
- }
-
- /// Return true if we can prove that `v1 + v2 <= k`.
- bool testConstraint(SignedVariable v1, SignedVariable v2, int k) {
- // Add the negated constraint and check for solvability.
- // !(v1 + v2 <= k) <==> -v1 - v2 <= -k-1
- Constraint constraint = new Constraint(v1.negated, v2.negated, -k - 1);
- octagon.pushConstraint(constraint);
- bool answer = octagon.isUnsolvable;
- octagon.popConstraint(constraint);
- return answer;
- }
-
- void makeLessThanOrEqual(SignedVariable v1, SignedVariable v2) {
- // v1 <= v2 <==> v1 - v2 <= 0
- applyConstraint(v1, v2.negated, 0);
- }
-
- void makeLessThan(SignedVariable v1, SignedVariable v2) {
- // v1 < v2 <==> v1 - v2 <= -1
- applyConstraint(v1, v2.negated, -1);
- }
-
- void makeGreaterThanOrEqual(SignedVariable v1, SignedVariable v2) {
- // v1 >= v2 <==> v2 - v1 <= 0
- applyConstraint(v2, v1.negated, 0);
- }
-
- void makeGreaterThan(SignedVariable v1, SignedVariable v2) {
- // v1 > v2 <==> v2 - v1 <= -1
- applyConstraint(v2, v1.negated, -1);
- }
-
- void makeLessThanOrEqualToConstant(SignedVariable v1, int k) {
- // v1 + v1 <= 2k
- applyConstraint(v1, v1, 2 * k);
- }
-
- void makeGreaterThanOrEqualToConstant(SignedVariable v1, int k) {
- // -v1 - v1 <= -2k
- applyConstraint(v1.negated, v1.negated, -2 * k);
- }
-
- void makeConstant(SignedVariable v1, int k) {
- // We model this using the constraints:
- // v1 + v1 <= 2k
- // -v1 - v1 <= -2k
- applyConstraint(v1, v1, 2 * k);
- applyConstraint(v1.negated, v1.negated, -2 * k);
- }
-
- /// Make `v1 = v2 + k`.
- void makeExactSum(SignedVariable v1, SignedVariable v2, int k) {
- applyConstraint(v1, v2.negated, k);
- applyConstraint(v1.negated, v2, -k);
- }
-
- /// Make `v1 = v2 [+] k` where [+] represents floating-point addition.
- void makeFloatingPointSum(SignedVariable v1, SignedVariable v2, int k) {
- if (isDefinitelyLessThanOrEqualToConstant(v2, MAX_SAFE_INT - k) &&
- isDefinitelyGreaterThanOrEqualToConstant(v2, -MAX_SAFE_INT + k)) {
- // The result is known to be in the 53-bit range, so no rounding occurs.
- makeExactSum(v1, v2, k);
- } else {
- // A rounding error may occur, so the result may not be exactly v2 + k.
- // We can still add monotonicity constraints:
- // adding a positive number cannot return a lesser number
- // adding a negative number cannot return a greater number
- if (k >= 0) {
- // v1 >= v2 <==> v2 - v1 <= 0 <==> -v1 + v2 <= 0
- applyConstraint(v1.negated, v2, 0);
- } else {
- // v1 <= v2 <==> v1 - v2 <= 0
- applyConstraint(v1, v2.negated, 0);
- }
- }
- }
-
- void makeEqual(SignedVariable v1, SignedVariable v2) {
- // We model this using the constraints:
- // v1 <= v2 <==> v1 - v2 <= 0
- // v1 >= v2 <==> v2 - v1 <= 0
- applyConstraint(v1, v2.negated, 0);
- applyConstraint(v2, v1.negated, 0);
- }
-
- void makeNotEqual(SignedVariable v1, SignedVariable v2) {
- // The octagon cannot represent non-equality, but we can sharpen a weak
- // inequality to a sharp one. If v1 and v2 are already known to be equal,
- // this will create a contradiction and eliminate a dead branch.
- // This is necessary for eliminating concurrent modification checks.
- if (isDefinitelyLessThanOrEqualTo(v1, v2)) {
- makeLessThan(v1, v2);
- } else if (isDefinitelyGreaterThanOrEqualTo(v1, v2)) {
- makeGreaterThan(v1, v2);
- }
- }
-
- /// Return true if we can prove that `v1 <= v2`.
- bool isDefinitelyLessThanOrEqualTo(SignedVariable v1, SignedVariable v2) {
- return testConstraint(v1, v2.negated, 0);
- }
-
- /// Return true if we can prove that `v1 < v2`.
- bool isDefinitelyLessThan(SignedVariable v1, SignedVariable v2) {
- return testConstraint(v1, v2.negated, -1);
- }
-
- /// Return true if we can prove that `v1 >= v2`.
- bool isDefinitelyGreaterThanOrEqualTo(SignedVariable v1, SignedVariable v2) {
- return testConstraint(v2, v1.negated, 0);
- }
-
- bool isDefinitelyLessThanOrEqualToConstant(SignedVariable v1, int value) {
- // v1 <= value <==> v1 + v1 <= 2 * value
- return testConstraint(v1, v1, 2 * value);
- }
-
- bool isDefinitelyGreaterThanOrEqualToConstant(SignedVariable v1, int value) {
- // v1 >= value <==> -v1 - v1 <= -2 * value
- return testConstraint(v1.negated, v1.negated, -2 * value);
- }
-
- // ------------- TAIL EXPRESSIONS -----------------
-
- @override
- void visitBranch(Branch node) {
- Primitive condition = node.condition;
- Continuation trueCont = node.trueContinuation;
- Continuation falseCont = node.falseContinuation;
- effectNumberAt[trueCont] = currentEffectNumber;
- effectNumberAt[falseCont] = currentEffectNumber;
- pushAction(() {
- // If the branching condition is known statically, either or both of the
- // branch continuations will be replaced by Unreachable. Clean up the
- // branch afterwards.
- if (trueCont.body is Unreachable && falseCont.body is Unreachable) {
- destroyAndReplace(node, new Unreachable());
- } else if (trueCont.body is Unreachable) {
- destroyAndReplace(
- node, new InvokeContinuation(falseCont, <Parameter>[]));
- } else if (falseCont.body is Unreachable) {
- destroyAndReplace(
- node, new InvokeContinuation(trueCont, <Parameter>[]));
- }
- });
- void pushTrue(makeConstraint()) {
- pushAction(() {
- makeConstraint();
- push(trueCont);
- });
- }
- void pushFalse(makeConstraint()) {
- pushAction(() {
- makeConstraint();
- push(falseCont);
- });
- }
- if (condition is ApplyBuiltinOperator &&
- 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));
- pushFalse(() => makeGreaterThan(v1, v2));
- return;
- case BuiltinOperator.NumLt:
- pushTrue(() => makeLessThan(v1, v2));
- pushFalse(() => makeGreaterThanOrEqual(v1, v2));
- return;
- case BuiltinOperator.NumGe:
- pushTrue(() => makeGreaterThanOrEqual(v1, v2));
- pushFalse(() => makeLessThan(v1, v2));
- return;
- case BuiltinOperator.NumGt:
- pushTrue(() => makeGreaterThan(v1, v2));
- pushFalse(() => makeLessThanOrEqual(v1, v2));
- return;
- case BuiltinOperator.StrictEq:
- pushTrue(() => makeEqual(v1, v2));
- pushFalse(() => makeNotEqual(v1, v2));
- return;
- case BuiltinOperator.StrictNeq:
- pushTrue(() => makeNotEqual(v1, v2));
- pushFalse(() => makeEqual(v1, v2));
- return;
- default:
- }
- }
-
- push(trueCont);
- push(falseCont);
- }
-
- @override
- void visitConstant(Constant node) {
- // TODO(asgerf): It might be faster to inline the constant in the
- // constraints that reference it.
- if (node.value.isInt) {
- IntConstantValue constant = node.value;
- makeConstant(getValue(node), constant.primitiveValue);
- }
- }
-
- @override
- void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- if (!isInt(node)) return;
- if (node.argumentRefs.length == 1) {
- applyUnaryOperator(node);
- } else if (node.argumentRefs.length == 2) {
- applyBinaryOperator(node);
- }
- }
-
- void applyBinaryOperator(ApplyBuiltinOperator node) {
- Primitive left = node.argument(0);
- Primitive right = node.argument(1);
- if (!isInt(left) || !isInt(right)) {
- return;
- }
- SignedVariable leftVar = getValue(left);
- SignedVariable rightVar = getValue(right);
- SignedVariable result = getValue(node);
- switch (node.operator) {
- case BuiltinOperator.NumAdd:
- int leftConst = getIntConstant(left);
- if (leftConst != null) {
- makeFloatingPointSum(result, rightVar, leftConst);
- }
- int rightConst = getIntConstant(right);
- if (rightConst != null) {
- makeFloatingPointSum(result, leftVar, rightConst);
- }
- // Attempt to compute the sign of the result.
- // TODO(asgerf): Compute upper/lower bounds instead of using 0.
- if (testConstraint(leftVar, rightVar, 0)) {
- makeLessThanOrEqualToConstant(result, 0);
- }
- if (testConstraint(leftVar.negated, rightVar.negated, 0)) {
- makeGreaterThanOrEqualToConstant(result, 0);
- }
- // Classical octagon-based analyzers would compute upper and lower
- // bounds for the two operands and add constraints for the result based
- // on those. For performance reasons we only compute the sign
- // TODO(asgerf): It seems expensive, but we should evaluate it.
- break;
-
- case BuiltinOperator.NumSubtract:
- int leftConst = getIntConstant(left);
- if (leftConst != null) {
- // result = leftConst - right = (-right) + leftConst
- makeFloatingPointSum(result, rightVar.negated, leftConst);
- }
- int rightConst = getIntConstant(right);
- if (rightConst != null) {
- // result = left - rightConst = left + (-rightConst)
- makeFloatingPointSum(result, leftVar, -rightConst);
- }
- // Attempt to compute the sign of the result.
- if (isDefinitelyGreaterThanOrEqualTo(leftVar, rightVar)) {
- makeGreaterThanOrEqualToConstant(result, 0);
- }
- if (isDefinitelyLessThanOrEqualTo(leftVar, rightVar)) {
- makeLessThanOrEqualToConstant(result, 0);
- }
- break;
-
- case BuiltinOperator.NumTruncatingDivideToSigned32:
- if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0)) {
- // If we divide by a positive number, the result is closer to zero.
- // If we divide by a negative number, the result is negative, and
- // thus less than the original (non-negative) number.
- // TODO(asgerf): The divisor is currently always positive, because
- // type propagation checks that, but we could do better.
- makeLessThanOrEqual(result, leftVar);
- }
- break;
-
- case BuiltinOperator.NumShr:
- if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0)) {
- makeLessThanOrEqual(result, leftVar);
- }
- int shiftAmount = getIntConstant(right);
- if (shiftAmount != null) {
- // TODO(asgerf): Compute upper bound on [leftVar] and use that
- // instead of MAX_UINT32.
- makeLessThanOrEqualToConstant(result, MAX_UINT32 >> shiftAmount);
- }
- break;
-
- case BuiltinOperator.NumRemainder:
- // TODO(asgerf): This check overlaps with checks performed in a type
- // propagation transformation, and we can do it more precisely here.
- // Should we do the rewrite here?
- if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0) &&
- isDefinitelyGreaterThanOrEqualToConstant(rightVar, 1)) {
- makeLessThanOrEqual(result, leftVar);
- makeLessThan(result, rightVar);
- }
- break;
-
- case BuiltinOperator.NumAnd:
- // We use the faster UInt32 check instead of constraint based checks
- // here, because the common case is that one operand is a constant.
- if (isUInt32(left)) {
- makeLessThanOrEqual(result, leftVar);
- }
- if (isUInt32(right)) {
- makeLessThanOrEqual(result, rightVar);
- }
- break;
-
- default:
- }
- }
-
- void applyUnaryOperator(ApplyBuiltinOperator node) {
- Primitive argument = node.argument(0);
- if (!isInt(argument)) return;
- if (node.operator == BuiltinOperator.NumNegate) {
- valueOf[node] = getValue(argument).negated;
- }
- }
-
- int getIntConstant(Primitive prim) {
- if (prim is Constant && prim.value.isInt) {
- IntConstantValue constant = prim.value;
- return constant.primitiveValue;
- }
- return null;
- }
-
- @override
- void visitRefinement(Refinement node) {
- // In general we should get the container length of the refined type and
- // add a constraint if we know the length after the refinement.
- // However, our current type system removes container information when a
- // type becomes part of a union, so this cannot happen.
- }
-
- @override
- void visitGetLength(GetLength node) {
- valueOf[node] = getLength(node.object, currentEffectNumber);
- }
-
- @override
- void visitBoundsCheck(BoundsCheck node) {
- if (node.checks == BoundsCheck.NONE) return;
- assert(node.indexRef != null); // Because there is at least one check.
- SignedVariable length =
- node.lengthRef == null ? null : getValue(node.length);
- SignedVariable index = getValue(node.index);
- if (node.hasUpperBoundCheck) {
- if (isDefinitelyLessThan(index, length)) {
- node.checks &= ~BoundsCheck.UPPER_BOUND;
- } else {
- makeLessThan(index, length);
- }
- }
- if (node.hasLowerBoundCheck) {
- if (isDefinitelyGreaterThanOrEqualToConstant(index, 0)) {
- node.checks &= ~BoundsCheck.LOWER_BOUND;
- } else {
- makeGreaterThanOrEqualToConstant(index, 0);
- }
- }
- if (node.hasEmptinessCheck) {
- if (isDefinitelyGreaterThanOrEqualToConstant(length, 1)) {
- node.checks &= ~BoundsCheck.EMPTINESS;
- } else {
- makeGreaterThanOrEqualToConstant(length, 1);
- }
- }
- 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
- ..indexRef.unlink()
- ..indexRef = null;
- }
- }
-
- void analyzeLoopEntry(InvokeContinuation node) {
- foundLoop = true;
- Continuation cont = node.continuation;
- if (isStrongLoopPass) {
- for (int i = 0; i < node.argumentRefs.length; ++i) {
- Parameter param = cont.parameters[i];
- if (!isInt(param)) continue;
- Primitive initialValue = node.argument(i);
- SignedVariable initialVariable = getValue(initialValue);
- Monotonicity mono = monotonicity[param];
- if (mono == null) {
- // Value never changes. This is extremely uncommon.
- param.replaceUsesWith(initialValue);
- } else if (mono == Monotonicity.Increasing) {
- makeGreaterThanOrEqual(getValue(param), initialVariable);
- } else if (mono == Monotonicity.Decreasing) {
- makeLessThanOrEqual(getValue(param), initialVariable);
- }
- }
- }
- if (loopEffects.changesIndexableLength(cont)) {
- currentEffectNumber = effectNumberAt[cont] = makeNewEffect();
- }
- push(cont);
- }
-
- void analyzeLoopContinue(InvokeContinuation node) {
- 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
- // loop.
- if (isStrongLoopPass) return;
-
- // 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.argumentRefs.length; ++i) {
- Parameter param = cont.parameters[i];
- if (!isInt(param)) continue;
- 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
- // henceforth that it might be increasing.
- markMonotonicity(cont.parameters[i], Monotonicity.Increasing);
- }
- if (!isDefinitelyGreaterThanOrEqualTo(arg, paramVar)) {
- // We couldn't prove that the value does not decrease, so assume
- // henceforth that it might be decreasing.
- markMonotonicity(cont.parameters[i], Monotonicity.Decreasing);
- }
- }
- }
-
- void markMonotonicity(Parameter param, Monotonicity mono) {
- Monotonicity current = monotonicity[param];
- if (current == null) {
- monotonicity[param] = mono;
- } else if (current != mono) {
- monotonicity[param] = Monotonicity.NotMonotone;
- }
- }
-
- @override
- void visitInvokeContinuation(InvokeContinuation node) {
- Continuation cont = node.continuation;
- if (node.isRecursive) {
- analyzeLoopContinue(node);
- } else if (cont.isRecursive) {
- analyzeLoopEntry(node);
- } else {
- int effect = effectNumberAt[cont];
- if (effect == null) {
- effectNumberAt[cont] = currentEffectNumber;
- } else if (effect != currentEffectNumber && effect != NEW_EFFECT) {
- effectNumberAt[cont] = NEW_EFFECT;
- }
- // TODO(asgerf): Compute join for parameters to increase precision?
- }
- }
-
- // ---------------- 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
- // was not rewritten to GetLength. But if we can prove that the call only
- // succeeds for indexables, we can trust that it returns the length.
- TypeMask successType =
- types.receiverTypeFor(node.selector, node.receiver.type);
- if (types.isDefinitelyIndexable(successType)) {
- valueOf[node] = getLength(node.receiver, currentEffectNumber);
- }
- }
- }
-
- @override
- void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- Primitive receiver = node.receiver;
- int effectBefore = currentEffectNumber;
- currentEffectNumber = makeNewEffect();
- int effectAfter = currentEffectNumber;
- SignedVariable lengthBefore = getLength(receiver, effectBefore);
- SignedVariable lengthAfter = getLength(receiver, effectAfter);
- switch (node.method) {
- case BuiltinMethod.Push:
- // after = before + count
- int count = node.argumentRefs.length;
- makeExactSum(lengthAfter, lengthBefore, count);
- break;
-
- case BuiltinMethod.Pop:
- // 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.valueRefs.length);
- }
-
- // ---------------- INTERIOR EXPRESSIONS --------------------
-
- @override
- Expression traverseContinuation(Continuation cont) {
- if (octagon.isUnsolvable) {
- destroyAndReplace(cont.body, new Unreachable());
- } else {
- int effect = effectNumberAt[cont];
- if (effect != null) {
- currentEffectNumber = effect == NEW_EFFECT ? makeNewEffect() : effect;
- }
- }
- return cont.body;
- }
-
- @override
- Expression traverseLetCont(LetCont node) {
- // Join continuations should be pushed at declaration-site, so all their
- // call sites are seen before they are analyzed.
- // Other continuations are pushed at the use site.
- for (Continuation cont in node.continuations) {
- if (cont.hasAtLeastOneUse &&
- !cont.isRecursive &&
- cont.firstRef.parent is InvokeContinuation) {
- push(cont);
- }
- }
- return node.body;
- }
-}
-
-/// Lattice representing the known (weak) monotonicity of a loop variable.
-///
-/// The lattice bottom is represented by `null` and represents the case where
-/// the loop variable never changes value during the loop.
-enum Monotonicity { NotMonotone, Increasing, Decreasing, }
diff --git a/pkg/compiler/lib/src/cps_ir/builtin_operator.dart b/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
deleted file mode 100644
index 7c5e45c..0000000
--- a/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
+++ /dev/null
@@ -1,239 +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 builtin_operator;
-// 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.
-///
-/// These operators are pure in the sense that they cannot throw, diverge,
-/// have observable side-effects, return new objects, nor depend on any
-/// mutable state.
-///
-/// Most operators place restrictions on the values that may be given as
-/// argument; their behaviour is unspecified if those requirements are violated.
-///
-/// In all cases, the word "null" refers to the Dart null object, corresponding
-/// to both JS null and JS undefined.
-///
-/// Some operators, notably [IsFloor] and [IsInteger], take "repeated"
-/// arguments to reflect the number of times the given value is referenced
-/// by the generated code. The tree IR needs to know the number of references
-/// to safely propagate assignments.
-enum BuiltinOperator {
- /// The numeric binary operators must take two numbers as argument.
- /// The bitwise operators coerce the result to an unsigned integer, but
- /// otherwise these all behave like the corresponding JS operator.
- NumAdd,
- NumSubtract,
- NumMultiply,
- NumDivide,
- NumAnd,
- NumOr,
- NumXor,
- NumShl,
- NumLt,
- NumLe,
- NumGt,
- NumGe,
-
- /// NumShr behaves like JS '>>>' but is valid only when the left is in the
- /// uint32 range and the right in the range [0, 31].
- NumShr,
-
- /// NumRemainder corresponds to JavaScript's `a % b`, and Dart's
- /// `a.remainder(b)`, except at zero, since JavaScript `1 % 0` is `NaN`.
- /// Dart's modulo (`%`) is the same as remainder only when if both arguments
- /// are non-negative.
- NumRemainder,
-
- /// Corresponds to `a ~/ b` when b is non-zero and the result fits in a signed
- /// 32 bit value.
- ///
- /// This case can be compiled to `(a / b) | 0`.
- NumTruncatingDivideToSigned32,
-
- /// Corresponds to JavaScript's negation, which converts 0 to -0.0.
- NumNegate,
-
- /// Bit inversions, with coercion to uint32.
- ///
- /// Compiles to `(~x) >>> 0`.
- NumBitNot,
-
- /// Concatenates any number of strings.
- ///
- /// Takes any number of arguments, and each argument must be a string.
- ///
- /// Returns the empty string if no arguments are given.
- StringConcatenate,
-
- /// Corresponds to `a.charCodeAt(b)`. `a' must be a String. The index `b` must
- /// be in range `0 <= b < a.length`.
- /// TODO(sra): Consider replacing with a Primitive to allow lowering when 'a'
- /// is nullable (i.e. throws).
- CharCodeAt,
-
- /// Returns true if the two arguments are the same value, and that value is
- /// not NaN, or if one argument is +0 and the other is -0.
- ///
- /// Compiled as a static method call.
- Identical,
-
- /// Like [Identical], except at most one argument may be null.
- ///
- /// Compiles to `===`.
- StrictEq,
-
- /// Negated version of [StrictEq]. Introduced by [LogicalRewriter] in Tree IR.
- StrictNeq,
-
- /// Returns true if the two arguments are both null or are the same string,
- /// boolean, or number, and that number is not NaN, or one argument is +0
- /// and the other is -0.
- ///
- /// One of the following must hold:
- /// - At least one argument is null.
- /// - Arguments are both strings, or both booleans, or both numbers.
- ///
- /// Compiles to `==`.
- LooseEq,
-
- /// Negated version of [LooseEq]. Introduced by [LogicalRewriter] in Tree IR.
- LooseNeq,
-
- /// Returns true if the argument is false, +0. -0, NaN, the empty string,
- /// or null.
- ///
- /// Compiles to `!`.
- IsFalsy,
-
- /// Returns true if the argument is a number.
- ///
- /// Compiles to `typeof x === 'number'`
- IsNumber,
-
- /// Returns true if the argument is not a number.
- ///
- /// Compiles to `typeof x !== 'number'`.
- IsNotNumber,
-
- /// Returns true if the argument is an integer, false if it is a double or
- /// null, and unspecified if it is anything else.
- ///
- /// The argument must be repeated 2 times.
- ///
- /// Compiles to `Math.floor(x) === x`
- IsFloor,
-
- /// Returns true if the argument is an integer.
- ///
- /// The argument must be repeated 3 times.
- ///
- /// Compiles to `typeof x === 'number' && Math.floor(x) === x`
- IsInteger,
-
- /// Returns true if the argument is not an integer.
- ///
- /// The argument must be repeated 3 times.
- ///
- /// Compiles to `typeof x !== 'number' || Math.floor(x) !== x`
- IsNotInteger,
-
- /// Returns true if `x` is an unsigned 32-bit integer.
- ///
- /// The argument must be repeated 2 times.
- ///
- /// Compiles to `x >>> 0 === x`
- IsUnsigned32BitInteger,
-
- /// Returns false if `x` is an unsigned 32-bit integer.
- ///
- /// The argument must be repeated 2 times.
- ///
- /// Compiles to `x >>> 0 !== x`
- IsNotUnsigned32BitInteger,
-
- /// Returns true if the argument is a fixed length Array.
- ///
- /// Uses one argument.
- ///
- /// Precondition: Argument is a JavaScript Array.
- IsFixedLengthJSArray,
-
- // TODO(sra): Remove this and replace with IsFalsy(IsFixedLengthJSArray(x)).
- IsExtendableJSArray,
-
- /// Returns true if the argument is an unmodifiable Array.
- ///
- /// Uses one argument.
- ///
- /// Precondition: Argument is a JavaScript Array.
- IsUnmodifiableJSArray,
-
- // TODO(sra): Remove this and replace with IsFalsy(IsUnmodifiableArray(x)).
- IsModifiableJSArray,
-}
-
-/// A method supported natively in the CPS and Tree IRs using the
-/// `ApplyBuiltinMethod` instructions.
-///
-/// These methods all operate on a distinguished 'object' argument, and
-/// take zero or more additional arguments.
-///
-/// These methods may mutate and depend on the state of the object argument,
-/// 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 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).
- ///
- /// Compiles to `object.push(x1, ..., xN)`.
- Push,
-
- /// 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.
-bool isCompoundableOperator(BuiltinOperator operator) {
- switch (operator) {
- case BuiltinOperator.NumAdd:
- case BuiltinOperator.NumSubtract:
- case BuiltinOperator.NumMultiply:
- case BuiltinOperator.NumDivide:
- case BuiltinOperator.NumRemainder:
- case BuiltinOperator.StringConcatenate:
- return true;
- default:
- 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
deleted file mode 100644
index b7c7b9b..0000000
--- a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
+++ /dev/null
@@ -1,374 +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 cps_ir.cps_fragment;
-
-import '../constants/values.dart';
-import '../elements/elements.dart';
-import '../io/source_information.dart';
-import '../types/types.dart' show TypeMask;
-import '../universe/selector.dart' show Selector;
-import 'cps_ir_nodes.dart';
-
-/// Builds a CPS fragment that can be plugged into another CPS term.
-///
-/// A CPS fragment contains a CPS term, possibly with a "hole" in it denoting
-/// where to insert new IR nodes. We say a fragment is "open" if it has such
-/// a hole. Otherwise, the fragment is "closed" and cannot be extended further.
-///
-/// This class is designed for building non-trivial CPS terms in a readable and
-/// non-error prone manner. It is not designed to manipulate existing IR nodes,
-/// nor is it intended to shield the user from every complexity in the IR.
-///
-/// EXAMPLES:
-///
-/// Call `cont` with `obj.field + 1` as argument:
-///
-/// CpsFragment cps = new CpsFragment();
-/// var fieldValue = cps.letPrim(new GetField(obj, field));
-/// var plusOne = cps.applyBuiltin(BuiltinOperator.NumAdd,
-/// [fieldValue, cps.makeOne()]);
-/// cps.invokeContinuation(cont, [plusOne]);
-///
-/// If `condition` is true then invoke `cont1`, else `cont2`.
-///
-/// cps.ifTruthy(condition).invokeContinuation(cont1, []);
-/// cps.invokeContinuation(cont2, []);
-///
-/// If `condition` is true then invoke `cont` with a bound primitive:
-///
-/// CpsFragment branch = cps.ifTruthy(condition);
-/// branch.invokeContinuation(cont, [branch.letPrim(arg)]);
-///
-/// Loop and call a method until it returns false:
-///
-/// Continuation loop = cps.beginLoop();
-/// var result = cps.invokeMethod(receiver, selector, ...);
-/// cps.ifFalsy(result).invokeContinuation(exit, []);
-/// cps.continueLoop(loop);
-///
-class CpsFragment {
- /// The root of the IR built using this fragment.
- Expression root;
-
- /// Node whose body is the hole in this CPS fragment. May be null.
- InteriorNode context;
-
- /// Source information to attach to every IR node created in the fragment.
- SourceInformation sourceInformation;
-
- CpsFragment([this.sourceInformation, this.context]);
-
- bool get isOpen => root == null || context != null;
- bool get isClosed => !isOpen;
- bool get isEmpty => root == null;
-
- /// Asserts that the fragment is non-empty and closed and returns the IR that
- /// was built.
- Expression get result {
- assert(!isEmpty);
- assert(isClosed);
- return root;
- }
-
- /// Put the given expression into the fragment's hole.
- ///
- /// Afterwards the fragment is closed and cannot be extended until a new
- /// [context] is set.
- void put(Expression node) {
- assert(root == null || context != null); // We must put the node somewhere.
- if (root == null) {
- root = node;
- }
- if (context != null) {
- context.body = node;
- node.parent = context;
- }
- context = null;
- }
-
- /// Bind a primitive. Returns the same primitive for convenience.
- Primitive letPrim(Primitive prim) {
- assert(prim != null);
- LetPrim let = new LetPrim(prim);
- put(let);
- context = let;
- return prim;
- }
-
- /// Bind a constant value.
- Primitive makeConstant(ConstantValue constant) {
- return letPrim(new Constant(constant));
- }
-
- Primitive makeZero() => makeConstant(new IntConstantValue(0));
- Primitive makeOne() => makeConstant(new IntConstantValue(1));
- Primitive makeMinusOne() => makeConstant(new IntConstantValue(-1));
- Primitive makeNull() => makeConstant(new NullConstantValue());
- Primitive makeTrue() => makeConstant(new TrueConstantValue());
- Primitive makeFalse() => makeConstant(new FalseConstantValue());
-
- /// Invoke a built-in operator.
- Primitive applyBuiltin(BuiltinOperator op, List<Primitive> args) {
- return letPrim(new ApplyBuiltinOperator(op, args, sourceInformation));
- }
-
- Primitive refine(Primitive value, TypeMask type) {
- return letPrim(new Refinement(value, type));
- }
-
- Primitive invokeBuiltin(
- BuiltinMethod method, Primitive receiver, List<Primitive> arguments,
- {bool receiverIsNotNull: false}) {
- ApplyBuiltinMethod apply =
- new ApplyBuiltinMethod(method, receiver, arguments, sourceInformation);
- return letPrim(apply);
- }
-
- /// Inserts an invocation and returns a primitive holding the returned value.
- Primitive invokeMethod(Primitive receiver, Selector selector, TypeMask mask,
- List<Primitive> arguments,
- {Primitive interceptor, CallingConvention callingConvention}) {
- InvokeMethod invoke = new InvokeMethod(receiver, selector, mask, arguments,
- sourceInformation: sourceInformation,
- callingConvention: callingConvention,
- interceptor: interceptor);
- return letPrim(invoke);
- }
-
- /// Inserts an invocation and returns a primitive holding the returned value.
- Primitive invokeStatic(FunctionElement target, List<Primitive> arguments) {
- return letPrim(new InvokeStatic(target, new Selector.fromElement(target),
- arguments, sourceInformation));
- }
-
- /// Inserts an invocation to a static function that throws an error.
- ///
- /// This closes the fragment; no more nodes may be added.
- void invokeStaticThrower(FunctionElement target, List<Primitive> arguments) {
- invokeStatic(target, arguments);
- put(new Unreachable());
- }
-
- /// Invoke a non-recursive continuation.
- ///
- /// This closes the fragment; no more nodes may be inserted.
- void invokeContinuation(Continuation cont, [List<Primitive> arguments]) {
- if (arguments == null) arguments = <Primitive>[];
- put(new InvokeContinuation(cont, arguments));
- }
-
- /// Build a loop with the given loop variables and initial values.
- /// Call [continueLoop] with the returned continuation to iterate the loop.
- ///
- /// The loop body becomes the new hole.
- Continuation beginLoop(
- [List<Parameter> loopVars, List<Primitive> initialValues]) {
- if (initialValues == null) {
- assert(loopVars == null);
- loopVars = <Parameter>[];
- initialValues = <Primitive>[];
- }
- Continuation cont = new Continuation(loopVars);
- put(new LetCont(cont, new InvokeContinuation(cont, initialValues)));
- context = cont;
- return cont;
- }
-
- /// Continue a loop started by [beginLoop].
- ///
- /// This closes the fragment; no more nodes may be inserted.
- void continueLoop(Continuation cont, [List<Primitive> updatedLoopVariables]) {
- put(new InvokeContinuation(cont, updatedLoopVariables, isRecursive: true));
- }
-
- /// Branch on [condition].
- ///
- /// Returns a new fragment for the 'then' branch, or the 'else' branch
- /// if [negate] is true.
- ///
- /// The other branch becomes the new hole.
- CpsFragment branch(Primitive condition,
- {bool negate: false, bool strict: false}) {
- Continuation trueCont = new Continuation(<Parameter>[]);
- Continuation falseCont = new Continuation(<Parameter>[]);
- put(new LetCont.two(
- trueCont,
- falseCont,
- new Branch(condition, trueCont, falseCont, sourceInformation,
- strict: strict)));
- if (negate) {
- context = trueCont;
- return new CpsFragment(sourceInformation, falseCont);
- } else {
- context = falseCont;
- return new CpsFragment(sourceInformation, trueCont);
- }
- }
-
- /// Branch on [condition].
- ///
- /// Returns a new fragment for the 'then' branch.
- ///
- /// The 'else' branch becomes the new hole.
- CpsFragment ifTruthy(Primitive condition) => branch(condition);
-
- /// Branch on [condition].
- ///
- /// Returns a new fragment for the 'else' branch.
- ///
- /// The 'then' branch becomes the new hole.
- CpsFragment ifFalsy(Primitive condition) => branch(condition, negate: true);
-
- /// Create a new empty continuation and bind it here.
- ///
- /// Convenient for making a join point where multiple branches
- /// meet later.
- ///
- /// The LetCont body becomes the new hole.
- ///
- /// Example use:
- ///
- /// Continuation fail = cps.letCont();
- ///
- /// // Fail if something
- /// cps.ifTrue(<condition>)
- /// ..invokeMethod(<method>)
- /// ..invokeContinuation(fail);
- ///
- /// // Fail if something else
- /// cps.ifTrue(<anotherCondition>)
- /// ..invokeMethod(<anotherMethod>)
- /// ..invokeContinuation(fail);
- ///
- /// // Build the fail branch
- /// cps.insideContinuation(fail)
- /// ..invokeStaticThrower(...);
- ///
- /// // Go to the happy branch
- /// cps.invokeContinuation(cont..)
- ///
- Continuation letCont([List<Parameter> parameters]) {
- if (parameters == null) parameters = <Parameter>[];
- Continuation cont = new Continuation(parameters);
- bindContinuation(cont);
- return cont;
- }
-
- /// Binds an existing continuation at this position.
- ///
- /// The LetCont body becomes the new hole.
- void bindContinuation(Continuation cont) {
- LetCont let = new LetCont(cont, null);
- put(let);
- context = let;
- }
-
- /// Inlines [target] at the current position, substituting the provided
- /// arguments.
- ///
- /// Returns a primitive containing the function's return value.
- ///
- /// The new hole is the point after [target] has returned. The fragment
- /// remains open, even if [target] never returns.
- ///
- /// The [target] function is destroyed and should not be reused.
- Primitive inlineFunction(
- FunctionDefinition target, Primitive receiver, List<Primitive> arguments,
- {Entity hint, Primitive interceptor}) {
- if (interceptor != null) {
- target.interceptorParameter.replaceUsesWith(interceptor);
- }
- if (receiver != null) {
- target.receiverParameter.replaceUsesWith(receiver);
- }
- for (int i = 0; i < arguments.length; ++i) {
- target.parameters[i].replaceUsesWith(arguments[i]);
- }
- Continuation returnCont = target.returnContinuation;
- bindContinuation(returnCont);
- put(target.body);
- Parameter returnValue = returnCont.parameters.single;
- returnValue.hint = hint;
- context = returnCont;
- return returnValue;
- }
-
- /// Returns a fragment whose context is the body of the given continuation.
- ///
- /// Does not change the state of this CPS fragment.
- ///
- /// Useful for building the body of a continuation created using [letCont].
- CpsFragment insideContinuation(Continuation cont) {
- return new CpsFragment(sourceInformation, cont);
- }
-
- /// Puts the given fragment into this one.
- ///
- /// If [other] was an open fragment, its hole becomes the new hole
- /// in this fragment.
- ///
- /// [other] is reset to an empty fragment after this.
- void append(CpsFragment other) {
- if (other.root == null) return;
- put(other.root);
- context = other.context;
- other.context = null;
- other.root = null;
- }
-
- /// Reads the value of the given mutable variable.
- Primitive getMutable(MutableVariable variable) {
- return letPrim(new GetMutable(variable));
- }
-
- /// Sets the value of the given mutable variable.
- void setMutable(MutableVariable variable, Primitive value) {
- letPrim(new SetMutable(variable, value));
- }
-
- /// Declare a new mutable variable.
- void letMutable(MutableVariable variable, Primitive initialValue) {
- LetMutable let = new LetMutable(variable, initialValue);
- put(let);
- context = let;
- }
-
- void insertBelow(InteriorNode node) {
- assert(isOpen);
- if (isEmpty) return;
- Expression child = node.body;
- node.body = root;
- root.parent = node;
- context.body = child;
- child.parent = context;
- root = context = null;
- }
-
- void insertAbove(InteriorExpression node) {
- insertBelow(node.parent);
- }
-}
-
-/// Removes [node], unlinking all its references and replaces it with [newNode].
-void destroyAndReplace(Expression node, Expression newNode) {
- InteriorNode parent = node.parent;
- RemovalVisitor.remove(node);
- parent.body = newNode;
- newNode.parent = parent;
-}
-
-/// Removes all [Refinement] uses of a given primitive that has no effective
-/// uses.
-void destroyRefinementsOfDeadPrimitive(Primitive prim) {
- while (prim.firstRef != null) {
- Refinement refine = prim.firstRef.parent;
- destroyRefinementsOfDeadPrimitive(refine);
- LetPrim letPrim = refine.parent;
- InteriorNode parent = letPrim.parent;
- parent.body = letPrim.body;
- letPrim.body.parent = parent;
- prim.firstRef.unlink();
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
deleted file mode 100644
index 3e1f9bf..0000000
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ /dev/null
@@ -1,2927 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.ir_builder;
-
-import '../closure.dart' as closure;
-import '../common.dart';
-import '../common/names.dart' show Selectors;
-import '../compile_time_constants.dart' show BackendConstantEnvironment;
-import '../constants/constant_system.dart';
-import '../constants/values.dart' show ConstantValue;
-import '../dart_types.dart';
-import '../elements/elements.dart';
-import '../io/source_information.dart';
-import '../js/js.dart' as js
- show
- js,
- objectLiteral,
- Expression,
- LiteralStatement,
- Template,
- InterpolatedExpression,
- isIdentityTemplate;
-import '../native/native.dart' show NativeBehavior;
-import '../tree/tree.dart' as ast;
-import '../types/types.dart' show TypeMask;
-import '../universe/call_structure.dart' show CallStructure;
-import '../universe/selector.dart' show Selector, SelectorKind;
-import 'cps_ir_builder_task.dart' show GlobalProgramInformation;
-import 'cps_ir_nodes.dart' as ir;
-
-/// A mapping from variable elements to their compile-time values.
-///
-/// Map elements denoted by parameters and local variables to the
-/// [ir.Primitive] that is their value. Parameters and locals are
-/// assigned indexes which can be used to refer to them.
-class Environment {
- /// A map from locals to their environment index.
- final Map<Local, int> variable2index;
-
- /// A reverse map from environment indexes to the variable.
- final List<Local> index2variable;
-
- /// A map from environment indexes to their value.
- final List<ir.Primitive> index2value;
-
- Environment.empty()
- : variable2index = <Local, int>{},
- index2variable = <Local>[],
- index2value = <ir.Primitive>[];
-
- /// Construct an environment that is a copy of another one.
- ///
- /// The mapping from elements to indexes is shared, not copied.
- Environment.from(Environment other)
- : variable2index = other.variable2index,
- index2variable = new List<Local>.from(other.index2variable),
- index2value = new List<ir.Primitive>.from(other.index2value);
-
- /// Construct an environment that is shaped like another one but with a
- /// fresh parameter for each variable.
- ///
- /// The mapping from elements to indexes is shared, not copied.
- Environment.fresh(Environment other)
- : variable2index = other.variable2index,
- index2variable = new List<Local>.from(other.index2variable),
- index2value = other.index2variable.map((Local local) {
- return new ir.Parameter(local);
- }).toList();
-
- get length => index2variable.length;
-
- ir.Primitive operator [](int index) => index2value[index];
-
- void extend(Local element, ir.Primitive value) {
- // Assert that the name is not already in the environment. `null` is used
- // as the name of anonymous variables.
- assert(!variable2index.containsKey(element));
- if (element != null) variable2index[element] = index2variable.length;
- index2variable.add(element);
- index2value.add(value);
- }
-
- /// Drop [count] values from the environment.
- ///
- /// Return the previous last value in the environment for convenience.
- ir.Primitive discard(int count) {
- assert(count > 0);
- assert(count <= index2variable.length);
- ir.Primitive value = index2value.last;
- // The map from variables to their index are shared, so we cannot remove
- // the mapping in `variable2index`.
- index2variable.length -= count;
- index2value.length -= count;
- return value;
- }
-
- ir.Primitive lookup(Local element) {
- assert(invariant(element, variable2index.containsKey(element),
- message: "Unknown variable: $element."));
- return index2value[variable2index[element]];
- }
-
- void update(Local element, ir.Primitive value) {
- index2value[variable2index[element]] = value;
- }
-
- /// Verify that the variable2index and index2variable maps agree up to the
- /// index [length] exclusive.
- bool sameDomain(int length, Environment other) {
- assert(this.length >= length);
- assert(other.length >= length);
- for (int i = 0; i < length; ++i) {
- // An index maps to the same variable in both environments.
- Local variable = index2variable[i];
- if (variable != other.index2variable[i]) return false;
-
- // A named variable maps to the same index in both environments.
- if (variable != null) {
- int index = variable2index[variable];
- if (index == null || index != other.variable2index[variable]) {
- return false;
- }
- }
- }
- return true;
- }
-
- bool contains(Local local) => variable2index.containsKey(local);
-}
-
-/// The abstract base class of objects that emit jumps to a continuation and
-/// give a handle to the continuation and its environment.
-abstract class JumpCollector {
- final JumpTarget target;
-
- ir.Continuation _continuation = null;
- final Environment _continuationEnvironment;
-
- final List<Iterable<LocalVariableElement>> _boxedTryVariables =
- <Iterable<LocalVariableElement>>[];
-
- /// Construct a collector for a given environment and optionally a target.
- ///
- /// The environment is the one in effect at the point where the jump's
- /// continuation will be bound. Continuations can take an extra argument
- /// (see [addJump]).
- JumpCollector(
- this._continuationEnvironment, this.target, bool hasExtraArgument) {
- if (hasExtraArgument) _continuationEnvironment.extend(null, null);
- }
-
- /// Construct a collector for collecting only return jumps.
- ///
- /// There is no jump target, it is implicitly the exit from the function.
- /// There is no environment at the destination.
- JumpCollector.retrn(this._continuation)
- : _continuationEnvironment = null,
- target = null;
-
- /// Construct a collector for collecting goto jumps.
- ///
- /// There is no continuation or environment at the destination.
- JumpCollector.goto(this.target) : _continuationEnvironment = null;
-
- /// True if the collector has not recorded any jumps to its continuation.
- bool get isEmpty;
-
- /// The continuation encapsulated by this collector.
- ir.Continuation get continuation;
-
- /// The compile-time environment to be used for translating code in the body
- /// of the continuation.
- Environment get environment;
-
- /// Emit a jump to the continuation for a given [IrBuilder].
- ///
- /// Jumps can take a single extra argument. This is used to pass return
- /// values to finally blocks for returns inside try/finally and to pass
- /// values of expressions that have internal control flow to their join-point
- /// continuations.
- void addJump(IrBuilder builder,
- [ir.Primitive value, SourceInformation sourceInformation]);
-
- /// Add a set of variables that were boxed on entry to a try block.
- ///
- /// All jumps from a try block to targets outside have to unbox the
- /// variables that were boxed on entry before invoking the target
- /// continuation. Call this function before translating a try block and
- /// call [leaveTry] after translating it.
- void enterTry(Iterable<LocalVariableElement> boxedOnEntry) {
- // The boxed variables are maintained as a stack to make leaving easy.
- _boxedTryVariables.add(boxedOnEntry);
- }
-
- /// Remove the most recently added set of variables boxed on entry to a try
- /// block.
- ///
- /// Call [enterTry] before translating a try block and call this function
- /// after translating it.
- void leaveTry() {
- _boxedTryVariables.removeLast();
- }
-
- void _buildTryExit(IrBuilder builder) {
- for (Iterable<LocalVariableElement> boxedOnEntry in _boxedTryVariables) {
- for (LocalVariableElement variable in boxedOnEntry) {
- assert(builder.isInMutableVariable(variable));
- ir.Primitive value = builder.buildLocalGet(variable);
- builder.environment.update(variable, value);
- }
- }
- }
-
- /// True if a jump inserted now will escape from a try block.
- ///
- /// Concretely, this is true when [enterTry] has been called without
- /// its corresponding [leaveTry] call.
- bool get isEscapingTry => _boxedTryVariables.isNotEmpty;
-}
-
-/// A class to collect 'forward' jumps.
-///
-/// A forward jump to a continuation in the sense of the CPS translation is
-/// a jump where the jump is emitted before any code in the body of the
-/// continuation is translated. They have the property that continuation
-/// parameters and the environment for the translation of the body can be
-/// determined based on the invocations, before translating the body. A
-/// [ForwardJumpCollector] can encapsulate a continuation where all the
-/// jumps are forward ones.
-///
-/// Examples of forward jumps in the translation are join points of
-/// if-then-else and breaks from loops.
-///
-/// The implementation strategy is that the collector collects invocation
-/// sites and the environments at those sites. Then it constructs a
-/// continuation 'on demand' after all the jumps are seen. It determines
-/// continuation parameters, the environment for the translation of code in
-/// the continuation body, and the arguments at the invocation site only
-/// after all the jumps to the continuation are seen.
-class ForwardJumpCollector extends JumpCollector {
- final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[];
- final List<Environment> _invocationEnvironments = <Environment>[];
-
- /// Construct a collector with a given base environment.
- ///
- /// The base environment is the one in scope at the site that the
- /// continuation represented by this collector will be bound. The
- /// environment is copied by the collector. Subsequent mutation of the
- /// original environment will not affect the collector.
- ForwardJumpCollector(Environment environment,
- {JumpTarget target, bool hasExtraArgument: false})
- : super(new Environment.from(environment), target, hasExtraArgument);
-
- bool get isEmpty => _invocations.isEmpty;
-
- ir.Continuation get continuation {
- if (_continuation == null) _setContinuation();
- return _continuation;
- }
-
- Environment get environment {
- if (_continuation == null) _setContinuation();
- return _continuationEnvironment;
- }
-
- void addJump(IrBuilder builder,
- [ir.Primitive value, SourceInformation sourceInformation]) {
- assert(_continuation == null);
- _buildTryExit(builder);
- ir.InvokeContinuation invoke =
- new ir.InvokeContinuation.uninitialized(isEscapingTry: isEscapingTry);
- builder.add(invoke);
- _invocations.add(invoke);
- // Truncate the environment at the invocation site so it only includes
- // values that will be continuation arguments. If an extra value is passed
- // it will already be included in the continuation environment, but it is
- // not present in the invocation environment.
- int delta = builder.environment.length - _continuationEnvironment.length;
- if (value != null) ++delta;
- if (delta > 0) builder.environment.discard(delta);
- if (value != null) builder.environment.extend(null, value);
- _invocationEnvironments.add(builder.environment);
- builder._current = null;
- // TODO(kmillikin): Can we set builder.environment to null to make it
- // less likely to mutate it?
- }
-
- void _setContinuation() {
- assert(_continuation == null);
- // We have seen all invocations of this continuation, and recorded the
- // environment in effect at each invocation site.
-
- // Compute the union of the assigned variables reaching the continuation.
- //
- // There is a continuation parameter for each environment variable
- // that has a different value (from the environment in scope at the
- // continuation binding) on some path. `_environment` is initially a copy
- // of the environment in scope at the continuation binding. Compute the
- // continuation parameters and add them to `_environment` so it will become
- // the one in scope for the continuation body.
- List<ir.Parameter> parameters = <ir.Parameter>[];
- if (_invocationEnvironments.isNotEmpty) {
- int length = _continuationEnvironment.length;
- for (int varIndex = 0; varIndex < length; ++varIndex) {
- for (Environment invocationEnvironment in _invocationEnvironments) {
- assert(invocationEnvironment.sameDomain(
- length, _continuationEnvironment));
- if (invocationEnvironment[varIndex] !=
- _continuationEnvironment[varIndex]) {
- ir.Parameter parameter = new ir.Parameter(
- _continuationEnvironment.index2variable[varIndex]);
- _continuationEnvironment.index2value[varIndex] = parameter;
- parameters.add(parameter);
- break;
- }
- }
- }
- }
- _continuation = new ir.Continuation(parameters);
-
- // Compute the intersection of the parameters with the environments at
- // each continuation invocation. Initialize the invocations.
- for (int jumpIndex = 0; jumpIndex < _invocations.length; ++jumpIndex) {
- Environment invocationEnvironment = _invocationEnvironments[jumpIndex];
- List<ir.Reference> arguments = <ir.Reference>[];
- int varIndex = 0;
- for (ir.Parameter parameter in parameters) {
- varIndex =
- _continuationEnvironment.index2value.indexOf(parameter, varIndex);
- arguments.add(new ir.Reference(invocationEnvironment[varIndex]));
- }
- ir.InvokeContinuation invocation = _invocations[jumpIndex];
- invocation.continuationRef = new ir.Reference(_continuation);
- invocation.argumentRefs = arguments;
- }
- }
-}
-
-/// A class to collect 'backward' jumps.
-///
-/// A backward jump to a continuation in the sense of the CPS translation is
-/// a jump where some code in the body of the continuation is translated
-/// before the jump is emitted. They have the property that the
-/// continuation parameters and the environment for the translation of the
-/// body must be determined before emitting all the invocations. A
-/// [BackwardJumpCollector] can ecapsulate a continuation where some jumps
-/// are backward ones.
-///
-/// Examples of backward jumps in the translation are the recursive
-/// invocations of loop continuations.
-///
-/// The implementation strategy is that the collector inserts a continuation
-/// parameter for each variable in scope at the entry to the continuation,
-/// before emitting any jump to the continuation. When a jump is added, it
-/// is given an argument for each continuation parameter.
-class BackwardJumpCollector extends JumpCollector {
- /// Construct a collector with a given base environment.
- ///
- /// The base environment is the one in scope at the site that the
- /// continuation represented by this collector will be bound. The
- /// translation of the continuation body will use an environment with the
- /// same shape, but with fresh continuation parameters for each variable.
- BackwardJumpCollector(Environment environment,
- {JumpTarget target, bool hasExtraArgument: false})
- : super(new Environment.fresh(environment), target, hasExtraArgument) {
- List<ir.Parameter> parameters =
- new List<ir.Parameter>.from(_continuationEnvironment.index2value);
- _continuation = new ir.Continuation(parameters, isRecursive: true);
- }
-
- bool isEmpty = true;
-
- ir.Continuation get continuation => _continuation;
- Environment get environment => _continuationEnvironment;
-
- void addJump(IrBuilder builder,
- [ir.Primitive value, SourceInformation sourceInformation]) {
- assert(_continuation.parameters.length <= builder.environment.length);
- isEmpty = false;
- _buildTryExit(builder);
- // Truncate the environment at the invocation site so it only includes
- // values that will be continuation arguments. If an extra value is passed
- // it will already be included in the continuation environment, but it is
- // not present in the invocation environment.
- int delta = builder.environment.length - _continuationEnvironment.length;
- if (value != null) ++delta;
- if (delta > 0) builder.environment.discard(delta);
- if (value != null) builder.environment.extend(null, value);
- builder.add(new ir.InvokeContinuation(
- _continuation, builder.environment.index2value,
- isRecursive: true, isEscapingTry: isEscapingTry));
- builder._current = null;
- }
-}
-
-/// Collect 'return' jumps.
-///
-/// A return jump is one that targets the return continuation of a function.
-/// Thus, returns from inside try/finally are not return jumps because they are
-/// intercepted by a block that contains the finally handler code.
-class ReturnJumpCollector extends JumpCollector {
- bool isEmpty = true;
- ir.Continuation get continuation => _continuation;
- Environment environment = null;
-
- /// Construct a return jump collector for a given return continuation.
- ReturnJumpCollector(ir.Continuation continuation) : super.retrn(continuation);
-
- void addJump(IrBuilder builder,
- [ir.Primitive value, SourceInformation sourceInformation]) {
- isEmpty = false;
- builder.add(new ir.InvokeContinuation(continuation, <ir.Primitive>[value],
- isEscapingTry: isEscapingTry, sourceInformation: sourceInformation));
- builder._current = null;
- }
-}
-
-/// Collect 'goto' jumps, continue to a labeled case from within a switch.
-///
-/// These jumps are unrestricted within the switch. They can be forward or
-/// backward. They are implemented by assigning to a state variable.
-class GotoJumpCollector extends JumpCollector {
- bool isEmpty = true;
- final ir.Continuation continuation = null;
- final Environment environment = null;
-
- int _stateVariableIndex;
- int _stateValue;
- JumpCollector _breakJoin;
-
- GotoJumpCollector(JumpTarget target, this._stateVariableIndex,
- this._stateValue, this._breakJoin)
- : super.goto(target);
-
- void addJump(IrBuilder builder,
- [ir.Primitive value, SourceInformation sourceInformation]) {
- isEmpty = false;
- ir.Primitive constant = builder.buildIntegerConstant(_stateValue);
- builder.environment.index2value[_stateVariableIndex] = constant;
- builder.jumpTo(_breakJoin);
- }
-}
-
-/// Function for building a node in the context of the current builder.
-typedef ir.Node BuildFunction(node);
-
-/// Function for building nodes in the context of the provided [builder].
-typedef ir.Node SubbuildFunction(IrBuilder builder);
-
-/// Mixin that provides encapsulated access to nested builders.
-abstract class IrBuilderMixin<N> {
- IrBuilder _irBuilder;
-
- /// Execute [f] with [builder] as the current builder.
- withBuilder(IrBuilder builder, f()) {
- assert(builder != null);
- IrBuilder prev = _irBuilder;
- _irBuilder = builder;
- var result = f();
- _irBuilder = prev;
- return result;
- }
-
- /// The current builder.
- IrBuilder get irBuilder {
- assert(_irBuilder != null);
- return _irBuilder;
- }
-
- /// Visits the [node].
- ir.Primitive visit(N node);
-
- /// Builds and returns the [ir.Node] for [node] or returns `null` if
- /// [node] is `null`.
- ir.Node build(N node) => node != null ? visit(node) : null;
-
- /// Returns a closure that takes an [IrBuilder] and builds [node] in its
- /// context using [build].
- SubbuildFunction subbuild(N node) {
- return (IrBuilder builder) => withBuilder(builder, () => build(node));
- }
-
- /// Returns a closure that takes an [IrBuilder] and runs [f] in its context.
- SubbuildFunction nested(f()) {
- return (IrBuilder builder) => withBuilder(builder, f);
- }
-
- /// Returns a closure that takes an [IrBuilder] and builds the sequence of
- /// [nodes] in its context using [build].
- // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses
- // `List` instead of `Link`.
- SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) {
- return (IrBuilder builder) {
- return withBuilder(builder, () => builder.buildSequence(nodes, build));
- };
- }
-}
-
-/// Shared state between delimited IrBuilders within the same function.
-class IrBuilderSharedState {
- final GlobalProgramInformation program;
-
- final BackendConstantEnvironment constants;
-
- ConstantSystem get constantSystem => constants.constantSystem;
-
- /// A stack of collectors for breaks.
- List<JumpCollector> breakCollectors = <JumpCollector>[];
-
- /// A stack of collectors for continues.
- List<JumpCollector> continueCollectors = <JumpCollector>[];
-
- final ExecutableElement currentElement;
-
- final ir.Continuation returnContinuation = new ir.Continuation.retrn();
-
- /// The target of a return from the function.
- ///
- /// A null value indicates that the target is the function's return
- /// continuation. Otherwise, when inside the try block of try/finally
- /// a return is intercepted to give a place to generate the finally code.
- JumpCollector returnCollector;
-
- /// Parameter holding the internal value of 'this' passed to the function.
- ///
- /// For nested functions, this is *not* captured receiver, but the function
- /// object itself.
- ir.Parameter thisParameter;
-
- /// If non-null, this refers to the receiver (`this`) in the enclosing method.
- ir.Primitive enclosingThis;
-
- final List<ir.Parameter> functionParameters = <ir.Parameter>[];
-
- /// Maps boxed locals to their location. These locals are not part of
- /// the environment.
- final Map<Local, ClosureLocation> boxedVariables = {};
-
- IrBuilderSharedState(this.program, this.constants, this.currentElement) {
- returnCollector = new ReturnJumpCollector(returnContinuation);
- }
-}
-
-class ThisParameterLocal implements Local {
- final ExecutableElement executableContext;
- ThisParameterLocal(this.executableContext);
- String get name => 'this';
- toString() => 'ThisParameterLocal($executableContext)';
-}
-
-/// The IR builder maintains an environment and an IR fragment.
-///
-/// The IR fragment is an expression with a hole in it. The hole represents
-/// the focus where new expressions can be added. The fragment is implemented
-/// by [root] which is the root of the expression and [_current] which is the
-/// expression that immediately contains the hole. Not all expressions have a
-/// hole (e.g., invocations, which always occur in tail position, do not have a
-/// hole). Expressions with a hole have a plug method.
-///
-/// The environment maintains the reaching definition of each local variable,
-/// including some synthetic locals such as [TypeVariableLocal].
-///
-/// Internally, IR builders also maintains a [JumpCollector] stack and tracks
-/// which variables are currently boxed or held in a mutable local variable.
-class IrBuilder {
- final List<ir.Parameter> _parameters = <ir.Parameter>[];
-
- final IrBuilderSharedState state;
-
- /// A map from variable indexes to their values.
- ///
- /// [BoxLocal]s map to their box. [LocalElement]s that are boxed are not
- /// in the map; look up their [BoxLocal] instead.
- Environment environment;
-
- /// A map from mutable local variables to their [ir.MutableVariable]s.
- ///
- /// Mutable variables are treated as boxed. Writes to them are observable
- /// side effects.
- Map<Local, ir.MutableVariable> mutableVariables;
-
- ir.Expression root = null;
- ir.Expression _current = null;
-
- GlobalProgramInformation get program => state.program;
-
- IrBuilder(GlobalProgramInformation program,
- BackendConstantEnvironment constants, ExecutableElement currentElement)
- : state = new IrBuilderSharedState(program, constants, currentElement),
- environment = new Environment.empty(),
- mutableVariables = <Local, ir.MutableVariable>{};
-
- IrBuilder._internal(this.state, this.environment, this.mutableVariables);
-
- /// Construct a delimited visitor for visiting a subtree.
- ///
- /// Build a subterm that is not (yet) connected to the CPS term. The
- /// delimited visitor has its own has its own context for building an IR
- /// expression, so the built expression is not plugged into the parent's
- /// context. It has its own compile-time environment mapping local
- /// variables to their values. If an optional environment argument is
- /// supplied, it is used as the builder's initial environment. Otherwise
- /// the environment is initially a copy of the parent builder's environment.
- IrBuilder makeDelimitedBuilder([Environment env = null]) {
- return new IrBuilder._internal(
- state,
- env != null ? env : new Environment.from(environment),
- mutableVariables);
- }
-
- /// True if [local] should currently be accessed from a [ir.MutableVariable].
- bool isInMutableVariable(Local local) {
- return mutableVariables.containsKey(local);
- }
-
- /// Creates a [ir.MutableVariable] for the given local.
- void makeMutableVariable(Local local) {
- mutableVariables[local] = new ir.MutableVariable(local);
- }
-
- /// Remove an [ir.MutableVariable] for a local.
- ///
- /// Subsequent access to the local will be direct rather than through the
- /// mutable variable.
- void removeMutableVariable(Local local) {
- mutableVariables.remove(local);
- }
-
- /// Gets the [MutableVariable] containing the value of [local].
- ir.MutableVariable getMutableVariable(Local local) {
- return mutableVariables[local];
- }
-
- bool get isOpen => root == null || _current != null;
-
- List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters,
- {ClosureScope closureScope, ClosureEnvironment env}) {
- _createThisParameter();
- _enterClosureEnvironment(env);
- _enterScope(closureScope);
- parameters.forEach(_createFunctionParameter);
- return _parameters;
- }
-
- /// Creates a parameter for [local] and adds it to the current environment.
- ir.Parameter _createLocalParameter(Local local) {
- ir.Parameter parameter = new ir.Parameter(local);
- _parameters.add(parameter);
- environment.extend(local, parameter);
- return parameter;
- }
-
- /// Plug an expression into the 'hole' in the context being accumulated. The
- /// empty context (just a hole) is represented by root (and current) being
- /// null. Since the hole in the current context is filled by this function,
- /// the new hole must be in the newly added expression---which becomes the
- /// new value of current.
- void add(ir.Expression expr) {
- assert(isOpen);
- if (root == null) {
- root = _current = expr;
- } else {
- _current = _current.plug(expr);
- }
- }
-
- /// Create and add a new [LetPrim] for [primitive].
- ir.Primitive addPrimitive(ir.Primitive primitive) {
- add(new ir.LetPrim(primitive));
- return primitive;
- }
-
- ir.Primitive buildInvokeStatic(Element element, Selector selector,
- List<ir.Primitive> arguments, SourceInformation sourceInformation) {
- assert(!element.isLocal);
- assert(!element.isInstanceMember);
- assert(isOpen);
- if (program.isJsInterop(element)) {
- return buildInvokeJsInteropMember(element, arguments, sourceInformation);
- }
- return addPrimitive(
- new ir.InvokeStatic(element, selector, arguments, sourceInformation));
- }
-
- ir.Primitive _buildInvokeSuper(Element target, Selector selector,
- List<ir.Primitive> arguments, SourceInformation sourceInformation) {
- assert(target.isInstanceMember);
- assert(isOpen);
- return addPrimitive(new ir.InvokeMethodDirectly(
- buildThis(), target, selector, arguments, sourceInformation));
- }
-
- ir.Primitive _buildInvokeDynamic(
- ir.Primitive receiver,
- Selector selector,
- TypeMask mask,
- List<ir.Primitive> arguments,
- SourceInformation sourceInformation) {
- assert(isOpen);
- return addPrimitive(new ir.InvokeMethod(receiver, selector, mask, arguments,
- sourceInformation: sourceInformation));
- }
-
- ir.Primitive _buildInvokeCall(
- ir.Primitive target,
- CallStructure callStructure,
- TypeMask mask,
- List<ir.Definition> arguments,
- SourceInformation sourceInformation) {
- Selector selector = callStructure.callSelector;
- return _buildInvokeDynamic(
- target, selector, mask, arguments, sourceInformation);
- }
-
- ir.Primitive buildStaticNoSuchMethod(Selector selector,
- List<ir.Primitive> arguments, SourceInformation sourceInformation) {
- ir.Primitive receiver = buildStringConstant('');
- ir.Primitive name = buildStringConstant(selector.name);
- ir.Primitive argumentList = buildListLiteral(null, arguments);
- ir.Primitive expectedArgumentNames = buildNullConstant();
- return buildStaticFunctionInvocation(
- program.throwNoSuchMethod,
- <ir.Primitive>[receiver, name, argumentList, expectedArgumentNames],
- sourceInformation);
- }
-
- /// Create a [ir.Constant] from [value] and add it to the CPS term.
- ir.Constant buildConstant(ConstantValue value,
- {SourceInformation sourceInformation}) {
- assert(isOpen);
- return addPrimitive(
- new ir.Constant(value, sourceInformation: sourceInformation));
- }
-
- /// Create an integer constant and add it to the CPS term.
- ir.Constant buildIntegerConstant(int value) {
- return buildConstant(state.constantSystem.createInt(value));
- }
-
- /// Create a double constant and add it to the CPS term.
- ir.Constant buildDoubleConstant(double value) {
- return buildConstant(state.constantSystem.createDouble(value));
- }
-
- /// Create a Boolean constant and add it to the CPS term.
- ir.Constant buildBooleanConstant(bool value) {
- return buildConstant(state.constantSystem.createBool(value));
- }
-
- /// Create a null constant and add it to the CPS term.
- ir.Constant buildNullConstant() {
- return buildConstant(state.constantSystem.createNull());
- }
-
- /// Create a string constant and add it to the CPS term.
- ir.Constant buildStringConstant(String value) {
- return buildConstant(
- state.constantSystem.createString(new ast.DartString.literal(value)));
- }
-
- /// Create a string constant and add it to the CPS term.
- ir.Constant buildDartStringConstant(ast.DartString value) {
- return buildConstant(state.constantSystem.createString(value));
- }
-
- /// Creates a non-constant list literal of the provided [type] and with the
- /// provided [values].
- ir.Primitive buildListLiteral(
- InterfaceType type, Iterable<ir.Primitive> values,
- {TypeMask allocationSiteType}) {
- assert(isOpen);
- return addPrimitive(new ir.LiteralList(type, values.toList(),
- allocationSiteType: allocationSiteType));
- }
-
- /// Creates a conditional expression with the provided [condition] where the
- /// then and else expression are created through the [buildThenExpression]
- /// and [buildElseExpression] functions, respectively.
- ir.Primitive buildConditional(
- ir.Primitive condition,
- ir.Primitive buildThenExpression(IrBuilder builder),
- ir.Primitive buildElseExpression(IrBuilder builder),
- SourceInformation sourceInformation) {
- assert(isOpen);
-
- // The then and else expressions are delimited.
- IrBuilder thenBuilder = makeDelimitedBuilder();
- IrBuilder elseBuilder = makeDelimitedBuilder();
- ir.Primitive thenValue = buildThenExpression(thenBuilder);
- ir.Primitive elseValue = buildElseExpression(elseBuilder);
-
- // Treat the values of the subexpressions as named values in the
- // environment, so they will be treated as arguments to the join-point
- // continuation. We know the environments are the right size because
- // expressions cannot introduce variable bindings.
- assert(environment.length == thenBuilder.environment.length);
- assert(environment.length == elseBuilder.environment.length);
- JumpCollector join =
- new ForwardJumpCollector(environment, hasExtraArgument: true);
- thenBuilder.jumpTo(join, thenValue);
- elseBuilder.jumpTo(join, elseValue);
-
- // Build the term
- // let cont join(x, ..., result) = [] in
- // let cont then() = [[thenPart]]; join(v, ...)
- // and else() = [[elsePart]]; join(v, ...)
- // in
- // if condition (then, else)
- ir.Continuation thenContinuation = new ir.Continuation([]);
- ir.Continuation elseContinuation = new ir.Continuation([]);
- thenContinuation.body = thenBuilder.root;
- elseContinuation.body = elseBuilder.root;
- add(new ir.LetCont(
- join.continuation,
- new ir.LetCont.two(
- thenContinuation,
- elseContinuation,
- new ir.Branch.strict(condition, thenContinuation, elseContinuation,
- sourceInformation))));
- environment = join.environment;
- return environment.discard(1);
- }
-
- /**
- * Add an explicit `return null` for functions that don't have a return
- * statement on each branch. This includes functions with an empty body,
- * such as `foo(){ }`.
- */
- void _ensureReturn() {
- if (!isOpen) return;
- ir.Constant constant = buildNullConstant();
- add(new ir.InvokeContinuation(state.returnContinuation, [constant]));
- _current = null;
- }
-
- /// Create a [ir.FunctionDefinition] using [root] as the body.
- ///
- /// The protocol for building a function is:
- /// 1. Call [buildFunctionHeader].
- /// 2. Call `buildXXX` methods to build the body.
- /// 3. Call [makeFunctionDefinition] to finish.
- ir.FunctionDefinition makeFunctionDefinition(
- SourceInformation sourceInformation) {
- _ensureReturn();
- return new ir.FunctionDefinition(state.currentElement, state.thisParameter,
- state.functionParameters, state.returnContinuation, root,
- sourceInformation: sourceInformation);
- }
-
- /// Create a invocation of the [method] on the super class where the call
- /// structure is defined [callStructure] and the argument values are defined
- /// by [arguments].
- ir.Primitive buildSuperMethodInvocation(
- MethodElement method,
- CallStructure callStructure,
- List<ir.Primitive> arguments,
- SourceInformation sourceInformation) {
- // TODO(johnniwinther): This shouldn't be necessary.
- SelectorKind kind = Elements.isOperatorName(method.name)
- ? SelectorKind.OPERATOR
- : SelectorKind.CALL;
- Selector selector = new Selector(kind, method.memberName, callStructure);
- return _buildInvokeSuper(method, selector, arguments, sourceInformation);
- }
-
- /// Create a read access of the [method] on the super class, i.e. a
- /// closurization of [method].
- ir.Primitive buildSuperMethodGet(
- MethodElement method, SourceInformation sourceInformation) {
- // TODO(johnniwinther): This should have its own ir node.
- return _buildInvokeSuper(method, new Selector.getter(method.memberName),
- const <ir.Primitive>[], sourceInformation);
- }
-
- /// Create a getter invocation of the [getter] on the super class.
- ir.Primitive buildSuperGetterGet(
- MethodElement getter, SourceInformation sourceInformation) {
- // TODO(johnniwinther): This should have its own ir node.
- return _buildInvokeSuper(getter, new Selector.getter(getter.memberName),
- const <ir.Primitive>[], sourceInformation);
- }
-
- /// Create an setter invocation of the [setter] on the super class with
- /// [value].
- ir.Primitive buildSuperSetterSet(MethodElement setter, ir.Primitive value,
- SourceInformation sourceInformation) {
- // TODO(johnniwinther): This should have its own ir node.
- _buildInvokeSuper(setter, new Selector.setter(setter.memberName),
- <ir.Primitive>[value], sourceInformation);
- return value;
- }
-
- /// Create an invocation of the index [method] on the super class with
- /// the provided [index].
- ir.Primitive buildSuperIndex(MethodElement method, ir.Primitive index,
- SourceInformation sourceInformation) {
- return _buildInvokeSuper(
- method, new Selector.index(), <ir.Primitive>[index], sourceInformation);
- }
-
- /// Create an invocation of the index set [method] on the super class with
- /// the provided [index] and [value].
- ir.Primitive buildSuperIndexSet(MethodElement method, ir.Primitive index,
- ir.Primitive value, SourceInformation sourceInformation) {
- _buildInvokeSuper(method, new Selector.indexSet(),
- <ir.Primitive>[index, value], sourceInformation);
- return value;
- }
-
- /// Create a dynamic invocation on [receiver] where the method name and
- /// argument structure are defined by [selector] and the argument values are
- /// defined by [arguments].
- ir.Primitive buildDynamicInvocation(
- ir.Primitive receiver,
- Selector selector,
- TypeMask mask,
- List<ir.Primitive> arguments,
- SourceInformation sourceInformation) {
- return _buildInvokeDynamic(
- receiver, selector, mask, arguments, sourceInformation);
- }
-
- /// Create a dynamic getter invocation on [receiver] where the getter name is
- /// defined by [selector].
- ir.Primitive buildDynamicGet(ir.Primitive receiver, Selector selector,
- TypeMask mask, SourceInformation sourceInformation) {
- assert(selector.isGetter);
- FieldElement field = program.locateSingleField(selector, mask);
- if (field != null) {
- // If the world says this resolves to a unique field, then it MUST be
- // treated as a field access, since the getter might not be emitted.
- return buildFieldGet(receiver, field, sourceInformation);
- } else {
- return _buildInvokeDynamic(
- receiver, selector, mask, const <ir.Primitive>[], sourceInformation);
- }
- }
-
- /// Create a dynamic setter invocation on [receiver] where the setter name and
- /// argument are defined by [selector] and [value], respectively.
- ir.Primitive buildDynamicSet(ir.Primitive receiver, Selector selector,
- TypeMask mask, ir.Primitive value, SourceInformation sourceInformation) {
- assert(selector.isSetter);
- FieldElement field = program.locateSingleField(selector, mask);
- if (field != null) {
- // If the world says this resolves to a unique field, then it MUST be
- // treated as a field access, since the setter might not be emitted.
- buildFieldSet(receiver, field, value, sourceInformation);
- } else {
- _buildInvokeDynamic(
- receiver, selector, mask, <ir.Primitive>[value], sourceInformation);
- }
- return value;
- }
-
- /// Create a dynamic index set invocation on [receiver] with the provided
- /// [index] and [value].
- ir.Primitive buildDynamicIndexSet(
- ir.Primitive receiver,
- TypeMask mask,
- ir.Primitive index,
- ir.Primitive value,
- SourceInformation sourceInformation) {
- _buildInvokeDynamic(receiver, new Selector.indexSet(), mask,
- <ir.Primitive>[index, value], sourceInformation);
- return value;
- }
-
- /// Create an invocation of the local [function] where argument structure is
- /// defined by [callStructure] and the argument values are defined by
- /// [arguments].
- ir.Primitive buildLocalFunctionInvocation(
- LocalFunctionElement function,
- CallStructure callStructure,
- List<ir.Primitive> arguments,
- SourceInformation sourceInformation) {
- // TODO(johnniwinther): Maybe this should have its own ir node.
- return buildCallInvocation(
- buildLocalGet(function), callStructure, arguments, sourceInformation);
- }
-
- /// Create a static invocation of [function].
- ///
- /// The arguments are not named and their values are defined by [arguments].
- ir.Primitive buildStaticFunctionInvocation(MethodElement function,
- List<ir.Primitive> arguments, SourceInformation sourceInformation) {
- Selector selector = new Selector.call(
- function.memberName, new CallStructure(arguments.length));
- return buildInvokeStatic(function, selector, arguments, sourceInformation);
- }
-
- /// Create a getter invocation of the static [getter].
- ir.Primitive buildStaticGetterGet(
- MethodElement getter, SourceInformation sourceInformation) {
- Selector selector = new Selector.getter(getter.memberName);
- return buildInvokeStatic(
- getter, selector, const <ir.Primitive>[], sourceInformation);
- }
-
- /// Create a write access to the static [field] with the [value].
- ir.Primitive buildStaticFieldSet(FieldElement field, ir.Primitive value,
- SourceInformation sourceInformation) {
- addPrimitive(new ir.SetStatic(field, value, sourceInformation));
- return value;
- }
-
- /// Create a setter invocation of the static [setter] with the [value].
- ir.Primitive buildStaticSetterSet(MethodElement setter, ir.Primitive value,
- SourceInformation sourceInformation) {
- Selector selector = new Selector.setter(setter.memberName);
- buildInvokeStatic(
- setter, selector, <ir.Primitive>[value], sourceInformation);
- return value;
- }
-
- /// Create an erroneous invocation where argument structure is defined by
- /// [selector] and the argument values are defined by [arguments].
- // TODO(johnniwinther): Make this more fine-grained.
- ir.Primitive buildErroneousInvocation(Element element, Selector selector,
- List<ir.Primitive> arguments, SourceInformation sourceInformation) {
- // TODO(johnniwinther): This should have its own ir node.
- return buildInvokeStatic(element, selector, arguments, sourceInformation);
- }
-
- /// Concatenate string values. The arguments must be strings.
- ir.Primitive buildStringConcatenation(
- List<ir.Primitive> arguments, SourceInformation sourceInformation) {
- assert(isOpen);
- return addPrimitive(new ir.ApplyBuiltinOperator(
- ir.BuiltinOperator.StringConcatenate, arguments, sourceInformation));
- }
-
- /// Create an invocation of the `call` method of [functionExpression], where
- /// the structure of arguments are given by [callStructure].
- // TODO(johnniwinther): This should take a [TypeMask].
- ir.Primitive buildCallInvocation(
- ir.Primitive functionExpression,
- CallStructure callStructure,
- List<ir.Definition> arguments,
- SourceInformation sourceInformation) {
- return _buildInvokeCall(
- functionExpression, callStructure, null, arguments, sourceInformation);
- }
-
- /// Creates an if-then-else statement with the provided [condition] where the
- /// then and else branches are created through the [buildThenPart] and
- /// [buildElsePart] functions, respectively.
- ///
- /// An if-then statement is created if [buildElsePart] is a no-op.
- // TODO(johnniwinther): Unify implementation with [buildConditional] and
- // [_buildLogicalOperator].
- void buildIf(
- ir.Primitive condition,
- void buildThenPart(IrBuilder builder),
- void buildElsePart(IrBuilder builder),
- SourceInformation sourceInformation) {
- assert(isOpen);
-
- // The then and else parts are delimited.
- IrBuilder thenBuilder = makeDelimitedBuilder();
- IrBuilder elseBuilder = makeDelimitedBuilder();
- buildThenPart(thenBuilder);
- buildElsePart(elseBuilder);
-
- // Build the term
- // (Result =) let cont then() = [[thenPart]]
- // and else() = [[elsePart]]
- // in
- // if condition (then, else)
- ir.Continuation thenContinuation = new ir.Continuation([]);
- ir.Continuation elseContinuation = new ir.Continuation([]);
- // If exactly one of the then and else continuation bodies is open (i.e.,
- // the other one has an exit on all paths), then Continuation.plug expects
- // that continuation to be listed first. Arbitrarily use [then, else]
- // order otherwise.
- List<ir.Continuation> arms = !thenBuilder.isOpen && elseBuilder.isOpen
- ? <ir.Continuation>[elseContinuation, thenContinuation]
- : <ir.Continuation>[thenContinuation, elseContinuation];
-
- ir.Expression result = new ir.LetCont.many(
- arms,
- new ir.Branch.strict(
- condition, thenContinuation, elseContinuation, sourceInformation));
-
- JumpCollector join; // Null if there is no join.
- if (thenBuilder.isOpen && elseBuilder.isOpen) {
- // There is a join-point continuation. Build the term
- // 'let cont join(x, ...) = [] in Result' and plug invocations of the
- // join-point continuation into the then and else continuations.
- join = new ForwardJumpCollector(environment);
- thenBuilder.jumpTo(join);
- elseBuilder.jumpTo(join);
- result = new ir.LetCont(join.continuation, result);
- }
-
- // The then or else term root could be null, but not both. If there is
- // a join then an InvokeContinuation was just added to both of them. If
- // there is no join, then at least one of them is closed and thus has a
- // non-null root by the definition of the predicate isClosed. In the
- // case that one of them is null, it must be the only one that is open
- // and thus contains the new hole in the context. This case is handled
- // after the branch is plugged into the current hole.
- thenContinuation.body = thenBuilder.root;
- elseContinuation.body = elseBuilder.root;
-
- add(result);
- if (join == null) {
- // At least one subexpression is closed.
- if (thenBuilder.isOpen) {
- if (thenBuilder.root != null) _current = thenBuilder._current;
- environment = thenBuilder.environment;
- } else if (elseBuilder.isOpen) {
- if (elseBuilder.root != null) _current = elseBuilder._current;
- environment = elseBuilder.environment;
- } else {
- _current = null;
- }
- } else {
- environment = join.environment;
- }
- }
-
- void jumpTo(JumpCollector collector,
- [ir.Primitive value, SourceInformation sourceInformation]) {
- collector.addJump(this, value, sourceInformation);
- }
-
- void addRecursiveContinuation(BackwardJumpCollector collector) {
- assert(environment.length == collector.environment.length);
- add(new ir.LetCont(
- collector.continuation,
- new ir.InvokeContinuation(
- collector.continuation, environment.index2value)));
- environment = collector.environment;
- }
-
- /// Creates a for loop in which the initializer, condition, body, update are
- /// created by [buildInitializer], [buildCondition], [buildBody] and
- /// [buildUpdate], respectively.
- ///
- /// The jump [target] is used to identify which `break` and `continue`
- /// statements that have this `for` statement as their target.
- ///
- /// The [closureScope] identifies variables that should be boxed in this loop.
- /// This includes variables declared inside the body of the loop as well as
- /// in the for-loop initializer.
- ///
- /// [loopVariables] is the list of variables declared in the for-loop
- /// initializer.
- void buildFor(
- {SubbuildFunction buildInitializer,
- SubbuildFunction buildCondition,
- SourceInformation conditionSourceInformation,
- SubbuildFunction buildBody,
- SubbuildFunction buildUpdate,
- JumpTarget target,
- ClosureScope closureScope,
- List<LocalElement> loopVariables}) {
- assert(isOpen);
-
- // For loops use four named continuations: the entry to the condition,
- // the entry to the body, the loop exit, and the loop successor (break).
- // The CPS translation of
- // [[for (initializer; condition; update) body; successor]] is:
- //
- // _enterForLoopInitializer();
- // [[initializer]];
- // let cont loop(x, ...) =
- // let prim cond = [[condition]] in
- // let cont break(x, ...) = [[successor]] in
- // let cont exit() = break(v, ...) in
- // let cont body() =
- // _enterForLoopBody();
- // let cont continue(x, ...) =
- // _enterForLoopUpdate();
- // [[update]];
- // loop(v, ...) in
- // [[body]];
- // continue(v, ...) in
- // branch cond (body, exit) in
- // loop(v, ...)
- //
- // If there are no breaks in the body, the break continuation is inlined
- // in the exit continuation (i.e., the translation of the successor
- // statement occurs in the exit continuation). If there is only one
- // invocation of the continue continuation (i.e., no continues in the
- // body), the continue continuation is inlined in the body.
- _enterForLoopInitializer(closureScope, loopVariables);
- buildInitializer(this);
-
- JumpCollector loop = new BackwardJumpCollector(environment);
- addRecursiveContinuation(loop);
-
- ir.Primitive condition = buildCondition(this);
- if (condition == null) {
- // If the condition is empty then the body is entered unconditionally.
- condition = buildBooleanConstant(true);
- }
- JumpCollector breakCollector =
- new ForwardJumpCollector(environment, target: target);
-
- // Use a pair of builders for the body, one for the entry code if any
- // and one for the body itself. We only decide whether to insert a
- // continue continuation until after translating the body and there is no
- // way to insert such a continuation between the entry code and the body
- // if they are translated together.
- IrBuilder outerBodyBuilder = makeDelimitedBuilder();
- outerBodyBuilder._enterForLoopBody(closureScope, loopVariables);
- JumpCollector continueCollector =
- new ForwardJumpCollector(outerBodyBuilder.environment, target: target);
-
- IrBuilder innerBodyBuilder = outerBodyBuilder.makeDelimitedBuilder();
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(continueCollector);
- buildBody(innerBodyBuilder);
- assert(state.breakCollectors.last == breakCollector);
- assert(state.continueCollectors.last == continueCollector);
- state.breakCollectors.removeLast();
- state.continueCollectors.removeLast();
-
- // The binding of the continue continuation should occur as late as
- // possible, that is, at the nearest common ancestor of all the continue
- // sites in the body. However, that is difficult to compute here, so it
- // is instead placed just outside the translation of the loop body. In
- // the case where there are no continues in the body, the updates are
- // translated immediately after the body.
- bool hasContinues = !continueCollector.isEmpty;
- IrBuilder updateBuilder;
- if (hasContinues) {
- if (innerBodyBuilder.isOpen) innerBodyBuilder.jumpTo(continueCollector);
- updateBuilder = makeDelimitedBuilder(continueCollector.environment);
- } else {
- updateBuilder = innerBodyBuilder;
- }
- updateBuilder._enterForLoopUpdate(closureScope, loopVariables);
- buildUpdate(updateBuilder);
- if (updateBuilder.isOpen) updateBuilder.jumpTo(loop);
- // Connect the inner and outer body builders. This is done only after
- // it is guaranteed that the updateBuilder has a non-empty term.
- if (hasContinues) {
- outerBodyBuilder.add(new ir.LetCont(
- continueCollector.continuation, innerBodyBuilder.root));
- continueCollector.continuation.body = updateBuilder.root;
- } else {
- outerBodyBuilder.add(innerBodyBuilder.root);
- }
-
- // Create loop exit and body entry continuations and a branch to them.
- ir.Continuation exitContinuation = new ir.Continuation([]);
- ir.Continuation bodyContinuation = new ir.Continuation([]);
- bodyContinuation.body = outerBodyBuilder.root;
- // Note the order of continuations: the first one is the one that will
- // be filled by LetCont.plug.
- ir.LetCont branch = new ir.LetCont.two(
- exitContinuation,
- bodyContinuation,
- new ir.Branch.strict(condition, bodyContinuation, exitContinuation,
- conditionSourceInformation));
- // If there are breaks in the body, then there must be a join-point
- // continuation for the normal exit and the breaks. Otherwise, the
- // successor is translated in the hole in the exit continuation.
- bool hasBreaks = !breakCollector.isEmpty;
- ir.LetCont letBreak;
- if (hasBreaks) {
- IrBuilder exitBuilder = makeDelimitedBuilder();
- exitBuilder.jumpTo(breakCollector);
- exitContinuation.body = exitBuilder.root;
- letBreak = new ir.LetCont(breakCollector.continuation, branch);
- add(letBreak);
- environment = breakCollector.environment;
- } else {
- add(branch);
- }
- }
-
- /// Creates a for-in loop, `for (v in e) b`.
- ///
- /// [buildExpression] creates the expression, `e`. The variable, `v`, can
- /// take one of three forms:
- /// 1) `v` can be declared within the for-in statement, like in
- /// `for (var v in e)`, in which case, [buildVariableDeclaration]
- /// creates its declaration and [variableElement] is the element for
- /// the declared variable,
- /// 2) `v` is predeclared statically known variable, that is top-level,
- /// static, or local variable, in which case [variableElement] is the
- /// variable element, and [variableSelector] defines its write access,
- /// 3) `v` is an instance variable in which case [variableSelector]
- /// defines its write access.
- /// [buildBody] creates the body, `b`, of the loop. The jump [target] is used
- /// to identify which `break` and `continue` statements that have this for-in
- /// statement as their target.
- void buildForIn(
- {SubbuildFunction buildExpression,
- SubbuildFunction buildVariableDeclaration,
- Element variableElement,
- Selector variableSelector,
- TypeMask variableMask,
- SourceInformation variableSetSourceInformation,
- TypeMask currentMask,
- SourceInformation currentSourceInformation,
- TypeMask iteratorMask,
- SourceInformation iteratorSourceInformation,
- TypeMask moveNextMask,
- SourceInformation moveNextSourceInformation,
- SubbuildFunction buildBody,
- JumpTarget target,
- ClosureScope closureScope,
- SourceInformation conditionSourceInformation}) {
- // The for-in loop
- //
- // for (a in e) s;
- //
- // Is compiled analogously to:
- //
- // it = e.iterator;
- // while (it.moveNext()) {
- // var a = it.current;
- // s;
- // }
-
- // Fill the current hole with:
- // let prim expressionReceiver = [[e]] in
- // let cont iteratorInvoked(iterator) =
- // [ ]
- // in expressionReceiver.iterator () iteratorInvoked
- ir.Primitive expressionReceiver = buildExpression(this);
- List<ir.Primitive> emptyArguments = <ir.Primitive>[];
- ir.Primitive iterator = addPrimitive(new ir.InvokeMethod(
- expressionReceiver, Selectors.iterator, iteratorMask, emptyArguments));
-
- // Fill with:
- // let cont loop(x, ...) =
- // let cont moveNextInvoked(condition) =
- // [ ]
- // in iterator.moveNext () moveNextInvoked
- // in loop(v, ...)
- JumpCollector loop = new BackwardJumpCollector(environment, target: target);
- addRecursiveContinuation(loop);
- ir.Primitive condition = addPrimitive(new ir.InvokeMethod(
- iterator, Selectors.moveNext, moveNextMask, emptyArguments));
-
- // As a delimited term, build:
- // <<BODY>> =
- // _enterScope();
- // [[variableDeclaration]]
- // let cont currentInvoked(currentValue) =
- // [[a = currentValue]];
- // [ ]
- // in iterator.current () currentInvoked
- IrBuilder bodyBuilder = makeDelimitedBuilder();
- bodyBuilder._enterScope(closureScope);
- if (buildVariableDeclaration != null) {
- buildVariableDeclaration(bodyBuilder);
- }
- ir.Primitive currentValue = bodyBuilder.addPrimitive(new ir.InvokeMethod(
- iterator, Selectors.current, currentMask, emptyArguments,
- sourceInformation: currentSourceInformation));
- // TODO(johnniwinther): Extract this as a provided strategy.
- if (Elements.isLocal(variableElement)) {
- bodyBuilder.buildLocalVariableSet(
- variableElement, currentValue, variableSetSourceInformation);
- } else if (Elements.isError(variableElement) ||
- Elements.isMalformed(variableElement)) {
- Selector selector = new Selector.setter(
- new Name(variableElement.name, variableElement.library));
- List<ir.Primitive> value = <ir.Primitive>[currentValue];
- // Note the comparison below. It can be the case that an element isError
- // and isMalformed.
- if (Elements.isError(variableElement)) {
- bodyBuilder.buildStaticNoSuchMethod(
- selector, value, variableSetSourceInformation);
- } else {
- bodyBuilder.buildErroneousInvocation(
- variableElement, selector, value, variableSetSourceInformation);
- }
- } else if (Elements.isStaticOrTopLevel(variableElement)) {
- if (variableElement.isField) {
- bodyBuilder.addPrimitive(new ir.SetStatic(
- variableElement, currentValue, variableSetSourceInformation));
- } else {
- bodyBuilder.buildStaticSetterSet(
- variableElement, currentValue, variableSetSourceInformation);
- }
- } else {
- ir.Primitive receiver = bodyBuilder.buildThis();
- assert(receiver != null);
- bodyBuilder.buildDynamicSet(receiver, variableSelector, variableMask,
- currentValue, variableSetSourceInformation);
- }
-
- // Translate the body in the hole in the delimited term above, and add
- // a jump to the loop if control flow is live after the body.
- JumpCollector breakCollector =
- new ForwardJumpCollector(environment, target: target);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(loop);
- buildBody(bodyBuilder);
- assert(state.breakCollectors.last == breakCollector);
- assert(state.continueCollectors.last == loop);
- state.breakCollectors.removeLast();
- state.continueCollectors.removeLast();
- if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop);
-
- // Create body entry and loop exit continuations and a branch to them.
- //
- // let cont exit() = [ ]
- // and body() = <<BODY>>
- // in branch condition (body, exit)
- ir.Continuation exitContinuation = new ir.Continuation([]);
- ir.Continuation bodyContinuation = new ir.Continuation([]);
- bodyContinuation.body = bodyBuilder.root;
- // Note the order of continuations: the first one is the one that will
- // be filled by LetCont.plug.
- ir.LetCont branch = new ir.LetCont.two(
- exitContinuation,
- bodyContinuation,
- new ir.Branch.strict(condition, bodyContinuation, exitContinuation,
- conditionSourceInformation));
- // If there are breaks in the body, then there must be a join-point
- // continuation for the normal exit and the breaks. Otherwise, the
- // successor is translated in the hole in the exit continuation.
- bool hasBreaks = !breakCollector.isEmpty;
- ir.LetCont letBreak;
- if (hasBreaks) {
- IrBuilder exitBuilder = makeDelimitedBuilder();
- exitBuilder.jumpTo(breakCollector);
- exitContinuation.body = exitBuilder.root;
- letBreak = new ir.LetCont(breakCollector.continuation, branch);
- add(letBreak);
- environment = breakCollector.environment;
- } else {
- add(branch);
- }
- }
-
- /// Creates a while loop in which the condition and body are created by
- /// [buildCondition] and [buildBody], respectively.
- ///
- /// The jump [target] is used to identify which `break` and `continue`
- /// statements that have this `while` statement as their target.
- void buildWhile(
- {SubbuildFunction buildCondition,
- SubbuildFunction buildBody,
- JumpTarget target,
- ClosureScope closureScope,
- SourceInformation sourceInformation}) {
- assert(isOpen);
- // While loops use four named continuations: the entry to the body, the
- // loop exit, the loop back edge (continue), and the loop exit (break).
- // The CPS translation of [[while (condition) body; successor]] is:
- //
- // let cont continue(x, ...) =
- // let prim cond = [[condition]] in
- // let cont break(x, ...) = [[successor]] in
- // let cont exit() = break(v, ...)
- // and body() =
- // _enterScope();
- // [[body]];
- // continue(v, ...)
- // in branch cond (body, exit)
- // in continue(v, ...)
- //
- // If there are no breaks in the body, the break continuation is inlined
- // in the exit continuation (i.e., the translation of the successor
- // statement occurs in the exit continuation).
- JumpCollector loop = new BackwardJumpCollector(environment, target: target);
- addRecursiveContinuation(loop);
-
- ir.Primitive condition = buildCondition(this);
-
- JumpCollector breakCollector =
- new ForwardJumpCollector(environment, target: target);
-
- IrBuilder bodyBuilder = makeDelimitedBuilder();
- bodyBuilder._enterScope(closureScope);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(loop);
- buildBody(bodyBuilder);
- assert(state.breakCollectors.last == breakCollector);
- assert(state.continueCollectors.last == loop);
- state.breakCollectors.removeLast();
- state.continueCollectors.removeLast();
- if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop);
-
- // Create body entry and loop exit continuations and a branch to them.
- ir.Continuation exitContinuation = new ir.Continuation([]);
- ir.Continuation bodyContinuation = new ir.Continuation([]);
- bodyContinuation.body = bodyBuilder.root;
- // Note the order of continuations: the first one is the one that will
- // be filled by LetCont.plug.
- ir.LetCont branch = new ir.LetCont.two(
- exitContinuation,
- bodyContinuation,
- new ir.Branch.strict(
- condition, bodyContinuation, exitContinuation, sourceInformation));
- // If there are breaks in the body, then there must be a join-point
- // continuation for the normal exit and the breaks. Otherwise, the
- // successor is translated in the hole in the exit continuation.
- bool hasBreaks = !breakCollector.isEmpty;
- ir.LetCont letBreak;
- if (hasBreaks) {
- IrBuilder exitBuilder = makeDelimitedBuilder();
- exitBuilder.jumpTo(breakCollector);
- exitContinuation.body = exitBuilder.root;
- letBreak = new ir.LetCont(breakCollector.continuation, branch);
- add(letBreak);
- environment = breakCollector.environment;
- } else {
- add(branch);
- }
- }
-
- /// Creates a do-while loop.
- ///
- /// The body and condition are created by [buildBody] and [buildCondition].
- /// The jump target [target] is the target of `break` and `continue`
- /// statements in the body that have the loop as their target.
- /// [closureScope] contains all the variables declared in the loop (but not
- /// declared in some inner closure scope).
- void buildDoWhile(
- {SubbuildFunction buildBody,
- SubbuildFunction buildCondition,
- JumpTarget target,
- ClosureScope closureScope,
- SourceInformation sourceInformation}) {
- assert(isOpen);
- // The CPS translation of [[do body; while (condition); successor]] is:
- //
- // let cont break(x, ...) = [[successor]] in
- // let cont rec loop(x, ...) =
- // let cont continue(x, ...) =
- // let prim cond = [[condition]] in
- // let cont exit() = break(v, ...)
- // and repeat() = loop(v, ...)
- // in branch cond (repeat, exit)
- // in [[body]]; continue(v, ...)
- // in loop(v, ...)
- IrBuilder loopBuilder = makeDelimitedBuilder();
- JumpCollector loop =
- new BackwardJumpCollector(loopBuilder.environment, target: target);
- loopBuilder.addRecursiveContinuation(loop);
-
- // Translate the body.
- JumpCollector breakCollector =
- new ForwardJumpCollector(environment, target: target);
- JumpCollector continueCollector =
- new ForwardJumpCollector(loopBuilder.environment, target: target);
- IrBuilder bodyBuilder = loopBuilder.makeDelimitedBuilder();
- bodyBuilder._enterScope(closureScope);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(continueCollector);
- buildBody(bodyBuilder);
- assert(state.breakCollectors.last == breakCollector);
- assert(state.continueCollectors.last == continueCollector);
- state.breakCollectors.removeLast();
- state.continueCollectors.removeLast();
- if (bodyBuilder.isOpen) bodyBuilder.jumpTo(continueCollector);
-
- // Construct the body of the continue continuation (i.e., the condition).
- // <Continue> =
- // let prim cond = [[condition]] in
- // let cont exit() = break(v, ...)
- // and repeat() = loop(v, ...)
- // in branch cond (repeat, exit)
- IrBuilder continueBuilder = loopBuilder.makeDelimitedBuilder();
- continueBuilder.environment = continueCollector.environment;
- ir.Primitive condition = buildCondition(continueBuilder);
-
- ir.Continuation exitContinuation = new ir.Continuation([]);
- IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder();
- exitBuilder.jumpTo(breakCollector);
- exitContinuation.body = exitBuilder.root;
- ir.Continuation repeatContinuation = new ir.Continuation([]);
- IrBuilder repeatBuilder = continueBuilder.makeDelimitedBuilder();
- repeatBuilder.jumpTo(loop);
- repeatContinuation.body = repeatBuilder.root;
-
- continueBuilder.add(new ir.LetCont.two(
- exitContinuation,
- repeatContinuation,
- new ir.Branch.strict(condition, repeatContinuation, exitContinuation,
- sourceInformation)));
- continueCollector.continuation.body = continueBuilder.root;
-
- // Construct the loop continuation (i.e., the body and condition).
- // <Loop> =
- // let cont continue(x, ...) =
- // <Continue>
- // in [[body]]; continue(v, ...)
- loopBuilder
- .add(new ir.LetCont(continueCollector.continuation, bodyBuilder.root));
-
- // And tie it all together.
- add(new ir.LetCont(breakCollector.continuation, loopBuilder.root));
- environment = breakCollector.environment;
- }
-
- void buildSimpleSwitch(JumpCollector join, List<SwitchCaseInfo> cases,
- SubbuildFunction buildDefaultBody) {
- IrBuilder casesBuilder = makeDelimitedBuilder();
- for (SwitchCaseInfo caseInfo in cases) {
- ir.Primitive condition = caseInfo.buildCondition(casesBuilder);
- IrBuilder thenBuilder = makeDelimitedBuilder();
- caseInfo.buildBody(thenBuilder);
- ir.Continuation thenContinuation = new ir.Continuation([]);
- thenContinuation.body = thenBuilder.root;
- ir.Continuation elseContinuation = new ir.Continuation([]);
- // A LetCont.two term has a hole as the body of the first listed
- // continuation, to be plugged by the translation. Therefore put the
- // else continuation first.
- casesBuilder.add(new ir.LetCont.two(
- elseContinuation,
- thenContinuation,
- new ir.Branch.strict(condition, thenContinuation, elseContinuation,
- caseInfo.sourceInformation)));
- }
-
- if (buildDefaultBody == null) {
- casesBuilder.jumpTo(join);
- } else {
- buildDefaultBody(casesBuilder);
- }
-
- if (!join.isEmpty) {
- add(new ir.LetCont(join.continuation, casesBuilder.root));
- environment = join.environment;
- } else if (casesBuilder.root != null) {
- add(casesBuilder.root);
- _current = casesBuilder._current;
- environment = casesBuilder.environment;
- } else {
- // The translation of the cases did not emit any code.
- }
- }
-
- /// Utility function to translate try/catch into the IR.
- ///
- /// The translation treats try/finally and try/catch/finally as if they
- /// were macro-expanded into try/catch. This utility function generates
- /// that try/catch. The function is parameterized over a list of variables
- /// that should be boxed on entry to the try, and over functions to emit
- /// code for entering the try, building the try body, leaving the try body,
- /// building the catch body, and leaving the entire try/catch.
- ///
- /// Please see the function's implementation for where these functions are
- /// called.
- void _helpBuildTryCatch(
- TryStatementInfo variables,
- void enterTry(IrBuilder builder),
- SubbuildFunction buildTryBlock,
- void leaveTry(IrBuilder builder),
- List<ir.Parameter> buildCatch(IrBuilder builder, JumpCollector join),
- void leaveTryCatch(
- IrBuilder builder, JumpCollector join, ir.Expression body)) {
- JumpCollector join = new ForwardJumpCollector(environment);
- IrBuilder tryCatchBuilder = makeDelimitedBuilder();
-
- // Variables treated as mutable in a try are not mutable outside of it.
- // Work with a copy of the outer builder's mutable variables.
- tryCatchBuilder.mutableVariables =
- new Map<Local, ir.MutableVariable>.from(mutableVariables);
- for (LocalVariableElement variable in variables.boxedOnEntry) {
- assert(!tryCatchBuilder.isInMutableVariable(variable));
- ir.Primitive value = tryCatchBuilder.buildLocalGet(variable);
- tryCatchBuilder.makeMutableVariable(variable);
- tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
- }
-
- IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
- enterTry(tryBuilder);
- buildTryBlock(tryBuilder);
- if (tryBuilder.isOpen) {
- join.enterTry(variables.boxedOnEntry);
- tryBuilder.jumpTo(join);
- join.leaveTry();
- }
- leaveTry(tryBuilder);
-
- IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
- for (LocalVariableElement variable in variables.boxedOnEntry) {
- assert(catchBuilder.isInMutableVariable(variable));
- ir.Primitive value = catchBuilder.buildLocalGet(variable);
- // After this point, the variables that were boxed on entry to the try
- // are no longer treated as mutable.
- catchBuilder.removeMutableVariable(variable);
- catchBuilder.environment.update(variable, value);
- }
-
- List<ir.Parameter> catchParameters = buildCatch(catchBuilder, join);
- ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
- catchContinuation.body = catchBuilder.root;
- tryCatchBuilder.add(new ir.LetHandler(catchContinuation, tryBuilder.root));
-
- leaveTryCatch(this, join, tryCatchBuilder.root);
- }
-
- /// Translates a try/catch.
- ///
- /// [variables] provides information on local variables declared and boxed
- /// within the try body.
- /// [buildTryBlock] builds the try block.
- /// [catchClauseInfos] provides access to the catch type, exception variable,
- /// and stack trace variable, and a function for building the catch block.
- void buildTryCatch(TryStatementInfo variables, SubbuildFunction buildTryBlock,
- List<CatchClauseInfo> catchClauseInfos) {
- assert(isOpen);
- // Catch handlers are in scope for their body. The CPS translation of
- // [[try tryBlock catch (ex, st) catchBlock; successor]] is:
- //
- // let cont join(v0, v1, ...) = [[successor]] in
- // let mutable m0 = x0 in
- // let mutable m1 = x1 in
- // ...
- // let handler catch_(ex, st) =
- // let prim p0 = GetMutable(m0) in
- // let prim p1 = GetMutable(m1) in
- // ...
- // [[catchBlock]]
- // join(p0, p1, ...)
- // in
- // [[tryBlock]]
- // let prim p0' = GetMutable(m0) in
- // let prim p1' = GetMutable(m1) in
- // ...
- // join(p0', p1', ...)
- //
- // In other words, both the try and catch block are in the scope of the
- // join-point continuation, and they are both in the scope of a sequence
- // of mutable bindings for the variables assigned in the try. The join-
- // point continuation is not in the scope of these mutable bindings.
- // The tryBlock is in the scope of a binding for the catch handler. Each
- // instruction (specifically, each call) in the tryBlock is in the dynamic
- // scope of the handler. The mutable bindings are dereferenced at the end
- // of the try block and at the beginning of the catch block, so the
- // variables are unboxed in the catch block and at the join point.
-
- void enterTry(IrBuilder builder) {
- // On entry to try of try/catch, update the builder's state to reflect the
- // variables that have been boxed.
- void interceptJump(JumpCollector collector) {
- collector.enterTry(variables.boxedOnEntry);
- }
- builder.state.breakCollectors.forEach(interceptJump);
- builder.state.continueCollectors.forEach(interceptJump);
- interceptJump(builder.state.returnCollector);
- }
-
- void leaveTry(IrBuilder builder) {
- // On exit from try of try/catch, update the builder's state to reflect
- // the variables that are no longer boxed.
- void restoreJump(JumpCollector collector) {
- collector.leaveTry();
- }
- builder.state.breakCollectors.forEach(restoreJump);
- builder.state.continueCollectors.forEach(restoreJump);
- restoreJump(builder.state.returnCollector);
- }
-
- List<ir.Parameter> buildCatch(IrBuilder builder, JumpCollector join) {
- // Translate the catch clauses. Multiple clauses are translated as if
- // they were explicitly cascaded if/else type tests.
-
- // Handlers are always translated as having both exception and stack trace
- // parameters. Multiple clauses do not have to use the same names for
- // them. Choose the first of each as the name hint for the respective
- // handler parameter.
- ir.Parameter exceptionParameter =
- new ir.Parameter(catchClauseInfos.first.exceptionVariable);
- LocalVariableElement traceVariable;
- CatchClauseInfo catchAll;
- for (int i = 0; i < catchClauseInfos.length; ++i) {
- CatchClauseInfo info = catchClauseInfos[i];
- if (info.type == null) {
- catchAll = info;
- catchClauseInfos.length = i;
- break;
- }
- if (traceVariable == null) {
- traceVariable = info.stackTraceVariable;
- }
- }
- ir.Parameter traceParameter = new ir.Parameter(traceVariable);
-
- ir.Expression buildCatchClause(CatchClauseInfo clause) {
- IrBuilder clauseBuilder = builder.makeDelimitedBuilder();
- if (clause.exceptionVariable != null) {
- clauseBuilder.declareLocalVariable(clause.exceptionVariable,
- initialValue: exceptionParameter);
- }
- if (clause.stackTraceVariable != null) {
- clauseBuilder.declareLocalVariable(clause.stackTraceVariable,
- initialValue: traceParameter);
- }
- clause.buildCatchBlock(clauseBuilder);
- if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join);
- return clauseBuilder.root;
- }
-
- // Expand multiple catch clauses into an explicit if/then/else. Iterate
- // them in reverse so the current block becomes the next else block.
- ir.Expression catchBody =
- (catchAll == null) ? new ir.Rethrow() : buildCatchClause(catchAll);
- for (CatchClauseInfo clause in catchClauseInfos.reversed) {
- ir.Continuation thenContinuation = new ir.Continuation([]);
- ir.Continuation elseContinuation = new ir.Continuation([]);
- thenContinuation.body = buildCatchClause(clause);
- elseContinuation.body = catchBody;
-
- // Build the type test guarding this clause. We can share the
- // environment with the nested builder because this part cannot mutate
- // it.
- IrBuilder checkBuilder = builder.makeDelimitedBuilder(environment);
- ir.Primitive typeMatches = checkBuilder.buildTypeOperator(
- exceptionParameter, clause.type, clause.sourceInformation,
- isTypeTest: true);
- checkBuilder.add(new ir.LetCont.two(
- thenContinuation,
- elseContinuation,
- new ir.Branch.strict(typeMatches, thenContinuation,
- elseContinuation, clause.sourceInformation)));
- catchBody = checkBuilder.root;
- }
- builder.add(catchBody);
-
- return <ir.Parameter>[exceptionParameter, traceParameter];
- }
-
- void leaveTryCatch(
- IrBuilder builder, JumpCollector join, ir.Expression body) {
- // Add the binding for the join-point continuation and continue the
- // translation in its body.
- builder.add(new ir.LetCont(join.continuation, body));
- builder.environment = join.environment;
- }
-
- _helpBuildTryCatch(variables, enterTry, buildTryBlock, leaveTry, buildCatch,
- leaveTryCatch);
- }
-
- /// Translates a try/finally.
- ///
- /// [variables] provides information on local variables declared and boxed
- /// within the try body.
- /// [buildTryBlock] builds the try block.
- /// [buildFinallyBlock] builds the finally block.
- void buildTryFinally(TryStatementInfo variables,
- SubbuildFunction buildTryBlock, SubbuildFunction buildFinallyBlock) {
- assert(isOpen);
- // Try/finally is implemented in terms of try/catch and by duplicating the
- // code for finally at all exits. The encoding is:
- //
- // try tryBlock finally finallyBlock
- // ==>
- // try tryBlock catch (ex, st) { finallyBlock; rethrow } finallyBlock
- //
- // Where in tryBlock, all of the break, continue, and return exits are
- // translated as jumps to continuations (bound outside the catch handler)
- // that include the finally code followed by a break, continue, or
- // return respectively.
-
- List<JumpCollector> savedBreaks, newBreaks, savedContinues, newContinues;
- JumpCollector savedReturn, newReturn;
- void enterTry(IrBuilder builder) {
- // On entry to the try of try/finally, update the builder's state to
- // relfect the variables that have been boxed. Then intercept all break,
- // continue, and return jumps out of the try so that they can go to
- // continuations that include the finally code.
- JumpCollector interceptJump(JumpCollector collector) {
- JumpCollector result =
- new ForwardJumpCollector(environment, target: collector.target);
- result.enterTry(variables.boxedOnEntry);
- return result;
- }
- savedBreaks = builder.state.breakCollectors;
- savedContinues = builder.state.continueCollectors;
- savedReturn = builder.state.returnCollector;
-
- builder.state.breakCollectors =
- newBreaks = savedBreaks.map(interceptJump).toList();
- builder.state.continueCollectors =
- newContinues = savedContinues.map(interceptJump).toList();
- builder.state.returnCollector = newReturn =
- new ForwardJumpCollector(environment, hasExtraArgument: true)
- ..enterTry(variables.boxedOnEntry);
- }
-
- void leaveTry(IrBuilder builder) {
- // On exit from the try of try/finally, update the builder's state to
- // reflect the variables that are no longer boxed and restore the
- // original, unintercepted break, continue, and return targets.
- void restoreJump(JumpCollector collector) {
- collector.leaveTry();
- }
- newBreaks.forEach(restoreJump);
- newContinues.forEach(restoreJump);
- newReturn.leaveTry();
- builder.state.breakCollectors = savedBreaks;
- builder.state.continueCollectors = savedContinues;
- builder.state.returnCollector = savedReturn;
- }
-
- List<ir.Parameter> buildCatch(IrBuilder builder, JumpCollector join) {
- // The catch block of the try/catch used for try/finally is the finally
- // code followed by a rethrow.
- buildFinallyBlock(builder);
- if (builder.isOpen) {
- builder.add(new ir.Rethrow());
- builder._current = null;
- }
- return <ir.Parameter>[new ir.Parameter(null), new ir.Parameter(null)];
- }
-
- void leaveTryCatch(
- IrBuilder builder, JumpCollector join, ir.Expression body) {
- // Build a list of continuations for jumps from the try block and
- // duplicate the finally code before jumping to the actual target.
- List<ir.Continuation> exits = <ir.Continuation>[join.continuation];
- void addJump(
- JumpCollector newCollector, JumpCollector originalCollector) {
- if (newCollector.isEmpty) return;
- IrBuilder builder = makeDelimitedBuilder(newCollector.environment);
- buildFinallyBlock(builder);
- if (builder.isOpen) builder.jumpTo(originalCollector);
- newCollector.continuation.body = builder.root;
- exits.add(newCollector.continuation);
- }
- for (int i = 0; i < newBreaks.length; ++i) {
- addJump(newBreaks[i], savedBreaks[i]);
- }
- for (int i = 0; i < newContinues.length; ++i) {
- addJump(newContinues[i], savedContinues[i]);
- }
- if (!newReturn.isEmpty) {
- IrBuilder builder = makeDelimitedBuilder(newReturn.environment);
- ir.Primitive value = builder.environment.discard(1);
- buildFinallyBlock(builder);
- if (builder.isOpen) builder.buildReturn(value: value);
- newReturn.continuation.body = builder.root;
- exits.add(newReturn.continuation);
- }
- builder.add(new ir.LetCont.many(exits, body));
- builder.environment = join.environment;
- buildFinallyBlock(builder);
- }
-
- _helpBuildTryCatch(variables, enterTry, buildTryBlock, leaveTry, buildCatch,
- leaveTryCatch);
- }
-
- /// Create a return statement `return value;` or `return;` if [value] is
- /// null.
- void buildReturn({ir.Primitive value, SourceInformation sourceInformation}) {
- // Build(Return(e), C) = C'[InvokeContinuation(return, x)]
- // where (C', x) = Build(e, C)
- //
- // Return without a subexpression is translated as if it were return null.
- assert(isOpen);
- if (value == null) {
- value = buildNullConstant();
- }
- jumpTo(state.returnCollector, value, sourceInformation);
- }
-
- /// Generate the body for a native function [function] that is annotated with
- /// an implementation in JavaScript (provided as string in [javaScriptCode]).
- void buildNativeFunctionBody(FunctionElement function, String javaScriptCode,
- SourceInformation sourceInformation) {
- NativeBehavior behavior = new NativeBehavior();
- behavior.sideEffects.setAllSideEffects();
- // Generate a [ForeignCode] statement from the given native code.
- buildForeignCode(
- js.js
- .statementTemplateYielding(new js.LiteralStatement(javaScriptCode)),
- <ir.Primitive>[],
- behavior,
- sourceInformation);
- }
-
- /// Generate the body for a native function that redirects to a native
- /// JavaScript function, getter, or setter.
- ///
- /// Generates a call to the real target, which is given by [functions]'s
- /// `fixedBackendName`, passing all parameters as arguments. The target can
- /// be the JavaScript implementation of a function, getter, or setter.
- void buildRedirectingNativeFunctionBody(FunctionElement function, String name,
- SourceInformation sourceInformation) {
- List<ir.Primitive> arguments = <ir.Primitive>[];
- NativeBehavior behavior = new NativeBehavior();
- behavior.sideEffects.setAllSideEffects();
- program.addNativeMethod(function);
- // Construct the access of the target element.
- String code = function.isInstanceMember ? '#.$name' : name;
- if (function.isInstanceMember) {
- arguments.add(state.thisParameter);
- }
- // Collect all parameters of the function and templates for them to be
- // inserted into the JavaScript code.
- List<String> argumentTemplates = <String>[];
- function.functionSignature.forEachParameter((ParameterElement parameter) {
- ir.Primitive input = environment.lookup(parameter);
- DartType type = program.unaliasType(parameter.type);
- if (type is FunctionType) {
- // The parameter type is a function type either directly or through
- // typedef(s).
- ir.Constant arity = buildIntegerConstant(type.computeArity());
- input = buildStaticFunctionInvocation(program.closureConverter,
- <ir.Primitive>[input, arity], sourceInformation);
- }
- arguments.add(input);
- argumentTemplates.add('#');
- });
- // Construct the application of parameters for functions and setters.
- if (function.kind == ElementKind.FUNCTION) {
- code = "$code(${argumentTemplates.join(', ')})";
- } else if (function.kind == ElementKind.SETTER) {
- code = "$code = ${argumentTemplates.single}";
- } else {
- assert(argumentTemplates.isEmpty);
- assert(function.kind == ElementKind.GETTER);
- }
- // Generate the [ForeignCode] expression and a return statement to return
- // its value.
- ir.Primitive value = buildForeignCode(
- js.js.uncachedExpressionTemplate(code),
- arguments,
- behavior,
- sourceInformation,
- type: program.getTypeMaskForNativeFunction(function));
- buildReturn(value: value, sourceInformation: sourceInformation);
- }
-
- static _isNotNull(ir.Primitive value) =>
- !(value is ir.Constant && value.value.isNull);
-
- /// Builds a call to a resolved js-interop element.
- ir.Primitive buildInvokeJsInteropMember(FunctionElement element,
- List<ir.Primitive> arguments, SourceInformation sourceInformation) {
- program.addNativeMethod(element);
- String target = program.getJsInteropTargetPath(element);
- // Strip off trailing arguments that were not specified.
- // TODO(jacobr,sigmund): assert that the trailing arguments are all null.
- // TODO(jacobr): rewrite named arguments to an object literal matching
- // the factory constructor case.
- var inputs = arguments.where(_isNotNull).toList();
-
- var behavior = new NativeBehavior()..sideEffects.setAllSideEffects();
- DartType type = element.isConstructor
- ? element.enclosingClass.thisType
- : element.type.returnType;
- // Native behavior effects here are similar to native/behavior.dart.
- // The return type is dynamic if we don't trust js-interop type
- // declarations.
- behavior.typesReturned.add(
- program.trustJSInteropTypeAnnotations ? type : const DynamicType());
-
- // The allocation effects include the declared type if it is native (which
- // includes js interop types).
- if (type.element != null && program.isNative(type.element)) {
- behavior.typesInstantiated.add(type);
- }
-
- // It also includes any other JS interop type if we don't trust the
- // annotation or if is declared too broad.
- if (!program.trustJSInteropTypeAnnotations ||
- type.isObject ||
- type.isDynamic) {
- behavior.typesInstantiated.add(program.jsJavascriptObjectType);
- }
-
- String code;
- if (element.isGetter) {
- code = target;
- } else if (element.isSetter) {
- code = "$target = #";
- } else {
- var args = new List.filled(inputs.length, '#').join(',');
- code = element.isConstructor ? "new $target($args)" : "$target($args)";
- }
- return buildForeignCode(
- js.js.parseForeignJS(code), inputs, behavior, sourceInformation);
- // TODO(sigmund): should we record the source-information here?
- }
-
- /// Builds an object literal that results from invoking a factory constructor
- /// of a js-interop anonymous type.
- ir.Primitive buildJsInteropObjectLiteral(ConstructorElement constructor,
- List<ir.Primitive> arguments, SourceInformation sourceInformation) {
- assert(program.isJsInteropAnonymous(constructor));
- program.addNativeMethod(constructor);
- FunctionSignature params = constructor.functionSignature;
- int i = 0;
- var filteredArguments = <ir.Primitive>[];
- var entries = new Map<String, js.Expression>();
- params.orderedForEachParameter((ParameterElement parameter) {
- // TODO(jacobr): throw if parameter names do not match names of property
- // names in the class.
- assert(parameter.isNamed);
- ir.Primitive argument = arguments[i++];
- if (_isNotNull(argument)) {
- filteredArguments.add(argument);
- entries[parameter.name] =
- new js.InterpolatedExpression(filteredArguments.length - 1);
- }
- });
- var code = new js.Template(null, js.objectLiteral(entries));
- var behavior = new NativeBehavior();
- if (program.trustJSInteropTypeAnnotations) {
- behavior.typesReturned.add(constructor.enclosingClass.thisType);
- }
-
- return buildForeignCode(
- code, filteredArguments, behavior, sourceInformation);
- }
-
- /// Create a blocks of [statements] by applying [build] to all reachable
- /// statements. The first statement is assumed to be reachable.
- // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses
- // `List` instead of `Link`.
- void buildBlock(var statements, BuildFunction build) {
- // Build(Block(stamements), C) = C'
- // where C' = statements.fold(Build, C)
- assert(isOpen);
- return buildSequence(statements, build);
- }
-
- /// Creates a sequence of [nodes] by applying [build] to all reachable nodes.
- ///
- /// The first node in the sequence does not need to be reachable.
- // TODO(johnniwinther): Type [nodes] as `Iterable` when `NodeList` uses
- // `List` instead of `Link`.
- void buildSequence(var nodes, BuildFunction build) {
- for (var node in nodes) {
- if (!isOpen) return;
- build(node);
- }
- }
-
- /// Creates a labeled statement
- void buildLabeledStatement({SubbuildFunction buildBody, JumpTarget target}) {
- JumpCollector join = new ForwardJumpCollector(environment, target: target);
- IrBuilder innerBuilder = makeDelimitedBuilder();
- innerBuilder.state.breakCollectors.add(join);
- buildBody(innerBuilder);
- innerBuilder.state.breakCollectors.removeLast();
- bool hasBreaks = !join.isEmpty;
- if (hasBreaks) {
- if (innerBuilder.isOpen) innerBuilder.jumpTo(join);
- add(new ir.LetCont(join.continuation, innerBuilder.root));
- environment = join.environment;
- } else if (innerBuilder.root != null) {
- add(innerBuilder.root);
- _current = innerBuilder._current;
- environment = innerBuilder.environment;
- } else {
- // The translation of the body did not emit any CPS term.
- }
- }
-
- // Build(BreakStatement L, C) = C[InvokeContinuation(...)]
- //
- // The continuation and arguments are filled in later after translating
- // the body containing the break.
- bool buildBreak(JumpTarget target) {
- return buildJumpInternal(target, state.breakCollectors);
- }
-
- // Build(ContinueStatement L, C) = C[InvokeContinuation(...)]
- //
- // The continuation and arguments are filled in later after translating
- // the body containing the continue.
- bool buildContinue(JumpTarget target) {
- return buildJumpInternal(target, state.continueCollectors);
- }
-
- bool buildJumpInternal(
- JumpTarget target, Iterable<JumpCollector> collectors) {
- assert(isOpen);
- for (JumpCollector collector in collectors) {
- if (target == collector.target) {
- jumpTo(collector);
- return true;
- }
- }
- return false;
- }
-
- void buildThrow(ir.Primitive value) {
- assert(isOpen);
- add(new ir.Throw(value));
- _current = null;
- }
-
- ir.Primitive buildNonTailThrow(ir.Primitive value) {
- assert(isOpen);
- ir.Parameter param = new ir.Parameter(null);
- ir.Continuation cont = new ir.Continuation(<ir.Parameter>[param]);
- add(new ir.LetCont(cont, new ir.Throw(value)));
- return param;
- }
-
- void buildRethrow() {
- assert(isOpen);
- add(new ir.Rethrow());
- _current = null;
- }
-
- /// Create a negation of [condition].
- ir.Primitive buildNegation(
- ir.Primitive condition, SourceInformation sourceInformation) {
- // ! e is translated as e ? false : true
-
- // Add a continuation parameter for the result of the expression.
- ir.Parameter resultParameter = new ir.Parameter(null);
-
- ir.Continuation joinContinuation = new ir.Continuation([resultParameter]);
- ir.Continuation thenContinuation = new ir.Continuation([]);
- ir.Continuation elseContinuation = new ir.Continuation([]);
-
- ir.Constant makeBoolConstant(bool value) {
- return new ir.Constant(state.constantSystem.createBool(value));
- }
-
- ir.Constant trueConstant = makeBoolConstant(true);
- ir.Constant falseConstant = makeBoolConstant(false);
-
- thenContinuation.body = new ir.LetPrim(falseConstant)
- ..plug(new ir.InvokeContinuation(joinContinuation, [falseConstant]));
- elseContinuation.body = new ir.LetPrim(trueConstant)
- ..plug(new ir.InvokeContinuation(joinContinuation, [trueConstant]));
-
- add(new ir.LetCont(
- joinContinuation,
- new ir.LetCont.two(
- thenContinuation,
- elseContinuation,
- new ir.Branch.strict(condition, thenContinuation, elseContinuation,
- sourceInformation))));
- return resultParameter;
- }
-
- /// Create a lazy and/or expression. [leftValue] is the value of the left
- /// operand and [buildRightValue] is called to process the value of the right
- /// operand in the context of its own [IrBuilder].
- ir.Primitive buildLogicalOperator(
- ir.Primitive leftValue,
- ir.Primitive buildRightValue(IrBuilder builder),
- SourceInformation sourceInformation,
- {bool isLazyOr: false}) {
- // e0 && e1 is translated as if e0 ? (e1 == true) : false.
- // e0 || e1 is translated as if e0 ? true : (e1 == true).
- // The translation must convert both e0 and e1 to booleans and handle
- // local variable assignments in e1.
- IrBuilder rightBuilder = makeDelimitedBuilder();
- ir.Primitive rightValue = buildRightValue(rightBuilder);
- // A dummy empty target for the branch on the left subexpression branch.
- // This enables using the same infrastructure for join-point continuations
- // as in visitIf and visitConditional. It will hold a definition of the
- // appropriate constant and an invocation of the join-point continuation.
- IrBuilder emptyBuilder = makeDelimitedBuilder();
- // Dummy empty targets for right true and right false. They hold
- // definitions of the appropriate constant and an invocation of the
- // join-point continuation.
- IrBuilder rightTrueBuilder = rightBuilder.makeDelimitedBuilder();
- IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder();
-
- // If we don't evaluate the right subexpression, the value of the whole
- // expression is this constant.
- ir.Constant leftBool = emptyBuilder.buildBooleanConstant(isLazyOr);
- // If we do evaluate the right subexpression, the value of the expression
- // is a true or false constant.
- ir.Constant rightTrue = rightTrueBuilder.buildBooleanConstant(true);
- ir.Constant rightFalse = rightFalseBuilder.buildBooleanConstant(false);
-
- // Result values are passed as continuation arguments, which are
- // constructed based on environments. These assertions are a sanity check.
- assert(environment.length == emptyBuilder.environment.length);
- assert(environment.length == rightTrueBuilder.environment.length);
- assert(environment.length == rightFalseBuilder.environment.length);
-
- // Wire up two continuations for the left subexpression, two continuations
- // for the right subexpression, and a three-way join continuation.
- JumpCollector join =
- new ForwardJumpCollector(environment, hasExtraArgument: true);
- emptyBuilder.jumpTo(join, leftBool);
- rightTrueBuilder.jumpTo(join, rightTrue);
- rightFalseBuilder.jumpTo(join, rightFalse);
- ir.Continuation leftTrueContinuation = new ir.Continuation([]);
- ir.Continuation leftFalseContinuation = new ir.Continuation([]);
- ir.Continuation rightTrueContinuation = new ir.Continuation([]);
- ir.Continuation rightFalseContinuation = new ir.Continuation([]);
- rightTrueContinuation.body = rightTrueBuilder.root;
- rightFalseContinuation.body = rightFalseBuilder.root;
- // The right subexpression has two continuations.
- rightBuilder.add(new ir.LetCont.two(
- rightTrueContinuation,
- rightFalseContinuation,
- new ir.Branch.strict(rightValue, rightTrueContinuation,
- rightFalseContinuation, sourceInformation)));
- // Depending on the operator, the left subexpression's continuations are
- // either the right subexpression or an invocation of the join-point
- // continuation.
- if (isLazyOr) {
- leftTrueContinuation.body = emptyBuilder.root;
- leftFalseContinuation.body = rightBuilder.root;
- } else {
- leftTrueContinuation.body = rightBuilder.root;
- leftFalseContinuation.body = emptyBuilder.root;
- }
-
- add(new ir.LetCont(
- join.continuation,
- new ir.LetCont.two(
- leftTrueContinuation,
- leftFalseContinuation,
- new ir.Branch.strict(leftValue, leftTrueContinuation,
- leftFalseContinuation, sourceInformation))));
- environment = join.environment;
- return environment.discard(1);
- }
-
- ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y,
- {SourceInformation sourceInformation}) {
- return addPrimitive(new ir.ApplyBuiltinOperator(
- ir.BuiltinOperator.Identical, <ir.Primitive>[x, y], sourceInformation));
- }
-
- /// Called when entering a nested function with free variables.
- ///
- /// The free variables must subsequently be accessible using [buildLocalGet]
- /// and [buildLocalSet].
- void _enterClosureEnvironment(ClosureEnvironment env) {
- if (env == null) return;
-
- // Obtain a reference to the function object (this).
- ir.Parameter thisPrim = state.thisParameter;
-
- // Obtain access to the free variables.
- env.freeVariables.forEach((Local local, ClosureLocation location) {
- if (location.isBox) {
- // Boxed variables are loaded from their box on-demand.
- state.boxedVariables[local] = location;
- } else {
- // Unboxed variables are loaded from the function object immediately.
- // This includes BoxLocals which are themselves unboxed variables.
- environment.extend(
- local, addPrimitive(new ir.GetField(thisPrim, location.field)));
- }
- });
-
- // If the function captures a reference to the receiver from the
- // enclosing method, remember which primitive refers to the receiver object.
- if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) {
- state.enclosingThis = environment.lookup(env.thisLocal);
- }
-
- // If the function has a self-reference, use the value of `this`.
- if (env.selfReference != null) {
- environment.extend(env.selfReference, thisPrim);
- }
- }
-
- /// Creates a box for [scope.box] and binds the captured variables to
- /// that box.
- ///
- /// The captured variables can subsequently be manipulated with
- /// [declareLocalVariable], [buildLocalGet], and [buildLocalSet].
- void enterScope(ClosureScope scope) => _enterScope(scope);
-
- /// Called when entering a function body or loop body.
- ///
- /// This is not called for for-loops, which instead use the methods
- /// [_enterForLoopInitializer], [_enterForLoopBody], and [_enterForLoopUpdate]
- /// due to their special scoping rules.
- ///
- /// The boxed variables declared in this scope must subsequently be available
- /// using [buildLocalGet], [buildLocalSet], etc.
- void _enterScope(ClosureScope scope) {
- if (scope == null) return;
- ir.CreateBox boxPrim = addPrimitive(new ir.CreateBox());
- environment.extend(scope.box, boxPrim);
- boxPrim.useElementAsHint(scope.box);
- scope.capturedVariables.forEach((Local local, ClosureLocation location) {
- assert(!state.boxedVariables.containsKey(local));
- if (location.isBox) {
- state.boxedVariables[local] = location;
- }
- });
- }
-
- /// Add the given function parameter to the IR, and bind it in the environment
- /// or put it in its box, if necessary.
- void _createFunctionParameter(Local parameterElement) {
- ir.Parameter parameter = new ir.Parameter(parameterElement);
- _parameters.add(parameter);
- state.functionParameters.add(parameter);
- ClosureLocation location = state.boxedVariables[parameterElement];
- if (location != null) {
- addPrimitive(new ir.SetField(
- environment.lookup(location.box), location.field, parameter));
- } else {
- environment.extend(parameterElement, parameter);
- }
- }
-
- void _createThisParameter() {
- assert(state.thisParameter == null);
- if (Elements.isStaticOrTopLevel(state.currentElement)) return;
- if (state.currentElement.isLocal) return;
- state.thisParameter =
- new ir.Parameter(new ThisParameterLocal(state.currentElement));
- }
-
- void declareLocalVariable(LocalElement variableElement,
- {ir.Primitive initialValue}) {
- assert(isOpen);
- if (initialValue == null) {
- initialValue = buildNullConstant();
- }
- ClosureLocation location = state.boxedVariables[variableElement];
- if (location != null) {
- addPrimitive(new ir.SetField(
- environment.lookup(location.box), location.field, initialValue));
- } else if (isInMutableVariable(variableElement)) {
- add(new ir.LetMutable(getMutableVariable(variableElement), initialValue));
- } else {
- initialValue.useElementAsHint(variableElement);
- environment.extend(variableElement, initialValue);
- }
- }
-
- /// Add [functionElement] to the environment with provided [definition].
- void declareLocalFunction(
- LocalFunctionElement functionElement,
- closure.ClosureClassElement classElement,
- SourceInformation sourceInformation) {
- ir.Primitive closure =
- buildFunctionExpression(classElement, sourceInformation);
- declareLocalVariable(functionElement, initialValue: closure);
- }
-
- ir.Primitive buildFunctionExpression(closure.ClosureClassElement classElement,
- SourceInformation sourceInformation) {
- List<ir.Primitive> arguments = <ir.Primitive>[];
- for (closure.ClosureFieldElement field in classElement.closureFields) {
- // Captured 'this' and type variables are not always available as locals
- // in the environment, so treat those specially.
- ir.Primitive value;
- if (field.local is closure.ThisLocal) {
- value = buildThis();
- } else if (field.local is closure.TypeVariableLocal) {
- closure.TypeVariableLocal variable = field.local;
- value = buildTypeVariableAccess(variable.typeVariable);
- } else {
- value = environment.lookup(field.local);
- }
- arguments.add(value);
- }
- return addPrimitive(new ir.CreateInstance(
- classElement, arguments, null, sourceInformation));
- }
-
- /// Create a read access of [local] function, variable, or parameter.
- // TODO(johnniwinther): Make [sourceInformation] mandatory.
- ir.Primitive buildLocalGet(LocalElement local,
- {SourceInformation sourceInformation}) {
- assert(isOpen);
- ClosureLocation location = state.boxedVariables[local];
- if (location != null) {
- ir.Primitive result = new ir.GetField(
- environment.lookup(location.box), location.field,
- sourceInformation: sourceInformation);
- result.useElementAsHint(local);
- return addPrimitive(result);
- } else if (isInMutableVariable(local)) {
- return addPrimitive(new ir.GetMutable(getMutableVariable(local),
- sourceInformation: sourceInformation));
- } else {
- return environment.lookup(local);
- }
- }
-
- /// Create a write access to [local] variable or parameter with the provided
- /// [value].
- ir.Primitive buildLocalVariableSet(LocalElement local, ir.Primitive value,
- SourceInformation sourceInformation) {
- assert(isOpen);
- ClosureLocation location = state.boxedVariables[local];
- if (location != null) {
- addPrimitive(new ir.SetField(
- environment.lookup(location.box), location.field, value,
- sourceInformation: sourceInformation));
- } else if (isInMutableVariable(local)) {
- addPrimitive(new ir.SetMutable(getMutableVariable(local), value,
- sourceInformation: sourceInformation));
- } else {
- value.useElementAsHint(local);
- environment.update(local, value);
- }
- return value;
- }
-
- /// Called before building the initializer of a for-loop.
- ///
- /// The loop variables will subsequently be declared using
- /// [declareLocalVariable].
- void _enterForLoopInitializer(
- ClosureScope scope, List<LocalElement> loopVariables) {
- if (scope == null) return;
- // If there are no boxed loop variables, don't create the box here, let
- // it be created inside the body instead.
- if (scope.boxedLoopVariables.isEmpty) return;
- _enterScope(scope);
- }
-
- /// Called before building the body of a for-loop.
- void _enterForLoopBody(ClosureScope scope, List<LocalElement> loopVariables) {
- if (scope == null) return;
- // If there are boxed loop variables, the box has already been created
- // at the initializer.
- if (!scope.boxedLoopVariables.isEmpty) return;
- _enterScope(scope);
- }
-
- /// Called before building the update of a for-loop.
- void _enterForLoopUpdate(
- ClosureScope scope, List<LocalElement> loopVariables) {
- if (scope == null) return;
- // If there are no boxed loop variables, then the box is created inside the
- // body, so there is no need to explicitly renew it.
- if (scope.boxedLoopVariables.isEmpty) return;
- ir.Primitive box = environment.lookup(scope.box);
- ir.Primitive newBox = addPrimitive(new ir.CreateBox());
- newBox.useElementAsHint(scope.box);
- for (VariableElement loopVar in scope.boxedLoopVariables) {
- ClosureLocation location = scope.capturedVariables[loopVar];
- ir.Primitive value = addPrimitive(new ir.GetField(box, location.field));
- addPrimitive(new ir.SetField(newBox, location.field, value));
- }
- environment.update(scope.box, newBox);
- }
-
- /// Creates an access to the receiver from the current (or enclosing) method.
- ///
- /// If inside a closure class, [buildThis] will redirect access through
- /// closure fields in order to access the receiver from the enclosing method.
- ir.Primitive buildThis() {
- if (state.enclosingThis != null) return state.enclosingThis;
- assert(state.thisParameter != null);
- return state.thisParameter;
- }
-
- ir.Primitive buildFieldGet(ir.Primitive receiver, FieldElement target,
- SourceInformation sourceInformation) {
- return addPrimitive(new ir.GetField(receiver, target,
- sourceInformation: sourceInformation,
- isFinal: program.fieldNeverChanges(target)));
- }
-
- void buildFieldSet(ir.Primitive receiver, FieldElement target,
- ir.Primitive value, SourceInformation sourceInformation) {
- addPrimitive(new ir.SetField(receiver, target, value,
- sourceInformation: sourceInformation));
- }
-
- ir.Primitive buildSuperFieldGet(
- FieldElement target, SourceInformation sourceInformation) {
- return addPrimitive(new ir.GetField(buildThis(), target,
- sourceInformation: sourceInformation));
- }
-
- ir.Primitive buildSuperFieldSet(FieldElement target, ir.Primitive value,
- SourceInformation sourceInformation) {
- addPrimitive(new ir.SetField(buildThis(), target, value,
- sourceInformation: sourceInformation));
- return value;
- }
-
- /// Loads parameters to a constructor body into the environment.
- ///
- /// The header for a constructor body differs from other functions in that
- /// some parameters are already boxed, and the box is passed as an argument
- /// instead of being created in the header.
- void buildConstructorBodyHeader(
- Iterable<Local> parameters, ClosureScope closureScope) {
- _createThisParameter();
- for (Local param in parameters) {
- ir.Parameter parameter = _createLocalParameter(param);
- state.functionParameters.add(parameter);
- }
- if (closureScope != null) {
- state.boxedVariables.addAll(closureScope.capturedVariables);
- }
- }
-
- /// Create a constructor invocation of [element] on [type] where the
- /// constructor name and argument structure are defined by [callStructure] and
- /// the argument values are defined by [arguments].
- ir.Primitive buildConstructorInvocation(
- ConstructorElement element,
- CallStructure callStructure,
- DartType type,
- List<ir.Primitive> arguments,
- SourceInformation sourceInformation,
- {TypeMask allocationSiteType}) {
- assert(isOpen);
- Selector selector =
- new Selector(SelectorKind.CALL, element.memberName, callStructure);
- ClassElement cls = element.enclosingClass;
- if (program.isJsInterop(element)) {
- if (program.isJsInteropAnonymous(element)) {
- return buildJsInteropObjectLiteral(
- element, arguments, sourceInformation);
- }
- return buildInvokeJsInteropMember(element, arguments, sourceInformation);
- }
- if (program.requiresRuntimeTypesFor(cls)) {
- InterfaceType interface = type;
- Iterable<ir.Primitive> typeArguments =
- interface.typeArguments.map((DartType argument) {
- return type.treatAsRaw
- ? buildNullConstant()
- : buildTypeExpression(argument);
- });
- arguments = new List<ir.Primitive>.from(arguments)..addAll(typeArguments);
- }
- return addPrimitive(new ir.InvokeConstructor(
- type, element, selector, arguments, sourceInformation,
- allocationSiteType: allocationSiteType));
- }
-
- ir.Primitive buildTypeExpression(DartType type) {
- type = program.unaliasType(type);
- if (type is TypeVariableType) {
- return buildTypeVariableAccess(type);
- } else if (type is InterfaceType || type is FunctionType) {
- List<ir.Primitive> arguments = <ir.Primitive>[];
- type.forEachTypeVariable((TypeVariableType variable) {
- ir.Primitive value = buildTypeVariableAccess(variable);
- arguments.add(value);
- });
- return addPrimitive(new ir.TypeExpression(
- ir.TypeExpressionKind.COMPLETE, type, arguments));
- } else if (type.treatAsDynamic) {
- return buildNullConstant();
- } else {
- // TypedefType can reach here, and possibly other things.
- throw 'unimplemented translation of type expression $type (${type.kind})';
- }
- }
-
- /// Obtains the internal type representation of the type held in [variable].
- ///
- /// The value of [variable] is taken from the current receiver object, or
- /// if we are currently building a constructor field initializer, from the
- /// corresponding type argument (field initializers are evaluated before the
- /// receiver object is created).
- ir.Primitive buildTypeVariableAccess(TypeVariableType variable,
- {SourceInformation sourceInformation}) {
- // If the local exists in the environment, use that.
- // This is put here when we are inside a constructor or field initializer,
- // (or possibly a closure inside one of these).
- Local local = new closure.TypeVariableLocal(variable, state.currentElement);
- if (environment.contains(local)) {
- return environment.lookup(local);
- }
-
- // If the type variable is not in a local, read its value from the
- // receiver object.
- ir.Primitive target = buildThis();
- return addPrimitive(
- new ir.ReadTypeVariable(variable, target, sourceInformation));
- }
-
- /// Make the given type variable accessible through the local environment
- /// with the value of [binding].
- void declareTypeVariable(TypeVariableType variable, DartType binding) {
- environment.extend(
- new closure.TypeVariableLocal(variable, state.currentElement),
- buildTypeExpression(binding));
- }
-
- /// Reifies the value of [variable] on the current receiver object.
- ir.Primitive buildReifyTypeVariable(
- TypeVariableType variable, SourceInformation sourceInformation) {
- ir.Primitive typeArgument =
- buildTypeVariableAccess(variable, sourceInformation: sourceInformation);
- return addPrimitive(
- new ir.ReifyRuntimeType(typeArgument, sourceInformation));
- }
-
- ir.Primitive buildInvocationMirror(
- Selector selector, List<ir.Primitive> arguments) {
- return addPrimitive(new ir.CreateInvocationMirror(selector, arguments));
- }
-
- ir.Primitive buildForeignCode(
- js.Template codeTemplate,
- List<ir.Primitive> arguments,
- NativeBehavior behavior,
- SourceInformation sourceInformation,
- {Element dependency,
- TypeMask type}) {
- assert(behavior != null);
- if (type == null) {
- type = program.getTypeMaskForForeign(behavior);
- }
- if (js.isIdentityTemplate(codeTemplate) && !program.isArrayType(type)) {
- // JS expression is just a refinement.
- // Do not do this for arrays - those are special because array types can
- // change after creation. The input and output must therefore be modeled
- // as distinct values.
- return addPrimitive(new ir.Refinement(arguments.single, type));
- }
- ir.Primitive result = addPrimitive(new ir.ForeignCode(
- codeTemplate, type, arguments, behavior, sourceInformation,
- dependency: dependency));
- if (!codeTemplate.isExpression) {
- // Close the term if this is a "throw" expression or native body.
- add(new ir.Unreachable());
- _current = null;
- }
- return result;
- }
-
- /// Creates a type test or type cast of [value] against [type].
- ir.Primitive buildTypeOperator(
- ir.Primitive value, DartType type, SourceInformation sourceInformation,
- {bool isTypeTest}) {
- assert(isOpen);
- assert(isTypeTest != null);
-
- type = program.unaliasType(type);
-
- if (type.isMalformed) {
- String message;
- if (type is MalformedType) {
- ErroneousElement element = type.element;
- message = element.message;
- } else {
- assert(type is MethodTypeVariableType);
- message = "Method type variables are not reified, "
- "so they cannot be tested dynamically";
- }
- ir.Primitive irMessage = buildStringConstant(message);
- return buildStaticFunctionInvocation(program.throwTypeErrorHelper,
- <ir.Primitive>[irMessage], sourceInformation);
- }
-
- List<ir.Primitive> typeArguments = const <ir.Primitive>[];
- if (type is GenericType && type.typeArguments.isNotEmpty) {
- typeArguments = type.typeArguments.map(buildTypeExpression).toList();
- } else if (type is TypeVariableType) {
- typeArguments = <ir.Primitive>[buildTypeVariableAccess(type)];
- } else if (type is FunctionType) {
- typeArguments = <ir.Primitive>[buildTypeExpression(type)];
- }
-
- if (isTypeTest) {
- // For type tests, we must treat specially the rare cases where `null`
- // satisfies the test (which otherwise never satisfies a type test).
- // This is not an optimization: the TypeOperator assumes that `null`
- // cannot satisfy the type test unless the type is a type variable.
- if (type.isObject || type.isDynamic) {
- // `x is Object` and `x is dynamic` are always true, even if x is null.
- return buildBooleanConstant(true);
- }
- if (type is InterfaceType && type.element == program.nullClass) {
- // `x is Null` is true if and only if x is null.
- return _buildCheckNull(value, sourceInformation);
- }
- return addPrimitive(new ir.TypeTest(value, type, typeArguments));
- } else {
- if (type.isObject || type.isDynamic) {
- // `x as Object` and `x as dynamic` are the same as `x`.
- return value;
- }
- return addPrimitive(new ir.TypeCast(value, type, typeArguments));
- }
- }
-
- /// Create an if-null expression. This is equivalent to a conditional
- /// expression whose result is either [value] if [value] is not null, or
- /// `right` if [value] is null. Only when [value] is null, [buildRight] is
- /// evaluated to produce the `right` value.
- ir.Primitive buildIfNull(
- ir.Primitive value,
- ir.Primitive buildRight(IrBuilder builder),
- SourceInformation sourceInformation) {
- ir.Primitive condition = _buildCheckNull(value, sourceInformation);
- return buildConditional(
- condition, buildRight, (_) => value, sourceInformation);
- }
-
- /// Create a conditional send. This is equivalent to a conditional expression
- /// that checks if [receiver] is null, if so, it returns null, otherwise it
- /// evaluates the [buildSend] expression.
- ir.Primitive buildIfNotNullSend(
- ir.Primitive receiver,
- ir.Primitive buildSend(IrBuilder builder),
- SourceInformation sourceInformation) {
- ir.Primitive condition = _buildCheckNull(receiver, sourceInformation);
- return buildConditional(
- condition, (_) => receiver, buildSend, sourceInformation);
- }
-
- /// Creates a type test checking whether [value] is null.
- ir.Primitive _buildCheckNull(
- ir.Primitive value, SourceInformation sourceInformation) {
- assert(isOpen);
- return buildIdentical(value, buildNullConstant(),
- sourceInformation: sourceInformation);
- }
-}
-
-/// Location of a variable relative to a given closure.
-class ClosureLocation {
- /// If not `null`, this location is [box].[field].
- /// The location of [box] can be obtained separately from an
- /// enclosing [ClosureEnvironment] or [ClosureScope].
- /// If `null`, then the location is [field] on the enclosing function object.
- final closure.BoxLocal box;
-
- /// The field in which the variable is stored.
- final Entity field;
-
- bool get isBox => box != null;
-
- ClosureLocation(this.box, this.field);
-
- /// Converts a map containing closure.dart's [CapturedVariable]s into one
- /// containing [ClosureLocation]s.
- ///
- /// There is a 1:1 corresponce between these; we do this because the
- /// IR builder should not depend on synthetic elements.
- static Map<Local, ClosureLocation> mapFrom(
- Map<Local, closure.CapturedVariable> map) {
- Map result = {};
- map.forEach((Local k, closure.CapturedVariable v) {
- closure.BoxLocal box = v is closure.BoxFieldElement ? v.box : null;
- result[k] = new ClosureLocation(box, v);
- });
- return result;
- }
-}
-
-/// Introduces a new box and binds local variables to this box.
-///
-/// A [ClosureScope] may exist for each function and for each loop.
-/// Generally, one may pass `null` to the [IrBuilder] instead of a
-/// [ClosureScope] when a given scope has no boxed variables.
-class ClosureScope {
- /// This box is now in scope and [capturedVariables] may use it.
- final closure.BoxLocal box;
-
- /// Maps [LocalElement]s to their location.
- final Map<Local, ClosureLocation> capturedVariables;
-
- /// If this is the scope of a for-loop, [boxedLoopVariables] is the list
- /// of boxed variables that are declared in the initializer.
- final List<VariableElement> boxedLoopVariables;
-
- factory ClosureScope(closure.ClosureScope scope) {
- return scope == null ? null : new ClosureScope._internal(scope);
- }
-
- ClosureScope._internal(closure.ClosureScope scope)
- : box = scope.boxElement,
- capturedVariables = ClosureLocation.mapFrom(scope.capturedVariables),
- boxedLoopVariables = scope.boxedLoopVariables;
-}
-
-/// Environment passed when building a nested function, describing how
-/// to access variables from the enclosing scope.
-class ClosureEnvironment {
- /// References to this local should be treated as recursive self-reference.
- /// (This is *not* in [freeVariables]).
- final LocalFunctionElement selfReference;
-
- /// If non-null, [thisLocal] has an entry in [freeVariables] describing where
- /// to find the captured value of `this`.
- final closure.ThisLocal thisLocal;
-
- /// Maps [LocalElement]s, [BoxLocal]s and [ThisLocal] to their location.
- final Map<Local, ClosureLocation> freeVariables;
-
- factory ClosureEnvironment(closure.ClosureClassMap closureClassMap) {
- if (closureClassMap.closureElement == null) return null;
- return new ClosureEnvironment._internal(closureClassMap);
- }
-
- ClosureEnvironment._internal(closure.ClosureClassMap closureClassMap)
- : selfReference = closureClassMap.closureElement,
- thisLocal = closureClassMap.thisLocal,
- freeVariables =
- ClosureLocation.mapFrom(closureClassMap.freeVariableMap);
-}
-
-class TryStatementInfo {
- final Set<LocalVariableElement> declared = new Set<LocalVariableElement>();
- final Set<LocalVariableElement> boxedOnEntry =
- new Set<LocalVariableElement>();
-}
-
-class CatchClauseInfo {
- final DartType type;
- final LocalVariableElement exceptionVariable;
- final LocalVariableElement stackTraceVariable;
- final SubbuildFunction buildCatchBlock;
- final SourceInformation sourceInformation;
-
- CatchClauseInfo(
- {this.type,
- this.exceptionVariable,
- this.stackTraceVariable,
- this.buildCatchBlock,
- this.sourceInformation});
-}
-
-class SwitchCaseInfo {
- final SubbuildFunction buildCondition;
- final SubbuildFunction buildBody;
- final SourceInformation sourceInformation;
-
- SwitchCaseInfo(this.buildCondition, this.buildBody, this.sourceInformation);
-}
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
deleted file mode 100644
index 80f149d..0000000
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ /dev/null
@@ -1,4033 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.ir_builder_task;
-
-import 'package:js_runtime/shared/embedded_names.dart'
- show JsBuiltin, JsGetName;
-
-import '../closure.dart' as closure;
-import '../common.dart';
-import '../common/names.dart' show Identifiers, Names, Selectors;
-import '../common/tasks.dart' show CompilerTask;
-import '../compiler.dart' show Compiler;
-import '../constants/expressions.dart';
-import '../constants/values.dart' show ConstantValue;
-import '../constants/values.dart';
-import '../dart_types.dart';
-import '../elements/elements.dart';
-import '../elements/modelx.dart' show ConstructorBodyElementX;
-import '../io/source_information.dart';
-import '../js/js.dart' as js show js, Template, Expression, Name;
-import '../js_backend/backend_helpers.dart' show BackendHelpers;
-import '../js_backend/js_backend.dart'
- show JavaScriptBackend, SyntheticConstantKind;
-import '../native/native.dart' show NativeBehavior, HasCapturedPlaceholders;
-import '../resolution/operators.dart' as op;
-import '../resolution/semantic_visitor.dart';
-import '../resolution/tree_elements.dart' show TreeElements;
-import '../ssa/types.dart' show TypeMaskFactory;
-import '../tree/tree.dart' as ast;
-import '../types/types.dart' show TypeMask;
-import '../universe/call_structure.dart' show CallStructure;
-import '../universe/selector.dart' show Selector;
-import '../util/util.dart';
-import 'cps_ir_builder.dart';
-import 'cps_ir_nodes.dart' as ir;
-import 'type_mask_system.dart' show TypeMaskSystem;
-// TODO(karlklose): remove.
-
-typedef void IrBuilderCallback(Element element, ir.FunctionDefinition irNode);
-
-class ExplicitReceiverParameter implements Local {
- final ExecutableElement executableContext;
-
- ExplicitReceiverParameter(this.executableContext);
-
- String get name => 'receiver';
- String toString() => 'ExplicitReceiverParameter($executableContext)';
-}
-
-/// This task provides the interface to build IR nodes from [ast.Node]s, which
-/// is used from the [CpsFunctionCompiler] to generate code.
-///
-/// This class is mainly there to correctly measure how long building the IR
-/// takes.
-class IrBuilderTask extends CompilerTask {
- final SourceInformationStrategy sourceInformationStrategy;
- final Compiler compiler;
-
- String bailoutMessage = null;
-
- /// If not null, this function will be called with for each
- /// [ir.FunctionDefinition] node that has been built.
- IrBuilderCallback builderCallback;
-
- IrBuilderTask(Compiler compiler, this.sourceInformationStrategy,
- [this.builderCallback])
- : compiler = compiler,
- super(compiler.measurer);
-
- String get name => 'CPS builder';
-
- ir.FunctionDefinition buildNode(
- AstElement element, TypeMaskSystem typeMaskSystem) {
- return measure(() {
- bailoutMessage = null;
-
- ResolvedAst resolvedAst = element.resolvedAst;
- element = element.implementation;
- return compiler.reporter.withCurrentElement(element, () {
- SourceInformationBuilder sourceInformationBuilder =
- sourceInformationStrategy.createBuilderForContext(resolvedAst);
-
- IrBuilderVisitor builder = new IrBuilderVisitor(
- resolvedAst, compiler, sourceInformationBuilder, typeMaskSystem);
- ir.FunctionDefinition irNode = builder.buildExecutable(element);
- if (irNode == null) {
- bailoutMessage = builder.bailoutMessage;
- } else if (builderCallback != null) {
- builderCallback(element, irNode);
- }
- return irNode;
- });
- });
- }
-}
-
-/// Translates the frontend AST of a method to its CPS IR.
-///
-/// The visitor has an [IrBuilder] which contains an IR fragment to build upon
-/// and the current reaching definition of local variables.
-///
-/// Visiting a statement or expression extends the IR builder's fragment.
-/// For expressions, the primitive holding the resulting value is returned.
-/// For statements, `null` is returned.
-// TODO(johnniwinther): Implement [SemanticDeclVisitor].
-class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
- with
- IrBuilderMixin<ast.Node>,
- SemanticSendResolvedMixin<ir.Primitive, dynamic>,
- ErrorBulkMixin<ir.Primitive, dynamic>,
- BaseImplementationOfStaticsMixin<ir.Primitive, dynamic>,
- BaseImplementationOfLocalsMixin<ir.Primitive, dynamic>,
- BaseImplementationOfDynamicsMixin<ir.Primitive, dynamic>,
- BaseImplementationOfConstantsMixin<ir.Primitive, dynamic>,
- BaseImplementationOfNewMixin<ir.Primitive, dynamic>,
- BaseImplementationOfCompoundsMixin<ir.Primitive, dynamic>,
- BaseImplementationOfSetIfNullsMixin<ir.Primitive, dynamic>,
- BaseImplementationOfIndexCompoundsMixin<ir.Primitive, dynamic>,
- BaseImplementationOfSuperIndexSetIfNullMixin<ir.Primitive, dynamic>
- implements SemanticSendVisitor<ir.Primitive, dynamic> {
- final ResolvedAst resolvedAst;
- final Compiler compiler;
- final SourceInformationBuilder sourceInformationBuilder;
- final TypeMaskSystem typeMaskSystem;
-
- /// A map from try statements in the source to analysis information about
- /// them.
- ///
- /// The analysis information includes the set of variables that must be
- /// copied into [ir.MutableVariable]s on entry to the try and copied out on
- /// exit.
- Map<ast.Node, TryStatementInfo> tryStatements = null;
-
- // In SSA terms, join-point continuation parameters are the phis and the
- // continuation invocation arguments are the corresponding phi inputs. To
- // support name introduction and renaming for source level variables, we use
- // nested (delimited) visitors for constructing subparts of the IR that will
- // need renaming. Each source variable is assigned an index.
- //
- // Each nested visitor maintains a list of free variable uses in the body.
- // These are implemented as a list of parameters, each with their own use
- // list of references. When the delimited subexpression is plugged into the
- // surrounding context, the free occurrences can be captured or become free
- // occurrences in the next outer delimited subexpression.
- //
- // Each nested visitor maintains a list that maps indexes of variables
- // assigned in the delimited subexpression to their reaching definition ---
- // that is, the definition in effect at the hole in 'current'. These are
- // used to determine if a join-point continuation needs to be passed
- // arguments, and what the arguments are.
-
- /// Construct a top-level visitor.
- IrBuilderVisitor(this.resolvedAst, this.compiler,
- this.sourceInformationBuilder, this.typeMaskSystem);
-
- TreeElements get elements => resolvedAst.elements;
-
- JavaScriptBackend get backend => compiler.backend;
- BackendHelpers get helpers => backend.helpers;
- DiagnosticReporter get reporter => compiler.reporter;
-
- String bailoutMessage = null;
-
- ir.Primitive visit(ast.Node node) => node.accept(this);
-
- @override
- ir.Primitive apply(ast.Node node, _) => node.accept(this);
-
- SemanticSendVisitor get sendVisitor => this;
-
- /// Result of closure conversion for the current body of code.
- ///
- /// Will be initialized upon entering the body of a function.
- /// It is computed by the [ClosureTranslator].
- closure.ClosureClassMap closureClassMap;
-
- /// If [node] has declarations for variables that should be boxed,
- /// returns a [ClosureScope] naming a box to create, and enumerating the
- /// variables that should be stored in the box.
- ///
- /// Also see [ClosureScope].
- ClosureScope getClosureScopeForNode(ast.Node node) {
- // We translate a ClosureScope from closure.dart into IR builder's variant
- // because the IR builder should not depend on the synthetic elements
- // created in closure.dart.
- return new ClosureScope(closureClassMap.capturingScopes[node]);
- }
-
- /// Returns the [ClosureScope] for any function, possibly different from the
- /// one currently being built.
- ClosureScope getClosureScopeForFunction(FunctionElement function) {
- closure.ClosureClassMap map = compiler.closureToClassMapper
- .computeClosureToClassMapping(function.resolvedAst);
- return new ClosureScope(map.capturingScopes[function.node]);
- }
-
- /// If the current function is a nested function with free variables (or a
- /// captured reference to `this`), returns a [ClosureEnvironment]
- /// indicating how to access these.
- ClosureEnvironment getClosureEnvironment() {
- return new ClosureEnvironment(closureClassMap);
- }
-
- IrBuilder getBuilderFor(Element element) {
- return new IrBuilder(
- new GlobalProgramInformation(compiler), backend.constants, element);
- }
-
- /// Builds the [ir.FunctionDefinition] for an executable element. In case the
- /// function uses features that cannot be expressed in the IR, this element
- /// returns `null`.
- ir.FunctionDefinition buildExecutable(ExecutableElement element) {
- return nullIfGiveup(() {
- ir.FunctionDefinition root;
- switch (element.kind) {
- case ElementKind.GENERATIVE_CONSTRUCTOR:
- root = buildConstructor(element);
- break;
-
- case ElementKind.GENERATIVE_CONSTRUCTOR_BODY:
- root = buildConstructorBody(element);
- break;
-
- case ElementKind.FACTORY_CONSTRUCTOR:
- case ElementKind.FUNCTION:
- case ElementKind.GETTER:
- case ElementKind.SETTER:
- root = buildFunction(element);
- break;
-
- case ElementKind.FIELD:
- if (Elements.isStaticOrTopLevel(element)) {
- root = buildStaticFieldInitializer(element);
- } else {
- // Instance field initializers are inlined in the constructor,
- // so we shouldn't need to build anything here.
- // TODO(asgerf): But what should we return?
- return null;
- }
- break;
-
- default:
- reporter.internalError(element, "Unexpected element type $element");
- }
- return root;
- });
- }
-
- /// Loads the type variables for all super classes of [superClass] into the
- /// IR builder's environment with their corresponding values.
- ///
- /// The type variables for [currentClass] must already be in the IR builder's
- /// environment.
- ///
- /// Type variables are stored as [TypeVariableLocal] in the environment.
- ///
- /// This ensures that access to type variables mentioned inside the
- /// constructors and initializers will happen through the local environment
- /// instead of using 'this'.
- void loadTypeVariablesForSuperClasses(ClassElement currentClass) {
- if (currentClass.isObject) return;
- loadTypeVariablesForType(currentClass.supertype);
- if (currentClass is MixinApplicationElement) {
- loadTypeVariablesForType(currentClass.mixinType);
- }
- }
-
- /// Loads all type variables for [type] and all of its super classes into
- /// the environment. All type variables mentioned in [type] must already
- /// be in the environment.
- void loadTypeVariablesForType(InterfaceType type) {
- ClassElement clazz = type.element;
- assert(clazz.typeVariables.length == type.typeArguments.length);
- for (int i = 0; i < clazz.typeVariables.length; ++i) {
- irBuilder.declareTypeVariable(
- clazz.typeVariables[i], type.typeArguments[i]);
- }
- loadTypeVariablesForSuperClasses(clazz);
- }
-
- /// Returns the constructor body associated with the given constructor or
- /// creates a new constructor body, if none can be found.
- ///
- /// Returns `null` if the constructor does not have a body.
- ConstructorBodyElement getConstructorBody(FunctionElement constructor) {
- // TODO(asgerf): This is largely inherited from the SSA builder.
- // The ConstructorBodyElement has an invalid function signature, but we
- // cannot add a BoxLocal as parameter, because BoxLocal is not an element.
- // Instead of forging ParameterElements to forge a FunctionSignature, we
- // need a way to create backend methods without creating more fake elements.
- assert(constructor.isGenerativeConstructor);
- assert(constructor.isImplementation);
- if (constructor.isSynthesized) return null;
- ResolvedAst resolvedAst = constructor.resolvedAst;
- ast.FunctionExpression node = constructor.node;
- // If we know the body doesn't have any code, we don't generate it.
- if (!node.hasBody) return null;
- if (node.hasEmptyBody) return null;
- ClassElement classElement = constructor.enclosingClass;
- ConstructorBodyElement bodyElement;
- classElement.forEachBackendMember((Element backendMember) {
- if (backendMember.isGenerativeConstructorBody) {
- ConstructorBodyElement body = backendMember;
- if (body.constructor == constructor) {
- bodyElement = backendMember;
- }
- }
- });
- if (bodyElement == null) {
- bodyElement = new ConstructorBodyElementX(resolvedAst, constructor);
- classElement.addBackendMember(bodyElement);
-
- if (constructor.isPatch) {
- // Create origin body element for patched constructors.
- ConstructorBodyElementX patch = bodyElement;
- ConstructorBodyElementX origin =
- new ConstructorBodyElementX(resolvedAst, constructor.origin);
- origin.applyPatch(patch);
- classElement.origin.addBackendMember(bodyElement.origin);
- }
- }
- assert(bodyElement.isGenerativeConstructorBody);
- return bodyElement;
- }
-
- /// The list of parameters to send from the generative constructor
- /// to the generative constructor body.
- ///
- /// Boxed parameters are not in the list, instead, a [BoxLocal] is passed
- /// containing the boxed parameters.
- ///
- /// For example, given the following constructor,
- ///
- /// Foo(x, y) : field = (() => ++x) { print(x + y) }
- ///
- /// the argument `x` would be replaced by a [BoxLocal]:
- ///
- /// Foo_body(box0, y) { print(box0.x + y) }
- ///
- List<Local> getConstructorBodyParameters(ConstructorBodyElement body) {
- List<Local> parameters = <Local>[];
- ClosureScope scope = getClosureScopeForFunction(body.constructor);
- if (scope != null) {
- parameters.add(scope.box);
- }
- body.functionSignature.orderedForEachParameter((ParameterElement param) {
- if (scope != null && scope.capturedVariables.containsKey(param)) {
- // Do not pass this parameter; the box will carry its value.
- } else {
- parameters.add(param);
- }
- });
- return parameters;
- }
-
- /// Builds the IR for a given constructor.
- ///
- /// 1. Computes the type held in all own or "inherited" type variables.
- /// 2. Evaluates all own or inherited field initializers.
- /// 3. Creates the object and assigns its fields and runtime type.
- /// 4. Calls constructor body and super constructor bodies.
- /// 5. Returns the created object.
- ir.FunctionDefinition buildConstructor(ConstructorElement constructor) {
- // TODO(asgerf): Optimization: If constructor is redirecting, then just
- // evaluate arguments and call the target constructor.
- constructor = constructor.implementation;
- ClassElement classElement = constructor.enclosingClass.implementation;
-
- IrBuilder builder = getBuilderFor(constructor);
-
- final bool requiresTypeInformation =
- builder.program.requiresRuntimeTypesFor(classElement);
-
- return withBuilder(builder, () {
- // Setup parameters and create a box if anything is captured.
- List<Local> parameters = <Local>[];
- if (constructor.isGenerativeConstructor &&
- backend.isNativeOrExtendsNative(classElement)) {
- parameters.add(new ExplicitReceiverParameter(constructor));
- }
- constructor.functionSignature
- .orderedForEachParameter((ParameterElement p) => parameters.add(p));
-
- int firstTypeArgumentParameterIndex;
-
- // If instances of the class may need runtime type information, we add a
- // synthetic parameter for each type parameter.
- if (requiresTypeInformation) {
- firstTypeArgumentParameterIndex = parameters.length;
- classElement.typeVariables.forEach((TypeVariableType variable) {
- parameters.add(new closure.TypeVariableLocal(variable, constructor));
- });
- } else {
- classElement.typeVariables.forEach((TypeVariableType variable) {
- irBuilder.declareTypeVariable(variable, const DynamicType());
- });
- }
-
- // Create IR parameters and setup the environment.
- List<ir.Parameter> irParameters = builder.buildFunctionHeader(parameters,
- closureScope: getClosureScopeForFunction(constructor));
-
- // Create a list of the values of all type argument parameters, if any.
- ir.Primitive typeInformation;
- if (requiresTypeInformation) {
- typeInformation = new ir.TypeExpression(
- ir.TypeExpressionKind.INSTANCE,
- classElement.thisType,
- irParameters.sublist(firstTypeArgumentParameterIndex));
- irBuilder.add(new ir.LetPrim(typeInformation));
- } else {
- typeInformation = null;
- }
-
- // -- Load values for type variables declared on super classes --
- // Field initializers for super classes can reference these, so they
- // must be available before evaluating field initializers.
- // This could be interleaved with field initialization, but we choose do
- // get it out of the way here to avoid complications with mixins.
- loadTypeVariablesForSuperClasses(classElement);
-
- /// Maps each field from this class or a superclass to its initial value.
- Map<FieldElement, ir.Primitive> fieldValues =
- <FieldElement, ir.Primitive>{};
-
- // -- Evaluate field initializers ---
- // Evaluate field initializers in constructor and super constructors.
- List<ConstructorElement> constructorList = <ConstructorElement>[];
- evaluateConstructorFieldInitializers(
- constructor, constructorList, fieldValues);
-
- // All parameters in all constructors are now bound in the environment.
- // BoxLocals for captured parameters are also in the environment.
- // The initial value of all fields are now bound in [fieldValues].
-
- // --- Create the object ---
- // Get the initial field values in the canonical order.
- List<ir.Primitive> instanceArguments = <ir.Primitive>[];
- List<FieldElement> fields = <FieldElement>[];
- classElement.forEachInstanceField((ClassElement c, FieldElement field) {
- ir.Primitive value = fieldValues[field];
- if (value != null) {
- fields.add(field);
- instanceArguments.add(value);
- } else {
- assert(backend.isNativeOrExtendsNative(c));
- // Native fields are initialized elsewhere.
- }
- }, includeSuperAndInjectedMembers: true);
-
- ir.Primitive instance;
- if (constructor.isGenerativeConstructor &&
- backend.isNativeOrExtendsNative(classElement)) {
- instance = irParameters.first;
- instance.type =
- new TypeMask.exact(classElement, typeMaskSystem.classWorld);
- irBuilder.addPrimitive(new ir.ReceiverCheck.nullCheck(
- instance, Selectors.toString_, null));
- for (int i = 0; i < fields.length; i++) {
- irBuilder.addPrimitive(
- new ir.SetField(instance, fields[i], instanceArguments[i]));
- }
- } else {
- instance = new ir.CreateInstance(
- classElement,
- instanceArguments,
- typeInformation,
- constructor.hasNode
- ? sourceInformationBuilder.buildCreate(constructor.node)
- // TODO(johnniwinther): Provide source information for creation
- // through synthetic constructors.
- : null);
- irBuilder.add(new ir.LetPrim(instance));
- }
-
- // --- Call constructor bodies ---
- for (ConstructorElement target in constructorList) {
- ConstructorBodyElement bodyElement = getConstructorBody(target);
- if (bodyElement == null) continue; // Skip if constructor has no body.
- List<ir.Primitive> bodyArguments = <ir.Primitive>[];
- for (Local param in getConstructorBodyParameters(bodyElement)) {
- bodyArguments.add(irBuilder.environment.lookup(param));
- }
- Selector selector = new Selector.call(
- target.memberName, new CallStructure(bodyArguments.length));
- irBuilder.addPrimitive(new ir.InvokeMethodDirectly(
- instance, bodyElement, selector, bodyArguments, null));
- }
-
- // --- step 4: return the created object ----
- irBuilder.buildReturn(
- value: instance,
- sourceInformation:
- sourceInformationBuilder.buildImplicitReturn(constructor));
-
- return irBuilder.makeFunctionDefinition(
- sourceInformationBuilder.buildVariableDeclaration());
- });
- }
-
- /// Make a visitor suitable for translating ASTs taken from [context].
- ///
- /// Every visitor can only be applied to nodes in one context, because
- /// the [elements] field is specific to that context.
- IrBuilderVisitor makeVisitorForContext(AstElement context) {
- ResolvedAst resolvedAst = context.resolvedAst;
- return new IrBuilderVisitor(resolvedAst, compiler,
- sourceInformationBuilder.forContext(resolvedAst), typeMaskSystem);
- }
-
- /// Builds the IR for an [expression] taken from a different [context].
- ///
- /// Such expressions need to be compiled with a different [sourceFile] and
- /// [elements] mapping.
- ir.Primitive inlineExpression(AstElement context, ast.Expression expression) {
- IrBuilderVisitor visitor = makeVisitorForContext(context);
- return visitor.withBuilder(irBuilder, () => visitor.visit(expression));
- }
-
- /// Evaluate the implicit super call in the given mixin constructor.
- void forwardSynthesizedMixinConstructor(
- ConstructorElement constructor,
- List<ConstructorElement> supers,
- Map<FieldElement, ir.Primitive> fieldValues) {
- assert(constructor.enclosingClass.implementation.isMixinApplication);
- assert(constructor.isSynthesized);
- ConstructorElement target = constructor.definingConstructor.implementation;
- // The resolver gives us the exact same FunctionSignature for the two
- // constructors. The parameters for the synthesized constructor
- // are already in the environment, so the target constructor's parameters
- // are also in the environment since their elements are the same.
- assert(constructor.functionSignature == target.functionSignature);
- IrBuilderVisitor visitor = makeVisitorForContext(target);
- visitor.withBuilder(irBuilder, () {
- visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues);
- });
- }
-
- /// In preparation of inlining (part of) [target], the [arguments] are moved
- /// into the environment bindings for the corresponding parameters.
- ///
- /// Defaults for optional arguments are evaluated in order to ensure
- /// all parameters are available in the environment.
- void loadArguments(ConstructorElement target, CallStructure call,
- List<ir.Primitive> arguments) {
- assert(target.isImplementation);
- assert(target.declaration == resolvedAst.element);
- FunctionSignature signature = target.functionSignature;
-
- // Establish a scope in case parameters are captured.
- ClosureScope scope = getClosureScopeForFunction(target);
- irBuilder.enterScope(scope);
-
- // Load required parameters
- int index = 0;
- signature.forEachRequiredParameter((ParameterElement param) {
- irBuilder.declareLocalVariable(param, initialValue: arguments[index]);
- index++;
- });
-
- // Load optional parameters, evaluating default values for omitted ones.
- signature.forEachOptionalParameter((ParameterElement param) {
- ir.Primitive value;
- // Load argument if provided.
- if (signature.optionalParametersAreNamed) {
- int nameIndex = call.namedArguments.indexOf(param.name);
- if (nameIndex != -1) {
- int translatedIndex = call.positionalArgumentCount + nameIndex;
- value = arguments[translatedIndex];
- }
- } else if (index < arguments.length) {
- value = arguments[index];
- }
- // Load default if argument was not provided.
- if (value == null) {
- if (param.initializer != null) {
- value = visit(param.initializer);
- } else {
- value = irBuilder.buildNullConstant();
- }
- }
- irBuilder.declareLocalVariable(param, initialValue: value);
- index++;
- });
- }
-
- /// Evaluates a call to the given constructor from an initializer list.
- ///
- /// Calls [loadArguments] and [evaluateConstructorFieldInitializers] in a
- /// visitor that has the proper [TreeElements] mapping.
- void evaluateConstructorCallFromInitializer(
- ConstructorElement target,
- CallStructure call,
- List<ir.Primitive> arguments,
- List<ConstructorElement> supers,
- Map<FieldElement, ir.Primitive> fieldValues) {
- IrBuilderVisitor visitor = makeVisitorForContext(target);
- visitor.withBuilder(irBuilder, () {
- visitor.loadArguments(target, call, arguments);
- visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues);
- });
- }
-
- /// Evaluates all field initializers on [constructor] and all constructors
- /// invoked through `this()` or `super()` ("superconstructors").
- ///
- /// The resulting field values will be available in [fieldValues]. The values
- /// are not stored in any fields.
- ///
- /// This procedure assumes that the parameters to [constructor] are available
- /// in the IR builder's environment.
- ///
- /// The parameters to superconstructors are, however, assumed *not* to be in
- /// the environment, but will be put there by this procedure.
- ///
- /// All constructors will be added to [supers], with superconstructors first.
- void evaluateConstructorFieldInitializers(
- ConstructorElement constructor,
- List<ConstructorElement> supers,
- Map<FieldElement, ir.Primitive> fieldValues) {
- assert(constructor.isImplementation);
- assert(constructor.declaration == resolvedAst.element);
- ClassElement enclosingClass = constructor.enclosingClass.implementation;
- // Evaluate declaration-site field initializers, unless this constructor
- // redirects to another using a `this()` initializer. In that case, these
- // will be initialized by the effective target constructor.
- if (!constructor.isRedirectingGenerative) {
- enclosingClass.forEachInstanceField((ClassElement c, FieldElement field) {
- if (field.initializer != null) {
- fieldValues[field] = inlineExpression(field, field.initializer);
- } else {
- if (backend.isNativeOrExtendsNative(c)) {
- // Native field is initialized elsewhere.
- } else {
- // Fields without an initializer default to null.
- // This value will be overwritten below if an initializer is found.
- fieldValues[field] = irBuilder.buildNullConstant();
- }
- }
- });
- }
- // If this is a mixin constructor, it does not have its own parameter list
- // or initializer list. Directly forward to the super constructor.
- // Note that the declaration-site initializers originating from the
- // mixed-in class were handled above.
- if (enclosingClass.isMixinApplication) {
- forwardSynthesizedMixinConstructor(constructor, supers, fieldValues);
- return;
- }
- // Evaluate initializing parameters, e.g. `Foo(this.x)`.
- constructor.functionSignature
- .orderedForEachParameter((ParameterElement parameter) {
- if (parameter.isInitializingFormal) {
- InitializingFormalElement fieldParameter = parameter;
- fieldValues[fieldParameter.fieldElement] =
- irBuilder.buildLocalGet(parameter);
- }
- });
- // Evaluate constructor initializers, e.g. `Foo() : x = 50`.
- ast.FunctionExpression node = constructor.node;
- bool hasConstructorCall = false; // Has this() or super() initializer?
- if (node != null && node.initializers != null) {
- for (ast.Node initializer in node.initializers) {
- if (initializer is ast.SendSet) {
- // Field initializer.
- FieldElement field = elements[initializer];
- fieldValues[field] = visit(initializer.arguments.head);
- } else if (initializer is ast.Send) {
- // Super or this initializer.
- ConstructorElement target = elements[initializer].implementation;
- Selector selector = elements.getSelector(initializer);
- List<ir.Primitive> arguments = initializer.arguments.mapToList(visit);
- evaluateConstructorCallFromInitializer(
- target, selector.callStructure, arguments, supers, fieldValues);
- hasConstructorCall = true;
- } else {
- reporter.internalError(
- initializer, "Unexpected initializer type $initializer");
- }
- }
- }
- // If no super() or this() was found, also call default superconstructor.
- if (!hasConstructorCall && !enclosingClass.isObject) {
- ClassElement superClass = enclosingClass.superclass;
- FunctionElement target = superClass.lookupDefaultConstructor();
- if (target == null) {
- reporter.internalError(superClass, "No default constructor available.");
- }
- target = target.implementation;
- evaluateConstructorCallFromInitializer(
- target, CallStructure.NO_ARGS, const [], supers, fieldValues);
- }
- // Add this constructor after the superconstructors.
- supers.add(constructor);
- }
-
- TryBoxedVariables _analyzeTryBoxedVariables(ast.Node node) {
- TryBoxedVariables variables = new TryBoxedVariables(elements);
- try {
- variables.analyze(node);
- } catch (e) {
- bailoutMessage = variables.bailoutMessage;
- rethrow;
- }
- return variables;
- }
-
- /// Builds the IR for the body of a constructor.
- ///
- /// This function is invoked from one or more "factory" constructors built by
- /// [buildConstructor].
- ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) {
- ConstructorElement constructor = body.constructor;
- ast.FunctionExpression node = constructor.node;
- closureClassMap = compiler.closureToClassMapper
- .computeClosureToClassMapping(constructor.resolvedAst);
-
- // We compute variables boxed in mutable variables on entry to each try
- // block, not including variables captured by a closure (which are boxed
- // in the heap). This duplicates some of the work of closure conversion
- // without directly using the results. This duplication is wasteful and
- // error-prone.
- // TODO(kmillikin): We should combine closure conversion and try/catch
- // variable analysis in some way.
- TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
- tryStatements = variables.tryStatements;
- IrBuilder builder = getBuilderFor(body);
-
- return withBuilder(builder, () {
- irBuilder.buildConstructorBodyHeader(
- getConstructorBodyParameters(body), getClosureScopeForNode(node));
- visit(node.body);
- return irBuilder.makeFunctionDefinition(
- sourceInformationBuilder.buildVariableDeclaration());
- });
- }
-
- ir.FunctionDefinition buildFunction(FunctionElement element) {
- assert(invariant(element, element.isImplementation));
- ast.FunctionExpression node = element.node;
-
- assert(!element.isSynthesized);
- assert(node != null);
- assert(elements[node] != null);
-
- closureClassMap = compiler.closureToClassMapper
- .computeClosureToClassMapping(element.resolvedAst);
- TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
- tryStatements = variables.tryStatements;
- IrBuilder builder = getBuilderFor(element);
- return withBuilder(
- builder, () => _makeFunctionBody(builder, element, node));
- }
-
- ir.FunctionDefinition buildStaticFieldInitializer(FieldElement element) {
- if (!backend.constants.lazyStatics.contains(element)) {
- return null; // Nothing to do.
- }
- closureClassMap = compiler.closureToClassMapper
- .computeClosureToClassMapping(element.resolvedAst);
- IrBuilder builder = getBuilderFor(element);
- return withBuilder(builder, () {
- irBuilder.buildFunctionHeader(<Local>[]);
- ir.Primitive initialValue = visit(element.initializer);
- ast.VariableDefinitions node = element.node;
- ast.SendSet sendSet = node.definitions.nodes.head;
- irBuilder.buildReturn(
- value: initialValue,
- sourceInformation:
- sourceInformationBuilder.buildReturn(sendSet.assignmentOperator));
- return irBuilder.makeFunctionDefinition(
- sourceInformationBuilder.buildVariableDeclaration());
- });
- }
-
- /// Builds the IR for a constant taken from a different [context].
- ///
- /// Such constants need to be compiled with a different [sourceFile] and
- /// [elements] mapping.
- ir.Primitive inlineConstant(AstElement context, ast.Expression exp) {
- IrBuilderVisitor visitor = makeVisitorForContext(context);
- return visitor.withBuilder(irBuilder, () => visitor.translateConstant(exp));
- }
-
- /// Creates a primitive for the default value of [parameter].
- ir.Primitive translateDefaultValue(ParameterElement parameter) {
- if (parameter.initializer == null ||
- // TODO(sigmund): JS doesn't support default values, so this should be
- // reported as an error earlier (Issue #25759).
- backend.isJsInterop(parameter.functionDeclaration)) {
- return irBuilder.buildNullConstant();
- } else {
- return inlineConstant(parameter.executableContext, parameter.initializer);
- }
- }
-
- /// Normalizes the argument list of a static invocation.
- ///
- /// A static invocation is one where the target is known. The argument list
- /// [arguments] is normalized by adding default values for optional arguments
- /// that are not passed, and by sorting it in place so that named arguments
- /// appear in a canonical order. A [CallStructure] reflecting this order
- /// is returned.
- CallStructure normalizeStaticArguments(CallStructure callStructure,
- FunctionElement target, List<ir.Primitive> arguments) {
- target = target.implementation;
- FunctionSignature signature = target.functionSignature;
- if (!signature.optionalParametersAreNamed &&
- signature.parameterCount == arguments.length) {
- return callStructure;
- }
-
- if (!signature.optionalParametersAreNamed) {
- int i = signature.requiredParameterCount;
- signature.forEachOptionalParameter((ParameterElement element) {
- if (i < callStructure.positionalArgumentCount) {
- ++i;
- } else {
- arguments.add(translateDefaultValue(element));
- }
- });
- return new CallStructure(signature.parameterCount);
- }
-
- int offset = signature.requiredParameterCount;
- List<ir.Primitive> namedArguments = arguments.sublist(offset);
- arguments.length = offset;
- List<String> normalizedNames = <String>[];
- // Iterate over the optional parameters of the signature, and try to
- // find them in the callStructure's named arguments. If found, we use the
- // value in the temporary list, otherwise the default value.
- signature.orderedOptionalParameters.forEach((ParameterElement element) {
- int nameIndex = callStructure.namedArguments.indexOf(element.name);
- arguments.add(nameIndex == -1
- ? translateDefaultValue(element)
- : namedArguments[nameIndex]);
- normalizedNames.add(element.name);
- });
- return new CallStructure(signature.parameterCount, normalizedNames);
- }
-
- /// Normalizes the argument list of a dynamic invocation.
- ///
- /// A dynamic invocation is one where the target is not known. The argument
- /// list [arguments] is normalized by sorting it in place so that the named
- /// arguments appear in a canonical order. A [CallStructure] reflecting this
- /// order is returned.
- CallStructure normalizeDynamicArguments(
- CallStructure callStructure, List<ir.Primitive> arguments) {
- assert(arguments.length == callStructure.argumentCount);
- if (callStructure.namedArguments.isEmpty) return callStructure;
- int destinationIndex = callStructure.positionalArgumentCount;
- List<ir.Primitive> namedArguments = arguments.sublist(destinationIndex);
- for (String argName in callStructure.getOrderedNamedArguments()) {
- int sourceIndex = callStructure.namedArguments.indexOf(argName);
- arguments[destinationIndex++] = namedArguments[sourceIndex];
- }
- return new CallStructure(
- callStructure.argumentCount, callStructure.getOrderedNamedArguments());
- }
-
- /// Read the value of [field].
- ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) {
- ConstantValue constant = getConstantForVariable(field);
- if (constant != null && !field.isAssignable) {
- typeMaskSystem.associateConstantValueWithElement(constant, field);
- return irBuilder.buildConstant(constant, sourceInformation: src);
- } else if (backend.constants.lazyStatics.contains(field)) {
- return irBuilder.addPrimitive(new ir.GetLazyStatic(field,
- sourceInformation: src,
- isFinal: compiler.world.fieldNeverChanges(field)));
- } else {
- return irBuilder.addPrimitive(new ir.GetStatic(field,
- sourceInformation: src,
- isFinal: compiler.world.fieldNeverChanges(field)));
- }
- }
-
- ir.FunctionDefinition _makeFunctionBody(
- IrBuilder builder, FunctionElement element, ast.FunctionExpression node) {
- FunctionSignature signature = element.functionSignature;
- List<Local> parameters = <Local>[];
- signature.orderedForEachParameter(
- (LocalParameterElement e) => parameters.add(e));
-
- bool requiresRuntimeTypes = false;
- if (element.isFactoryConstructor) {
- requiresRuntimeTypes =
- builder.program.requiresRuntimeTypesFor(element.enclosingElement);
- if (requiresRuntimeTypes) {
- // Type arguments are passed in as extra parameters.
- for (DartType typeVariable in element.enclosingClass.typeVariables) {
- parameters.add(new closure.TypeVariableLocal(typeVariable, element));
- }
- }
- }
-
- irBuilder.buildFunctionHeader(parameters,
- closureScope: getClosureScopeForNode(node),
- env: getClosureEnvironment());
-
- if (element == helpers.jsArrayTypedConstructor) {
- // Generate a body for JSArray<E>.typed(allocation):
- //
- // t1 = setRuntimeTypeInfo(allocation, TypeExpression($E));
- // return Refinement(t1, <JSArray>);
- //
- assert(parameters.length == 1 || parameters.length == 2);
- ir.Primitive allocation = irBuilder.buildLocalGet(parameters[0]);
-
- // Only call setRuntimeTypeInfo if JSArray requires the type parameter.
- if (requiresRuntimeTypes) {
- assert(parameters.length == 2);
- closure.TypeVariableLocal typeParameter = parameters[1];
- ir.Primitive typeArgument =
- irBuilder.buildTypeVariableAccess(typeParameter.typeVariable);
-
- ir.Primitive typeInformation = irBuilder.addPrimitive(
- new ir.TypeExpression(ir.TypeExpressionKind.INSTANCE,
- element.enclosingClass.thisType, <ir.Primitive>[typeArgument]));
-
- MethodElement helper = helpers.setRuntimeTypeInfo;
- CallStructure callStructure = CallStructure.TWO_ARGS;
- Selector selector = new Selector.call(helper.memberName, callStructure);
- allocation = irBuilder.buildInvokeStatic(
- helper,
- selector,
- <ir.Primitive>[allocation, typeInformation],
- sourceInformationBuilder.buildGeneric(node));
- }
-
- ir.Primitive refinement = irBuilder.addPrimitive(
- new ir.Refinement(allocation, typeMaskSystem.arrayType));
-
- irBuilder.buildReturn(
- value: refinement,
- sourceInformation:
- sourceInformationBuilder.buildImplicitReturn(element));
- } else {
- visit(node.body);
- }
- return irBuilder.makeFunctionDefinition(
- sourceInformationBuilder.buildVariableDeclaration());
- }
-
- /// Builds the IR for creating an instance of the closure class corresponding
- /// to the given nested function.
- closure.ClosureClassElement makeSubFunction(ast.FunctionExpression node) {
- closure.ClosureClassMap innerMap =
- compiler.closureToClassMapper.getMappingForNestedFunction(node);
- closure.ClosureClassElement closureClass = innerMap.closureClassElement;
- return closureClass;
- }
-
- ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
- return irBuilder.buildFunctionExpression(
- makeSubFunction(node), sourceInformationBuilder.buildCreate(node));
- }
-
- visitFunctionDeclaration(ast.FunctionDeclaration node) {
- LocalFunctionElement element = elements[node.function];
- Object inner = makeSubFunction(node.function);
- irBuilder.declareLocalFunction(
- element, inner, sourceInformationBuilder.buildCreate(node.function));
- }
-
- // ## Statements ##
- visitBlock(ast.Block node) {
- irBuilder.buildBlock(node.statements.nodes, build);
- }
-
- ir.Primitive visitBreakStatement(ast.BreakStatement node) {
- if (!irBuilder.buildBreak(elements.getTargetOf(node))) {
- reporter.internalError(node, "'break' target not found");
- }
- return null;
- }
-
- ir.Primitive visitContinueStatement(ast.ContinueStatement node) {
- if (!irBuilder.buildContinue(elements.getTargetOf(node))) {
- reporter.internalError(node, "'continue' target not found");
- }
- return null;
- }
-
- // Build(EmptyStatement, C) = C
- ir.Primitive visitEmptyStatement(ast.EmptyStatement node) {
- assert(irBuilder.isOpen);
- return null;
- }
-
- // Build(ExpressionStatement(e), C) = C'
- // where (C', _) = Build(e, C)
- ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) {
- assert(irBuilder.isOpen);
- if (node.expression is ast.Throw) {
- // Throw expressions that occur as statements are translated differently
- // from ones that occur as subexpressions. This is achieved by peeking
- // at statement-level expressions here.
- irBuilder.buildThrow(visit(node.expression));
- } else {
- visit(node.expression);
- }
- return null;
- }
-
- ir.Primitive visitRethrow(ast.Rethrow node) {
- assert(irBuilder.isOpen);
- irBuilder.buildRethrow();
- return null;
- }
-
- /// Construct a method that executes the forwarding call to the target
- /// constructor. This is only required, if the forwarding factory
- /// constructor can potentially be the target of a reflective call, because
- /// the builder shortcuts calls to redirecting factories at the call site
- /// (see [handleConstructorInvoke]).
- visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) {
- ConstructorElement targetConstructor =
- elements.getRedirectingTargetConstructor(node).implementation;
- ConstructorElement redirectingConstructor =
- irBuilder.state.currentElement.implementation;
- List<ir.Primitive> arguments = <ir.Primitive>[];
- FunctionSignature redirectingSignature =
- redirectingConstructor.functionSignature;
- List<String> namedParameters = <String>[];
- redirectingSignature.forEachParameter((ParameterElement parameter) {
- arguments.add(irBuilder.environment.lookup(parameter));
- if (parameter.isNamed) {
- namedParameters.add(parameter.name);
- }
- });
- ClassElement cls = redirectingConstructor.enclosingClass;
- InterfaceType targetType =
- redirectingConstructor.computeEffectiveTargetType(cls.thisType);
- CallStructure callStructure =
- new CallStructure(redirectingSignature.parameterCount, namedParameters);
- callStructure =
- normalizeStaticArguments(callStructure, targetConstructor, arguments);
- ir.Primitive instance = irBuilder.buildConstructorInvocation(
- targetConstructor,
- callStructure,
- targetType,
- arguments,
- sourceInformationBuilder.buildNew(node));
- irBuilder.buildReturn(
- value: instance,
- sourceInformation: sourceInformationBuilder.buildReturn(node));
- }
-
- visitFor(ast.For node) {
- List<LocalElement> loopVariables = <LocalElement>[];
- if (node.initializer is ast.VariableDefinitions) {
- ast.VariableDefinitions definitions = node.initializer;
- for (ast.Node node in definitions.definitions.nodes) {
- LocalElement loopVariable = elements[node];
- loopVariables.add(loopVariable);
- }
- }
-
- JumpTarget target = elements.getTargetDefinition(node);
- irBuilder.buildFor(
- buildInitializer: subbuild(node.initializer),
- buildCondition: subbuild(node.condition),
- buildBody: subbuild(node.body),
- buildUpdate: subbuildSequence(node.update),
- closureScope: getClosureScopeForNode(node),
- loopVariables: loopVariables,
- target: target);
- }
-
- visitIf(ast.If node) {
- irBuilder.buildIf(build(node.condition), subbuild(node.thenPart),
- subbuild(node.elsePart), sourceInformationBuilder.buildIf(node));
- }
-
- visitLabeledStatement(ast.LabeledStatement node) {
- ast.Statement body = node.statement;
- if (body is ast.Loop) {
- visit(body);
- } else {
- JumpTarget target = elements.getTargetDefinition(body);
- irBuilder.buildLabeledStatement(
- buildBody: subbuild(body), target: target);
- }
- }
-
- visitDoWhile(ast.DoWhile node) {
- irBuilder.buildDoWhile(
- buildBody: subbuild(node.body),
- buildCondition: subbuild(node.condition),
- target: elements.getTargetDefinition(node),
- closureScope: getClosureScopeForNode(node));
- }
-
- visitWhile(ast.While node) {
- irBuilder.buildWhile(
- buildCondition: subbuild(node.condition),
- buildBody: subbuild(node.body),
- target: elements.getTargetDefinition(node),
- closureScope: getClosureScopeForNode(node));
- }
-
- visitAsyncForIn(ast.AsyncForIn node) {
- // Translate await for into a loop over a StreamIterator. The source
- // statement:
- //
- // await for (<decl> in <stream>) <body>
- //
- // is translated as if it were:
- //
- // var iterator = new StreamIterator(<stream>);
- // try {
- // while (await iterator.hasNext()) {
- // <decl> = await iterator.current;
- // <body>
- // }
- // } finally {
- // await iterator.cancel();
- // }
- ir.Primitive stream = visit(node.expression);
- ir.Primitive dummyTypeArgument = irBuilder.buildNullConstant();
- ConstructorElement constructor = helpers.streamIteratorConstructor;
- ir.Primitive iterator = irBuilder.addPrimitive(new ir.InvokeConstructor(
- constructor.enclosingClass.thisType,
- constructor,
- new Selector.callConstructor(constructor.memberName, 1),
- <ir.Primitive>[stream, dummyTypeArgument],
- sourceInformationBuilder.buildGeneric(node)));
-
- buildTryBody(IrBuilder builder) {
- ir.Node buildLoopCondition(IrBuilder builder) {
- ir.Primitive moveNext = builder.buildDynamicInvocation(
- iterator,
- Selectors.moveNext,
- elements.getMoveNextTypeMask(node),
- <ir.Primitive>[],
- sourceInformationBuilder.buildForInMoveNext(node));
- return builder.addPrimitive(new ir.Await(moveNext));
- }
-
- ir.Node buildLoopBody(IrBuilder builder) {
- return withBuilder(builder, () {
- ir.Primitive current = irBuilder.buildDynamicInvocation(
- iterator,
- Selectors.current,
- elements.getCurrentTypeMask(node),
- <ir.Primitive>[],
- sourceInformationBuilder.buildForInCurrent(node));
- Element variable = elements.getForInVariable(node);
- SourceInformation sourceInformation =
- sourceInformationBuilder.buildForInSet(node);
- if (Elements.isLocal(variable)) {
- if (node.declaredIdentifier.asVariableDefinitions() != null) {
- irBuilder.declareLocalVariable(variable);
- }
- irBuilder.buildLocalVariableSet(
- variable, current, sourceInformation);
- } else if (Elements.isError(variable) ||
- Elements.isMalformed(variable)) {
- Selector selector =
- new Selector.setter(new Name(variable.name, variable.library));
- List<ir.Primitive> args = <ir.Primitive>[current];
- // Note the comparison below. It can be the case that an element
- // isError and isMalformed.
- if (Elements.isError(variable)) {
- irBuilder.buildStaticNoSuchMethod(
- selector, args, sourceInformation);
- } else {
- irBuilder.buildErroneousInvocation(
- variable, selector, args, sourceInformation);
- }
- } else if (Elements.isStaticOrTopLevel(variable)) {
- if (variable.isField) {
- irBuilder.addPrimitive(new ir.SetStatic(variable, current));
- } else {
- irBuilder.buildStaticSetterSet(
- variable, current, sourceInformation);
- }
- } else {
- ir.Primitive receiver = irBuilder.buildThis();
- ast.Node identifier = node.declaredIdentifier;
- irBuilder.buildDynamicSet(
- receiver,
- elements.getSelector(identifier),
- elements.getTypeMask(identifier),
- current,
- sourceInformation);
- }
- visit(node.body);
- });
- }
-
- builder.buildWhile(
- buildCondition: buildLoopCondition,
- buildBody: buildLoopBody,
- target: elements.getTargetDefinition(node),
- closureScope: getClosureScopeForNode(node));
- }
-
- ir.Node buildFinallyBody(IrBuilder builder) {
- ir.Primitive cancellation = builder.buildDynamicInvocation(
- iterator,
- Selectors.cancel,
- backend.dynamicType,
- <ir.Primitive>[],
- sourceInformationBuilder.buildGeneric(node));
- return builder.addPrimitive(new ir.Await(cancellation));
- }
-
- irBuilder.buildTryFinally(
- new TryStatementInfo(), buildTryBody, buildFinallyBody);
- }
-
- visitAwait(ast.Await node) {
- assert(irBuilder.isOpen);
- ir.Primitive value = visit(node.expression);
- return irBuilder.addPrimitive(new ir.Await(value));
- }
-
- visitYield(ast.Yield node) {
- assert(irBuilder.isOpen);
- ir.Primitive value = visit(node.expression);
- return irBuilder.addPrimitive(new ir.Yield(value, node.hasStar));
- }
-
- visitSyncForIn(ast.SyncForIn node) {
- // [node.declaredIdentifier] can be either an [ast.VariableDefinitions]
- // (defining a new local variable) or a send designating some existing
- // variable.
- ast.Node identifier = node.declaredIdentifier;
- ast.VariableDefinitions variableDeclaration =
- identifier.asVariableDefinitions();
- Element variableElement = elements.getForInVariable(node);
- Selector selector = elements.getSelector(identifier);
-
- irBuilder.buildForIn(
- buildExpression: subbuild(node.expression),
- buildVariableDeclaration: subbuild(variableDeclaration),
- variableElement: variableElement,
- variableSelector: selector,
- variableMask: elements.getTypeMask(identifier),
- variableSetSourceInformation:
- sourceInformationBuilder.buildForInSet(node),
- currentMask: elements.getCurrentTypeMask(node),
- currentSourceInformation:
- sourceInformationBuilder.buildForInCurrent(node),
- moveNextMask: elements.getMoveNextTypeMask(node),
- moveNextSourceInformation:
- sourceInformationBuilder.buildForInMoveNext(node),
- iteratorMask: elements.getIteratorTypeMask(node),
- iteratorSourceInformation:
- sourceInformationBuilder.buildForInIterator(node),
- buildBody: subbuild(node.body),
- target: elements.getTargetDefinition(node),
- closureScope: getClosureScopeForNode(node));
- }
-
- /// If compiling with trusted type annotations, assumes that [value] is
- /// now known to be `null` or an instance of [type].
- ///
- /// This is also where we should add type checks in checked mode, but this
- /// is not supported yet.
- ir.Primitive checkType(ir.Primitive value, DartType dartType) {
- if (!compiler.options.trustTypeAnnotations) return value;
- TypeMask type = typeMaskSystem.subtypesOf(dartType).nullable();
- return irBuilder.addPrimitive(new ir.Refinement(value, type));
- }
-
- ir.Primitive checkTypeVsElement(ir.Primitive value, TypedElement element) {
- return checkType(value, element.type);
- }
-
- ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) {
- assert(irBuilder.isOpen);
- for (ast.Node definition in node.definitions.nodes) {
- Element element = elements[definition];
- ir.Primitive initialValue;
- // Definitions are either SendSets if there is an initializer, or
- // Identifiers if there is no initializer.
- if (definition is ast.SendSet) {
- assert(!definition.arguments.isEmpty);
- assert(definition.arguments.tail.isEmpty);
- initialValue = visit(definition.arguments.head);
- initialValue = checkTypeVsElement(initialValue, element);
- } else {
- assert(definition is ast.Identifier);
- }
- irBuilder.declareLocalVariable(element, initialValue: initialValue);
- }
- return null;
- }
-
- static final RegExp nativeRedirectionRegExp =
- new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$');
-
- // Build(Return(e), C) = C'[InvokeContinuation(return, x)]
- // where (C', x) = Build(e, C)
- //
- // Return without a subexpression is translated as if it were return null.
- visitReturn(ast.Return node) {
- assert(irBuilder.isOpen);
- SourceInformation source = sourceInformationBuilder.buildReturn(node);
- if (node.beginToken.value == 'native') {
- FunctionElement function = irBuilder.state.currentElement;
- assert(backend.isNative(function));
- ast.Node nativeBody = node.expression;
- if (nativeBody != null) {
- ast.LiteralString jsCode = nativeBody.asLiteralString();
- String javaScriptCode = jsCode.dartString.slowToString();
- assert(invariant(
- nativeBody, !nativeRedirectionRegExp.hasMatch(javaScriptCode),
- message: "Deprecated syntax, use @JSName('name') instead."));
- assert(invariant(
- nativeBody, function.functionSignature.parameterCount == 0,
- message: 'native "..." syntax is restricted to '
- 'functions with zero parameters.'));
- irBuilder.buildNativeFunctionBody(function, javaScriptCode,
- sourceInformationBuilder.buildForeignCode(node));
- } else {
- String name = backend.nativeData.getFixedBackendName(function);
- irBuilder.buildRedirectingNativeFunctionBody(function, name, source);
- }
- } else {
- irBuilder.buildReturn(
- value: build(node.expression), sourceInformation: source);
- }
- }
-
- visitSwitchStatement(ast.SwitchStatement node) {
- // Dart switch cases can be labeled and be the target of continue from
- // within the switch. Such cases are 'recursive'. If there are any
- // recursive cases, we implement the switch using a pair of switches with
- // the second one switching over a state variable in a loop. The first
- // switch contains the non-recursive cases, and the second switch contains
- // the recursive ones.
- //
- // For example, for the Dart switch:
- //
- // switch (E) {
- // case 0:
- // BODY0;
- // break;
- // LABEL0: case 1:
- // BODY1;
- // break;
- // case 2:
- // BODY2;
- // continue LABEL1;
- // LABEL1: case 3:
- // BODY3;
- // continue LABEL0;
- // default:
- // BODY4;
- // }
- //
- // We translate it as if it were the JavaScript:
- //
- // var state = -1;
- // switch (E) {
- // case 0:
- // BODY0;
- // break;
- // case 1:
- // state = 0; // Recursive, label ID = 0.
- // break;
- // case 2:
- // BODY2;
- // state = 1; // Continue to label ID = 1.
- // break;
- // case 3:
- // state = 1; // Recursive, label ID = 1.
- // break;
- // default:
- // BODY4;
- // }
- // L: while (state != -1) {
- // case 0:
- // BODY1;
- // break L; // Break from switch becomes break from loop.
- // case 1:
- // BODY2;
- // state = 0; // Continue to label ID = 0.
- // break;
- // }
- assert(irBuilder.isOpen);
- // Preprocess: compute a list of cases that are the target of continue.
- // These are the so-called 'recursive' cases.
- List<JumpTarget> continueTargets = <JumpTarget>[];
- List<ast.Node> switchCases = node.cases.nodes.toList();
- for (ast.SwitchCase switchCase in switchCases) {
- for (ast.Node labelOrCase in switchCase.labelsAndCases) {
- if (labelOrCase is ast.Label) {
- LabelDefinition definition = elements.getLabelDefinition(labelOrCase);
- if (definition != null && definition.isContinueTarget) {
- continueTargets.add(definition.target);
- }
- }
- }
- }
-
- // If any cases are continue targets, use an anonymous local value to
- // implement a state machine. The initial value is -1.
- ir.Primitive initial;
- int stateIndex;
- if (continueTargets.isNotEmpty) {
- initial = irBuilder.buildIntegerConstant(-1);
- stateIndex = irBuilder.environment.length;
- irBuilder.environment.extend(null, initial);
- }
-
- // Use a simple switch for the non-recursive cases. A break will go to the
- // join-point after the switch. A continue to a labeled case will assign
- // to the state variable and go to the join-point.
- ir.Primitive value = visit(node.expression);
- JumpCollector join = new ForwardJumpCollector(irBuilder.environment,
- target: elements.getTargetDefinition(node));
- irBuilder.state.breakCollectors.add(join);
- for (int i = 0; i < continueTargets.length; ++i) {
- // The state value is i, the case's position in the list of recursive
- // cases.
- irBuilder.state.continueCollectors
- .add(new GotoJumpCollector(continueTargets[i], stateIndex, i, join));
- }
-
- // For each non-default case use a pair of functions, one to translate the
- // condition and one to translate the body. For the default case use a
- // function to translate the body. Use continueTargetIterator as a pointer
- // to the next recursive case.
- Iterator<JumpTarget> continueTargetIterator = continueTargets.iterator;
- continueTargetIterator.moveNext();
- List<SwitchCaseInfo> cases = <SwitchCaseInfo>[];
- SubbuildFunction buildDefaultBody;
- for (ast.SwitchCase switchCase in switchCases) {
- JumpTarget nextContinueTarget = continueTargetIterator.current;
- if (switchCase.isDefaultCase) {
- if (nextContinueTarget != null &&
- switchCase == nextContinueTarget.statement) {
- // In this simple switch, recursive cases are as if they immediately
- // continued to themselves.
- buildDefaultBody = nested(() {
- irBuilder.buildContinue(nextContinueTarget);
- });
- continueTargetIterator.moveNext();
- } else {
- // Non-recursive cases consist of the translation of the body.
- // For the default case, there is implicitly a break if control
- // flow reaches the end.
- buildDefaultBody = nested(() {
- irBuilder.buildSequence(switchCase.statements, visit);
- if (irBuilder.isOpen) irBuilder.jumpTo(join);
- });
- }
- continue;
- }
-
- ir.Primitive buildCondition(IrBuilder builder) {
- // There can be multiple cases sharing the same body, because empty
- // cases are allowed to fall through to the next one. Each case is
- // a comparison, build a short-circuited disjunction of all of them.
- return withBuilder(builder, () {
- ir.Primitive condition;
- for (ast.Node labelOrCase in switchCase.labelsAndCases) {
- if (labelOrCase is ast.CaseMatch) {
- ir.Primitive buildComparison() {
- ir.Primitive constant =
- translateConstant(labelOrCase.expression);
- return irBuilder.buildIdentical(value, constant);
- }
-
- if (condition == null) {
- condition = buildComparison();
- } else {
- condition = irBuilder.buildLogicalOperator(
- condition,
- nested(buildComparison),
- sourceInformationBuilder.buildSwitchCase(switchCase),
- isLazyOr: true);
- }
- }
- }
- return condition;
- });
- }
-
- SubbuildFunction buildBody;
- if (nextContinueTarget != null &&
- switchCase == nextContinueTarget.statement) {
- // Recursive cases are as if they immediately continued to themselves.
- buildBody = nested(() {
- irBuilder.buildContinue(nextContinueTarget);
- });
- continueTargetIterator.moveNext();
- } else {
- // Non-recursive cases consist of the translation of the body. It is a
- // runtime error if control-flow reaches the end of the body of any but
- // the last case.
- buildBody = (IrBuilder builder) {
- withBuilder(builder, () {
- irBuilder.buildSequence(switchCase.statements, visit);
- if (irBuilder.isOpen) {
- if (switchCase == switchCases.last) {
- irBuilder.jumpTo(join);
- } else {
- Element error = helpers.fallThroughError;
- ir.Primitive exception = irBuilder.buildInvokeStatic(
- error,
- new Selector.fromElement(error),
- <ir.Primitive>[],
- sourceInformationBuilder.buildGeneric(node));
- irBuilder.buildThrow(exception);
- }
- }
- });
- return null;
- };
- }
-
- cases.add(new SwitchCaseInfo(buildCondition, buildBody,
- sourceInformationBuilder.buildSwitchCase(switchCase)));
- }
-
- irBuilder.buildSimpleSwitch(join, cases, buildDefaultBody);
- irBuilder.state.breakCollectors.removeLast();
- irBuilder.state.continueCollectors.length -= continueTargets.length;
- if (continueTargets.isEmpty) return;
-
- // If there were recursive cases build a while loop whose body is a
- // switch containing (only) the recursive cases. The condition is
- // 'state != initialValue' so the loop is not taken when the state variable
- // has not been assigned.
- //
- // 'loop' is the join-point of the exits from the inner switch which will
- // perform another iteration of the loop. 'exit' is the join-point of the
- // breaks from the switch, outside the loop.
- JumpCollector loop = new ForwardJumpCollector(irBuilder.environment);
- JumpCollector exit = new ForwardJumpCollector(irBuilder.environment,
- target: elements.getTargetDefinition(node));
- irBuilder.state.breakCollectors.add(exit);
- for (int i = 0; i < continueTargets.length; ++i) {
- irBuilder.state.continueCollectors
- .add(new GotoJumpCollector(continueTargets[i], stateIndex, i, loop));
- }
- cases.clear();
- for (int i = 0; i < continueTargets.length; ++i) {
- // The conditions compare to the recursive case index.
- ir.Primitive buildCondition(IrBuilder builder) {
- ir.Primitive constant = builder.buildIntegerConstant(i);
- return builder.buildIdentical(
- builder.environment.index2value[stateIndex], constant);
- }
-
- ir.Primitive buildBody(IrBuilder builder) {
- withBuilder(builder, () {
- ast.SwitchCase switchCase = continueTargets[i].statement;
- irBuilder.buildSequence(switchCase.statements, visit);
- if (irBuilder.isOpen) {
- if (switchCase == switchCases.last) {
- irBuilder.jumpTo(exit);
- } else {
- Element error = helpers.fallThroughError;
- ir.Primitive exception = irBuilder.buildInvokeStatic(
- error,
- new Selector.fromElement(error),
- <ir.Primitive>[],
- sourceInformationBuilder.buildGeneric(node));
- irBuilder.buildThrow(exception);
- }
- }
- });
- return null;
- }
-
- cases.add(new SwitchCaseInfo(buildCondition, buildBody,
- sourceInformationBuilder.buildSwitch(node)));
- }
-
- // A loop with a simple switch in the body.
- IrBuilder whileBuilder = irBuilder.makeDelimitedBuilder();
- whileBuilder.buildWhile(buildCondition: (IrBuilder builder) {
- ir.Primitive condition = builder.buildIdentical(
- builder.environment.index2value[stateIndex], initial);
- return builder.buildNegation(
- condition, sourceInformationBuilder.buildSwitch(node));
- }, buildBody: (IrBuilder builder) {
- builder.buildSimpleSwitch(loop, cases, null);
- });
- // Jump to the exit continuation. This jump is the body of the loop exit
- // continuation, so the loop exit continuation can be eta-reduced. The
- // jump is here for simplicity because `buildWhile` does not expose the
- // loop's exit continuation directly and has already emitted all jumps
- // to it anyway.
- whileBuilder.jumpTo(exit);
- irBuilder.add(new ir.LetCont(exit.continuation, whileBuilder.root));
- irBuilder.environment = exit.environment;
- irBuilder.environment.discard(1); // Discard the state variable.
- irBuilder.state.breakCollectors.removeLast();
- irBuilder.state.continueCollectors.length -= continueTargets.length;
- }
-
- visitTryStatement(ast.TryStatement node) {
- List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[];
- for (ast.CatchBlock catchClause in node.catchBlocks.nodes) {
- LocalVariableElement exceptionVariable;
- if (catchClause.exception != null) {
- exceptionVariable = elements[catchClause.exception];
- }
- LocalVariableElement stackTraceVariable;
- if (catchClause.trace != null) {
- stackTraceVariable = elements[catchClause.trace];
- }
- DartType type;
- if (catchClause.onKeyword != null) {
- type = elements.getType(catchClause.type);
- }
- catchClauseInfos.add(new CatchClauseInfo(
- type: type,
- exceptionVariable: exceptionVariable,
- stackTraceVariable: stackTraceVariable,
- buildCatchBlock: subbuild(catchClause.block),
- sourceInformation: sourceInformationBuilder.buildCatch(catchClause)));
- }
-
- assert(!node.catchBlocks.isEmpty || node.finallyBlock != null);
- if (!node.catchBlocks.isEmpty && node.finallyBlock != null) {
- // Try/catch/finally is encoded in terms of try/catch and try/finally:
- //
- // try tryBlock catch (ex, st) catchBlock finally finallyBlock
- // ==>
- // try { try tryBlock catch (ex, st) catchBlock } finally finallyBlock
- irBuilder.buildTryFinally(tryStatements[node.finallyBlock],
- (IrBuilder inner) {
- inner.buildTryCatch(tryStatements[node.catchBlocks],
- subbuild(node.tryBlock), catchClauseInfos);
- }, subbuild(node.finallyBlock));
- } else if (!node.catchBlocks.isEmpty) {
- irBuilder.buildTryCatch(tryStatements[node.catchBlocks],
- subbuild(node.tryBlock), catchClauseInfos);
- } else {
- irBuilder.buildTryFinally(tryStatements[node.finallyBlock],
- subbuild(node.tryBlock), subbuild(node.finallyBlock));
- }
- }
-
- // ## Expressions ##
- ir.Primitive visitConditional(ast.Conditional node) {
- return irBuilder.buildConditional(
- build(node.condition),
- subbuild(node.thenExpression),
- subbuild(node.elseExpression),
- sourceInformationBuilder.buildIf(node));
- }
-
- // For all simple literals:
- // Build(Literal(c), C) = C[let val x = Constant(c) in [], x]
- ir.Primitive visitLiteralBool(ast.LiteralBool node) {
- assert(irBuilder.isOpen);
- return irBuilder.buildBooleanConstant(node.value);
- }
-
- ir.Primitive visitLiteralDouble(ast.LiteralDouble node) {
- assert(irBuilder.isOpen);
- return irBuilder.buildDoubleConstant(node.value);
- }
-
- ir.Primitive visitLiteralInt(ast.LiteralInt node) {
- assert(irBuilder.isOpen);
- return irBuilder.buildIntegerConstant(node.value);
- }
-
- ir.Primitive visitLiteralNull(ast.LiteralNull node) {
- assert(irBuilder.isOpen);
- return irBuilder.buildNullConstant();
- }
-
- ir.Primitive visitLiteralString(ast.LiteralString node) {
- assert(irBuilder.isOpen);
- return irBuilder.buildDartStringConstant(node.dartString);
- }
-
- ConstantValue getConstantForNode(ast.Node node) {
- return irBuilder.state.constants.getConstantValueForNode(node, elements);
- }
-
- ConstantValue getConstantForVariable(VariableElement element) {
- ConstantExpression constant = element.constant;
- if (constant != null) {
- return irBuilder.state.constants.getConstantValue(constant);
- }
- return null;
- }
-
- ir.Primitive buildConstantExpression(
- ConstantExpression expression, SourceInformation sourceInformation) {
- return irBuilder.buildConstant(
- irBuilder.state.constants.getConstantValue(expression),
- sourceInformation: sourceInformation);
- }
-
- /// Returns the allocation site-specific type for a given allocation.
- ///
- /// Currently, it is an error to call this with anything that is not the
- /// allocation site for a List object (a literal list or a call to one
- /// of the List constructors).
- TypeMask getAllocationSiteType(ast.Node node) {
- return compiler.typesTask
- .getGuaranteedTypeOfNode(elements.analyzedElement, node);
- }
-
- ir.Primitive visitLiteralList(ast.LiteralList node) {
- if (node.isConst) {
- return translateConstant(node);
- }
- List<ir.Primitive> values = node.elements.nodes.mapToList(visit);
- InterfaceType type = elements.getType(node);
- TypeMask allocationSiteType = getAllocationSiteType(node);
- // TODO(sra): In checked mode, the elements must be checked as though
- // operator[]= is called.
- ir.Primitive list = irBuilder.buildListLiteral(type, values,
- allocationSiteType: allocationSiteType);
- if (type.treatAsRaw) return list;
- // Call JSArray<E>.typed(allocation) to install the reified type.
- ConstructorElement constructor = helpers.jsArrayTypedConstructor;
- ir.Primitive tagged = irBuilder.buildConstructorInvocation(
- constructor.effectiveTarget,
- CallStructure.ONE_ARG,
- constructor.computeEffectiveTargetType(type),
- <ir.Primitive>[list],
- sourceInformationBuilder.buildNew(node));
-
- if (allocationSiteType == null) return tagged;
-
- return irBuilder
- .addPrimitive(new ir.Refinement(tagged, allocationSiteType));
- }
-
- ir.Primitive visitLiteralMap(ast.LiteralMap node) {
- assert(irBuilder.isOpen);
- if (node.isConst) {
- return translateConstant(node);
- }
-
- InterfaceType type = elements.getType(node);
-
- if (node.entries.nodes.isEmpty) {
- if (type.treatAsRaw) {
- return irBuilder.buildStaticFunctionInvocation(
- helpers.mapLiteralUntypedEmptyMaker,
- <ir.Primitive>[],
- sourceInformationBuilder.buildNew(node));
- } else {
- ConstructorElement constructor = helpers.mapLiteralConstructorEmpty;
- return irBuilder.buildConstructorInvocation(
- constructor.effectiveTarget,
- CallStructure.NO_ARGS,
- constructor.computeEffectiveTargetType(type),
- <ir.Primitive>[],
- sourceInformationBuilder.buildNew(node));
- }
- }
-
- List<ir.Primitive> keysAndValues = <ir.Primitive>[];
- for (ast.LiteralMapEntry entry in node.entries.nodes.toList()) {
- keysAndValues.add(visit(entry.key));
- keysAndValues.add(visit(entry.value));
- }
- ir.Primitive keysAndValuesList =
- irBuilder.buildListLiteral(null, keysAndValues);
-
- if (type.treatAsRaw) {
- return irBuilder.buildStaticFunctionInvocation(
- helpers.mapLiteralUntypedMaker,
- <ir.Primitive>[keysAndValuesList],
- sourceInformationBuilder.buildNew(node));
- } else {
- ConstructorElement constructor = helpers.mapLiteralConstructor;
- return irBuilder.buildConstructorInvocation(
- constructor.effectiveTarget,
- CallStructure.ONE_ARG,
- constructor.computeEffectiveTargetType(type),
- <ir.Primitive>[keysAndValuesList],
- sourceInformationBuilder.buildNew(node));
- }
- }
-
- ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) {
- assert(irBuilder.isOpen);
- return translateConstant(node);
- }
-
- ir.Primitive visitParenthesizedExpression(ast.ParenthesizedExpression node) {
- assert(irBuilder.isOpen);
- return visit(node.expression);
- }
-
- // Stores the result of visiting a CascadeReceiver, so we can return it from
- // its enclosing Cascade.
- ir.Primitive _currentCascadeReceiver;
-
- ir.Primitive visitCascadeReceiver(ast.CascadeReceiver node) {
- assert(irBuilder.isOpen);
- return _currentCascadeReceiver = visit(node.expression);
- }
-
- ir.Primitive visitCascade(ast.Cascade node) {
- assert(irBuilder.isOpen);
- var oldCascadeReceiver = _currentCascadeReceiver;
- // Throw away the result of visiting the expression.
- // Instead we return the result of visiting the CascadeReceiver.
- visit(node.expression);
- ir.Primitive receiver = _currentCascadeReceiver;
- _currentCascadeReceiver = oldCascadeReceiver;
- return receiver;
- }
-
- @override
- ir.Primitive visitAssert(ast.Assert node) {
- assert(irBuilder.isOpen);
- if (compiler.options.enableUserAssertions) {
- return giveup(node, 'assert in checked mode not implemented');
- } else {
- // The call to assert and its argument expression must be ignored
- // in production mode.
- // Assertions can only occur in expression statements, so no value needs
- // to be returned.
- return null;
- }
- }
-
- // ## Sends ##
- @override
- void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) {
- if (prefix != null) buildCheckDeferredIsLoaded(prefix, node);
- }
-
- /// Create a call to check that a deferred import has already been loaded.
- ir.Primitive buildCheckDeferredIsLoaded(PrefixElement prefix, ast.Send node) {
- SourceInformation sourceInformation =
- sourceInformationBuilder.buildCall(node, node.selector);
- ir.Primitive name = irBuilder.buildStringConstant(
- compiler.deferredLoadTask.getImportDeferName(node, prefix));
- ir.Primitive uri =
- irBuilder.buildStringConstant('${prefix.deferredImport.uri}');
- return irBuilder.buildStaticFunctionInvocation(
- helpers.checkDeferredIsLoaded,
- <ir.Primitive>[name, uri],
- sourceInformation);
- }
-
- ir.Primitive visitNamedArgument(ast.NamedArgument node) {
- assert(irBuilder.isOpen);
- return visit(node.expression);
- }
-
- @override
- ir.Primitive visitExpressionInvoke(ast.Send node, ast.Node expression,
- ast.NodeList argumentsNode, CallStructure callStructure, _) {
- ir.Primitive receiver = visit(expression);
- List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit);
- callStructure = normalizeDynamicArguments(callStructure, arguments);
- return irBuilder.buildCallInvocation(receiver, callStructure, arguments,
- sourceInformationBuilder.buildCall(node, argumentsNode));
- }
-
- /// Returns `true` if [node] is a super call.
- // TODO(johnniwinther): Remove the need for this.
- bool isSuperCall(ast.Send node) {
- return node != null && node.receiver != null && node.receiver.isSuper();
- }
-
- @override
- ir.Primitive handleConstantGet(
- ast.Node node, ConstantExpression constant, _) {
- return buildConstantExpression(
- constant, sourceInformationBuilder.buildGet(node));
- }
-
- /// If [node] is null, returns this.
- /// Otherwise visits [node] and returns the result.
- ir.Primitive translateReceiver(ast.Expression node) {
- return node != null ? visit(node) : irBuilder.buildThis();
- }
-
- @override
- ir.Primitive handleDynamicGet(
- ast.Send node, ast.Node receiver, Name name, _) {
- return irBuilder.buildDynamicGet(
- translateReceiver(receiver),
- new Selector.getter(name),
- elements.getTypeMask(node),
- sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive visitIfNotNullDynamicPropertyGet(
- ast.Send node, ast.Node receiver, Name name, _) {
- ir.Primitive target = visit(receiver);
- return irBuilder.buildIfNotNullSend(
- target,
- nested(() => irBuilder.buildDynamicGet(
- target,
- new Selector.getter(name),
- elements.getTypeMask(node),
- sourceInformationBuilder.buildGet(node))),
- sourceInformationBuilder.buildIf(node));
- }
-
- @override
- ir.Primitive visitDynamicTypeLiteralGet(
- ast.Send node, ConstantExpression constant, _) {
- return buildConstantExpression(
- constant, sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive visitLocalVariableGet(
- ast.Send node, LocalVariableElement element, _) {
- return element.isConst
- ? irBuilder.buildConstant(getConstantForVariable(element),
- sourceInformation: sourceInformationBuilder.buildGet(node))
- : irBuilder.buildLocalGet(element);
- }
-
- ir.Primitive handleLocalGet(ast.Send node, LocalElement element, _) {
- return irBuilder.buildLocalGet(element);
- }
-
- @override
- ir.Primitive handleStaticFunctionGet(
- ast.Send node, MethodElement function, _) {
- return irBuilder.addPrimitive(new ir.GetStatic(function, isFinal: true));
- }
-
- @override
- ir.Primitive handleStaticGetterGet(ast.Send node, FunctionElement getter, _) {
- return buildStaticGetterGet(
- getter, node, sourceInformationBuilder.buildGet(node));
- }
-
- /// Create a getter invocation of the static getter [getter]. This also
- /// handles the special case where [getter] is the `loadLibrary`
- /// pseudo-function on library prefixes of deferred imports.
- ir.Primitive buildStaticGetterGet(MethodElement getter, ast.Send node,
- SourceInformation sourceInformation) {
- if (getter.isDeferredLoaderGetter) {
- PrefixElement prefix = getter.enclosingElement;
- ir.Primitive loadId = irBuilder.buildStringConstant(
- compiler.deferredLoadTask.getImportDeferName(node, prefix));
- return irBuilder.buildStaticFunctionInvocation(
- compiler.loadLibraryFunction,
- <ir.Primitive>[loadId],
- sourceInformation);
- } else {
- return irBuilder.buildStaticGetterGet(getter, sourceInformation);
- }
- }
-
- @override
- ir.Primitive visitSuperFieldGet(ast.Send node, FieldElement field, _) {
- return irBuilder.buildSuperFieldGet(
- field, sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive visitSuperGetterGet(ast.Send node, FunctionElement getter, _) {
- return irBuilder.buildSuperGetterGet(
- getter, sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive visitSuperMethodGet(ast.Send node, MethodElement method, _) {
- return irBuilder.buildSuperMethodGet(
- method, sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive visitUnresolvedSuperGet(ast.Send node, Element element, _) {
- return buildSuperNoSuchMethod(
- elements.getSelector(node),
- elements.getTypeMask(node),
- [],
- sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive visitUnresolvedSuperSet(
- ast.Send node, Element element, ast.Node rhs, _) {
- return buildSuperNoSuchMethod(
- elements.getSelector(node),
- elements.getTypeMask(node),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitThisGet(ast.Identifier node, _) {
- if (irBuilder.state.thisParameter == null) {
- // TODO(asgerf,johnniwinther): Should be in a visitInvalidThis method.
- // 'this' in static context. Just translate to null.
- assert(compiler.compilationFailed);
- return irBuilder.buildNullConstant();
- }
- return irBuilder.buildThis();
- }
-
- ir.Primitive translateTypeVariableTypeLiteral(
- TypeVariableElement element, SourceInformation sourceInformation) {
- return irBuilder.buildReifyTypeVariable(element.type, sourceInformation);
- }
-
- @override
- ir.Primitive visitTypeVariableTypeLiteralGet(
- ast.Send node, TypeVariableElement element, _) {
- return translateTypeVariableTypeLiteral(
- element, sourceInformationBuilder.buildGet(node));
- }
-
- ir.Primitive translateLogicalOperator(ast.Expression left,
- ast.Expression right, SourceInformation sourceInformation,
- {bool isLazyOr}) {
- ir.Primitive leftValue = visit(left);
-
- ir.Primitive buildRightValue(IrBuilder rightBuilder) {
- return withBuilder(rightBuilder, () => visit(right));
- }
-
- return irBuilder.buildLogicalOperator(
- leftValue, buildRightValue, sourceInformation,
- isLazyOr: isLazyOr);
- }
-
- @override
- ir.Primitive visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) {
- return irBuilder.buildIfNull(
- build(left), subbuild(right), sourceInformationBuilder.buildIf(node));
- }
-
- @override
- ir.Primitive visitLogicalAnd(
- ast.Send node, ast.Node left, ast.Node right, _) {
- return translateLogicalOperator(
- left, right, sourceInformationBuilder.buildIf(node),
- isLazyOr: false);
- }
-
- @override
- ir.Primitive visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) {
- return translateLogicalOperator(
- left, right, sourceInformationBuilder.buildIf(node),
- isLazyOr: true);
- }
-
- @override
- ir.Primitive visitAs(ast.Send node, ast.Node expression, DartType type, _) {
- ir.Primitive receiver = visit(expression);
- return irBuilder.buildTypeOperator(
- receiver, type, sourceInformationBuilder.buildAs(node),
- isTypeTest: false);
- }
-
- @override
- ir.Primitive visitIs(ast.Send node, ast.Node expression, DartType type, _) {
- ir.Primitive value = visit(expression);
- return irBuilder.buildTypeOperator(
- value, type, sourceInformationBuilder.buildIs(node),
- isTypeTest: true);
- }
-
- @override
- ir.Primitive visitIsNot(
- ast.Send node, ast.Node expression, DartType type, _) {
- ir.Primitive value = visit(expression);
- ir.Primitive check = irBuilder.buildTypeOperator(
- value, type, sourceInformationBuilder.buildIs(node),
- isTypeTest: true);
- return irBuilder.buildNegation(
- check, sourceInformationBuilder.buildIf(node));
- }
-
- ir.Primitive translateBinary(ast.Send node, ast.Node left,
- op.BinaryOperator operator, ast.Node right) {
- ir.Primitive receiver = visit(left);
- Selector selector = new Selector.binaryOperator(operator.selectorName);
- List<ir.Primitive> arguments = <ir.Primitive>[visit(right)];
- CallStructure callStructure =
- normalizeDynamicArguments(selector.callStructure, arguments);
- return irBuilder.buildDynamicInvocation(
- receiver,
- new Selector(selector.kind, selector.memberName, callStructure),
- elements.getTypeMask(node),
- arguments,
- sourceInformationBuilder.buildCall(node, node.selector));
- }
-
- @override
- ir.Primitive visitBinary(ast.Send node, ast.Node left,
- op.BinaryOperator operator, ast.Node right, _) {
- return translateBinary(node, left, operator, right);
- }
-
- @override
- ir.Primitive visitIndex(ast.Send node, ast.Node receiver, ast.Node index, _) {
- ir.Primitive target = visit(receiver);
- Selector selector = new Selector.index();
- List<ir.Primitive> arguments = <ir.Primitive>[visit(index)];
- CallStructure callStructure =
- normalizeDynamicArguments(selector.callStructure, arguments);
- return irBuilder.buildDynamicInvocation(
- target,
- new Selector(selector.kind, selector.memberName, callStructure),
- elements.getTypeMask(node),
- arguments,
- sourceInformationBuilder.buildCall(receiver, node.selector));
- }
-
- ir.Primitive translateSuperBinary(
- FunctionElement function,
- op.BinaryOperator operator,
- ast.Node argument,
- SourceInformation sourceInformation) {
- List<ir.Primitive> arguments = <ir.Primitive>[visit(argument)];
- return irBuilder.buildSuperMethodInvocation(
- function, CallStructure.ONE_ARG, arguments, sourceInformation);
- }
-
- @override
- ir.Primitive visitSuperBinary(ast.Send node, FunctionElement function,
- op.BinaryOperator operator, ast.Node argument, _) {
- return translateSuperBinary(function, operator, argument,
- sourceInformationBuilder.buildBinary(node));
- }
-
- @override
- ir.Primitive visitSuperIndex(
- ast.Send node, FunctionElement function, ast.Node index, _) {
- return irBuilder.buildSuperIndex(
- function, visit(index), sourceInformationBuilder.buildIndex(node));
- }
-
- @override
- ir.Primitive visitEquals(ast.Send node, ast.Node left, ast.Node right, _) {
- return translateBinary(node, left, op.BinaryOperator.EQ, right);
- }
-
- @override
- ir.Primitive visitSuperEquals(
- ast.Send node, FunctionElement function, ast.Node argument, _) {
- return translateSuperBinary(function, op.BinaryOperator.EQ, argument,
- sourceInformationBuilder.buildBinary(node));
- }
-
- @override
- ir.Primitive visitNot(ast.Send node, ast.Node expression, _) {
- return irBuilder.buildNegation(
- visit(expression), sourceInformationBuilder.buildIf(node));
- }
-
- @override
- ir.Primitive visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) {
- return irBuilder.buildNegation(
- translateBinary(node, left, op.BinaryOperator.NOT_EQ, right),
- sourceInformationBuilder.buildIf(node));
- }
-
- @override
- ir.Primitive visitSuperNotEquals(
- ast.Send node, FunctionElement function, ast.Node argument, _) {
- return irBuilder.buildNegation(
- translateSuperBinary(function, op.BinaryOperator.NOT_EQ, argument,
- sourceInformationBuilder.buildBinary(node)),
- sourceInformationBuilder.buildIf(node));
- }
-
- @override
- ir.Primitive visitUnary(
- ast.Send node, op.UnaryOperator operator, ast.Node expression, _) {
- // TODO(johnniwinther): Clean up the creation of selectors.
- Selector selector = operator.selector;
- ir.Primitive receiver = translateReceiver(expression);
- return irBuilder.buildDynamicInvocation(
- receiver,
- selector,
- elements.getTypeMask(node),
- const [],
- sourceInformationBuilder.buildCall(expression, node));
- }
-
- @override
- ir.Primitive visitSuperUnary(
- ast.Send node, op.UnaryOperator operator, FunctionElement function, _) {
- return irBuilder.buildSuperMethodInvocation(function, CallStructure.NO_ARGS,
- const [], sourceInformationBuilder.buildCall(node, node));
- }
-
- // TODO(johnniwinther): Handle this in the [IrBuilder] to ensure the correct
- // semantic correlation between arguments and invocation.
- CallStructure translateDynamicArguments(ast.NodeList nodeList,
- CallStructure callStructure, List<ir.Primitive> arguments) {
- assert(arguments.isEmpty);
- for (ast.Node node in nodeList) arguments.add(visit(node));
- return normalizeDynamicArguments(callStructure, arguments);
- }
-
- // TODO(johnniwinther): Handle this in the [IrBuilder] to ensure the correct
- // semantic correlation between arguments and invocation.
- CallStructure translateStaticArguments(ast.NodeList nodeList, Element element,
- CallStructure callStructure, List<ir.Primitive> arguments) {
- assert(arguments.isEmpty);
- for (ast.Node node in nodeList) arguments.add(visit(node));
- return normalizeStaticArguments(callStructure, element, arguments);
- }
-
- ir.Primitive translateCallInvoke(
- ir.Primitive target,
- ast.NodeList argumentsNode,
- CallStructure callStructure,
- SourceInformation sourceInformation) {
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure =
- translateDynamicArguments(argumentsNode, callStructure, arguments);
- return irBuilder.buildCallInvocation(
- target, callStructure, arguments, sourceInformation);
- }
-
- @override
- ir.Primitive handleConstantInvoke(ast.Send node, ConstantExpression constant,
- ast.NodeList arguments, CallStructure callStructure, _) {
- ir.Primitive target = buildConstantExpression(
- constant, sourceInformationBuilder.buildGet(node));
- return translateCallInvoke(target, arguments, callStructure,
- sourceInformationBuilder.buildCall(node, arguments));
- }
-
- @override
- ir.Primitive handleConstructorInvoke(
- ast.NewExpression node,
- ConstructorElement constructor,
- DartType type,
- ast.NodeList argumentsNode,
- CallStructure callStructure,
- _) {
- // TODO(sigmund): move these checks down after visiting arguments
- // (see issue #25355)
- ast.Send send = node.send;
- // If an allocation refers to a type using a deferred import prefix (e.g.
- // `new lib.A()`), we must ensure that the deferred import has already been
- // loaded.
- var prefix =
- compiler.deferredLoadTask.deferredPrefixElement(send, elements);
- if (prefix != null) buildCheckDeferredIsLoaded(prefix, send);
-
- // We also emit deferred import checks when using redirecting factories that
- // refer to deferred prefixes.
- if (constructor.isRedirectingFactory && !constructor.isCyclicRedirection) {
- ConstructorElement current = constructor;
- while (current.isRedirectingFactory) {
- var prefix = current.redirectionDeferredPrefix;
- if (prefix != null) buildCheckDeferredIsLoaded(prefix, send);
- current = current.immediateRedirectionTarget;
- }
- }
-
- List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit);
- if (constructor.isGenerativeConstructor &&
- backend.isNativeOrExtendsNative(constructor.enclosingClass)) {
- arguments.insert(0, irBuilder.buildNullConstant());
- }
- // Use default values from the effective target, not the immediate target.
- ConstructorElement target;
- if (constructor == compiler.symbolConstructor) {
- // The Symbol constructor should perform validation of its argument
- // which is not expressible as a Dart const constructor. Instead, the
- // libraries contain a dummy const constructor implementation that
- // doesn't perform validation and the compiler compiles a call to
- // (non-const) Symbol.validated when it sees new Symbol(...).
- target = helpers.symbolValidatedConstructor;
- } else {
- target = constructor.implementation;
- }
- while (target.isRedirectingFactory && !target.isCyclicRedirection) {
- target = target.effectiveTarget.implementation;
- }
-
- callStructure = normalizeStaticArguments(callStructure, target, arguments);
- TypeMask allocationSiteType;
-
- if (Elements.isFixedListConstructorCall(constructor, send, compiler) ||
- Elements.isGrowableListConstructorCall(constructor, send, compiler) ||
- Elements.isFilledListConstructorCall(constructor, send, compiler) ||
- Elements.isConstructorOfTypedArraySubclass(constructor, compiler)) {
- allocationSiteType = getAllocationSiteType(send);
- }
- ConstructorElement constructorImplementation = constructor.implementation;
- return irBuilder.buildConstructorInvocation(
- target,
- callStructure,
- constructorImplementation.computeEffectiveTargetType(type),
- arguments,
- sourceInformationBuilder.buildNew(node),
- allocationSiteType: allocationSiteType);
- }
-
- @override
- ir.Primitive handleDynamicInvoke(ast.Send node, ast.Node receiver,
- ast.NodeList argumentsNode, Selector selector, _) {
- ir.Primitive target = translateReceiver(receiver);
- List<ir.Primitive> arguments = <ir.Primitive>[];
- CallStructure callStructure = translateDynamicArguments(
- argumentsNode, selector.callStructure, arguments);
- return irBuilder.buildDynamicInvocation(
- target,
- new Selector(selector.kind, selector.memberName, callStructure),
- elements.getTypeMask(node),
- arguments,
- sourceInformationBuilder.buildCall(node, node.selector));
- }
-
- @override
- ir.Primitive visitIfNotNullDynamicPropertyInvoke(ast.Send node,
- ast.Node receiver, ast.NodeList argumentsNode, Selector selector, _) {
- ir.Primitive target = visit(receiver);
- return irBuilder.buildIfNotNullSend(target, nested(() {
- List<ir.Primitive> arguments = <ir.Primitive>[];
- CallStructure callStructure = translateDynamicArguments(
- argumentsNode, selector.callStructure, arguments);
- return irBuilder.buildDynamicInvocation(
- target,
- new Selector(selector.kind, selector.memberName, callStructure),
- elements.getTypeMask(node),
- arguments,
- sourceInformationBuilder.buildCall(node, node.selector));
- }), sourceInformationBuilder.buildIf(node));
- }
-
- ir.Primitive handleLocalInvoke(ast.Send node, LocalElement element,
- ast.NodeList argumentsNode, CallStructure callStructure, _) {
- ir.Primitive function = irBuilder.buildLocalGet(element);
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure =
- translateDynamicArguments(argumentsNode, callStructure, arguments);
- return irBuilder.buildCallInvocation(function, callStructure, arguments,
- sourceInformationBuilder.buildCall(node, argumentsNode));
- }
-
- @override
- ir.Primitive handleStaticFieldGet(ast.Send node, FieldElement field, _) {
- return buildStaticFieldGet(field, sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive handleStaticFieldInvoke(ast.Send node, FieldElement field,
- ast.NodeList argumentsNode, CallStructure callStructure, _) {
- SourceInformation src = sourceInformationBuilder.buildGet(node);
- ir.Primitive target = buildStaticFieldGet(field, src);
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure =
- translateDynamicArguments(argumentsNode, callStructure, arguments);
- return irBuilder.buildCallInvocation(target, callStructure, arguments,
- sourceInformationBuilder.buildCall(node, argumentsNode));
- }
-
- @override
- ir.Primitive handleStaticFunctionInvoke(ast.Send node, MethodElement function,
- ast.NodeList argumentsNode, CallStructure callStructure, _) {
- if (compiler.backend.isForeign(function)) {
- return handleForeignCode(node, function, argumentsNode, callStructure);
- } else {
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure = translateStaticArguments(
- argumentsNode, function, callStructure, arguments);
- Selector selector = new Selector.call(function.memberName, callStructure);
- return irBuilder.buildInvokeStatic(function, selector, arguments,
- sourceInformationBuilder.buildCall(node, node.selector));
- }
- }
-
- @override
- ir.Primitive handleStaticFunctionIncompatibleInvoke(
- ast.Send node,
- MethodElement function,
- ast.NodeList arguments,
- CallStructure callStructure,
- _) {
- return irBuilder.buildStaticNoSuchMethod(
- elements.getSelector(node),
- arguments.nodes.mapToList(visit),
- sourceInformationBuilder.buildCall(node, node.selector));
- }
-
- @override
- ir.Primitive handleStaticGetterInvoke(ast.Send node, FunctionElement getter,
- ast.NodeList argumentsNode, CallStructure callStructure, _) {
- ir.Primitive target = buildStaticGetterGet(
- getter, node, sourceInformationBuilder.buildGet(node));
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure =
- translateDynamicArguments(argumentsNode, callStructure, arguments);
- return irBuilder.buildCallInvocation(target, callStructure, arguments,
- sourceInformationBuilder.buildCall(node, argumentsNode));
- }
-
- @override
- ir.Primitive visitSuperFieldInvoke(ast.Send node, FieldElement field,
- ast.NodeList argumentsNode, CallStructure callStructure, _) {
- ir.Primitive target = irBuilder.buildSuperFieldGet(
- field, sourceInformationBuilder.buildGet(node));
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure =
- translateDynamicArguments(argumentsNode, callStructure, arguments);
- return irBuilder.buildCallInvocation(target, callStructure, arguments,
- sourceInformationBuilder.buildCall(node, argumentsNode));
- }
-
- @override
- ir.Primitive visitSuperGetterInvoke(ast.Send node, FunctionElement getter,
- ast.NodeList argumentsNode, CallStructure callStructure, _) {
- ir.Primitive target = irBuilder.buildSuperGetterGet(
- getter, sourceInformationBuilder.buildGet(node));
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure =
- translateDynamicArguments(argumentsNode, callStructure, arguments);
- return irBuilder.buildCallInvocation(target, callStructure, arguments,
- sourceInformationBuilder.buildCall(node, argumentsNode));
- }
-
- @override
- ir.Primitive visitSuperMethodInvoke(ast.Send node, MethodElement method,
- ast.NodeList argumentsNode, CallStructure callStructure, _) {
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure = translateStaticArguments(
- argumentsNode, method, callStructure, arguments);
- return irBuilder.buildSuperMethodInvocation(method, callStructure,
- arguments, sourceInformationBuilder.buildCall(node, node.selector));
- }
-
- @override
- ir.Primitive visitSuperMethodIncompatibleInvoke(
- ast.Send node,
- MethodElement method,
- ast.NodeList arguments,
- CallStructure callStructure,
- _) {
- List<ir.Primitive> normalizedArguments = <ir.Primitive>[];
- CallStructure normalizedCallStructure = translateDynamicArguments(
- arguments, callStructure, normalizedArguments);
- return buildSuperNoSuchMethod(
- new Selector.call(method.memberName, normalizedCallStructure),
- elements.getTypeMask(node),
- normalizedArguments,
- sourceInformationBuilder.buildCall(node, arguments));
- }
-
- @override
- ir.Primitive visitUnresolvedSuperInvoke(ast.Send node, Element element,
- ast.NodeList argumentsNode, Selector selector, _) {
- List<ir.Primitive> arguments = <ir.Primitive>[];
- CallStructure callStructure = translateDynamicArguments(
- argumentsNode, selector.callStructure, arguments);
- // TODO(johnniwinther): Supply a member name to the visit function instead
- // of looking it up in elements.
- return buildSuperNoSuchMethod(
- new Selector.call(elements.getSelector(node).memberName, callStructure),
- elements.getTypeMask(node),
- arguments,
- sourceInformationBuilder.buildCall(node, argumentsNode));
- }
-
- @override
- ir.Primitive visitThisInvoke(
- ast.Send node, ast.NodeList arguments, CallStructure callStructure, _) {
- return translateCallInvoke(irBuilder.buildThis(), arguments, callStructure,
- sourceInformationBuilder.buildCall(node, arguments));
- }
-
- @override
- ir.Primitive visitTypeVariableTypeLiteralInvoke(
- ast.Send node,
- TypeVariableElement element,
- ast.NodeList arguments,
- CallStructure callStructure,
- _) {
- return translateCallInvoke(
- translateTypeVariableTypeLiteral(
- element, sourceInformationBuilder.buildGet(node)),
- arguments,
- callStructure,
- sourceInformationBuilder.buildCall(node, arguments));
- }
-
- @override
- ir.Primitive visitIndexSet(
- ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, _) {
- return irBuilder.buildDynamicIndexSet(
- visit(receiver),
- elements.getTypeMask(node),
- visit(index),
- visit(rhs),
- sourceInformationBuilder.buildIndexSet(node));
- }
-
- @override
- ir.Primitive visitSuperIndexSet(ast.SendSet node, FunctionElement function,
- ast.Node index, ast.Node rhs, _) {
- return irBuilder.buildSuperIndexSet(function, visit(index), visit(rhs),
- sourceInformationBuilder.buildIndexSet(node));
- }
-
- ir.Primitive translateIfNull(ast.SendSet node, ir.Primitive getValue(),
- ast.Node rhs, void setValue(ir.Primitive value)) {
- ir.Primitive value = getValue();
- // Unlike other compound operators if-null conditionally will not do the
- // assignment operation.
- return irBuilder.buildIfNull(value, nested(() {
- ir.Primitive newValue = build(rhs);
- setValue(newValue);
- return newValue;
- }), sourceInformationBuilder.buildIf(node));
- }
-
- ir.Primitive translateCompounds(ast.SendSet node, ir.Primitive getValue(),
- CompoundRhs rhs, void setValue(ir.Primitive value)) {
- ir.Primitive value = getValue();
- op.BinaryOperator operator = rhs.operator;
- assert(operator.kind != op.BinaryOperatorKind.IF_NULL);
-
- Selector operatorSelector =
- new Selector.binaryOperator(operator.selectorName);
- ir.Primitive rhsValue;
- if (rhs.kind == CompoundKind.ASSIGNMENT) {
- rhsValue = visit(rhs.rhs);
- } else {
- rhsValue = irBuilder.buildIntegerConstant(1);
- }
- List<ir.Primitive> arguments = <ir.Primitive>[rhsValue];
- CallStructure callStructure =
- normalizeDynamicArguments(operatorSelector.callStructure, arguments);
- TypeMask operatorTypeMask =
- elements.getOperatorTypeMaskInComplexSendSet(node);
- SourceInformation operatorSourceInformation =
- sourceInformationBuilder.buildCall(node, node.assignmentOperator);
- ir.Primitive result = irBuilder.buildDynamicInvocation(
- value,
- new Selector(
- operatorSelector.kind, operatorSelector.memberName, callStructure),
- operatorTypeMask,
- arguments,
- operatorSourceInformation);
- setValue(result);
- return rhs.kind == CompoundKind.POSTFIX ? value : result;
- }
-
- ir.Primitive translateSetIfNull(ast.SendSet node, ir.Primitive getValue(),
- ast.Node rhs, void setValue(ir.Primitive value)) {
- ir.Primitive value = getValue();
- // Unlike other compound operators if-null conditionally will not do the
- // assignment operation.
- return irBuilder.buildIfNull(value, nested(() {
- ir.Primitive newValue = build(rhs);
- setValue(newValue);
- return newValue;
- }), sourceInformationBuilder.buildIf(node));
- }
-
- @override
- ir.Primitive handleSuperIndexSetIfNull(
- ast.SendSet node,
- Element indexFunction,
- Element indexSetFunction,
- ast.Node index,
- ast.Node rhs,
- arg,
- {bool isGetterValid,
- bool isSetterValid}) {
- return translateSetIfNull(
- node,
- () {
- if (isGetterValid) {
- return irBuilder.buildSuperMethodGet(
- indexFunction, sourceInformationBuilder.buildIndex(node));
- } else {
- return buildSuperNoSuchGetter(
- indexFunction,
- elements.getGetterTypeMaskInComplexSendSet(node),
- sourceInformationBuilder.buildIndex(node));
- }
- },
- rhs,
- (ir.Primitive result) {
- if (isSetterValid) {
- return irBuilder.buildSuperMethodGet(
- indexSetFunction, sourceInformationBuilder.buildIndexSet(node));
- } else {
- return buildSuperNoSuchSetter(
- indexSetFunction,
- elements.getTypeMask(node),
- result,
- sourceInformationBuilder.buildIndexSet(node));
- }
- });
- }
-
- @override
- ir.Primitive visitIndexSetIfNull(
- ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, arg) {
- ir.Primitive target = visit(receiver);
- ir.Primitive indexValue = visit(index);
- return translateSetIfNull(
- node,
- () {
- Selector selector = new Selector.index();
- List<ir.Primitive> arguments = <ir.Primitive>[indexValue];
- CallStructure callStructure =
- normalizeDynamicArguments(selector.callStructure, arguments);
- return irBuilder.buildDynamicInvocation(
- target,
- new Selector(selector.kind, selector.memberName, callStructure),
- elements.getGetterTypeMaskInComplexSendSet(node),
- arguments,
- sourceInformationBuilder.buildCall(receiver, node));
- },
- rhs,
- (ir.Primitive result) {
- irBuilder.buildDynamicIndexSet(target, elements.getTypeMask(node),
- indexValue, result, sourceInformationBuilder.buildIndexSet(node));
- });
- }
-
- @override
- ir.Primitive handleDynamicSet(
- ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) {
- return irBuilder.buildDynamicSet(
- translateReceiver(receiver),
- new Selector.setter(name),
- elements.getTypeMask(node),
- visit(rhs),
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitIfNotNullDynamicPropertySet(
- ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) {
- ir.Primitive target = visit(receiver);
- return irBuilder.buildIfNotNullSend(
- target,
- nested(() => irBuilder.buildDynamicSet(
- target,
- new Selector.setter(name),
- elements.getTypeMask(node),
- visit(rhs),
- sourceInformationBuilder.buildAssignment(node))),
- sourceInformationBuilder.buildIf(node));
- }
-
- @override
- ir.Primitive handleLocalSet(
- ast.SendSet node, LocalElement element, ast.Node rhs, _) {
- ir.Primitive value = visit(rhs);
- value = checkTypeVsElement(value, element);
- return irBuilder.buildLocalVariableSet(
- element, value, sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive handleStaticFieldSet(
- ast.SendSet node, FieldElement field, ast.Node rhs, _) {
- ir.Primitive value = visit(rhs);
- irBuilder.addPrimitive(new ir.SetStatic(
- field, value, sourceInformationBuilder.buildAssignment(node)));
- return value;
- }
-
- @override
- ir.Primitive visitSuperFieldSet(
- ast.SendSet node, FieldElement field, ast.Node rhs, _) {
- return irBuilder.buildSuperFieldSet(
- field, visit(rhs), sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitSuperSetterSet(
- ast.SendSet node, FunctionElement setter, ast.Node rhs, _) {
- return irBuilder.buildSuperSetterSet(
- setter, visit(rhs), sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitUnresolvedSuperIndexSet(
- ast.Send node, Element element, ast.Node index, ast.Node rhs, arg) {
- return giveup(node, 'visitUnresolvedSuperIndexSet');
- }
-
- @override
- ir.Primitive handleStaticSetterSet(
- ast.SendSet node, FunctionElement setter, ast.Node rhs, _) {
- return irBuilder.buildStaticSetterSet(
- setter, visit(rhs), sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive handleTypeLiteralConstantCompounds(
- ast.SendSet node, ConstantExpression constant, CompoundRhs rhs, arg) {
- SourceInformation src = sourceInformationBuilder.buildGet(node);
- return translateCompounds(
- node,
- () {
- return buildConstantExpression(constant, src);
- },
- rhs,
- (ir.Primitive value) {
- // The binary operator will throw before this.
- });
- }
-
- @override
- ir.Primitive handleTypeLiteralConstantSetIfNulls(
- ast.SendSet node, ConstantExpression constant, ast.Node rhs, _) {
- // The type literal is never `null`.
- return buildConstantExpression(
- constant, sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive handleDynamicCompounds(
- ast.SendSet node, ast.Node receiver, Name name, CompoundRhs rhs, arg) {
- ir.Primitive target = translateReceiver(receiver);
- ir.Primitive helper() {
- return translateCompounds(
- node,
- () {
- return irBuilder.buildDynamicGet(
- target,
- new Selector.getter(name),
- elements.getGetterTypeMaskInComplexSendSet(node),
- sourceInformationBuilder.buildGet(node));
- },
- rhs,
- (ir.Primitive result) {
- irBuilder.buildDynamicSet(
- target,
- new Selector.setter(name),
- elements.getTypeMask(node),
- result,
- sourceInformationBuilder.buildAssignment(node));
- });
- }
- return node.isConditional
- ? irBuilder.buildIfNotNullSend(
- target, nested(helper), sourceInformationBuilder.buildIf(node))
- : helper();
- }
-
- @override
- ir.Primitive handleDynamicSetIfNulls(
- ast.Send node, ast.Node receiver, Name name, ast.Node rhs, _) {
- ir.Primitive target = translateReceiver(receiver);
- ir.Primitive helper() {
- return translateSetIfNull(
- node,
- () {
- return irBuilder.buildDynamicGet(
- target,
- new Selector.getter(name),
- elements.getGetterTypeMaskInComplexSendSet(node),
- sourceInformationBuilder.buildGet(node));
- },
- rhs,
- (ir.Primitive result) {
- irBuilder.buildDynamicSet(
- target,
- new Selector.setter(name),
- elements.getTypeMask(node),
- result,
- sourceInformationBuilder.buildAssignment(node));
- });
- }
- return node.isConditional
- ? irBuilder.buildIfNotNullSend(
- target, nested(helper), sourceInformationBuilder.buildIf(node))
- : helper();
- }
-
- ir.Primitive buildLocalNoSuchSetter(LocalElement local, ir.Primitive value,
- SourceInformation sourceInformation) {
- Selector selector = new Selector.setter(
- new Name(local.name, local.library, isSetter: true));
- return irBuilder.buildStaticNoSuchMethod(
- selector, [value], sourceInformation);
- }
-
- @override
- ir.Primitive handleLocalCompounds(
- ast.SendSet node, LocalElement local, CompoundRhs rhs, arg,
- {bool isSetterValid}) {
- return translateCompounds(
- node,
- () {
- return irBuilder.buildLocalGet(local);
- },
- rhs,
- (ir.Primitive result) {
- if (isSetterValid) {
- irBuilder.buildLocalVariableSet(
- local, result, sourceInformationBuilder.buildAssignment(node));
- } else {
- Selector selector = new Selector.setter(
- new Name(local.name, local.library, isSetter: true));
- irBuilder.buildStaticNoSuchMethod(selector, <ir.Primitive>[result],
- sourceInformationBuilder.buildAssignment(node));
- }
- });
- }
-
- @override
- ir.Primitive handleLocalSetIfNulls(
- ast.SendSet node, LocalElement local, ast.Node rhs, _,
- {bool isSetterValid}) {
- return translateSetIfNull(
- node,
- () {
- return irBuilder.buildLocalGet(local,
- sourceInformation: sourceInformationBuilder.buildGet(node));
- },
- rhs,
- (ir.Primitive result) {
- SourceInformation sourceInformation =
- sourceInformationBuilder.buildAssignment(node);
- if (isSetterValid) {
- irBuilder.buildLocalVariableSet(local, result, sourceInformation);
- } else {
- Selector selector = new Selector.setter(
- new Name(local.name, local.library, isSetter: true));
- irBuilder.buildStaticNoSuchMethod(
- selector, <ir.Primitive>[result], sourceInformation);
- }
- });
- }
-
- @override
- ir.Primitive handleStaticCompounds(
- ast.SendSet node,
- Element getter,
- CompoundGetter getterKind,
- Element setter,
- CompoundSetter setterKind,
- CompoundRhs rhs,
- arg) {
- return translateCompounds(
- node,
- () {
- SourceInformation sourceInformation =
- sourceInformationBuilder.buildGet(node);
- switch (getterKind) {
- case CompoundGetter.FIELD:
- return buildStaticFieldGet(getter, sourceInformation);
- case CompoundGetter.GETTER:
- return buildStaticGetterGet(getter, node, sourceInformation);
- case CompoundGetter.METHOD:
- return irBuilder.addPrimitive(new ir.GetStatic(getter,
- sourceInformation: sourceInformation, isFinal: true));
- case CompoundGetter.UNRESOLVED:
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.getter(new Name(getter.name, getter.library)),
- <ir.Primitive>[],
- sourceInformation);
- }
- },
- rhs,
- (ir.Primitive result) {
- SourceInformation sourceInformation =
- sourceInformationBuilder.buildAssignment(node);
- switch (setterKind) {
- case CompoundSetter.FIELD:
- irBuilder.addPrimitive(
- new ir.SetStatic(setter, result, sourceInformation));
- return;
- case CompoundSetter.SETTER:
- irBuilder.buildStaticSetterSet(setter, result, sourceInformation);
- return;
- case CompoundSetter.INVALID:
- irBuilder.buildStaticNoSuchMethod(
- new Selector.setter(new Name(setter.name, setter.library)),
- <ir.Primitive>[result],
- sourceInformation);
- return;
- }
- });
- }
-
- @override
- ir.Primitive handleStaticSetIfNulls(
- ast.SendSet node,
- Element getter,
- CompoundGetter getterKind,
- Element setter,
- CompoundSetter setterKind,
- ast.Node rhs,
- _) {
- return translateSetIfNull(
- node,
- () {
- SourceInformation sourceInformation =
- sourceInformationBuilder.buildGet(node);
- switch (getterKind) {
- case CompoundGetter.FIELD:
- return buildStaticFieldGet(getter, sourceInformation);
- case CompoundGetter.GETTER:
- return buildStaticGetterGet(getter, node, sourceInformation);
- case CompoundGetter.METHOD:
- return irBuilder.addPrimitive(new ir.GetStatic(getter,
- sourceInformation: sourceInformation, isFinal: true));
- case CompoundGetter.UNRESOLVED:
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.getter(new Name(getter.name, getter.library)),
- <ir.Primitive>[],
- sourceInformation);
- }
- },
- rhs,
- (ir.Primitive result) {
- SourceInformation sourceInformation =
- sourceInformationBuilder.buildAssignment(node);
- switch (setterKind) {
- case CompoundSetter.FIELD:
- irBuilder.addPrimitive(
- new ir.SetStatic(setter, result, sourceInformation));
- return;
- case CompoundSetter.SETTER:
- irBuilder.buildStaticSetterSet(setter, result, sourceInformation);
- return;
- case CompoundSetter.INVALID:
- irBuilder.buildStaticNoSuchMethod(
- new Selector.setter(new Name(setter.name, setter.library)),
- <ir.Primitive>[result],
- sourceInformation);
- return;
- }
- });
- }
-
- ir.Primitive buildSuperNoSuchGetter(
- Element element, TypeMask mask, SourceInformation sourceInformation) {
- return buildSuperNoSuchMethod(
- new Selector.getter(new Name(element.name, element.library)),
- mask,
- const <ir.Primitive>[],
- sourceInformation);
- }
-
- ir.Primitive buildSuperNoSuchSetter(Element element, TypeMask mask,
- ir.Primitive value, SourceInformation sourceInformation) {
- return buildSuperNoSuchMethod(
- new Selector.setter(new Name(element.name, element.library)),
- mask,
- <ir.Primitive>[value],
- sourceInformation);
- }
-
- @override
- ir.Primitive handleSuperCompounds(
- ast.SendSet node,
- Element getter,
- CompoundGetter getterKind,
- Element setter,
- CompoundSetter setterKind,
- CompoundRhs rhs,
- arg) {
- return translateCompounds(
- node,
- () {
- switch (getterKind) {
- case CompoundGetter.FIELD:
- return irBuilder.buildSuperFieldGet(
- getter, sourceInformationBuilder.buildGet(node));
- case CompoundGetter.GETTER:
- return irBuilder.buildSuperGetterGet(
- getter, sourceInformationBuilder.buildGet(node));
- case CompoundGetter.METHOD:
- return irBuilder.buildSuperMethodGet(
- getter, sourceInformationBuilder.buildGet(node));
- case CompoundGetter.UNRESOLVED:
- return buildSuperNoSuchGetter(
- getter,
- elements.getGetterTypeMaskInComplexSendSet(node),
- sourceInformationBuilder.buildGet(node));
- }
- },
- rhs,
- (ir.Primitive result) {
- switch (setterKind) {
- case CompoundSetter.FIELD:
- irBuilder.buildSuperFieldSet(setter, result,
- sourceInformationBuilder.buildAssignment(node));
- return;
- case CompoundSetter.SETTER:
- irBuilder.buildSuperSetterSet(setter, result,
- sourceInformationBuilder.buildAssignment(node));
- return;
- case CompoundSetter.INVALID:
- buildSuperNoSuchSetter(setter, elements.getTypeMask(node), result,
- sourceInformationBuilder.buildAssignment(node));
- return;
- }
- });
- }
-
- @override
- ir.Primitive handleSuperSetIfNulls(
- ast.SendSet node,
- Element getter,
- CompoundGetter getterKind,
- Element setter,
- CompoundSetter setterKind,
- ast.Node rhs,
- _) {
- return translateSetIfNull(
- node,
- () {
- switch (getterKind) {
- case CompoundGetter.FIELD:
- return irBuilder.buildSuperFieldGet(
- getter, sourceInformationBuilder.buildGet(node));
- case CompoundGetter.GETTER:
- return irBuilder.buildSuperGetterGet(
- getter, sourceInformationBuilder.buildGet(node));
- case CompoundGetter.METHOD:
- return irBuilder.buildSuperMethodGet(
- getter, sourceInformationBuilder.buildGet(node));
- case CompoundGetter.UNRESOLVED:
- return buildSuperNoSuchGetter(
- getter,
- elements.getGetterTypeMaskInComplexSendSet(node),
- sourceInformationBuilder.buildGet(node));
- }
- },
- rhs,
- (ir.Primitive result) {
- switch (setterKind) {
- case CompoundSetter.FIELD:
- irBuilder.buildSuperFieldSet(setter, result,
- sourceInformationBuilder.buildAssignment(node));
- return;
- case CompoundSetter.SETTER:
- irBuilder.buildSuperSetterSet(setter, result,
- sourceInformationBuilder.buildAssignment(node));
- return;
- case CompoundSetter.INVALID:
- buildSuperNoSuchSetter(setter, elements.getTypeMask(node), result,
- sourceInformationBuilder.buildAssignment(node));
- return;
- }
- });
- }
-
- @override
- ir.Primitive handleTypeVariableTypeLiteralCompounds(ast.SendSet node,
- TypeVariableElement typeVariable, CompoundRhs rhs, arg) {
- return translateCompounds(
- node,
- () {
- return irBuilder.buildReifyTypeVariable(
- typeVariable.type, sourceInformationBuilder.buildGet(node));
- },
- rhs,
- (ir.Primitive value) {
- // The binary operator will throw before this.
- });
- }
-
- @override
- ir.Primitive visitTypeVariableTypeLiteralSetIfNull(
- ast.Send node, TypeVariableElement element, ast.Node rhs, _) {
- // The type variable is never `null`.
- return translateTypeVariableTypeLiteral(
- element, sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive handleIndexCompounds(ast.SendSet node, ast.Node receiver,
- ast.Node index, CompoundRhs rhs, arg) {
- ir.Primitive target = visit(receiver);
- ir.Primitive indexValue = visit(index);
- return translateCompounds(
- node,
- () {
- Selector selector = new Selector.index();
- List<ir.Primitive> arguments = <ir.Primitive>[indexValue];
- CallStructure callStructure =
- normalizeDynamicArguments(selector.callStructure, arguments);
- return irBuilder.buildDynamicInvocation(
- target,
- new Selector(selector.kind, selector.memberName, callStructure),
- elements.getGetterTypeMaskInComplexSendSet(node),
- arguments,
- sourceInformationBuilder.buildCall(receiver, node));
- },
- rhs,
- (ir.Primitive result) {
- irBuilder.buildDynamicIndexSet(target, elements.getTypeMask(node),
- indexValue, result, sourceInformationBuilder.buildIndexSet(node));
- });
- }
-
- @override
- ir.Primitive handleSuperIndexCompounds(
- ast.SendSet node,
- Element indexFunction,
- Element indexSetFunction,
- ast.Node index,
- CompoundRhs rhs,
- arg,
- {bool isGetterValid,
- bool isSetterValid}) {
- ir.Primitive indexValue = visit(index);
- return translateCompounds(
- node,
- () {
- if (isGetterValid) {
- return irBuilder.buildSuperIndex(indexFunction, indexValue,
- sourceInformationBuilder.buildIndex(node));
- } else {
- return buildSuperNoSuchMethod(
- new Selector.index(),
- elements.getGetterTypeMaskInComplexSendSet(node),
- <ir.Primitive>[indexValue],
- sourceInformationBuilder.buildIndex(node));
- }
- },
- rhs,
- (ir.Primitive result) {
- if (isSetterValid) {
- irBuilder.buildSuperIndexSet(indexSetFunction, indexValue, result,
- sourceInformationBuilder.buildIndexSet(node));
- } else {
- buildSuperNoSuchMethod(
- new Selector.indexSet(),
- elements.getTypeMask(node),
- <ir.Primitive>[indexValue, result],
- sourceInformationBuilder.buildIndexSet(node));
- }
- });
- }
-
- /// Build code to handle foreign code, that is, native JavaScript code, or
- /// builtin values and operations of the backend.
- ir.Primitive handleForeignCode(ast.Send node, MethodElement function,
- ast.NodeList argumentList, CallStructure callStructure) {
- void validateArgumentCount({int minimum, int exactly}) {
- assert((minimum == null) != (exactly == null));
- int count = 0;
- int maximum;
- if (exactly != null) {
- minimum = exactly;
- maximum = exactly;
- }
- for (ast.Node argument in argumentList) {
- count++;
- if (maximum != null && count > maximum) {
- internalError(argument, 'Additional argument.');
- }
- }
- if (count < minimum) {
- internalError(node, 'Expected at least $minimum arguments.');
- }
- }
-
- /// Call a helper method from the isolate library. The isolate library uses
- /// its own isolate structure, that encapsulates dart2js's isolate.
- ir.Primitive buildIsolateHelperInvocation(
- MethodElement element, CallStructure callStructure) {
- if (element == null) {
- reporter.internalError(node, 'Isolate library and compiler mismatch.');
- }
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure = translateStaticArguments(
- argumentList, element, callStructure, arguments);
- Selector selector = new Selector.call(element.memberName, callStructure);
- return irBuilder.buildInvokeStatic(element, selector, arguments,
- sourceInformationBuilder.buildCall(node, node.selector));
- }
-
- /// Lookup the value of the enum described by [node].
- getEnumValue(ast.Node node, EnumClassElement enumClass, List values) {
- Element element = elements[node];
- if (element is! EnumConstantElement ||
- element.enclosingClass != enumClass) {
- internalError(node, 'expected a JsBuiltin enum value');
- }
- EnumConstantElement enumConstant = element;
- int index = enumConstant.index;
- return values[index];
- }
-
- /// Returns the String the node evaluates to, or throws an error if the
- /// result is not a string constant.
- String expectStringConstant(ast.Node node) {
- ir.Primitive nameValue = visit(node);
- if (nameValue is ir.Constant && nameValue.value.isString) {
- StringConstantValue constantValue = nameValue.value;
- return constantValue.primitiveValue.slowToString();
- } else {
- return internalError(node, 'expected a literal string');
- }
- }
-
- Link<ast.Node> argumentNodes = argumentList.nodes;
- NativeBehavior behavior = elements.getNativeData(node);
- switch (function.name) {
- case 'JS':
- validateArgumentCount(minimum: 2);
- // The first two arguments are the type and the foreign code template,
- // which already have been analyzed by the resolver and can be retrieved
- // using [NativeBehavior]. We can ignore these arguments in the backend.
- List<ir.Primitive> arguments =
- argumentNodes.skip(2).mapToList(visit, growable: false);
- if (behavior.codeTemplate.positionalArgumentCount != arguments.length) {
- reporter.reportErrorMessage(node, MessageKind.GENERIC, {
- 'text': 'Mismatch between number of placeholders'
- ' and number of arguments.'
- });
- return irBuilder.buildNullConstant();
- }
-
- if (HasCapturedPlaceholders.check(behavior.codeTemplate.ast)) {
- reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE);
- return irBuilder.buildNullConstant();
- }
-
- return irBuilder.buildForeignCode(behavior.codeTemplate, arguments,
- behavior, sourceInformationBuilder.buildForeignCode(node));
-
- case 'DART_CLOSURE_TO_JS':
- // TODO(ahe): This should probably take care to wrap the closure in
- // another closure that saves the current isolate.
- case 'RAW_DART_FUNCTION_REF':
- validateArgumentCount(exactly: 1);
-
- ast.Node argument = node.arguments.single;
- FunctionElement closure = elements[argument].implementation;
- if (!Elements.isStaticOrTopLevelFunction(closure)) {
- internalError(argument, 'only static or toplevel function supported');
- }
- if (closure.functionSignature.hasOptionalParameters) {
- internalError(
- argument, 'closures with optional parameters not supported');
- }
- return irBuilder.buildForeignCode(
- js.js.expressionTemplateYielding(
- backend.emitter.staticFunctionAccess(closure)),
- <ir.Primitive>[],
- NativeBehavior.PURE,
- sourceInformationBuilder.buildForeignCode(node),
- dependency: closure);
-
- case 'JS_BUILTIN':
- // The first argument is a description of the type and effect of the
- // builtin, which has already been analyzed in the frontend. The second
- // argument must be a [JsBuiltin] value. All other arguments are
- // values used by the JavaScript template that is associated with the
- // builtin.
- validateArgumentCount(minimum: 2);
-
- ast.Node builtin = argumentNodes.tail.head;
- JsBuiltin value =
- getEnumValue(builtin, helpers.jsBuiltinEnum, JsBuiltin.values);
- js.Template template = backend.emitter.builtinTemplateFor(value);
- List<ir.Primitive> arguments =
- argumentNodes.skip(2).mapToList(visit, growable: false);
- return irBuilder.buildForeignCode(template, arguments, behavior,
- sourceInformationBuilder.buildForeignCode(node));
-
- case 'JS_EMBEDDED_GLOBAL':
- validateArgumentCount(exactly: 2);
-
- String name = expectStringConstant(argumentNodes.tail.head);
- js.Expression access =
- backend.emitter.generateEmbeddedGlobalAccess(name);
- js.Template template = js.js.expressionTemplateYielding(access);
- return irBuilder.buildForeignCode(template, <ir.Primitive>[], behavior,
- sourceInformationBuilder.buildForeignCode(node));
-
- case 'JS_INTERCEPTOR_CONSTANT':
- validateArgumentCount(exactly: 1);
-
- ast.Node argument = argumentNodes.head;
- ir.Primitive argumentValue = visit(argument);
- if (argumentValue is ir.Constant && argumentValue.value.isType) {
- TypeConstantValue constant = argumentValue.value;
- ConstantValue interceptorValue =
- new InterceptorConstantValue(constant.representedType);
- return irBuilder.buildConstant(interceptorValue);
- }
- return internalError(argument, 'expected Type as argument');
-
- case 'JS_EFFECT':
- return irBuilder.buildNullConstant();
-
- case 'JS_GET_NAME':
- validateArgumentCount(exactly: 1);
-
- ast.Node argument = argumentNodes.head;
- JsGetName id =
- getEnumValue(argument, helpers.jsGetNameEnum, JsGetName.values);
- js.Name name = backend.namer.getNameForJsGetName(argument, id);
- ConstantValue nameConstant = new SyntheticConstantValue(
- SyntheticConstantKind.NAME, js.js.quoteName(name));
-
- return irBuilder.buildConstant(nameConstant);
-
- case 'JS_GET_FLAG':
- validateArgumentCount(exactly: 1);
-
- String name = expectStringConstant(argumentNodes.first);
- bool value = false;
- switch (name) {
- case 'MUST_RETAIN_METADATA':
- value = backend.mustRetainMetadata;
- break;
- case 'USE_CONTENT_SECURITY_POLICY':
- value = compiler.options.useContentSecurityPolicy;
- break;
- default:
- internalError(node, 'Unknown internal flag "$name".');
- }
- return irBuilder.buildBooleanConstant(value);
-
- case 'JS_STRING_CONCAT':
- validateArgumentCount(exactly: 2);
- List<ir.Primitive> arguments = argumentNodes.mapToList(visit);
- return irBuilder.buildStringConcatenation(
- arguments, sourceInformationBuilder.buildForeignCode(node));
-
- case 'JS_CURRENT_ISOLATE_CONTEXT':
- validateArgumentCount(exactly: 0);
-
- if (!compiler.hasIsolateSupport) {
- // If the isolate library is not used, we just generate code
- // to fetch the current isolate.
- continue getStaticState;
- }
- return buildIsolateHelperInvocation(
- helpers.currentIsolate, CallStructure.NO_ARGS);
-
- getStaticState: case 'JS_GET_STATIC_STATE':
- validateArgumentCount(exactly: 0);
-
- return irBuilder.buildForeignCode(
- js.js.parseForeignJS(backend.namer.staticStateHolder),
- const <ir.Primitive>[],
- NativeBehavior.DEPENDS_OTHER,
- sourceInformationBuilder.buildForeignCode(node));
-
- case 'JS_SET_STATIC_STATE':
- validateArgumentCount(exactly: 1);
-
- ir.Primitive value = visit(argumentNodes.single);
- String isolateName = backend.namer.staticStateHolder;
- return irBuilder.buildForeignCode(
- js.js.parseForeignJS("$isolateName = #"),
- <ir.Primitive>[value],
- NativeBehavior.CHANGES_OTHER,
- sourceInformationBuilder.buildForeignCode(node));
-
- case 'JS_CALL_IN_ISOLATE':
- validateArgumentCount(exactly: 2);
-
- if (!compiler.hasIsolateSupport) {
- ir.Primitive closure = visit(argumentNodes.tail.head);
- return irBuilder.buildCallInvocation(
- closure,
- CallStructure.NO_ARGS,
- const <ir.Primitive>[],
- sourceInformationBuilder.buildForeignCode(node));
- }
- return buildIsolateHelperInvocation(
- helpers.callInIsolate, CallStructure.TWO_ARGS);
-
- default:
- return giveup(node, 'unplemented native construct: ${function.name}');
- }
- }
-
- /// Evaluates a string interpolation and appends each part to [accumulator]
- /// (after stringify conversion).
- void buildStringParts(ast.Node node, List<ir.Primitive> accumulator) {
- if (node is ast.StringJuxtaposition) {
- buildStringParts(node.first, accumulator);
- buildStringParts(node.second, accumulator);
- } else if (node is ast.StringInterpolation) {
- buildStringParts(node.string, accumulator);
- for (ast.StringInterpolationPart part in node.parts) {
- buildStringParts(part.expression, accumulator);
- buildStringParts(part.string, accumulator);
- }
- } else if (node is ast.LiteralString) {
- // Empty strings often occur at the end of a string interpolation,
- // do not bother to include them.
- if (!node.dartString.isEmpty) {
- accumulator.add(irBuilder.buildDartStringConstant(node.dartString));
- }
- } else if (node is ast.ParenthesizedExpression) {
- buildStringParts(node.expression, accumulator);
- } else {
- ir.Primitive value = visit(node);
- accumulator.add(irBuilder.buildStaticFunctionInvocation(
- helpers.stringInterpolationHelper,
- <ir.Primitive>[value],
- sourceInformationBuilder.buildStringInterpolation(node)));
- }
- }
-
- ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) {
- assert(irBuilder.isOpen);
- List<ir.Primitive> parts = <ir.Primitive>[];
- buildStringParts(node, parts);
- return irBuilder.buildStringConcatenation(
- parts, sourceInformationBuilder.buildStringInterpolation(node));
- }
-
- ir.Primitive visitStringInterpolation(ast.StringInterpolation node) {
- assert(irBuilder.isOpen);
- List<ir.Primitive> parts = <ir.Primitive>[];
- buildStringParts(node, parts);
- return irBuilder.buildStringConcatenation(
- parts, sourceInformationBuilder.buildStringInterpolation(node));
- }
-
- ir.Primitive translateConstant(ast.Node node) {
- assert(irBuilder.isOpen);
- return irBuilder.buildConstant(getConstantForNode(node),
- sourceInformation: sourceInformationBuilder.buildGet(node));
- }
-
- ir.Primitive visitThrow(ast.Throw node) {
- assert(irBuilder.isOpen);
- // This function is not called for throw expressions occurring as
- // statements.
- return irBuilder.buildNonTailThrow(visit(node.expression));
- }
-
- ir.Primitive buildSuperNoSuchMethod(Selector selector, TypeMask mask,
- List<ir.Primitive> arguments, SourceInformation sourceInformation) {
- ClassElement cls = elements.analyzedElement.enclosingClass;
- MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_);
- if (!Selectors.noSuchMethod_.signatureApplies(element)) {
- element = compiler.coreClasses.objectClass
- .lookupMember(Identifiers.noSuchMethod_);
- }
- return irBuilder.buildSuperMethodInvocation(
- element,
- Selectors.noSuchMethod_.callStructure,
- [irBuilder.buildInvocationMirror(selector, arguments)],
- sourceInformation);
- }
-
- @override
- ir.Primitive visitUnresolvedCompound(ast.Send node, Element element,
- op.AssignmentOperator operator, ast.Node rhs, _) {
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.getter(new Name(element.name, element.library)),
- [],
- sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive visitUnresolvedClassConstructorInvoke(
- ast.NewExpression node,
- Element element,
- DartType type,
- ast.NodeList arguments,
- Selector selector,
- _) {
- // If the class is missing it's a runtime error.
- ir.Primitive message =
- irBuilder.buildStringConstant("Unresolved class: '${element.name}'");
- return irBuilder.buildStaticFunctionInvocation(helpers.throwRuntimeError,
- <ir.Primitive>[message], sourceInformationBuilder.buildNew(node));
- }
-
- @override
- ir.Primitive visitUnresolvedConstructorInvoke(
- ast.NewExpression node,
- Element constructor,
- DartType type,
- ast.NodeList argumentsNode,
- Selector selector,
- _) {
- // If the class is there but the constructor is missing, it's an NSM error.
- List<ir.Primitive> arguments = <ir.Primitive>[];
- CallStructure callStructure = translateDynamicArguments(
- argumentsNode, selector.callStructure, arguments);
- return irBuilder.buildStaticNoSuchMethod(
- new Selector(selector.kind, selector.memberName, callStructure),
- arguments,
- sourceInformationBuilder.buildNew(node));
- }
-
- @override
- ir.Primitive visitConstructorIncompatibleInvoke(
- ast.NewExpression node,
- ConstructorElement constructor,
- DartType type,
- ast.NodeList argumentsNode,
- CallStructure callStructure,
- _) {
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure =
- translateDynamicArguments(argumentsNode, callStructure, arguments);
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.call(constructor.memberName, callStructure),
- arguments,
- sourceInformationBuilder.buildNew(node));
- }
-
- @override
- ir.Primitive visitUnresolvedGet(ast.Send node, Element element, _) {
- return irBuilder.buildStaticNoSuchMethod(elements.getSelector(node), [],
- sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive visitUnresolvedInvoke(ast.Send node, Element element,
- ast.NodeList arguments, Selector selector, _) {
- return irBuilder.buildStaticNoSuchMethod(
- elements.getSelector(node),
- arguments.nodes.mapToList(visit),
- sourceInformationBuilder.buildCall(node, node.selector));
- }
-
- @override
- ir.Primitive visitUnresolvedRedirectingFactoryConstructorInvoke(
- ast.NewExpression node,
- ConstructorElement constructor,
- InterfaceType type,
- ast.NodeList argumentsNode,
- CallStructure callStructure,
- _) {
- String nameString = Elements.reconstructConstructorName(constructor);
- Name name = new Name(nameString, constructor.library);
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure =
- translateDynamicArguments(argumentsNode, callStructure, arguments);
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.call(name, callStructure),
- arguments,
- sourceInformationBuilder.buildNew(node));
- }
-
- @override
- ir.Primitive visitUnresolvedSet(
- ast.Send node, Element element, ast.Node rhs, _) {
- return irBuilder.buildStaticNoSuchMethod(elements.getSelector(node),
- [visit(rhs)], sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitUnresolvedSuperIndex(
- ast.Send node, Element function, ast.Node index, _) {
- // Assume the index getter is missing.
- return buildSuperNoSuchMethod(
- new Selector.index(),
- elements.getTypeMask(node),
- [visit(index)],
- sourceInformationBuilder.buildIndex(node));
- }
-
- @override
- ir.Primitive visitUnresolvedSuperBinary(ast.Send node, Element element,
- op.BinaryOperator operator, ast.Node argument, _) {
- return buildSuperNoSuchMethod(
- elements.getSelector(node),
- elements.getTypeMask(node),
- [visit(argument)],
- sourceInformationBuilder.buildCall(node, node.selector));
- }
-
- @override
- ir.Primitive visitUnresolvedSuperUnary(
- ast.Send node, op.UnaryOperator operator, Element element, _) {
- return buildSuperNoSuchMethod(
- elements.getSelector(node),
- elements.getTypeMask(node),
- [],
- sourceInformationBuilder.buildCall(node, node.selector));
- }
-
- @override
- ir.Primitive bulkHandleNode(ast.Node node, String message, _) {
- return giveup(node, "Unhandled node: ${message.replaceAll('#', '$node')}");
- }
-
- @override
- ir.Primitive bulkHandleError(ast.Node node, ErroneousElement error, _) {
- return irBuilder.buildNullConstant();
- }
-
- @override
- ir.Primitive visitClassTypeLiteralSet(
- ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) {
- InterfaceType type = constant.type;
- ClassElement element = type.element;
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.setter(element.memberName),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitTypedefTypeLiteralSet(
- ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) {
- TypedefType type = constant.type;
- TypedefElement element = type.element;
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.setter(element.memberName),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitTypeVariableTypeLiteralSet(
- ast.SendSet node, TypeVariableElement element, ast.Node rhs, _) {
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.setter(element.memberName),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitDynamicTypeLiteralSet(
- ast.SendSet node, ConstantExpression constant, ast.Node rhs, _) {
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.setter(Names.dynamic_),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitAbstractClassConstructorInvoke(
- ast.NewExpression node,
- ConstructorElement element,
- InterfaceType type,
- ast.NodeList arguments,
- CallStructure callStructure,
- _) {
- for (ast.Node argument in arguments) visit(argument);
- ir.Primitive name =
- irBuilder.buildStringConstant(element.enclosingClass.name);
- return irBuilder.buildStaticFunctionInvocation(
- helpers.throwAbstractClassInstantiationError,
- <ir.Primitive>[name],
- sourceInformationBuilder.buildNew(node));
- }
-
- @override
- ir.Primitive handleFinalStaticFieldSet(
- ast.SendSet node, FieldElement field, ast.Node rhs, _) {
- // TODO(asgerf): Include class name somehow for static class members?
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.setter(field.memberName),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitFinalSuperFieldSet(
- ast.SendSet node, FieldElement field, ast.Node rhs, _) {
- return buildSuperNoSuchMethod(
- new Selector.setter(field.memberName),
- elements.getTypeMask(node),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive handleImmutableLocalSet(
- ast.SendSet node, LocalElement local, ast.Node rhs, _) {
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.setter(new Name(local.name, local.library)),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive handleStaticFunctionSet(
- ast.Send node, MethodElement function, ast.Node rhs, _) {
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.setter(function.memberName),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive handleStaticGetterSet(
- ast.SendSet node, GetterElement getter, ast.Node rhs, _) {
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.setter(getter.memberName),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive handleStaticSetterGet(ast.Send node, SetterElement setter, _) {
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.getter(setter.memberName),
- [],
- sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive handleStaticSetterInvoke(ast.Send node, SetterElement setter,
- ast.NodeList argumentsNode, CallStructure callStructure, _) {
- // Translate as a method call.
- List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit);
- return irBuilder.buildStaticNoSuchMethod(
- new Selector.call(setter.memberName, callStructure),
- arguments,
- sourceInformationBuilder.buildCall(node, argumentsNode));
- }
-
- @override
- ir.Primitive visitSuperGetterSet(
- ast.SendSet node, GetterElement getter, ast.Node rhs, _) {
- return buildSuperNoSuchMethod(
- new Selector.setter(getter.memberName),
- elements.getTypeMask(node),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitSuperMethodSet(
- ast.Send node, MethodElement method, ast.Node rhs, _) {
- return buildSuperNoSuchMethod(
- new Selector.setter(method.memberName),
- elements.getTypeMask(node),
- [visit(rhs)],
- sourceInformationBuilder.buildAssignment(node));
- }
-
- @override
- ir.Primitive visitSuperSetterGet(ast.Send node, SetterElement setter, _) {
- return buildSuperNoSuchMethod(
- new Selector.getter(setter.memberName),
- elements.getTypeMask(node),
- [],
- sourceInformationBuilder.buildGet(node));
- }
-
- @override
- ir.Primitive visitSuperSetterInvoke(ast.Send node, SetterElement setter,
- ast.NodeList argumentsNode, CallStructure callStructure, _) {
- List<ir.Primitive> arguments = <ir.Primitive>[];
- callStructure =
- translateDynamicArguments(argumentsNode, callStructure, arguments);
- return buildSuperNoSuchMethod(
- new Selector.call(setter.memberName, callStructure),
- elements.getTypeMask(node),
- arguments,
- sourceInformationBuilder.buildCall(node, argumentsNode));
- }
-
- ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) {
- try {
- return action();
- } catch (e) {
- if (e == ABORT_IRNODE_BUILDER) {
- return null;
- }
- rethrow;
- }
- }
-
- internalError(ast.Node node, String message) {
- reporter.internalError(node, message);
- }
-
- @override
- visitNode(ast.Node node) {
- giveup(node, "Unhandled node");
- }
-
- dynamic giveup(ast.Node node, [String reason]) {
- bailoutMessage = '($node): $reason';
- throw ABORT_IRNODE_BUILDER;
- }
-}
-
-final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
-
-/// Determines which local variables should be boxed in a mutable variable
-/// inside a given try block.
-class TryBoxedVariables extends ast.Visitor {
- final TreeElements elements;
- TryBoxedVariables(this.elements);
-
- FunctionElement currentFunction;
- bool insideInitializer = false;
- Set<Local> capturedVariables = new Set<Local>();
-
- /// A map containing variables boxed inside try blocks.
- ///
- /// The map is keyed by the [NodeList] of catch clauses for try/catch and
- /// by the finally block for try/finally. try/catch/finally is treated
- /// as a try/catch nested in the try block of a try/finally.
- Map<ast.Node, TryStatementInfo> tryStatements =
- <ast.Node, TryStatementInfo>{};
-
- List<TryStatementInfo> tryNestingStack = <TryStatementInfo>[];
- bool get inTryStatement => tryNestingStack.isNotEmpty;
-
- String bailoutMessage = null;
-
- giveup(ast.Node node, [String reason]) {
- bailoutMessage = '($node): $reason';
- throw ABORT_IRNODE_BUILDER;
- }
-
- void markAsCaptured(Local local) {
- capturedVariables.add(local);
- }
-
- analyze(ast.Node node) {
- visit(node);
- // Variables that are captured by a closure are boxed for their entire
- // lifetime, so they never need to be boxed on entry to a try block.
- // They are not filtered out before this because we cannot identify all
- // of them in the same pass (they may be captured by a closure after the
- // try statement).
- for (TryStatementInfo info in tryStatements.values) {
- info.boxedOnEntry.removeAll(capturedVariables);
- }
- }
-
- visit(ast.Node node) => node.accept(this);
-
- visitNode(ast.Node node) {
- node.visitChildren(this);
- }
-
- void handleSend(ast.Send node) {
- Element element = elements[node];
- if (Elements.isLocal(element) &&
- !element.isConst &&
- element.enclosingElement != currentFunction) {
- LocalElement local = element;
- markAsCaptured(local);
- }
- }
-
- visitSend(ast.Send node) {
- handleSend(node);
- node.visitChildren(this);
- }
-
- visitSendSet(ast.SendSet node) {
- handleSend(node);
- Element element = elements[node];
- if (Elements.isLocal(element)) {
- LocalElement local = element;
- if (insideInitializer &&
- (local.isRegularParameter || local.isInitializingFormal) &&
- local.enclosingElement == currentFunction) {
- assert(local.enclosingElement.isConstructor);
- // Initializers in an initializer-list can communicate via parameters.
- // If a parameter is stored in an initializer list we box it.
- // TODO(sigurdm): Fix this.
- // Though these variables do not outlive the activation of the
- // function, they still need to be boxed. As a simplification, we
- // treat them as if they are captured by a closure (i.e., they do
- // outlive the activation of the function).
- markAsCaptured(local);
- } else if (inTryStatement) {
- assert(local.isRegularParameter ||
- local.isVariable ||
- local.isInitializingFormal);
- // Search for the position of the try block containing the variable
- // declaration, or -1 if it is declared outside the outermost try.
- int i = tryNestingStack.length - 1;
- while (i >= 0 && !tryNestingStack[i].declared.contains(local)) {
- --i;
- }
- // If there is a next inner try, then the variable should be boxed on
- // entry to it.
- if (i + 1 < tryNestingStack.length) {
- tryNestingStack[i + 1].boxedOnEntry.add(local);
- }
- }
- }
- node.visitChildren(this);
- }
-
- visitFunctionExpression(ast.FunctionExpression node) {
- FunctionElement savedFunction = currentFunction;
- currentFunction = elements[node];
-
- if (currentFunction.asyncMarker != AsyncMarker.SYNC &&
- currentFunction.asyncMarker != AsyncMarker.SYNC_STAR &&
- currentFunction.asyncMarker != AsyncMarker.ASYNC) {
- giveup(node, "cannot handle async* functions");
- }
-
- if (node.initializers != null) {
- visit(node.initializers);
- }
- visit(node.body);
- currentFunction = savedFunction;
- }
-
- visitTryStatement(ast.TryStatement node) {
- // Try/catch/finally is treated as two simpler constructs: try/catch and
- // try/finally. The encoding is:
- //
- // try S0 catch (ex, st) S1 finally S2
- // ==>
- // try { try S0 catch (ex, st) S1 } finally S2
- //
- // The analysis associates variables assigned in S0 with the catch clauses
- // and variables assigned in S0 and S1 with the finally block.
- TryStatementInfo enterTryFor(ast.Node node) {
- TryStatementInfo info = new TryStatementInfo();
- tryStatements[node] = info;
- tryNestingStack.add(info);
- return info;
- }
- void leaveTryFor(TryStatementInfo info) {
- assert(tryNestingStack.last == info);
- tryNestingStack.removeLast();
- }
- bool hasCatch = !node.catchBlocks.isEmpty;
- bool hasFinally = node.finallyBlock != null;
- TryStatementInfo catchInfo, finallyInfo;
- // There is a nesting stack of try blocks, so the outer try/finally block
- // is added first.
- if (hasFinally) finallyInfo = enterTryFor(node.finallyBlock);
- if (hasCatch) catchInfo = enterTryFor(node.catchBlocks);
- visit(node.tryBlock);
-
- if (hasCatch) {
- leaveTryFor(catchInfo);
- visit(node.catchBlocks);
- }
- if (hasFinally) {
- leaveTryFor(finallyInfo);
- visit(node.finallyBlock);
- }
- }
-
- visitVariableDefinitions(ast.VariableDefinitions node) {
- if (inTryStatement) {
- for (ast.Node definition in node.definitions.nodes) {
- LocalVariableElement local = elements[definition];
- assert(local != null);
- // In the closure conversion pass we check for isInitializingFormal,
- // but I'm not sure it can arise.
- assert(!local.isInitializingFormal);
- tryNestingStack.last.declared.add(local);
- }
- }
- node.visitChildren(this);
- }
-}
-
-/// The [IrBuilder]s view on the information about the program that has been
-/// computed in resolution and and type interence.
-class GlobalProgramInformation {
- final Compiler _compiler;
- JavaScriptBackend get _backend => _compiler.backend;
-
- GlobalProgramInformation(this._compiler);
-
- /// Returns [true], if the analysis could not determine that the type
- /// arguments for the class [cls] are never used in the program.
- bool requiresRuntimeTypesFor(ClassElement cls) {
- return cls.typeVariables.isNotEmpty && _backend.classNeedsRti(cls);
- }
-
- FunctionElement get throwTypeErrorHelper => _backend.helpers.throwTypeError;
- Element get throwNoSuchMethod => _backend.helpers.throwNoSuchMethod;
-
- ClassElement get nullClass => _compiler.coreClasses.nullClass;
-
- DartType unaliasType(DartType type) => type.unaliased;
-
- TypeMask getTypeMaskForForeign(NativeBehavior behavior) {
- if (behavior == null) {
- return _backend.dynamicType;
- }
- return TypeMaskFactory.fromNativeBehavior(behavior, _compiler);
- }
-
- bool isArrayType(TypeMask type) {
- return type.satisfies(_backend.helpers.jsArrayClass, _compiler.world);
- }
-
- TypeMask getTypeMaskForNativeFunction(FunctionElement function) {
- return _compiler.typesTask.getGuaranteedReturnTypeOfElement(function);
- }
-
- FieldElement locateSingleField(Selector selector, TypeMask type) {
- return _compiler.world.locateSingleField(selector, type);
- }
-
- bool fieldNeverChanges(FieldElement field) {
- return _compiler.world.fieldNeverChanges(field);
- }
-
- Element get closureConverter {
- return _backend.helpers.closureConverter;
- }
-
- void addNativeMethod(FunctionElement function) {
- _backend.emitter.nativeEmitter.nativeMethods.add(function);
- }
-
- bool get trustJSInteropTypeAnnotations =>
- _compiler.options.trustJSInteropTypeAnnotations;
-
- bool isNative(ClassElement element) => _backend.isNative(element);
-
- bool isJsInterop(FunctionElement element) => _backend.isJsInterop(element);
-
- bool isJsInteropAnonymous(FunctionElement element) =>
- _backend.jsInteropAnalysis.hasAnonymousAnnotation(element.contextClass);
-
- String getJsInteropTargetPath(FunctionElement element) {
- return '${_backend.namer.fixedBackendPath(element)}.'
- '${_backend.nativeData.getFixedBackendName(element)}';
- }
-
- DartType get jsJavascriptObjectType =>
- _backend.helpers.jsJavaScriptObjectClass.thisType;
-}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
deleted file mode 100644
index 6363c88..0000000
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
+++ /dev/null
@@ -1,276 +0,0 @@
-library dart2js.cps_ir_integrity;
-
-import '../tracer.dart' as tracer;
-import 'cps_ir_nodes.dart';
-import 'cps_ir_nodes_sexpr.dart';
-
-/// Dump S-expressions on error if the tracer is enabled.
-///
-/// Technically this has nothing to do with the tracer, but if you want one
-/// enabled, you typically want the other as well, so we use the same flag.
-const bool ENABLE_DUMP = tracer.TRACE_FILTER_PATTERN != null;
-
-enum ScopeType { InScope, InDefinition, NotInScope }
-
-/// Performs integrity checks on the CPS IR.
-///
-/// To be run for debugging purposes, not for use in production.
-///
-/// The following integrity checks are performed:
-///
-/// - References are in scope of their definitions.
-/// - Recursive Continuations and InvokeContinuations are marked as recursive.
-/// - InvokeContinuations have the same arity as their target.
-/// - Reference chains are valid doubly-linked lists.
-/// - Reference chains contain exactly the references that are in the IR.
-/// - Each definition object occurs only once in the IR (no redeclaring).
-/// - Each reference object occurs only once in the IR (no sharing).
-///
-class CheckCpsIntegrity extends TrampolineRecursiveVisitor {
- FunctionDefinition topLevelNode;
- final Map<Definition, ScopeType> inScope = <Definition, ScopeType>{};
- final List<Definition> definitions = [];
- String previousPass;
-
- void handleDeclaration(Definition def) {
- definitions.add(def);
- // Check the reference chain for cycles broken links.
- Reference anchor = null;
- int i = 0;
- for (Reference ref = def.firstRef; ref != null; ref = ref.next) {
- if (ref.definition != def) {
- error(
- 'Reference to ${ref.definition} found in '
- 'reference chain for $def',
- def);
- }
- if (ref == anchor) {
- error('Cyclic reference chain for $def', def);
- }
- if (i & ++i == 0) {
- // Move the anchor every 2^Nth step.
- anchor = ref;
- }
- }
- }
-
- void enterScope(Iterable<Definition> definitions) {
- for (Definition def in definitions) {
- inScope[def] = ScopeType.InScope;
- }
- pushAction(() {
- for (Definition def in definitions) {
- inScope[def] = ScopeType.NotInScope;
- }
- });
- }
-
- void enterContinuation(Continuation cont) {
- inScope[cont] = ScopeType.InDefinition;
- pushAction(() {
- inScope[cont] = ScopeType.NotInScope;
- });
- }
-
- void check(FunctionDefinition node, String previousPass) {
- // [check] will be called multiple times per instance to avoid reallocating
- // the large [inScope] map. Reset the other fields.
- this.topLevelNode = node;
- this.previousPass = previousPass;
- this.definitions.clear();
- ParentChecker.checkParents(node, this);
- visit(node);
- // Check for broken reference chains. We check this last, so out-of-scope
- // references are not classified as a broken reference chain.
- definitions.forEach(checkReferenceChain);
- }
-
- @override
- Expression traverseLetCont(LetCont node) {
- node.continuations.forEach(handleDeclaration);
- node.continuations.forEach(push);
-
- // Put all continuations in scope when visiting the body.
- enterScope(node.continuations);
-
- return node.body;
- }
-
- @override
- Expression traverseLetPrim(LetPrim node) {
- handleDeclaration(node.primitive);
-
- // Process references in the primitive.
- visit(node.primitive);
-
- // Put the primitive in scope when visiting the body.
- enterScope([node.primitive]);
-
- return node.body;
- }
-
- @override
- Expression traverseLetMutable(LetMutable node) {
- handleDeclaration(node.variable);
- processReference(node.valueRef);
-
- // Put the primitive in scope when visiting the body.
- enterScope([node.variable]);
-
- return node.body;
- }
-
- @override
- Expression traverseContinuation(Continuation cont) {
- if (cont.isReturnContinuation) {
- error('Non-return continuation missing body', cont);
- }
- cont.parameters.forEach(handleDeclaration);
- enterScope(cont.parameters);
- // Put every continuation in scope at its own body. The isRecursive
- // flag is checked explicitly using [insideContinuations].
- enterScope([cont]);
- enterContinuation(cont);
- return cont.body;
- }
-
- @override
- visitFunctionDefinition(FunctionDefinition node) {
- if (node.interceptorParameter != null) {
- handleDeclaration(node.interceptorParameter);
- enterScope([node.interceptorParameter]);
- }
- if (node.receiverParameter != null) {
- handleDeclaration(node.receiverParameter);
- enterScope([node.receiverParameter]);
- }
- node.parameters.forEach(handleDeclaration);
- enterScope(node.parameters);
- handleDeclaration(node.returnContinuation);
- enterScope([node.returnContinuation]);
- if (!node.returnContinuation.isReturnContinuation) {
- error('Return continuation with a body', node);
- }
- visit(node.body);
- }
-
- @override
- processReference(Reference ref) {
- Definition def = ref.definition;
- if (inScope[def] == ScopeType.NotInScope) {
- error('Referenced out of scope: $def', ref);
- }
- if (ref.previous == ref) {
- error('Shared Reference object to $def', ref);
- }
- if (ref.previous == null && def.firstRef != ref ||
- ref.previous != null && ref.previous.next != ref) {
- error('Broken .previous link in reference to $def', def);
- }
- ref.previous = ref; // Mark reference as "seen". We will repair it later.
- }
-
- @override
- processInvokeContinuation(InvokeContinuation node) {
- Continuation target = node.continuation;
- if (node.isRecursive && inScope[target] == ScopeType.InScope) {
- error('Non-recursive InvokeContinuation marked as recursive', node);
- }
- if (!node.isRecursive && inScope[target] == ScopeType.InDefinition) {
- error('Recursive InvokeContinuation marked as non-recursive', node);
- }
- if (node.isRecursive && !target.isRecursive) {
- error('Recursive Continuation was not marked as recursive', node);
- }
- if (node.argumentRefs.length != target.parameters.length) {
- error('Arity mismatch in InvokeContinuation', node);
- }
- }
-
- @override
- processInvokeMethod(InvokeMethod node) {
- if (node.callingConvention == CallingConvention.Intercepted) {
- if (node.interceptorRef == null) {
- error('No interceptor on intercepted call', node);
- }
- } else {
- if (node.interceptorRef != null) {
- error('Interceptor on call with ${node.callingConvention}', node);
- }
- }
- }
-
- void checkReferenceChain(Definition def) {
- Reference previous = null;
- for (Reference ref = def.firstRef; ref != null; ref = ref.next) {
- if (ref.previous != ref) {
- // Reference was not seen during IR traversal, so it is orphaned.
- error('Orphaned reference in reference chain for $def', def);
- }
- // Repair the .previous link that was used for marking.
- ref.previous = previous;
- previous = ref;
- }
- }
-
- error(String message, node) {
- String sexpr;
- if (ENABLE_DUMP) {
- try {
- Decorator decorator = (n, String s) => n == node ? '**$s**' : s;
- sexpr = new SExpressionStringifier(decorator).visit(topLevelNode);
- sexpr = 'SExpr dump (offending node marked with **):\n\n$sexpr';
- } catch (e) {
- sexpr = '(Exception thrown by SExpressionStringifier: $e)';
- }
- } else {
- sexpr = '(Set DUMP_IR flag to enable SExpr dump)';
- }
- throw 'CPS integrity violation\n'
- 'After \'$previousPass\' on ${topLevelNode.element}\n'
- '$message\n\n'
- '$sexpr\n';
- }
-}
-
-/// Traverses the CPS term and checks that node.parent is correctly set
-/// for each visited node.
-class ParentChecker extends DeepRecursiveVisitor {
- static void checkParents(Node node, CheckCpsIntegrity main) {
- ParentChecker visitor = new ParentChecker._make(main);
- visitor._worklist.add(node);
- visitor.trampoline();
- }
-
- ParentChecker._make(this.main);
-
- Node _parent;
- final List<Node> _worklist = <Node>[];
- final CheckCpsIntegrity main;
-
- void trampoline() {
- while (_worklist.isNotEmpty) {
- _parent = _worklist.removeLast();
- _parent.accept(this);
- }
- }
-
- error(String message, node) => main.error(message, node);
-
- @override
- visit(Node node) {
- _worklist.add(node);
- if (node.parent != _parent) {
- error('Parent pointer on $node is ${node.parent} but should be $_parent',
- node);
- }
- }
-
- @override
- processReference(Reference node) {
- if (node.parent != _parent) {
- error('Parent pointer on $node is ${node.parent} but should be $_parent',
- 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
deleted file mode 100644
index 7ba13c8..0000000
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ /dev/null
@@ -1,3123 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-library dart2js.ir_nodes;
-
-import 'dart:collection';
-import 'cps_fragment.dart' show CpsFragment;
-import 'cps_ir_nodes_sexpr.dart';
-import '../constants/values.dart' as values;
-import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType;
-import '../elements/elements.dart';
-import '../io/source_information.dart' show SourceInformation;
-import '../types/types.dart' show TypeMask;
-import '../universe/selector.dart' show Selector;
-
-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.
-import '../js/js.dart' as js show Template, isNullGuardOnFirstArgument;
-import '../native/native.dart' as native show NativeBehavior;
-
-abstract class Node {
- /// A pointer to the parent node. Is null until set by optimization passes.
- Node parent;
-
- /// Workaround for a slow Object.hashCode in the VM.
- static int _usedHashCodes = 0;
- final int hashCode = ++_usedHashCodes;
-
- Node() {
- setParentPointers();
- }
-
- accept(Visitor visitor);
-
- /// Updates the [parent] of the immediate children to refer to this node.
- ///
- /// All constructors call this method to initialize parent pointers.
- void setParentPointers();
-
- /// Returns the SExpression for the subtree rooted at this node.
- ///
- /// [annotations] maps strings to nodes and/or nodes to values that will be
- /// converted to strings. Each binding causes the annotation to appear on the
- /// given node.
- ///
- /// For example, the following could be used to diagnose a problem with nodes
- /// not appearing in an environment map:
- ///
- /// if (environment[node] == null)
- /// root.debugPrint({
- /// 'currentNode': node,
- /// 'caller': someContinuation
- /// });
- /// throw 'Node was not in environment';
- /// }
- ///
- /// If two strings map to the same node, it will be given both annotations.
- ///
- /// Avoid using nodes as keys if there is a chance that two keys are the
- /// same node.
- String debugString([Map annotations = const {}]) {
- return new SExpressionStringifier()
- .withAnnotations(annotations)
- .withTypes()
- .visit(this);
- }
-
- /// Prints the result of [debugString].
- void debugPrint([Map annotations = const {}]) {
- print(debugString(annotations));
- }
-}
-
-/// Expressions can be evaluated, and may diverge, throw, and/or have
-/// side-effects.
-///
-/// Evaluation continues by stepping into a sub-expression, invoking a
-/// continuation, or throwing an exception.
-///
-/// Expressions do not a return value. Expressions that produce values should
-/// invoke a [Continuation] with the result as argument. Alternatively, values
-/// that can be obtained without side-effects, divergence, or throwing
-/// exceptions can be built using a [LetPrim].
-///
-/// All subclasses implement exactly one of [CallExpression],
-/// [InteriorExpression], or [TailExpression].
-abstract class Expression extends Node {
- InteriorNode get parent; // Only InteriorNodes may contain expressions.
-
- Expression plug(Expression expr) => throw 'impossible';
-
- /// The next expression in the basic block.
- ///
- /// For [InteriorExpression]s this is the body, for [CallExpressions] it is
- /// the body of the continuation, and for [TailExpressions] it is `null`.
- Expression get next;
-
- accept(BlockVisitor visitor);
-}
-
-/// Represents a node with a child node, which can be accessed through the
-/// `body` member. A typical usage is when removing a node from the CPS graph:
-///
-/// Node child = node.body;
-/// InteriorNode parent = node.parent;
-///
-/// child.parent = parent;
-/// parent.body = child;
-abstract class InteriorNode extends Node {
- Expression get body;
- void set body(Expression body);
-
- accept(BlockVisitor visitor);
-}
-
-/// 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 hasExactlyOneUse => firstRef != null && firstRef.next == null;
- bool get hasNoUses => firstRef == null;
- bool get hasAtLeastOneUse => firstRef != null;
- bool get hasMultipleUses => !hasAtMostOneUse;
-
- void replaceUsesWith(Definition<T> newDefinition) {
- if (newDefinition == this) return;
- if (hasNoUses) return;
- Reference<T> previous, current = firstRef;
- do {
- current.definition = newDefinition;
- previous = current;
- current = current.next;
- } while (current != null);
- previous.next = newDefinition.firstRef;
- if (newDefinition.firstRef != null) {
- newDefinition.firstRef.previous = previous;
- }
- newDefinition.firstRef = firstRef;
- firstRef = null;
- }
-}
-
-/// 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;
- final List<Refinement> stack = <Refinement>[];
-
- EffectiveUseIterator(Primitive prim) : next = prim.firstRef;
-
- bool moveNext() {
- Reference<Primitive> ref = next;
- while (true) {
- if (ref == null) {
- if (stack.isNotEmpty) {
- ref = stack.removeLast().firstRef;
- } else {
- current = null;
- return false;
- }
- } else if (ref.parent is Refinement) {
- stack.add(ref.parent);
- ref = ref.next;
- } else {
- current = ref;
- next = current.next;
- return true;
- }
- }
- }
-}
-
-class RefinedUseIterable extends IterableBase<Reference<Primitive>> {
- Primitive primitive;
- RefinedUseIterable(this.primitive);
- EffectiveUseIterator get iterator => new EffectiveUseIterator(primitive);
-}
-
-/// A named value.
-///
-/// The identity of the [Primitive] object is the name of the value.
-/// The subclass describes how to compute the value.
-///
-/// All primitives except [Parameter] must be bound by a [LetPrim].
-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;
-
- /// True if the primitive can be removed, assuming it has no uses
- /// (this getter does not check if there are any uses).
- ///
- /// False must be returned for primitives that may throw, diverge, or have
- /// observable side-effects.
- bool get isSafeForElimination;
-
- /// True if time-of-evaluation is irrelevant for the given primitive,
- /// assuming its inputs are the same values.
- bool get isSafeForReordering;
-
- /// The source information associated with this primitive.
- // 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
- /// that was checked to be non-null, respectively.
- ///
- /// Those instructions all return the corresponding operand directly, and
- /// this getter can be used to get (closer to) where the value came from.
- //
- // TODO(asgerf): Also do this for [TypeCast]?
- Primitive get effectiveDefinition => this;
-
- /// Like [effectiveDefinition] but only unfolds [Refinement] nodes.
- Primitive get unrefined => this;
-
- /// True if the two primitives are (refinements of) the same value.
- bool sameValue(Primitive other) {
- return effectiveDefinition == other.effectiveDefinition;
- }
-
- /// Iterates all non-refinement uses of the primitive and all uses of
- /// a [Refinement] of this primitive (transitively).
- ///
- /// Notes regarding concurrent modification:
- /// - The current reference may safely be unlinked.
- /// - Yet unvisited references may not be unlinked.
- /// - References to this primitive created during iteration will not be seen.
- /// - References to a refinement of this primitive may not be created during
- /// iteration.
- RefinedUseIterable get refinedUses => new RefinedUseIterable(this);
-
- bool get hasMultipleRefinedUses {
- Iterator it = refinedUses.iterator;
- return it.moveNext() && it.moveNext();
- }
-
- bool get hasNoRefinedUses {
- return refinedUses.isEmpty;
- }
-
- /// Unlinks all references contained in this node.
- void destroy() {
- assert(hasNoUses);
- RemovalVisitor.remove(this);
- }
-
- /// Replaces this definition, both at the binding site and at all uses sites.
- ///
- /// This can be thought of as changing the definition of a `let` while
- /// preserving the variable name:
- ///
- /// let x = OLD in BODY
- /// ==>
- /// let x = NEW in BODY
- ///
- void replaceWith(Primitive newDefinition) {
- assert(this is! Parameter);
- assert(newDefinition is! Parameter);
- assert(newDefinition.parent == null);
- replaceUsesWith(newDefinition);
- destroy();
- LetPrim let = parent;
- let.primitive = newDefinition;
- newDefinition.parent = let;
- newDefinition.useElementAsHint(hint);
- }
-
- /// Replaces this definition with a CPS fragment (a term with a hole in it),
- /// given the value to replace the uses of the definition with.
- ///
- /// This can be thought of as substituting:
- ///
- /// let x = OLD in BODY
- /// ==>
- /// FRAGMENT[BODY{newPrimitive/x}]
- void replaceWithFragment(CpsFragment fragment, Primitive newPrimitive) {
- assert(this is! Parameter);
- replaceUsesWith(newPrimitive);
- destroy();
- LetPrim let = parent;
- fragment.insertBelow(let);
- let.remove();
- }
-}
-
-/// 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'.
-class Continuation extends Definition<Continuation> implements InteriorNode {
- final List<Parameter> parameters;
- Expression body = null;
-
- // A continuation is recursive if it has any recursive invocations.
- bool isRecursive;
-
- /// True if this is the return continuation. The return continuation is bound
- /// by [FunctionDefinition].
- bool get isReturnContinuation => body == null;
-
- /// True if this is a branch continuation. Branch continuations are bound
- /// by [LetCont] and can only have one use.
- bool get isBranchContinuation => firstRef?.parent is Branch;
-
- /// True if this is the exception handler bound by a [LetHandler].
- bool get isHandlerContinuation => parent is LetHandler;
-
- /// True if this is a non-return continuation that can be targeted by
- /// [InvokeContinuation].
- bool get isJoinContinuation {
- return body != null &&
- parent is! LetHandler &&
- (firstRef == null || firstRef.parent is InvokeContinuation);
- }
-
- Continuation(this.parameters, {this.isRecursive: false});
-
- Continuation.retrn()
- : parameters = <Parameter>[new Parameter(null)],
- isRecursive = false;
-
- accept(BlockVisitor visitor) => visitor.visitContinuation(this);
-
- void setParentPointers() {
- _setParentsOnNodes(parameters, this);
- if (body != null) body.parent = this;
- }
-}
-
-/// Common interface for [Primitive] and [MutableVariable].
-abstract class Variable<T extends Variable<T>> extends Definition<T> {
- /// Type of value held in the variable.
- ///
- /// Is `null` until initialized by type propagation.
- TypeMask type;
-
- /// The [VariableElement] or [ParameterElement] from which the variable
- /// binding originated.
- Entity hint;
-
- Variable(this.hint);
-
- /// Use the given element as a hint for naming this primitive.
- ///
- /// Has no effect if this primitive already has a non-null [element].
- void useElementAsHint(Entity hint) {
- this.hint ??= hint;
- }
-}
-
-/// Identifies a mutable variable.
-class MutableVariable extends Variable<MutableVariable> {
- MutableVariable(Entity hint) : super(hint);
-
- accept(Visitor v) => v.visitMutableVariable(this);
-
- void setParentPointers() {}
-}
-
-/// A function definition, consisting of parameters and a body.
-///
-/// There is an explicit parameter for the `this` argument, and a return
-/// continuation to invoke when returning from the function.
-class FunctionDefinition extends InteriorNode {
- final ExecutableElement element;
- Parameter interceptorParameter;
- final Parameter receiverParameter;
- final List<Parameter> parameters;
- final Continuation returnContinuation;
- final SourceInformation sourceInformation;
- Expression body;
-
- FunctionDefinition(this.element, this.receiverParameter, this.parameters,
- this.returnContinuation, this.body,
- {this.interceptorParameter, this.sourceInformation});
-
- accept(BlockVisitor visitor) => visitor.visitFunctionDefinition(this);
-
- void setParentPointers() {
- if (interceptorParameter != null) interceptorParameter.parent = this;
- if (receiverParameter != null) receiverParameter.parent = this;
- _setParentsOnNodes(parameters, this);
- returnContinuation.parent = this;
- if (body != null) body.parent = this;
- }
-}
-
-// ----------------------------------------------------------------------------
-// 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 interceptorRef => null;
- Primitive get interceptor => interceptorRef?.definition;
-
- 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);
-
- CallingConvention get callingConvention => CallingConvention.Normal;
-
- 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> interceptorRef;
- Reference<Primitive> receiverRef;
- Selector selector;
- TypeMask mask;
- final List<Reference<Primitive>> argumentRefs;
- final SourceInformation sourceInformation;
- CallingConvention _callingConvention;
-
- CallingConvention get callingConvention => _callingConvention;
-
- InvokeMethod(
- Primitive receiver, this.selector, this.mask, List<Primitive> arguments,
- {this.sourceInformation,
- CallingConvention callingConvention,
- Primitive interceptor})
- : this.receiverRef = new Reference<Primitive>(receiver),
- this.argumentRefs = _referenceList(arguments),
- this.interceptorRef = _optionalReference(interceptor),
- this._callingConvention = callingConvention ??
- (interceptor != null
- ? CallingConvention.Intercepted
- : CallingConvention.Normal);
-
- accept(Visitor visitor) => visitor.visitInvokeMethod(this);
-
- bool get hasValue => true;
-
- void setParentPointers() {
- interceptorRef?.parent = this;
- receiverRef.parent = this;
- _setParentsOnList(argumentRefs, this);
- }
-
- void makeIntercepted(Primitive interceptor) {
- interceptorRef?.unlink();
- interceptorRef = new Reference<Primitive>(interceptor)..parent = this;
- _callingConvention = CallingConvention.Intercepted;
- }
-
- void makeOneShotIntercepted() {
- interceptorRef?.unlink();
- interceptorRef = null;
- _callingConvention = CallingConvention.OneShotIntercepted;
- }
-
- void makeDummyIntercepted() {
- interceptorRef?.unlink();
- interceptorRef = null;
- _callingConvention = CallingConvention.DummyIntercepted;
- }
-}
-
-/// 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> interceptorRef;
- Reference<Primitive> receiverRef;
- final FunctionElement target;
- final Selector selector;
- final List<Reference<Primitive>> argumentRefs;
- final SourceInformation sourceInformation;
-
- InvokeMethodDirectly(Primitive receiver, this.target, this.selector,
- List<Primitive> arguments, this.sourceInformation,
- {Primitive interceptor})
- : this.receiverRef = new Reference<Primitive>(receiver),
- this.argumentRefs = _referenceList(arguments),
- this.interceptorRef = _optionalReference(interceptor);
-
- accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this);
-
- bool get hasValue => true;
-
- void setParentPointers() {
- interceptorRef?.parent = this;
- receiverRef.parent = this;
- _setParentsOnList(argumentRefs, this);
- }
-
- bool get isConstructorBodyCall => target is ConstructorBodyElement;
- bool get isTearOff => selector.isGetter && !target.isGetter;
-
- void makeIntercepted(Primitive interceptor) {
- interceptorRef?.unlink();
- interceptorRef = new Reference<Primitive>(interceptor)..parent = this;
- }
-}
-
-/// 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;
- final SourceInformation sourceInformation;
-
- MutableVariable get variable => variableRef.definition;
-
- GetMutable(MutableVariable variable, {this.sourceInformation})
- : 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;
- final SourceInformation sourceInformation;
-
- MutableVariable get variable => variableRef.definition;
- Primitive get value => valueRef.definition;
-
- SetMutable(MutableVariable variable, Primitive value,
- {this.sourceInformation})
- : 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;
- final SourceInformation sourceInformation;
-
- /// 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.sourceInformation, 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;
- final SourceInformation sourceInformation;
-
- Primitive get object => objectRef.definition;
- Primitive get value => valueRef.definition;
-
- SetField(Primitive object, this.field, Primitive value,
- {this.sourceInformation})
- : 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.
- 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 SourceInformation sourceInformation;
- 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.sourceInformation,
- {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> valueRef;
-
- final SourceInformation sourceInformation;
-
- Primitive get value => valueRef.definition;
-
- ReifyRuntimeType(Primitive value, this.sourceInformation)
- : this.valueRef = new Reference<Primitive>(value);
-
- @override
- accept(Visitor visitor) => visitor.visitReifyRuntimeType(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {
- valueRef.parent = this;
- }
-}
-
-/// Read the value the type variable [variable] from the target object.
-///
-/// The resulting value is an internal representation (and not neccessarily a
-/// Dart object), and must be reified by [ReifyRuntimeType], if it should be
-/// used as a Dart value.
-class ReadTypeVariable extends Primitive {
- final TypeVariableType variable;
- final Reference<Primitive> targetRef;
- final SourceInformation sourceInformation;
-
- Primitive get target => targetRef.definition;
-
- ReadTypeVariable(this.variable, Primitive target, this.sourceInformation)
- : this.targetRef = new Reference<Primitive>(target);
-
- @override
- accept(Visitor visitor) => visitor.visitReadTypeVariable(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {
- targetRef.parent = this;
- }
-}
-
-enum TypeExpressionKind { COMPLETE, INSTANCE }
-
-/// Constructs a representation of a closed or ground-term type (that is, a type
-/// without type variables).
-///
-/// There are two forms:
-///
-/// - COMPLETE: A complete form that is self contained, used for the values of
-/// type parameters and non-raw is-checks.
-///
-/// - INSTANCE: A headless flat form for representing the sequence of values of
-/// the type parameters of an instance of a generic type.
-///
-/// The COMPLETE form value is constructed from [dartType] by replacing the type
-/// variables with consecutive values from [arguments], in the order generated
-/// by [DartType.forEachTypeVariable]. The type variables in [dartType] are
-/// treated as 'holes' in the term, which means that it must be ensured at
-/// construction, that duplicate occurences of a type variable in [dartType]
-/// are assigned the same value.
-///
-/// The INSTANCE form is constructed as a list of [arguments]. This is the same
-/// as the COMPLETE form for the 'thisType', except the root term's type is
-/// missing; this is implicit as the raw type of instance. The [dartType] of
-/// the INSTANCE form must be the thisType of some class.
-///
-/// While we would like to remove the constrains on the INSTANCE form, we can
-/// get by with a tree of TypeExpressions. Consider:
-///
-/// class Foo<T> {
-/// ... new Set<List<T>>()
-/// }
-/// class Set<E1> {
-/// factory Set() => new _LinkedHashSet<E1>();
-/// }
-/// class List<E2> { ... }
-/// class _LinkedHashSet<E3> { ... }
-///
-/// After inlining the factory constructor for `Set<E1>`, the CreateInstance
-/// should have type `_LinkedHashSet<List<T>>` and the TypeExpression should be
-/// a tree:
-///
-/// CreateInstance(dartType: _LinkedHashSet<List<T>>,
-/// [], // No arguments
-/// TypeExpression(INSTANCE,
-/// dartType: _LinkedHashSet<E3>, // _LinkedHashSet's thisType
-/// TypeExpression(COMPLETE, // E3 = List<T>
-/// dartType: List<E2>,
-/// ReadTypeVariable(this, T)))) // E2 = T
-//
-// TODO(sra): The INSTANCE form requires the actual instance for full
-// interpretation. I want to move to a representation where the INSTANCE form is
-// also a complete form (possibly the same).
-class TypeExpression extends Primitive {
- final TypeExpressionKind kind;
- final DartType dartType;
- final List<Reference<Primitive>> argumentRefs;
-
- 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);
- }
-
- @override
- accept(Visitor visitor) {
- return visitor.visitTypeExpression(this);
- }
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {
- _setParentsOnList(argumentRefs, this);
- }
-
- String get kindAsString {
- switch (kind) {
- case TypeExpressionKind.COMPLETE:
- return 'COMPLETE';
- case TypeExpressionKind.INSTANCE:
- return 'INSTANCE';
- }
- }
-}
-
-class Await extends UnsafePrimitive {
- final Reference<Primitive> inputRef;
-
- Primitive get input => inputRef.definition;
-
- Await(Primitive input) : this.inputRef = new Reference<Primitive>(input);
-
- @override
- accept(Visitor visitor) {
- return visitor.visitAwait(this);
- }
-
- bool get hasValue => true;
-
- void setParentPointers() {
- inputRef.parent = this;
- }
-}
-
-class Yield extends UnsafePrimitive {
- final Reference<Primitive> inputRef;
- final bool hasStar;
-
- Primitive get input => inputRef.definition;
-
- Yield(Primitive input, this.hasStar)
- : this.inputRef = new Reference<Primitive>(input);
-
- @override
- accept(Visitor visitor) {
- return visitor.visitYield(this);
- }
-
- bool get hasValue => true;
-
- void setParentPointers() {
- 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;
- final SourceInformation sourceInformation;
-
- 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,
- this.sourceInformation,
- {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, SourceInformation sourceInformation)
- : this(condition, trueCont, falseCont, sourceInformation, strict: true);
-
- Branch.loose(Primitive condition, Continuation trueCont,
- Continuation falseCont, SourceInformation sourceInformation)
- : this(condition, trueCont, falseCont, sourceInformation, strict: false);
-
- accept(BlockVisitor visitor) => visitor.visitBranch(this);
-
- void setParentPointers() {
- conditionRef.parent = this;
- trueContinuationRef.parent = this;
- falseContinuationRef.parent = this;
- }
-}
-
-// ----------------------------------------------------------------------------
-// UTILITY STUFF
-// ----------------------------------------------------------------------------
-
-Reference<Primitive> _optionalReference(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;
- }
-}
-
-void _setParentsOnList(List<Reference> nodes, Node parent) {
- for (Reference node in nodes) {
- node.parent = parent;
- }
-}
-
-// ----------------------------------------------------------------------------
-// VISITORS
-// ----------------------------------------------------------------------------
-
-/// Visitor for block-level traversals that do not need to dispatch on
-/// primitives.
-abstract class BlockVisitor<T> {
- const BlockVisitor();
-
- T visit(Node node) => node.accept(this);
-
- // Block headers.
- T visitFunctionDefinition(FunctionDefinition node) => null;
- T visitContinuation(Continuation node) => null;
-
- // Interior expressions.
- T visitLetPrim(LetPrim node) => null;
- T visitLetCont(LetCont node) => null;
- T visitLetHandler(LetHandler node) => null;
- T visitLetMutable(LetMutable node) => null;
-
- // Tail expressions.
- T visitInvokeContinuation(InvokeContinuation node) => null;
- T visitThrow(Throw node) => null;
- T visitRethrow(Rethrow node) => null;
- T visitBranch(Branch node) => null;
- T visitUnreachable(Unreachable node) => null;
-
- /// Visits block-level nodes in lexical post-order (not post-dominator order).
- ///
- /// Continuations and function definitions are considered "block headers".
- /// The block itself is the sequence of interior expressions in the body,
- /// terminated by a tail expression.
- ///
- /// Each block is visited starting with its tail expression, then every
- /// interior expression from bottom to top, and finally the block header
- /// is visited.
- ///
- /// Blocks are visited in post-order, so the body of a continuation is always
- /// processed before its non-recursive invocation sites.
- ///
- /// The IR may be transformed during the traversal, but only the original
- /// nodes will be visited.
- static void traverseInPostOrder(FunctionDefinition root, BlockVisitor v) {
- List<Continuation> stack = <Continuation>[];
- List<Node> nodes = <Node>[];
- void walkBlock(InteriorNode block) {
- nodes.add(block);
- Expression node = block.body;
- nodes.add(node);
- while (node.next != null) {
- if (node is LetCont) {
- stack.addAll(node.continuations);
- } else if (node is LetHandler) {
- stack.add(node.handler);
- }
- node = node.next;
- nodes.add(node);
- }
- }
- walkBlock(root);
- while (stack.isNotEmpty) {
- walkBlock(stack.removeLast());
- }
- nodes.reversed.forEach(v.visit);
- }
-
- /// Visits block-level nodes in lexical pre-order.
- ///
- /// Traversal continues at the original success for the current node, so:
- /// - The current node can safely be removed.
- /// - Nodes inserted immediately below the current node will not be seen.
- /// - The body of the current node should not be moved/removed, as traversal
- /// would otherwise continue into an orphaned or relocated node.
- static void traverseInPreOrder(FunctionDefinition root, BlockVisitor v) {
- List<Continuation> stack = <Continuation>[];
- void walkBlock(InteriorNode block) {
- v.visit(block);
- Expression node = block.body;
- while (node != null) {
- if (node is LetCont) {
- stack.addAll(node.continuations);
- } else if (node is LetHandler) {
- stack.add(node.handler);
- }
- Expression next = node.next;
- v.visit(node);
- node = next;
- }
- }
- walkBlock(root);
- while (stack.isNotEmpty) {
- walkBlock(stack.removeLast());
- }
- }
-}
-
-abstract class Visitor<T> implements BlockVisitor<T> {
- const Visitor();
-
- T visit(Node node);
-
- // Definitions.
- T visitInvokeStatic(InvokeStatic node);
- T visitInvokeMethod(InvokeMethod node);
- T visitInvokeMethodDirectly(InvokeMethodDirectly node);
- T visitInvokeConstructor(InvokeConstructor node);
- T visitTypeCast(TypeCast node);
- T visitSetMutable(SetMutable node);
- T visitSetStatic(SetStatic node);
- T visitSetField(SetField node);
- T visitGetLazyStatic(GetLazyStatic node);
- T visitAwait(Await node);
- T visitYield(Yield node);
- T visitLiteralList(LiteralList node);
- T visitConstant(Constant node);
- T visitGetMutable(GetMutable node);
- T visitParameter(Parameter node);
- T visitMutableVariable(MutableVariable node);
- T visitGetStatic(GetStatic node);
- T visitInterceptor(Interceptor node);
- T visitCreateInstance(CreateInstance node);
- T visitGetField(GetField node);
- T visitCreateBox(CreateBox node);
- T visitReifyRuntimeType(ReifyRuntimeType node);
- T visitReadTypeVariable(ReadTypeVariable node);
- T visitTypeExpression(TypeExpression node);
- T visitCreateInvocationMirror(CreateInvocationMirror node);
- T visitTypeTest(TypeTest node);
- T visitTypeTestViaFlag(TypeTestViaFlag node);
- T visitApplyBuiltinOperator(ApplyBuiltinOperator node);
- T visitApplyBuiltinMethod(ApplyBuiltinMethod node);
- T visitGetLength(GetLength node);
- T visitGetIndex(GetIndex node);
- T visitSetIndex(SetIndex node);
- T visitRefinement(Refinement node);
- T visitBoundsCheck(BoundsCheck node);
- T visitReceiverCheck(ReceiverCheck node);
- T visitForeignCode(ForeignCode node);
-}
-
-/// Recursively visits all children of a CPS term.
-///
-/// The user of the class is responsible for avoiding stack overflows from
-/// deep recursion, e.g. by overriding methods to cut off recursion at certain
-/// points.
-///
-/// All recursive invocations occur through the [visit] method, which the
-/// subclass may override as a generic way to control the visitor without
-/// overriding all visitor methods.
-///
-/// The `process*` methods are called in pre-order for every node visited.
-/// These can be overridden without disrupting the visitor traversal.
-class DeepRecursiveVisitor implements Visitor {
- const DeepRecursiveVisitor();
-
- visit(Node node) => node.accept(this);
-
- processReference(Reference ref) {}
-
- processFunctionDefinition(FunctionDefinition node) {}
- visitFunctionDefinition(FunctionDefinition node) {
- processFunctionDefinition(node);
- if (node.interceptorParameter != null) visit(node.interceptorParameter);
- if (node.receiverParameter != null) visit(node.receiverParameter);
- node.parameters.forEach(visit);
- visit(node.body);
- }
-
- processContinuation(Continuation node) {}
- visitContinuation(Continuation node) {
- processContinuation(node);
- node.parameters.forEach(visit);
- if (node.body != null) visit(node.body);
- }
-
- // Expressions.
- processLetPrim(LetPrim node) {}
- visitLetPrim(LetPrim node) {
- processLetPrim(node);
- visit(node.primitive);
- visit(node.body);
- }
-
- processLetCont(LetCont node) {}
- visitLetCont(LetCont node) {
- processLetCont(node);
- node.continuations.forEach(visit);
- visit(node.body);
- }
-
- processLetHandler(LetHandler node) {}
- visitLetHandler(LetHandler node) {
- processLetHandler(node);
- visit(node.handler);
- visit(node.body);
- }
-
- processLetMutable(LetMutable node) {}
- visitLetMutable(LetMutable node) {
- processLetMutable(node);
- visit(node.variable);
- processReference(node.valueRef);
- visit(node.body);
- }
-
- processInvokeStatic(InvokeStatic node) {}
- visitInvokeStatic(InvokeStatic node) {
- processInvokeStatic(node);
- node.argumentRefs.forEach(processReference);
- }
-
- processInvokeContinuation(InvokeContinuation node) {}
- visitInvokeContinuation(InvokeContinuation node) {
- processInvokeContinuation(node);
- processReference(node.continuationRef);
- node.argumentRefs.forEach(processReference);
- }
-
- processInvokeMethod(InvokeMethod node) {}
- visitInvokeMethod(InvokeMethod node) {
- processInvokeMethod(node);
- if (node.interceptorRef != null) {
- processReference(node.interceptorRef);
- }
- processReference(node.receiverRef);
- node.argumentRefs.forEach(processReference);
- }
-
- processInvokeMethodDirectly(InvokeMethodDirectly node) {}
- visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- processInvokeMethodDirectly(node);
- if (node.interceptorRef != null) {
- processReference(node.interceptorRef);
- }
- processReference(node.receiverRef);
- node.argumentRefs.forEach(processReference);
- }
-
- processInvokeConstructor(InvokeConstructor node) {}
- visitInvokeConstructor(InvokeConstructor node) {
- processInvokeConstructor(node);
- node.argumentRefs.forEach(processReference);
- }
-
- processThrow(Throw node) {}
- visitThrow(Throw node) {
- processThrow(node);
- processReference(node.valueRef);
- }
-
- processRethrow(Rethrow node) {}
- visitRethrow(Rethrow node) {
- processRethrow(node);
- }
-
- processBranch(Branch node) {}
- visitBranch(Branch node) {
- processBranch(node);
- processReference(node.trueContinuationRef);
- processReference(node.falseContinuationRef);
- processReference(node.conditionRef);
- }
-
- processTypeCast(TypeCast node) {}
- visitTypeCast(TypeCast node) {
- processTypeCast(node);
- processReference(node.valueRef);
- node.typeArgumentRefs.forEach(processReference);
- }
-
- processTypeTest(TypeTest node) {}
- visitTypeTest(TypeTest node) {
- processTypeTest(node);
- processReference(node.valueRef);
- node.typeArgumentRefs.forEach(processReference);
- }
-
- processTypeTestViaFlag(TypeTestViaFlag node) {}
- visitTypeTestViaFlag(TypeTestViaFlag node) {
- processTypeTestViaFlag(node);
- processReference(node.interceptorRef);
- }
-
- processSetMutable(SetMutable node) {}
- visitSetMutable(SetMutable node) {
- processSetMutable(node);
- processReference(node.variableRef);
- processReference(node.valueRef);
- }
-
- processGetLazyStatic(GetLazyStatic node) {}
- visitGetLazyStatic(GetLazyStatic node) {
- processGetLazyStatic(node);
- }
-
- processLiteralList(LiteralList node) {}
- visitLiteralList(LiteralList node) {
- processLiteralList(node);
- node.valueRefs.forEach(processReference);
- }
-
- processConstant(Constant node) {}
- visitConstant(Constant node) {
- processConstant(node);
- }
-
- processMutableVariable(node) {}
- visitMutableVariable(MutableVariable node) {
- processMutableVariable(node);
- }
-
- processGetMutable(GetMutable node) {}
- visitGetMutable(GetMutable node) {
- processGetMutable(node);
- processReference(node.variableRef);
- }
-
- processParameter(Parameter node) {}
- visitParameter(Parameter node) {
- processParameter(node);
- }
-
- processInterceptor(Interceptor node) {}
- visitInterceptor(Interceptor node) {
- processInterceptor(node);
- processReference(node.inputRef);
- }
-
- processCreateInstance(CreateInstance node) {}
- visitCreateInstance(CreateInstance node) {
- processCreateInstance(node);
- node.argumentRefs.forEach(processReference);
- if (node.typeInformationRef != null) {
- processReference(node.typeInformationRef);
- }
- }
-
- processSetField(SetField node) {}
- visitSetField(SetField node) {
- processSetField(node);
- processReference(node.objectRef);
- processReference(node.valueRef);
- }
-
- processGetField(GetField node) {}
- visitGetField(GetField node) {
- processGetField(node);
- processReference(node.objectRef);
- }
-
- processGetStatic(GetStatic node) {}
- visitGetStatic(GetStatic node) {
- processGetStatic(node);
- if (node.witnessRef != null) {
- processReference(node.witnessRef);
- }
- }
-
- processSetStatic(SetStatic node) {}
- visitSetStatic(SetStatic node) {
- processSetStatic(node);
- processReference(node.valueRef);
- }
-
- processCreateBox(CreateBox node) {}
- visitCreateBox(CreateBox node) {
- processCreateBox(node);
- }
-
- processReifyRuntimeType(ReifyRuntimeType node) {}
- visitReifyRuntimeType(ReifyRuntimeType node) {
- processReifyRuntimeType(node);
- processReference(node.valueRef);
- }
-
- processReadTypeVariable(ReadTypeVariable node) {}
- visitReadTypeVariable(ReadTypeVariable node) {
- processReadTypeVariable(node);
- processReference(node.targetRef);
- }
-
- processTypeExpression(TypeExpression node) {}
- visitTypeExpression(TypeExpression node) {
- processTypeExpression(node);
- node.argumentRefs.forEach(processReference);
- }
-
- processCreateInvocationMirror(CreateInvocationMirror node) {}
- visitCreateInvocationMirror(CreateInvocationMirror node) {
- processCreateInvocationMirror(node);
- node.argumentRefs.forEach(processReference);
- }
-
- processApplyBuiltinOperator(ApplyBuiltinOperator node) {}
- visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- processApplyBuiltinOperator(node);
- node.argumentRefs.forEach(processReference);
- }
-
- processApplyBuiltinMethod(ApplyBuiltinMethod node) {}
- visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- processApplyBuiltinMethod(node);
- processReference(node.receiverRef);
- node.argumentRefs.forEach(processReference);
- }
-
- processForeignCode(ForeignCode node) {}
- visitForeignCode(ForeignCode node) {
- processForeignCode(node);
- node.argumentRefs.forEach(processReference);
- }
-
- processUnreachable(Unreachable node) {}
- visitUnreachable(Unreachable node) {
- processUnreachable(node);
- }
-
- processAwait(Await node) {}
- visitAwait(Await node) {
- processAwait(node);
- processReference(node.inputRef);
- }
-
- processYield(Yield node) {}
- visitYield(Yield node) {
- processYield(node);
- processReference(node.inputRef);
- }
-
- processGetLength(GetLength node) {}
- visitGetLength(GetLength node) {
- processGetLength(node);
- processReference(node.objectRef);
- }
-
- processGetIndex(GetIndex node) {}
- visitGetIndex(GetIndex node) {
- processGetIndex(node);
- processReference(node.objectRef);
- processReference(node.indexRef);
- }
-
- processSetIndex(SetIndex node) {}
- visitSetIndex(SetIndex node) {
- processSetIndex(node);
- processReference(node.objectRef);
- processReference(node.indexRef);
- processReference(node.valueRef);
- }
-
- processRefinement(Refinement node) {}
- visitRefinement(Refinement node) {
- processRefinement(node);
- processReference(node.value);
- }
-
- processBoundsCheck(BoundsCheck node) {}
- visitBoundsCheck(BoundsCheck node) {
- processBoundsCheck(node);
- processReference(node.objectRef);
- if (node.indexRef != null) {
- processReference(node.indexRef);
- }
- if (node.lengthRef != null) {
- processReference(node.lengthRef);
- }
- }
-
- processNullCheck(ReceiverCheck node) {}
- visitReceiverCheck(ReceiverCheck node) {
- processNullCheck(node);
- processReference(node.valueRef);
- if (node.conditionRef != null) {
- processReference(node.conditionRef);
- }
- }
-}
-
-typedef void StackAction();
-
-/// Calls `process*` for all nodes in a tree.
-/// For simple usage, only override the `process*` methods.
-///
-/// To avoid deep recursion, this class uses an "action stack" containing
-/// callbacks to be invoked after the processing of some term has finished.
-///
-/// To avoid excessive overhead from the action stack, basic blocks of
-/// interior nodes are iterated in a loop without using the action stack.
-///
-/// The iteration order can be controlled by overriding the `traverse*`
-/// methods for [LetCont], [LetPrim], [LetMutable], [LetHandler] and
-/// [Continuation].
-///
-/// The `traverse*` methods return the expression to visit next, and may
-/// push other subterms onto the stack using [push] or [pushAction] to visit
-/// them later. Actions pushed onto the stack will be executed after the body
-/// has been processed (and the stack actions it pushed have been executed).
-///
-/// By default, the `traverse` methods visit all non-recursive subterms,
-/// push all bound continuations on the stack, and return the body of the term.
-///
-/// Subclasses should not override the `visit` methods for the nodes that have
-/// a `traverse` method.
-class TrampolineRecursiveVisitor extends DeepRecursiveVisitor {
- List<StackAction> _stack = <StackAction>[];
-
- void pushAction(StackAction callback) {
- _stack.add(callback);
- }
-
- void push(Continuation cont) {
- _stack.add(() {
- if (cont.isReturnContinuation) {
- traverseContinuation(cont);
- } else {
- _processBlock(traverseContinuation(cont));
- }
- });
- }
-
- visitFunctionDefinition(FunctionDefinition node) {
- processFunctionDefinition(node);
- if (node.interceptorParameter != null) visit(node.interceptorParameter);
- if (node.receiverParameter != null) visit(node.receiverParameter);
- node.parameters.forEach(visit);
- visit(node.body);
- }
-
- visitContinuation(Continuation cont) {
- if (cont.isReturnContinuation) {
- traverseContinuation(cont);
- } else {
- int initialHeight = _stack.length;
- Expression body = traverseContinuation(cont);
- _trampoline(body, initialHeight: initialHeight);
- }
- }
-
- visitLetPrim(LetPrim node) => _trampoline(node);
- visitLetCont(LetCont node) => _trampoline(node);
- visitLetHandler(LetHandler node) => _trampoline(node);
- visitLetMutable(LetMutable node) => _trampoline(node);
-
- Expression traverseContinuation(Continuation cont) {
- processContinuation(cont);
- cont.parameters.forEach(visitParameter);
- return cont.body;
- }
-
- Expression traverseLetCont(LetCont node) {
- processLetCont(node);
- node.continuations.forEach(push);
- return node.body;
- }
-
- Expression traverseLetHandler(LetHandler node) {
- processLetHandler(node);
- push(node.handler);
- return node.body;
- }
-
- Expression traverseLetPrim(LetPrim node) {
- processLetPrim(node);
- visit(node.primitive);
- return node.body;
- }
-
- Expression traverseLetMutable(LetMutable node) {
- processLetMutable(node);
- visit(node.variable);
- processReference(node.valueRef);
- return node.body;
- }
-
- void _trampoline(Expression node, {int initialHeight}) {
- initialHeight = initialHeight ?? _stack.length;
- _processBlock(node);
- while (_stack.length > initialHeight) {
- StackAction callback = _stack.removeLast();
- callback();
- }
- }
-
- _processBlock(Expression node) {
- while (node is InteriorExpression) {
- if (node is LetCont) {
- node = traverseLetCont(node);
- } else if (node is LetHandler) {
- node = traverseLetHandler(node);
- } else if (node is LetPrim) {
- node = traverseLetPrim(node);
- } else {
- node = traverseLetMutable(node);
- }
- }
- visit(node);
- }
-}
-
-/// Visit a just-deleted subterm and unlink all [Reference]s in it.
-class RemovalVisitor extends TrampolineRecursiveVisitor {
- processReference(Reference reference) {
- reference.unlink();
- }
-
- static void remove(Node node) {
- (new RemovalVisitor()).visit(node);
- }
-}
-
-/// A visitor to copy instances of [Definition] or its subclasses, except for
-/// instances of [Continuation].
-///
-/// The visitor maintains a map from original definitions to their copies.
-/// When the [copy] method is called for a non-Continuation definition,
-/// a copy is created, added to the map and returned as the result. Copying a
-/// definition assumes that the definitions of all references have already
-/// been copied by the same visitor.
-class DefinitionCopyingVisitor extends Visitor<Definition> {
- Map<Definition, Definition> _copies = <Definition, Definition>{};
-
- /// Put a copy into the map.
- ///
- /// This method should be used instead of directly adding copies to the map.
- Definition putCopy(Definition original, Definition copy) {
- if (copy is Variable) {
- Variable originalVariable = original;
- copy.type = originalVariable.type;
- copy.hint = originalVariable.hint;
- }
- return _copies[original] = copy;
- }
-
- /// 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);
- return putCopy(node, visit(node));
- }
-
- Definition visit(Node node) => node.accept(this);
-
- visitFunctionDefinition(FunctionDefinition node) {}
- visitLetPrim(LetPrim node) {}
- visitLetCont(LetCont node) {}
- visitLetHandler(LetHandler node) {}
- visitLetMutable(LetMutable node) {}
- visitInvokeContinuation(InvokeContinuation node) {}
- visitThrow(Throw node) {}
- visitRethrow(Rethrow node) {}
- visitBranch(Branch node) {}
- visitUnreachable(Unreachable node) {}
- visitContinuation(Continuation node) {}
-
- Definition visitInvokeStatic(InvokeStatic node) {
- return new InvokeStatic(node.target, node.selector,
- getList(node.argumentRefs), node.sourceInformation);
- }
-
- Definition visitInvokeMethod(InvokeMethod node) {
- return new InvokeMethod(getCopy(node.receiverRef), node.selector, node.mask,
- getList(node.argumentRefs),
- sourceInformation: node.sourceInformation,
- callingConvention: node.callingConvention,
- interceptor: getCopyOrNull(node.interceptorRef));
- }
-
- Definition visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- return new InvokeMethodDirectly(getCopy(node.receiverRef), node.target,
- node.selector, getList(node.argumentRefs), node.sourceInformation,
- interceptor: getCopyOrNull(node.interceptorRef));
- }
-
- Definition visitInvokeConstructor(InvokeConstructor node) {
- 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.valueRef), node.dartType, getList(node.typeArgumentRefs));
- }
-
- Definition visitSetMutable(SetMutable node) {
- return new SetMutable(getCopy(node.variableRef), getCopy(node.valueRef),
- sourceInformation: node.sourceInformation);
- }
-
- Definition visitSetStatic(SetStatic node) {
- return new SetStatic(
- node.element, getCopy(node.valueRef), node.sourceInformation);
- }
-
- Definition visitSetField(SetField node) {
- return new SetField(
- getCopy(node.objectRef), node.field, getCopy(node.valueRef),
- sourceInformation: node.sourceInformation);
- }
-
- Definition visitGetLazyStatic(GetLazyStatic node) {
- return new GetLazyStatic(node.element,
- isFinal: node.isFinal, sourceInformation: node.sourceInformation);
- }
-
- Definition visitAwait(Await node) {
- return new Await(getCopy(node.inputRef));
- }
-
- Definition visitYield(Yield node) {
- return new Yield(getCopy(node.inputRef), node.hasStar);
- }
-
- Definition visitLiteralList(LiteralList node) {
- return new LiteralList(node.dartType, getList(node.valueRefs))
- ..allocationSiteType = node.allocationSiteType;
- }
-
- Definition visitConstant(Constant node) {
- return new Constant(node.value, sourceInformation: node.sourceInformation);
- }
-
- Definition visitGetMutable(GetMutable node) {
- return new GetMutable(getCopy(node.variableRef),
- sourceInformation: node.sourceInformation);
- }
-
- Definition visitParameter(Parameter node) {
- return new Parameter(node.hint);
- }
-
- Definition visitMutableVariable(MutableVariable node) {
- return new MutableVariable(node.hint);
- }
-
- Definition visitGetStatic(GetStatic node) {
- 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.inputRef), node.sourceInformation)
- ..interceptedClasses.addAll(node.interceptedClasses);
- }
-
- Definition visitCreateInstance(CreateInstance node) {
- return new CreateInstance(node.classElement, getList(node.argumentRefs),
- getCopyOrNull(node.typeInformationRef), node.sourceInformation);
- }
-
- Definition visitGetField(GetField node) {
- return new GetField(getCopy(node.objectRef), node.field,
- isFinal: node.isFinal);
- }
-
- Definition visitCreateBox(CreateBox node) {
- return new CreateBox();
- }
-
- Definition visitReifyRuntimeType(ReifyRuntimeType node) {
- return new ReifyRuntimeType(getCopy(node.valueRef), node.sourceInformation);
- }
-
- Definition visitReadTypeVariable(ReadTypeVariable node) {
- return new ReadTypeVariable(
- node.variable, getCopy(node.targetRef), node.sourceInformation);
- }
-
- Definition visitTypeExpression(TypeExpression node) {
- return new TypeExpression(
- node.kind, node.dartType, getList(node.argumentRefs));
- }
-
- Definition visitCreateInvocationMirror(CreateInvocationMirror node) {
- return new CreateInvocationMirror(
- node.selector, getList(node.argumentRefs));
- }
-
- Definition visitTypeTest(TypeTest node) {
- return new TypeTest(
- getCopy(node.valueRef), node.dartType, getList(node.typeArgumentRefs));
- }
-
- Definition visitTypeTestViaFlag(TypeTestViaFlag node) {
- return new TypeTestViaFlag(getCopy(node.interceptorRef), node.dartType);
- }
-
- Definition visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- return new ApplyBuiltinOperator(
- node.operator, getList(node.argumentRefs), node.sourceInformation);
- }
-
- Definition visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- return new ApplyBuiltinMethod(node.method, getCopy(node.receiverRef),
- getList(node.argumentRefs), node.sourceInformation);
- }
-
- Definition visitGetLength(GetLength node) {
- return new GetLength(getCopy(node.objectRef), isFinal: node.isFinal);
- }
-
- Definition visitGetIndex(GetIndex node) {
- return new GetIndex(getCopy(node.objectRef), getCopy(node.indexRef));
- }
-
- Definition visitSetIndex(SetIndex node) {
- return new SetIndex(getCopy(node.objectRef), getCopy(node.indexRef),
- getCopy(node.valueRef));
- }
-
- Definition visitRefinement(Refinement node) {
- return new Refinement(getCopy(node.value), node.refineType);
- }
-
- Definition visitBoundsCheck(BoundsCheck node) {
- if (node.hasNoChecks) {
- return new BoundsCheck.noCheck(
- getCopy(node.objectRef), node.sourceInformation);
- } else {
- 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.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.argumentRefs), node.nativeBehavior, node.sourceInformation,
- dependency: node.dependency);
- }
-}
-
-/// A trampolining visitor to copy [FunctionDefinition]s.
-class CopyingVisitor extends TrampolineRecursiveVisitor {
- // The visitor maintains a map from original continuations to their copies.
- Map<Continuation, Continuation> _copies = <Continuation, Continuation>{};
-
- // The visitor uses an auxiliary visitor to copy definitions.
- DefinitionCopyingVisitor _definitions = new DefinitionCopyingVisitor();
-
- // While copying a block, the state of the visitor is a 'linked list' of
- // the expressions in the block's body, with a pointer to the last element
- // of the list.
- Expression _first = null;
- Expression _current = null;
-
- void plug(Expression body) {
- if (_first == null) {
- _first = body;
- } else {
- assert(_current != null);
- InteriorExpression interior = _current;
- interior.body = body;
- body.parent = interior;
- }
- _current = body;
- }
-
- // Continuations are added to the visitor's stack to be visited after copying
- // the current block is finished. The stack action saves the current block,
- // copies the continuation's body, sets the body on the copy of the
- // continuation, and restores the current block.
- //
- // Note that continuations are added to the copy map before the stack action
- // to visit them is performed.
- void push(Continuation cont) {
- assert(!cont.isReturnContinuation);
- _stack.add(() {
- Expression savedFirst = _first;
- _first = _current = null;
- _processBlock(cont.body);
- Continuation contCopy = _copies[cont];
- contCopy.body = _first;
- _first.parent = contCopy;
- _first = savedFirst;
- _current = null;
- });
- }
-
- FunctionDefinition copy(FunctionDefinition node) {
- assert(_first == null && _current == null);
- _first = _current = null;
- // Definitions are copied where they are bound, before processing
- // expressions in the scope of their binding.
- Parameter thisParameter = node.receiverParameter == null
- ? null
- : _definitions.copy(node.receiverParameter);
- Parameter interceptorParameter = node.interceptorParameter == null
- ? null
- : _definitions.copy(node.interceptorParameter);
- List<Parameter> parameters =
- node.parameters.map(_definitions.copy).toList();
- // Though the return continuation's parameter does not have any uses,
- // we still make a proper copy to ensure that hints, type, etc. are
- // copied.
- Parameter returnParameter =
- _definitions.copy(node.returnContinuation.parameters.first);
- Continuation returnContinuation =
- _copies[node.returnContinuation] = new Continuation([returnParameter]);
-
- visit(node.body);
- FunctionDefinition copy = new FunctionDefinition(
- node.element, thisParameter, parameters, returnContinuation, _first,
- interceptorParameter: interceptorParameter,
- sourceInformation: node.sourceInformation);
- _first = _current = null;
- return copy;
- }
-
- Node visit(Node node) => node.accept(this);
-
- Expression traverseLetCont(LetCont node) {
- // Continuations are copied where they are bound, before processing
- // expressions in the scope of their binding.
- List<Continuation> continuations = node.continuations.map((Continuation c) {
- push(c);
- return _copies[c] =
- new Continuation(c.parameters.map(_definitions.copy).toList());
- }).toList();
- plug(new LetCont.many(continuations, null));
- return node.body;
- }
-
- Expression traverseLetHandler(LetHandler node) {
- // 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());
- plug(new LetHandler(handler, null));
- return node.body;
- }
-
- Expression traverseLetPrim(LetPrim node) {
- plug(new LetPrim(_definitions.copy(node.primitive)));
- return node.body;
- }
-
- Expression traverseLetMutable(LetMutable node) {
- 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], _definitions.getList(node.argumentRefs),
- isRecursive: node.isRecursive,
- isEscapingTry: node.isEscapingTry,
- sourceInformation: node.sourceInformation));
- }
-
- visitThrow(Throw node) {
- plug(new Throw(_definitions.getCopy(node.valueRef)));
- }
-
- visitRethrow(Rethrow node) {
- plug(new Rethrow());
- }
-
- visitBranch(Branch node) {
- plug(new Branch.loose(
- _definitions.getCopy(node.conditionRef),
- _copies[node.trueContinuation],
- _copies[node.falseContinuation],
- node.sourceInformation)..isStrictCheck = node.isStrictCheck);
- }
-
- visitUnreachable(Unreachable node) {
- plug(new Unreachable());
- }
-}
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
deleted file mode 100644
index 8d32d04..0000000
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ /dev/null
@@ -1,574 +0,0 @@
-// 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 dart2js.ir_nodes_sexpr;
-
-import '../constants/values.dart';
-import '../universe/call_structure.dart' show CallStructure;
-import '../util/util.dart';
-import 'cps_ir_nodes.dart';
-
-/// A [Decorator] is a function used by [SExpressionStringifier] to augment the
-/// output produced for a node or reference. It can be provided to the
-/// constructor.
-typedef String Decorator(node, String s);
-
-/// Generate a Lisp-like S-expression representation of an IR node as a string.
-class SExpressionStringifier extends Indentation implements Visitor<String> {
- final _Namer namer = new _Namer();
-
- String newValueName(Primitive node) => namer.nameValue(node);
- String newContinuationName(Continuation node) => namer.nameContinuation(node);
- Decorator decorator;
-
- SExpressionStringifier([this.decorator]) {
- if (this.decorator == null) {
- this.decorator = (node, String s) => s;
- }
- }
-
- /// Create a stringifier with an extra layer of decoration.
- SExpressionStringifier withDecorator(Decorator subDecorator) {
- return new SExpressionStringifier((node, String s) {
- return subDecorator(node, decorator(node, s));
- });
- }
-
- /// Create a stringifier that displays type information.
- SExpressionStringifier withTypes() => withDecorator(typeDecorator);
-
- /// Creates a stringifier that adds annotations from a map;
- /// see [Node.debugString].
- SExpressionStringifier withAnnotations(Map annotations) {
- return withDecorator(decoratorFromMap(annotations));
- }
-
- static Decorator decoratorFromMap(Map annotations) {
- Map<Node, String> nodeMap = {};
- for (var key in annotations.keys) {
- if (key is Node) {
- nodeMap[key] = '${annotations[key]}';
- } else {
- String text = key;
- Node node = annotations[key];
- if (nodeMap.containsKey(node)) {
- // In case two annotations belong to the same node,
- // put both annotations on that node.
- nodeMap[node] += ' $text';
- } else {
- nodeMap[node] = text;
- }
- }
- }
- return (node, string) {
- String text = nodeMap[node];
- if (text != null) return '***$string*** $text';
- return string;
- };
- }
-
- static String typeDecorator(node, String string) {
- return node is Variable ? '$string:${node.type}' : string;
- }
-
- String access(Reference<Definition> r) {
- if (r == null) return '**** NULL ****';
- return decorator(r, namer.getName(r.definition));
- }
-
- String optionalAccess(Reference<Definition> reference) {
- return reference == null ? '()' : '(${access(reference)})';
- }
-
- String visitParameter(Parameter node) {
- return namer.nameParameter(node);
- }
-
- String visitMutableVariable(MutableVariable node) {
- return namer.nameMutableVariable(node);
- }
-
- /// Main entry point for creating a [String] from a [Node]. All recursive
- /// calls must go through this method.
- String visit(Node node) {
- if (node == null) return '**** NULL ****';
- String s = node.accept(this);
- return decorator(node, s);
- }
-
- String formatOptionalParameter(Parameter parameter) {
- return parameter == null ? '()' : '(${visit(parameter)})';
- }
-
- String visitFunctionDefinition(FunctionDefinition node) {
- String name = node.element.name;
- String interceptorParameter =
- formatOptionalParameter(node.interceptorParameter);
- String thisParameter = formatOptionalParameter(node.receiverParameter);
- String parameters = node.parameters.map(visit).join(' ');
- namer.setReturnContinuation(node.returnContinuation);
- String body = indentBlock(() => visit(node.body));
- return '$indentation'
- '(FunctionDefinition $name $interceptorParameter $thisParameter '
- '($parameters) return\n'
- '$body)';
- }
-
- String visitLetPrim(LetPrim node) {
- String name = newValueName(node.primitive);
- String value = visit(node.primitive);
- String bindings = '($name $value)';
- String skip = ' ' * '(LetPrim ('.length;
- while (node.body is LetPrim) {
- node = node.body;
- name = newValueName(node.primitive);
- value = visit(node.primitive);
- String binding = decorator(node, '($name $value)');
- bindings += '\n${indentation}$skip$binding';
- }
- String body = indentBlock(() => visit(node.body));
- return '$indentation(LetPrim ($bindings)\n$body)';
- }
-
- bool isBranchTarget(Continuation cont) {
- return cont.hasExactlyOneUse && cont.firstRef.parent is Branch;
- }
-
- String visitLetCont(LetCont node) {
- String conts;
- bool first = true;
- String skip = ' ' * '(LetCont ('.length;
- for (Continuation continuation in node.continuations) {
- // Branch continuations will be printed at their use site.
- if (isBranchTarget(continuation)) continue;
- if (first) {
- first = false;
- conts = visit(continuation);
- } else {
- // Each subsequent line is indented additional spaces to align it
- // with the previous continuation.
- conts += '\n${indentation}$skip${visit(continuation)}';
- }
- }
- // If there were no continuations printed, just print the body.
- if (first) return visit(node.body);
-
- String body = indentBlock(() => visit(node.body));
- return '$indentation(LetCont ($conts)\n$body)';
- }
-
- String visitLetHandler(LetHandler node) {
- // There are no explicit references to the handler, so we leave it
- // anonymous in the printed representation.
- String parameters = node.handler.parameters
- .map((p) => '${decorator(p, newValueName(p))}')
- .join(' ');
- String handlerBody =
- indentBlock(() => indentBlock(() => visit(node.handler.body)));
- String body = indentBlock(() => visit(node.body));
- return '$indentation(LetHandler (($parameters)\n$handlerBody)\n$body)';
- }
-
- String visitLetMutable(LetMutable node) {
- String name = visit(node.variable);
- String value = access(node.valueRef);
- String body = indentBlock(() => visit(node.body));
- return '$indentation(LetMutable ($name $value)\n$body)';
- }
-
- String formatArguments(
- CallStructure call, List<Reference<Primitive>> arguments,
- [CallingConvention callingConvention = CallingConvention.Normal]) {
- int positionalArgumentCount = call.positionalArgumentCount;
- List<String> args =
- arguments.take(positionalArgumentCount).map(access).toList();
- List<String> argumentNames = call.getOrderedNamedArguments();
- for (int i = 0; i < argumentNames.length; ++i) {
- String name = argumentNames[i];
- String arg = access(arguments[positionalArgumentCount + i]);
- args.add("($name: $arg)");
- }
- // Constructors can have type parameter after the named arguments.
- args.addAll(arguments
- .skip(positionalArgumentCount + argumentNames.length)
- .map(access));
- return '(${args.join(' ')})';
- }
-
- String visitInvokeStatic(InvokeStatic node) {
- String name = node.target.name;
- String args =
- formatArguments(node.selector.callStructure, node.argumentRefs);
- return '(InvokeStatic $name $args)';
- }
-
- String visitInvokeMethod(InvokeMethod node) {
- String name = node.selector.name;
- String interceptor = optionalAccess(node.interceptorRef);
- String receiver = access(node.receiverRef);
- String arguments = formatArguments(
- node.selector.callStructure, node.argumentRefs, node.callingConvention);
- return '(InvokeMethod $interceptor $receiver $name $arguments)';
- }
-
- String visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- String interceptor = optionalAccess(node.interceptorRef);
- String receiver = access(node.receiverRef);
- String name = node.selector.name;
- String arguments = formatArguments(
- node.selector.callStructure, node.argumentRefs, node.callingConvention);
- return '(InvokeMethodDirectly $interceptor $receiver $name $arguments)';
- }
-
- String visitInvokeConstructor(InvokeConstructor node) {
- // TODO(karlklose): for illegal nodes constructed for tests or unresolved
- // constructor calls in the DartBackend, we get an element with no enclosing
- // class. Clean this up by introducing a name field to the node and
- // removing [ErroneousElement]s from the IR.
- String name = node.dartType != null
- ? node.dartType.toString()
- : node.target.enclosingClass.name;
- if (!node.target.name.isEmpty) {
- name = '${name}.${node.target.name}';
- }
- String args =
- formatArguments(node.selector.callStructure, node.argumentRefs);
- return '(InvokeConstructor $name $args)';
- }
-
- String visitInvokeContinuation(InvokeContinuation node) {
- String name = access(node.continuationRef);
- if (node.isRecursive) name = 'rec $name';
- String args = node.argumentRefs == null
- ? '**** NULL ****'
- : node.argumentRefs.map(access).join(' ');
- String escaping = node.isEscapingTry ? ' escape' : '';
- return '$indentation(InvokeContinuation $name ($args)$escaping)';
- }
-
- String visitThrow(Throw node) {
- String value = access(node.valueRef);
- return '$indentation(Throw $value)';
- }
-
- String visitRethrow(Rethrow node) {
- return '$indentation(Rethrow)';
- }
-
- String visitBranch(Branch node) {
- String condition = access(node.conditionRef);
- assert(isBranchTarget(node.trueContinuation));
- assert(isBranchTarget(node.falseContinuation));
- String trueCont = indentBlock(() => visit(node.trueContinuation));
- String falseCont = indentBlock(() => visit(node.falseContinuation));
- String strict = node.isStrictCheck ? 'Strict' : 'NonStrict';
- return '$indentation(Branch $strict $condition\n$trueCont\n$falseCont)';
- }
-
- String visitUnreachable(Unreachable node) {
- return '$indentation(Unreachable)';
- }
-
- String visitConstant(Constant node) {
- String value = node.value.accept(new ConstantStringifier(), null);
- return '(Constant $value)';
- }
-
- String visitContinuation(Continuation node) {
- if (isBranchTarget(node)) {
- assert(node.parameters.isEmpty);
- assert(!node.isRecursive);
- return indentBlock(() => visit(node.body));
- }
- String name = newContinuationName(node);
- if (node.isRecursive) name = 'rec $name';
- // TODO(karlklose): this should be changed to `.map(visit).join(' ')`
- // and should recurse to [visit]. Currently we can't do that, because
- // the unstringifier_test produces [LetConts] with dummy arguments on
- // them.
- String parameters = node.parameters
- .map((p) => '${decorator(p, newValueName(p))}')
- .join(' ');
- String body = indentBlock(() => indentBlock(() => visit(node.body)));
- return '($name ($parameters)\n$body)';
- }
-
- String visitGetMutable(GetMutable node) {
- return '(GetMutable ${access(node.variableRef)})';
- }
-
- String visitSetMutable(SetMutable node) {
- String value = access(node.valueRef);
- return '(SetMutable ${access(node.variableRef)} $value)';
- }
-
- String visitTypeCast(TypeCast node) {
- 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.valueRef);
- String typeArguments = node.typeArgumentRefs.map(access).join(' ');
- return '(TypeTest $value ${node.dartType} ($typeArguments))';
- }
-
- String visitTypeTestViaFlag(TypeTestViaFlag node) {
- String interceptor = access(node.interceptorRef);
- return '(TypeTestViaFlag $interceptor ${node.dartType})';
- }
-
- String visitLiteralList(LiteralList node) {
- String values = node.valueRefs.map(access).join(' ');
- return '(LiteralList ($values))';
- }
-
- String visitSetField(SetField node) {
- String object = access(node.objectRef);
- String field = node.field.name;
- String value = access(node.valueRef);
- return '(SetField $object $field $value)';
- }
-
- String visitGetField(GetField node) {
- String object = access(node.objectRef);
- String field = node.field.name;
- return '(GetField $object $field)';
- }
-
- String visitGetStatic(GetStatic node) {
- String element = node.element.name;
- return '(GetStatic $element)';
- }
-
- String visitSetStatic(SetStatic node) {
- String element = node.element.name;
- String value = access(node.valueRef);
- return '(SetStatic $element $value)';
- }
-
- String visitGetLazyStatic(GetLazyStatic node) {
- String element = node.element.name;
- return '(GetLazyStatic $element)';
- }
-
- String visitCreateBox(CreateBox node) {
- return '(CreateBox)';
- }
-
- String visitCreateInstance(CreateInstance node) {
- String className = node.classElement.name;
- 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.inputRef)})';
- }
-
- String visitReifyRuntimeType(ReifyRuntimeType node) {
- return '(ReifyRuntimeType ${access(node.valueRef)})';
- }
-
- String visitReadTypeVariable(ReadTypeVariable node) {
- return '(ReadTypeVariable ${access(node.targetRef)}.${node.variable})';
- }
-
- String visitTypeExpression(TypeExpression node) {
- 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.argumentRefs.map(access).join(' ');
- return '(CreateInvocationMirror $selector ($args))';
- }
-
- String visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- String operator = node.operator.toString();
- String args = node.argumentRefs.map(access).join(' ');
- return '(ApplyBuiltinOperator $operator ($args))';
- }
-
- String visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- String method = node.method.toString();
- String receiver = access(node.receiverRef);
- String args = node.argumentRefs.map(access).join(' ');
- return '(ApplyBuiltinMethod $method $receiver ($args))';
- }
-
- String visitForeignCode(ForeignCode node) {
- String arguments = node.argumentRefs.map(access).join(' ');
- return '(JS "${node.codeTemplate.source}" ($arguments))';
- }
-
- String visitGetLength(GetLength node) {
- String object = access(node.objectRef);
- return '(GetLength $object)';
- }
-
- String visitGetIndex(GetIndex node) {
- String object = access(node.objectRef);
- String index = access(node.indexRef);
- return '(GetIndex $object $index)';
- }
-
- String visitSetIndex(SetIndex node) {
- 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.inputRef);
- return '(Await $value)';
- }
-
- @override
- String visitYield(Yield node) {
- String value = access(node.inputRef);
- return '(Yield $value)';
- }
-
- String visitRefinement(Refinement node) {
- String value = access(node.value);
- return '(Refinement $value ${node.type})';
- }
-
- String visitBoundsCheck(BoundsCheck node) {
- 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.valueRef);
- String condition = optionalAccess(node.conditionRef);
- return '(ReceiverCheck $value ${node.selector} $condition '
- '${node.flagString}))';
- }
-}
-
-class ConstantStringifier extends ConstantValueVisitor<String, Null> {
- // Some of these methods are unimplemented because we haven't had a need
- // to print such constants. When printing is implemented, the corresponding
- // parsing support should be added to SExpressionUnstringifier.parseConstant
- // in the dart2js tests (currently in the file
- // tests/compiler/dart2js/backend_dart/sexpr_unstringifier.dart).
-
- String _failWith(ConstantValue constant) {
- throw 'Stringification not supported for ${constant.toStructuredText()}';
- }
-
- String visitFunction(FunctionConstantValue constant, _) {
- return '(Function "${constant.toDartText()}")';
- }
-
- String visitNull(NullConstantValue constant, _) {
- return '(Null)';
- }
-
- String visitNonConstant(NonConstantValue constant, _) {
- return '(NonConstant)';
- }
-
- String visitInt(IntConstantValue constant, _) {
- return '(Int ${constant.toDartText()})';
- }
-
- String visitDouble(DoubleConstantValue constant, _) {
- return '(Double ${constant.toDartText()})';
- }
-
- String visitBool(BoolConstantValue constant, _) {
- return '(Bool ${constant.toDartText()})';
- }
-
- String visitString(StringConstantValue constant, _) {
- return '(String ${constant.toDartText()})';
- }
-
- String visitList(ListConstantValue constant, _) {
- String entries =
- constant.entries.map((entry) => entry.accept(this, _)).join(' ');
- return '(List $entries)';
- }
-
- String visitMap(MapConstantValue constant, _) {
- List<String> elements = <String>[];
- for (int i = 0; i < constant.keys.length; ++i) {
- ConstantValue key = constant.keys[i];
- ConstantValue value = constant.values[i];
- elements.add('(${key.accept(this, _)} . ${value.accept(this, _)})');
- }
- return '(Map (${elements.join(' ')}))';
- }
-
- String visitConstructed(ConstructedConstantValue constant, _) {
- return '(Constructed "${constant.toDartText()}")';
- }
-
- String visitType(TypeConstantValue constant, _) {
- return '(Type "${constant.representedType}")';
- }
-
- String visitInterceptor(InterceptorConstantValue constant, _) {
- return '(Interceptor "${constant.toDartText()}")';
- }
-
- String visitSynthetic(SyntheticConstantValue constant, _) {
- return '(Synthetic "${constant.toDartText()}")';
- }
-
- String visitDeferred(DeferredConstantValue constant, _) {
- return _failWith(constant);
- }
-}
-
-class _Namer {
- final Map<Node, String> _names = <Node, String>{};
- int _valueCounter = 0;
- int _continuationCounter = 0;
-
- // TODO(sra): Make the methods not assert and print something indicating an
- // error, so printer can be used to inspect broken terms.
-
- String nameParameter(Parameter parameter) {
- assert(!_names.containsKey(parameter));
- String name =
- parameter.hint != null ? parameter.hint.name : nameValue(parameter);
- return _names[parameter] = name;
- }
-
- String nameMutableVariable(MutableVariable variable) {
- assert(!_names.containsKey(variable));
- return _names[variable] = variable.hint.name;
- }
-
- String nameContinuation(Continuation node) {
- assert(!_names.containsKey(node));
- return _names[node] = 'k${_continuationCounter++}';
- }
-
- String nameValue(Primitive node) {
- assert(!_names.containsKey(node));
- return _names[node] = 'v${_valueCounter++}';
- }
-
- void setReturnContinuation(Continuation node) {
- assert(!_names.containsKey(node) || _names[node] == 'return');
- _names[node] = 'return';
- }
-
- String getName(Node node) {
- if (!_names.containsKey(node)) return 'MISSING_NAME';
- return _names[node];
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
deleted file mode 100644
index 3f13ee7..0000000
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ /dev/null
@@ -1,684 +0,0 @@
-// 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 dart2js.ir_tracer;
-
-import 'dart:async' show EventSink;
-
-import '../tracer.dart';
-import 'cps_ir_nodes.dart' as cps_ir;
-
-/**
- * If true, show LetCont expressions in output.
- */
-const bool IR_TRACE_LET_CONT = false;
-
-class IRTracer extends TracerUtil implements cps_ir.Visitor {
- EventSink<String> output;
-
- IRTracer(this.output);
-
- visit(cps_ir.Node node) => node.accept(this);
-
- void traceGraph(String name, cps_ir.FunctionDefinition node) {
- tag("cfg", () {
- printProperty("name", name);
-
- names = new Names();
- BlockCollector builder = new BlockCollector(names);
- builder.visit(node);
-
- for (Block block in builder.entries) {
- printBlock(block, entryPoint: node);
- }
- for (Block block in builder.cont2block.values) {
- printBlock(block);
- }
- names = null;
- });
- }
-
- // Temporary field used during tree walk
- Names names;
-
- visitFunctionDefinition(cps_ir.FunctionDefinition node) {
- unexpectedNode(node);
- }
-
- // Bodies and initializers are not visited. They contain continuations which
- // are found by a BlockCollector, then those continuations are processed by
- // this visitor.
- unexpectedNode(cps_ir.Node node) {
- throw 'The IR tracer reached an unexpected IR instruction: $node';
- }
-
- int countUses(cps_ir.Definition definition) {
- int count = 0;
- cps_ir.Reference ref = definition.firstRef;
- while (ref != null) {
- ++count;
- ref = ref.next;
- }
- return count;
- }
-
- /// If [entryPoint] is given, this block is an entry point.
- printBlock(Block block, {cps_ir.FunctionDefinition entryPoint}) {
- tag("block", () {
- printProperty("name", block.name);
- printProperty("from_bci", -1);
- printProperty("to_bci", -1);
- printProperty("predecessors", block.pred.map((n) => n.name));
- printProperty("successors", block.succ.map((n) => n.name));
- printEmptyProperty("xhandlers");
- printEmptyProperty("flags");
- tag("states", () {
- tag("locals", () {
- printProperty("size", 0);
- printProperty("method", "None");
- });
- });
- tag("HIR", () {
- String formatParameter(cps_ir.Parameter param) {
- return '${names.name(param)} ${param.type}';
- }
- if (entryPoint != null) {
- String thisParam = entryPoint.receiverParameter != null
- ? formatParameter(entryPoint.receiverParameter)
- : 'no receiver';
- String interceptorParam = entryPoint.interceptorParameter != null
- ? formatParameter(entryPoint.interceptorParameter)
- : 'no interceptor';
- String params = entryPoint.parameters.map(formatParameter).join(', ');
- printStmt('x0', 'Entry ($interceptorParam) ($thisParam) ($params)');
- }
- String params = block.parameters.map(formatParameter).join(', ');
- printStmt('x0', 'Parameters ($params)');
- visit(block.body);
- });
- });
- }
-
- void printStmt(String resultVar, String contents) {
- int bci = 0;
- int uses = 0;
- addIndent();
- add("$bci $uses $resultVar $contents <|@\n");
- }
-
- visitLetPrim(cps_ir.LetPrim node) {
- String id = names.name(node.primitive);
- String primitive = visit(node.primitive);
- printStmt(id, "LetPrim $id = $primitive [type=${node.primitive.type}]");
- visit(node.body);
- }
-
- visitLetCont(cps_ir.LetCont node) {
- if (IR_TRACE_LET_CONT) {
- String dummy = names.name(node);
-
- String nameContinuation(cps_ir.Continuation cont) {
- String name = names.name(cont);
- return cont.isRecursive ? '$name*' : name;
- }
-
- String ids = node.continuations.map(nameContinuation).join(', ');
- printStmt(dummy, "LetCont $ids");
- }
- visit(node.body);
- }
-
- visitLetHandler(cps_ir.LetHandler node) {
- if (IR_TRACE_LET_CONT) {
- String dummy = names.name(node);
- String id = names.name(node.handler);
- printStmt(dummy, "LetHandler $id = <$id>");
- }
- visit(node.body);
- }
-
- visitLetMutable(cps_ir.LetMutable node) {
- String id = names.name(node.variable);
- printStmt(id, "LetMutable $id = ${formatReference(node.valueRef)}");
- visit(node.body);
- }
-
- visitInvokeStatic(cps_ir.InvokeStatic node) {
- String callName = node.selector.name;
- String args = node.argumentRefs.map(formatReference).join(', ');
- return "InvokeStatic $callName ($args)";
- }
-
- visitInvokeMethod(cps_ir.InvokeMethod node) {
- String receiver = formatReference(node.receiverRef);
- String callName = node.selector.name;
- String args = node.argumentRefs.map(formatReference).join(', ');
- return "InvokeMethod $receiver $callName ($args)";
- }
-
- visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
- String receiver = formatReference(node.receiverRef);
- String callName = node.selector.name;
- String args = node.argumentRefs.map(formatReference).join(', ');
- return "InvokeMethodDirectly $receiver $callName ($args)";
- }
-
- visitInvokeConstructor(cps_ir.InvokeConstructor node) {
- String className = node.target.enclosingClass.name;
- String callName;
- if (node.target.name.isEmpty) {
- callName = '${className}';
- } else {
- callName = '${className}.${node.target.name}';
- }
- 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.valueRef);
- printStmt(dummy, "Throw $value");
- }
-
- visitRethrow(cps_ir.Rethrow node) {
- String dummy = names.name(node);
- printStmt(dummy, "Rethrow");
- }
-
- visitUnreachable(cps_ir.Unreachable node) {
- String dummy = names.name(node);
- printStmt(dummy, 'Unreachable');
- }
-
- visitLiteralList(cps_ir.LiteralList node) {
- String values = node.valueRefs.map(formatReference).join(', ');
- return "LiteralList ($values)";
- }
-
- visitTypeCast(cps_ir.TypeCast node) {
- 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.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.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.inputRef);
- return 'Await $value';
- }
-
- visitYield(cps_ir.Yield node) {
- String name = node.hasStar ? 'YieldStar' : 'Yield';
- String value = formatReference(node.inputRef);
- return '$name $value';
- }
-
- visitSetMutable(cps_ir.SetMutable node) {
- String variable = names.name(node.variable);
- String value = formatReference(node.valueRef);
- return 'SetMutable $variable := $value';
- }
-
- String formatReference(cps_ir.Reference ref) {
- if (ref == null) return 'null';
- cps_ir.Definition target = ref.definition;
- if (target is cps_ir.Continuation && target.isReturnContinuation) {
- return "return"; // Do not generate a name for the return continuation
- } else {
- return names.name(ref.definition);
- }
- }
-
- visitConstant(cps_ir.Constant node) {
- return "Constant ${node.value.toStructuredText()}";
- }
-
- visitParameter(cps_ir.Parameter node) {
- return "Parameter ${names.name(node)}";
- }
-
- visitMutableVariable(cps_ir.MutableVariable node) {
- return "MutableVariable ${names.name(node)}";
- }
-
- visitContinuation(cps_ir.Continuation node) {
- return "Continuation ${names.name(node)}";
- }
-
- visitSetField(cps_ir.SetField node) {
- String object = formatReference(node.objectRef);
- String field = node.field.name;
- String value = formatReference(node.valueRef);
- return 'SetField $object.$field = $value';
- }
-
- visitGetField(cps_ir.GetField node) {
- String object = formatReference(node.objectRef);
- String field = node.field.name;
- String finalFlag = node.isFinal ? 'final' : 'non-final';
- return 'GetField $object.$field $finalFlag';
- }
-
- visitGetStatic(cps_ir.GetStatic node) {
- String element = node.element.name;
- 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.valueRef);
- return 'SetStatic $element = $value';
- }
-
- visitGetLazyStatic(cps_ir.GetLazyStatic node) {
- String element = node.element.name;
- String finalFlag = node.isFinal ? 'final' : 'non-final';
- return "GetLazyStatic $element $finalFlag";
- }
-
- visitCreateBox(cps_ir.CreateBox node) {
- return 'CreateBox';
- }
-
- visitCreateInstance(cps_ir.CreateInstance node) {
- String className = node.classElement.name;
- 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.inputRef)}, '
- '${node.interceptedClasses})';
- }
-
- visitGetMutable(cps_ir.GetMutable node) {
- String variable = names.name(node.variable);
- return 'GetMutable $variable';
- }
-
- visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
- return "ReadTypeVariable ${node.variable.element} "
- "${formatReference(node.targetRef)}";
- }
-
- visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
- return "ReifyRuntimeType ${formatReference(node.valueRef)}";
- }
-
- visitTypeExpression(cps_ir.TypeExpression node) {
- return "TypeExpression ${node.kindAsString} ${node.dartType}"
- "${node.argumentRefs.map(formatReference).join(', ')}";
- }
-
- visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
- String args = node.argumentRefs.map(formatReference).join(', ');
- return "CreateInvocationMirror(${node.selector.name}, $args)";
- }
-
- visitTypeTest(cps_ir.TypeTest node) {
- 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.interceptorRef);
- return "TypeTestViaFlag ($interceptor ${node.dartType})";
- }
-
- visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
- String operator = node.operator.toString();
- 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.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.argumentRefs.map(formatReference).join(', ');
- printStmt(
- id, "ForeignCode ${node.type} ${node.codeTemplate.source} $arguments");
- }
-
- visitGetLength(cps_ir.GetLength node) {
- 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.objectRef);
- String index = formatReference(node.indexRef);
- return 'GetIndex $object $index';
- }
-
- visitSetIndex(cps_ir.SetIndex node) {
- String object = formatReference(node.objectRef);
- String index = formatReference(node.indexRef);
- String value = formatReference(node.valueRef);
- return 'SetIndex $object $index $value';
- }
-
- visitRefinement(cps_ir.Refinement node) {
- String value = formatReference(node.value);
- return 'Refinement $value ${node.refineType}';
- }
-
- visitBoundsCheck(cps_ir.BoundsCheck node) {
- String object = formatReference(node.objectRef);
- String index =
- node.indexRef == null ? 'no-index' : formatReference(node.indexRef);
- String length =
- node.lengthRef == null ? 'no-length' : formatReference(node.lengthRef);
- return 'BoundsCheck $object $index $length ${node.checkString}';
- }
-
- visitReceiverCheck(cps_ir.ReceiverCheck node) {
- String value = formatReference(node.valueRef);
- String condition = formatReference(node.conditionRef);
- return 'ReceiverCheck $value $condition ${node.selector} '
- '${node.flagString}';
- }
-}
-
-/**
- * Invents (and remembers) names for Continuations, Parameters, etc.
- * The names must match the conventions used by IR Hydra, e.g.
- * Continuations and Functions must have names of form B### since they
- * are visualized as basic blocks.
- */
-class Names {
- final Map<Object, String> names = {};
- final Map<String, int> counters = {'r': 0, 'B': 0, 'v': 0, 'x': 0, 'c': 0};
-
- String prefix(x) {
- if (x is cps_ir.Parameter) return 'r';
- if (x is cps_ir.Continuation || x is cps_ir.FunctionDefinition) return 'B';
- if (x is cps_ir.Primitive) return 'v';
- if (x is cps_ir.MutableVariable) return 'c';
- return 'x';
- }
-
- String name(x) {
- String nam = names[x];
- if (nam == null) {
- String pref = prefix(x);
- int id = counters[pref]++;
- nam = names[x] = '${pref}${id}';
- }
- return nam;
- }
-}
-
-/**
- * A vertex in the graph visualization, used in place of basic blocks.
- */
-class Block {
- String name;
- final List<cps_ir.Parameter> parameters;
- final cps_ir.Expression body;
- final List<Block> succ = <Block>[];
- final List<Block> pred = <Block>[];
-
- Block(this.name, this.parameters, this.body);
-
- void addEdgeTo(Block successor) {
- succ.add(successor);
- successor.pred.add(this);
- }
-}
-
-class BlockCollector implements cps_ir.Visitor {
- final Map<cps_ir.Continuation, Block> cont2block =
- <cps_ir.Continuation, Block>{};
- final Set<Block> entries = new Set<Block>();
- Block currentBlock;
-
- Names names;
- BlockCollector(this.names);
-
- Block getBlock(cps_ir.Continuation c) {
- Block block = cont2block[c];
- if (block == null) {
- block = new Block(names.name(c), c.parameters, c.body);
- cont2block[c] = block;
- }
- return block;
- }
-
- visit(cps_ir.Node node) => node.accept(this);
-
- visitFunctionDefinition(cps_ir.FunctionDefinition node) {
- currentBlock = new Block(names.name(node), [], node.body);
- entries.add(currentBlock);
- visit(node.body);
- }
-
- visitLetPrim(cps_ir.LetPrim exp) {
- visit(exp.body);
- }
-
- visitLetCont(cps_ir.LetCont exp) {
- exp.continuations.forEach(visit);
- visit(exp.body);
- }
-
- visitLetHandler(cps_ir.LetHandler exp) {
- visit(exp.handler);
- visit(exp.body);
- }
-
- visitLetMutable(cps_ir.LetMutable exp) {
- visit(exp.body);
- }
-
- void addEdgeToContinuation(cps_ir.Reference continuation) {
- cps_ir.Definition target = continuation.definition;
- if (target is cps_ir.Continuation && !target.isReturnContinuation) {
- currentBlock.addEdgeTo(getBlock(target));
- }
- }
-
- visitInvokeContinuation(cps_ir.InvokeContinuation exp) {
- addEdgeToContinuation(exp.continuationRef);
- }
-
- visitInvokeStatic(cps_ir.InvokeStatic node) {
- unexpectedNode(node);
- }
-
- visitInvokeMethod(cps_ir.InvokeMethod node) {
- unexpectedNode(node);
- }
-
- visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
- unexpectedNode(node);
- }
-
- visitInvokeConstructor(cps_ir.InvokeConstructor node) {
- unexpectedNode(node);
- }
-
- visitThrow(cps_ir.Throw exp) {}
-
- visitRethrow(cps_ir.Rethrow exp) {}
-
- visitUnreachable(cps_ir.Unreachable node) {}
-
- visitGetLazyStatic(cps_ir.GetLazyStatic node) {
- unexpectedNode(node);
- }
-
- visitBranch(cps_ir.Branch exp) {
- cps_ir.Continuation trueTarget = exp.trueContinuation;
- if (!trueTarget.isReturnContinuation) {
- currentBlock.addEdgeTo(getBlock(trueTarget));
- }
- cps_ir.Continuation falseTarget = exp.falseContinuation;
- if (!falseTarget.isReturnContinuation) {
- currentBlock.addEdgeTo(getBlock(falseTarget));
- }
- }
-
- visitTypeCast(cps_ir.TypeCast node) {
- unexpectedNode(node);
- }
-
- visitContinuation(cps_ir.Continuation c) {
- var old_node = currentBlock;
- currentBlock = getBlock(c);
- visit(c.body);
- currentBlock = old_node;
- }
-
- // Primitives and conditions are not visited when searching for blocks.
- unexpectedNode(cps_ir.Node node) {
- throw "The IR tracer's block collector reached an unexpected IR "
- "instruction: $node";
- }
-
- visitLiteralList(cps_ir.LiteralList node) {
- unexpectedNode(node);
- }
-
- visitConstant(cps_ir.Constant node) {
- unexpectedNode(node);
- }
-
- visitGetMutable(cps_ir.GetMutable node) {
- unexpectedNode(node);
- }
-
- visitParameter(cps_ir.Parameter node) {
- unexpectedNode(node);
- }
-
- visitMutableVariable(cps_ir.MutableVariable node) {
- unexpectedNode(node);
- }
-
- visitGetField(cps_ir.GetField node) {
- unexpectedNode(node);
- }
-
- visitGetStatic(cps_ir.GetStatic node) {
- unexpectedNode(node);
- }
-
- visitCreateBox(cps_ir.CreateBox node) {
- unexpectedNode(node);
- }
-
- visitCreateInstance(cps_ir.CreateInstance node) {
- unexpectedNode(node);
- }
-
- visitInterceptor(cps_ir.Interceptor node) {
- unexpectedNode(node);
- }
-
- visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
- unexpectedNode(node);
- }
-
- visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
- unexpectedNode(node);
- }
-
- visitTypeExpression(cps_ir.TypeExpression node) {
- unexpectedNode(node);
- }
-
- visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
- unexpectedNode(node);
- }
-
- visitTypeTest(cps_ir.TypeTest node) {
- unexpectedNode(node);
- }
-
- visitTypeTestViaFlag(cps_ir.TypeTestViaFlag node) {
- unexpectedNode(node);
- }
-
- visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
- unexpectedNode(node);
- }
-
- visitApplyBuiltinMethod(cps_ir.ApplyBuiltinMethod node) {
- unexpectedNode(node);
- }
-
- visitGetLength(cps_ir.GetLength node) {
- unexpectedNode(node);
- }
-
- visitGetIndex(cps_ir.GetIndex node) {
- unexpectedNode(node);
- }
-
- visitSetIndex(cps_ir.SetIndex node) {
- unexpectedNode(node);
- }
-
- visitSetMutable(cps_ir.SetMutable node) {
- unexpectedNode(node);
- }
-
- visitSetField(cps_ir.SetField node) {
- unexpectedNode(node);
- }
-
- visitSetStatic(cps_ir.SetStatic node) {
- unexpectedNode(node);
- }
-
- visitForeignCode(cps_ir.ForeignCode node) {
- unexpectedNode(node);
- }
-
- visitAwait(cps_ir.Await node) {
- unexpectedNode(node);
- }
-
- visitYield(cps_ir.Yield node) {
- unexpectedNode(node);
- }
-
- visitRefinement(cps_ir.Refinement node) {
- unexpectedNode(node);
- }
-
- visitBoundsCheck(cps_ir.BoundsCheck node) {
- unexpectedNode(node);
- }
-
- visitReceiverCheck(cps_ir.ReceiverCheck node) {
- unexpectedNode(node);
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart b/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart
deleted file mode 100644
index b936885..0000000
--- a/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart
+++ /dev/null
@@ -1,76 +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 dart2js.cps_ir.eagerly_load_statics;
-
-import '../elements/elements.dart';
-import 'cps_fragment.dart';
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart' show Pass;
-
-/// Replaces [GetLazyStatic] with [GetStatic] when the static field is known
-/// to have been initialized.
-///
-/// Apart from [GetStatic] generating better code, this improves the side-effect
-/// analysis in the [GVN] pass, since [GetStatic] has no effects.
-class EagerlyLoadStatics extends TrampolineRecursiveVisitor implements Pass {
- String get passName => 'Eagerly load statics';
-
- Map<FieldElement, Primitive> initializerFor = <FieldElement, Primitive>{};
-
- final Map<Continuation, Map<FieldElement, Primitive>> initializersAt =
- <Continuation, Map<FieldElement, Primitive>>{};
-
- static Map<FieldElement, Primitive> cloneFieldMap(
- Map<FieldElement, Primitive> map) {
- return new Map<FieldElement, Primitive>.from(map);
- }
-
- void rewrite(FunctionDefinition node) {
- 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);
- push(cont);
- }
- return node.body;
- }
-
- Expression traverseLetHandler(LetHandler node) {
- initializersAt[node.handler] = cloneFieldMap(initializerFor);
- push(node.handler);
- return node.body;
- }
-
- Expression traverseContinuation(Continuation cont) {
- initializerFor = initializersAt[cont];
- return cont.body;
- }
-
- void visitGetLazyStatic(GetLazyStatic node) {
- Primitive initializer = initializerFor[node.element];
- 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;
- }
- }
-
- void visitSetStatic(SetStatic node) {
- initializerFor.putIfAbsent(node.element, () => node);
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/effects.dart b/pkg/compiler/lib/src/cps_ir/effects.dart
deleted file mode 100644
index 2a28785..0000000
--- a/pkg/compiler/lib/src/cps_ir/effects.dart
+++ /dev/null
@@ -1,200 +0,0 @@
-// 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
deleted file mode 100644
index 7f0e7e0..0000000
--- a/pkg/compiler/lib/src/cps_ir/finalize.dart
+++ /dev/null
@@ -1,108 +0,0 @@
-library dart2js.cps_ir.finalize;
-
-import '../js/js.dart' as js;
-import '../js_backend/backend_helpers.dart';
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import 'cps_fragment.dart';
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart' show Pass;
-
-/// A transformation pass that must run immediately before the tree IR builder.
-///
-/// This expands [BoundsCheck] nodes into more low-level operations.
-class Finalize extends TrampolineRecursiveVisitor implements Pass {
- String get passName => 'Finalize';
-
- JavaScriptBackend backend;
- BackendHelpers get helpers => backend.helpers;
-
- Finalize(this.backend);
-
- void rewrite(FunctionDefinition node) {
- visit(node);
- }
-
- Expression traverseLetPrim(LetPrim node) {
- CpsFragment cps = visit(node.primitive);
- if (cps == null) return node.body;
- cps.insertBelow(node);
- Expression next = node.body;
- node.remove();
- return next;
- }
-
- bool areAdjacent(Primitive first, Primitive second) {
- return first.parent == second.parent.parent;
- }
-
- CpsFragment visitBoundsCheck(BoundsCheck node) {
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- if (node.hasNoChecks) {
- node
- ..replaceUsesWith(node.object)
- ..destroy();
- return cps;
- }
- Continuation fail = cps.letCont();
- Primitive index = node.index;
- if (node.hasIntegerCheck) {
- cps
- .ifTruthy(cps.applyBuiltin(
- BuiltinOperator.IsNotUnsigned32BitInteger, [index, index]))
- .invokeContinuation(fail);
- } else if (node.hasLowerBoundCheck) {
- cps
- .ifTruthy(
- cps.applyBuiltin(BuiltinOperator.NumLt, [index, cps.makeZero()]))
- .invokeContinuation(fail);
- }
- if (node.hasUpperBoundCheck) {
- Primitive length = node.length;
- if (length is GetLength &&
- length.hasExactlyOneUse &&
- areAdjacent(length, node)) {
- // Rebind the GetLength here, so it does not get stuck outside the
- // condition, blocked from propagating by the lower bounds check.
- LetPrim lengthBinding = length.parent;
- lengthBinding.remove();
- cps.letPrim(length);
- }
- cps
- .ifTruthy(cps.applyBuiltin(BuiltinOperator.NumGe, [index, length]))
- .invokeContinuation(fail);
- }
- if (node.hasEmptinessCheck) {
- cps
- .ifTruthy(cps.applyBuiltin(
- BuiltinOperator.StrictEq, [node.length, cps.makeZero()]))
- .invokeContinuation(fail);
- }
- cps.insideContinuation(fail).invokeStaticThrower(
- helpers.throwIndexOutOfRangeException, [node.object, index]);
- node
- ..replaceUsesWith(node.object)
- ..destroy();
- return cps;
- }
-
- void visitGetStatic(GetStatic node) {
- if (node.witnessRef != null) {
- node
- ..witnessRef.unlink()
- ..witnessRef = null;
- }
- }
-
- void visitForeignCode(ForeignCode node) {
- if (js.isIdentityTemplate(node.codeTemplate)) {
- // The CPS builder replaces identity templates with refinements, except
- // when the refined type is an array type. Some optimizations assume the
- // 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.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
deleted file mode 100644
index 4c49d7a..0000000
--- a/pkg/compiler/lib/src/cps_ir/gvn.dart
+++ /dev/null
@@ -1,618 +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 dart2js.cps_ir.gvn;
-
-import '../compiler.dart' show Compiler;
-import '../elements/elements.dart';
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import '../world.dart';
-import 'cps_ir_nodes.dart';
-import 'effects.dart';
-import 'loop_effects.dart';
-import 'loop_hierarchy.dart';
-import 'optimizers.dart' show Pass;
-import 'type_mask_system.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
-/// loops when possible.
-///
-/// Reusing values can introduce new temporaries, which in some cases is more
-/// expensive than recomputing the value on-demand. For example, pulling an
-/// expression such as "n+1" out of a loop is generally not worth it.
-/// Such primitives are said to be "trivial".
-///
-/// Trivial primitives are shared on-demand, i.e. they are only shared if
-/// this enables a non-trivial primitive to be hoisted out of a loop.
-//
-// TODO(asgerf): Enable hoisting across refinement guards when this is safe:
-// - Determine the type required for a given primitive to be "safe"
-// - Recompute the type of a primitive after hoisting.
-// E.g. GetIndex on a String can become a GetIndex on an arbitrary
-// indexable, which is still safe but the type may change
-// - Since the new type may be worse, insert a refinement at the old
-// definition site, so we do not degrade existing type information.
-//
-class GVN extends TrampolineRecursiveVisitor implements Pass {
- String get passName => 'GVN';
-
- final Compiler compiler;
- final TypeMaskSystem types;
- JavaScriptBackend get backend => compiler.backend;
- World get world => compiler.world;
-
- final GvnTable gvnTable = new GvnTable();
- GvnVectorBuilder gvnVectorBuilder;
- 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;
-
- /// The loop currently enclosing the binding of a given primitive.
- final Map<Primitive, Continuation> loopHeaderFor =
- <Primitive, Continuation>{};
-
- /// The GVNs for primitives that have been hoisted outside the given loop.
- ///
- /// These should be removed from the environment when exiting the loop.
- final Map<Continuation, List<int>> loopHoistedBindings =
- <Continuation, List<int>>{};
-
- /// Maps GVNs to a currently-in-scope binding for that value.
- final Map<int, Primitive> environment = <int, Primitive>{};
-
- /// Maps GVN'able primitives to their global value number.
- final Map<Primitive, int> gvnFor = <Primitive, int>{};
-
- Continuation currentLoopHeader;
-
- GVN(this.compiler, this.types);
-
- void rewrite(FunctionDefinition node) {
- effectNumbers = new EffectNumbers.fresh(effectNumberer);
- gvnVectorBuilder = new GvnVectorBuilder(gvnFor, compiler, types);
- loopHierarchy = new LoopHierarchy(node);
- loopEffects =
- new LoopSideEffects(node, world, loopHierarchy: loopHierarchy);
- visit(node);
- }
-
- // ------------------ GLOBAL VALUE NUMBERING ---------------------
-
- /// True if [prim] can be eliminated if its value is already in scope.
- bool canReplaceWithExistingValue(Primitive prim) {
- // Primitives that have no side effects other than potentially throwing are
- // known not the throw if the value is already in scope. Handling those
- // specially is equivalent to updating refinements during GVN.
- // GetLazyStatic cannot have side effects because the field has already
- // been initialized.
- return prim.isSafeForElimination ||
- prim is GetField ||
- prim is GetLength ||
- prim is GetIndex ||
- prim is GetLazyStatic;
- }
-
- @override
- Expression traverseLetPrim(LetPrim node) {
- Expression next = node.body;
- Primitive prim = node.primitive;
-
- loopHeaderFor[prim] = currentLoopHeader;
-
- if (prim is Refinement) {
- // Do not share refinements (they have no runtime or code size cost), and
- // do not put them in the GVN table because GvnVectorBuilder unfolds
- // refinements by itself.
- return next;
- }
-
- // Update effect numbers due to side effects from a static initializer.
- // GetLazyStatic is GVN'ed like a GetStatic, but the effects of the static
- // initializer occur before reading the field.
- if (prim is GetLazyStatic) {
- addSideEffectsOfPrimitive(prim);
- }
-
- // Compute the GVN vector for this computation.
- List vector = gvnVectorBuilder.make(prim, effectNumbers);
-
- // Update effect numbers due to side effects.
- // 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) {
- addSideEffectsOfPrimitive(prim);
- }
-
- if (vector == null) {
- // The primitive is not GVN'able. Move on.
- return next;
- }
-
- // Compute the GVN for this primitive.
- int gvn = gvnTable.insert(vector);
- gvnFor[prim] = gvn;
-
- // Try to reuse a previously computed value with the same GVN.
- Primitive existing = environment[gvn];
- if (existing != null &&
- canReplaceWithExistingValue(prim) &&
- !isFastConstant(prim)) {
- if (prim is Interceptor) {
- Interceptor interceptor = existing;
- interceptor.interceptedClasses.addAll(prim.interceptedClasses);
- }
- prim
- ..replaceUsesWith(existing)
- ..destroy();
- node.remove();
- return next;
- }
-
- if (tryToHoistOutOfLoop(prim, gvn)) {
- return next;
- }
-
- // The primitive could not be hoisted. Put the primitive in the
- // environment while processing the body of the LetPrim.
- environment[gvn] = prim;
- pushAction(() {
- assert(environment[gvn] == prim);
- environment[gvn] = existing;
- });
-
- return next;
- }
-
- bool isFirstImpureExpressionInLoop(Expression exp) {
- InteriorNode node = exp.parent;
- for (; node is Expression; node = node.parent) {
- if (node is LetPrim && node.primitive.isSafeForElimination) {
- continue;
- }
- if (node is LetCont) {
- continue;
- }
- return false;
- }
- return node == currentLoopHeader;
- }
-
- bool isHoistablePrimitive(Primitive prim) {
- if (prim.isSafeForElimination) return true;
- if (prim is ReceiverCheck ||
- prim is BoundsCheck ||
- prim is GetLength ||
- prim is GetField ||
- prim is GetIndex) {
- // Expressions that potentially throw but have no other effects can be
- // hoisted if they occur as the first impure expression in a loop.
- // Note regarding BoundsCheck: the current array length is an input to
- // check, so the check itself has no heap dependency. It will only be
- // hoisted if the length was hoisted.
- // TODO(asgerf): In general we could hoist these out of multiple loops,
- // but the trick we use here only works for one loop level.
- return isFirstImpureExpressionInLoop(prim.parent);
- }
- return false;
- }
-
- /// Try to hoist the binding of [prim] out of loops. Returns `true` if it was
- /// hoisted or marked as a trivial hoist-on-demand primitive.
- bool tryToHoistOutOfLoop(Primitive prim, int gvn) {
- // Bail out fast if the primitive is not inside a loop.
- if (currentLoopHeader == null) return false;
-
- // Do not hoist primitives with side effects.
- if (!isHoistablePrimitive(prim)) return false;
-
- LetPrim letPrim = prim.parent;
-
- // Find the depth of the outermost scope where we can bind the primitive
- // without bringing a reference out of scope. 0 is the depth of the
- // top-level scope.
- int hoistDepth = 0;
- List<Primitive> inputsHoistedOnDemand = <Primitive>[];
- InputVisitor.forEach(prim, (Reference ref) {
- Primitive input = ref.definition;
- if (canIgnoreRefinementGuards(prim)) {
- input = input.effectiveDefinition;
- }
- if (isFastConstant(input)) {
- // Fast constants can be hoisted all the way out, but should only be
- // hoisted if needed to hoist something else.
- inputsHoistedOnDemand.add(input);
- } else {
- Continuation loopHeader = loopHeaderFor[input];
- Continuation referencedLoop =
- loopHierarchy.lowestCommonAncestor(loopHeader, currentLoopHeader);
- int depth = loopHierarchy.getDepth(referencedLoop);
- if (depth > hoistDepth) {
- hoistDepth = depth;
- }
- }
- });
-
- // Bail out if it can not be hoisted further out than it is now.
- if (hoistDepth == loopHierarchy.getDepth(currentLoopHeader)) return false;
-
- // Walk up the loop hierarchy and check at every step that any heap
- // dependencies can safely be hoisted out of the loop.
- Continuation enclosingLoop = currentLoopHeader;
- Continuation hoistTarget = null;
- while (loopHierarchy.getDepth(enclosingLoop) > hoistDepth &&
- canHoistHeapDependencyOutOfLoop(prim, enclosingLoop)) {
- hoistTarget = enclosingLoop;
- enclosingLoop = loopHierarchy.getEnclosingLoop(enclosingLoop);
- }
-
- // Bail out if heap dependencies prohibit any hoisting at all.
- if (hoistTarget == null) return false;
-
- if (isFastConstant(prim)) {
- // The overhead from introducting a temporary might be greater than
- // the overhead of evaluating this primitive at every iteration.
- // Only hoist if this enables hoisting of a non-trivial primitive.
- return true;
- }
-
- LetCont loopBinding = hoistTarget.parent;
-
- // The primitive may depend on values that have not yet been
- // hoisted as far as they can. Hoist those now.
- for (Primitive input in inputsHoistedOnDemand) {
- hoistTrivialPrimitive(input, loopBinding, enclosingLoop);
- }
-
- // Hoist the primitive.
- letPrim.remove();
- letPrim.insertAbove(loopBinding);
- loopHeaderFor[prim] = enclosingLoop;
-
- // If a refinement guard was bypassed, use the best refinement
- // currently in scope.
- if (canIgnoreRefinementGuards(prim)) {
- int target = loopHierarchy.getDepth(enclosingLoop);
- InputVisitor.forEach(prim, (Reference ref) {
- Primitive input = ref.definition;
- while (input is Refinement) {
- Continuation loop = loopHeaderFor[input];
- loop = loopHierarchy.lowestCommonAncestor(loop, currentLoopHeader);
- if (loopHierarchy.getDepth(loop) <= target) break;
- Refinement refinement = input;
- input = refinement.value.definition;
- }
- ref.changeTo(input);
- });
- }
-
- // Put the primitive in the environment while processing the loop.
- environment[gvn] = prim;
- loopHoistedBindings.putIfAbsent(hoistTarget, () => <int>[]).add(gvn);
- return true;
- }
-
- /// If the given primitive is a trivial primitive that should be hoisted
- /// on-demand, hoist it and its dependent values above [loopBinding].
- void hoistTrivialPrimitive(
- Primitive prim, LetCont loopBinding, Continuation enclosingLoop) {
- assert(isFastConstant(prim));
-
- // The primitive might already be bound in an outer scope. Do not relocate
- // the primitive unless we are lifting it. For example;
- // t1 = a + b
- // t2 = t1 + c
- // t3 = t1 * t2
- // If it was decided that `t3` should be hoisted, `t1` will be seen twice by
- // this method: by the direct reference and by reference through `t2`.
- // The second time it is seen, it will already have been moved.
- Continuation currentLoop = loopHeaderFor[prim];
- int currentDepth = loopHierarchy.getDepth(currentLoop);
- int targetDepth = loopHierarchy.getDepth(enclosingLoop);
- if (currentDepth <= targetDepth) return;
-
- // Hoist the trivial primitives being depended on so they remain in scope.
- InputVisitor.forEach(prim, (Reference ref) {
- hoistTrivialPrimitive(ref.definition, loopBinding, enclosingLoop);
- });
-
- // Move the primitive.
- LetPrim binding = prim.parent;
- binding.remove();
- binding.insertAbove(loopBinding);
- loopHeaderFor[prim] = enclosingLoop;
- }
-
- bool canIgnoreRefinementGuards(Primitive primitive) {
- return primitive is Interceptor;
- }
-
- /// Returns true if [prim] is a constant that has no significant runtime cost.
- bool isFastConstant(Primitive prim) {
- return prim is Constant && (prim.value.isPrimitive || prim.value.isDummy);
- }
-
- /// 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.
- bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) {
- // If the primitive might throw, we have to check that it is the first
- // impure expression in the loop. This has already been checked if
- // [loop] is the current loop header, but for other loops we just give up.
- if (!prim.isSafeForElimination && loop != currentLoopHeader) {
- return false;
- }
- 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.
-
- void addSideEffectsOfPrimitive(Primitive prim) {
- addSideEffects(prim.effects);
- }
-
- 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.fresh(effectNumberer);
- push(node.handler);
- return node.body;
- }
-
- Expression traverseContinuation(Continuation cont) {
- Continuation oldLoopHeader = currentLoopHeader;
- currentLoopHeader = loopHierarchy.getLoopHeader(cont);
- pushAction(() {
- currentLoopHeader = oldLoopHeader;
- });
- for (Parameter param in cont.parameters) {
- loopHeaderFor[param] = currentLoopHeader;
- }
- if (cont.isRecursive) {
- addSideEffects(loopEffects.getSideEffectsInLoop(cont));
- pushAction(() {
- List<int> hoistedBindings = loopHoistedBindings[cont];
- if (hoistedBindings != null) {
- hoistedBindings.forEach(environment.remove);
- }
- });
- } else {
- effectNumbers = effectsAt[cont];
- assert(effectNumbers != null);
- }
-
- return cont.body;
- }
-
- void visitInvokeContinuation(InvokeContinuation node) {
- Continuation cont = node.continuation;
- if (cont.isRecursive) return;
- EffectNumbers join = effectsAt[cont];
- if (join == null) {
- effectsAt[cont] = effectNumbers.copy();
- } else {
- join.join(effectNumberer, effectNumbers);
- }
- }
-
- void visitBranch(Branch node) {
- 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();
- }
-}
-
-/// Maps vectors to numbers, such that two vectors with the same contents
-/// map to the same number.
-class GvnTable {
- Map<GvnEntry, int> _table = <GvnEntry, int>{};
- int _usedGvns = 0;
- int _makeNewGvn() => ++_usedGvns;
-
- int insert(List vector) {
- return _table.putIfAbsent(new GvnEntry(vector), _makeNewGvn);
- }
-}
-
-/// Wrapper around a [List] that compares for equality based on contents
-/// instead of object identity.
-class GvnEntry {
- final List vector;
- final int hashCode;
-
- GvnEntry(List vector)
- : vector = vector,
- hashCode = computeHashCode(vector);
-
- bool operator ==(other) {
- if (other is! GvnEntry) return false;
- GvnEntry entry = other;
- List otherVector = entry.vector;
- if (vector.length != otherVector.length) return false;
- for (int i = 0; i < vector.length; ++i) {
- if (vector[i] != otherVector[i]) return false;
- }
- return true;
- }
-
- /// Combines the hash codes of [vector] using Jenkin's hash function, with
- /// intermediate results truncated to SMI range.
- static int computeHashCode(List vector) {
- int hash = 0;
- for (int i = 0; i < vector.length; ++i) {
- hash = 0x1fffffff & (hash + vector[i].hashCode);
- hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
- hash = hash ^ (hash >> 6);
- }
- hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
- hash = hash ^ (hash >> 11);
- return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
- }
-}
-
-/// Converts GVN'able primitives to a vector containing all the values
-/// to be considered when computing a GVN for it.
-///
-/// This includes the instruction type, inputs, effect numbers for any part
-/// of the heap being depended on, as well as any instruction-specific payload
-/// such as any DartTypes, Elements, and operator kinds.
-///
-/// Each `visit` or `process` method for a primitive must initialize [vector]
-/// if the primitive is GVN'able and fill in any components except the inputs.
-/// The inputs will be filled in by [processReference].
-class GvnVectorBuilder extends DeepRecursiveVisitor {
- List vector;
- final Map<Primitive, int> gvnFor;
- final Compiler compiler;
- World get world => compiler.world;
- JavaScriptBackend get backend => compiler.backend;
- final TypeMaskSystem types;
- EffectNumbers effectNumbers;
-
- GvnVectorBuilder(this.gvnFor, this.compiler, this.types);
-
- List make(Primitive prim, EffectNumbers effectNumbers) {
- this.effectNumbers = effectNumbers;
- vector = null;
- visit(prim);
- return vector;
- }
-
- /// The `process` methods below do not insert the referenced arguments into
- /// the vector, but instead rely on them being inserted here.
- processReference(Reference ref) {
- if (vector == null) return;
- Primitive prim = ref.definition.effectiveDefinition;
- vector.add(gvnFor[prim] ?? prim);
- }
-
- processTypeTest(TypeTest node) {
- vector = [GvnCode.TYPE_TEST, node.dartType];
- }
-
- processTypeTestViaFlag(TypeTestViaFlag node) {
- vector = [GvnCode.TYPE_TEST_VIA_FLAG, node.dartType];
- }
-
- processApplyBuiltinOperator(ApplyBuiltinOperator node) {
- vector = [GvnCode.BUILTIN_OPERATOR, node.operator.index];
- }
-
- processGetLength(GetLength 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
- // effect number in its vector while the second one does not.
- vector = [GvnCode.GET_LENGTH];
- } else {
- vector = [GvnCode.GET_LENGTH, effectNumbers.indexableLength];
- }
- }
-
- bool isNativeField(FieldElement field) {
- // TODO(asgerf): We should add a GetNativeField instruction.
- return backend.isNative(field);
- }
-
- processGetField(GetField node) {
- if (isNativeField(node.field)) {
- vector = null; // Native field access cannot be GVN'ed.
- } else if (node.isFinal) {
- vector = [GvnCode.GET_FIELD, node.field];
- } else {
- vector = [GvnCode.GET_FIELD, node.field, effectNumbers.instanceField];
- }
- }
-
- processGetIndex(GetIndex node) {
- vector = [GvnCode.GET_INDEX, effectNumbers.indexableContent];
- }
-
- visitGetStatic(GetStatic node) {
- if (node.isFinal) {
- vector = [GvnCode.GET_STATIC, node.element];
- } else {
- vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
- }
- // Suppress visit to witness argument.
- }
-
- processGetLazyStatic(GetLazyStatic node) {
- if (node.isFinal) {
- vector = [GvnCode.GET_STATIC, node.element];
- } else {
- vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
- }
- }
-
- processConstant(Constant node) {
- vector = [GvnCode.CONSTANT, node.value];
- }
-
- processReifyRuntimeType(ReifyRuntimeType node) {
- vector = [GvnCode.REIFY_RUNTIME_TYPE];
- }
-
- processReadTypeVariable(ReadTypeVariable node) {
- vector = [GvnCode.READ_TYPE_VARIABLE, node.variable];
- }
-
- processTypeExpression(TypeExpression node) {
- vector = [GvnCode.TYPE_EXPRESSION, node.kind.index, node.dartType];
- }
-
- processInterceptor(Interceptor node) {
- vector = [GvnCode.INTERCEPTOR];
- }
-}
-
-class GvnCode {
- static const int TYPE_TEST = 1;
- static const int TYPE_TEST_VIA_FLAG = 2;
- static const int BUILTIN_OPERATOR = 3;
- static const int GET_LENGTH = 4;
- static const int GET_FIELD = 5;
- static const int GET_INDEX = 6;
- static const int GET_STATIC = 7;
- static const int CONSTANT = 8;
- static const int REIFY_RUNTIME_TYPE = 9;
- static const int READ_TYPE_VARIABLE = 10;
- static const int TYPE_EXPRESSION = 11;
- static const int INTERCEPTOR = 12;
-}
-
-typedef ReferenceCallback(Reference ref);
-
-class InputVisitor extends DeepRecursiveVisitor {
- ReferenceCallback callback;
-
- InputVisitor(this.callback);
-
- @override
- processReference(Reference ref) {
- callback(ref);
- }
-
- static void forEach(Primitive node, ReferenceCallback callback) {
- new InputVisitor(callback).visit(node);
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/inline.dart b/pkg/compiler/lib/src/cps_ir/inline.dart
deleted file mode 100644
index 89af4dc..0000000
--- a/pkg/compiler/lib/src/cps_ir/inline.dart
+++ /dev/null
@@ -1,613 +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 cps_ir.optimization.inline;
-
-import 'package:js_ast/js_ast.dart' as js;
-
-import '../dart_types.dart' show DartType, GenericType;
-import '../elements/elements.dart';
-import '../js_backend/codegen/task.dart' show CpsFunctionCompiler;
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import '../types/types.dart' show TypeMask;
-import '../universe/call_structure.dart' show CallStructure;
-import '../universe/selector.dart' show Selector;
-import '../world.dart' show World;
-import 'cps_fragment.dart';
-import 'cps_ir_builder.dart' show ThisParameterLocal;
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart';
-import 'type_mask_system.dart' show TypeMaskSystem;
-
-/// Inlining stack entries.
-///
-/// During inlining, a stack is used to detect cycles in the call graph.
-class StackEntry {
- // Dynamically resolved calls might be targeting an adapter function that
- // fills in optional arguments not passed at the call site. Therefore these
- // calls are represented by the eventual target and the call structure at
- // the call site, which together identify the target. Statically resolved
- // calls are represented by the target element and a null call structure.
- final ExecutableElement target;
- final CallStructure callStructure;
-
- StackEntry(this.target, this.callStructure);
-
- bool match(ExecutableElement otherTarget, CallStructure otherCallStructure) {
- if (target != otherTarget) return false;
- if (callStructure == null) return otherCallStructure == null;
- return otherCallStructure != null &&
- callStructure.match(otherCallStructure);
- }
-}
-
-/// Inlining cache entries.
-class CacheEntry {
- // The cache maps a function element to a list of entries, where each entry
- // is a tuple of (call structure, abstract receiver, abstract arguments)
- // along with the inlining decision and optional IR function definition.
- final CallStructure callStructure;
- final TypeMask receiver;
- final List<TypeMask> arguments;
-
- final bool decision;
- final FunctionDefinition function;
-
- CacheEntry(this.callStructure, this.receiver, this.arguments, this.decision,
- this.function);
-
- bool match(CallStructure otherCallStructure, TypeMask otherReceiver,
- List<TypeMask> otherArguments) {
- if (callStructure == null) {
- if (otherCallStructure != null) return false;
- } else if (otherCallStructure == null ||
- !callStructure.match(otherCallStructure)) {
- return false;
- }
-
- if (receiver != otherReceiver) return false;
- assert(arguments.length == otherArguments.length);
- for (int i = 0; i < arguments.length; ++i) {
- if (arguments[i] != otherArguments[i]) return false;
- }
- return true;
- }
-}
-
-/// An inlining cache.
-///
-/// During inlining a cache is used to remember inlining decisions for shared
-/// parts of the call graph, to avoid exploring them more than once.
-///
-/// The cache maps a tuple of (function element, call structure,
-/// abstract receiver, abstract arguments) to a boolean inlining decision and
-/// an IR function definition if the decision is positive.
-class InliningCache {
- static const int ABSENT = -1;
- static const int NO_INLINE = 0;
-
- final Map<ExecutableElement, FunctionDefinition> unoptimized =
- <ExecutableElement, FunctionDefinition>{};
-
- final Map<ExecutableElement, List<CacheEntry>> map =
- <ExecutableElement, List<CacheEntry>>{};
-
- // When function definitions are put into or removed from the cache, they are
- // copied because the compiler passes will mutate them.
- final CopyingVisitor copier = new CopyingVisitor();
-
- void _putInternal(
- ExecutableElement element,
- CallStructure callStructure,
- TypeMask receiver,
- List<TypeMask> arguments,
- bool decision,
- FunctionDefinition function) {
- map.putIfAbsent(element, () => <CacheEntry>[]).add(
- new CacheEntry(callStructure, receiver, arguments, decision, function));
- }
-
- /// Put a positive inlining decision in the cache.
- ///
- /// A positive inlining decision maps to an IR function definition.
- void putPositive(
- ExecutableElement element,
- CallStructure callStructure,
- TypeMask receiver,
- List<TypeMask> arguments,
- FunctionDefinition function) {
- _putInternal(element, callStructure, receiver, arguments, true,
- copier.copy(function));
- }
-
- /// Put a negative inlining decision in the cache.
- void putNegative(ExecutableElement element, CallStructure callStructure,
- TypeMask receiver, List<TypeMask> arguments) {
- _putInternal(element, callStructure, receiver, arguments, false, null);
- }
-
- /// Look up a tuple in the cache.
- ///
- /// A positive lookup result return the IR function definition. A negative
- /// lookup result returns [NO_INLINE]. If there is no cached result,
- /// [ABSENT] is returned.
- get(ExecutableElement element, CallStructure callStructure, TypeMask receiver,
- List<TypeMask> arguments) {
- List<CacheEntry> entries = map[element];
- if (entries != null) {
- for (CacheEntry entry in entries) {
- if (entry.match(callStructure, receiver, arguments)) {
- if (entry.decision) {
- FunctionDefinition function = copier.copy(entry.function);
- ParentVisitor.setParents(function);
- return function;
- }
- return NO_INLINE;
- }
- }
- }
- return ABSENT;
- }
-
- /// Cache the unoptimized CPS term for a function.
- ///
- /// The unoptimized term should not have any inlining-context-specific
- /// optimizations applied to it. It will be used to compile the
- /// non-specialized version of the function.
- void putUnoptimized(ExecutableElement element, FunctionDefinition function) {
- unoptimized.putIfAbsent(element, () => copier.copy(function));
- }
-
- /// Look up the unoptimized CPS term for a function.
- ///
- /// The unoptimized term will not have any inlining-context-specific
- /// optimizations applied to it. It can be used to compile the
- /// non-specialized version of the function.
- FunctionDefinition getUnoptimized(ExecutableElement element) {
- FunctionDefinition function = unoptimized[element];
- if (function != null) {
- function = copier.copy(function);
- ParentVisitor.setParents(function);
- }
- return function;
- }
-}
-
-class Inliner implements Pass {
- get passName => 'Inline calls';
-
- final CpsFunctionCompiler functionCompiler;
-
- final InliningCache cache = new InliningCache();
-
- final List<StackEntry> stack = <StackEntry>[];
-
- Inliner(this.functionCompiler);
-
- bool isCalledOnce(Element element) {
- if (element is ConstructorBodyElement) {
- ClassElement class_ = element.enclosingClass;
- return !functionCompiler.compiler.world.hasAnyStrictSubclass(class_) &&
- class_.constructors.tail?.isEmpty ??
- false;
- }
- return functionCompiler.compiler.typesTask.typesInferrer
- .isCalledOnce(element);
- }
-
- void rewrite(FunctionDefinition node, [CallStructure callStructure]) {
- ExecutableElement function = node.element;
-
- // Inlining in asynchronous or generator functions is disabled. Inlining
- // triggers a bug in the async rewriter.
- // TODO(kmillikin): Fix the bug and eliminate this restriction if it makes
- // sense.
- if (function is FunctionElement &&
- function.asyncMarker != AsyncMarker.SYNC) {
- return;
- }
-
- // Do not inline in functions containing try statements. V8 does not
- // optimize code in such functions, so inlining will move optimizable code
- // into a context where it cannot be optimized.
- if (function.resolvedAst.kind == ResolvedAstKind.PARSED &&
- function.resolvedAst.elements.containsTryStatement) {
- return;
- }
-
- stack.add(new StackEntry(function, callStructure));
- new InliningVisitor(this).visit(node);
- assert(stack.last.match(function, callStructure));
- stack.removeLast();
- new ShrinkingReducer().rewrite(node);
- }
-}
-
-/// Compute an abstract size of an IR function definition.
-///
-/// The size represents the cost of inlining at a call site.
-class SizeVisitor extends TrampolineRecursiveVisitor {
- int size = 0;
-
- void countArgument(Primitive argument, Parameter parameter) {
- // If a parameter is unused and the corresponding argument has only the
- // one use at the invocation, then inlining the call might enable
- // elimination of the argument. This 'pays for itself' by decreasing the
- // cost of inlining at the call site.
- if (argument != null && argument.hasExactlyOneUse && parameter.hasNoUses) {
- --size;
- }
- }
-
- static int sizeOf(InvocationPrimitive invoke, FunctionDefinition function) {
- SizeVisitor visitor = new SizeVisitor();
- visitor.visit(function);
- if (invoke.callingConvention == CallingConvention.Intercepted) {
- // Note that if the invocation is a dummy-intercepted call, then the
- // target has an unused interceptor parameter, but the caller provides
- // no interceptor argument.
- visitor.countArgument(invoke.interceptor, function.interceptorParameter);
- }
- visitor.countArgument(invoke.receiver, function.receiverParameter);
- for (int i = 0; i < invoke.argumentRefs.length; ++i) {
- visitor.countArgument(invoke.argument(i), function.parameters[i]);
- }
- return visitor.size;
- }
-
- // Inlining a function incurs a cost equal to the number of primitives and
- // non-jump tail expressions.
- // TODO(kmillikin): Tune the size computation and size bound.
- processLetPrim(LetPrim node) => ++size;
- processLetMutable(LetMutable node) => ++size;
- processBranch(Branch node) => ++size;
- processThrow(Throw nose) => ++size;
- processRethrow(Rethrow node) => ++size;
-
- // Discount primitives that do not generate code.
- processRefinement(Refinement node) => --size;
- processBoundsCheck(BoundsCheck node) {
- if (node.hasNoChecks) {
- --size;
- }
- }
-
- processForeignCode(ForeignCode node) {
- // Count the number of nodes in the JS fragment, and discount the size
- // originally added by LetPrim.
- JsSizeVisitor visitor = new JsSizeVisitor();
- node.codeTemplate.ast.accept(visitor);
- size += visitor.size - 1;
- }
-}
-
-class JsSizeVisitor extends js.BaseVisitor {
- int size = 0;
-
- visitNode(js.Node node) {
- ++size;
- return super.visitNode(node);
- }
-
- visitInterpolatedExpression(js.InterpolatedExpression node) {
- // Suppress call to visitNode. Placeholders should not be counted, because
- // the argument has already been counted, and will in most cases be inserted
- // directly in the placeholder.
- }
-}
-
-class InliningVisitor extends TrampolineRecursiveVisitor {
- final Inliner _inliner;
-
- // A successful inlining attempt returns the [Primitive] that represents the
- // result of the inlined call or null. If the result is non-null, the body
- // of the inlined function is available in this field.
- CpsFragment _fragment;
-
- InliningVisitor(this._inliner);
-
- JavaScriptBackend get backend => _inliner.functionCompiler.backend;
- TypeMaskSystem get typeSystem => _inliner.functionCompiler.typeSystem;
- World get world => _inliner.functionCompiler.compiler.world;
-
- FunctionDefinition compileToCpsIr(AstElement element) {
- return _inliner.functionCompiler.compileToCpsIr(element);
- }
-
- void optimizeBeforeInlining(FunctionDefinition function) {
- _inliner.functionCompiler.optimizeCpsBeforeInlining(function);
- }
-
- void applyCpsPass(Pass pass, FunctionDefinition function) {
- return _inliner.functionCompiler.applyCpsPass(pass, function);
- }
-
- bool isRecursive(Element target, CallStructure callStructure) {
- return _inliner.stack.any((StackEntry s) => s.match(target, callStructure));
- }
-
- @override
- Expression traverseLetPrim(LetPrim node) {
- // A successful inlining attempt will set the node's body to null, so it is
- // read before visiting the primitive.
- Expression next = node.body;
- Primitive replacement = visit(node.primitive);
- if (replacement != null) {
- node.primitive.replaceWithFragment(_fragment, replacement);
- }
- return next;
- }
-
- TypeMask abstractType(Primitive def) {
- return def.type ?? typeSystem.dynamicType;
- }
-
- /// Build the IR term for the function that adapts a call site targeting a
- /// 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.type;
- Parameter interceptorParameter =
- node.interceptorRef != null ? new Parameter(null) : null;
- List<Parameter> parameters =
- new List<Parameter>.generate(node.argumentRefs.length, (int index) {
- // TODO(kmillikin): Use a hint for the parameter names.
- return new Parameter(null)..type = node.argument(index).type;
- });
- Continuation returnContinuation = new Continuation.retrn();
- CpsFragment cps = new CpsFragment();
-
- FunctionSignature signature = target.functionSignature;
- int requiredParameterCount = signature.requiredParameterCount;
- List<Primitive> arguments = new List<Primitive>.generate(
- requiredParameterCount, (int index) => parameters[index]);
-
- int parameterIndex = requiredParameterCount;
- CallStructure newCallStructure;
- if (signature.optionalParametersAreNamed) {
- List<String> incomingNames =
- node.selector.callStructure.getOrderedNamedArguments();
- List<String> outgoingNames = <String>[];
- int nameIndex = 0;
- signature.orderedOptionalParameters.forEach((ParameterElement formal) {
- if (nameIndex < incomingNames.length &&
- formal.name == incomingNames[nameIndex]) {
- arguments.add(parameters[parameterIndex++]);
- ++nameIndex;
- } else {
- Constant defaultValue = cps.makeConstant(
- backend.constants.getConstantValue(formal.constant));
- defaultValue.type = typeSystem.getParameterType(formal);
- arguments.add(defaultValue);
- }
- outgoingNames.add(formal.name);
- });
- newCallStructure =
- new CallStructure(signature.parameterCount, outgoingNames);
- } else {
- signature.forEachOptionalParameter((ParameterElement formal) {
- if (parameterIndex < parameters.length) {
- arguments.add(parameters[parameterIndex++]);
- } else {
- Constant defaultValue = cps.makeConstant(
- backend.constants.getConstantValue(formal.constant));
- defaultValue.type = typeSystem.getParameterType(formal);
- arguments.add(defaultValue);
- }
- });
- newCallStructure = new CallStructure(signature.parameterCount);
- }
-
- Selector newSelector = new Selector(
- node.selector.kind, node.selector.memberName, newCallStructure);
- Primitive result = cps.invokeMethod(
- thisParameter, newSelector, node.mask, arguments,
- interceptor: interceptorParameter,
- callingConvention: node.callingConvention);
- result.type = typeSystem.getInvokeReturnType(node.selector, node.mask);
- returnContinuation.parameters.single.type = result.type;
- cps.invokeContinuation(returnContinuation, <Primitive>[result]);
- return new FunctionDefinition(
- target, thisParameter, parameters, returnContinuation, cps.root,
- interceptorParameter: interceptorParameter);
- }
-
- // Given an invocation and a known target, possibly perform inlining.
- //
- // An optional call structure indicates a dynamic call. Calls that are
- // already resolved statically have a null call structure.
- //
- // The [Primitive] representing the result of the inlined call is returned
- // if the call was inlined, and the inlined function body is available in
- // [_fragment]. If the call was not inlined, null is returned.
- Primitive tryInlining(InvocationPrimitive invoke, FunctionElement target,
- CallStructure callStructure) {
- // Quick checks: do not inline or even cache calls to targets without an
- // AST node, targets that are asynchronous or generator functions, or
- // targets containing a try statement.
- if (!target.hasNode) return null;
- if (backend.isJsInterop(target)) return null;
- if (target.asyncMarker != AsyncMarker.SYNC) return null;
- // V8 does not optimize functions containing a try statement. Inlining
- // code containing a try statement will make the optimizable calling code
- // become unoptimizable.
- if (target.resolvedAst.elements.containsTryStatement) {
- return null;
- }
-
- // Don't inline methods that never return. They are usually helper functions
- // that throw an exception.
- if (invoke.type.isEmpty) {
- // TODO(sra): It would be ok to inline if doing so was shrinking.
- return null;
- }
-
- if (isBlacklisted(target)) return null;
-
- if (invoke.callingConvention == CallingConvention.OneShotIntercepted) {
- // One-shot interceptor calls with a known target are only inserted on
- // uncommon code paths, so they should not be inlined.
- return null;
- }
-
- Primitive receiver = invoke.receiver;
- TypeMask abstractReceiver =
- receiver == null ? null : abstractType(receiver);
- // The receiver is non-null in a method body, unless the receiver is known
- // to be `null` (isEmpty covers `null` and unreachable).
- TypeMask abstractReceiverInMethod = abstractReceiver == null
- ? null
- : abstractReceiver.isEmptyOrNull
- ? abstractReceiver
- : abstractReceiver.nonNullable();
- List<TypeMask> abstractArguments =
- invoke.arguments.map(abstractType).toList();
- var cachedResult = _inliner.cache.get(
- target, callStructure, abstractReceiverInMethod, abstractArguments);
-
- // Negative inlining result in the cache.
- if (cachedResult == InliningCache.NO_INLINE) return null;
-
- Primitive finish(FunctionDefinition function) {
- _fragment = new CpsFragment(invoke.sourceInformation);
- 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 (receiver != null && abstractReceiver.isNullable) {
- receiver =
- nullReceiverGuard(invoke, _fragment, receiver, abstractReceiver);
- }
- return _fragment.inlineFunction(function, receiver, arguments,
- interceptor: invoke.interceptor, hint: invoke.hint);
- }
-
- // Positive inlining result in the cache.
- if (cachedResult is FunctionDefinition) {
- return finish(cachedResult);
- }
-
- // We have not seen this combination of target and abstract arguments
- // before. Make an inlining decision.
- assert(cachedResult == InliningCache.ABSENT);
- Primitive doNotInline() {
- _inliner.cache.putNegative(
- target, callStructure, abstractReceiverInMethod, abstractArguments);
- return null;
- }
- if (backend.annotations.noInline(target)) return doNotInline();
- if (isRecursive(target, callStructure)) return doNotInline();
-
- FunctionDefinition function;
- if (callStructure != null &&
- target.functionSignature.parameterCount !=
- callStructure.argumentCount) {
- // The argument count at the call site does not match the target's
- // formal parameter count. Build the IR term for an adapter function
- // body.
- if (backend.isNative(target)) {
- // TODO(25548): Generate correct adaptor for native methods.
- return doNotInline();
- } else {
- function = buildAdapter(invoke, target);
- }
- } else {
- function = compileToCpsIr(target);
- if (function.receiverParameter != null) {
- function.receiverParameter.type = abstractReceiverInMethod;
- }
- for (int i = 0; i < invoke.argumentRefs.length; ++i) {
- function.parameters[i].type = invoke.argument(i).type;
- }
- optimizeBeforeInlining(function);
- }
-
- // Inline calls in the body.
- _inliner.rewrite(function, callStructure);
-
- // Compute the size.
- // TODO(kmillikin): Tune the size bound.
- int size = SizeVisitor.sizeOf(invoke, function);
- if (!_inliner.isCalledOnce(target) && size > 11) return doNotInline();
-
- _inliner.cache.putPositive(target, callStructure, abstractReceiverInMethod,
- abstractArguments, function);
- return finish(function);
- }
-
- Primitive nullReceiverGuard(InvocationPrimitive invoke, CpsFragment fragment,
- Primitive dartReceiver, TypeMask abstractReceiver) {
- if (invoke is! InvokeMethod) return dartReceiver;
- InvokeMethod invokeMethod = invoke;
- Selector selector = invokeMethod.selector;
- if (typeSystem.isDefinitelyNum(abstractReceiver, allowNull: true)) {
- Primitive condition = _fragment.letPrim(new ApplyBuiltinOperator(
- BuiltinOperator.IsNotNumber,
- <Primitive>[dartReceiver],
- invoke.sourceInformation));
- condition.type = typeSystem.boolType;
- Primitive check = _fragment.letPrim(new ReceiverCheck.nullCheck(
- dartReceiver, selector, invoke.sourceInformation,
- condition: condition));
- check.type = abstractReceiver.nonNullable();
- return check;
- }
-
- Primitive check = _fragment.letPrim(new ReceiverCheck.nullCheck(
- dartReceiver, selector, invoke.sourceInformation));
- check.type = abstractReceiver.nonNullable();
- return check;
- }
-
- @override
- Primitive visitInvokeStatic(InvokeStatic node) {
- return tryInlining(node, node.target, null);
- }
-
- @override
- Primitive visitInvokeMethod(InvokeMethod node) {
- Primitive receiver = node.receiver;
- Element element = world.locateSingleElement(node.selector, receiver.type);
- if (element == null || element is! FunctionElement) return null;
- if (node.selector.isGetter != element.isGetter) return null;
- if (node.selector.isSetter != element.isSetter) return null;
- if (node.selector.name != element.name) return null;
-
- return tryInlining(
- node, element.asFunctionElement(), node.selector.callStructure);
- }
-
- @override
- Primitive visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- if (node.selector.isGetter != node.target.isGetter) return null;
- if (node.selector.isSetter != node.target.isSetter) return null;
- return tryInlining(node, node.target, null);
- }
-
- @override
- Primitive visitInvokeConstructor(InvokeConstructor node) {
- if (node.dartType is GenericType) {
- // We cannot inline a constructor invocation containing type arguments
- // because CreateInstance in the body does not know the type arguments.
- // We would incorrectly instantiate a class like A instead of A<B>.
- // TODO(kmillikin): try to fix this.
- GenericType generic = node.dartType;
- if (generic.typeArguments.any((DartType t) => !t.isDynamic)) return null;
- }
- return tryInlining(node, node.target, null);
- }
-
- bool isBlacklisted(FunctionElement target) {
- ClassElement enclosingClass = target.enclosingClass;
- if (target.isOperator &&
- (enclosingClass == backend.helpers.jsNumberClass ||
- enclosingClass == backend.helpers.jsDoubleClass ||
- enclosingClass == backend.helpers.jsIntClass)) {
- // These should be handled by operator specialization.
- return true;
- }
- if (target == backend.helpers.stringInterpolationHelper) return true;
- return false;
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
deleted file mode 100644
index e57f43f..0000000
--- a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
+++ /dev/null
@@ -1,425 +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 cps_ir.optimization.insert_refinements;
-
-import 'dart:math' show min;
-
-import '../common/names.dart';
-import '../elements/elements.dart';
-import '../types/types.dart' show TypeMask;
-import '../universe/selector.dart';
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart' show Pass;
-import 'type_mask_system.dart';
-
-/// Inserts [Refinement] nodes in the IR to allow for sparse path-sensitive
-/// type analysis in the [TypePropagator] pass.
-///
-/// Refinement nodes are inserted at the arms of a [Branch] node with a
-/// condition of form `x is T` or `x == null`.
-///
-/// Refinement nodes are inserted after a method invocation to refine the
-/// receiver to the types that can respond to the given selector.
-class InsertRefinements extends TrampolineRecursiveVisitor implements Pass {
- String get passName => 'Insert refinement nodes';
-
- final TypeMaskSystem types;
-
- /// Maps unrefined primitives to its refinement currently in scope (if any).
- final Map<Primitive, Refinement> refinementFor = <Primitive, Refinement>{};
-
- InsertRefinements(this.types);
-
- void rewrite(FunctionDefinition node) {
- visit(node.body);
- }
-
- /// Updates references to refer to the refinement currently in scope.
- void processReference(Reference node) {
- Definition definition = node.definition;
- if (definition is Primitive) {
- Primitive prim = definition.effectiveDefinition;
- Refinement refined = refinementFor[prim];
- if (refined != null && refined != definition) {
- node.changeTo(refined);
- }
- }
- }
-
- /// Sinks the binding of [cont] to immediately above [use].
- ///
- /// This is used to ensure that everything in scope at [use] is also in scope
- /// inside [cont], so refinements can be inserted inside [cont] without
- /// accidentally referencing a primitive out of scope.
- ///
- /// It is always safe to do this for single-use continuations, because
- /// strictly more things are in scope at the use site, and there can't be any
- /// other use of [cont] that might fall out of scope since there is only
- /// that single use.
- void sinkContinuationToUse(Continuation cont, Expression use) {
- assert(cont.hasExactlyOneUse && cont.firstRef.parent == use);
- assert(!cont.isRecursive);
- LetCont let = cont.parent;
- InteriorNode useParent = use.parent;
- if (useParent == let) return;
- if (let.continuations.length > 1) {
- // Create a new LetCont binding only this continuation.
- let.continuations.remove(cont);
- let = new LetCont(cont, null);
- } else {
- let.remove(); // Reuse the existing LetCont.
- }
- let.insertAbove(use);
- }
-
- /// Sets [refined] to be the current refinement for its value, and pushes an
- /// action that will restore the original scope again.
- ///
- /// The refinement is inserted as the child of [insertionParent] if it has
- /// at least one use after its scope has been processed.
- void applyRefinement(InteriorNode insertionParent, Refinement refined) {
- Primitive value = refined.effectiveDefinition;
- Primitive currentRefinement = refinementFor[value];
- refinementFor[value] = refined;
- pushAction(() {
- refinementFor[value] = currentRefinement;
- if (refined.hasNoUses) {
- // Clean up refinements that are not used.
- refined.destroy();
- } else {
- LetPrim let = new LetPrim(refined);
- let.insertBelow(insertionParent);
- }
- });
- }
-
- /// Enqueues [cont] for processing in a context where [refined] is the
- /// current refinement for its value.
- void pushRefinement(Continuation cont, Refinement refined) {
- pushAction(() {
- applyRefinement(cont, refined);
- push(cont);
- });
- }
-
- /// Refine the type of each argument on [node] according to the provided
- /// type masks.
- void _refineArguments(
- InvocationPrimitive node, List<TypeMask> argumentSuccessTypes) {
- if (argumentSuccessTypes == null) return;
-
- // Note: node.dartArgumentsLength is shorter when the call doesn't include
- // some optional arguments.
- int length = min(argumentSuccessTypes.length, node.argumentRefs.length);
- for (int i = 0; i < length; i++) {
- TypeMask argSuccessType = argumentSuccessTypes[i];
-
- // Skip arguments that provide no refinement.
- if (argSuccessType == types.dynamicType) continue;
-
- applyRefinement(
- node.parent, new Refinement(node.argument(i), argSuccessType));
- }
- }
-
- void visitInvokeStatic(InvokeStatic node) {
- node.argumentRefs.forEach(processReference);
- _refineArguments(node, _getSuccessTypesForStaticMethod(types, node.target));
- }
-
- void visitInvokeMethod(InvokeMethod node) {
- // Update references to their current refined values.
- processReference(node.receiverRef);
- node.argumentRefs.forEach(processReference);
-
- // If the call is intercepted, we want to refine the actual receiver,
- // not the interceptor.
- Primitive receiver = node.receiver;
-
- // Do not try to refine the receiver of closure calls; the class world
- // does not know about closure classes.
- Selector selector = node.selector;
- if (!selector.isClosureCall) {
- // Filter away receivers that throw on this selector.
- TypeMask type = types.receiverTypeFor(selector, node.mask);
- Refinement refinement = new Refinement(receiver, type);
- LetPrim letPrim = node.parent;
- applyRefinement(letPrim, refinement);
-
- // Refine arguments of methods on numbers which we know will throw on
- // invalid argument values.
- _refineArguments(
- node, _getSuccessTypesForInstanceMethod(types, type, selector));
- }
- }
-
- void visitTypeCast(TypeCast node) {
- Primitive value = node.value;
-
- processReference(node.valueRef);
- node.typeArgumentRefs.forEach(processReference);
-
- // Refine the type of the input.
- TypeMask type = types.subtypesOf(node.dartType).nullable();
- Refinement refinement = new Refinement(value, type);
- LetPrim letPrim = node.parent;
- applyRefinement(letPrim, refinement);
- }
-
- void visitRefinement(Refinement node) {
- // We found a pre-existing refinement node. These are generated by the
- // IR builder to hold information from --trust-type-annotations.
- // Update its input to use our own current refinement, then update the
- // environment to use this refinement.
- processReference(node.value);
- Primitive value = node.value.definition.effectiveDefinition;
- Primitive oldRefinement = refinementFor[value];
- refinementFor[value] = node;
- pushAction(() {
- refinementFor[value] = oldRefinement;
- });
- }
-
- bool isTrue(Primitive prim) {
- return prim is Constant && prim.value.isTrue;
- }
-
- void visitBranch(Branch node) {
- processReference(node.conditionRef);
- Primitive condition = node.condition;
-
- 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.
- sinkContinuationToUse(trueCont, node);
- sinkContinuationToUse(falseCont, node);
-
- // If the condition is an 'is' check, promote the checked value.
- if (condition is TypeTest) {
- Primitive value = condition.value;
- TypeMask type = types.subtypesOf(condition.dartType);
- Primitive refinedValue = new Refinement(value, type);
- pushRefinement(trueCont, refinedValue);
- push(falseCont);
- return;
- }
-
- // If the condition is comparison with a constant, promote the other value.
- // This can happen either for calls to `==` or `identical` calls, such
- // as the ones inserted by the unsugaring pass.
-
- void refineEquality(Primitive first, Primitive second,
- Continuation trueCont, Continuation falseCont) {
- if (second is Constant && second.value.isNull) {
- Refinement refinedTrue = new Refinement(first, types.nullType);
- Refinement refinedFalse = new Refinement(first, types.nonNullType);
- pushRefinement(trueCont, refinedTrue);
- pushRefinement(falseCont, refinedFalse);
- } else if (first is Constant && first.value.isNull) {
- Refinement refinedTrue = new Refinement(second, types.nullType);
- Refinement refinedFalse = new Refinement(second, types.nonNullType);
- pushRefinement(trueCont, refinedTrue);
- pushRefinement(falseCont, refinedFalse);
- } else {
- push(trueCont);
- push(falseCont);
- }
- }
-
- if (condition is InvokeMethod && condition.selector == Selectors.equals) {
- refineEquality(
- condition.receiver, condition.argument(0), trueCont, falseCont);
- return;
- }
-
- if (condition is ApplyBuiltinOperator &&
- condition.operator == BuiltinOperator.Identical) {
- refineEquality(
- condition.argument(0), condition.argument(1), trueCont, falseCont);
- return;
- }
-
- push(trueCont);
- push(falseCont);
- }
-
- @override
- Expression traverseLetCont(LetCont node) {
- for (Continuation cont in node.continuations) {
- // Do not push the branch continuations here. visitBranch will do that.
- if (!(cont.hasExactlyOneUse && cont.firstRef.parent is Branch)) {
- push(cont);
- }
- }
- return node.body;
- }
-}
-
-// TODO(sigmund): ideally this whitelist information should be stored as
-// metadata annotations on the runtime libraries so we can keep it in sync with
-// the implementation more easily.
-// TODO(sigmund): add support for constructors.
-// TODO(sigmund): add checks for RegExp and DateTime (currently not exposed as
-// easily in TypeMaskSystem).
-// TODO(sigmund): after the above TODOs are fixed, add:
-// ctor JSArray.fixed: [types.uint32Type],
-// ctor JSArray.growable: [types.uintType],
-// ctor DateTime': [int, int, int, int, int, int, int],
-// ctor DateTime.utc': [int, int, int, int, int, int, int],
-// ctor DateTime._internal': [int, int, int, int, int, int, int, bool],
-// ctor RegExp': [string, dynamic, dynamic],
-// method RegExp.allMatches: [string, int],
-// method RegExp.firstMatch: [string],
-// method RegExp.hasMatch: [string],
-List<TypeMask> _getSuccessTypesForInstanceMethod(
- TypeMaskSystem types, TypeMask receiver, Selector selector) {
- if (types.isDefinitelyInt(receiver)) {
- switch (selector.name) {
- case 'toSigned':
- case 'toUnsigned':
- case 'modInverse':
- case 'gcd':
- return [types.intType];
-
- case 'modPow':
- return [types.intType, types.intType];
- }
- // Note: num methods on int values are handled below.
- }
-
- if (types.isDefinitelyNum(receiver)) {
- switch (selector.name) {
- case 'clamp':
- return [types.numType, types.numType];
- case 'toStringAsFixed':
- case 'toStringAsPrecision':
- case 'toRadixString':
- return [types.intType];
- case 'toStringAsExponential':
- return [types.intType.nullable()];
- case 'compareTo':
- case 'remainder':
- case '+':
- case '-':
- case '/':
- case '*':
- case '%':
- case '~/':
- case '<<':
- case '>>':
- case '&':
- case '|':
- case '^':
- case '<':
- case '>':
- case '<=':
- case '>=':
- return [types.numType];
- default:
- return null;
- }
- }
-
- if (types.isDefinitelyString(receiver)) {
- switch (selector.name) {
- case 'allMatches':
- return [types.stringType, types.intType];
- case 'endsWith':
- return [types.stringType];
- case 'replaceAll':
- return [types.dynamicType, types.stringType];
- case 'replaceFirst':
- return [types.dynamicType, types.stringType, types.intType];
- case 'replaceFirstMapped':
- return [
- types.dynamicType,
- types.dynamicType.nonNullable(),
- types.intType
- ];
- case 'split':
- return [types.dynamicType.nonNullable()];
- case 'replaceRange':
- return [types.intType, types.intType, types.stringType];
- case 'startsWith':
- return [types.dynamicType, types.intType];
- case 'substring':
- return [types.intType, types.uintType.nullable()];
- case 'indexOf':
- return [types.dynamicType.nonNullable(), types.uintType];
- case 'lastIndexOf':
- return [types.dynamicType.nonNullable(), types.uintType.nullable()];
- case 'contains':
- return [
- types.dynamicType.nonNullable(),
- // TODO(sigmund): update runtime to add check for int?
- types.dynamicType
- ];
- case 'codeUnitAt':
- return [types.uintType];
- case '+':
- return [types.stringType];
- case '*':
- return [types.uint32Type];
- case '[]':
- return [types.uintType];
- default:
- return null;
- }
- }
-
- if (types.isDefinitelyArray(receiver)) {
- switch (selector.name) {
- case 'removeAt':
- case 'insert':
- return [types.uintType];
- case 'sublist':
- return [types.uintType, types.uintType.nullable()];
- case 'length':
- return selector.isSetter ? [types.uintType] : null;
- case '[]':
- case '[]=':
- return [types.uintType];
- default:
- return null;
- }
- }
- return null;
-}
-
-List<TypeMask> _getSuccessTypesForStaticMethod(
- TypeMaskSystem types, FunctionElement target) {
- var lib = target.library;
- if (lib.isDartCore) {
- var cls = target.enclosingClass?.name;
- if (cls == 'int' && target.name == 'parse') {
- // source, onError, radix
- return [types.stringType, types.dynamicType, types.uint31Type.nullable()];
- } else if (cls == 'double' && target.name == 'parse') {
- return [types.stringType, types.dynamicType];
- }
- }
-
- if (lib.isPlatformLibrary && '${lib.canonicalUri}' == 'dart:math') {
- switch (target.name) {
- case 'sqrt':
- case 'sin':
- case 'cos':
- case 'tan':
- case 'acos':
- case 'asin':
- case 'atan':
- case 'atan2':
- case 'exp':
- case 'log':
- return [types.numType];
- case 'pow':
- return [types.numType, types.numType];
- }
- }
-
- return null;
-}
diff --git a/pkg/compiler/lib/src/cps_ir/loop_effects.dart b/pkg/compiler/lib/src/cps_ir/loop_effects.dart
deleted file mode 100644
index e2f5e22..0000000
--- a/pkg/compiler/lib/src/cps_ir/loop_effects.dart
+++ /dev/null
@@ -1,99 +0,0 @@
-library dart2js.cps_ir.loop_effects;
-
-import '../world.dart';
-import 'cps_ir_nodes.dart';
-import 'effects.dart';
-import 'loop_hierarchy.dart';
-
-/// 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, int> loopSideEffects = {};
- Continuation currentLoopHeader;
-
- LoopSideEffects(FunctionDefinition node, this.world, {this.loopHierarchy}) {
- if (loopHierarchy == null) {
- loopHierarchy = new LoopHierarchy(node);
- }
- visit(node);
- }
-
- /// Returns the accumulated effects and dependencies on all paths from the
- /// loop entry to any recursive invocation of the 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 changesIndexableLength(Continuation loop) {
- return loopSideEffects[loop] & Effects.changesIndexableLength != 0;
- }
-
- @override
- Expression traverseContinuation(Continuation cont) {
- if (cont.isRecursive) {
- loopSideEffects[cont] = Effects.none;
- exitContinuations[cont] = <Continuation>[];
- pushAction(() {
- if (currentLoopHeader != null) {
- loopSideEffects[currentLoopHeader] |= loopSideEffects[cont];
- }
- exitContinuations[cont].forEach(push);
- });
- }
- Continuation oldLoopHeader = currentLoopHeader;
- currentLoopHeader = loopHierarchy.getLoopHeader(cont);
- pushAction(() {
- currentLoopHeader = oldLoopHeader;
- });
- return cont.body;
- }
-
- @override
- Expression traverseLetHandler(LetHandler node) {
- enqueueContinuation(node.handler);
- return node.body;
- }
-
- @override
- Expression traverseLetCont(LetCont node) {
- node.continuations.forEach(enqueueContinuation);
- 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) {
- push(cont);
- } else {
- // Multiple loops can be exited at once.
- // Register as an exit from the outermost loop being exited.
- Continuation inner = currentLoopHeader;
- Continuation outer = loopHierarchy.getEnclosingLoop(currentLoopHeader);
- while (outer != loop) {
- if (inner == null) {
- // The shrinking reductions pass must run before any pass that relies
- // on computing loop side effects.
- world.compiler.reporter.internalError(
- null,
- 'Unreachable continuations must be removed before computing '
- 'loop side effects.');
- }
- inner = outer;
- outer = loopHierarchy.getEnclosingLoop(outer);
- }
- exitContinuations[inner].add(cont);
- }
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
deleted file mode 100644
index 4433510..0000000
--- a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
+++ /dev/null
@@ -1,175 +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 dart2js.cps_ir.loop_hierarchy;
-
-import 'cps_fragment.dart';
-import 'cps_ir_nodes.dart';
-
-/// Determines the effective nesting of loops.
-///
-/// The effective nesting of loops is different from the lexical nesting, since
-/// recursive continuations can generally contain all the code following
-/// after the loop in addition to the looping code itself.
-///
-/// For example, the 'else' branch below is not effectively part of the loop:
-///
-/// let rec kont x =
-/// if (<loop condition>)
-/// <loop body>
-/// InvokeContinuation kont x'
-/// else
-/// <after loop>
-/// return p.foo()
-///
-/// We use the term "loop" to mean recursive continuation.
-/// The `null` value is used to represent a context not part of any loop.
-class LoopHierarchy {
- /// Nesting depth of the given loop.
- Map<Continuation, int> loopDepth = <Continuation, int>{};
-
- /// The innermost loop (other than itself) that may be invoked recursively
- /// as a result of invoking the given continuation.
- Map<Continuation, Continuation> loopTarget = <Continuation, Continuation>{};
-
- /// Current nesting depth.
- int _currentDepth = 0;
-
- /// The loop target to use for missing code. Used by [update].
- Continuation _exitLoop;
-
- /// Computes the loop hierarchy for the given function.
- ///
- /// Parent pointers must be computed for [node].
- LoopHierarchy(FunctionDefinition node) {
- _processBlock(node.body, null);
- }
-
- /// Returns the innermost loop which [cont] is effectively part of.
- Continuation getLoopHeader(Continuation cont) {
- return cont.isRecursive ? cont : loopTarget[cont];
- }
-
- /// Returns the innermost loop which the given continuation is part of, other
- /// than itself.
- Continuation getEnclosingLoop(Continuation cont) {
- return loopTarget[cont];
- }
-
- /// Marks the innermost loop as a subloop of the other loop.
- ///
- /// Returns the innermost loop.
- ///
- /// Both continuations, [c1] and [c2] may be null (i.e. no loop).
- ///
- /// A loop is said to be a subloop of an enclosing loop if it can invoke
- /// that loop recursively. This information is stored in [loopTarget].
- ///
- /// This method is only invoked with two distinct loops if there is a
- /// point that can reach a recursive invocation of both loops.
- /// This implies that one loop is nested in the other, because they must
- /// both be in scope at that point.
- Continuation _markInnerLoop(Continuation c1, Continuation c2) {
- assert(c1 == null || c1.isRecursive);
- assert(c2 == null || c2.isRecursive);
- if (c1 == null) return c2;
- if (c2 == null) return c1;
- if (c1 == c2) return c1;
- if (loopDepth[c1] > loopDepth[c2]) {
- loopTarget[c1] = _markInnerLoop(loopTarget[c1], c2);
- return c1;
- } else {
- loopTarget[c2] = _markInnerLoop(loopTarget[c2], c1);
- return c2;
- }
- }
-
- /// Analyzes the body of [cont] and returns the innermost loop
- /// that can be invoked recursively from [cont] (other than [cont] itself).
- ///
- /// [catchLoop] is the innermost loop that can be invoked recursively
- /// from the current exception handler.
- Continuation _processContinuation(Continuation cont, Continuation catchLoop) {
- if (cont.isRecursive) {
- ++_currentDepth;
- loopDepth[cont] = _currentDepth;
- Continuation target = _processBlock(cont.body, catchLoop);
- _markInnerLoop(loopTarget[cont], target);
- --_currentDepth;
- } else {
- loopTarget[cont] = _processBlock(cont.body, catchLoop);
- }
- return loopTarget[cont];
- }
-
- /// Analyzes a basic block and returns the innermost loop that
- /// can be invoked recursively from that block.
- Continuation _processBlock(Expression node, Continuation catchLoop) {
- for (; node != null && node is! TailExpression; node = node.next) {
- if (node is LetCont) {
- for (Continuation cont in node.continuations) {
- _processContinuation(cont, catchLoop);
- }
- } else if (node is LetHandler) {
- catchLoop = _processContinuation(node.handler, catchLoop);
- }
- }
- Continuation target;
- if (node is InvokeContinuation) {
- if (node.isRecursive) {
- target = node.continuation;
- } else {
- target = loopTarget[node.continuation];
- }
- } else if (node is Branch) {
- target = _markInnerLoop(loopTarget[node.trueContinuation],
- loopTarget[node.falseContinuation]);
- } else if (node == null) {
- // If the code ends abruptly, use the exit loop provided in [update].
- target = _exitLoop;
- } else {
- assert(node is Unreachable || node is Throw || node == null);
- }
- return _markInnerLoop(target, catchLoop);
- }
-
- /// Returns the innermost loop that effectively encloses both
- /// c1 and c2 (or `null` if there is no such loop).
- Continuation lowestCommonAncestor(Continuation c1, Continuation c2) {
- int d1 = getDepth(c1), d2 = getDepth(c2);
- while (c1 != c2) {
- if (d1 <= d2) {
- c2 = getEnclosingLoop(c2);
- d2 = getDepth(c2);
- } else {
- c1 = getEnclosingLoop(c1);
- d1 = getDepth(c1);
- }
- }
- return c1;
- }
-
- /// Returns the lexical nesting depth of [loop].
- int getDepth(Continuation loop) {
- if (loop == null) return 0;
- return loopDepth[loop];
- }
-
- /// Sets the loop header for each continuation bound inside the given
- /// fragment.
- ///
- /// If the fragment is open, [exitLoop] denotes the loop header for
- /// the code that will occur after the fragment.
- ///
- /// [catchLoop] is the loop target for the catch clause of the try/catch
- /// surrounding the inserted fragment.
- void update(CpsFragment fragment,
- {Continuation exitLoop, Continuation catchLoop}) {
- if (fragment.isEmpty) return;
- _exitLoop = exitLoop;
- _currentDepth = getDepth(exitLoop);
- _processBlock(fragment.root, catchLoop);
- _exitLoop = null;
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart b/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart
deleted file mode 100644
index 8d84f0f..0000000
--- a/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart
+++ /dev/null
@@ -1,252 +0,0 @@
-library dart2js.cps_ir.loop_invariant_branch;
-
-import 'cps_fragment.dart';
-import 'cps_ir_nodes.dart';
-import 'loop_hierarchy.dart';
-import 'optimizers.dart';
-import 'redundant_join.dart' show AlphaRenamer;
-
-/// Hoists branches out of loops, where:
-/// - the branch is at the entry point of a loop
-/// - the branch condition is loop-invariant
-/// - one arm of the branch is not effectively part of the loop
-///
-/// Schematically:
-///
-/// b = COND
-/// while (true) {
-/// if (b)
-/// BRANCH (contains no continue to loop)
-/// else
-/// LOOP
-/// }
-///
-/// ==>
-///
-/// b = COND
-/// if (b)
-/// BRANCH
-/// else
-/// while (true)
-/// LOOP
-///
-/// As in [RedundantJoinEliminator], parameters are treated as names with
-/// lexical scoping during this pass, and a given parameter "name" may be
-/// declared by more than one continuation. The reference chains for parameters
-/// are therefore meaningless during this pass, until repaired by [AlphaRenamer]
-/// at the end.
-class LoopInvariantBranchMotion extends BlockVisitor implements Pass {
- String get passName => 'Loop invariant branch motion';
-
- LoopHierarchy loopHierarchy;
- final Map<Primitive, Continuation> loopHeaderFor =
- <Primitive, Continuation>{};
- final Map<Continuation, Continuation> catchLoopFor =
- <Continuation, Continuation>{};
- Continuation currentLoopHeader;
- Continuation currentCatchLoop;
- List<Continuation> loops = <Continuation>[];
- bool wasHoisted = false;
-
- void rewrite(FunctionDefinition node) {
- loopHierarchy = new LoopHierarchy(node);
- BlockVisitor.traverseInPreOrder(node, this);
- // Process loops bottom-up so a branch can be hoisted multiple times.
- loops.reversed.forEach(hoistEntryCheck);
- if (wasHoisted) {
- new AlphaRenamer().visit(node);
- }
- }
-
- void visitLetHandler(LetHandler node) {
- currentCatchLoop = loopHierarchy.getLoopHeader(node.handler);
- }
-
- void visitContinuation(Continuation node) {
- currentLoopHeader = loopHierarchy.getLoopHeader(node);
- for (Parameter param in node.parameters) {
- loopHeaderFor[param] = currentLoopHeader;
- }
- catchLoopFor[node] = currentCatchLoop;
- if (node.isRecursive) {
- loops.add(node);
- }
- }
-
- void visitLetPrim(LetPrim node) {
- loopHeaderFor[node.primitive] = currentLoopHeader;
- }
-
- void hoistEntryCheck(Continuation loop) {
- // Keep hoisting branches out of the loop, there can be more than one.
- while (tryHoistEntryCheck(loop));
- }
-
- Expression getEffectiveBody(Expression exp) {
- // TODO(asgerf): We could also bypass constants here but constant pooling
- // is likely to be a better solution for that.
- while (exp is LetCont) {
- exp = exp.next;
- }
- return exp;
- }
-
- /// Adds [parameters] to [cont] and updates every invocation to pass the
- /// corresponding parameter values as arguments. Thus, the parameters are
- /// passed in explicitly instead of being captured.
- ///
- /// This only works because [AlphaRenamer] cleans up at the end of this pass.
- ///
- /// Schematically:
- ///
- /// let outer(x1, x2, x3) =
- /// let inner(y) = BODY
- /// [ .. inner(y') .. ]
- ///
- /// ==> (append parameters)
- ///
- /// let outer(x1, x2, x3) =
- /// let inner(y, x1, x2, x3) = BODY
- /// [ .. inner(y', x1, x2, x3) .. ]
- ///
- /// ==> (hoist, not performed by this method)
- ///
- /// let inner(y, x1, x2, x3) = BODY
- /// let outer(x1, x2, x3) =
- /// [ .. inner(y', x1, x2, x3) .. ]
- ///
- void appendParameters(Continuation cont, List<Parameter> parameters) {
- cont.parameters.addAll(parameters);
- for (Reference ref = cont.firstRef; ref != null; ref = ref.next) {
- Node use = ref.parent;
- if (use is InvokeContinuation) {
- for (Parameter loopParam in parameters) {
- use.argumentRefs
- .add(new Reference<Primitive>(loopParam)..parent = use);
- }
- }
- }
- }
-
- bool tryHoistEntryCheck(Continuation loop) {
- // Check if this is a loop starting with a branch.
- Expression body = getEffectiveBody(loop.body);
- if (body is! Branch) return false;
- Branch branch = body;
-
- // Is the condition loop invariant?
- Primitive condition = branch.condition;
- if (loopHeaderFor[condition] == loop) return false;
-
- Continuation trueCont = branch.trueContinuation;
- Continuation falseCont = branch.falseContinuation;
- Continuation hoistedCase; // The branch to hoist.
- Continuation loopCase; // The branch that is part of the loop.
-
- // Check that one branch is part of the loop, and the other is an exit.
- if (loopHierarchy.getLoopHeader(trueCont) != loop &&
- loopHierarchy.getLoopHeader(falseCont) == loop) {
- hoistedCase = trueCont;
- loopCase = falseCont;
- } else if (loopHierarchy.getLoopHeader(falseCont) != loop &&
- loopHierarchy.getLoopHeader(trueCont) == loop) {
- hoistedCase = falseCont;
- loopCase = trueCont;
- } else {
- return false;
- }
-
- // Hoist non-loop continuations out of the loop.
- // The hoisted branch can reference other continuations bound in the loop,
- // so to stay in scope, those need to be hoisted as well.
- //
- // let b = COND
- // let loop(x) =
- // let join(y) = JOIN
- // let hoistCase() = HOIST
- // let loopCase() = LOOP
- // branch b hoistCase loopCase
- // in loop(i)
- //
- // ==>
- //
- // let b = COND
- // let join(y,x) = JOIN
- // let hoistCase(x) = HOIST
- // let loop(x) =
- // let loopCase() = LOOP
- // branch b hoistCase loopCase
- // in loop(i)
- //
- LetCont loopBinding = loop.parent;
- Expression it = loop.body;
- while (it is LetCont) {
- LetCont let = it;
- it = let.body;
- for (Continuation cont in let.continuations) {
- if (loopHierarchy.getEnclosingLoop(cont) != loop) {
- appendParameters(cont, loop.parameters);
- new LetCont(cont, null).insertAbove(loopBinding);
- }
- }
- let.continuations.removeWhere((cont) => cont.parent != let);
- if (let.continuations.isEmpty) {
- let.remove();
- }
- }
-
- // Create a new branch to call the hoisted continuation or the loop:
- //
- // let loop(x) =
- // let loopCase() = LOOP
- // branch b hoistCase loopCase
- // in loop(i)
- //
- // ==>
- //
- // let newTrue() = hoistCase(i)
- // let newFalse() =
- // let loop(x) =
- // let loopCase() = LOOP
- // branch b hoistCase loopCase
- // branch b newTrue newFalse
- //
- InvokeContinuation loopEntry = loopBinding.body;
- List<Primitive> loopArgs = loopEntry.arguments.toList();
- CpsFragment cps = new CpsFragment();
- cps
- .branch(condition,
- strict: branch.isStrictCheck, negate: hoistedCase == falseCont)
- .invokeContinuation(hoistedCase, loopArgs);
-
- // The continuations created in the fragment need to have their loop header
- // set so the loop hierarchy remains intact
- loopHierarchy.update(cps,
- exitLoop: loopHierarchy.getEnclosingLoop(loop),
- catchLoop: catchLoopFor[loop]);
-
- // Insert above the loop. This will put the loop itself in a branch.
- cps.insertAbove(loopBinding);
-
- // Replace the old branch with the loopCase, still bound inside the loop:
- //
- // let loop(x) =
- // let loopCase() = LOOP
- // branch b hoistCase loopCase
- // in loop(i)
- //
- // ==>
- //
- // let loop(x) =
- // let loopCase() = LOOP
- // loopCase()
- // in loop(i)
- //
- destroyAndReplace(branch, new InvokeContinuation(loopCase, []));
-
- // Record that at least one branch was hoisted to trigger alpha renaming.
- wasHoisted = true;
-
- return true;
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
deleted file mode 100644
index ee44978..0000000
--- a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
+++ /dev/null
@@ -1,247 +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 dart2js.cps_ir.mutable_ssa;
-
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart';
-
-/// Determines which mutable variables should be rewritten to phi assignments
-/// in this pass.
-///
-/// We do not rewrite variables that have an assignment inside a try block that
-/// does not contain its declaration.
-class MutableVariablePreanalysis extends TrampolineRecursiveVisitor {
- // Number of try blocks enclosing the current position.
- int currentDepth = 0;
-
- /// Number of try blocks enclosing the declaration of a given mutable
- /// variable.
- ///
- /// All mutable variables seen will be present in the map after the analysis.
- Map<MutableVariable, int> variableDepth = <MutableVariable, int>{};
-
- /// Variables with an assignment inside a try block that does not contain
- /// its declaration.
- Set<MutableVariable> hasAssignmentInTry = new Set<MutableVariable>();
-
- @override
- Expression traverseLetHandler(LetHandler node) {
- push(node.handler);
- ++currentDepth;
- pushAction(() => --currentDepth);
- return node.body;
- }
-
- void processLetMutable(LetMutable node) {
- variableDepth[node.variable] = currentDepth;
- }
-
- void processSetMutable(SetMutable node) {
- MutableVariable variable = node.variable;
- if (currentDepth > variableDepth[variable]) {
- hasAssignmentInTry.add(variable);
- }
- }
-
- /// True if there are no mutable variables or they are all assigned inside
- /// a try block. In this case, there is nothing to do and the pass should
- /// be skipped.
- bool get allMutablesAreAssignedInTryBlocks {
- return hasAssignmentInTry.length == variableDepth.length;
- }
-}
-
-/// Replaces mutable variables with continuation parameters, effectively
-/// bringing them into SSA form.
-///
-/// This pass is intended to clean up mutable variables that were introduced
-/// by an optimization in the type propagation pass.
-///
-/// This implementation potentially creates a lot of redundant and dead phi
-/// parameters. These will be cleaned up by redundant phi elimination and
-/// shrinking reductions.
-///
-/// Discussion:
-/// For methods with a lot of mutable variables, creating all the spurious
-/// parameters might be too expensive. If this is the case, we should
-/// improve this pass to avoid most spurious parameters in practice.
-class MutableVariableEliminator implements Pass {
- String get passName => 'Mutable variable elimination';
-
- /// Mutable variables currently in scope, in order of declaration.
- /// This list determines the order of the corresponding phi parameters.
- final List<MutableVariable> mutableVariables = <MutableVariable>[];
-
- /// Number of phi parameters added to the given continuation.
- final Map<Continuation, int> continuationPhiCount = <Continuation, int>{};
-
- /// Stack of yet unprocessed continuations interleaved with the
- /// mutable variables currently in scope.
- ///
- /// Continuations are processed when taken off the stack and mutable
- /// variables fall out of scope (i.e. removed from [mutableVariables]) when
- /// taken off the stack.
- final List<StackItem> stack = <StackItem>[];
-
- MutableVariablePreanalysis analysis;
-
- void rewrite(FunctionDefinition node) {
- analysis = new MutableVariablePreanalysis()..visit(node);
- if (analysis.allMutablesAreAssignedInTryBlocks) {
- // Skip the pass if there is nothing to do.
- return;
- }
- processBlock(node.body, <MutableVariable, Primitive>{});
- while (stack.isNotEmpty) {
- StackItem item = stack.removeLast();
- if (item is ContinuationItem) {
- processBlock(item.continuation.body, item.environment);
- } else {
- assert(item is VariableItem);
- mutableVariables.removeLast();
- }
- }
- }
-
- bool shouldRewrite(MutableVariable variable) {
- return !analysis.hasAssignmentInTry.contains(variable);
- }
-
- bool isJoinContinuation(Continuation cont) {
- return !cont.hasExactlyOneUse || cont.firstRef.parent is InvokeContinuation;
- }
-
- /// If some useful source information is attached to exactly one of the
- /// two definitions, the information is copied onto the other.
- void mergeHints(MutableVariable variable, Primitive value) {
- if (variable.hint == null) {
- variable.hint = value.hint;
- } else if (value.hint == null) {
- value.hint = variable.hint;
- }
- }
-
- /// Processes a basic block, replacing mutable variable uses with direct
- /// references to their values.
- ///
- /// [environment] is the current value of each mutable variable. The map
- /// will be mutated during the processing.
- ///
- /// Continuations to be processed are put on the stack for later processing.
- void processBlock(
- Expression node, Map<MutableVariable, Primitive> environment) {
- Expression next = node.next;
- for (; node is! TailExpression; node = next, next = node.next) {
- if (node is LetMutable && shouldRewrite(node.variable)) {
- // Put the new mutable variable on the stack while processing the body,
- // and pop it off again when done with the body.
- mutableVariables.add(node.variable);
- stack.add(new VariableItem());
-
- // Put the initial value into the environment.
- Primitive value = node.value;
- environment[node.variable] = value;
-
- // Preserve variable names.
- mergeHints(node.variable, value);
-
- // Remove the mutable variable binding.
- node.valueRef.unlink();
- node.remove();
- } else if (node is LetPrim && node.primitive is SetMutable) {
- SetMutable setter = node.primitive;
- MutableVariable variable = setter.variable;
- if (shouldRewrite(variable)) {
- // As above, update the environment, preserve variables and remove
- // the mutable variable assignment.
- 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;
- if (shouldRewrite(variable)) {
- // Replace with the reaching definition from the environment.
- Primitive value = environment[variable];
- getter.replaceUsesWith(value);
- mergeHints(variable, value);
- node.remove();
- }
- } else if (node is LetCont) {
- // Create phi parameters for each join continuation bound here, and put
- // them on the stack for later processing.
- // Note that non-join continuations are handled at the use-site.
- for (Continuation cont in node.continuations) {
- if (!isJoinContinuation(cont)) continue;
- // Create a phi parameter for every mutable variable in scope.
- // At the same time, build the environment to use for processing
- // the continuation (mapping mutables to phi parameters).
- continuationPhiCount[cont] = mutableVariables.length;
- Map<MutableVariable, Primitive> environment =
- <MutableVariable, Primitive>{};
- for (MutableVariable variable in mutableVariables) {
- Parameter phi = new Parameter(variable.hint);
- phi.type = variable.type;
- cont.parameters.add(phi);
- phi.parent = cont;
- environment[variable] = phi;
- }
- stack.add(new ContinuationItem(cont, environment));
- }
- } else if (node is LetHandler) {
- // Process the catch block later and continue into the try block.
- // We can use the same environment object for the try and catch blocks.
- // The current environment bindings cannot change inside the try block
- // because we exclude all variables assigned inside a try block.
- // The environment might be extended with more bindings before we
- // analyze the catch block, but that's ok.
- stack.add(new ContinuationItem(node.handler, environment));
- }
- }
-
- // Analyze the terminal node.
- if (node is InvokeContinuation) {
- 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.
- int phiCount = continuationPhiCount[cont];
- for (int i = 0; i < phiCount; ++i) {
- Primitive value = environment[mutableVariables[i]];
- Reference<Primitive> arg = new Reference<Primitive>(value);
- node.argumentRefs.add(arg);
- arg.parent = node;
- }
- } else if (node is Branch) {
- // Enqueue both branches with the current environment.
- // 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,
- new Map<MutableVariable, Primitive>.from(environment)));
- stack.add(new ContinuationItem(node.falseContinuation, environment));
- } else {
- assert(node is Throw || node is Unreachable);
- }
- }
-}
-
-abstract class StackItem {}
-
-/// Represents a mutable variable that is in scope.
-///
-/// The topmost mutable variable falls out of scope when this item is
-/// taken off the stack.
-class VariableItem extends StackItem {}
-
-/// Represents a yet unprocessed continuation together with the
-/// environment in which to process it.
-class ContinuationItem extends StackItem {
- final Continuation continuation;
- final Map<MutableVariable, Primitive> environment;
-
- ContinuationItem(this.continuation, this.environment);
-}
diff --git a/pkg/compiler/lib/src/cps_ir/octagon.dart b/pkg/compiler/lib/src/cps_ir/octagon.dart
deleted file mode 100644
index 83feb77..0000000
--- a/pkg/compiler/lib/src/cps_ir/octagon.dart
+++ /dev/null
@@ -1,197 +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 dart2js.cps_ir.octagon;
-
-import 'dart:collection';
-
-/// For every variable in the constraint system, two [SignedVariable]s exist,
-/// representing the positive and negative uses of the variable.
-///
-/// For instance, `v1 - v2` is represented as `v1 + (-v2)`, with -v2 being
-/// a "negative use" of v2.
-class SignedVariable {
- /// Negated version of this variable.
- SignedVariable _negated;
- SignedVariable get negated => _negated;
-
- /// Constraints that mention this signed variable.
- final List<Constraint> _constraints = <Constraint>[];
-
- static int _hashCount = 0;
- final int hashCode = (_hashCount = _hashCount + 1) & 0x0fffffff;
-
- SignedVariable._make() {
- _negated = new SignedVariable._makeTwin(this);
- }
-
- SignedVariable._makeTwin(this._negated);
-}
-
-/// A constraint of form `v1 + v2 <= k`.
-class Constraint {
- final SignedVariable v1, v2;
- final int bound;
-
- Constraint(this.v1, this.v2, this.bound);
-}
-
-/// A system of constraints of form `v1 + v2 <= k`.
-///
-/// Constraints can be added and removed in stack-order. The octagon will
-/// always determine whether it is in a solvable state, but will otherwise
-/// not optimize its internal representation.
-///
-/// There is currently no support for querying the upper and lower bounds
-/// of a variable, (which can be used to approximate ternary constraints
-/// `v1 + v2 + v3 <= k`), but it is something we could consider adding.
-class Octagon {
- /// Number of constraints that have been added since the constraint system
- /// became unsolvable (including the constraint that made it unsolvable).
- ///
- /// This is well-defined because constraints are pushed/popped in stack order.
- int _unsolvableCounter = 0;
-
- /// True if the constraint system is unsolvable in its current state.
- ///
- /// It will remain unsolvable until a number of constraints have been popped.
- bool get isUnsolvable => _unsolvableCounter > 0;
-
- /// True if the constraint system is solvable in its current state.
- bool get isSolvable => _unsolvableCounter == 0;
-
- /// Make a new variable, optionally with known lower and upper bounds
- /// (both inclusive).
- ///
- /// The constraints generated for [min] and [max] are also expressible using
- /// [Constraint] objects, but the constraints added in [makeVariable] live
- /// outside the stack discipline (i.e. the bounds are never popped), which is
- /// useful when generating variables on-the-fly.
- SignedVariable makeVariable([int min, int max]) {
- SignedVariable v1 = new SignedVariable._make();
- if (min != null) {
- // v1 >= min <==> -v1 - v1 <= -2 * min
- v1.negated._constraints
- .add(new Constraint(v1.negated, v1.negated, -2 * min));
- }
- if (max != null) {
- // v1 <= max <==> v1 + v1 <= 2 * max
- v1._constraints.add(new Constraint(v1, v1, 2 * max));
- }
- return v1;
- }
-
- /// Add the constraint `v1 + v2 <= k`.
- ///
- /// The constraint should be removed again using [popConstraint].
- void pushConstraint(Constraint constraint) {
- if (_unsolvableCounter > 0 ||
- _unsolvableCounter == 0 && _checkUnsolvable(constraint)) {
- ++_unsolvableCounter;
- }
- constraint.v1._constraints.add(constraint);
- if (constraint.v1 != constraint.v2) {
- constraint.v2._constraints.add(constraint);
- }
- }
-
- /// Remove a constraint that was previously added with [pushConstraint].
- ///
- /// Constraints must be added and removed in stack-order.
- void popConstraint(Constraint constraint) {
- assert(constraint.v1._constraints.last == constraint);
- assert(constraint.v2._constraints.last == constraint);
- constraint.v1._constraints.removeLast();
- if (constraint.v1 != constraint.v2) {
- constraint.v2._constraints.removeLast();
- }
- if (_unsolvableCounter > 0) {
- --_unsolvableCounter;
- }
- }
-
- /// Return true if [constraint] would make the constraint system unsolvable.
- ///
- /// Assumes the system is currently solvable.
- bool _checkUnsolvable(Constraint constraint) {
- // Constraints are transitively composed like so:
- // v1 + v2 <= k1
- // -v2 + v3 <= k2
- // implies:
- // v1 + v3 <= k1 + k2
- //
- // We construct a graph such that the tightest bound on `v1 + v3` is the
- // weight of the shortest path from `v1` to `-v3`.
- //
- // Every constraint `v1 + v2 <= k` gives rise to two edges:
- // (v1) --k--> (-v2)
- // (v2) --k--> (-v1)
- //
- // The system is unsolvable if and only if a negative-weight cycle exists
- // in this graph (this corresponds to a variable being less than itself).
-
- // Check if a negative-weight cycle would be created by adding [constraint].
- int length = _cycleLength(constraint);
- return length != null && length < 0;
- }
-
- /// Returns the length of the shortest simple cycle that would be created by
- /// adding [constraint] to the graph.
- ///
- /// Assumes there are no existing negative-weight cycles. The new cycle
- /// may have negative weight as [constraint] has not been added yet.
- int _cycleLength(Constraint constraint) {
- // Single-source shortest path using a FIFO queue.
- Queue<SignedVariable> worklist = new Queue<SignedVariable>();
- Map<SignedVariable, int> distance = {};
- void updateDistance(SignedVariable v, int newDistance) {
- int oldDistance = distance[v];
- if (oldDistance == null || oldDistance > newDistance) {
- distance[v] = newDistance;
- worklist.addLast(v);
- }
- }
- void iterateWorklist() {
- while (!worklist.isEmpty) {
- SignedVariable v1 = worklist.removeFirst();
- int distanceToV1 = distance[v1];
- for (Constraint c in v1._constraints) {
- SignedVariable v2 = c.v1 == v1 ? c.v2 : c.v1;
- updateDistance(v2.negated, distanceToV1 + c.bound);
- }
- }
- }
- // Two new edges will be added by the constraint `v1 + v2 <= k`:
- //
- // A. (v1) --> (-v2)
- // B. (v2) --> (-v1)
- //
- // We need to check for two kinds of cycles:
- //
- // Using only A: (-v2) --> (v1) --A--> (-v2)
- // Using B and then A: (-v2) --> (v2) --B--> (-v1) --> (v1) --A--> (-v2)
- //
- // Because of the graph symmetry, cycles using only B or using A and then B
- // exist if and only if the corresponding cycle above exist, so there is no
- // need to check for those.
- //
- // Do a single-source shortest paths reaching out from (-v2).
- updateDistance(constraint.v2.negated, 0);
- iterateWorklist();
- if (constraint.v1 != constraint.v2) {
- int distanceToV2 = distance[constraint.v2];
- if (distanceToV2 != null) {
- // Allow one use of the B edge.
- // This must be done outside fixpoint iteration as an infinite loop
- // would arise when an negative-weight cycle using only B exists.
- updateDistance(constraint.v1.negated, distanceToV2 + constraint.bound);
- iterateWorklist();
- }
- }
- // Get the distance to (v1) and check if the A edge would complete a cycle.
- int distanceToV1 = distance[constraint.v1];
- if (distanceToV1 == null) return null;
- return distanceToV1 + constraint.bound;
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
deleted file mode 100644
index 59ef662..0000000
--- a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
+++ /dev/null
@@ -1,327 +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 dart2js.cps_ir.optimize_interceptors;
-
-import '../constants/values.dart';
-import '../elements/elements.dart';
-import '../io/source_information.dart' show SourceInformation;
-import '../js_backend/backend_helpers.dart' show BackendHelpers;
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import '../types/types.dart' show TypeMask;
-import '../world.dart';
-import 'cps_fragment.dart';
-import 'cps_ir_nodes.dart';
-import 'loop_hierarchy.dart';
-import 'optimizers.dart';
-import 'type_mask_system.dart';
-
-/// Replaces `getInterceptor` calls with interceptor constants when possible,
-/// or with "almost constant" expressions like "x && CONST" when the input
-/// is either null or has a known interceptor.
-///
-/// Narrows the set of intercepted classes for interceptor calls.
-///
-/// Replaces calls on interceptors with one-shot interceptors.
-class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass {
- String get passName => 'Optimize interceptors';
-
- final TypeMaskSystem typeSystem;
- final JavaScriptBackend backend;
- LoopHierarchy loopHierarchy;
- Continuation currentLoopHeader;
-
- OptimizeInterceptors(this.backend, this.typeSystem);
-
- BackendHelpers get helpers => backend.helpers;
- World get classWorld => backend.compiler.world;
-
- Map<Interceptor, Continuation> loopHeaderFor = <Interceptor, Continuation>{};
-
- void rewrite(FunctionDefinition node) {
- // TODO(asgerf): Computing the LoopHierarchy here may be overkill when all
- // we want is to hoist constants out of loops.
- loopHierarchy = new LoopHierarchy(node);
- visit(node.body);
- new ShareConstants().visit(node);
- }
-
- @override
- Expression traverseContinuation(Continuation cont) {
- Continuation oldLoopHeader = currentLoopHeader;
- currentLoopHeader = loopHierarchy.getLoopHeader(cont);
- pushAction(() {
- currentLoopHeader = oldLoopHeader;
- });
- return cont.body;
- }
-
- bool hasNoFalsyValues(ClassElement class_) {
- return class_ != helpers.jsInterceptorClass &&
- class_ != helpers.jsNullClass &&
- class_ != helpers.jsBoolClass &&
- class_ != helpers.jsStringClass &&
- !class_.isSubclassOf(helpers.jsNumberClass);
- }
-
- Continuation getCurrentOuterLoop({Continuation scope}) {
- Continuation inner = null, outer = currentLoopHeader;
- while (outer != scope) {
- inner = outer;
- outer = loopHierarchy.getEnclosingLoop(outer);
- }
- return inner;
- }
-
- /// Binds the given constant in a primitive, in scope of the [useSite].
- ///
- /// The constant will be hoisted out of loops, and shared with other requests
- /// for the same constant as long as it is in scope.
- Primitive makeConstantFor(ConstantValue constant,
- {Expression useSite,
- TypeMask type,
- SourceInformation sourceInformation,
- Entity hint}) {
- Constant prim =
- new Constant(constant, sourceInformation: sourceInformation);
- prim.hint = hint;
- prim.type = type;
- LetPrim letPrim = new LetPrim(prim);
- Continuation loop = getCurrentOuterLoop();
- if (loop != null) {
- LetCont loopBinding = loop.parent;
- letPrim.insertAbove(loopBinding);
- } else {
- letPrim.insertAbove(useSite);
- }
- return prim;
- }
-
- void computeInterceptedClasses(Interceptor interceptor) {
- Set<ClassElement> intercepted = interceptor.interceptedClasses;
- intercepted.clear();
- for (Reference ref = interceptor.firstRef; ref != null; ref = ref.next) {
- Node use = ref.parent;
- if (use is InvokeMethod) {
- TypeMask type = use.receiver.type;
- bool canOccurAsReceiver(ClassElement elem) {
- return classWorld.isInstantiated(elem) &&
- !typeSystem.areDisjoint(
- type, typeSystem.getInterceptorSubtypes(elem));
- }
- Iterable<ClassElement> classes =
- backend.getInterceptedClassesOn(use.selector.name);
- intercepted.addAll(classes.where(canOccurAsReceiver));
- } else {
- intercepted.clear();
- intercepted.add(backend.helpers.jsInterceptorClass);
- break;
- }
- }
- if (intercepted.contains(backend.helpers.jsInterceptorClass) ||
- intercepted.contains(backend.helpers.jsNullClass)) {
- // If the null value is intercepted, update the type of the interceptor.
- // The Tree IR uses this information to determine if the method lookup
- // on an InvokeMethod might throw.
- interceptor.type = interceptor.type.nonNullable();
- }
- }
-
- /// True if [node] may return [JSNumber] instead of [JSInt] or [JSDouble].
- bool jsNumberClassSuffices(Interceptor node) {
- // No methods on JSNumber call 'down' to methods on JSInt or JSDouble. If
- // all uses of the interceptor are for methods is defined only on JSNumber
- // then JSNumber will suffice in place of choosing between JSInt or
- // JSDouble.
- for (Reference ref = node.firstRef; ref != null; ref = ref.next) {
- if (ref.parent is InvokeMethod) {
- InvokeMethod invoke = ref.parent;
- if (invoke.interceptorRef != ref) return false;
- var interceptedClasses =
- backend.getInterceptedClassesOn(invoke.selector.name);
- if (interceptedClasses.contains(helpers.jsDoubleClass)) return false;
- if (interceptedClasses.contains(helpers.jsIntClass)) return false;
- continue;
- }
- // Other uses need full distinction.
- return false;
- }
- return true;
- }
-
- /// True if [node] can intercept a `null` value and return the [JSNull]
- /// interceptor.
- bool canInterceptNull(Interceptor node) {
- for (Reference ref = node.firstRef; ref != null; ref = ref.next) {
- Node use = ref.parent;
- if (use is InvokeMethod) {
- if (selectorsOnNull.contains(use.selector) &&
- use.receiver.type.isNullable) {
- return true;
- }
- } else {
- return true;
- }
- }
- return false;
- }
-
- /// Returns the only interceptor class that may be returned by [node], or
- /// `null` if no such class could be found.
- ClassElement getSingleInterceptorClass(Interceptor node) {
- // 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;
- TypeMask type = input.type;
- if (canInterceptNull(node)) return null;
- type = type.nonNullable();
- if (typeSystem.isDefinitelyArray(type)) {
- return backend.helpers.jsArrayClass;
- }
- if (typeSystem.isDefinitelyInt(type)) {
- return backend.helpers.jsIntClass;
- }
- if (typeSystem.isDefinitelyNum(type) && jsNumberClassSuffices(node)) {
- return backend.helpers.jsNumberClass;
- }
- ClassElement singleClass = type.singleClass(classWorld);
- if (singleClass != null &&
- singleClass.isSubclassOf(backend.helpers.jsInterceptorClass)) {
- return singleClass;
- }
- return null;
- }
-
- /// Try to replace [interceptor] with a constant, and return `true` if
- /// successful.
- bool constifyInterceptor(Interceptor interceptor) {
- LetPrim let = interceptor.parent;
- Primitive input = interceptor.input;
- ClassElement classElement = getSingleInterceptorClass(interceptor);
-
- if (classElement == null) return false;
- ConstantValue constant = new InterceptorConstantValue(classElement.rawType);
-
- if (!input.type.isNullable) {
- Primitive constantPrim = makeConstantFor(constant,
- useSite: let,
- type: interceptor.type,
- sourceInformation: interceptor.sourceInformation);
- constantPrim.useElementAsHint(interceptor.hint);
- interceptor
- ..replaceUsesWith(constantPrim)
- ..destroy();
- let.remove();
- } else {
- Primitive constantPrim = makeConstantFor(constant,
- useSite: let,
- type: interceptor.type.nonNullable(),
- sourceInformation: interceptor.sourceInformation);
- CpsFragment cps = new CpsFragment(interceptor.sourceInformation);
- Parameter param = new Parameter(interceptor.hint);
- param.type = interceptor.type;
- Continuation cont = cps.letCont(<Parameter>[param]);
- if (hasNoFalsyValues(classElement)) {
- // If null is the only falsy value, compile as "x && CONST".
- cps.ifFalsy(input).invokeContinuation(cont, [input]);
- } else {
- // If there are other falsy values compile as "x == null ? x : CONST".
- Primitive condition =
- cps.applyBuiltin(BuiltinOperator.LooseEq, [input, cps.makeNull()]);
- cps.ifTruthy(condition).invokeContinuation(cont, [input]);
- }
- cps.invokeContinuation(cont, [constantPrim]);
- cps.context = cont;
- cps.insertAbove(let);
- interceptor
- ..replaceUsesWith(param)
- ..destroy();
- let.remove();
- }
- return true;
- }
-
- @override
- Expression traverseLetPrim(LetPrim node) {
- Expression next = node.body;
- visit(node.primitive);
- return next;
- }
-
- @override
- void visitInterceptor(Interceptor node) {
- if (constifyInterceptor(node)) return;
- computeInterceptedClasses(node);
- if (node.hasExactlyOneUse) {
- // Set the loop header on single-use interceptors so [visitInvokeMethod]
- // can determine if it should become a one-shot interceptor.
- loopHeaderFor[node] = currentLoopHeader;
- }
- }
-
- @override
- void visitInvokeMethod(InvokeMethod node) {
- if (node.callingConvention != CallingConvention.Intercepted) return;
- Primitive interceptor = node.interceptor;
- if (interceptor is! Interceptor ||
- interceptor.hasMultipleUses ||
- loopHeaderFor[interceptor] != currentLoopHeader) {
- return;
- }
- // TODO(asgerf): Consider heuristics for when to use one-shot interceptors.
- // E.g. using only one-shot interceptors with a fast path.
- node.makeOneShotIntercepted();
- }
-
- @override
- void visitTypeTestViaFlag(TypeTestViaFlag node) {
- Primitive interceptor = node.interceptor;
- if (interceptor is! Interceptor ||
- interceptor.hasMultipleUses ||
- loopHeaderFor[interceptor] != currentLoopHeader ||
- !backend.mayGenerateInstanceofCheck(node.dartType)) {
- return;
- }
- Interceptor inter = interceptor;
- Primitive value = inter.input;
- node.replaceWith(new TypeTest(value, node.dartType, [])..type = node.type);
- }
-}
-
-/// Shares interceptor constants when one is in scope of another.
-///
-/// Interceptor optimization runs after GVN, hence this clean-up step is needed.
-///
-/// TODO(asgerf): Handle in separate constant optimization pass? With some other
-/// constant-related optimizations, like cloning small constants at use-site.
-class ShareConstants extends TrampolineRecursiveVisitor {
- Map<ConstantValue, Constant> sharedConstantFor = <ConstantValue, Constant>{};
-
- Expression traverseLetPrim(LetPrim node) {
- Expression next = node.body;
- if (node.primitive is Constant && shouldShareConstant(node.primitive)) {
- Constant prim = node.primitive;
- Constant existing = sharedConstantFor[prim.value];
- if (existing != null) {
- existing.useElementAsHint(prim.hint);
- prim
- ..replaceUsesWith(existing)
- ..destroy();
- node.remove();
- return next;
- }
- sharedConstantFor[prim.value] = prim;
- pushAction(() {
- assert(sharedConstantFor[prim.value] == prim);
- sharedConstantFor.remove(prim.value);
- });
- }
- return next;
- }
-
- bool shouldShareConstant(Constant constant) {
- return constant.value.isInterceptor;
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
deleted file mode 100644
index 3e22e10..0000000
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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 dart2js.cps_ir.optimizers;
-
-import '../common/names.dart';
-import '../constants/values.dart';
-import '../universe/selector.dart';
-import 'cps_ir_nodes.dart';
-
-export 'backward_null_check_remover.dart' show BackwardNullCheckRemover;
-export 'bounds_checker.dart' show BoundsChecker;
-export 'eagerly_load_statics.dart' show EagerlyLoadStatics;
-export 'gvn.dart' show GVN;
-export 'inline.dart' show Inliner;
-export 'insert_refinements.dart' show InsertRefinements;
-export 'loop_invariant_branch.dart' show LoopInvariantBranchMotion;
-export 'mutable_ssa.dart' show MutableVariableEliminator;
-export 'optimize_interceptors.dart' show OptimizeInterceptors;
-export 'parent_visitor.dart' show ParentVisitor;
-export 'path_based_optimizer.dart' show PathBasedOptimizer;
-export 'redundant_join.dart' show RedundantJoinEliminator;
-export 'redundant_phi.dart' show RedundantPhiEliminator;
-export 'redundant_refinement.dart' show RedundantRefinementEliminator;
-export 'scalar_replacement.dart' show ScalarReplacer;
-export 'shrinking_reductions.dart' show ShrinkingReducer;
-export 'type_propagation.dart' show TypePropagator;
-export 'update_refinements.dart' show UpdateRefinements;
-export 'use_field_initializers.dart' show UseFieldInitializers;
-
-/// An optimization pass over the CPS IR.
-abstract class Pass {
- /// Applies optimizations to root, rewriting it in the process.
- void rewrite(FunctionDefinition root);
-
- String get passName;
-}
-
-// Shared code between optimizations
-
-/// Returns true if [value] is false, null, 0, -0, NaN, or the empty string.
-bool isFalsyConstant(ConstantValue value) {
- return value.isFalse ||
- value.isNull ||
- value.isZero ||
- value.isMinusZero ||
- value.isNaN ||
- value is StringConstantValue && value.primitiveValue.isEmpty;
-}
-
-/// Returns true if [value] satisfies a branching condition with the
-/// given strictness.
-///
-/// For non-strict, this is the opposite of [isFalsyConstant].
-bool isTruthyConstant(ConstantValue value, {bool strict: false}) {
- return strict ? value.isTrue : !isFalsyConstant(value);
-}
-
-/// Selectors that do not throw when invoked on the null value.
-final List<Selector> selectorsOnNull = <Selector>[
- Selectors.equals,
- Selectors.hashCode_,
- Selectors.runtimeType_,
- Selectors.toString_,
- Selectors.toStringGetter,
- Selectors.noSuchMethodGetter
-];
diff --git a/pkg/compiler/lib/src/cps_ir/parent_visitor.dart b/pkg/compiler/lib/src/cps_ir/parent_visitor.dart
deleted file mode 100644
index bb98c33..0000000
--- a/pkg/compiler/lib/src/cps_ir/parent_visitor.dart
+++ /dev/null
@@ -1,42 +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 cps_ir.parent_visitor;
-
-import 'cps_ir_nodes.dart';
-
-/// Traverses the CPS term and sets node.parent for each visited node.
-class ParentVisitor extends DeepRecursiveVisitor {
- static void setParents(Node node) {
- ParentVisitor visitor = new ParentVisitor._make();
- visitor._worklist.add(node);
- visitor.trampoline();
- }
-
- /// Private to avoid accidental `new ParentVisitor().visit(node)` calls.
- ParentVisitor._make();
-
- Node _parent;
- final List<Node> _worklist = <Node>[];
-
- void trampoline() {
- while (_worklist.isNotEmpty) {
- _parent = _worklist.removeLast();
- _parent.accept(this);
- }
- }
-
- @override
- visit(Node node) {
- _worklist.add(node);
- assert(_parent != node);
- assert(_parent != null);
- node.parent = _parent;
- }
-
- @override
- processReference(Reference node) {
- node.parent = _parent;
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart b/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart
deleted file mode 100644
index d7f4acc..0000000
--- a/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart
+++ /dev/null
@@ -1,175 +0,0 @@
-// 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.path_based_optimizer;
-
-import '../js_backend/js_backend.dart';
-import 'cps_fragment.dart';
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart';
-import 'type_mask_system.dart';
-
-/// Optimizations based on intraprocedural forward dataflow analysis, taking
-/// into account path information that is not expressed by [Refinement] nodes.
-///
-/// ---
-///
-/// Removes branches that branch on the same value as a previously seen branch.
-/// For example:
-///
-/// if (x == y) {
-/// if (x == y) TRUE else FALSE
-/// }
-///
-/// ==> ([GVN] pass merges identical expressions)
-///
-/// var b = (x == y)
-/// if (b) {
-/// if (b) TRUE else FALSE
-/// }
-///
-/// ==> (this pass removes the duplicate branch)
-///
-/// var b = (x == y)
-/// if (b) {
-/// TRUE
-/// }
-///
-/// ---
-///
-/// Removes interceptors for method calls whose receiver is known to be a
-/// self-interceptor. For example:
-///
-/// x.foo$1();
-/// getInterceptor(x).$eq(x, y);
-///
-/// ==> (`x` is a self-interceptor, remove the `getInterceptor` call)
-///
-/// x.foo$1();
-/// x.$eq(0, y);
-///
-/// Although there is a [Refinement] node after the call to `x.foo$1()`, the
-/// refined type cannot always be represented exactly, and type propagation
-/// may therefore not see that `x` is a self-interceptor.
-//
-// TODO(asgerf): A kind of redundant join can arise where a branching condition
-// is known to be true/false on all but one predecessor for a branch. We could
-// try to reduce those.
-//
-// TODO(asgerf): Could be more precise if GVN shared expressions that are not
-// in direct scope of one another, e.g. by using phis pass the shared value.
-//
-class PathBasedOptimizer extends TrampolineRecursiveVisitor implements Pass {
- String get passName => 'Path-based optimizations';
-
- // Classification of all values.
- static const int TRUE = 1 << 0;
- static const int SELF_INTERCEPTOR = 1 << 1;
- static const int INTERCEPTED_TRUTHY = 1 << 2;
- static const int FALSE = 1 << 3;
- static const int OTHER_FALSY = 1 << 4;
-
- static const int TRUTHY = TRUE | SELF_INTERCEPTOR | INTERCEPTED_TRUTHY;
- static const int FALSY = FALSE | OTHER_FALSY;
- static const int ANY = TRUTHY | FALSY;
-
- final JavaScriptBackend backend;
- final TypeMaskSystem typeSystem;
-
- PathBasedOptimizer(this.backend, this.typeSystem);
-
- /// The possible values of the given primitive (or ANY if absent) at the
- /// current traversal position.
- Map<Primitive, int> valueOf = <Primitive, int>{};
-
- /// The possible values of each primitive at the entry to a continuation.
- ///
- /// Unreachable continuations are absent from the map.
- final Map<Continuation, Map<Primitive, int>> valuesAt =
- <Continuation, Map<Primitive, int>>{};
-
- void rewrite(FunctionDefinition node) {
- visit(node);
- }
-
- Map<Primitive, int> copy(Map<Primitive, int> map) {
- return new Map<Primitive, int>.from(map);
- }
-
- Expression traverseLetHandler(LetHandler node) {
- valuesAt[node.handler] = copy(valueOf);
- push(node.handler);
- return node.body;
- }
-
- Expression traverseContinuation(Continuation cont) {
- valueOf = valuesAt[cont];
- if (valueOf == null) {
- // Do not go into unreachable code.
- destroyAndReplace(cont.body, new Unreachable());
- }
- return cont.body;
- }
-
- void visitInvokeContinuation(InvokeContinuation node) {
- Continuation cont = node.continuation;
- if (cont.isReturnContinuation) return;
- if (node.isRecursive) return;
- Map<Primitive, int> target = valuesAt[cont];
- if (target == null) {
- valuesAt[cont] = valueOf;
- } else {
- for (Primitive prim in target.keys) {
- target[prim] |= valueOf[prim] ?? ANY;
- }
- }
- }
-
- visitBranch(Branch node) {
- 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.
- valuesAt[trueCont] = copy(valueOf);
- valuesAt[falseCont] = valueOf;
- return;
- }
- int values = valueOf[condition] ?? ANY;
- int positiveValues = node.isStrictCheck ? TRUE : TRUTHY;
- int negativeValues = (~positiveValues) & ANY;
- if (values & positiveValues == 0) {
- destroyAndReplace(node, new InvokeContinuation(falseCont, []));
- valuesAt[falseCont] = valueOf;
- } else if (values & negativeValues == 0) {
- destroyAndReplace(node, new InvokeContinuation(trueCont, []));
- valuesAt[trueCont] = valueOf;
- } else {
- valuesAt[trueCont] = copy(valueOf)..[condition] = values & positiveValues;
- valuesAt[falseCont] = valueOf..[condition] = values & negativeValues;
- }
- }
-
- void visitInvokeMethod(InvokeMethod node) {
- int receiverValue = valueOf[node.receiver] ?? ANY;
- if (!backend.isInterceptedSelector(node.selector)) {
- // Only self-interceptors can respond to a non-intercepted selector.
- valueOf[node.receiver] = receiverValue & SELF_INTERCEPTOR;
- } else if (receiverValue & ~SELF_INTERCEPTOR == 0 &&
- node.callingConvention == CallingConvention.Intercepted) {
- // This is an intercepted call whose receiver is definitely a
- // self-interceptor.
- // TODO(25646): If TypeMasks could represent "any self-interceptor" this
- // optimization should be subsumed by type propagation.
- node.interceptorRef.changeTo(node.receiver);
-
- // Replace the extra receiver argument with a dummy value if the
- // target definitely does not use it.
- if (typeSystem.targetIgnoresReceiverArgument(
- node.receiver.type, node.selector)) {
- node.makeDummyIntercepted();
- }
- }
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_join.dart b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
deleted file mode 100644
index 3ba1d61..0000000
--- a/pkg/compiler/lib/src/cps_ir/redundant_join.dart
+++ /dev/null
@@ -1,262 +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 dart2js.cps_ir.redundant_join_elimination;
-
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart';
-
-/// Eliminates redundant join points.
-///
-/// A redundant join point is a continuation that immediately branches
-/// based on one of its parameters, and that parameter is a constant value
-/// at every invocation. Each invocation is redirected to jump directly
-/// to the branch target.
-///
-/// Internally in this pass, parameters are treated as names with lexical
-/// scoping, and a given parameter "name" may be declared by more than
-/// 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 {
- String get passName => 'Redundant join elimination';
-
- final Set<Branch> workSet = new Set<Branch>();
-
- void rewrite(FunctionDefinition node) {
- visit(node);
-
- while (workSet.isNotEmpty) {
- Branch branch = workSet.first;
- workSet.remove(branch);
- rewriteBranch(branch);
- }
-
- new AlphaRenamer().visit(node);
- }
-
- void processBranch(Branch node) {
- workSet.add(node);
- }
-
- /// Returns the body of [node], ignoring all LetCont nodes.
- Expression getEffectiveBody(InteriorNode node) {
- while (true) {
- Expression body = node.body;
- if (body is LetCont) {
- node = body;
- } else {
- return body;
- }
- }
- }
-
- /// Returns the parent of [node], ignoring all LetCont nodes.
- InteriorNode getEffectiveParent(Expression node) {
- while (true) {
- Node parent = node.parent;
- if (parent is LetCont) {
- node = parent;
- } else {
- return parent;
- }
- }
- }
-
- void rewriteBranch(Branch branch) {
- InteriorNode parent = getEffectiveParent(branch);
- if (parent is! Continuation) return;
- Continuation branchCont = parent;
-
- // Other optimizations take care of single-use continuations.
- if (!branchCont.hasMultipleUses) return;
-
- // It might be beneficial to rewrite calls to recursive continuations,
- // but we currently do not support this.
- if (branchCont.isRecursive) return;
-
- // Check that the branching condition is a parameter on the
- // 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;
- int parameterIndex = branchCont.parameters.indexOf(condition);
- if (parameterIndex == -1) return;
-
- // Check that all callers hit a fixed branch, and count the number
- // of times each branch is hit.
- // We know all callers are InvokeContinuations because they are the only
- // valid uses of a multi-use continuation.
- int trueHits = 0, falseHits = 0;
- InvokeContinuation trueCall, falseCall;
- for (Reference ref = branchCont.firstRef; ref != null; ref = ref.next) {
- InvokeContinuation invoke = ref.parent;
- Primitive argument = invoke.argument(parameterIndex);
- if (argument is! Constant) return; // Branching condition is unknown.
- Constant constant = argument;
- if (isTruthyConstant(constant.value, strict: branch.isStrictCheck)) {
- ++trueHits;
- trueCall = invoke;
- } else {
- ++falseHits;
- falseCall = invoke;
- }
- }
-
- // The optimization is now known to be safe, but it only pays off if
- // one of the callers can inline its target, since otherwise we end up
- // replacing a boolean variable with a labeled break.
- // TODO(asgerf): The labeled break might be better? Evaluate.
- if (!(trueHits == 1 && !trueCall.isEscapingTry ||
- falseHits == 1 && !falseCall.isEscapingTry)) {
- return;
- }
-
- // Lift any continuations bound inside branchCont so they are in scope at
- // the call sites. When lifting, the parameters of branchCont fall out of
- // scope, so they are added as parameters on each lifted continuation.
- // Schematically:
- //
- // (LetCont (branchCont (x1, x2, x3) =
- // (LetCont (innerCont (y) = ...) in
- // [... innerCont(y') ...]))
- //
- // =>
- //
- // (LetCont (innerCont (y, x1, x2, x3) = ...) in
- // (LetCont (branchCont (x1, x2, x3) =
- // [... innerCont(y', x1, x2, x3) ...])
- //
- // Parameter objects become shared between branchCont and the lifted
- // continuations. [AlphaRenamer] will clean up at the end of this pass.
- LetCont outerLetCont = branchCont.parent;
- while (branchCont.body is LetCont) {
- LetCont innerLetCont = branchCont.body;
- for (Continuation innerCont in innerLetCont.continuations) {
- innerCont.parameters.addAll(branchCont.parameters);
- for (Reference ref = innerCont.firstRef; ref != null; ref = ref.next) {
- Expression use = ref.parent;
- if (use is InvokeContinuation) {
- for (Parameter param in branchCont.parameters) {
- use.argumentRefs
- .add(new Reference<Primitive>(param)..parent = use);
- }
- } else {
- // The branch will be eliminated, so don't worry about updating it.
- assert(use == branch);
- }
- }
- }
- innerLetCont.remove();
- innerLetCont.insertAbove(outerLetCont);
- }
-
- assert(branchCont.body == branch);
-
- Continuation trueCont = branch.trueContinuation;
- Continuation falseCont = branch.falseContinuation;
-
- assert(branchCont != trueCont);
- assert(branchCont != falseCont);
-
- // Rewrite every invocation of branchCont to call either the true or false
- // branch directly. Since these were lifted out above branchCont, they are
- // now in scope.
- // Since trueCont and falseCont were branch targets, they originally
- // had no parameters, and so after the lifting, their parameters are
- // exactly the same as those accepted by branchCont.
- while (branchCont.firstRef != null) {
- Reference reference = branchCont.firstRef;
- InvokeContinuation invoke = branchCont.firstRef.parent;
- Constant condition = invoke.argument(parameterIndex);
- if (isTruthyConstant(condition.value, strict: branch.isStrictCheck)) {
- invoke.continuationRef.changeTo(trueCont);
- } else {
- invoke.continuationRef.changeTo(falseCont);
- }
- assert(branchCont.firstRef != reference);
- }
-
- // Remove the now-unused branchCont continuation.
- assert(branchCont.hasNoUses);
- branch.trueContinuationRef.unlink();
- branch.falseContinuationRef.unlink();
- outerLetCont.continuations.remove(branchCont);
- if (outerLetCont.continuations.isEmpty) {
- outerLetCont.remove();
- }
-
- // We may have created new redundant join points in the two branches.
- enqueueContinuation(trueCont);
- enqueueContinuation(falseCont);
- }
-
- void enqueueContinuation(Continuation cont) {
- Expression body = getEffectiveBody(cont);
- if (body is Branch) {
- workSet.add(body);
- }
- }
-}
-
-/// Ensures parameter objects are not shared between different continuations,
-/// akin to alpha-renaming variables so every variable is named uniquely.
-/// For example:
-///
-/// LetCont (k1 x = (return x)) in
-/// LetCont (k2 x = (InvokeContinuation k3 x)) in ...
-/// =>
-/// LetCont (k1 x = (return x)) in
-/// LetCont (k2 x' = (InvokeContinuation k3 x')) in ...
-///
-/// After lifting LetConts in the main pass above, parameter objects can have
-/// multiple bindings. Each reference implicitly refers to the binding that
-/// is currently in scope.
-///
-/// This returns the IR to its normal form after redundant joins have been
-/// eliminated.
-class AlphaRenamer extends TrampolineRecursiveVisitor {
- Map<Parameter, Parameter> renaming = <Parameter, Parameter>{};
-
- processContinuation(Continuation cont) {
- if (cont.isReturnContinuation) return;
-
- List<Parameter> shadowedKeys = <Parameter>[];
- List<Parameter> shadowedValues = <Parameter>[];
-
- // Create new parameters and update the environment.
- for (int i = 0; i < cont.parameters.length; ++i) {
- Parameter param = cont.parameters[i];
- shadowedKeys.add(param);
- shadowedValues.add(renaming.remove(param));
- // If the parameter appears to belong to another continuation,
- // create a new parameter object for this continuation.
- if (param.parent != cont) {
- Parameter newParam = new Parameter(param.hint);
- newParam.type = param.type;
- renaming[param] = newParam;
- cont.parameters[i] = newParam;
- newParam.parent = cont;
- }
- }
-
- pushAction(() {
- // Restore the original environment.
- for (int i = 0; i < cont.parameters.length; ++i) {
- renaming.remove(cont.parameters[i]);
- if (shadowedValues[i] != null) {
- renaming[shadowedKeys[i]] = shadowedValues[i];
- }
- }
- });
- }
-
- processReference(Reference ref) {
- Parameter target = renaming[ref.definition];
- if (target != null) {
- ref.changeTo(target);
- }
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
deleted file mode 100644
index 96e6431..0000000
--- a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
+++ /dev/null
@@ -1,205 +0,0 @@
-// 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 dart2js.cps_ir.redundant_phi_elimination;
-
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart';
-
-/// Eliminate redundant phis from the given [FunctionDefinition].
-///
-/// Phis in this case are [Continuations] together with corresponding
-/// [InvokeContinuation]s. A [Continuation] parameter at position i is redundant
-/// if for all [InvokeContinuation]s, the parameter at position i is identical
-/// (except for feedback). Redundant parameters are removed from the
-/// continuation signature, all invocations, and replaced within the
-/// continuation body.
-class RedundantPhiEliminator extends TrampolineRecursiveVisitor
- implements Pass {
- String get passName => 'Redundant phi elimination';
-
- final Set<Continuation> workSet = new Set<Continuation>();
-
- @override
- void rewrite(FunctionDefinition root) {
- // Traverse the tree once to build the work set.
- visit(root);
-
- // Process each continuation one-by-one.
- while (workSet.isNotEmpty) {
- Continuation cont = workSet.first;
- workSet.remove(cont);
-
- if (cont.isReturnContinuation) {
- continue; // Skip function return continuations.
- }
-
- _processContinuation(cont);
- }
- }
-
- /// Called for each continuation on the work set. Modifies the IR graph if
- /// [cont] is a candidate for redundant phi elimination.
- void _processContinuation(Continuation cont) {
- // Generate the list of all cont invocations. If cont is used in any other
- // context (i.e. as a continuation of InvokeMethod), it is not possible to
- // optimize.
- List<InvokeContinuation> invokes = <InvokeContinuation>[];
- for (Reference ref = cont.firstRef; ref != null; ref = ref.next) {
- Node parent = ref.parent;
- if (parent is InvokeContinuation && ref == parent.continuationRef) {
- invokes.add(parent);
- } else {
- return; // Can't optimize.
- }
- }
-
- if (invokes.isEmpty) {
- return; // Continuation is never invoked, can't optimize.
- }
-
- /// Returns the unique definition of parameter i if it exists and null
- /// otherwise. A definition is unique if it is the only value used to
- /// invoke the continuation, excluding feedback.
- Primitive uniqueDefinitionOf(int i) {
- Primitive value = null;
- for (InvokeContinuation invoke in invokes) {
- Primitive def = invoke.argument(i).effectiveDefinition;
-
- if (cont.parameters[i] == def) {
- // Invocation param == param in LetCont (i.e. a recursive call).
- continue;
- } else if (value == null) {
- value = def; // Set initial comparison value.
- } else if (value != def) {
- return null; // Differing invocation arguments.
- }
- }
-
- return value;
- }
-
- // If uniqueDefinition is in the body of the LetCont binding the
- // continuation, then we will drop the continuation binding to just inside
- // the binding of uniqueDefiniton. This is not safe if we drop the
- // continuation binding inside a LetHandler exception handler binding.
- LetCont letCont = cont.parent;
- bool safeForHandlers(Definition uniqueDefinition) {
- bool seenHandler = false;
- Node current = uniqueDefinition.parent;
- while (current != null) {
- if (current == letCont) return !seenHandler;
- seenHandler = seenHandler || current is LetHandler;
- current = current.parent;
- }
- // When uniqueDefinition is not in the body of the LetCont binding the
- // continuation, we will not move any code, so that is safe.
- return true;
- }
-
- // Check if individual parameters are always called with a unique
- // definition, and remove them if that is the case. During each iteration,
- // we read the current parameter/argument from index `src` and copy it
- // to index `dst`.
- int dst = 0;
- for (int src = 0; src < cont.parameters.length; src++) {
- // Is the current phi redundant?
- Primitive uniqueDefinition = uniqueDefinitionOf(src);
- if (uniqueDefinition == null || !safeForHandlers(uniqueDefinition)) {
- // Reorganize parameters and arguments in case of deletions.
- if (src != dst) {
- cont.parameters[dst] = cont.parameters[src];
- for (InvokeContinuation invoke in invokes) {
- invoke.argumentRefs[dst] = invoke.argumentRefs[src];
- }
- }
- dst++;
- continue;
- }
-
- Primitive oldDefinition = cont.parameters[src];
-
- // Add continuations of about-to-be modified invokes to worklist since
- // we might introduce new optimization opportunities.
- for (Reference ref = oldDefinition.firstRef;
- ref != null;
- ref = ref.next) {
- Node parent = ref.parent;
- if (parent is InvokeContinuation) {
- Continuation thatCont = parent.continuation;
- if (thatCont != cont) {
- workSet.add(thatCont);
- }
- }
- }
-
- // Replace individual parameters:
- // * In the continuation body, replace occurrence of param with value,
- // * and implicitly remove param from continuation signature and
- // invocations by not incrementing `dst`. References of removed
- // arguments are unlinked to keep definition usages up to date.
- oldDefinition.replaceUsesWith(uniqueDefinition);
- for (InvokeContinuation invoke in invokes) {
- invoke.argumentRefs[src].unlink();
- }
-
- // Finally, if the substituted definition is not in scope of the affected
- // continuation, move the continuation binding. This is safe to do since
- // the continuation is referenced only as the target in continuation
- // invokes, and all such invokes must be within the scope of
- // [uniqueDefinition]. Note that this is linear in the depth of
- // the binding of [uniqueDefinition].
- letCont = _makeUniqueBinding(cont);
- _moveIntoScopeOf(letCont, uniqueDefinition);
- }
-
- // Remove trailing items from parameter and argument lists.
- cont.parameters.length = dst;
- for (InvokeContinuation invoke in invokes) {
- invoke.argumentRefs.length = dst;
- }
- }
-
- void processLetCont(LetCont node) {
- node.continuations.forEach(workSet.add);
- }
-}
-
-/// Returns true, iff [letCont] is not scope of [definition].
-/// Linear in the depth of definition within the IR graph.
-bool _isInScopeOf(LetCont letCont, Definition definition) {
- for (Node node = definition.parent; node != null; node = node.parent) {
- if (node == letCont) {
- return false;
- }
- }
-
- return true;
-}
-
-/// Moves [letCont] below the binding of [definition] within the IR graph.
-/// Does nothing if [letCont] is already within the scope of [definition].
-/// Assumes that one argument is nested within the scope of the other
-/// when this method is called.
-void _moveIntoScopeOf(LetCont letCont, Definition definition) {
- if (_isInScopeOf(letCont, definition)) return;
-
- InteriorNode binding = definition.parent;
- letCont.remove();
- letCont.insertBelow(binding);
-}
-
-/// Ensures [continuation] has its own LetCont binding by creating
-/// a new LetCont below its current binding, if necessary.
-///
-/// Returns the LetCont that now binds [continuation].
-LetCont _makeUniqueBinding(Continuation continuation) {
- LetCont letCont = continuation.parent;
- if (letCont.continuations.length == 1) return letCont;
- letCont.continuations.remove(continuation);
- LetCont newBinding = new LetCont(continuation, null);
- continuation.parent = newBinding;
- newBinding.insertBelow(letCont);
- return newBinding;
-}
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_refinement.dart b/pkg/compiler/lib/src/cps_ir/redundant_refinement.dart
deleted file mode 100644
index 8cd13b3..0000000
--- a/pkg/compiler/lib/src/cps_ir/redundant_refinement.dart
+++ /dev/null
@@ -1,57 +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 dart2js.cps_ir.redundant_refinement;
-
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart' show Pass;
-import 'type_mask_system.dart';
-
-/// Removes [Refinement] nodes where the input value is already known to
-/// satisfy the refinement type.
-///
-/// Note: This pass improves loop-invariant code motion in the GVN pass because
-/// GVN will currently not hoist a primitive across a refinement guard.
-/// But some opportunities for hoisting are still missed. A field access can
-/// safely be hoisted across a non-redundant refinement as long as the less
-/// refined value is still known to have the field. For example:
-///
-/// class A { var field; }
-/// class B extends A {}
-///
-/// var x = getA(); // Return type is subclass of A.
-/// while (x is B) { // Refinement to B is not redundant.
-/// x.field.baz++; // x.field is safe for hoisting,
-/// } // but blocked by the refinement node.
-///
-/// Ideally, this pass should go away and GVN should handle refinements
-/// directly.
-class RedundantRefinementEliminator extends TrampolineRecursiveVisitor
- implements Pass {
- String get passName => 'Redundant refinement elimination';
-
- TypeMaskSystem typeSystem;
-
- RedundantRefinementEliminator(this.typeSystem);
-
- void rewrite(FunctionDefinition node) {
- visit(node);
- }
-
- Expression traverseLetPrim(LetPrim node) {
- Expression next = node.body;
- if (node.primitive is Refinement) {
- Refinement refinement = node.primitive;
- Primitive value = refinement.value.definition;
- if (typeSystem.isMorePreciseOrEqual(value.type, refinement.refineType)) {
- refinement
- ..replaceUsesWith(value)
- ..destroy();
- node.remove();
- return next;
- }
- }
- return next;
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
deleted file mode 100644
index b66f88f..0000000
--- a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
+++ /dev/null
@@ -1,223 +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 dart2js.cps_ir.scalar_replacement;
-
-import 'dart:collection' show Queue;
-
-import '../common.dart';
-import '../compiler.dart' as dart2js show Compiler;
-import '../constants/values.dart';
-import '../elements/elements.dart';
-import '../types/types.dart';
-import '../world.dart' show World;
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart';
-
-/**
- * Replaces aggregates with a set of local values. Performs inlining of
- * single-use closures to generate more replaceable aggregates.
- */
-class ScalarReplacer extends Pass {
- String get passName => 'Scalar replacement';
-
- final InternalErrorFunction _internalError;
- final World _classWorld;
-
- ScalarReplacer(dart2js.Compiler compiler)
- : _internalError = compiler.reporter.internalError,
- _classWorld = compiler.world;
-
- @override
- void rewrite(FunctionDefinition root) {
- ScalarReplacementVisitor analyzer =
- new ScalarReplacementVisitor(_internalError, _classWorld);
- analyzer.analyze(root);
- analyzer.process();
- }
-}
-
-/**
- * Do scalar replacement of aggregates on instances. Since scalar replacement
- * can create new candidates, iterate until all scalar replacements are done.
- */
-class ScalarReplacementVisitor extends TrampolineRecursiveVisitor {
- final InternalErrorFunction internalError;
- final World classWorld;
- ScalarReplacementRemovalVisitor removalVisitor;
-
- Primitive _current = null;
- Set<Primitive> _allocations = new Set<Primitive>();
- Queue<Primitive> _queue = new Queue<Primitive>();
-
- ScalarReplacementVisitor(this.internalError, this.classWorld) {
- removalVisitor = new ScalarReplacementRemovalVisitor(this);
- }
-
- void analyze(FunctionDefinition root) {
- visit(root);
- }
-
- void process() {
- while (_queue.isNotEmpty) {
- Primitive allocation = _queue.removeFirst();
- _allocations.remove(allocation);
- _current = allocation;
- tryScalarReplacement(allocation);
- }
- }
-
- void tryScalarReplacement(Primitive allocation) {
- // We can do scalar replacement of an aggregate if all uses of an allocation
- // are reads or writes.
- for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
- Node use = ref.parent;
- if (use is GetField) continue;
- if (use is SetField && use.objectRef == ref) continue;
- return;
- }
-
- Set<FieldElement> reads = new Set<FieldElement>();
- Set<FieldElement> writes = new Set<FieldElement>();
- for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
- Node use = ref.parent;
- if (use is GetField) {
- reads.add(use.field);
- } else if (use is SetField) {
- writes.add(use.field);
- } else {
- assert(false);
- }
- }
-
- // Find the initial values of the fields. A CreateBox has no initial
- // values. CreateInstance has initial values in the order of the fields.
- Map<FieldElement, Primitive> fieldInitialValues =
- <FieldElement, Primitive>{};
- if (allocation is CreateInstance) {
- int i = 0;
- allocation.classElement.forEachInstanceField(
- (ClassElement enclosingClass, FieldElement field) {
- Primitive argument = allocation.argument(i++);
- fieldInitialValues[field] = argument;
- }, includeSuperAndInjectedMembers: true);
- }
-
- // Create [MutableVariable]s for each written field. Initialize the
- // MutableVariable with the value from the allocator, or initialize with a
- // `null` constant if there is not initial value.
- Map<FieldElement, MutableVariable> cells =
- <FieldElement, MutableVariable>{};
- InteriorNode insertionPoint = allocation.parent; // LetPrim
- for (FieldElement field in writes) {
- MutableVariable variable = new MutableVariable(field);
- variable.type = new TypeMask.nonNullEmpty();
- cells[field] = variable;
- Primitive initialValue = fieldInitialValues[field];
- if (initialValue == null) {
- assert(allocation is CreateBox);
- initialValue = new Constant(new NullConstantValue());
- LetPrim let = new LetPrim(initialValue);
- let.primitive.parent = let;
- insertionPoint = let..insertBelow(insertionPoint);
- }
- LetMutable let = new LetMutable(variable, initialValue);
- let.valueRef.parent = let;
- insertionPoint = let..insertBelow(insertionPoint);
- }
-
- // Replace references with MutableVariable operations or references to the
- // field's value.
- for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
- Node use = ref.parent;
- if (use is GetField) {
- GetField getField = use;
- MutableVariable variable = cells[getField.field];
- if (variable != null) {
- GetMutable getter = new GetMutable(variable);
- getter.type = getField.type;
- getter.variableRef.parent = getter;
- getField.replaceUsesWith(getter);
- replacePrimitive(getField, getter);
- deletePrimitive(getField);
- } else {
- Primitive value = fieldInitialValues[getField.field];
- getField.replaceUsesWith(value);
- deleteLetPrimOf(getField);
- }
- } else if (use is SetField && use.objectRef == ref) {
- SetField setField = use;
- MutableVariable variable = cells[setField.field];
- Primitive value = setField.value;
- variable.type = variable.type.union(value.type, classWorld);
- SetMutable setter = new SetMutable(variable, value);
- setter.variableRef.parent = setter;
- setter.valueRef.parent = setter;
- setField.replaceUsesWith(setter);
- replacePrimitive(setField, setter);
- deletePrimitive(setField);
- } else {
- assert(false);
- }
- }
-
- // Delete [allocation] since that might 'free' another scalar replacement
- // candidate by deleting the last non-field-access.
- deleteLetPrimOf(allocation);
- }
-
- /// Replaces [old] with [primitive] in [old]'s parent [LetPrim].
- void replacePrimitive(Primitive old, Primitive primitive) {
- LetPrim letPrim = old.parent;
- letPrim.primitive = primitive;
- primitive.parent = letPrim;
- }
-
- void deleteLetPrimOf(Primitive primitive) {
- assert(primitive.hasNoUses);
- LetPrim letPrim = primitive.parent;
- letPrim.remove();
- deletePrimitive(primitive);
- }
-
- void deletePrimitive(Primitive primitive) {
- assert(primitive.hasNoUses);
- removalVisitor.visit(primitive);
- }
-
- void reconsider(Definition node) {
- if (node is CreateInstance || node is CreateBox) {
- if (node == _current) return;
- enqueue(node);
- }
- }
-
- void enqueue(Primitive node) {
- assert(node is CreateInstance || node is CreateBox);
- if (_allocations.contains(node)) return;
- _allocations.add(node);
- _queue.add(node);
- }
-
- // -------------------------- Visitor overrides ------------------------------
- void visitCreateInstance(CreateInstance node) {
- enqueue(node);
- }
-
- void visitCreateBox(CreateBox node) {
- enqueue(node);
- }
-}
-
-/// Visit a just-deleted subterm and unlink all [Reference]s in it. Reconsider
-/// allocations for scalar replacement.
-class ScalarReplacementRemovalVisitor extends TrampolineRecursiveVisitor {
- ScalarReplacementVisitor process;
-
- ScalarReplacementRemovalVisitor(this.process);
-
- processReference(Reference reference) {
- process.reconsider(reference.definition);
- reference.unlink();
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
deleted file mode 100644
index 3e3fd94..0000000
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ /dev/null
@@ -1,712 +0,0 @@
-// 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 dart2js.cps_ir.shrinking_reductions;
-
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart';
-
-/**
- * [ShrinkingReducer] applies shrinking reductions to CPS terms as described
- * in 'Compiling with Continuations, Continued' by Andrew Kennedy.
- */
-class ShrinkingReducer extends Pass {
- String get passName => 'Shrinking reductions';
-
- final List<_ReductionTask> _worklist = new List<_ReductionTask>();
-
- /// Applies shrinking reductions to root, mutating root in the process.
- @override
- void rewrite(FunctionDefinition root) {
- _RedexVisitor redexVisitor = new _RedexVisitor(_worklist);
-
- // Sweep over the term, collecting redexes into the worklist.
- redexVisitor.visit(root);
-
- _iterateWorklist();
- }
-
- void _iterateWorklist() {
- while (_worklist.isNotEmpty) {
- _ReductionTask task = _worklist.removeLast();
- _processTask(task);
- }
- }
-
- /// Call instead of [_iterateWorklist] to check at every step that no
- /// redex was missed.
- void _debugWorklist(FunctionDefinition root) {
- while (_worklist.isNotEmpty) {
- _ReductionTask task = _worklist.removeLast();
- String irBefore =
- root.debugString({task.node: '${task.kind} applied here'});
- _processTask(task);
- Set seenRedexes = _worklist.where(isValidTask).toSet();
- Set actualRedexes = (new _RedexVisitor([])..visit(root)).worklist.toSet();
- if (!seenRedexes.containsAll(actualRedexes)) {
- _ReductionTask missedTask =
- actualRedexes.firstWhere((x) => !seenRedexes.contains(x));
- print('\nBEFORE $task:\n');
- print(irBefore);
- print('\nAFTER $task:\n');
- root.debugPrint({missedTask.node: 'MISSED ${missedTask.kind}'});
- throw 'Missed $missedTask after processing $task';
- }
- }
- }
-
- bool isValidTask(_ReductionTask task) {
- switch (task.kind) {
- case _ReductionKind.DEAD_VAL:
- return _isDeadVal(task.node);
- case _ReductionKind.DEAD_CONT:
- return _isDeadCont(task.node);
- case _ReductionKind.BETA_CONT_LIN:
- return _isBetaContLin(task.node);
- case _ReductionKind.ETA_CONT:
- return _isEtaCont(task.node);
- case _ReductionKind.DEAD_PARAMETER:
- return _isDeadParameter(task.node);
- case _ReductionKind.BRANCH:
- return _isBranchRedex(task.node);
- }
- }
-
- /// Removes the given node from the CPS graph, replacing it with its body
- /// and marking it as deleted. The node's parent must be a [[InteriorNode]].
- void _removeNode(InteriorNode node) {
- Node body = node.body;
- InteriorNode parent = node.parent;
- assert(parent.body == node);
-
- body.parent = parent;
- parent.body = body;
- node.parent = null;
-
- // The removed node could be the last node between a continuation and
- // an InvokeContinuation in the body.
- if (parent is Continuation) {
- _checkEtaCont(parent);
- _checkUselessBranchTarget(parent);
- }
- }
-
- /// Remove a given continuation from the CPS graph. The LetCont itself is
- /// removed if the given continuation is the only binding.
- void _removeContinuation(Continuation cont) {
- LetCont parent = cont.parent;
- if (parent.continuations.length == 1) {
- _removeNode(parent);
- } else {
- parent.continuations.remove(cont);
- }
- cont.parent = null;
- }
-
- void _processTask(_ReductionTask task) {
- // Skip tasks for deleted nodes.
- if (task.node.parent == null) {
- return;
- }
-
- switch (task.kind) {
- case _ReductionKind.DEAD_VAL:
- _reduceDeadVal(task);
- break;
- case _ReductionKind.DEAD_CONT:
- _reduceDeadCont(task);
- break;
- case _ReductionKind.BETA_CONT_LIN:
- _reduceBetaContLin(task);
- break;
- case _ReductionKind.ETA_CONT:
- _reduceEtaCont(task);
- break;
- case _ReductionKind.DEAD_PARAMETER:
- _reduceDeadParameter(task);
- break;
- case _ReductionKind.BRANCH:
- _reduceBranch(task);
- break;
- }
- }
-
- /// Applies the dead-val reduction:
- /// letprim x = V in E -> E (x not free in E).
- void _reduceDeadVal(_ReductionTask task) {
- if (_isRemoved(task.node)) return;
- assert(_isDeadVal(task.node));
-
- LetPrim deadLet = task.node;
- Primitive deadPrim = deadLet.primitive;
- assert(deadPrim.hasNoRefinedUses);
- // The node has no effective uses but can have refinement uses, which
- // themselves can have more refinements uses (but only refinement uses).
- // We must remove the entire refinement tree while looking for redexes
- // whenever we remove one.
- List<Primitive> deadlist = <Primitive>[deadPrim];
- while (deadlist.isNotEmpty) {
- Primitive node = deadlist.removeLast();
- while (node.firstRef != null) {
- Reference ref = node.firstRef;
- Refinement use = ref.parent;
- deadlist.add(use);
- ref.unlink();
- }
- LetPrim binding = node.parent;
- _removeNode(binding); // Remove the binding and check for eta redexes.
- }
-
- // Perform bookkeeping on removed body and scan for new redexes.
- new _RemovalVisitor(_worklist).visit(deadPrim);
- }
-
- /// Applies the dead-cont reduction:
- /// letcont k x = E0 in E1 -> E1 (k not free in E1).
- void _reduceDeadCont(_ReductionTask task) {
- assert(_isDeadCont(task.node));
-
- // Remove dead continuation.
- Continuation cont = task.node;
- _removeContinuation(cont);
-
- // Perform bookkeeping on removed body and scan for new redexes.
- new _RemovalVisitor(_worklist).visit(cont);
- }
-
- /// Applies the beta-cont-lin reduction:
- /// letcont k x = E0 in E1[k y] -> E1[E0[y/x]] (k not free in E1).
- void _reduceBetaContLin(_ReductionTask task) {
- // Might have been mutated, recheck if reduction is still valid.
- // In the following example, the beta-cont-lin reduction of k0 could have
- // been invalidated by removal of the dead continuation k1:
- //
- // letcont k0 x0 = E0 in
- // letcont k1 x1 = k0 x1 in
- // return x2
- if (!_isBetaContLin(task.node)) {
- return;
- }
-
- Continuation cont = task.node;
- InvokeContinuation invoke = cont.firstRef.parent;
- InteriorNode invokeParent = invoke.parent;
- Expression body = cont.body;
-
- // Replace the invocation with the continuation body.
- invokeParent.body = body;
- body.parent = invokeParent;
- cont.body = null;
-
- // Substitute the invocation argument for the continuation parameter.
- for (int i = 0; i < invoke.argumentRefs.length; i++) {
- Parameter param = cont.parameters[i];
- Primitive argument = invoke.argument(i);
- param.replaceUsesWith(argument);
- argument.useElementAsHint(param.hint);
- _checkConstantBranchCondition(argument);
- }
-
- // Remove the continuation after inlining it so we can check for eta redexes
- // which may arise after removing the LetCont.
- _removeContinuation(cont);
-
- // Perform bookkeeping on substituted body and scan for new redexes.
- new _RemovalVisitor(_worklist).visit(invoke);
-
- if (invokeParent is Continuation) {
- _checkEtaCont(invokeParent);
- _checkUselessBranchTarget(invokeParent);
- }
- }
-
- /// Applies the eta-cont reduction:
- /// letcont k x = j x in E -> E[j/k].
- /// If k is unused, degenerates to dead-cont.
- void _reduceEtaCont(_ReductionTask task) {
- // Might have been mutated, recheck if reduction is still valid.
- // In the following example, the eta-cont reduction of k1 could have been
- // invalidated by an earlier beta-cont-lin reduction of k0.
- //
- // letcont k0 x0 = E0 in
- // letcont k1 x1 = k0 x1 in E1
- if (!_isEtaCont(task.node)) {
- return;
- }
-
- // Remove the continuation.
- Continuation cont = task.node;
- _removeContinuation(cont);
-
- InvokeContinuation invoke = cont.body;
- Continuation wrappedCont = invoke.continuation;
-
- for (int i = 0; i < cont.parameters.length; ++i) {
- wrappedCont.parameters[i].useElementAsHint(cont.parameters[i].hint);
- }
-
- // If the invocation of wrappedCont is escaping, then all invocations of
- // cont will be as well, after the reduction.
- if (invoke.isEscapingTry) {
- Reference current = cont.firstRef;
- while (current != null) {
- InvokeContinuation owner = current.parent;
- owner.isEscapingTry = true;
- current = current.next;
- }
- }
-
- // Replace all occurrences with the wrapped continuation and find redexes.
- while (cont.firstRef != null) {
- Reference ref = cont.firstRef;
- ref.changeTo(wrappedCont);
- Node use = ref.parent;
- if (use is InvokeContinuation && use.parent is Continuation) {
- _checkUselessBranchTarget(use.parent);
- }
- }
-
- // Perform bookkeeping on removed body and scan for new redexes.
- new _RemovalVisitor(_worklist).visit(cont);
- }
-
- void _reduceBranch(_ReductionTask task) {
- Branch branch = task.node;
- // Replace Branch with InvokeContinuation of one of the targets. When the
- // 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;
- if (condition is Constant) {
- target = isTruthyConstant(condition.value, strict: branch.isStrictCheck)
- ? branch.trueContinuation
- : branch.falseContinuation;
- } else if (_isBranchTargetOfUselessIf(branch.trueContinuation)) {
- target = branch.trueContinuation;
- } else {
- return;
- }
-
- InvokeContinuation invoke = new InvokeContinuation(target, <Primitive>[]
- // TODO(sra): Add sourceInformation.
- /*, sourceInformation: branch.sourceInformation*/);
- branch.parent.body = invoke;
- invoke.parent = branch.parent;
- branch.parent = null;
-
- new _RemovalVisitor(_worklist).visit(branch);
- }
-
- void _reduceDeadParameter(_ReductionTask task) {
- // Continuation eta-reduction can destroy a dead parameter redex. For
- // example, in the term:
- //
- // let cont k0(v0) = /* v0 is not used */ in
- // let cont k1(v1) = k0(v1) in
- // call foo () k1
- //
- // Continuation eta-reduction of k1 gives:
- //
- // let cont k0(v0) = /* v0 is not used */ in
- // call foo () k0
- //
- // Where the dead parameter reduction is no longer valid because we do not
- // allow removing the paramter of call continuations. We disallow such eta
- // reductions in [_isEtaCont].
- Parameter parameter = task.node;
- if (_isParameterRemoved(parameter)) return;
- assert(_isDeadParameter(parameter));
-
- Continuation continuation = parameter.parent;
- int index = continuation.parameters.indexOf(parameter);
- assert(index != -1);
- continuation.parameters.removeAt(index);
- parameter.parent = null; // Mark as removed.
-
- // 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.argumentRefs[index];
- argument.unlink();
- 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);
- if (invoke.parent is Continuation) {
- _checkEtaCont(invoke.parent);
- _checkUselessBranchTarget(invoke.parent);
- }
- }
-
- // Removing an unused parameter can create an eta-redex, in case the
- // body is an InvokeContinuation that now has matching arguments.
- _checkEtaCont(continuation);
- }
-
- void _checkEtaCont(Continuation continuation) {
- if (_isEtaCont(continuation)) {
- _worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, continuation));
- }
- }
-
- void _checkUselessBranchTarget(Continuation continuation) {
- if (_isBranchTargetOfUselessIf(continuation)) {
- _worklist.add(new _ReductionTask(
- _ReductionKind.BRANCH, continuation.firstRef.parent));
- }
- }
-
- void _checkConstantBranchCondition(Primitive primitive) {
- if (primitive is! Constant) return;
- for (Reference ref = primitive.firstRef; ref != null; ref = ref.next) {
- Node use = ref.parent;
- if (use is Branch) {
- _worklist.add(new _ReductionTask(_ReductionKind.BRANCH, use));
- }
- }
- }
-
- void _checkDeadPrimitive(Primitive primitive) {
- primitive = primitive.unrefined;
- if (primitive is Parameter) {
- if (_isDeadParameter(primitive)) {
- _worklist
- .add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER, primitive));
- }
- } else if (primitive.parent is LetPrim) {
- LetPrim letPrim = primitive.parent;
- if (_isDeadVal(letPrim)) {
- _worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, letPrim));
- }
- }
- }
-}
-
-bool _isRemoved(InteriorNode node) {
- return node.parent == null;
-}
-
-bool _isParameterRemoved(Parameter parameter) {
- // A parameter can be removed directly or because its continuation is removed.
- return parameter.parent == null || _isRemoved(parameter.parent);
-}
-
-/// Returns true iff the bound primitive is unused, and has no effects
-/// preventing it from being eliminated.
-bool _isDeadVal(LetPrim node) {
- return !_isRemoved(node) &&
- node.primitive.hasNoRefinedUses &&
- node.primitive.isSafeForElimination;
-}
-
-/// Returns true iff the continuation is unused.
-bool _isDeadCont(Continuation cont) {
- return !_isRemoved(cont) &&
- !cont.isReturnContinuation &&
- !cont.hasAtLeastOneUse;
-}
-
-/// Returns true iff the continuation has a body (i.e., it is not the return
-/// continuation), it is used exactly once, and that use is as the continuation
-/// of a continuation invocation.
-bool _isBetaContLin(Continuation cont) {
- if (_isRemoved(cont)) return false;
-
- // There is a restriction on continuation eta-redexes that the body is not an
- // invocation of the return continuation, because that leads to worse code
- // when translating back to direct style (it duplicates returns). There is no
- // such restriction here because continuation beta-reduction is only performed
- // for singly referenced continuations. Thus, there is no possibility of code
- // duplication.
- if (cont.isReturnContinuation || !cont.hasExactlyOneUse) {
- return false;
- }
-
- if (cont.firstRef.parent is! InvokeContinuation) return false;
-
- InvokeContinuation invoke = cont.firstRef.parent;
-
- // Beta-reduction will move the continuation's body to its unique invocation
- // site. This is not safe if the body is moved into an exception handler
- // binding.
- if (invoke.isEscapingTry) return false;
-
- return true;
-}
-
-/// Returns true iff the continuation consists of a continuation
-/// invocation, passing on all parameters. Special cases exist (see below).
-bool _isEtaCont(Continuation cont) {
- if (_isRemoved(cont)) return false;
-
- if (!cont.isJoinContinuation || cont.body is! InvokeContinuation) {
- return false;
- }
-
- InvokeContinuation invoke = cont.body;
- 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).
- if (invokedCont.isReturnContinuation) {
- return false;
- }
-
- // Translation to direct style generates different statements for recursive
- // and non-recursive invokes. It should still be possible to apply eta-cont if
- // this is not a self-invocation.
- //
- // TODO(kmillikin): Remove this restriction if it makes sense to do so.
- if (invoke.isRecursive) {
- return false;
- }
-
- // If cont has more parameters than the invocation has arguments, the extra
- // parameters will be dead and dead-parameter will eventually create the
- // eta-redex if possible.
- //
- // If the invocation's arguments are simply a permutation of cont's
- // parameters, then there is likewise a possible reduction that involves
- // rewriting the invocations of cont. We are missing that reduction here.
- //
- // If cont has fewer parameters than the invocation has arguments then a
- // reduction would still possible, since the extra invocation arguments must
- // be in scope at all the invocations of cont. For example:
- //
- // let cont k1(x1) = k0(x0, x1) in E -eta-> E'
- // where E' has k0(x0, v) substituted for each k1(v).
- //
- // HOWEVER, adding continuation parameters is unlikely to be an optimization
- // since it duplicates assignments used in direct-style to implement parameter
- // passing.
- //
- // TODO(kmillikin): find real occurrences of these patterns, and see if they
- // can be optimized.
- 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.argument(i) != cont.parameters[i]) {
- return false;
- }
- }
-
- return true;
-}
-
-Expression _unfoldDeadRefinements(Expression node) {
- while (node is LetPrim) {
- LetPrim let = node;
- Primitive prim = let.primitive;
- if (prim.hasAtLeastOneUse || prim is! Refinement) return node;
- node = node.next;
- }
- return node;
-}
-
-bool _isBranchRedex(Branch branch) {
- return _isUselessIf(branch) || branch.condition is Constant;
-}
-
-bool _isBranchTargetOfUselessIf(Continuation cont) {
- // A useless-if has an empty then and else branch, e.g. `if (cond);`.
- //
- // Detect T or F in
- //
- // let cont Join() = ...
- // in let cont T() = Join()
- // F() = Join()
- // in branch condition T F
- //
- if (!cont.hasExactlyOneUse) return false;
- Node use = cont.firstRef.parent;
- if (use is! Branch) return false;
- return _isUselessIf(use);
-}
-
-bool _isUselessIf(Branch branch) {
- Continuation trueCont = branch.trueContinuation;
- Expression trueBody = _unfoldDeadRefinements(trueCont.body);
- if (trueBody is! InvokeContinuation) return false;
- Continuation falseCont = branch.falseContinuation;
- Expression falseBody = _unfoldDeadRefinements(falseCont.body);
- if (falseBody is! InvokeContinuation) return false;
- InvokeContinuation trueInvoke = trueBody;
- InvokeContinuation falseInvoke = falseBody;
- if (trueInvoke.continuation != falseInvoke.continuation) {
- return false;
- }
- // Matching zero arguments should be adequate, since isomorphic true and false
- // invocations should result in redundant phis which are removed elsewhere.
- //
- // Note that the argument lists are not necessarily the same length here,
- // because we could be looking for new redexes in the middle of performing a
- // 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.argumentRefs.isEmpty && falseInvoke.argumentRefs.isEmpty;
-}
-
-bool _isDeadParameter(Parameter parameter) {
- if (_isParameterRemoved(parameter)) return false;
-
- // We cannot remove function parameters as an intraprocedural optimization.
- if (parameter.parent is! Continuation || parameter.hasAtLeastOneUse) {
- return false;
- }
-
- // We cannot remove the parameter to a call continuation, because the
- // resulting expression will not be well-formed (call continuations have
- // exactly one argument). The return continuation is a call continuation, so
- // we cannot remove its dummy parameter.
- Continuation continuation = parameter.parent;
- if (!continuation.isJoinContinuation) return false;
-
- return true;
-}
-
-/// Traverses a term and adds any found redexes to the worklist.
-class _RedexVisitor extends TrampolineRecursiveVisitor {
- final List<_ReductionTask> worklist;
-
- _RedexVisitor(this.worklist);
-
- void processLetPrim(LetPrim node) {
- if (_isDeadVal(node)) {
- worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node));
- }
- }
-
- void processBranch(Branch node) {
- if (_isBranchRedex(node)) {
- worklist.add(new _ReductionTask(_ReductionKind.BRANCH, node));
- }
- }
-
- void processContinuation(Continuation node) {
- // While it would be nice to remove exception handlers that are provably
- // unnecessary (e.g., the body cannot throw), that takes more sophisticated
- // analysis than we do in this pass.
- if (node.parent is LetHandler) return;
-
- // Continuation beta- and eta-redexes can overlap, namely when an eta-redex
- // is invoked exactly once. We prioritize continuation beta-redexes over
- // eta-redexes because some reductions (e.g., dead parameter elimination)
- // can destroy a continuation eta-redex. If we prioritized eta- over
- // beta-redexes, this would implicitly "create" the corresponding beta-redex
- // (in the sense that it would still apply) and the algorithm would not
- // detect it.
- if (_isDeadCont(node)) {
- worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, node));
- } else if (_isBetaContLin(node)) {
- worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, node));
- } else if (_isEtaCont(node)) {
- worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, node));
- }
- }
-
- void processParameter(Parameter node) {
- if (_isDeadParameter(node)) {
- worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER, node));
- }
- }
-}
-
-/// Traverses a deleted CPS term, marking nodes that might participate in a
-/// redex as deleted and adding newly created redexes to the worklist.
-///
-/// Deleted nodes that might participate in a reduction task are marked so that
-/// any corresponding tasks can be skipped. Nodes are marked so by setting
-/// their parent to the deleted sentinel.
-class _RemovalVisitor extends TrampolineRecursiveVisitor {
- final List<_ReductionTask> worklist;
-
- _RemovalVisitor(this.worklist);
-
- void processLetPrim(LetPrim node) {
- node.parent = null;
- }
-
- void processContinuation(Continuation node) {
- node.parent = null;
- }
-
- void processBranch(Branch node) {
- node.parent = null;
- }
-
- void processReference(Reference reference) {
- reference.unlink();
-
- if (reference.definition is Primitive) {
- Primitive primitive = reference.definition.unrefined;
- Node parent = primitive.parent;
- // The parent might be the deleted sentinel, or it might be a
- // Continuation or FunctionDefinition if the primitive is an argument.
- if (parent is LetPrim && _isDeadVal(parent)) {
- worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent));
- } else if (primitive is Parameter && _isDeadParameter(primitive)) {
- worklist
- .add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER, primitive));
- }
- } else if (reference.definition is Continuation) {
- Continuation cont = reference.definition;
- Node parent = cont.parent;
- // The parent might be the deleted sentinel, or it might be a
- // Body if the continuation is the return continuation.
- if (parent is LetCont) {
- if (cont.isRecursive && cont.hasAtMostOneUse) {
- // Convert recursive to nonrecursive continuations. If the
- // continuation is still in use, it is either dead and will be
- // removed, or it is called nonrecursively outside its body.
- cont.isRecursive = false;
- }
- if (_isDeadCont(cont)) {
- worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont));
- } else if (_isBetaContLin(cont)) {
- worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, cont));
- } else if (_isBranchTargetOfUselessIf(cont)) {
- worklist.add(
- new _ReductionTask(_ReductionKind.BRANCH, cont.firstRef.parent));
- }
- }
- }
- }
-}
-
-enum _ReductionKind {
- DEAD_VAL,
- DEAD_CONT,
- BETA_CONT_LIN,
- ETA_CONT,
- DEAD_PARAMETER,
- BRANCH
-}
-
-/// Represents a reduction task on the worklist. Implements both hashCode and
-/// operator== since instantiations are used as Set elements.
-class _ReductionTask {
- final _ReductionKind kind;
- final Node node;
-
- int get hashCode {
- return (node.hashCode << 3) | kind.index;
- }
-
- _ReductionTask(this.kind, this.node) {
- assert(node is Continuation ||
- node is LetPrim ||
- node is Parameter ||
- node is Branch);
- }
-
- bool operator ==(_ReductionTask that) {
- return (that.kind == this.kind && that.node == this.node);
- }
-
- String toString() => "$kind: $node";
-}
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
deleted file mode 100644
index a2bb010..0000000
--- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
+++ /dev/null
@@ -1,615 +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 dart2js.type_mask_system;
-
-import '../closure.dart' show ClosureFieldElement, BoxLocal, TypeVariableLocal;
-import '../common/names.dart' show Identifiers;
-import '../compiler.dart' as dart2js show Compiler;
-import '../constants/values.dart';
-import '../dart_types.dart' as types;
-import '../elements/elements.dart';
-import '../js_backend/backend_helpers.dart' show BackendHelpers;
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import '../types/abstract_value_domain.dart';
-import '../types/constants.dart' show computeTypeMask;
-import '../types/types.dart';
-import '../universe/selector.dart' show Selector;
-import '../world.dart' show World;
-
-class TypeMaskSystem implements AbstractValueDomain {
- final TypesTask inferrer;
- final World classWorld;
- final JavaScriptBackend backend;
-
- TypeMask _numStringBoolType;
- TypeMask _fixedLengthType;
- TypeMask _interceptorType;
- TypeMask _interceptedTypes; // Does not include null.
-
- TypeMask __indexableTypeTest;
-
- // The full type of a constant (e.g. a ContainerTypeMask) is not available on
- // the constant. Type inference flows the type to some place where it is used,
- // e.g. a parameter. For constant values that are the value of static const
- // fields we need to remember the association.
- final Map<ConstantValue, TypeMask> _constantMasks =
- <ConstantValue, TypeMask>{};
-
- @override
- TypeMask get dynamicType => inferrer.dynamicType;
-
- @override
- TypeMask get typeType => inferrer.typeType;
-
- @override
- TypeMask get functionType => inferrer.functionType;
-
- @override
- TypeMask get boolType => inferrer.boolType;
-
- @override
- TypeMask get intType => inferrer.intType;
-
- @override
- TypeMask get doubleType => inferrer.doubleType;
-
- @override
- TypeMask get numType => inferrer.numType;
-
- @override
- TypeMask get stringType => inferrer.stringType;
-
- @override
- TypeMask get listType => inferrer.listType;
-
- @override
- TypeMask get mapType => inferrer.mapType;
-
- @override
- TypeMask get nonNullType => inferrer.nonNullType;
-
- @override
- TypeMask get nullType => inferrer.nullType;
-
- @override
- TypeMask get extendableArrayType => backend.extendableArrayType;
-
- @override
- TypeMask get fixedArrayType => backend.fixedArrayType;
-
- @override
- TypeMask get arrayType =>
- new TypeMask.nonNullSubclass(helpers.jsArrayClass, classWorld);
-
- @override
- TypeMask get uint31Type => inferrer.uint31Type;
-
- @override
- TypeMask get uint32Type => inferrer.uint32Type;
-
- @override
- TypeMask get uintType => inferrer.positiveIntType;
-
- @override
- TypeMask get numStringBoolType {
- if (_numStringBoolType == null) {
- // Build the number+string+bool type. To make containment tests more
- // inclusive, we use the num, String, bool types for this, not
- // the JSNumber, JSString, JSBool subclasses.
- TypeMask anyNum =
- new TypeMask.nonNullSubtype(classWorld.numClass, classWorld);
- TypeMask anyString =
- new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld);
- TypeMask anyBool =
- new TypeMask.nonNullSubtype(classWorld.boolClass, classWorld);
- _numStringBoolType = new TypeMask.unionOf(
- <TypeMask>[anyNum, anyString, anyBool], classWorld);
- }
- return _numStringBoolType;
- }
-
- @override
- TypeMask get fixedLengthType {
- if (_fixedLengthType == null) {
- List<TypeMask> fixedLengthTypes = <TypeMask>[
- stringType,
- backend.fixedArrayType
- ];
- if (classWorld.isInstantiated(helpers.typedArrayClass)) {
- fixedLengthTypes.add(nonNullSubclass(helpers.typedArrayClass));
- }
- _fixedLengthType = new TypeMask.unionOf(fixedLengthTypes, classWorld);
- }
- return _fixedLengthType;
- }
-
- @override
- TypeMask get interceptorType {
- if (_interceptorType == null) {
- _interceptorType =
- new TypeMask.nonNullSubtype(helpers.jsInterceptorClass, classWorld);
- }
- return _interceptorType;
- }
-
- @override
- TypeMask get interceptedTypes {
- // Does not include null.
- if (_interceptedTypes == null) {
- // We redundantly include subtypes of num/string/bool as intercepted
- // types, because the type system does not infer that their
- // implementations are all subclasses of Interceptor.
- _interceptedTypes = new TypeMask.unionOf(
- <TypeMask>[interceptorType, numStringBoolType], classWorld);
- }
- return _interceptedTypes;
- }
-
- TypeMask get _indexableTypeTest {
- if (__indexableTypeTest == null) {
- // Make a TypeMask containing Indexable and (redundantly) subtypes of
- // string because the type inference does not infer that all strings are
- // indexables.
- TypeMask indexable =
- new TypeMask.nonNullSubtype(helpers.jsIndexableClass, classWorld);
- TypeMask anyString =
- new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld);
- __indexableTypeTest =
- new TypeMask.unionOf(<TypeMask>[indexable, anyString], classWorld);
- }
- return __indexableTypeTest;
- }
-
- ClassElement get jsNullClass => helpers.jsNullClass;
-
- BackendHelpers get helpers => backend.helpers;
-
- // TODO(karlklose): remove compiler here.
- TypeMaskSystem(dart2js.Compiler compiler)
- : inferrer = compiler.typesTask,
- classWorld = compiler.world,
- backend = compiler.backend {}
-
- @override
- bool methodIgnoresReceiverArgument(FunctionElement function) {
- assert(backend.isInterceptedMethod(function));
- ClassElement clazz = function.enclosingClass.declaration;
- return !clazz.isSubclassOf(helpers.jsInterceptorClass) &&
- !classWorld.isUsedAsMixin(clazz);
- }
-
- @override
- bool targetIgnoresReceiverArgument(TypeMask type, Selector selector) {
- // Check if any of the possible targets depend on the extra receiver
- // argument. Mixins do this, and tear-offs always needs the extra receiver
- // argument because BoundClosure uses it for equality and hash code.
- // TODO(15933): Make automatically generated property extraction
- // closures work with the dummy receiver optimization.
- bool needsReceiver(Element target) {
- if (target is! FunctionElement) return false;
- FunctionElement function = target;
- return selector.isGetter && !function.isGetter ||
- !methodIgnoresReceiverArgument(function);
- }
- return !classWorld.allFunctions.filter(selector, type).any(needsReceiver);
- }
-
- @override
- Element locateSingleElement(TypeMask mask, Selector selector) {
- return mask.locateSingleElement(selector, mask, classWorld.compiler);
- }
-
- @override
- ClassElement singleClass(TypeMask mask) {
- return mask.singleClass(classWorld);
- }
-
- @override
- bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) {
- return mask.needsNoSuchMethodHandling(selector, classWorld);
- }
-
- @override
- TypeMask getReceiverType(MethodElement method) {
- assert(method.isInstanceMember);
- if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) {
- // If used as a mixin, the receiver could be any of the classes that mix
- // in the class, and these are not considered subclasses.
- // TODO(asgerf): Exclude the subtypes that only `implement` the class.
- return nonNullSubtype(method.enclosingClass);
- } else {
- return nonNullSubclass(method.enclosingClass);
- }
- }
-
- @override
- TypeMask getParameterType(ParameterElement parameter) {
- return inferrer.getGuaranteedTypeOfElement(parameter);
- }
-
- @override
- TypeMask getReturnType(FunctionElement function) {
- return inferrer.getGuaranteedReturnTypeOfElement(function);
- }
-
- @override
- TypeMask getInvokeReturnType(Selector selector, TypeMask mask) {
- TypeMask result = inferrer.getGuaranteedTypeOfSelector(selector, mask);
- // Tearing off .call from a function returns the function itself.
- if (selector.isGetter &&
- selector.name == Identifiers.call &&
- !areDisjoint(functionType, mask)) {
- result = join(result, functionType);
- }
- return result;
- }
-
- @override
- TypeMask getFieldType(FieldElement field) {
- if (field is ClosureFieldElement) {
- // The type inference does not report types for all closure fields.
- // Box fields are never null.
- if (field.local is BoxLocal) return nonNullType;
- // Closure fields for type variables contain the internal representation
- // of the type (which can be null), not the Type object.
- if (field.local is TypeVariableLocal) return dynamicType;
- }
- return inferrer.getGuaranteedTypeOfElement(field);
- }
-
- @override
- TypeMask join(TypeMask a, TypeMask b) {
- return a.union(b, classWorld);
- }
-
- @override
- TypeMask intersection(TypeMask a, TypeMask b) {
- if (a == null) return b;
- if (b == null) return a;
- return a.intersection(b, classWorld);
- }
-
- void associateConstantValueWithElement(
- ConstantValue constant, Element element) {
- // TODO(25093): Replace this code with an approach that works for anonymous
- // constants and non-constant literals.
- if (constant is ListConstantValue || constant is MapConstantValue) {
- // Inferred type is usually better (e.g. a ContainerTypeMask) but is
- // occasionally less general.
- TypeMask computed = computeTypeMask(inferrer.compiler, constant);
- TypeMask inferred = inferrer.getGuaranteedTypeOfElement(element);
- TypeMask best = intersection(inferred, computed);
- assert(!best.isEmptyOrNull);
- _constantMasks[constant] = best;
- }
- }
-
- @override
- TypeMask getTypeOf(ConstantValue constant) {
- return _constantMasks[constant] ??
- computeTypeMask(inferrer.compiler, constant);
- }
-
- @override
- ConstantValue getConstantOf(TypeMask mask) {
- if (!mask.isValue) return null;
- if (mask.isNullable) return null; // e.g. 'true or null'.
- ValueTypeMask valueMask = mask;
- if (valueMask.value.isBool) return valueMask.value;
- // TODO(sra): Consider other values. Be careful with large strings.
- return null;
- }
-
- @override
- TypeMask nonNullExact(ClassElement element) {
- // TODO(johnniwinther): I don't think the follow is valid anymore.
- // The class world does not know about classes created by
- // closure conversion, so just treat those as a subtypes of Function.
- // TODO(asgerf): Maybe closure conversion should create a new ClassWorld?
- if (element.isClosure) return functionType;
- return new TypeMask.nonNullExact(element.declaration, classWorld);
- }
-
- @override
- TypeMask nonNullSubclass(ClassElement element) {
- if (element.isClosure) return functionType;
- return new TypeMask.nonNullSubclass(element.declaration, classWorld);
- }
-
- @override
- TypeMask nonNullSubtype(ClassElement element) {
- if (element.isClosure) return functionType;
- return new TypeMask.nonNullSubtype(element.declaration, classWorld);
- }
-
- @override
- bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t.nonNullable().containsOnlyBool(classWorld);
- }
-
- @override
- bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t.nonNullable().containsOnlyNum(classWorld);
- }
-
- @override
- bool isDefinitelyString(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t.nonNullable().containsOnlyString(classWorld);
- }
-
- @override
- bool isDefinitelyNumStringBool(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return numStringBoolType.containsMask(t.nonNullable(), classWorld);
- }
-
- @override
- bool isDefinitelyNotNumStringBool(TypeMask t) {
- return areDisjoint(t, numStringBoolType);
- }
-
- /// True if all values of [t] are either integers or not numbers at all.
- ///
- /// This does not imply that the value is an integer, since most other values
- /// such as null are also not a non-integer double.
- @override
- bool isDefinitelyNotNonIntegerDouble(TypeMask t) {
- // Even though int is a subclass of double in the JS type system, we can
- // still check this with disjointness, because [doubleType] is the *exact*
- // double class, so this excludes things that are known to be instances of a
- // more specific class.
- // We currently exploit that there are no subclasses of double that are
- // not integers (e.g. there is no UnsignedDouble class or whatever).
- return areDisjoint(t, doubleType);
- }
-
- @override
- bool isDefinitelyNonNegativeInt(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- // The JSPositiveInt class includes zero, despite the name.
- return t.satisfies(helpers.jsPositiveIntClass, classWorld);
- }
-
- @override
- bool isDefinitelyInt(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t.nonNullable().containsOnlyInt(classWorld);
- }
-
- @override
- bool isDefinitelyUint31(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t.satisfies(helpers.jsUInt31Class, classWorld);
- }
-
- @override
- bool isDefinitelyUint32(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t.satisfies(helpers.jsUInt32Class, classWorld);
- }
-
- @override
- bool isDefinitelyUint(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t.satisfies(helpers.jsPositiveIntClass, classWorld);
- }
-
- @override
- bool isDefinitelyArray(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t.nonNullable().satisfies(helpers.jsArrayClass, classWorld);
- }
-
- @override
- bool isDefinitelyMutableArray(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t.nonNullable().satisfies(helpers.jsMutableArrayClass, classWorld);
- }
-
- @override
- bool isDefinitelyFixedArray(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t.nonNullable().satisfies(helpers.jsFixedArrayClass, classWorld);
- }
-
- @override
- bool isDefinitelyExtendableArray(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t
- .nonNullable()
- .satisfies(helpers.jsExtendableArrayClass, classWorld);
- }
-
- @override
- bool isDefinitelyIndexable(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return _indexableTypeTest.containsMask(t.nonNullable(), classWorld);
- }
-
- @override
- bool isDefinitelyMutableIndexable(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return t
- .nonNullable()
- .satisfies(helpers.jsMutableIndexableClass, classWorld);
- }
-
- @override
- bool isDefinitelyFixedLengthIndexable(TypeMask t, {bool allowNull: false}) {
- if (!allowNull && t.isNullable) return false;
- return fixedLengthType.containsMask(t.nonNullable(), classWorld);
- }
-
- @override
- bool isDefinitelyIntercepted(TypeMask t, {bool allowNull}) {
- assert(allowNull != null);
- if (!allowNull && t.isNullable) return false;
- return interceptedTypes.containsMask(t.nonNullable(), classWorld);
- }
-
- @override
- bool isDefinitelySelfInterceptor(TypeMask t, {bool allowNull: false}) {
- assert(allowNull != null);
- if (!allowNull && t.isNullable) return false;
- return areDisjoint(t, interceptorType);
- }
-
- /// Given a class from the interceptor hierarchy, returns a [TypeMask]
- /// matching all values with that interceptor (or a subtype thereof).
- @override
- TypeMask getInterceptorSubtypes(ClassElement class_) {
- if (class_ == helpers.jsInterceptorClass) {
- return interceptorType.nullable();
- } else if (class_ == helpers.jsNullClass) {
- return nullType;
- } else {
- return nonNullSubclass(class_);
- }
- }
-
- @override
- bool areDisjoint(TypeMask leftType, TypeMask rightType) =>
- leftType.isDisjoint(rightType, classWorld);
-
- @override
- bool isMorePreciseOrEqual(TypeMask t1, TypeMask t2) {
- return t2.containsMask(t1, classWorld);
- }
-
- @override
- AbstractBool isSubtypeOf(TypeMask value, types.DartType type,
- {bool allowNull}) {
- assert(allowNull != null);
- if (type is types.DynamicType) {
- return AbstractBool.True;
- }
- if (type is types.InterfaceType) {
- TypeMask typeAsMask = allowNull
- ? new TypeMask.subtype(type.element, classWorld)
- : new TypeMask.nonNullSubtype(type.element, classWorld);
- if (areDisjoint(value, typeAsMask)) {
- // Disprove the subtype relation based on the class alone.
- return AbstractBool.False;
- }
- if (!type.treatAsRaw) {
- // If there are type arguments, we cannot prove the subtype relation,
- // because the type arguments are unknown on both the value and type.
- return AbstractBool.Maybe;
- }
- if (typeAsMask.containsMask(value, classWorld)) {
- // All possible values are contained in the set of allowed values.
- // Note that we exploit the fact that [typeAsMask] is an exact
- // representation of [type], not an approximation.
- return AbstractBool.True;
- }
- // The value is neither contained in the type, nor disjoint from the type.
- return AbstractBool.Maybe;
- }
- // TODO(asgerf): Support function types, and what else might be missing.
- return AbstractBool.Maybe;
- }
-
- /// Returns whether [type] is one of the falsy values: false, 0, -0, NaN,
- /// the empty string, or null.
- @override
- AbstractBool boolify(TypeMask type) {
- if (isDefinitelyNotNumStringBool(type) && !type.isNullable) {
- return AbstractBool.True;
- }
- return AbstractBool.Maybe;
- }
-
- @override
- AbstractBool strictBoolify(TypeMask type) {
- if (areDisjoint(type, boolType)) return AbstractBool.False;
- return AbstractBool.Maybe;
- }
-
- /// Create a type mask containing at least all subtypes of [type].
- @override
- TypeMask subtypesOf(types.DartType type) {
- if (type is types.InterfaceType) {
- ClassElement element = type.element;
- if (element.isObject) {
- return dynamicType;
- }
- if (element == classWorld.nullClass) {
- return nullType;
- }
- if (element == classWorld.stringClass) {
- return stringType;
- }
- if (element == classWorld.numClass || element == classWorld.doubleClass) {
- return numType;
- }
- if (element == classWorld.intClass) {
- return intType;
- }
- if (element == classWorld.boolClass) {
- return boolType;
- }
- return new TypeMask.nonNullSubtype(element, classWorld);
- }
- if (type is types.FunctionType) {
- return functionType;
- }
- return dynamicType;
- }
-
- /// Returns a subset of [mask] containing at least the types
- /// that can respond to [selector] without throwing.
- @override
- TypeMask receiverTypeFor(Selector selector, TypeMask mask) {
- return classWorld.allFunctions.receiverType(selector, mask);
- }
-
- /// The result of an index operation on something of [type], or the dynamic
- /// type if unknown.
- @override
- TypeMask elementTypeOfIndexable(TypeMask type) {
- if (type is UnionTypeMask) {
- return new TypeMask.unionOf(
- type.disjointMasks.map(elementTypeOfIndexable), classWorld);
- }
- if (type is ContainerTypeMask) {
- return type.elementType;
- }
- if (isDefinitelyString(type)) {
- return stringType;
- }
- if (type.satisfies(helpers.jsIndexingBehaviorInterface, classWorld)) {
- return getInvokeReturnType(new Selector.index(), type);
- }
- return dynamicType;
- }
-
- /// The length of something of [type], or `null` if unknown.
- @override
- int getContainerLength(TypeMask type) {
- if (type is ContainerTypeMask) {
- return type.length;
- } else {
- return null;
- }
- }
-
- /// Returns the type of the entry at a given index, `null` if unknown.
- TypeMask indexWithConstant(TypeMask container, ConstantValue indexValue) {
- if (container is DictionaryTypeMask) {
- if (indexValue is StringConstantValue) {
- String key = indexValue.primitiveValue.slowToString();
- TypeMask result = container.typeMap[key];
- if (result != null) return result;
- }
- }
- if (container is ContainerTypeMask) {
- return container.elementType;
- }
- return null;
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
deleted file mode 100644
index 75ede1f..0000000
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ /dev/null
@@ -1,3503 +0,0 @@
-// 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 dart2js.cps_ir.type_propagation;
-
-import '../closure.dart' show ClosureClassElement;
-import '../common.dart';
-import '../common/names.dart' show Identifiers, Selectors;
-import '../compiler.dart' as dart2js show Compiler;
-import '../constants/constant_system.dart';
-import '../constants/values.dart';
-import '../dart_types.dart' as types;
-import '../elements/elements.dart';
-import '../io/source_information.dart' show SourceInformation;
-import '../js_backend/backend_helpers.dart' show BackendHelpers;
-import '../js_backend/codegen/task.dart' show CpsFunctionCompiler;
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import '../resolution/operators.dart';
-import '../tree/tree.dart' as ast;
-import '../types/abstract_value_domain.dart' show AbstractBool;
-import '../types/types.dart';
-import '../universe/selector.dart' show Selector;
-import '../world.dart' show World;
-import 'cps_fragment.dart';
-import 'cps_ir_nodes.dart';
-import 'effects.dart';
-import 'optimizers.dart';
-import 'type_mask_system.dart';
-
-class ConstantPropagationLattice {
- final TypeMaskSystem typeSystem;
- final ConstantSystem constantSystem;
- final types.DartTypes dartTypes;
- final AbstractConstantValue anything;
- final AbstractConstantValue nothing = new AbstractConstantValue.nothing();
- final AbstractConstantValue nullValue;
- final AbstractConstantValue trueValue;
- final AbstractConstantValue falseValue;
-
- ConstantPropagationLattice(CpsFunctionCompiler functionCompiler)
- : typeSystem = functionCompiler.typeSystem,
- constantSystem = functionCompiler.compiler.backend.constantSystem,
- dartTypes = functionCompiler.compiler.types,
- anything = new AbstractConstantValue.nonConstant(
- functionCompiler.typeSystem.dynamicType),
- nullValue = new AbstractConstantValue.constantValue(
- new NullConstantValue(), new TypeMask.empty()),
- trueValue = new AbstractConstantValue.constantValue(
- new TrueConstantValue(), functionCompiler.typeSystem.boolType),
- falseValue = new AbstractConstantValue.constantValue(
- new FalseConstantValue(), functionCompiler.typeSystem.boolType);
-
- AbstractConstantValue constant(ConstantValue value, [TypeMask type]) {
- if (type == null) type = typeSystem.getTypeOf(value);
- return new AbstractConstantValue.constantValue(value, type);
- }
-
- AbstractConstantValue nonConstant([TypeMask type]) {
- if (type == null) type = typeSystem.dynamicType;
- return new AbstractConstantValue.nonConstant(type);
- }
-
- /// Compute the join of two values in the lattice.
- AbstractConstantValue join(AbstractConstantValue x, AbstractConstantValue y) {
- assert(x != null);
- assert(y != null);
-
- if (x.isNothing) {
- return y;
- } else if (y.isNothing) {
- return x;
- } else if (x.isConstant && y.isConstant && x.constant == y.constant) {
- return x;
- } else {
- return new AbstractConstantValue.nonConstant(
- typeSystem.join(x.type, y.type));
- }
- }
-
- /// True if all members of this value are booleans.
- bool isDefinitelyBool(AbstractConstantValue value, {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyBool(value.type, allowNull: allowNull);
- }
-
- /// True if all members of this value are numbers.
- bool isDefinitelyNum(AbstractConstantValue value, {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyNum(value.type, allowNull: allowNull);
- }
-
- /// True if all members of this value are strings.
- bool isDefinitelyString(AbstractConstantValue value,
- {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyString(value.type, allowNull: allowNull);
- }
-
- /// True if all members of this value are numbers, strings, or booleans.
- bool isDefinitelyNumStringBool(AbstractConstantValue value,
- {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyNumStringBool(value.type, allowNull: allowNull);
- }
-
- /// True if this value cannot be a string, number, or boolean.
- bool isDefinitelyNotNumStringBool(AbstractConstantValue value) {
- return value.isNothing ||
- typeSystem.isDefinitelyNotNumStringBool(value.type);
- }
-
- /// True if this value cannot be a non-integer double.
- ///
- /// In other words, if true is returned, and the value is a number, then
- /// it is a whole number and is not NaN, Infinity, or minus Infinity.
- bool isDefinitelyNotNonIntegerDouble(AbstractConstantValue value) {
- return value.isNothing ||
- value.isConstant && !value.constant.isDouble ||
- typeSystem.isDefinitelyNotNonIntegerDouble(value.type);
- }
-
- bool isDefinitelyInt(AbstractConstantValue value, {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyInt(value.type, allowNull: allowNull);
- }
-
- bool isDefinitelyUint31(AbstractConstantValue value,
- {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyUint31(value.type, allowNull: allowNull);
- }
-
- bool isDefinitelyUint32(AbstractConstantValue value,
- {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyUint32(value.type, allowNull: allowNull);
- }
-
- bool isDefinitelyUint(AbstractConstantValue value, {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyUint(value.type, allowNull: allowNull);
- }
-
- bool isDefinitelyArray(AbstractConstantValue value, {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyArray(value.type, allowNull: allowNull);
- }
-
- bool isDefinitelyMutableArray(AbstractConstantValue value,
- {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyMutableArray(value.type, allowNull: allowNull);
- }
-
- bool isDefinitelyFixedArray(AbstractConstantValue value,
- {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyFixedArray(value.type, allowNull: allowNull);
- }
-
- bool isDefinitelyExtendableArray(AbstractConstantValue value,
- {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyExtendableArray(value.type,
- allowNull: allowNull);
- }
-
- bool isDefinitelyIndexable(AbstractConstantValue value,
- {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyIndexable(value.type, allowNull: allowNull);
- }
-
- /// Returns `true` if [value] represents an int value that must be in the
- /// inclusive range.
- bool isDefinitelyIntInRange(AbstractConstantValue value, {int min, int max}) {
- if (value.isNothing) return true;
- if (!isDefinitelyInt(value)) return false;
- PrimitiveConstantValue constant = value.constant;
- if (constant == null) return false;
- if (!constant.isInt) return false;
- if (min != null && constant.primitiveValue < min) return false;
- if (max != null && constant.primitiveValue > max) return false;
- return true;
- }
-
- /// Returns whether the given [value] is an instance of [type].
- ///
- /// Since [value] and [type] are not always known, [AbstractBool.Maybe] is
- /// returned if the answer is not known.
- ///
- /// [AbstractBool.Nothing] is returned if [value] is nothing.
- ///
- /// If [allowNull] is true, `null` is considered an instance of anything,
- /// otherwise it is only considered an instance of [Object], [dynamic], and
- /// [Null].
- AbstractBool isSubtypeOf(AbstractConstantValue value, types.DartType type,
- {bool allowNull}) {
- assert(allowNull != null);
- if (value.isNothing) {
- return AbstractBool.Nothing;
- }
- if (value.isConstant) {
- if (value.constant.isNull) {
- if (allowNull ||
- type.isObject ||
- type.isDynamic ||
- type == dartTypes.coreTypes.nullType) {
- return AbstractBool.True;
- }
- if (type is types.TypeVariableType) {
- return AbstractBool.Maybe;
- }
- return AbstractBool.False;
- }
- if (type == dartTypes.coreTypes.intType) {
- return constantSystem.isInt(value.constant)
- ? AbstractBool.True
- : AbstractBool.False;
- }
- types.DartType valueType = value.constant.getType(dartTypes.coreTypes);
- if (constantSystem.isSubtype(dartTypes, valueType, type)) {
- return AbstractBool.True;
- }
- if (!dartTypes.isPotentialSubtype(valueType, type)) {
- return AbstractBool.False;
- }
- return AbstractBool.Maybe;
- }
- return typeSystem.isSubtypeOf(value.type, type, allowNull: allowNull);
- }
-
- /// Returns the possible results of applying [operator] to [value],
- /// assuming the operation does not throw.
- ///
- /// Because we do not explicitly track thrown values, we currently use the
- /// convention that constant values are returned from this method only
- /// if the operation is known not to throw.
- ///
- /// This method returns `null` if a good result could not be found. In that
- /// case, it is best to fall back on interprocedural type information.
- AbstractConstantValue unaryOp(
- UnaryOperator operator, AbstractConstantValue value) {
- switch (operator.kind) {
- case UnaryOperatorKind.COMPLEMENT:
- return bitNotSpecial(value);
- case UnaryOperatorKind.NEGATE:
- return negateSpecial(value);
- default:
- break;
- }
- // TODO(asgerf): Also return information about whether this can throw?
- if (value.isNothing) {
- return nothing;
- }
- if (value.isConstant) {
- UnaryOperation operation = constantSystem.lookupUnary(operator);
- ConstantValue result = operation.fold(value.constant);
- if (result == null) return anything;
- return constant(result);
- }
- return null; // TODO(asgerf): Look up type?
- }
-
- /// Returns the possible results of applying [operator] to [left], [right],
- /// assuming the operation does not throw.
- ///
- /// Because we do not explicitly track thrown values, we currently use the
- /// convention that constant values are returned from this method only
- /// if the operation is known not to throw.
- ///
- /// This method returns `null` if a good result could not be found. In that
- /// case, it is best to fall back on interprocedural type information.
- AbstractConstantValue binaryOp(BinaryOperator operator,
- AbstractConstantValue left, AbstractConstantValue right) {
- switch (operator.kind) {
- case BinaryOperatorKind.ADD:
- return addSpecial(left, right);
-
- case BinaryOperatorKind.SUB:
- return subtractSpecial(left, right);
-
- case BinaryOperatorKind.MUL:
- return multiplySpecial(left, right);
-
- case BinaryOperatorKind.DIV:
- return divideSpecial(left, right);
-
- case BinaryOperatorKind.IDIV:
- return truncatingDivideSpecial(left, right);
-
- case BinaryOperatorKind.MOD:
- return moduloSpecial(left, right);
-
- case BinaryOperatorKind.EQ:
- return equalSpecial(left, right);
-
- case BinaryOperatorKind.AND:
- return andSpecial(left, right);
-
- case BinaryOperatorKind.OR:
- return orSpecial(left, right);
-
- case BinaryOperatorKind.XOR:
- return xorSpecial(left, right);
-
- case BinaryOperatorKind.SHL:
- return shiftLeftSpecial(left, right);
-
- case BinaryOperatorKind.SHR:
- return shiftRightSpecial(left, right);
-
- case BinaryOperatorKind.LT:
- return lessSpecial(left, right);
-
- case BinaryOperatorKind.LTEQ:
- return lessEqualSpecial(left, right);
-
- case BinaryOperatorKind.GT:
- return greaterSpecial(left, right);
-
- case BinaryOperatorKind.GTEQ:
- return greaterEqualSpecial(left, right);
-
- default:
- break;
- }
-
- if (left.isNothing || right.isNothing) {
- return nothing;
- }
- if (left.isConstant && right.isConstant) {
- BinaryOperation operation = constantSystem.lookupBinary(operator);
- ConstantValue result = operation.fold(left.constant, right.constant);
- if (result != null) return constant(result);
- }
- return null; // The caller will use return type from type inference.
- }
-
- AbstractConstantValue foldUnary(
- UnaryOperation operation, AbstractConstantValue value) {
- if (value.isNothing) return nothing;
- if (value.isConstant) {
- ConstantValue result = operation.fold(value.constant);
- if (result != null) return constant(result);
- }
- return null;
- }
-
- AbstractConstantValue bitNotSpecial(AbstractConstantValue value) {
- return foldUnary(constantSystem.bitNot, value);
- }
-
- AbstractConstantValue negateSpecial(AbstractConstantValue value) {
- AbstractConstantValue folded = foldUnary(constantSystem.negate, value);
- if (folded != null) return folded;
- if (isDefinitelyInt(value, allowNull: true)) {
- return nonConstant(typeSystem.intType);
- }
- return null;
- }
-
- AbstractConstantValue foldBinary(BinaryOperation operation,
- AbstractConstantValue left, AbstractConstantValue right) {
- if (left.isNothing || right.isNothing) return nothing;
- if (left.isConstant && right.isConstant) {
- ConstantValue result = operation.fold(left.constant, right.constant);
- if (result != null) return constant(result);
- }
- return null;
- }
-
- AbstractConstantValue closedOnInt(
- AbstractConstantValue left, AbstractConstantValue right) {
- if (isDefinitelyInt(left, allowNull: true) &&
- isDefinitelyInt(right, allowNull: true)) {
- return nonConstant(typeSystem.intType);
- }
- return null;
- }
-
- AbstractConstantValue closedOnUint(
- AbstractConstantValue left, AbstractConstantValue right) {
- if (isDefinitelyUint(left, allowNull: true) &&
- isDefinitelyUint(right, allowNull: true)) {
- return nonConstant(typeSystem.uintType);
- }
- return null;
- }
-
- AbstractConstantValue closedOnUint31(
- AbstractConstantValue left, AbstractConstantValue right) {
- if (isDefinitelyUint31(left, allowNull: true) &&
- isDefinitelyUint31(right, allowNull: true)) {
- return nonConstant(typeSystem.uint31Type);
- }
- return null;
- }
-
- AbstractConstantValue addSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- AbstractConstantValue folded = foldBinary(constantSystem.add, left, right);
- if (folded != null) return folded;
- if (isDefinitelyNum(left, allowNull: true)) {
- if (isDefinitelyUint31(left, allowNull: true) &&
- isDefinitelyUint31(right, allowNull: true)) {
- return nonConstant(typeSystem.uint32Type);
- }
- return closedOnUint(left, right) ?? closedOnInt(left, right);
- }
- return null;
- }
-
- AbstractConstantValue subtractSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- AbstractConstantValue folded =
- foldBinary(constantSystem.subtract, left, right);
- return folded ?? closedOnInt(left, right);
- }
-
- AbstractConstantValue multiplySpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- AbstractConstantValue folded =
- foldBinary(constantSystem.multiply, left, right);
- return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
- }
-
- AbstractConstantValue divideSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- return foldBinary(constantSystem.divide, left, right);
- }
-
- AbstractConstantValue truncatingDivideSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- AbstractConstantValue folded =
- foldBinary(constantSystem.truncatingDivide, left, right);
- if (folded != null) return folded;
- if (isDefinitelyNum(left, allowNull: true)) {
- if (isDefinitelyUint32(left, allowNull: true) &&
- isDefinitelyIntInRange(right, min: 2)) {
- return nonConstant(typeSystem.uint31Type);
- }
- if (isDefinitelyUint(right, allowNull: true)) {
- // `0` will be an exception, other values will shrink the result.
- if (isDefinitelyUint31(left, allowNull: true)) {
- return nonConstant(typeSystem.uint31Type);
- }
- if (isDefinitelyUint32(left, allowNull: true)) {
- return nonConstant(typeSystem.uint32Type);
- }
- if (isDefinitelyUint(left, allowNull: true)) {
- return nonConstant(typeSystem.uintType);
- }
- }
- return nonConstant(typeSystem.intType);
- }
- return null;
- }
-
- AbstractConstantValue moduloSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- AbstractConstantValue folded =
- foldBinary(constantSystem.modulo, left, right);
- return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
- }
-
- AbstractConstantValue remainderSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- if (left.isNothing || right.isNothing) return nothing;
- AbstractConstantValue folded = null; // Remainder not in constant system.
- return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
- }
-
- AbstractConstantValue codeUnitAtSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- return foldBinary(constantSystem.codeUnitAt, left, right);
- }
-
- AbstractConstantValue equalSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- AbstractConstantValue folded =
- foldBinary(constantSystem.equal, left, right);
- if (folded != null) return folded;
- bool behavesLikeIdentity =
- isDefinitelyNumStringBool(left, allowNull: true) ||
- right.isNullConstant;
- if (behavesLikeIdentity && typeSystem.areDisjoint(left.type, right.type)) {
- return constant(new FalseConstantValue());
- }
- return null;
- }
-
- AbstractConstantValue andSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- AbstractConstantValue folded =
- foldBinary(constantSystem.bitAnd, left, right);
- if (folded != null) return folded;
- if (isDefinitelyNum(left, allowNull: true)) {
- if (isDefinitelyUint31(left, allowNull: true) ||
- isDefinitelyUint31(right, allowNull: true)) {
- // Either 31-bit argument will truncate the other.
- return nonConstant(typeSystem.uint31Type);
- }
- }
- return null;
- }
-
- AbstractConstantValue orSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- AbstractConstantValue folded =
- foldBinary(constantSystem.bitOr, left, right);
- return folded ?? closedOnUint31(left, right);
- }
-
- AbstractConstantValue xorSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- AbstractConstantValue folded =
- foldBinary(constantSystem.bitXor, left, right);
- return folded ?? closedOnUint31(left, right);
- }
-
- AbstractConstantValue shiftLeftSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- return foldBinary(constantSystem.shiftLeft, left, right);
- }
-
- AbstractConstantValue shiftRightSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- AbstractConstantValue folded =
- foldBinary(constantSystem.shiftRight, left, right);
- if (folded != null) return folded;
- if (isDefinitelyUint31(left, allowNull: true)) {
- return nonConstant(typeSystem.uint31Type);
- } else if (isDefinitelyUint32(left, allowNull: true)) {
- if (isDefinitelyIntInRange(right, min: 1, max: 31)) {
- // A zero will be shifted into the 'sign' bit.
- return nonConstant(typeSystem.uint31Type);
- }
- return nonConstant(typeSystem.uint32Type);
- }
- return null;
- }
-
- AbstractConstantValue lessSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- if (isDefinitelyUint(left) && right.isZeroOrNegativeConstant) {
- return falseValue; // "uint < 0" is false.
- } else if (left.isNegativeConstant && isDefinitelyUint(right)) {
- return trueValue; // "-1 < uint" is true.
- }
- return foldBinary(constantSystem.less, left, right);
- }
-
- AbstractConstantValue lessEqualSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- if (isDefinitelyUint(left) && right.isNegativeConstant) {
- return falseValue; // "uint <= -1" is false.
- } else if (left.isZeroOrNegativeConstant && isDefinitelyUint(right)) {
- return trueValue; // "0 <= uint" is true.
- }
- return foldBinary(constantSystem.lessEqual, left, right);
- }
-
- AbstractConstantValue greaterSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- if (left.isZeroOrNegativeConstant && isDefinitelyUint(right)) {
- return falseValue; // "0 > uint" is false
- } else if (isDefinitelyUint(left) && right.isNegativeConstant) {
- return trueValue; // "uint > -1" is true
- }
- return foldBinary(constantSystem.greater, left, right);
- }
-
- AbstractConstantValue greaterEqualSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- if (left.isNegativeConstant && isDefinitelyUint(right)) {
- return falseValue; // "-1 >= uint" is false
- } else if (isDefinitelyUint(left) && right.isZeroOrNegativeConstant) {
- return trueValue; // "uint >= 0" is true
- }
- return foldBinary(constantSystem.greaterEqual, left, right);
- }
-
- AbstractConstantValue intConstant(int value) {
- return constant(new IntConstantValue(value));
- }
-
- AbstractConstantValue lengthSpecial(AbstractConstantValue input) {
- if (input.isConstant) {
- ConstantValue constant = input.constant;
- if (constant is StringConstantValue) {
- return intConstant(constant.length);
- } else if (constant is ListConstantValue) {
- return intConstant(constant.length);
- }
- }
- int length = typeSystem.getContainerLength(input.type);
- if (length != null) {
- return intConstant(length);
- }
- return null; // The caller will use return type from type inference.
- }
-
- AbstractConstantValue stringConstant(String value) {
- return constant(new StringConstantValue(new ast.DartString.literal(value)));
- }
-
- AbstractConstantValue indexSpecial(
- AbstractConstantValue left, AbstractConstantValue right) {
- if (left.isNothing || right.isNothing) return nothing;
- if (right.isConstant) {
- ConstantValue index = right.constant;
- if (left.isConstant) {
- ConstantValue receiver = left.constant;
- if (receiver is StringConstantValue) {
- if (index is IntConstantValue) {
- String stringValue = receiver.primitiveValue.slowToString();
- int indexValue = index.primitiveValue;
- if (0 <= indexValue && indexValue < stringValue.length) {
- return stringConstant(stringValue[indexValue]);
- } else {
- return nothing; // Will throw.
- }
- }
- } else if (receiver is ListConstantValue) {
- if (index is IntConstantValue) {
- int indexValue = index.primitiveValue;
- if (0 <= indexValue && indexValue < receiver.length) {
- return constant(receiver.entries[indexValue]);
- } else {
- return nothing; // Will throw.
- }
- }
- } else if (receiver is MapConstantValue) {
- ConstantValue result = receiver.lookup(index);
- if (result != null) {
- return constant(result);
- }
- return constant(new NullConstantValue());
- }
- }
- TypeMask type = typeSystem.indexWithConstant(left.type, index);
- if (type != null) return nonConstant(type);
- }
- // TODO(asgerf): Handle case where 'left' is a List or Map constant but
- // the index is unknown.
- return null; // The caller will use return type from type inference.
- }
-
- AbstractConstantValue stringify(AbstractConstantValue value) {
- if (value.isNothing) return nothing;
- if (value.isNonConst) return nonConstant(typeSystem.stringType);
- ConstantValue constantValue = value.constant;
- if (constantValue is StringConstantValue) {
- return value;
- } else if (constantValue is PrimitiveConstantValue) {
- // Note: The primitiveValue for a StringConstantValue is not suitable
- // for toString() use since it is a DartString. But the other subclasses
- // returns an unwrapped Dart value we can safely convert to a string.
- return stringConstant(constantValue.primitiveValue.toString());
- } else {
- return nonConstant(typeSystem.stringType);
- }
- }
-
- /// Returns whether [value] is one of the falsy values: false, 0, -0, NaN,
- /// the empty string, or null.
- AbstractBool boolify(AbstractConstantValue value) {
- if (value.isNothing) return AbstractBool.Nothing;
- if (value.isConstant) {
- ConstantValue constantValue = value.constant;
- if (isFalsyConstant(constantValue)) {
- return AbstractBool.False;
- } else {
- return AbstractBool.True;
- }
- }
- return typeSystem.boolify(value.type);
- }
-
- /// Returns whether [value] is the value `true`.
- AbstractBool strictBoolify(AbstractConstantValue value) {
- if (value.isNothing) return AbstractBool.Nothing;
- if (value.isConstant) {
- return value.constant.isTrue ? AbstractBool.True : AbstractBool.False;
- }
- return typeSystem.strictBoolify(value.type);
- }
-
- /// The possible return types of a method that may be targeted by
- /// [selector] on [receiver].
- AbstractConstantValue getInvokeReturnType(
- Selector selector, AbstractConstantValue receiver) {
- return fromMask(typeSystem.getInvokeReturnType(selector, receiver.type));
- }
-
- AbstractConstantValue fromMask(TypeMask mask) {
- ConstantValue constantValue = typeSystem.getConstantOf(mask);
- if (constantValue != null) return constant(constantValue, mask);
- return nonConstant(mask);
- }
-
- AbstractConstantValue nonNullable(AbstractConstantValue value) {
- if (value.isNullConstant) return nothing;
- if (!value.isNullable) return value;
- return nonConstant(value.type.nonNullable());
- }
-
- AbstractConstantValue intersectWithType(
- AbstractConstantValue value, TypeMask type) {
- if (value.isNothing || typeSystem.areDisjoint(value.type, type)) {
- return nothing;
- } else if (value.isConstant) {
- return value;
- } else {
- return nonConstant(typeSystem.intersection(value.type, type));
- }
- }
-
- /// If [value] is an integer constant, returns its value, otherwise `null`.
- int intValue(AbstractConstantValue value) {
- if (value.isConstant && value.constant.isInt) {
- PrimitiveConstantValue constant = value.constant;
- return constant.primitiveValue;
- }
- return null;
- }
-}
-
-/**
- * Propagates types (including value types for constants) throughout the IR, and
- * replaces branches with fixed jumps as well as side-effect free expressions
- * with known constant results.
- *
- * Should be followed by the [ShrinkingReducer] pass.
- *
- * Implemented according to 'Constant Propagation with Conditional Branches'
- * by Wegman, Zadeck.
- */
-class TypePropagator extends Pass {
- String get passName => 'Type propagation';
-
- final CpsFunctionCompiler _functionCompiler;
- final Map<Variable, ConstantValue> _values = <Variable, ConstantValue>{};
- final ConstantPropagationLattice _lattice;
- final bool recomputeAll;
-
- TypePropagator(CpsFunctionCompiler functionCompiler,
- {this.recomputeAll: false})
- : _functionCompiler = functionCompiler,
- _lattice = new ConstantPropagationLattice(functionCompiler);
-
- dart2js.Compiler get _compiler => _functionCompiler.compiler;
- InternalErrorFunction get _internalError => _compiler.reporter.internalError;
-
- @override
- void rewrite(FunctionDefinition root) {
- // Analyze. In this phase, the entire term is analyzed for reachability
- // and the abstract value of each expression.
- TypePropagationVisitor analyzer =
- new TypePropagationVisitor(_lattice, _values, _internalError);
-
- analyzer.analyze(root, recomputeAll);
-
- // Transform. Uses the data acquired in the previous analysis phase to
- // replace branches with fixed targets and side-effect-free expressions
- // with constant results or existing values that are in scope.
- TransformingVisitor transformer = new TransformingVisitor(
- _compiler, _functionCompiler, _lattice, analyzer, _internalError);
- transformer.transform(root);
- }
-}
-
-final Map<String, BuiltinOperator> NumBinaryBuiltins =
- const <String, BuiltinOperator>{
- '+': BuiltinOperator.NumAdd,
- '-': BuiltinOperator.NumSubtract,
- '*': BuiltinOperator.NumMultiply,
- '/': BuiltinOperator.NumDivide,
- '&': BuiltinOperator.NumAnd,
- '|': BuiltinOperator.NumOr,
- '^': BuiltinOperator.NumXor,
- '<': BuiltinOperator.NumLt,
- '<=': BuiltinOperator.NumLe,
- '>': BuiltinOperator.NumGt,
- '>=': BuiltinOperator.NumGe
-};
-
-/**
- * Uses the information from a preceding analysis pass in order to perform the
- * actual transformations on the CPS graph.
- */
-class TransformingVisitor extends DeepRecursiveVisitor {
- final TypePropagationVisitor analyzer;
- final ConstantPropagationLattice lattice;
- final dart2js.Compiler compiler;
- final CpsFunctionCompiler functionCompiler;
-
- JavaScriptBackend get backend => compiler.backend;
- BackendHelpers get helpers => backend.helpers;
- TypeMaskSystem get typeSystem => lattice.typeSystem;
- types.DartTypes get dartTypes => lattice.dartTypes;
- World get classWorld => typeSystem.classWorld;
- Map<Variable, ConstantValue> get values => analyzer.values;
-
- final InternalErrorFunction internalError;
-
- final List<Node> stack = <Node>[];
-
- TypeCheckOperator checkIsNumber;
-
- TransformingVisitor(this.compiler, this.functionCompiler, this.lattice,
- this.analyzer, this.internalError) {
- checkIsNumber = new ClassTypeCheckOperator(
- helpers.jsNumberClass, BuiltinOperator.IsNotNumber);
- }
-
- void transform(FunctionDefinition root) {
- // If one of the parameters has no value, the function is unreachable.
- // We assume all values in scope have a non-empty type (otherwise the
- // scope is unreachable), so this optimization is required.
- // TODO(asgerf): Can we avoid emitting the function is the first place?
- for (Parameter param in root.parameters) {
- if (getValue(param).isNothing) {
- // Replace with `throw "Unreachable";`
- CpsFragment cps = new CpsFragment(null);
- Primitive message =
- cps.makeConstant(new StringConstantValue.fromString("Unreachable"));
- cps.put(new Throw(message));
- replaceSubtree(root.body, cps.result);
- return;
- }
- }
- push(root.body);
- while (stack.isNotEmpty) {
- visit(stack.removeLast());
- }
- }
-
- void push(Node node) {
- assert(node != null);
- stack.add(node);
- }
-
- void pushAll(Iterable<Node> nodes) {
- nodes.forEach(push);
- }
-
- /************************* INTERIOR EXPRESSIONS *************************/
- //
- // These return nothing, and must push recursive children on the stack.
-
- void visitLetCont(LetCont node) {
- pushAll(node.continuations);
- push(node.body);
- }
-
- void visitLetHandler(LetHandler node) {
- push(node.handler);
- push(node.body);
- }
-
- void visitLetMutable(LetMutable node) {
- visit(node.variable);
- push(node.body);
- }
-
- void visitLetPrim(LetPrim node) {
- Primitive prim = node.primitive;
-
- // Try to remove a dead primitive.
- if (prim.hasNoUses && prim.isSafeForElimination) {
- push(node.body);
- prim.destroy();
- node.remove();
- return;
- }
-
- // Try to constant-fold the primitive.
- if (prim is! Constant && prim is! Refinement && prim.isSafeForElimination) {
- AbstractConstantValue value = getValue(prim);
- if (value.isConstant) {
- if (constantIsSafeToCopy(value.constant)) {
- prim.replaceWith(makeConstantPrimitive(value.constant));
- push(node.body);
- return;
- }
- }
- }
-
- // Try to specialize the primitive.
- var replacement = visit(prim);
- if (replacement is CpsFragment) {
- reanalyzeFragment(replacement);
- replacement.insertBelow(node);
- push(node.body); // Get the body before removing the node.
- prim.destroy();
- node.remove();
- return;
- }
- if (replacement is Primitive) {
- prim.replaceWith(replacement);
- reanalyze(replacement);
- // Reanalyze this node. Further specialization may be possible.
- push(node);
- return;
- }
- assert(replacement == null);
-
- // Remove dead code after a primitive that always throws.
- if (isAlwaysThrowingOrDiverging(prim)) {
- replaceSubtree(node.body, new Unreachable());
- return;
- }
-
- push(node.body);
- }
-
- bool constantIsSafeToCopy(ConstantValue constant) {
- // TODO(25230, 25231): We should refer to large shared strings by name.
- // This number is chosen to prevent huge strings being copied. Don't make
- // this too small, otherwise it will suppress otherwise harmless constant
- // folding.
- const int MAXIMUM_LENGTH_OF_DUPLICATED_STRING = 500;
- return constant is StringConstantValue
- ? constant.length < MAXIMUM_LENGTH_OF_DUPLICATED_STRING
- : true;
- }
-
- bool isAlwaysThrowingOrDiverging(Primitive prim) {
- if (prim is SetField) {
- return getValue(prim.object).isNullConstant;
- }
- if (prim is SetIndex) {
- return getValue(prim.object).isNullConstant;
- }
- // If a primitive has a value, but can't return anything, it must throw
- // or diverge.
- return prim.hasValue && prim.type.isEmpty;
- }
-
- void visitContinuation(Continuation node) {
- if (node.isReturnContinuation) return;
- if (!analyzer.reachableContinuations.contains(node)) {
- replaceSubtree(node.body, new Unreachable());
- }
- // Process the continuation body.
- // Note that the continuation body may have changed since the continuation
- // was put on the stack (e.g. [visitInvokeContinuation] may do this).
- push(node.body);
- }
-
- /************************* TRANSFORMATION HELPERS *************************/
-
- /// Sets parent pointers and computes types for the given subtree.
- void reanalyze(Node node) {
- ParentVisitor.setParents(node);
- analyzer.reanalyzeSubtree(node);
- }
-
- /// Sets parent pointers and computes types for the given fragment.
- void reanalyzeFragment(CpsFragment code) {
- if (code.isEmpty) return;
- if (code.isOpen) {
- // Temporarily close the fragment while analyzing it.
- // TODO(asgerf): Perhaps the analyzer should just cope with missing nodes.
- InteriorNode context = code.context;
- code.put(new Unreachable());
- reanalyze(code.root);
- code.context = context;
- context.body = null;
- } else {
- reanalyze(code.root);
- }
- }
-
- /// Removes the entire subtree of [node] and inserts [replacement].
- ///
- /// All references in the [node] subtree are unlinked all types in
- /// [replacement] are recomputed.
- ///
- /// [replacement] must be "fresh", i.e. it must not contain significant parts
- /// of the original IR inside of it, as this leads to redundant reprocessing.
- void replaceSubtree(Expression node, Expression replacement) {
- InteriorNode parent = node.parent;
- parent.body = replacement;
- replacement.parent = parent;
- node.parent = null;
- RemovalVisitor.remove(node);
- reanalyze(replacement);
- }
-
- /// Inserts [insertedCode] before [node].
- ///
- /// [node] will end up in the hole of [insertedCode], and [insertedCode]
- /// will become rooted where [node] was.
- void insertBefore(Expression node, CpsFragment insertedCode) {
- if (insertedCode.isEmpty) return; // Nothing to do.
- assert(insertedCode.isOpen);
- InteriorNode parent = node.parent;
- InteriorNode context = insertedCode.context;
-
- parent.body = insertedCode.root;
- insertedCode.root.parent = parent;
-
- // We want to recompute the types for [insertedCode] without
- // traversing the entire subtree of [node]. Temporarily close the
- // term with a dummy node while recomputing types.
- context.body = new Unreachable();
- reanalyze(insertedCode.root);
-
- context.body = node;
- node.parent = context;
- }
-
- /// Make a constant primitive for [constant] and set its entry in [values].
- Constant makeConstantPrimitive(ConstantValue constant) {
- Constant primitive = new Constant(constant);
- primitive.type = typeSystem.getTypeOf(constant);
- values[primitive] = constant;
- return primitive;
- }
-
- /// Builds `(LetPrim p (InvokeContinuation k p))`.
- ///
- /// No parent pointers are set.
- LetPrim makeLetPrimInvoke(Primitive primitive, Continuation continuation) {
- assert(continuation.parameters.length == 1);
-
- LetPrim letPrim = new LetPrim(primitive);
- InvokeContinuation invoke =
- new InvokeContinuation(continuation, <Primitive>[primitive]);
- letPrim.body = invoke;
- values[primitive] = values[continuation.parameters.single];
- primitive.hint = continuation.parameters.single.hint;
-
- return letPrim;
- }
-
- /************************* TAIL EXPRESSIONS *************************/
-
- // A branch can be eliminated and replaced by an invocation if only one of
- // the possible continuations is reachable. Removal often leads to both dead
- // primitives (the condition variable) and dead continuations (the unreachable
- // branch), which are both removed by the shrinking reductions pass.
- //
- // (Branch (IsTrue true) k0 k1) -> (InvokeContinuation k0)
- void visitBranch(Branch node) {
- 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.
- if (lattice.isDefinitelyBool(conditionValue, allowNull: true)) {
- node.isStrictCheck = false;
- }
-
- AbstractBool boolifiedValue = node.isStrictCheck
- ? lattice.strictBoolify(conditionValue)
- : lattice.boolify(conditionValue);
-
- if (boolifiedValue == AbstractBool.True) {
- replaceSubtree(falseCont.body, new Unreachable());
- InvokeContinuation invoke = new InvokeContinuation(trueCont, []);
- replaceSubtree(node, invoke);
- push(invoke);
- return;
- }
- if (boolifiedValue == AbstractBool.False) {
- replaceSubtree(trueCont.body, new Unreachable());
- InvokeContinuation invoke = new InvokeContinuation(falseCont, []);
- replaceSubtree(node, invoke);
- push(invoke);
- return;
- }
-
- // Shortcut negation to help simplify control flow. The tree IR will insert
- // a negation again if that's useful.
- if (condition is ApplyBuiltinOperator &&
- condition.operator == BuiltinOperator.IsFalsy) {
- node.conditionRef.changeTo(condition.argument(0));
- node.trueContinuationRef.changeTo(falseCont);
- node.falseContinuationRef.changeTo(trueCont);
- return;
- }
- }
-
- void visitInvokeContinuation(InvokeContinuation node) {
- // Inline the single-use continuations. These are often introduced when
- // specializing an invocation node. These would also be inlined by a later
- // 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;
- if (cont.hasExactlyOneUse &&
- !cont.isReturnContinuation &&
- !cont.isRecursive &&
- !node.isEscapingTry) {
- 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.argumentRefs[i].unlink();
- }
- node.continuationRef.unlink();
- InteriorNode parent = node.parent;
- Expression body = cont.body;
- parent.body = body;
- body.parent = parent;
- cont.body = new Unreachable();
- cont.body.parent = cont;
- push(body);
- }
- }
-
- /// Returns the possible targets of [selector] when invoked on a receiver
- /// of type [receiverType].
- Iterable<Element> getAllTargets(TypeMask receiverType, Selector selector) {
- return compiler.world.allFunctions.filter(selector, receiverType);
- }
-
- /************************* CALL EXPRESSIONS *************************/
-
- /// Replaces [node] with a more specialized instruction, if possible.
- ///
- /// Returns `true` if the node was replaced.
- specializeOperatorCall(InvokeMethod node) {
- if (!backend.isInterceptedSelector(node.selector)) return null;
- if (node.argumentRefs.length > 1) return null;
- if (node.callingConvention == CallingConvention.OneShotIntercepted) {
- return null;
- }
-
- bool trustPrimitives = compiler.options.trustPrimitives;
-
- /// Check that the receiver and argument satisfy the given type checks, and
- /// throw a [NoSuchMethodError] or [ArgumentError] if the check fails.
- CpsFragment makeGuard(TypeCheckOperator receiverGuard,
- [TypeCheckOperator argumentGuard]) {
- CpsFragment cps = new CpsFragment(node.sourceInformation);
-
- // Make no guards if trusting primitives.
- if (trustPrimitives) return cps;
-
- // Determine which guards are needed.
- ChecksNeeded receiverChecks =
- receiverGuard.getChecksNeeded(node.receiver, classWorld);
- bool needReceiverGuard = receiverChecks != ChecksNeeded.None;
- bool needArgumentGuard = argumentGuard != null &&
- argumentGuard.needsCheck(node.argument(0), classWorld);
-
- if (!needReceiverGuard && !needArgumentGuard) return cps;
-
- // If we only need the receiver check, emit the specialized receiver
- // check instruction. Examples:
- //
- // if (typeof receiver !== "number") return receiver.$lt;
- // if (typeof receiver !== "number") return receiver.$lt();
- //
- if (!needArgumentGuard) {
- Primitive condition = receiverGuard.makeCheck(cps, node.receiver);
- cps.letPrim(new ReceiverCheck(
- node.receiver, node.selector, node.sourceInformation,
- condition: condition,
- useSelector: true,
- isNullCheck: receiverChecks == ChecksNeeded.Null));
- return cps;
- }
-
- // TODO(asgerf): We should consider specialized instructions for
- // argument checks and receiver+argument checks, to avoid breaking up
- // basic blocks.
-
- // Emit as `H.iae(x)` if only the argument check may fail. For example:
- //
- // if (typeof argument !== "number") return H.iae(argument);
- //
- if (!needReceiverGuard) {
- cps
- .ifTruthy(argumentGuard.makeCheck(cps, node.argument(0)))
- .invokeStaticThrower(
- helpers.throwIllegalArgumentException, [node.argument(0)]);
- return cps;
- }
-
- // Both receiver and argument check is needed. Emit as a combined check
- // using a one-shot interceptor to produce the exact error message in
- // the error case. For example:
- //
- // if (typeof receiver !== "number" || typeof argument !== "number")
- // return J.$lt(receiver, argument);
- //
- Continuation fail = cps.letCont();
- cps
- .ifTruthy(receiverGuard.makeCheck(cps, node.receiver))
- .invokeContinuation(fail);
- cps
- .ifTruthy(argumentGuard.makeCheck(cps, node.argument(0)))
- .invokeContinuation(fail);
-
- cps.insideContinuation(fail)
- ..invokeMethod(
- node.receiver, node.selector, node.mask, [node.argument(0)],
- callingConvention: CallingConvention.OneShotIntercepted)
- ..put(new Unreachable());
-
- return cps;
- }
-
- /// Replaces the call with [operator], using the receiver and first argument
- /// as operands (in that order).
- ///
- /// If [guard] is given, the receiver and argument are both checked using
- /// that operator.
- CpsFragment makeBinary(BuiltinOperator operator,
- {TypeCheckOperator guard: TypeCheckOperator.none}) {
- CpsFragment cps = makeGuard(guard, guard);
- Primitive left = guard.makeRefinement(cps, node.receiver, classWorld);
- Primitive right = guard.makeRefinement(cps, node.argument(0), classWorld);
- Primitive result = cps.applyBuiltin(operator, [left, right]);
- result.hint = node.hint;
- node.replaceUsesWith(result);
- return cps;
- }
-
- /// Like [makeBinary] but for unary operators with the receiver as the
- /// argument.
- CpsFragment makeUnary(BuiltinOperator operator,
- {TypeCheckOperator guard: TypeCheckOperator.none}) {
- CpsFragment cps = makeGuard(guard);
- Primitive argument = guard.makeRefinement(cps, node.receiver, classWorld);
- Primitive result = cps.applyBuiltin(operator, [argument]);
- result.hint = node.hint;
- node.replaceUsesWith(result);
- return cps;
- }
-
- Selector renameToOptimizedSelector(String name) {
- return new Selector.call(
- new Name(name, backend.helpers.interceptorsLibrary),
- node.selector.callStructure);
- }
-
- /// Replaces the call with a call to [name] with the same inputs.
- InvokeMethod makeRenamedInvoke(String name) {
- return new InvokeMethod(node.receiver, renameToOptimizedSelector(name),
- node.mask, node.arguments.toList(),
- sourceInformation: node.sourceInformation,
- callingConvention: node.callingConvention,
- interceptor: node.interceptor);
- }
-
- TypeMask successType =
- typeSystem.receiverTypeFor(node.selector, node.receiver.type);
-
- if (node.selector.isOperator && node.argumentRefs.length == 1) {
- Primitive leftArg = node.receiver;
- Primitive rightArg = node.argument(0);
- AbstractConstantValue left = getValue(leftArg);
- AbstractConstantValue right = getValue(rightArg);
-
- String opname = node.selector.name;
- if (opname == '==') {
- // Equality is special due to its treatment of null values and the
- // fact that Dart-null corresponds to both JS-null and JS-undefined.
- // Please see documentation for IsFalsy, StrictEq, and LooseEq.
- if (left.isNullConstant || right.isNullConstant) {
- return makeBinary(BuiltinOperator.Identical);
- }
- // There are several implementations of == that behave like identical.
- // Specialize it if we definitely call one of those.
- bool behavesLikeIdentical = true;
- for (Element target in getAllTargets(left.type, node.selector)) {
- ClassElement clazz = target.enclosingClass.declaration;
- if (clazz != compiler.world.objectClass &&
- clazz != helpers.jsInterceptorClass &&
- clazz != helpers.jsNullClass) {
- behavesLikeIdentical = false;
- break;
- }
- }
- if (behavesLikeIdentical) {
- return makeBinary(BuiltinOperator.Identical);
- }
- } else {
- if (typeSystem.isDefinitelyNum(successType)) {
- // Try to insert a numeric operator.
- BuiltinOperator operator = NumBinaryBuiltins[opname];
- if (operator != null) {
- return makeBinary(operator, guard: checkIsNumber);
- }
-
- // The following specializations only apply to integers.
- // The Math.floor test is quite large, so we only apply these in cases
- // where the guard does not involve Math.floor.
-
- // Shift operators are not in [NumBinaryBuiltins] because Dart shifts
- // behave different to JS shifts, especially in the handling of the
- // shift count.
- // Try to insert a shift-left operator.
- if (opname == '<<' &&
- lattice.isDefinitelyInt(left, allowNull: true) &&
- lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
- return makeBinary(BuiltinOperator.NumShl, guard: checkIsNumber);
- }
- // Try to insert a shift-right operator. JavaScript's right shift is
- // consistent with Dart's only for left operands in the unsigned
- // 32-bit range.
- if (opname == '>>') {
- if (lattice.isDefinitelyUint32(left, allowNull: true) &&
- lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
- return makeBinary(BuiltinOperator.NumShr, guard: checkIsNumber);
- } else if (lattice.isDefinitelyUint(left) &&
- lattice.isDefinitelyUint(right)) {
- return makeRenamedInvoke('_shrBothPositive');
- } else if (lattice.isDefinitelyUint(left) &&
- lattice.isDefinitelyNum(right)) {
- return makeRenamedInvoke('_shrReceiverPositive');
- } else if (lattice.isDefinitelyNum(left) &&
- lattice.isDefinitelyUint(right)) {
- return makeRenamedInvoke('_shrOtherPositive');
- }
- }
- // Try to use remainder for '%'. Both operands must be non-negative
- // and the divisor must be non-zero.
- if (opname == '%' &&
- lattice.isDefinitelyUint(left, allowNull: true) &&
- lattice.isDefinitelyUint(right) &&
- lattice.isDefinitelyIntInRange(right, min: 1)) {
- return makeBinary(BuiltinOperator.NumRemainder,
- guard: checkIsNumber);
- }
-
- if (opname == '~/' &&
- lattice.isDefinitelyUint32(left, allowNull: true) &&
- lattice.isDefinitelyIntInRange(right, min: 2)) {
- return makeBinary(BuiltinOperator.NumTruncatingDivideToSigned32,
- guard: checkIsNumber);
- }
- }
- if (lattice.isDefinitelyString(left, allowNull: trustPrimitives) &&
- lattice.isDefinitelyString(right, allowNull: trustPrimitives) &&
- opname == '+') {
- // TODO(asgerf): Add IsString builtin so we can use a guard here.
- return makeBinary(BuiltinOperator.StringConcatenate);
- }
- }
- }
- if (node.selector.isOperator && node.argumentRefs.length == 0) {
- if (typeSystem.isDefinitelyNum(successType)) {
- String opname = node.selector.name;
- if (opname == '~') {
- return makeUnary(BuiltinOperator.NumBitNot, guard: checkIsNumber);
- }
- if (opname == 'unary-') {
- return makeUnary(BuiltinOperator.NumNegate, guard: checkIsNumber);
- }
- }
- }
- if (node.selector.isCall) {
- String name = node.selector.name;
- Primitive receiver = node.receiver;
- AbstractConstantValue receiverValue = getValue(receiver);
- if (name == 'remainder') {
- if (node.argumentRefs.length == 1) {
- Primitive arg = node.argument(0);
- AbstractConstantValue argValue = getValue(arg);
- if (lattice.isDefinitelyInt(receiverValue, allowNull: true) &&
- lattice.isDefinitelyInt(argValue) &&
- isIntNotZero(argValue)) {
- return makeBinary(BuiltinOperator.NumRemainder,
- guard: checkIsNumber);
- }
- }
- } else if (name == 'codeUnitAt') {
- if (node.argumentRefs.length == 1) {
- Primitive index = node.argument(0);
- if (lattice.isDefinitelyString(receiverValue) &&
- lattice.isDefinitelyInt(getValue(index))) {
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- receiver = makeBoundsCheck(cps, receiver, index);
- ApplyBuiltinOperator get = cps.applyBuiltin(
- BuiltinOperator.CharCodeAt, <Primitive>[receiver, index]);
- node.replaceUsesWith(get);
- get.hint = node.hint;
- return cps;
- }
- }
- }
- }
- return null;
- }
-
- /// Returns `true` if [value] represents an int value that cannot be zero.
- bool isIntNotZero(AbstractConstantValue value) {
- return lattice.isDefinitelyIntInRange(value, min: 1) ||
- lattice.isDefinitelyIntInRange(value, max: -1);
- }
-
- bool isInterceptedSelector(Selector selector) {
- return backend.isInterceptedSelector(selector);
- }
-
- /// If [node] is a getter or setter invocation, tries to replace the
- /// invocation with a direct access to a field.
- ///
- /// Returns `true` if the node was replaced.
- specializeFieldAccess(InvokeMethod node) {
- AbstractConstantValue receiver = getValue(node.receiver);
- Element target =
- typeSystem.locateSingleElement(receiver.type, node.selector);
- if (target is! FieldElement) return null;
- // TODO(asgerf): Inlining native fields will make some tests pass for the
- // wrong reason, so for testing reasons avoid inlining them.
- if (backend.isNative(target) || backend.isJsInterop(target)) {
- return null;
- }
- if (node.selector.isGetter) {
- return new GetField(node.receiver, target);
- } else if (node.selector.isSetter) {
- if (target.isFinal) return null;
- assert(node.hasNoUses);
- return new SetField(node.receiver, target, node.argument(0));
- } else if (node.selector.isCall) {
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- Primitive fieldValue = cps.letPrim(new GetField(node.receiver, target));
- Primitive result = cps.invokeMethod(
- fieldValue,
- new Selector.callClosureFrom(node.selector),
- typeSystem.getFieldType(target),
- node.arguments.toList());
- node.replaceUsesWith(result);
- return cps;
- } else {
- return null;
- }
- }
-
- /// Create a check that throws if [index] is not a valid index on [list].
- ///
- /// This function assumes that [index] is an integer.
- ///
- /// Returns a CPS fragment whose context is the branch where no error
- /// was thrown.
- Primitive makeBoundsCheck(CpsFragment cps, Primitive list, Primitive index,
- [int checkKind = BoundsCheck.BOTH_BOUNDS | BoundsCheck.INTEGER]) {
- if (compiler.options.trustPrimitives) {
- return cps.letPrim(new BoundsCheck.noCheck(list, cps.sourceInformation));
- } else {
- GetLength length = cps.letPrim(new GetLength(list));
- list = cps.refine(list, typeSystem.nonNullType);
- BoundsCheck check = cps.letPrim(new BoundsCheck(
- list, index, length, checkKind, cps.sourceInformation));
- if (check.hasIntegerCheck) {
- if (typeSystem.isDefinitelyInt(index.type)) {
- check.checks &= ~BoundsCheck.INTEGER;
- } else {
- cps.refine(index, typeSystem.uint32Type);
- }
- }
- return check;
- }
- }
-
- /// Create a check that throws if the length of [list] is not equal to
- /// [originalLength].
- ///
- /// Returns a CPS fragment whose context is the branch where no error
- /// was thrown.
- CpsFragment makeConcurrentModificationCheck(
- Primitive list, Primitive originalLength, SourceInformation sourceInfo) {
- CpsFragment cps = new CpsFragment(sourceInfo);
- Primitive lengthChanged = cps.applyBuiltin(BuiltinOperator.StrictNeq,
- <Primitive>[originalLength, cps.letPrim(new GetLength(list))]);
- cps.ifTruthy(lengthChanged).invokeStaticThrower(
- helpers.throwConcurrentModificationError, <Primitive>[list]);
- return cps;
- }
-
- /// Tries to replace [node] with a direct `length` or index access.
- ///
- /// Returns `true` if the node was replaced.
- specializeIndexableAccess(InvokeMethod node) {
- Primitive receiver = node.receiver;
- AbstractConstantValue receiverValue = getValue(receiver);
- if (!typeSystem.isDefinitelyIndexable(receiverValue.type,
- allowNull: true)) {
- return null;
- }
- switch (node.selector.name) {
- case 'length':
- 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.argument(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.options.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.argument(0);
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- receiver = makeBoundsCheck(cps, receiver, index);
- GetIndex get = cps.letPrim(new GetIndex(receiver, index));
- node.replaceUsesWith(get);
- // TODO(asgerf): Make replaceUsesWith set the hint?
- get.hint = node.hint;
- return cps;
-
- case '[]=':
- if (!typeSystem.isDefinitelyMutableIndexable(receiverValue.type,
- allowNull: true)) {
- return null;
- }
- Primitive index = node.argument(0);
- Primitive value = node.argument(1);
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- receiver = makeBoundsCheck(cps, receiver, index);
- cps.letPrim(new SetIndex(receiver, index, value));
- assert(node.hasNoUses);
- return cps;
-
- case 'isEmpty':
- if (!node.selector.isGetter) return null;
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- Primitive length = cps.letPrim(new GetLength(receiver));
- Constant zero = cps.makeZero();
- ApplyBuiltinOperator op =
- cps.applyBuiltin(BuiltinOperator.StrictEq, [length, zero]);
- node.replaceUsesWith(op);
- op.hint = node.hint;
- return cps;
-
- case 'isNotEmpty':
- if (!node.selector.isGetter) return null;
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- Primitive length = cps.letPrim(new GetLength(receiver));
- Constant zero = cps.makeZero();
- ApplyBuiltinOperator op =
- cps.applyBuiltin(BuiltinOperator.StrictNeq, [length, zero]);
- node.replaceUsesWith(op);
- op.hint = node.hint;
- return cps;
-
- default:
- return null;
- }
- }
-
- /// Tries to replace [node] with one or more direct array access operations.
- ///
- /// Returns `true` if the node was replaced.
- CpsFragment specializeArrayAccess(InvokeMethod node) {
- Primitive list = node.receiver;
- AbstractConstantValue listValue = getValue(list);
- // Ensure that the object is a native list or null.
- if (!lattice.isDefinitelyArray(listValue, allowNull: true)) {
- return null;
- }
- bool isFixedLength =
- lattice.isDefinitelyFixedArray(listValue, allowNull: true);
- bool isExtendable =
- lattice.isDefinitelyExtendableArray(listValue, allowNull: true);
- SourceInformation sourceInfo = node.sourceInformation;
- switch (node.selector.name) {
- case 'add':
- if (!node.selector.isCall ||
- node.selector.positionalArgumentCount != 1 ||
- node.selector.namedArgumentCount != 0) {
- return null;
- }
- if (!isExtendable) return null;
- Primitive addedItem = node.argument(0);
- CpsFragment cps = new CpsFragment(sourceInfo);
- cps.invokeBuiltin(BuiltinMethod.Push, list, <Primitive>[addedItem]);
- if (node.hasAtLeastOneUse) {
- node.replaceUsesWith(cps.makeNull());
- }
- return cps;
-
- case 'removeLast':
- if (!node.selector.isCall || node.selector.argumentCount != 0) {
- return null;
- }
- if (!isExtendable) return null;
- CpsFragment cps = new CpsFragment(sourceInfo);
- list = makeBoundsCheck(
- cps, list, cps.makeMinusOne(), BoundsCheck.EMPTINESS);
- Primitive removedItem =
- cps.invokeBuiltin(BuiltinMethod.Pop, list, <Primitive>[]);
- removedItem.hint = node.hint;
- node.replaceUsesWith(removedItem);
- return cps;
-
- case 'addAll':
- if (!node.selector.isCall || node.selector.argumentCount != 1) {
- return null;
- }
- if (!isExtendable) return null;
- Primitive addedList = node.argument(0);
- // Rewrite addAll([x1, ..., xN]) to push(x1), ..., push(xN).
- // Ensure that the list is not mutated between creation and use.
- // We aim for the common case where this is the only use of the list,
- // which also guarantees that this list is not mutated before use.
- if (addedList is! LiteralList || !addedList.hasExactlyOneUse) {
- return null;
- }
- LiteralList addedLiteral = addedList;
- CpsFragment cps = new CpsFragment(sourceInfo);
- for (Reference value in addedLiteral.valueRefs) {
- cps.invokeBuiltin(
- BuiltinMethod.Push, list, <Primitive>[value.definition]);
- }
- if (node.hasAtLeastOneUse) {
- node.replaceUsesWith(cps.makeNull());
- }
- return cps;
-
- case 'elementAt':
- if (!node.selector.isCall ||
- node.selector.positionalArgumentCount != 1 ||
- node.selector.namedArgumentCount != 0) {
- return null;
- }
- if (listValue.isNullable) return null;
- Primitive index = node.argument(0);
- if (!lattice.isDefinitelyInt(getValue(index))) return null;
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- list = makeBoundsCheck(cps, list, index);
- GetIndex get = cps.letPrim(new GetIndex(list, index));
- get.hint = node.hint;
- node.replaceUsesWith(get);
- return cps;
-
- case 'forEach':
- Element element =
- compiler.world.locateSingleElement(node.selector, listValue.type);
- if (element == null || !element.isFunction || !node.selector.isCall)
- return null;
- assert(node.selector.positionalArgumentCount == 1);
- assert(node.selector.namedArgumentCount == 0);
- FunctionDefinition target = functionCompiler.compileToCpsIr(element);
-
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- Primitive result = cps.inlineFunction(
- target, node.receiver, node.arguments.toList(),
- interceptor: node.interceptor, hint: node.hint);
- node.replaceUsesWith(result);
- return cps;
-
- case 'iterator':
- // TODO(asgerf): This should be done differently.
- // The types are recomputed in a very error-prone manner.
- if (!node.selector.isGetter) return null;
- Primitive iterator = node;
- LetPrim iteratorBinding = node.parent;
-
- // Check that all uses of the iterator are 'moveNext' and 'current'.
- assert(!isInterceptedSelector(Selectors.moveNext));
- assert(!isInterceptedSelector(Selectors.current));
- for (Reference ref in iterator.refinedUses) {
- if (ref.parent is! InvokeMethod) return null;
- InvokeMethod use = ref.parent;
- if (ref != use.receiverRef) return null;
- if (use.selector != Selectors.moveNext &&
- use.selector != Selectors.current) {
- return null;
- }
- }
-
- // Rewrite the iterator variable to 'current' and 'index' variables.
- Primitive originalLength = new GetLength(list);
- originalLength.hint = new OriginalLengthEntity();
- MutableVariable index = new MutableVariable(new LoopIndexEntity());
- MutableVariable current = new MutableVariable(new LoopItemEntity());
-
- // Rewrite all uses of the iterator.
- for (Reference ref in iterator.refinedUses) {
- InvokeMethod use = ref.parent;
- if (use.selector == Selectors.current) {
- // Rewrite iterator.current to a use of the 'current' variable.
- if (use.hint != null) {
- // If 'current' was originally moved into a named variable, use
- // that variable name for the mutable variable.
- current.hint = use.hint;
- }
- use.replaceWith(new GetMutable(current));
- } else {
- assert(use.selector == Selectors.moveNext);
- // Rewrite iterator.moveNext() to:
- //
- // if (index < list.length) {
- // current = null;
- // continuation(false);
- // } else {
- // current = list[index];
- // index = index + 1;
- // continuation(true);
- // }
- //
- // (The above does not show concurrent modification checks)
-
- // [cps] contains the code we insert instead of moveNext().
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- Parameter result = new Parameter(node.hint);
- Continuation moveNextCont = cps.letCont(<Parameter>[result]);
-
- // We must check for concurrent modification when calling moveNext.
- // When moveNext is used as a loop condition, the check prevents
- // `index < list.length` from becoming the loop condition, and we
- // get code like this:
- //
- // while (true) {
- // if (originalLength !== list.length) throw;
- // if (index < list.length) {
- // ...
- // } else {
- // ...
- // break;
- // }
- // }
- //
- // For loops, we therefore check for concurrent modification before
- // invoking the recursive continuation, so the loop becomes:
- //
- // if (originalLength !== list.length) throw;
- // while (index < list.length) {
- // ...
- // if (originalLength !== list.length) throw;
- // }
- //
- // The check before the loop can often be eliminated because it
- // follows immediately after the 'iterator' call.
- InteriorNode parent = getEffectiveParent(use.parent);
- if (!isFixedLength) {
- if (parent is Continuation && parent.isRecursive) {
- // Check for concurrent modification before every invocation
- // of the continuation.
- // TODO(asgerf): Do this in a continuation so multiple
- // continues can share the same code.
- for (Reference ref = parent.firstRef;
- ref != null;
- ref = ref.next) {
- Expression invocationCaller = ref.parent;
- if (getEffectiveParent(invocationCaller) == iteratorBinding) {
- // No need to check for concurrent modification immediately
- // after the call to 'iterator'.
- continue;
- }
- CpsFragment check = makeConcurrentModificationCheck(
- list, originalLength, sourceInfo);
- insertBefore(invocationCaller, check);
- }
- } else {
- cps.append(makeConcurrentModificationCheck(
- list, originalLength, sourceInfo));
- }
- }
-
- // Check if there are more elements.
- Primitive hasMore = cps.applyBuiltin(BuiltinOperator.NumLt,
- [cps.getMutable(index), cps.letPrim(new GetLength(list))]);
-
- // Return false if there are no more.
- CpsFragment falseBranch = cps.ifFalsy(hasMore);
- falseBranch
- ..setMutable(current, falseBranch.makeNull())
- ..invokeContinuation(moveNextCont, [falseBranch.makeFalse()]);
-
- // Return true if there are more element.
- current.type = typeSystem.elementTypeOfIndexable(listValue.type);
- cps.setMutable(current,
- cps.letPrim(new GetIndex(list, cps.getMutable(index))));
- cps.setMutable(
- index,
- cps.applyBuiltin(BuiltinOperator.NumAdd,
- [cps.getMutable(index), cps.makeOne()]));
- cps.invokeContinuation(moveNextCont, [cps.makeTrue()]);
-
- reanalyzeFragment(cps);
-
- // Replace the moveNext() call. It will be visited later.
- LetPrim let = use.parent;
- cps.context = moveNextCont;
- cps.insertBelow(let);
- let.remove();
- use
- ..replaceUsesWith(result)
- ..destroy();
- }
- }
-
- // All effective uses have been rewritten.
- destroyRefinementsOfDeadPrimitive(iterator);
-
- // Rewrite the iterator call to initializers for 'index' and 'current'.
- CpsFragment cps = new CpsFragment();
- cps.letMutable(index, cps.makeZero());
- cps.letMutable(current, cps.makeNull());
- cps.letPrim(originalLength);
- return cps;
-
- default:
- return null;
- }
- }
-
- /// Returns the first parent of [node] that is not a pure expression.
- InteriorNode getEffectiveParent(Expression node) {
- while (true) {
- InteriorNode parent = node.parent;
- if (parent is LetCont ||
- parent is LetPrim && parent.primitive.isSafeForReordering ||
- parent is LetPrim && parent.primitive is Refinement) {
- node = parent as dynamic; // Make analyzer accept cross cast.
- } else {
- return parent;
- }
- }
- }
-
- /// Rewrites an invocation of a torn-off method into a method call directly
- /// on the receiver. For example:
- ///
- /// obj.get$foo().call$<n>(<args>)
- /// =>
- /// obj.foo$<n>(<args>)
- ///
- Primitive specializeClosureCall(InvokeMethod node) {
- Selector call = node.selector;
- if (!call.isClosureCall) return null;
-
- assert(!isInterceptedSelector(call));
- assert(call.argumentCount == node.argumentRefs.length);
-
- Primitive tearOff = node.receiver.effectiveDefinition;
- // Note: We don't know if [tearOff] is actually a tear-off.
- // We name variables based on the pattern we are trying to match.
-
- if (tearOff is GetStatic && tearOff.element.isFunction) {
- FunctionElement target = tearOff.element;
- FunctionSignature signature = target.functionSignature;
-
- // If the selector does not apply, don't bother (will throw at runtime).
- if (!call.signatureApplies(target)) return null;
-
- // If some optional arguments are missing, give up.
- // TODO(asgerf): Improve optimization by inserting default arguments.
- if (call.argumentCount != signature.parameterCount) return null;
-
- // Replace with InvokeStatic.
- // The tear-off will be cleaned up by shrinking reductions.
- return new InvokeStatic(target, new Selector.fromElement(target),
- node.arguments.toList(), node.sourceInformation);
- }
- if (tearOff is InvokeMethod && tearOff.selector.isGetter) {
- Selector getter = tearOff.selector;
-
- // TODO(asgerf): Support torn-off intercepted methods.
- if (isInterceptedSelector(getter)) return null;
-
- LetPrim tearOffBinding = tearOff.parent;
-
- Primitive object = tearOff.receiver;
-
- // Ensure that the object actually has a foo member, since we might
- // otherwise alter a noSuchMethod call.
- TypeMask type = getValue(object).type;
- if (typeSystem.needsNoSuchMethodHandling(type, getter)) return null;
-
- Element element = typeSystem.locateSingleElement(type, getter);
-
- // If it's definitely not a tear-off, the rewrite is not worth it.
- // If we don't know what the target is, we assume that it's better to
- // rewrite (as long as it's safe to do so).
- if (element != null && element.isGetter) return null;
-
- // Either the target is a tear-off or we don't know what it is.
- // If we don't know for sure, the getter might have side effects, which
- // can make the rewriting unsafe, because we risk suppressing side effects
- // in the getter.
- // Determine if the getter invocation can have side-effects.
- bool isPure = element != null && !element.isGetter;
-
- // If there are multiple uses, we cannot eliminate the getter call and
- // therefore risk duplicating its side effects.
- if (!isPure && tearOff.hasMultipleRefinedUses) return null;
-
- // If the getter call is impure, we risk reordering side effects,
- // unless it is immediately prior to the closure call.
- if (!isPure && getEffectiveParent(node.parent) != tearOffBinding) {
- return null;
- }
-
- InvokeMethod invoke = new InvokeMethod(
- object,
- new Selector.call(getter.memberName, call.callStructure),
- type,
- node.arguments.toList(),
- sourceInformation: node.sourceInformation);
- node.receiverRef
- .changeTo(new Parameter(null)); // Remove the tear off use.
-
- if (tearOff.hasNoRefinedUses) {
- // Eliminate the getter call if it has no more uses.
- // This cannot be delegated to other optimizations because we need to
- // avoid duplication of side effects.
- destroyRefinementsOfDeadPrimitive(tearOff);
- tearOff.destroy();
- tearOffBinding.remove();
- } else {
- // There are more uses, so we cannot eliminate the getter call. This
- // means we duplicated the effects of the getter call, but we should
- // only get here if the getter has no side effects.
- assert(isPure);
- }
-
- return invoke;
- }
- return null;
- }
-
- /// Inlines a single-use closure if it leaves the closure object with only
- /// field accesses. This is optimized later by [ScalarReplacer].
- CpsFragment specializeSingleUseClosureCall(InvokeMethod node) {
- Selector call = node.selector;
- if (!call.isClosureCall) return null;
-
- assert(!isInterceptedSelector(call));
- assert(call.argumentCount == node.argumentRefs.length);
-
- Primitive receiver = node.receiver;
- if (receiver is! CreateInstance) return null;
- CreateInstance createInstance = receiver;
- if (!createInstance.hasExactlyOneUse) return null;
-
- // Inline only closures. This avoids inlining the 'call' method of a class
- // that has many allocation sites.
- if (createInstance.classElement is! ClosureClassElement) return null;
-
- ClosureClassElement closureClassElement = createInstance.classElement;
- Element element = closureClassElement.localLookup(Identifiers.call);
-
- if (element == null || !element.isFunction) return null;
- FunctionElement functionElement = element;
- if (functionElement.asyncMarker != AsyncMarker.SYNC) return null;
-
- if (!call.signatureApplies(functionElement)) return null;
- // Inline only for exact match.
- // TODO(sra): Handle call with defaulted arguments.
- Selector targetSelector = new Selector.fromElement(functionElement);
- if (call.callStructure != targetSelector.callStructure) return null;
-
- // Don't inline if [target] contains try-catch or try-finally. JavaScript
- // engines typically do poor optimization of the entire function containing
- // the 'try'.
- if (functionElement.resolvedAst.elements.containsTryStatement) return null;
-
- FunctionDefinition target =
- functionCompiler.compileToCpsIr(functionElement);
-
- // Accesses to closed-over values are field access primitives. We we don't
- // inline if there are other uses of 'this' since that could be an escape or
- // a recursive call.
- for (Reference ref = target.receiverParameter.firstRef;
- ref != null;
- ref = ref.next) {
- Node use = ref.parent;
- 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.objectRef) continue;
- return null;
- }
-
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- Primitive returnValue = cps.inlineFunction(
- target, node.receiver, node.arguments.toList(),
- hint: node.hint);
- node.replaceUsesWith(returnValue);
- return cps;
- }
-
- visitInterceptor(Interceptor node) {
- // Replace the interceptor with its input if the value is not intercepted.
- // If the input might be null, we cannot do this since the interceptor
- // 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;
- 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.receiver.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.interceptorRef.changeTo(node.receiver);
- }
- }
-
- visitInvokeMethod(InvokeMethod node) {
- var specialized = specializeOperatorCall(node) ??
- specializeFieldAccess(node) ??
- specializeIndexableAccess(node) ??
- specializeArrayAccess(node) ??
- specializeSingleUseClosureCall(node) ??
- specializeClosureCall(node);
- if (specialized != null) return specialized;
-
- TypeMask receiverType = node.receiver.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;
-
- if (node.callingConvention == CallingConvention.Intercepted &&
- !canBeNonThrowingCallOnNull &&
- 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.interceptorRef.changeTo(node.receiver);
-
- // Replace the extra receiver argument with a dummy value if the
- // target definitely does not use it.
- if (typeSystem.targetIgnoresReceiverArgument(
- receiverType, node.selector)) {
- node.makeDummyIntercepted();
- }
- }
- }
-
- CpsFragment visitTypeCast(TypeCast node) {
- AbstractConstantValue value = getValue(node.value);
- switch (lattice.isSubtypeOf(value, node.dartType, allowNull: true)) {
- case AbstractBool.Maybe:
- case AbstractBool.Nothing:
- return null;
-
- case AbstractBool.True:
- // Return an unused primitive moved again.
- node.replaceUsesWith(node.value);
- return new CpsFragment(); // Remove the node.
-
- case AbstractBool.False:
- // Note: The surrounding LetPrim will remove the following code because
- // it always throws. We don't need to do it here.
- return null;
- }
- }
-
- /// Specialize calls to internal static methods.
- specializeInternalMethodCall(InvokeStatic node) {
- if (node.target == backend.helpers.stringInterpolationHelper) {
- Primitive argument = node.argument(0);
- AbstractConstantValue value = getValue(argument);
- if (lattice.isDefinitelyString(value)) {
- node.replaceUsesWith(argument);
- return new CpsFragment();
- } else if (typeSystem.isDefinitelySelfInterceptor(value.type)) {
- TypeMask toStringReturn =
- typeSystem.getInvokeReturnType(Selectors.toString_, value.type);
- if (typeSystem.isDefinitelyString(toStringReturn)) {
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- Primitive invoke = cps.invokeMethod(
- argument, Selectors.toString_, value.type, [],
- callingConvention: CallingConvention.DummyIntercepted);
- node.replaceUsesWith(invoke);
- return cps;
- }
- }
- } else if (node.target == compiler.identicalFunction) {
- if (node.argumentRefs.length == 2) {
- return new ApplyBuiltinOperator(BuiltinOperator.Identical,
- [node.argument(0), node.argument(1)], node.sourceInformation);
- }
- }
- return null;
- }
-
- visitInvokeStatic(InvokeStatic node) {
- node.effects =
- Effects.from(compiler.world.getSideEffectsOfElement(node.target));
- return specializeInternalMethodCall(node);
- }
-
- AbstractConstantValue getValue(Variable node) {
- assert(node.type != null);
- ConstantValue constant = values[node];
- if (constant != null) {
- return new AbstractConstantValue.constantValue(constant, node.type);
- }
- return new AbstractConstantValue.nonConstant(node.type);
- }
-
- /*************************** PRIMITIVES **************************/
- //
- // The visit method for a primitive may return one of the following:
- // - Primitive:
- // The visited primitive will be replaced by the returned primitive.
- // The type of the primitive will be recomputed.
- // - CpsFragment:
- // The primitive binding will be destroyed and replaced by the given
- // code fragment. All types in the fragment will be recomputed.
- // - Null:
- // Nothing happens. The primitive remains as it is.
- //
-
- visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- ast.DartString getString(AbstractConstantValue value) {
- StringConstantValue constant = value.constant;
- return constant.primitiveValue;
- }
- switch (node.operator) {
- case BuiltinOperator.StringConcatenate:
- // Concatenate consecutive constants.
- bool argumentsWereRemoved = false;
- int i = 0;
- while (i < node.argumentRefs.length - 1) {
- int startOfSequence = i;
- AbstractConstantValue firstValue = getValue(node.argument(i++));
- if (!firstValue.isConstant) continue;
- AbstractConstantValue secondValue = getValue(node.argument(i++));
- if (!secondValue.isConstant) continue;
-
- ast.DartString string = new ast.ConsDartString(
- getString(firstValue), getString(secondValue));
-
- // We found a sequence of at least two constants.
- // Look for the end of the sequence.
- while (i < node.argumentRefs.length) {
- AbstractConstantValue value = getValue(node.argument(i));
- if (!value.isConstant) break;
- string = new ast.ConsDartString(string, getString(value));
- ++i;
- }
- Constant prim =
- makeConstantPrimitive(new StringConstantValue(string));
- new LetPrim(prim).insertAbove(node.parent);
- for (int k = startOfSequence; k < i; ++k) {
- node.argumentRefs[k].unlink();
- node.argumentRefs[k] = null; // Remove the argument after the loop.
- }
- node.argumentRefs[startOfSequence] = new Reference<Primitive>(prim);
- node.argumentRefs[startOfSequence].parent = node;
- argumentsWereRemoved = true;
- }
- if (argumentsWereRemoved) {
- node.argumentRefs.removeWhere((ref) => ref == null);
- }
- if (node.argumentRefs.length == 1) {
- Primitive input = node.argument(0);
- node.replaceUsesWith(input);
- input.useElementAsHint(node.hint);
- }
- // TODO(asgerf): Rebalance nested StringConcats that arise from
- // rewriting the + operator to StringConcat.
- break;
-
- case BuiltinOperator.Identical:
- Primitive leftArg = node.argument(0);
- Primitive rightArg = node.argument(1);
- AbstractConstantValue left = getValue(leftArg);
- AbstractConstantValue right = getValue(rightArg);
- BuiltinOperator newOperator;
- if (left.isNullConstant || right.isNullConstant) {
- // Use `==` for comparing against null, so JS undefined and JS null
- // are considered equal.
- newOperator = BuiltinOperator.LooseEq;
- } else if (!left.isNullable || !right.isNullable) {
- // If at most one operand can be Dart null, we can use `===`.
- // This is not safe when we might compare JS null and JS undefined.
- newOperator = BuiltinOperator.StrictEq;
- } else if (lattice.isDefinitelyNum(left, allowNull: true) &&
- lattice.isDefinitelyNum(right, allowNull: true)) {
- // If both operands can be null, but otherwise are of the same type,
- // we can use `==` for comparison.
- // This is not safe e.g. for comparing strings against numbers.
- newOperator = BuiltinOperator.LooseEq;
- } else if (lattice.isDefinitelyString(left, allowNull: true) &&
- lattice.isDefinitelyString(right, allowNull: true)) {
- newOperator = BuiltinOperator.LooseEq;
- } else if (lattice.isDefinitelyBool(left, allowNull: true) &&
- lattice.isDefinitelyBool(right, allowNull: true)) {
- newOperator = BuiltinOperator.LooseEq;
- }
- if (newOperator != null) {
- return new ApplyBuiltinOperator(
- newOperator, node.arguments.toList(), node.sourceInformation);
- }
- break;
-
- case BuiltinOperator.StrictEq:
- case BuiltinOperator.LooseEq:
- case BuiltinOperator.StrictNeq:
- case BuiltinOperator.LooseNeq:
- bool negated = node.operator == BuiltinOperator.StrictNeq ||
- node.operator == BuiltinOperator.LooseNeq;
- for (int firstIndex in [0, 1]) {
- int secondIndex = 1 - firstIndex;
- Primitive firstArg = node.argument(firstIndex);
- Primitive secondArg = node.argument(secondIndex);
- AbstractConstantValue first = getValue(firstArg);
- if (!lattice.isDefinitelyBool(first)) continue;
- AbstractConstantValue second = getValue(secondArg);
- if (!second.isConstant || !second.constant.isBool) continue;
- bool isTrueConstant = second.constant.isTrue;
- if (isTrueConstant == !negated) {
- // (x === true) ==> x
- // (x !== false) ==> x
- node.replaceUsesWith(firstArg);
- return null;
- } else {
- // (x === false) ==> !x
- // (x !== true) ==> !x
- return new ApplyBuiltinOperator(
- BuiltinOperator.IsFalsy, [firstArg], node.sourceInformation);
- }
- }
- break;
-
- default:
- }
- return null;
- }
-
- void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {}
-
- visitTypeTest(TypeTest node) {
- Primitive prim = node.value;
-
- Primitive unaryBuiltinOperator(BuiltinOperator operator) =>
- new ApplyBuiltinOperator(
- operator, <Primitive>[prim], node.sourceInformation);
-
- AbstractConstantValue value = getValue(prim);
- types.DartType dartType = node.dartType;
-
- if (!(dartType.isInterfaceType && dartType.isRaw)) {
- // TODO(23685): Efficient function arity check.
- // TODO(sra): Pass interceptor to runtime subtype functions.
- return null;
- }
-
- if (dartType == dartTypes.coreTypes.intType) {
- // Compile as typeof x === 'number' && Math.floor(x) === x
- if (lattice.isDefinitelyNum(value, allowNull: true)) {
- // If value is null or a number, we can skip the typeof test.
- return new ApplyBuiltinOperator(BuiltinOperator.IsFloor,
- <Primitive>[prim, prim], node.sourceInformation);
- }
- if (lattice.isDefinitelyNotNonIntegerDouble(value)) {
- // If the value cannot be a non-integer double, but might not be a
- // number at all, we can skip the Math.floor test.
- return unaryBuiltinOperator(BuiltinOperator.IsNumber);
- }
- return new ApplyBuiltinOperator(BuiltinOperator.IsInteger,
- <Primitive>[prim, prim, prim], node.sourceInformation);
- }
- if (node.dartType == dartTypes.coreTypes.numType ||
- node.dartType == dartTypes.coreTypes.doubleType) {
- return new ApplyBuiltinOperator(
- BuiltinOperator.IsNumber, <Primitive>[prim], node.sourceInformation);
- }
-
- AbstractBool isNullableSubtype =
- lattice.isSubtypeOf(value, node.dartType, allowNull: true);
- AbstractBool isNullPassingTest =
- lattice.isSubtypeOf(lattice.nullValue, node.dartType, allowNull: false);
- if (isNullableSubtype == AbstractBool.True &&
- isNullPassingTest == AbstractBool.False) {
- // Null is the only value not satisfying the type test.
- // Replace the type test with a null-check.
- // This has lower priority than the 'typeof'-based tests because
- // 'typeof' expressions might give the VM some more useful information.
- Primitive nullConst = makeConstantPrimitive(new NullConstantValue());
- new LetPrim(nullConst).insertAbove(node.parent);
- return new ApplyBuiltinOperator(BuiltinOperator.LooseNeq,
- <Primitive>[prim, nullConst], node.sourceInformation);
- }
-
- if (dartType.element == functionCompiler.glue.jsFixedArrayClass) {
- // TODO(sra): Check input is restricted to JSArray.
- return unaryBuiltinOperator(BuiltinOperator.IsFixedLengthJSArray);
- }
-
- if (dartType.element == functionCompiler.glue.jsExtendableArrayClass) {
- // TODO(sra): Check input is restricted to JSArray.
- return unaryBuiltinOperator(BuiltinOperator.IsExtendableJSArray);
- }
-
- if (dartType.element == functionCompiler.glue.jsMutableArrayClass) {
- // TODO(sra): Check input is restricted to JSArray.
- return unaryBuiltinOperator(BuiltinOperator.IsModifiableJSArray);
- }
-
- if (dartType.element == functionCompiler.glue.jsUnmodifiableArrayClass) {
- // TODO(sra): Check input is restricted to JSArray.
- return unaryBuiltinOperator(BuiltinOperator.IsUnmodifiableJSArray);
- }
-
- if (dartType == dartTypes.coreTypes.stringType ||
- dartType == dartTypes.coreTypes.boolType) {
- // These types are recognized in tree_ir TypeOperator codegen.
- return null;
- }
-
- // TODO(sra): If getInterceptor(x) === x or JSNull, rewrite
- // getInterceptor(x).$isFoo ---> x != null && x.$isFoo
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- Interceptor interceptor =
- cps.letPrim(new Interceptor(prim, node.sourceInformation));
- Primitive testViaFlag =
- cps.letPrim(new TypeTestViaFlag(interceptor, dartType));
- node.replaceUsesWith(testViaFlag);
- return cps;
- }
-
- Primitive visitTypeTestViaFlag(TypeTestViaFlag node) {
- return null;
- }
-
- visitBoundsCheck(BoundsCheck node) {
- // Eliminate bounds checks using constant folding.
- // The [BoundsChecker] pass does not try to eliminate checks that could be
- // eliminated by constant folding.
- if (node.hasNoChecks) return;
- Primitive indexPrim = node.index;
- int index = lattice.intValue(getValue(indexPrim));
- int length =
- node.lengthRef == null ? null : lattice.intValue(getValue(node.length));
- if (index != null && length != null && index < length) {
- node.checks &= ~BoundsCheck.UPPER_BOUND;
- }
- if (index != null && index >= 0) {
- node.checks &= ~BoundsCheck.LOWER_BOUND;
- }
- if (length != null && length > 0) {
- node.checks &= ~BoundsCheck.EMPTINESS;
- }
- if (typeSystem.isDefinitelyInt(indexPrim.type)) {
- node.checks &= ~BoundsCheck.INTEGER;
- }
- 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.
- // TODO(asgerf): Since this was eliminated by constant folding, it should
- // be safe to remove because any path-sensitive information we relied
- // upon to do this are expressed by other refinement nodes that also
- // 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
- ..indexRef.unlink()
- ..indexRef = null;
- }
- }
-
- visitReceiverCheck(ReceiverCheck node) {
- Primitive input = node.value;
- if (!input.type.isNullable &&
- (node.isNullCheck ||
- !input.type.needsNoSuchMethodHandling(node.selector, classWorld))) {
- node.replaceUsesWith(input);
- return new CpsFragment();
- }
- return null;
- }
-
- visitGetLength(GetLength node) {
- node.isFinal = typeSystem.isDefinitelyFixedLengthIndexable(node.object.type,
- allowNull: true);
- }
-
- visitReadTypeVariable(ReadTypeVariable node) {
- // Pattern match on
- //
- // ReadTypeVariable(var, CreateInstance(..., TypeExpression(arguments)))
- //
- // and extract the argument that corresponds to the type variable. This is a
- // shrinking reduction.
- //
- // TODO(sra): This is a shrinking reduction that does not depend on inferred
- // types so it should be done in the shrinking reductions pass.
- //
- // TODO(sra): A non-shrinking version of this rewrite could be done as part
- // of scalar replacement.
-
- 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;
- ClassElement createdClass = instance.classElement;
- // In the general case, a substitution could generate a large type
- // term. Avoid this by restricting to direct indexing.
- // TODO(sra): Also include cases that require substitution but the end
- // result is the same as some indexing or a simple constant type.
- if (backend.rti.isTrivialSubstitution(createdClass, context)) {
- int index = functionCompiler.glue.getTypeVariableIndex(node.variable);
- if (0 <= index && index < typeExpression.argumentRefs.length) {
- node.replaceUsesWith(typeExpression.argument(index));
- return new CpsFragment();
- }
- }
- }
- }
- return null;
- }
-
- bool isNullConstant(Primitive prim) => prim is Constant && prim.value.isNull;
-
- visitCreateInstance(CreateInstance node) {
- Primitive typeInformation = node.typeInformation;
- if (typeInformation is TypeExpression &&
- typeInformation.arguments.every(isNullConstant)) {
- node
- ..typeInformationRef.unlink()
- ..typeInformationRef = null;
- }
- }
-}
-
-/**
- * Runs an analysis pass on the given function definition in order to detect
- * const-ness as well as reachability, both of which are used in the subsequent
- * transformation pass.
- */
-class TypePropagationVisitor implements Visitor {
- // The node worklist stores nodes that are both reachable and need to be
- // processed, but have not been processed yet. Using a worklist avoids deep
- // recursion.
- // The node worklist and the reachable set operate in concert: nodes are
- // only ever added to the worklist when they have not yet been marked as
- // reachable, and adding a node to the worklist is always followed by marking
- // it reachable.
- // TODO(jgruber): Storing reachability per-edge instead of per-node would
- // allow for further optimizations.
- final List<Node> nodeWorklist = <Node>[];
- final Set<Continuation> reachableContinuations = new Set<Continuation>();
-
- // The definition workset stores all definitions which need to be reprocessed
- // since their lattice value has changed.
- final List<Definition> defWorklist = <Definition>[];
-
- final ConstantPropagationLattice lattice;
- final InternalErrorFunction internalError;
-
- TypeMaskSystem get typeSystem => lattice.typeSystem;
-
- JavaScriptBackend get backend => typeSystem.backend;
-
- dart2js.Compiler get compiler => backend.compiler;
-
- World get classWorld => typeSystem.classWorld;
-
- AbstractConstantValue get nothing => lattice.nothing;
-
- AbstractConstantValue nonConstant([TypeMask type]) {
- return lattice.nonConstant(type);
- }
-
- AbstractConstantValue constantValue(ConstantValue constant, [TypeMask type]) {
- return lattice.constant(constant, type);
- }
-
- // Stores the current lattice value for primitives and mutable variables.
- // Access through [getValue] and [setValue].
- final Map<Variable, ConstantValue> values;
-
- TypePropagationVisitor(this.lattice, this.values, this.internalError);
-
- void analyze(FunctionDefinition root, bool recomputeAll) {
- reachableContinuations.clear();
- if (recomputeAll) {
- new ResetAnalysisInfo(reachableContinuations, values).visit(root);
- }
-
- // Initially, only the root node is reachable.
- push(root);
-
- iterateWorklist();
- }
-
- void reanalyzeSubtree(Node node) {
- new ResetAnalysisInfo(reachableContinuations, values).visit(node);
- push(node);
- iterateWorklist();
- }
-
- void iterateWorklist() {
- while (true) {
- if (nodeWorklist.isNotEmpty) {
- // Process a new reachable expression.
- Node node = nodeWorklist.removeLast();
- visit(node);
- } else if (defWorklist.isNotEmpty) {
- // Process all usages of a changed definition.
- Definition def = defWorklist.removeLast();
-
- // Visit all uses of this definition. This might add new entries to
- // [nodeWorklist], for example by visiting a newly-constant usage within
- // a branch node.
- for (Reference ref = def.firstRef; ref != null; ref = ref.next) {
- visit(ref.parent);
- }
- } else {
- break; // Both worklists empty.
- }
- }
- }
-
- /// Adds [node] to the worklist.
- void push(Node node) {
- nodeWorklist.add(node);
- }
-
- /// If the passed node is not yet reachable, mark it reachable and add it
- /// to the work list.
- void setReachable(Continuation cont) {
- if (reachableContinuations.add(cont)) {
- push(cont);
- }
- }
-
- /// Returns the lattice value corresponding to [node], defaulting to nothing.
- ///
- /// Never returns null.
- AbstractConstantValue getValue(Variable node) {
- ConstantValue constant = values[node];
- if (constant != null) {
- return new AbstractConstantValue.constantValue(constant, node.type);
- }
- if (node.type != null) {
- return new AbstractConstantValue.nonConstant(node.type);
- }
- return lattice.nothing;
- }
-
- /// Joins the passed lattice [updateValue] to the current value of [node],
- /// and adds it to the definition work set if it has changed and [node] is
- /// a definition.
- void setValue(Variable node, AbstractConstantValue updateValue) {
- AbstractConstantValue oldValue = getValue(node);
- AbstractConstantValue newValue = lattice.join(oldValue, updateValue);
- node.type = newValue.type; // Ensure type is initialized even if bottom.
- if (oldValue == newValue) {
- return;
- }
-
- // Values may only move in the direction NOTHING -> CONSTANT -> NONCONST.
- assert(newValue.kind >= oldValue.kind);
-
- values[node] = newValue.isConstant ? newValue.constant : null;
- defWorklist.add(node);
- }
-
- /// Sets the type of the given primitive.
- ///
- /// If [updateValue] is a constant and [canReplace] is true, the primitive
- /// is also marked as safe for elimination, so it can be constant-folded.
- void setResult(UnsafePrimitive prim, AbstractConstantValue updateValue,
- {bool canReplace: false}) {
- // TODO(asgerf): Separate constant folding from side effect analysis.
- setValue(prim, updateValue);
- prim.isSafeForElimination = canReplace && updateValue.isConstant;
- }
-
- bool isInterceptedSelector(Selector selector) {
- return backend.isInterceptedSelector(selector);
- }
-
- // -------------------------- Visitor overrides ------------------------------
- void visit(Node node) {
- node.accept(this);
- }
-
- void visitFunctionDefinition(FunctionDefinition node) {
- if (node.interceptorParameter != null) {
- setValue(node.interceptorParameter, nonConstant(typeSystem.nonNullType));
- }
- // If the abstract value of the function parameters is Nothing, use the
- // inferred parameter type. Otherwise (e.g., when inlining) do not
- // change the abstract value.
- if (node.receiverParameter != null &&
- getValue(node.receiverParameter).isNothing) {
- setValue(node.receiverParameter,
- nonConstant(typeSystem.getReceiverType(node.element)));
- }
- bool hasParameterWithoutValue = false;
- for (Parameter param in node.parameters) {
- if (getValue(param).isNothing) {
- TypeMask type = param.hint is ParameterElement
- ? typeSystem.getParameterType(param.hint)
- : typeSystem.dynamicType;
- setValue(param, lattice.fromMask(type));
- if (type.isEmpty) hasParameterWithoutValue = true;
- }
- }
- if (!hasParameterWithoutValue) {
- // Don't analyze unreachable code.
- push(node.body);
- }
- }
-
- void visitLetPrim(LetPrim node) {
- visit(node.primitive); // No reason to delay visits to primitives.
- push(node.body);
- }
-
- void visitLetCont(LetCont node) {
- // The continuation is only marked as reachable on use.
- push(node.body);
- }
-
- void visitLetHandler(LetHandler node) {
- push(node.body);
- // The handler is assumed to be reachable (we could instead treat it as
- // unreachable unless we find something reachable that might throw in the
- // body --- it's not clear if we want to do that here or in some other
- // pass). The handler parameters are assumed to be unknown.
- //
- // TODO(kmillikin): we should set the type of the exception and stack
- // trace here. The way we do that depends on how we handle 'on T' catch
- // clauses.
- setReachable(node.handler);
- for (Parameter param in node.handler.parameters) {
- setValue(param, nonConstant());
- }
- }
-
- void visitLetMutable(LetMutable node) {
- setValue(node.variable, getValue(node.value));
- push(node.body);
- }
-
- void visitInvokeStatic(InvokeStatic node) {
- if (node.target == backend.helpers.stringInterpolationHelper) {
- AbstractConstantValue argValue = getValue(node.argument(0));
- setResult(node, lattice.stringify(argValue), canReplace: true);
- return;
- }
-
- TypeMask returnType = typeSystem.getReturnType(node.target);
- setResult(node, lattice.fromMask(returnType));
- }
-
- void visitInvokeContinuation(InvokeContinuation node) {
- 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.argumentRefs.length; i++) {
- Primitive def = node.argument(i);
- AbstractConstantValue cell = getValue(def);
- setValue(cont.parameters[i], cell);
- }
- }
-
- void visitInvokeMethod(InvokeMethod node) {
- AbstractConstantValue receiver = getValue(node.receiver);
- if (receiver.isNothing) {
- return setResult(node, lattice.nothing);
- }
-
- void finish(AbstractConstantValue result, {bool canReplace: false}) {
- if (result == null) {
- canReplace = false;
- result = lattice.getInvokeReturnType(node.selector, receiver);
- }
- setResult(node, result, canReplace: canReplace);
- }
-
- if (node.selector.isGetter) {
- // Constant fold known length of containers.
- if (node.selector == Selectors.length) {
- if (typeSystem.isDefinitelyIndexable(receiver.type, allowNull: true)) {
- AbstractConstantValue length = lattice.lengthSpecial(receiver);
- return finish(length, canReplace: !receiver.isNullable);
- }
- }
- return finish(null);
- }
-
- if (node.selector.isCall) {
- if (node.selector == Selectors.codeUnitAt) {
- AbstractConstantValue right = getValue(node.argument(0));
- AbstractConstantValue result =
- lattice.codeUnitAtSpecial(receiver, right);
- return finish(result, canReplace: !receiver.isNullable);
- }
- return finish(null);
- }
-
- if (node.selector == Selectors.index) {
- AbstractConstantValue right = getValue(node.argument(0));
- AbstractConstantValue result = lattice.indexSpecial(receiver, right);
- return finish(result, canReplace: !receiver.isNullable);
- }
-
- if (!node.selector.isOperator) {
- return finish(null);
- }
-
- // Calculate the resulting constant if possible.
- String opname = node.selector.name;
- if (node.argumentRefs.length == 0) {
- // Unary operator.
- if (opname == "unary-") {
- opname = "-";
- }
- UnaryOperator operator = UnaryOperator.parse(opname);
- AbstractConstantValue result = lattice.unaryOp(operator, receiver);
- return finish(result, canReplace: !receiver.isNullable);
- } else if (node.argumentRefs.length == 1) {
- // Binary operator.
- AbstractConstantValue right = getValue(node.argument(0));
- BinaryOperator operator = BinaryOperator.parse(opname);
- AbstractConstantValue result =
- lattice.binaryOp(operator, receiver, right);
- return finish(result, canReplace: !receiver.isNullable);
- }
- return finish(null);
- }
-
- void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- void unaryOp(
- AbstractConstantValue operation(AbstractConstantValue argument),
- TypeMask defaultType) {
- AbstractConstantValue value = getValue(node.argument(0));
- setValue(node, operation(value) ?? nonConstant(defaultType));
- }
-
- void binaryOp(
- AbstractConstantValue operation(
- AbstractConstantValue left, AbstractConstantValue right),
- TypeMask defaultType) {
- AbstractConstantValue left = getValue(node.argument(0));
- AbstractConstantValue right = getValue(node.argument(1));
- setValue(node, operation(left, right) ?? nonConstant(defaultType));
- }
-
- void binaryNumOp(
- AbstractConstantValue operation(
- AbstractConstantValue left, AbstractConstantValue right)) {
- binaryOp(operation, typeSystem.numType);
- }
-
- void binaryUint32Op(
- AbstractConstantValue operation(
- AbstractConstantValue left, AbstractConstantValue right)) {
- binaryOp(operation, typeSystem.uint32Type);
- }
-
- void binaryBoolOp(
- AbstractConstantValue operation(
- AbstractConstantValue left, AbstractConstantValue right)) {
- binaryOp(operation, typeSystem.boolType);
- }
-
- switch (node.operator) {
- case BuiltinOperator.StringConcatenate:
- ast.DartString stringValue = const ast.LiteralDartString('');
- for (Reference<Primitive> arg in node.argumentRefs) {
- AbstractConstantValue value = getValue(arg.definition);
- if (value.isNothing) {
- setValue(node, lattice.nothing);
- return; // And come back later
- } else if (value.isConstant &&
- value.constant.isString &&
- stringValue != null) {
- StringConstantValue constant = value.constant;
- stringValue =
- new ast.ConsDartString(stringValue, constant.primitiveValue);
- } else {
- stringValue = null;
- break;
- }
- }
- if (stringValue == null) {
- setValue(node, nonConstant(typeSystem.stringType));
- } else {
- setValue(node, constantValue(new StringConstantValue(stringValue)));
- }
- break;
-
- case BuiltinOperator.CharCodeAt:
- binaryOp(lattice.codeUnitAtSpecial, typeSystem.uint31Type);
- break;
-
- case BuiltinOperator.Identical:
- case BuiltinOperator.StrictEq:
- case BuiltinOperator.StrictNeq:
- case BuiltinOperator.LooseEq:
- case BuiltinOperator.LooseNeq:
- bool negated = node.operator == BuiltinOperator.StrictNeq ||
- node.operator == BuiltinOperator.LooseNeq;
- AbstractConstantValue left = getValue(node.argument(0));
- AbstractConstantValue right = getValue(node.argument(1));
- if (left.isNothing || right.isNothing) {
- setValue(node, lattice.nothing);
- return;
- }
- if (left.isConstant && right.isConstant) {
- ConstantValue equal = lattice.constantSystem.identity
- .fold(left.constant, right.constant);
- if (equal != null && equal.isBool) {
- ConstantValue result =
- new BoolConstantValue(equal.isTrue == !negated);
- setValue(node, constantValue(result, typeSystem.boolType));
- return;
- }
- }
- if (typeSystem.areDisjoint(left.type, right.type)) {
- ConstantValue result = new BoolConstantValue(negated);
- setValue(node, constantValue(result, typeSystem.boolType));
- return;
- }
- setValue(node, nonConstant(typeSystem.boolType));
- break;
-
- case BuiltinOperator.NumAdd:
- binaryNumOp(lattice.addSpecial);
- break;
-
- case BuiltinOperator.NumSubtract:
- binaryNumOp(lattice.subtractSpecial);
- break;
-
- case BuiltinOperator.NumMultiply:
- binaryNumOp(lattice.multiplySpecial);
- break;
-
- case BuiltinOperator.NumDivide:
- binaryNumOp(lattice.divideSpecial);
- break;
-
- case BuiltinOperator.NumRemainder:
- binaryNumOp(lattice.remainderSpecial);
- break;
-
- case BuiltinOperator.NumTruncatingDivideToSigned32:
- binaryNumOp(lattice.truncatingDivideSpecial);
- break;
-
- case BuiltinOperator.NumAnd:
- binaryUint32Op(lattice.andSpecial);
- break;
-
- case BuiltinOperator.NumOr:
- binaryUint32Op(lattice.orSpecial);
- break;
-
- case BuiltinOperator.NumXor:
- binaryUint32Op(lattice.xorSpecial);
- break;
-
- case BuiltinOperator.NumShl:
- binaryUint32Op(lattice.shiftLeftSpecial);
- break;
-
- case BuiltinOperator.NumShr:
- binaryUint32Op(lattice.shiftRightSpecial);
- break;
-
- case BuiltinOperator.NumLt:
- binaryBoolOp(lattice.lessSpecial);
- break;
-
- case BuiltinOperator.NumLe:
- binaryBoolOp(lattice.lessEqualSpecial);
- break;
-
- case BuiltinOperator.NumGt:
- binaryBoolOp(lattice.greaterSpecial);
- break;
-
- case BuiltinOperator.NumGe:
- binaryBoolOp(lattice.greaterEqualSpecial);
- break;
-
- case BuiltinOperator.NumBitNot:
- unaryOp(lattice.bitNotSpecial, typeSystem.uint32Type);
- break;
-
- case BuiltinOperator.NumNegate:
- unaryOp(lattice.negateSpecial, typeSystem.numType);
- break;
-
- case BuiltinOperator.StrictNeq:
- case BuiltinOperator.LooseNeq:
- case BuiltinOperator.IsFalsy:
- case BuiltinOperator.IsNumber:
- case BuiltinOperator.IsNotNumber:
- case BuiltinOperator.IsNotInteger:
- case BuiltinOperator.IsFloor:
- case BuiltinOperator.IsInteger:
- case BuiltinOperator.IsUnsigned32BitInteger:
- case BuiltinOperator.IsNotUnsigned32BitInteger:
- setValue(node, nonConstant(typeSystem.boolType));
- break;
-
- case BuiltinOperator.IsFixedLengthJSArray:
- case BuiltinOperator.IsExtendableJSArray:
- case BuiltinOperator.IsUnmodifiableJSArray:
- case BuiltinOperator.IsModifiableJSArray:
- setValue(node, nonConstant(typeSystem.boolType));
- break;
- }
- }
-
- void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- AbstractConstantValue receiver = getValue(node.receiver);
- if (node.method == BuiltinMethod.Pop) {
- setValue(
- node, nonConstant(typeSystem.elementTypeOfIndexable(receiver.type)));
- } else {
- setValue(node, nonConstant());
- }
- }
-
- void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- if (node.isConstructorBodyCall) {
- setResult(node, lattice.nullValue);
- } else if (node.isTearOff) {
- setResult(node, nonConstant(typeSystem.functionType));
- } else {
- setResult(node, nonConstant(typeSystem.getReturnType(node.target)));
- }
- }
-
- void visitInvokeConstructor(InvokeConstructor node) {
- if (node.allocationSiteType != null) {
- setResult(node, nonConstant(node.allocationSiteType));
- } else {
- setResult(node, nonConstant(typeSystem.getReturnType(node.target)));
- }
- }
-
- void visitThrow(Throw node) {}
-
- void visitRethrow(Rethrow node) {}
-
- void visitUnreachable(Unreachable node) {}
-
- void visitBranch(Branch node) {
- AbstractConstantValue conditionCell = getValue(node.condition);
- AbstractBool boolifiedValue = node.isStrictCheck
- ? lattice.strictBoolify(conditionCell)
- : lattice.boolify(conditionCell);
- switch (boolifiedValue) {
- case AbstractBool.Nothing:
- break;
- case AbstractBool.True:
- setReachable(node.trueContinuation);
- break;
- case AbstractBool.False:
- setReachable(node.falseContinuation);
- break;
- case AbstractBool.Maybe:
- setReachable(node.trueContinuation);
- setReachable(node.falseContinuation);
- break;
- }
- }
-
- void visitTypeTest(TypeTest node) {
- handleTypeTest(node, getValue(node.value), node.dartType);
- }
-
- void visitTypeTestViaFlag(TypeTestViaFlag node) {
- // TODO(sra): We could see if we can find the value in the interceptor
- // expression. It would probably have no benefit - we only see
- // TypeTestViaFlag after rewriting TypeTest and the rewrite of TypeTest
- // would already have done the interesting optimizations.
- setValue(node, nonConstant(typeSystem.boolType));
- }
-
- void handleTypeTest(
- Primitive node, AbstractConstantValue input, types.DartType dartType) {
- TypeMask boolType = typeSystem.boolType;
- switch (lattice.isSubtypeOf(input, dartType, allowNull: false)) {
- case AbstractBool.Nothing:
- break; // And come back later.
-
- case AbstractBool.True:
- setValue(node, constantValue(new TrueConstantValue(), boolType));
- break;
-
- case AbstractBool.False:
- setValue(node, constantValue(new FalseConstantValue(), boolType));
- break;
-
- case AbstractBool.Maybe:
- setValue(node, nonConstant(boolType));
- break;
- }
- }
-
- void visitTypeCast(TypeCast node) {
- AbstractConstantValue input = getValue(node.value);
- switch (lattice.isSubtypeOf(input, node.dartType, allowNull: true)) {
- case AbstractBool.Nothing:
- setValue(node, lattice.nothing);
- break; // And come back later.
-
- case AbstractBool.True:
- setValue(node, input);
- break;
-
- case AbstractBool.False:
- setValue(node, lattice.nothing); // Cast fails.
- break;
-
- case AbstractBool.Maybe:
- // Narrow type of output to those that survive the cast.
- TypeMask type = input.type.intersection(
- typeSystem.subtypesOf(node.dartType).nullable(), classWorld);
- setValue(node, nonConstant(type));
- break;
- }
- }
-
- void visitSetMutable(SetMutable node) {
- setValue(node.variable, getValue(node.value));
- }
-
- void visitLiteralList(LiteralList node) {
- if (node.allocationSiteType != null) {
- setValue(node, nonConstant(node.allocationSiteType));
- } else {
- setValue(node, nonConstant(typeSystem.extendableArrayType));
- }
- }
-
- void visitConstant(Constant node) {
- ConstantValue value = node.value;
- if (value.isDummy || !value.isConstant) {
- // TODO(asgerf): Explain how this happens and why we don't want them.
- setValue(node, nonConstant(typeSystem.getTypeOf(value)));
- } else {
- setValue(node, constantValue(value, typeSystem.getTypeOf(value)));
- }
- }
-
- void visitGetMutable(GetMutable node) {
- setValue(node, getValue(node.variable));
- }
-
- void visitMutableVariable(MutableVariable node) {}
-
- void visitParameter(Parameter node) {}
-
- void visitContinuation(Continuation node) {
- node.parameters.forEach(visit);
-
- if (node.body != null) {
- push(node.body);
- }
- }
-
- void visitGetStatic(GetStatic node) {
- if (node.element.isFunction) {
- setValue(node, nonConstant(typeSystem.functionType));
- } else {
- setValue(node, nonConstant(typeSystem.getFieldType(node.element)));
- }
- }
-
- void visitSetStatic(SetStatic node) {}
-
- void visitGetLazyStatic(GetLazyStatic node) {
- setResult(node, nonConstant(typeSystem.getFieldType(node.element)));
- }
-
- void visitInterceptor(Interceptor node) {
- push(node.input);
- AbstractConstantValue value = getValue(node.input);
- if (value.isNothing) {
- setValue(node, nothing);
- } else if (value.isNullable &&
- !node.interceptedClasses.contains(backend.helpers.jsNullClass)) {
- // If the input is null and null is not mapped to an interceptor then
- // null gets returned.
- // TODO(asgerf): Add the NullInterceptor when it enables us to
- // propagate an assignment.
- setValue(node, nonConstant());
- } else {
- setValue(node, nonConstant(typeSystem.nonNullType));
- }
- }
-
- void visitGetField(GetField node) {
- AbstractConstantValue object = getValue(node.object);
- if (object.isNothing || object.isNullConstant) {
- setValue(node, nothing);
- return;
- }
- node.objectIsNotNull = object.isDefinitelyNotNull;
- if (object.isConstant && object.constant.isConstructedObject) {
- ConstructedConstantValue constructedConstant = object.constant;
- ConstantValue value = constructedConstant.fields[node.field];
- if (value != null) {
- setValue(node, constantValue(value));
- return;
- }
- }
- setValue(node, lattice.fromMask(typeSystem.getFieldType(node.field)));
- }
-
- void visitSetField(SetField node) {}
-
- void visitCreateBox(CreateBox node) {
- setValue(node, nonConstant(typeSystem.nonNullType));
- }
-
- void visitCreateInstance(CreateInstance node) {
- setValue(node,
- nonConstant(typeSystem.nonNullExact(node.classElement.declaration)));
- }
-
- void visitReifyRuntimeType(ReifyRuntimeType node) {
- setValue(node, nonConstant(typeSystem.typeType));
- }
-
- void visitReadTypeVariable(ReadTypeVariable node) {
- // TODO(karlklose): come up with a type marker for JS entities or switch to
- // real constants of type [Type].
- setValue(node, nonConstant());
- }
-
- @override
- void visitTypeExpression(TypeExpression node) {
- // TODO(karlklose): come up with a type marker for JS entities or switch to
- // real constants of type [Type].
- setValue(node, nonConstant());
- }
-
- void visitCreateInvocationMirror(CreateInvocationMirror node) {
- // TODO(asgerf): Expose [Invocation] type.
- setValue(node, nonConstant(typeSystem.nonNullType));
- }
-
- @override
- void visitForeignCode(ForeignCode node) {
- bool firstArgumentIsNullable = false;
- if (node.argumentRefs.length > 0) {
- AbstractConstantValue first =
- getValue(node.argumentRefs.first.definition);
- if (first.isNothing) {
- setValue(node, nothing);
- return;
- }
- firstArgumentIsNullable = first.isNullable;
- }
- setValue(node, nonConstant(node.storedType));
- node.isSafeForElimination =
- !node.nativeBehavior.sideEffects.hasSideEffects() &&
- (!node.nativeBehavior.throwBehavior.canThrow ||
- (!firstArgumentIsNullable &&
- node.nativeBehavior.throwBehavior.isOnlyNullNSMGuard));
- }
-
- @override
- void visitGetLength(GetLength node) {
- AbstractConstantValue input = getValue(node.object);
- node.objectIsNotNull = input.isDefinitelyNotNull;
- AbstractConstantValue length = lattice.lengthSpecial(input);
- if (length != null) {
- // TODO(asgerf): Constant-folding the length might degrade the VM's
- // own bounds-check elimination?
- setValue(node, length);
- } else {
- setValue(node, nonConstant(typeSystem.uint32Type));
- }
- }
-
- @override
- void visitGetIndex(GetIndex node) {
- AbstractConstantValue object = getValue(node.object);
- if (object.isNothing || object.isNullConstant) {
- setValue(node, nothing);
- } else {
- node.objectIsNotNull = object.isDefinitelyNotNull;
- setValue(
- node, nonConstant(typeSystem.elementTypeOfIndexable(object.type)));
- }
- }
-
- @override
- void visitSetIndex(SetIndex node) {}
-
- @override
- void visitAwait(Await node) {
- setResult(node, nonConstant());
- }
-
- @override
- visitYield(Yield node) {
- setValue(node, nonConstant());
- }
-
- @override
- void visitRefinement(Refinement node) {
- setValue(
- node,
- lattice.intersectWithType(
- getValue(node.value.definition), node.refineType));
- }
-
- @override
- void visitBoundsCheck(BoundsCheck node) {
- setValue(node, getValue(node.object));
- }
-
- @override
- void visitReceiverCheck(ReceiverCheck node) {
- AbstractConstantValue value = getValue(node.value);
- if (node.isNullCheck) {
- // Avoid expensive TypeMask operations for null checks.
- setValue(node, lattice.nonNullable(value));
- } else if (value.isConstant &&
- !value.type.needsNoSuchMethodHandling(node.selector, classWorld)) {
- // Preserve constants, unless the check fails for the constant.
- setValue(node, value);
- } else {
- setValue(node,
- nonConstant(typeSystem.receiverTypeFor(node.selector, value.type)));
- }
- }
-}
-
-/// Represents the abstract value of a primitive value at some point in the
-/// program. Abstract values of all kinds have a type [T].
-///
-/// The different kinds of abstract values represents the knowledge about the
-/// constness of the value:
-/// NOTHING: cannot have any value
-/// CONSTANT: is a constant. The value is stored in the [constant] field,
-/// and the type of the constant is in the [type] field.
-/// NONCONST: not a constant, but [type] may hold some information.
-class AbstractConstantValue {
- static const int NOTHING = 0;
- static const int CONSTANT = 1;
- static const int NONCONST = 2;
-
- final int kind;
- final ConstantValue constant;
- final TypeMask type;
-
- AbstractConstantValue._internal(this.kind, this.constant, this.type) {
- assert(kind != CONSTANT || constant != null);
- assert(constant is! SyntheticConstantValue);
- }
-
- AbstractConstantValue.nothing()
- : this._internal(NOTHING, null, new TypeMask.nonNullEmpty());
-
- AbstractConstantValue.constantValue(ConstantValue constant, TypeMask type)
- : this._internal(CONSTANT, constant, type);
-
- factory AbstractConstantValue.nonConstant(TypeMask type) {
- if (type.isEmpty) {
- return new AbstractConstantValue.nothing();
- } else if (type.isNull) {
- return new AbstractConstantValue.constantValue(
- new NullConstantValue(), type);
- } else {
- return new AbstractConstantValue._internal(NONCONST, null, type);
- }
- }
-
- bool get isNothing => (kind == NOTHING);
- bool get isConstant => (kind == CONSTANT);
- bool get isNonConst => (kind == NONCONST);
- bool get isNullConstant => kind == CONSTANT && constant.isNull;
- bool get isTrueConstant => kind == CONSTANT && constant.isTrue;
- bool get isFalseConstant => kind == CONSTANT && constant.isFalse;
- bool get isZeroConstant => kind == CONSTANT && constant.isZero;
- bool get isZeroOrNegativeConstant {
- if (kind != CONSTANT || !constant.isNum) return false;
- PrimitiveConstantValue value = constant;
- return value.primitiveValue <= 0;
- }
-
- bool get isNegativeConstant {
- if (kind != CONSTANT || !constant.isNum) return false;
- PrimitiveConstantValue value = constant;
- return value.primitiveValue < 0;
- }
-
- bool get isNullable => kind != NOTHING && type.isNullable;
- bool get isDefinitelyNotNull => kind == NOTHING || !type.isNullable;
-
- int get hashCode {
- int hash = kind * 31 + constant.hashCode * 59 + type.hashCode * 67;
- return hash & 0x3fffffff;
- }
-
- bool operator ==(AbstractConstantValue that) {
- return that.kind == this.kind &&
- that.constant == this.constant &&
- that.type == this.type;
- }
-
- String toString() {
- switch (kind) {
- case NOTHING:
- return "Nothing";
- case CONSTANT:
- return "Constant: ${constant.toDartText()}: $type";
- case NONCONST:
- return "Non-constant: $type";
- default:
- assert(false);
- }
- return null;
- }
-}
-
-/// Suggested name for a synthesized loop index.
-class LoopIndexEntity extends Entity {
- String get name => 'i';
-}
-
-/// Suggested name for the current element of a list being iterated.
-class LoopItemEntity extends Entity {
- String get name => 'current';
-}
-
-/// Suggested name for the original length of a list, for use in checks
-/// for concurrent modification.
-class OriginalLengthEntity extends Entity {
- String get name => 'length';
-}
-
-class ResetAnalysisInfo extends TrampolineRecursiveVisitor {
- Set<Continuation> reachableContinuations;
- Map<Variable, ConstantValue> values;
-
- ResetAnalysisInfo(this.reachableContinuations, this.values);
-
- void clear(Variable variable) {
- variable.type = null;
- values[variable] = null;
- }
-
- processFunctionDefinition(FunctionDefinition node) {
- clear(node.returnContinuation.parameters.single);
- node.parameters.forEach(clear);
- }
-
- processContinuation(Continuation cont) {
- reachableContinuations.remove(cont);
- cont.parameters.forEach(clear);
- }
-
- processLetPrim(LetPrim node) {
- clear(node.primitive);
- }
-
- processLetMutable(LetMutable node) {
- clear(node.variable);
- }
-}
-
-enum ChecksNeeded {
- /// No check is needed.
- None,
-
- /// Only null may fail the check.
- Null,
-
- /// Full check required.
- Complete,
-}
-
-/// Generates runtime checks against a some type criteria, and determines at
-/// compile-time if the check is needed.
-///
-/// This class only generates the condition for determining if a check should
-/// fail. Throwing the appropriate error in response to a failure is handled
-/// elsewhere.
-abstract class TypeCheckOperator {
- const TypeCheckOperator();
- static const TypeCheckOperator none = const NoTypeCheckOperator();
-
- /// Determines to what extent a runtime check is needed.
- ///
- /// Sometimes a check can be slightly improved if it is known that null is the
- /// only possible input that fails the check.
- ChecksNeeded getChecksNeeded(Primitive value, World world);
-
- /// Make an expression that returns `true` if [value] should fail the check.
- ///
- /// The result should be used in a check of the form:
- ///
- /// if (makeCheck(value)) throw Error(value);
- ///
- Primitive makeCheck(CpsFragment cps, Primitive value);
-
- /// Refine [value] after a succesful check.
- Primitive makeRefinement(CpsFragment cps, Primitive value, World world);
-
- bool needsCheck(Primitive value, World world) {
- return getChecksNeeded(value, world) != ChecksNeeded.None;
- }
-}
-
-/// Check that always passes.
-class NoTypeCheckOperator extends TypeCheckOperator {
- const NoTypeCheckOperator();
-
- ChecksNeeded getChecksNeeded(Primitive value, World world) {
- return ChecksNeeded.None;
- }
-
- Primitive makeCheck(CpsFragment cps, Primitive value) {
- return cps.makeFalse();
- }
-
- Primitive makeRefinement(CpsFragment cps, Primitive value, World world) {
- return value;
- }
-}
-
-/// Checks using a built-in operator that a value is an instance of a given
-/// class.
-class ClassTypeCheckOperator extends TypeCheckOperator {
- ClassElement classElement;
- BuiltinOperator negatedOperator;
-
- ClassTypeCheckOperator(this.classElement, this.negatedOperator);
-
- ChecksNeeded getChecksNeeded(Primitive value, World world) {
- TypeMask type = value.type;
- if (type.satisfies(classElement, world)) {
- return type.isNullable ? ChecksNeeded.Null : ChecksNeeded.None;
- } else {
- return ChecksNeeded.Complete;
- }
- }
-
- Primitive makeCheck(CpsFragment cps, Primitive value) {
- return cps.applyBuiltin(negatedOperator, [value]);
- }
-
- Primitive makeRefinement(CpsFragment cps, Primitive value, World world) {
- return cps.refine(value, new TypeMask.nonNullSubclass(classElement, world));
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/update_refinements.dart b/pkg/compiler/lib/src/cps_ir/update_refinements.dart
deleted file mode 100644
index 20d333f..0000000
--- a/pkg/compiler/lib/src/cps_ir/update_refinements.dart
+++ /dev/null
@@ -1,100 +0,0 @@
-library dart2js.cps_ir.update_refinements;
-
-import '../world.dart';
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart' show Pass;
-import 'type_mask_system.dart';
-
-/// Updates all references to use the most refined version in scope.
-///
-/// [GVN] and [RedundantJoinElimination], and possibly other passes, can create
-/// references that don't use the best refinement in scope. This pass improves
-/// the refinement information.
-///
-//
-// TODO(asgerf): Could be done during GVN for another adjacent pass.
-// It is easier to measure performance and rearrange passes when it has its
-// own pass, but we can merge it with an adjacent pass later.
-//
-class UpdateRefinements extends TrampolineRecursiveVisitor implements Pass {
- String get passName => 'Update refinements';
-
- final TypeMaskSystem typeSystem;
- World get classWorld => typeSystem.classWorld;
-
- Map<Primitive, Primitive> refinementFor = <Primitive, Primitive>{};
-
- UpdateRefinements(this.typeSystem);
-
- void rewrite(FunctionDefinition node) {
- visit(node);
- }
-
- Expression traverseLetPrim(LetPrim node) {
- Expression next = node.body;
- visit(node.primitive);
- return next;
- }
-
- visitReceiverCheck(ReceiverCheck node) {
- if (refine(node.valueRef)) {
- // Update the type if the input has changed.
- Primitive value = node.value;
- if (value.type.needsNoSuchMethodHandling(node.selector, classWorld)) {
- node.type = typeSystem.receiverTypeFor(node.selector, value.type);
- } else {
- // Check is no longer needed.
- node
- ..replaceUsesWith(value)
- ..destroy();
- LetPrim letPrim = node.parent;
- letPrim.remove();
- return;
- }
- }
- // Use the ReceiverCheck as a refinement.
- Primitive value = node.effectiveDefinition;
- Primitive old = refinementFor[value];
- refinementFor[value] = node;
- pushAction(() {
- refinementFor[value] = old;
- });
- }
-
- visitRefinement(Refinement node) {
- if (refine(node.value)) {
- // Update the type if the input has changed.
- node.type =
- typeSystem.intersection(node.value.definition.type, node.refineType);
- }
- Primitive value = node.effectiveDefinition;
- Primitive old = refinementFor[value];
- refinementFor[value] = node;
- pushAction(() {
- refinementFor[value] = old;
- });
- }
-
- visitBoundsCheck(BoundsCheck node) {
- super.visitBoundsCheck(node);
- if (node.hasIntegerCheck && typeSystem.isDefinitelyInt(node.index.type)) {
- node.checks &= ~BoundsCheck.INTEGER;
- }
- }
-
- processReference(Reference ref) {
- refine(ref);
- }
-
- bool refine(Reference ref) {
- Definition def = ref.definition;
- if (def is Primitive) {
- Primitive refinement = refinementFor[def.effectiveDefinition];
- if (refinement != null && refinement != ref.definition) {
- ref.changeTo(refinement);
- return true;
- }
- }
- return false;
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart b/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
deleted file mode 100644
index 6019742..0000000
--- a/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
+++ /dev/null
@@ -1,220 +0,0 @@
-// 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.use_field_initializers;
-
-import '../elements/elements.dart';
-import '../js_backend/js_backend.dart';
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart';
-
-/// Eliminates [SetField] instructions when the value can instead be passed into
-/// the field initializer of a [CreateInstance] instruction.
-///
-/// This compensates for a somewhat common pattern where fields are initialized
-/// in the constructor body instead of using initializers. For example:
-///
-/// class Foo {
-/// var x, y;
-/// Foo(x, y) {
-/// this.x = x;
-/// this.y = y;
-/// }
-/// }
-///
-/// ==> (IR for Foo constructor)
-///
-/// foo = new D.Foo(null, null);
-/// foo.x = 'a';
-/// foo.y = 'b';
-///
-/// ==> (after this pass)
-///
-/// foo = new D.Foo('a', 'b');
-//
-// TODO(asgerf): Store forwarding and load elimination could most likely
-// handle this more generally.
-//
-class UseFieldInitializers extends BlockVisitor implements Pass {
- String get passName => 'Use field initializers';
-
- final JavaScriptBackend backend;
-
- final Set<CreateInstance> unescaped = new Set<CreateInstance>();
-
- /// Continuation bindings separating the current traversal position from an
- /// unescaped [CreateInstance]. When [CreateInstance] is sunk, these
- /// continuations must sink as well to ensure the object remains in scope
- /// inside the bound continuations.
- final List<LetCont> letConts = <LetCont>[];
-
- /// If non-null, the bindings in [letConts] should sink to immediately below
- /// this node.
- InteriorNode letContSinkTarget = null;
- EscapeVisitor escapeVisitor;
-
- UseFieldInitializers(this.backend);
-
- void rewrite(FunctionDefinition node) {
- escapeVisitor = new EscapeVisitor(this);
- BlockVisitor.traverseInPreOrder(node, this);
- }
-
- void escape(Reference ref) {
- Definition def = ref.definition;
- if (def is CreateInstance) {
- unescaped.remove(def);
- if (unescaped.isEmpty) {
- sinkLetConts();
- letConts.clear();
- }
- }
- }
-
- void visitContinuation(Continuation node) {
- endBasicBlock();
- }
-
- void visitLetHandler(LetHandler node) {
- endBasicBlock();
- }
-
- void visitInvokeContinuation(InvokeContinuation node) {
- endBasicBlock();
- }
-
- void visitBranch(Branch node) {
- endBasicBlock();
- }
-
- void visitRethrow(Rethrow node) {
- endBasicBlock();
- }
-
- void visitThrow(Throw node) {
- endBasicBlock();
- }
-
- void visitUnreachable(Unreachable node) {
- endBasicBlock();
- }
-
- void visitLetMutable(LetMutable node) {
- escape(node.valueRef);
- }
-
- void visitLetCont(LetCont node) {
- if (unescaped.isNotEmpty) {
- // Ensure we do not lift a LetCont if there is a sink target set above
- // the current node.
- sinkLetConts();
- letConts.add(node);
- }
- }
-
- void sinkLetConts() {
- if (letContSinkTarget != null) {
- for (LetCont letCont in letConts.reversed) {
- letCont
- ..remove()
- ..insertBelow(letContSinkTarget);
- }
- letContSinkTarget = null;
- }
- }
-
- void endBasicBlock() {
- sinkLetConts();
- letConts.clear();
- unescaped.clear();
- }
-
- void visitLetPrim(LetPrim node) {
- Primitive prim = node.primitive;
- if (prim is CreateInstance) {
- unescaped.add(prim);
- prim.argumentRefs.forEach(escape);
- return;
- }
- if (unescaped.isEmpty) return;
- if (prim is SetField) {
- 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.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.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.
- rebindCreateInstanceAt(object, node);
- letContSinkTarget = node;
- }
- }
- return;
- }
- if (prim is GetField) {
- // 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;
- if (object is CreateInstance && unescaped.contains(object)) {
- int index = getFieldIndex(object.classElement, prim.field);
- if (index == -1) {
- escape(prim.objectRef);
- } else {
- prim.replaceUsesWith(object.argument(index));
- prim.destroy();
- node.remove();
- }
- }
- return;
- }
- escapeVisitor.visit(node.primitive);
- }
-
- void rebindCreateInstanceAt(CreateInstance prim, LetPrim newBinding) {
- removeBinding(prim);
- newBinding.primitive = prim;
- prim.parent = newBinding;
- }
-
- /// Returns the index of [field] in the canonical initialization order in
- /// [classElement], or -1 if the field is not initialized at creation time
- /// for that class.
- int getFieldIndex(ClassElement classElement, FieldElement field) {
- // There is no stored map from a field to its index in a given class, so we
- // have to iterate over all instance fields until we find it.
- int current = -1, index = -1;
- classElement.forEachInstanceField((host, currentField) {
- if (!backend.isNativeOrExtendsNative(host)) {
- ++current;
- if (currentField == field) {
- index = current;
- }
- }
- }, includeSuperAndInjectedMembers: true);
- return index;
- }
-
- void removeBinding(Primitive prim) {
- LetPrim node = prim.parent;
- node.remove();
- }
-}
-
-class EscapeVisitor extends DeepRecursiveVisitor {
- final UseFieldInitializers main;
- EscapeVisitor(this.main);
-
- processReference(Reference ref) {
- main.escape(ref);
- }
-}
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 5efe438..e90f8d8 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -81,7 +81,8 @@
var pattern = new RegExp('^(${patterns.join(")\$|^(")})\$');
Iterator<String> arguments = argv.iterator;
- OUTER: while (arguments.moveNext()) {
+ OUTER:
+ while (arguments.moveNext()) {
String argument = arguments.current;
Match match = pattern.firstMatch(argument);
assert(match.groupCount == handlers.length);
@@ -317,7 +318,6 @@
new OptionHandler(
'--output-type=dart|--output-type=dart-multi|--output-type=js',
setOutputType),
- new OptionHandler(Flags.useCpsIr, passThrough),
new OptionHandler(Flags.noFrequencyBasedMinification, passThrough),
new OptionHandler(Flags.verbose, setVerbose),
new OptionHandler(Flags.version, (_) => wantVersion = true),
@@ -685,9 +685,6 @@
Generates output even if the program contains compile-time errors. Use the
exit code to determine if compilation failed.
- --use-cps-ir
- Experimental. Use the new CPS based backend for code generation.
-
--no-frequency-based-minification
Experimental. Disabled the new frequency based minifying namer and use the
old namer instead.
diff --git a/pkg/compiler/lib/src/dart2js_stress.dart b/pkg/compiler/lib/src/dart2js_stress.dart
index 453d95c..804c577 100644
--- a/pkg/compiler/lib/src/dart2js_stress.dart
+++ b/pkg/compiler/lib/src/dart2js_stress.dart
@@ -33,5 +33,6 @@
}
});
}
+
iterate();
}
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 449a434..723bd9f 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -404,6 +404,7 @@
elements.add(element);
collectDependencies(element);
}
+
ClassElement cls = element.declaration;
cls.forEachLocalMember(addLiveInstanceMember);
if (cls.implementation != cls) {
@@ -460,6 +461,7 @@
iterateTags(library.implementation);
}
}
+
traverseLibrary(root);
result.add(compiler.coreLibrary);
return result;
@@ -872,6 +874,7 @@
}
}
}
+
ast.Node first = firstNode(send);
ast.Node identifier = first.asIdentifier();
if (identifier == null) return null;
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index 8baffd6..e1715744 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -609,7 +609,9 @@
"Cannot resolve '#{name}'.",
howToFix: "Did you mean to add the 'async' marker "
"to the enclosing function?",
- examples: const ["main() { (() => await -3)(); }",]),
+ examples: const [
+ "main() { (() => await -3)(); }",
+ ]),
MessageKind.CANNOT_RESOLVE_IN_INITIALIZER: const MessageTemplate(
MessageKind.CANNOT_RESOLVE_IN_INITIALIZER,
@@ -1996,7 +1998,9 @@
"Cannot assign a value to a type. Note that types are never null, "
"so this ??= assignment has no effect.",
howToFix: "Try removing the '??=' assignment.",
- examples: const ["class A {} main() { print(A ??= 3);}",]),
+ examples: const [
+ "class A {} main() { print(A ??= 3);}",
+ ]),
MessageKind.VOID_NOT_ALLOWED: const MessageTemplate(
MessageKind.VOID_NOT_ALLOWED,
@@ -3085,7 +3089,11 @@
MessageKind.UNMATCHED_TOKEN,
"Can't find '#{end}' to match '#{begin}'.",
howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const ["main(", "main(){", "main(){]}",]),
+ examples: const [
+ "main(",
+ "main(){",
+ "main(){]}",
+ ]),
MessageKind.UNTERMINATED_TOKEN: const MessageTemplate(
MessageKind.UNTERMINATED_TOKEN,
@@ -3209,7 +3217,8 @@
MessageKind.MAIN_WITH_EXTRA_PARAMETER: const MessageTemplate(
MessageKind.MAIN_WITH_EXTRA_PARAMETER,
"'#{main}' cannot have more than two parameters.",
- howToFix: DONT_KNOW_HOW_TO_FIX, /* Don't state the obvious. */
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ /* Don't state the obvious. */
examples: const ['main(a, b, c) {}']),
MessageKind.COMPILER_CRASHED: const MessageTemplate(
diff --git a/pkg/compiler/lib/src/elements/common.dart b/pkg/compiler/lib/src/elements/common.dart
index b3a43ca..2e99eff 100644
--- a/pkg/compiler/lib/src/elements/common.dart
+++ b/pkg/compiler/lib/src/elements/common.dart
@@ -182,19 +182,9 @@
return path.substring(path.lastIndexOf('/') + 1);
}
}
-
- int compareTo(LibraryElement other) {
- if (this == other) return 0;
- return libraryOrScriptName.compareTo(other.libraryOrScriptName);
- }
}
-abstract class CompilationUnitElementCommon implements CompilationUnitElement {
- int compareTo(CompilationUnitElement other) {
- if (this == other) return 0;
- return '${script.readableUri}'.compareTo('${other.script.readableUri}');
- }
-}
+abstract class CompilationUnitElementCommon implements CompilationUnitElement {}
abstract class ClassElementCommon implements ClassElement {
@override
@@ -589,8 +579,8 @@
constructors.forEach(f);
if (mixin != null)
mixin.forEachLocalMember((Element mixedInElement) {
- if (mixedInElement.isInstanceMember) f(mixedInElement);
- });
+ if (mixedInElement.isInstanceMember) f(mixedInElement);
+ });
}
}
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index 67cdd60..e80ea6b 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -693,9 +693,9 @@
/// on the source code order.
static int compareByPosition(Element a, Element b) {
if (identical(a, b)) return 0;
- int r = a.library.compareTo(b.library);
+ int r = _compareLibraries(a.library, b.library);
if (r != 0) return r;
- r = a.compilationUnit.compareTo(b.compilationUnit);
+ r = _compareCompilationUnits(a.compilationUnit, b.compilationUnit);
if (r != 0) return r;
int offsetA = a.sourceOffset ?? -1;
int offsetB = b.sourceOffset ?? -1;
@@ -708,6 +708,62 @@
return a.hashCode.compareTo(b.hashCode);
}
+ // Somewhat stable ordering for [LibraryElement]s
+ static int _compareLibraries(LibraryElement a, LibraryElement b) {
+ if (a == b) return 0;
+
+ int byCanonicalUriPath() {
+ return a.canonicalUri.path.compareTo(b.canonicalUri.path);
+ }
+
+ // Order: platform < package < other.
+ if (a.isPlatformLibrary) {
+ if (b.isPlatformLibrary) return byCanonicalUriPath();
+ return -1;
+ }
+ if (b.isPlatformLibrary) return 1;
+
+ if (a.isPackageLibrary) {
+ if (b.isPackageLibrary) return byCanonicalUriPath();
+ return -1;
+ }
+ if (b.isPackageLibrary) return 1;
+
+ return _compareCanonicalUri(a.canonicalUri, b.canonicalUri);
+ }
+
+ static int _compareCanonicalUri(Uri a, Uri b) {
+ int r = a.scheme.compareTo(b.scheme);
+ if (r != 0) return r;
+
+ // We would like the order of 'file:' Uris to be stable across different
+ // users or different builds from temporary directories. We sort by
+ // pathSegments elements from the last to the first since that tends to find
+ // a stable distinction regardless of directory root.
+ List<String> aSegments = a.pathSegments;
+ List<String> bSegments = b.pathSegments;
+ int aI = aSegments.length;
+ int bI = bSegments.length;
+ while (aI > 0 && bI > 0) {
+ String aSegment = aSegments[--aI];
+ String bSegment = bSegments[--bI];
+ r = aSegment.compareTo(bSegment);
+ if (r != 0) return r;
+ }
+ return aI.compareTo(bI); // Shortest first.
+ }
+
+ static int _compareCompilationUnits(
+ CompilationUnitElement a, CompilationUnitElement b) {
+ if (a == b) return 0;
+ // Compilation units are compared only within the same library so we expect
+ // the Uris to usually be clustered together with a common scheme and path
+ // prefix.
+ Uri aUri = a.script.readableUri;
+ Uri bUri = b.script.readableUri;
+ return '${aUri}'.compareTo('${bUri}');
+ }
+
static List<Element> sortedByPosition(Iterable<Element> elements) {
return elements.toList()..sort(compareByPosition);
}
@@ -841,8 +897,6 @@
Script get script;
void forEachLocalMember(f(Element element));
-
- int compareTo(CompilationUnitElement other);
}
abstract class ImportElement extends Element {
@@ -931,8 +985,6 @@
/// Note: the returned filename is still escaped ("a%20b.dart" instead of
/// "a b.dart").
String get libraryOrScriptName;
-
- int compareTo(LibraryElement other);
}
/// The implicit scope defined by a import declaration with a prefix clause.
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index b8a2987..ded05a0 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -1196,6 +1196,7 @@
f(element);
}
}
+
localMembers.forEach(filterPatch);
} else {
localMembers.forEach(f);
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
index eebe56f..2e554e5 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
@@ -468,6 +468,7 @@
inferrer.recordLocalUpdate(local, type);
}
}
+
if (capturedAndBoxed.containsKey(local)) {
inferrer.recordTypeOfNonFinalField(node, capturedAndBoxed[local], type);
} else if (inTryBlock) {
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index c2956ff..0a6c628 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -10,7 +10,6 @@
import '../compiler.dart' show Compiler;
import '../constants/values.dart' show ConstantValue, IntConstantValue;
import '../core_types.dart' show CoreClasses, CoreTypes;
-import '../cps_ir/cps_ir_nodes.dart' as cps_ir show Node;
import '../dart_types.dart' show DartType;
import '../elements/elements.dart';
import '../js_backend/js_backend.dart' as js;
@@ -259,10 +258,6 @@
// TODO(johnniwinther): Pass the [ResolvedAst] instead of [owner].
void updateSelectorInTree(
AstElement owner, Spannable node, Selector selector, TypeMask mask) {
- if (node is cps_ir.Node) {
- // TODO(lry): update selector for IrInvokeDynamic.
- throw "updateSelector for IR node $node";
- }
ast.Node astNode = node;
TreeElements elements = owner.resolvedAst.elements;
if (astNode.asSendSet() != null) {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index c21b118..0c3fb31 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -10,7 +10,6 @@
import '../common/names.dart' show Identifiers;
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
-import '../cps_ir/cps_ir_nodes.dart' as cps_ir show Node;
import '../dart_types.dart' show DartType, FunctionType, TypeKind;
import '../elements/elements.dart';
import '../tree/dartstring.dart' show DartString;
@@ -390,9 +389,8 @@
* This map contains the callers of [element]. It stores all unique call sites
* to enable counting the global number of call sites of [element].
*
- * A call site is either an AST [ast.Node], a [cps_ir.Node] or in the case of
- * synthesized calls, an [Element] (see uses of [synthesizeForwardingCall]
- * in [SimpleTypeInferrerVisitor]).
+ * A call site is either an AST [ast.Node], an [Element] (see uses of
+ * [synthesizeForwardingCall] in [SimpleTypeInferrerVisitor]).
*
* The global information is summarized in [cleanup], after which [_callers]
* is set to `null`.
@@ -403,7 +401,7 @@
: super._internal(null, element);
void addCall(Element caller, Spannable node) {
- assert(node is ast.Node || node is cps_ir.Node || node is Element);
+ assert(node is ast.Node || node is Element);
_callers ??= <Element, Setlet>{};
_callers.putIfAbsent(caller, () => new Setlet()).add(node);
}
@@ -882,10 +880,12 @@
bool isUInt31(info) {
return info.type.satisfies(uint31Implementation, classWorld);
}
+
bool isPositiveInt(info) {
return info.type
.satisfies(classWorld.backend.positiveIntImplementation, classWorld);
}
+
TypeInformation tryLater() => inferrer.types.nonNullEmptyType;
TypeInformation argument =
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index a70b5d3..eb0b535 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -1074,8 +1074,7 @@
js.Statement translateToStatement(js.Statement node) {
List<js.Statement> statements = translateToStatementSequence(node);
- if (statements.length == 1)
- return statements.single;
+ if (statements.length == 1) return statements.single;
return new js.Block(statements);
}
@@ -1440,7 +1439,7 @@
js.Catch catchPart = (node.catchPart == null)
? null
: new js.Catch(node.catchPart.declaration,
- translateToBlock(node.catchPart.body));
+ translateToBlock(node.catchPart.body));
js.Block finallyPart = (node.finallyPart == null)
? null
: translateToBlock(node.finallyPart);
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 0ab92e4..b79556e 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -68,7 +68,6 @@
import 'backend_impact.dart';
import 'backend_serialization.dart' show JavaScriptBackendSerialization;
import 'checked_mode_helpers.dart';
-import 'codegen/task.dart';
import 'constant_handler_javascript.dart';
import 'custom_elements_analysis.dart';
import 'js_interop_analysis.dart' show JsInteropAnalysis;
@@ -629,9 +628,7 @@
constantCompilerTask = new JavaScriptConstantTask(compiler);
impactTransformer = new JavaScriptImpactTransformer(this);
patchResolverTask = new PatchResolverTask(compiler);
- functionCompiler = compiler.options.useCpsIr
- ? new CpsFunctionCompiler(compiler, this, sourceInformationStrategy)
- : new SsaFunctionCompiler(this, sourceInformationStrategy);
+ functionCompiler = new SsaFunctionCompiler(this, sourceInformationStrategy);
serialization = new JavaScriptBackendSerialization(this);
}
@@ -1203,6 +1200,7 @@
}
return ctor;
}
+
Element getMember(String name) {
// The constructor is on the patch class, but dart2js unit tests don't
// have a patch class.
@@ -1216,6 +1214,7 @@
}
return element;
}
+
helpers.mapLiteralConstructor = getFactory('_literal', 1);
helpers.mapLiteralConstructorEmpty = getFactory('_empty', 0);
enqueueInResolution(helpers.mapLiteralConstructor, registry);
@@ -2582,17 +2581,7 @@
}
@override
- bool enableCodegenWithErrorsIfSupported(Spannable node) {
- if (compiler.options.useCpsIr) {
- // TODO(25747): Support code generation with compile-time errors.
- reporter.reportHintMessage(node, MessageKind.GENERIC, {
- 'text': "Generation of code with compile time errors is currently "
- "not supported with the CPS IR."
- });
- return false;
- }
- return true;
- }
+ bool enableCodegenWithErrorsIfSupported(Spannable node) => true;
jsAst.Expression rewriteAsync(
FunctionElement element, jsAst.Expression code) {
diff --git a/pkg/compiler/lib/src/js_backend/backend_helpers.dart b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
index b9e011d..3852e2f 100644
--- a/pkg/compiler/lib/src/js_backend/backend_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
@@ -245,6 +245,7 @@
}
return result;
}
+
jsInvocationMirrorClass = lookupHelperClass('JSInvocationMirror');
boundClosureClass = lookupHelperClass('BoundClosure');
closureClass = lookupHelperClass('Closure');
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
deleted file mode 100644
index add58ce..0000000
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ /dev/null
@@ -1,1240 +0,0 @@
-// 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 code_generator;
-
-import '../../closure.dart' show ClosureClassElement;
-import '../../common/codegen.dart' show CodegenRegistry;
-import '../../constants/values.dart';
-import '../../dart_types.dart';
-import '../../elements/elements.dart';
-import '../../io/source_information.dart' show SourceInformation;
-import '../../js/js.dart' as js;
-import '../../tree_ir/tree_ir_nodes.dart' as tree_ir;
-import '../../tree_ir/tree_ir_nodes.dart'
- show BuiltinMethod, BuiltinOperator, isCompoundableOperator;
-import '../../types/types.dart' show TypeMask;
-import '../../universe/call_structure.dart' show CallStructure;
-import '../../universe/selector.dart' show Selector;
-import '../../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
-import '../../util/maplet.dart';
-import 'glue.dart';
-
-class CodegenBailout {
- final tree_ir.Node node;
- final String reason;
- CodegenBailout(this.node, this.reason);
- String get message {
- return 'bailout${node != null ? " on $node" : ""}: $reason';
- }
-}
-
-class CodeGenerator extends tree_ir.StatementVisitor
- with tree_ir.ExpressionVisitor<js.Expression> {
- final CodegenRegistry registry;
-
- final Glue glue;
-
- ExecutableElement currentFunction;
-
- /// Maps variables to their name.
- Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{};
-
- /// Maps local constants to their name.
- Maplet<VariableElement, String> constantNames =
- new Maplet<VariableElement, String>();
-
- /// Variable names that have already been used. Used to avoid name clashes.
- Set<String> usedVariableNames = new Set<String>();
-
- final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack();
-
- /// Stacks whose top element is the current target of an unlabeled break
- /// or continue. For continues, this is the loop node itself.
- final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack();
- final tree_ir.FallthroughStack shortContinue = new tree_ir.FallthroughStack();
-
- /// When the top element is true, [Unreachable] statements will be emitted
- /// as [Return]s, otherwise they are emitted as empty because they are
- /// followed by the end of the method.
- ///
- /// Note on why the [fallthrough] stack should not be used for this:
- /// Ordinary statements may choose whether to use the [fallthrough] target,
- /// and the choice to do so may disable an optimization in [visitIf].
- /// But omitting an unreachable 'return' should have lower priority than
- /// the optimizations in [visitIf], so [visitIf] will instead tell the
- /// [Unreachable] statements whether they may use fallthrough or not.
- List<bool> emitUnreachableAsReturn = <bool>[false];
-
- final Map<tree_ir.Label, String> labelNames = <tree_ir.Label, String>{};
-
- List<js.Statement> accumulator = new List<js.Statement>();
-
- CodeGenerator(this.glue, this.registry);
-
- /// Generates JavaScript code for the body of [function].
- js.Fun buildFunction(tree_ir.FunctionDefinition function) {
- registerDefaultParameterValues(function.element);
- currentFunction = function.element;
- tree_ir.Statement statement = function.body;
- while (statement != null) {
- statement = visitStatement(statement);
- }
-
- List<js.Parameter> parameters = new List<js.Parameter>();
- Set<tree_ir.Variable> parameterSet = new Set<tree_ir.Variable>();
- Set<String> declaredVariables = new Set<String>();
-
- for (tree_ir.Variable parameter in function.parameters) {
- String name = getVariableName(parameter);
- parameters.add(new js.Parameter(name));
- parameterSet.add(parameter);
- declaredVariables.add(name);
- }
-
- List<js.VariableInitialization> jsVariables = <js.VariableInitialization>[];
-
- // Declare variables with an initializer. Pull statements into the
- // initializer until we find a statement that cannot be pulled in.
- int accumulatorIndex = 0;
- while (accumulatorIndex < accumulator.length) {
- js.Node node = accumulator[accumulatorIndex];
-
- // Check that node is an assignment to a local variable.
- if (node is! js.ExpressionStatement) break;
- js.ExpressionStatement stmt = node;
- if (stmt.expression is! js.Assignment) break;
- js.Assignment assign = stmt.expression;
- if (assign.leftHandSide is! js.VariableUse) break;
- if (assign.op != null) break; // Compound assignment.
- js.VariableUse use = assign.leftHandSide;
-
- // Do not touch non-local variables.
- if (!usedVariableNames.contains(use.name)) break;
-
- // We cannot declare a variable more than once.
- if (!declaredVariables.add(use.name)) break;
-
- js.VariableInitialization jsVariable = new js.VariableInitialization(
- new js.VariableDeclaration(use.name), assign.value);
- jsVariables.add(jsVariable);
-
- ++accumulatorIndex;
- }
-
- // If the last statement is a for loop with an initializer expression, try
- // to pull that expression into an initializer as well.
- pullFromForLoop: if (accumulatorIndex < accumulator.length &&
- accumulator[accumulatorIndex] is js.For) {
- js.For forLoop = accumulator[accumulatorIndex];
- if (forLoop.init is! js.Assignment) break pullFromForLoop;
- js.Assignment assign = forLoop.init;
- if (assign.leftHandSide is! js.VariableUse) break pullFromForLoop;
- if (assign.op != null) break pullFromForLoop; // Compound assignment.
- js.VariableUse use = assign.leftHandSide;
-
- // Do not touch non-local variables.
- if (!usedVariableNames.contains(use.name)) break pullFromForLoop;
-
- // We cannot declare a variable more than once.
- if (!declaredVariables.add(use.name)) break pullFromForLoop;
-
- js.VariableInitialization jsVariable = new js.VariableInitialization(
- new js.VariableDeclaration(use.name), assign.value);
- jsVariables.add(jsVariable);
-
- // Remove the initializer from the for loop.
- accumulator[accumulatorIndex] =
- new js.For(null, forLoop.condition, forLoop.update, forLoop.body);
- }
-
- // Discard the statements that were pulled in the initializer.
- if (accumulatorIndex > 0) {
- accumulator = accumulator.sublist(accumulatorIndex);
- }
-
- // Declare remaining variables.
- for (tree_ir.Variable variable in variableNames.keys) {
- String name = getVariableName(variable);
- if (declaredVariables.contains(name)) continue;
- js.VariableInitialization jsVariable =
- new js.VariableInitialization(new js.VariableDeclaration(name), null);
- jsVariables.add(jsVariable);
- }
-
- if (jsVariables.length > 0) {
- // Would be nice to avoid inserting at the beginning of list.
- accumulator.insert(
- 0,
- new js.ExpressionStatement(new js.VariableDeclarationList(jsVariables)
- .withSourceInformation(function.sourceInformation)));
- }
- return new js.Fun(parameters, new js.Block(accumulator));
- }
-
- @override
- js.Expression visitExpression(tree_ir.Expression node) {
- js.Expression result = node.accept(this);
- if (result == null) {
- glue.reportInternalError('$node did not produce code.');
- }
- return result;
- }
-
- /// Generates a name for the given variable. First trying with the name of
- /// the [Variable.element] if it is non-null.
- String getVariableName(tree_ir.Variable variable) {
- // Functions are not nested in the JS backend.
- assert(variable.host == currentFunction);
-
- // Get the name if we already have one.
- String name = variableNames[variable];
- if (name != null) {
- return name;
- }
-
- // Synthesize a variable name that isn't used elsewhere.
- String prefix = variable.element == null ? 'v' : variable.element.name;
- int counter = 0;
- name = glue.safeVariableName(
- variable.element == null ? '$prefix$counter' : variable.element.name);
- while (!usedVariableNames.add(name)) {
- ++counter;
- name = '$prefix$counter';
- }
- variableNames[variable] = name;
-
- return name;
- }
-
- List<js.Expression> visitExpressionList(
- List<tree_ir.Expression> expressions) {
- List<js.Expression> result = new List<js.Expression>(expressions.length);
- for (int i = 0; i < expressions.length; ++i) {
- result[i] = visitExpression(expressions[i]);
- }
- return result;
- }
-
- giveup(tree_ir.Node node,
- [String reason = 'unimplemented in CodeGenerator']) {
- throw new CodegenBailout(node, reason);
- }
-
- @override
- js.Expression visitConditional(tree_ir.Conditional node) {
- return new js.Conditional(
- visitExpression(node.condition),
- visitExpression(node.thenExpression),
- visitExpression(node.elseExpression));
- }
-
- js.Expression buildConstant(ConstantValue constant,
- {SourceInformation sourceInformation}) {
- registry.registerCompileTimeConstant(constant);
- return glue
- .constantReference(constant)
- .withSourceInformation(sourceInformation);
- }
-
- @override
- js.Expression visitConstant(tree_ir.Constant node) {
- return buildConstant(node.value, sourceInformation: node.sourceInformation);
- }
-
- js.Expression buildStaticInvoke(Element target, List<js.Expression> arguments,
- {SourceInformation sourceInformation}) {
- if (target.isConstructor) {
- // TODO(johnniwinther): Avoid dependency on [isGenerativeConstructor] by
- // using backend-specific [StatisUse] classes.
- registry.registerStaticUse(new StaticUse.constructorInvoke(
- target.declaration, new CallStructure.unnamed(arguments.length)));
- } else {
- registry.registerStaticUse(new StaticUse.staticInvoke(
- target.declaration, new CallStructure.unnamed(arguments.length)));
- }
- js.Expression elementAccess = glue.staticFunctionAccess(target);
- return new js.Call(elementAccess, arguments,
- sourceInformation: sourceInformation);
- }
-
- @override
- js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) {
- if (node.constant != null) return giveup(node);
-
- registry.registerInstantiation(node.type);
- FunctionElement target = node.target;
- List<js.Expression> arguments = visitExpressionList(node.arguments);
- return buildStaticInvoke(target, arguments,
- sourceInformation: node.sourceInformation);
- }
-
- void registerMethodInvoke(Selector selector, TypeMask receiverType) {
- registry.registerDynamicUse(new DynamicUse(selector, receiverType));
- if (!selector.isGetter && !selector.isSetter) {
- // TODO(sigurdm): We should find a better place to register the call.
- Selector call = new Selector.callClosureFrom(selector);
- registry.registerDynamicUse(new DynamicUse(call, null));
- }
- }
-
- @override
- js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) {
- TypeMask mask = glue.extendMaskIfReachesAll(node.selector, node.mask);
- registerMethodInvoke(node.selector, mask);
- return js
- .propertyCall(
- visitExpression(node.receiver),
- glue.invocationName(node.selector),
- visitExpressionList(node.arguments))
- .withSourceInformation(node.sourceInformation);
- }
-
- @override
- js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) {
- FunctionElement target = node.target;
- List<js.Expression> arguments = visitExpressionList(node.arguments);
- return buildStaticInvoke(target, arguments,
- sourceInformation: node.sourceInformation);
- }
-
- @override
- js.Expression visitInvokeMethodDirectly(tree_ir.InvokeMethodDirectly node) {
- if (node.isTearOff) {
- // If this is a tear-off, register the fact that a tear-off closure
- // will be created, and that this tear-off must bypass ordinary
- // dispatch to ensure the super method is invoked.
- registry.registerStaticUse(new StaticUse.staticInvoke(
- glue.closureFromTearOff,
- new CallStructure.unnamed(
- glue.closureFromTearOff.parameters.length)));
- registry.registerStaticUse(new StaticUse.superTearOff(node.target));
- }
- if (node.target is ConstructorBodyElement) {
- registry.registerStaticUse(new StaticUse.constructorBodyInvoke(
- node.target.declaration,
- new CallStructure.unnamed(node.arguments.length)));
- // A constructor body cannot be overriden or intercepted, so we can
- // use the short form for this invocation.
- return js.js('#.#(#)', [
- visitExpression(node.receiver),
- glue.instanceMethodName(node.target),
- visitExpressionList(node.arguments)
- ]).withSourceInformation(node.sourceInformation);
- }
- registry.registerStaticUse(new StaticUse.superInvoke(
- node.target.declaration,
- new CallStructure.unnamed(node.arguments.length)));
- return js.js('#.#.call(#, #)', [
- glue.prototypeAccess(node.target.enclosingClass),
- glue.invocationName(node.selector),
- visitExpression(node.receiver),
- visitExpressionList(node.arguments)
- ]).withSourceInformation(node.sourceInformation);
- }
-
- @override
- js.Expression visitOneShotInterceptor(tree_ir.OneShotInterceptor node) {
- registerMethodInvoke(node.selector, node.mask);
- registry.registerUseInterceptor();
- return js.js('#.#(#)', [
- glue.getInterceptorLibrary(),
- glue.registerOneShotInterceptor(node.selector),
- visitExpressionList(node.arguments)
- ]).withSourceInformation(node.sourceInformation);
- }
-
- @override
- js.Expression visitLiteralList(tree_ir.LiteralList node) {
- registry.registerInstantiatedClass(glue.listClass);
- List<js.Expression> entries = visitExpressionList(node.values);
- return new js.ArrayInitializer(entries);
- }
-
- @override
- js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) {
- return new js.Binary(
- node.operator, visitExpression(node.left), visitExpression(node.right));
- }
-
- @override
- js.Expression visitNot(tree_ir.Not node) {
- return new js.Prefix("!", visitExpression(node.operand));
- }
-
- @override
- js.Expression visitThis(tree_ir.This node) {
- return new js.This();
- }
-
- /// Ensure that 'instanceof' checks may be performed against [class_].
- ///
- /// Even if the class is never instantiated, a JS constructor must be emitted
- /// so the 'instanceof' expression does not throw an exception at runtime.
- bool tryRegisterInstanceofCheck(ClassElement class_) {
- if (glue.classWorld.isInstantiated(class_)) {
- // Ensure the class remains instantiated during backend tree-shaking.
- // TODO(asgerf): We could have a more precise hook to inform the emitter
- // that the JS constructor function is needed, without the class being
- // instantiated.
- registry.registerInstantiatedClass(class_);
- return true;
- }
- // Will throw if the JS constructor is not emitted, so do not allow the
- // instanceof check. This should only happen when certain optimization
- // passes are disabled, as the type check itself is trivial.
- return false;
- }
-
- @override
- js.Expression visitTypeOperator(tree_ir.TypeOperator node) {
- js.Expression value = visitExpression(node.value);
- List<js.Expression> typeArguments = visitExpressionList(node.typeArguments);
- DartType type = node.type;
- if (type is InterfaceType) {
- registry.registerTypeUse(new TypeUse.isCheck(type));
- ClassElement clazz = type.element;
-
- if (glue.isStringClass(clazz)) {
- if (node.isTypeTest) {
- return js.js(r'typeof # === "string"', <js.Expression>[value]);
- }
- // TODO(sra): Implement fast cast via calling 'stringTypeCast'.
- } else if (glue.isBoolClass(clazz)) {
- if (node.isTypeTest) {
- return js.js(r'typeof # === "boolean"', <js.Expression>[value]);
- }
- // TODO(sra): Implement fast cast via calling 'boolTypeCast'.
- } else if (node.isTypeTest &&
- node.typeArguments.isEmpty &&
- glue.mayGenerateInstanceofCheck(type) &&
- tryRegisterInstanceofCheck(clazz)) {
- return js.js('# instanceof #', [value, glue.constructorAccess(clazz)]);
- }
-
- // The helper we use needs the JSArray class to exist, but for some
- // reason the helper does not cause this dependency to be registered.
- // TODO(asgerf): Most programs need List anyway, but we should fix this.
- registry.registerInstantiatedClass(glue.listClass);
-
- // We use one of the two helpers:
- //
- // checkSubtype(value, $isT, typeArgs, $asT)
- // subtypeCast(value, $isT, typeArgs, $asT)
- //
- // Any of the last two arguments may be null if there are no type
- // arguments, and/or if no substitution is required.
- Element function =
- node.isTypeTest ? glue.getCheckSubtype() : glue.getSubtypeCast();
-
- js.Expression isT = js.quoteName(glue.getTypeTestTag(type));
-
- js.Expression typeArgumentArray = typeArguments.isNotEmpty
- ? new js.ArrayInitializer(typeArguments)
- : new js.LiteralNull();
-
- js.Expression asT = glue.hasStrictSubtype(clazz)
- ? js.quoteName(glue.getTypeSubstitutionTag(clazz))
- : new js.LiteralNull();
-
- return buildStaticHelperInvocation(
- function, <js.Expression>[value, isT, typeArgumentArray, asT]);
- } else if (type is TypeVariableType || type is FunctionType) {
- registry.registerTypeUse(new TypeUse.isCheck(type));
-
- Element function = node.isTypeTest
- ? glue.getCheckSubtypeOfRuntimeType()
- : glue.getSubtypeOfRuntimeTypeCast();
-
- // The only type argument is the type held in the type variable.
- js.Expression typeValue = typeArguments.single;
-
- return buildStaticHelperInvocation(
- function, <js.Expression>[value, typeValue]);
- }
- return giveup(node, 'type check unimplemented for $type.');
- }
-
- @override
- js.Expression visitGetTypeTestProperty(tree_ir.GetTypeTestProperty node) {
- js.Expression object = visitExpression(node.object);
- DartType dartType = node.dartType;
- assert(dartType.isInterfaceType);
- registry.registerTypeUse(new TypeUse.isCheck(dartType));
- //glue.registerIsCheck(dartType, registry);
- js.Expression property = glue.getTypeTestTag(dartType);
- return js.js(r'#.#', [object, property]);
- }
-
- @override
- js.Expression visitVariableUse(tree_ir.VariableUse node) {
- return buildVariableAccess(node.variable)
- .withSourceInformation(node.sourceInformation);
- }
-
- js.Expression buildVariableAccess(tree_ir.Variable variable) {
- return new js.VariableUse(getVariableName(variable));
- }
-
- /// Returns the JS operator for the given built-in operator for use in a
- /// compound assignment (not including the '=' sign).
- String getAsCompoundOperator(BuiltinOperator operator) {
- switch (operator) {
- case BuiltinOperator.NumAdd:
- case BuiltinOperator.StringConcatenate:
- return '+';
- case BuiltinOperator.NumSubtract:
- return '-';
- case BuiltinOperator.NumMultiply:
- return '*';
- case BuiltinOperator.NumDivide:
- return '/';
- case BuiltinOperator.NumRemainder:
- return '%';
- default:
- throw 'Not a compoundable operator: $operator';
- }
- }
-
- bool isCompoundableBuiltin(tree_ir.Expression exp) {
- return exp is tree_ir.ApplyBuiltinOperator &&
- exp.arguments.length == 2 &&
- isCompoundableOperator(exp.operator);
- }
-
- bool isOneConstant(tree_ir.Expression exp) {
- return exp is tree_ir.Constant && exp.value.isOne;
- }
-
- js.Expression makeAssignment(js.Expression leftHand, tree_ir.Expression value,
- {SourceInformation sourceInformation, BuiltinOperator compound}) {
- if (isOneConstant(value)) {
- if (compound == BuiltinOperator.NumAdd) {
- return new js.Prefix('++', leftHand)
- .withSourceInformation(sourceInformation);
- }
- if (compound == BuiltinOperator.NumSubtract) {
- return new js.Prefix('--', leftHand)
- .withSourceInformation(sourceInformation);
- }
- }
- if (compound != null) {
- return new js.Assignment.compound(
- leftHand, getAsCompoundOperator(compound), visitExpression(value))
- .withSourceInformation(sourceInformation);
- }
- return new js.Assignment(leftHand, visitExpression(value))
- .withSourceInformation(sourceInformation);
- }
-
- @override
- js.Expression visitAssign(tree_ir.Assign node) {
- js.Expression variable = buildVariableAccess(node.variable);
- if (isCompoundableBuiltin(node.value)) {
- tree_ir.ApplyBuiltinOperator rhs = node.value;
- tree_ir.Expression left = rhs.arguments[0];
- tree_ir.Expression right = rhs.arguments[1];
- if (left is tree_ir.VariableUse && left.variable == node.variable) {
- return makeAssignment(variable, right,
- compound: rhs.operator, sourceInformation: node.sourceInformation);
- }
- }
- return makeAssignment(variable, node.value,
- sourceInformation: node.sourceInformation);
- }
-
- @override
- void visitContinue(tree_ir.Continue node) {
- tree_ir.Statement next = fallthrough.target;
- if (node.target.binding == next ||
- next is tree_ir.Continue && node.target == next.target) {
- // Fall through to continue target or to equivalent continue.
- fallthrough.use();
- } else if (node.target.binding == shortContinue.target) {
- // The target is the immediately enclosing loop.
- shortContinue.use();
- accumulator.add(new js.Continue(null));
- } else {
- accumulator.add(new js.Continue(makeLabel(node.target)));
- }
- }
-
- /// True if [other] is the target of [node] or is a [Break] with the same
- /// target. This means jumping to [other] is equivalent to executing [node].
- bool isEffectiveBreakTarget(tree_ir.Break node, tree_ir.Statement other) {
- return node.target.binding.next == other ||
- other is tree_ir.Break && node.target == other.target;
- }
-
- /// True if the given break is equivalent to an unlabeled continue.
- bool isShortContinue(tree_ir.Break node) {
- tree_ir.Statement next = node.target.binding.next;
- return next is tree_ir.Continue &&
- next.target.binding == shortContinue.target;
- }
-
- @override
- void visitBreak(tree_ir.Break node) {
- if (isEffectiveBreakTarget(node, fallthrough.target)) {
- // Fall through to break target or to equivalent break.
- fallthrough.use();
- } else if (isEffectiveBreakTarget(node, shortBreak.target)) {
- // Unlabeled break to the break target or to an equivalent break.
- shortBreak.use();
- accumulator.add(new js.Break(null));
- } else if (isShortContinue(node)) {
- // An unlabeled continue is better than a labeled break.
- shortContinue.use();
- accumulator.add(new js.Continue(null));
- } else {
- accumulator.add(new js.Break(makeLabel(node.target)));
- }
- }
-
- @override
- visitExpressionStatement(tree_ir.ExpressionStatement node) {
- js.Expression exp = visitExpression(node.expression);
- if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) {
- // Emit as 'return exp' to assist local analysis in the VM.
- SourceInformation sourceInformation = node.expression.sourceInformation;
- accumulator
- .add(new js.Return(exp).withSourceInformation(sourceInformation));
- return null;
- } else {
- accumulator.add(new js.ExpressionStatement(exp));
- return node.next;
- }
- }
-
- bool isNullReturn(tree_ir.Statement node) {
- return node is tree_ir.Return && isNull(node.value);
- }
-
- bool isEndOfMethod(tree_ir.Statement node) {
- return isNullReturn(node) ||
- node is tree_ir.Break && isNullReturn(node.target.binding.next);
- }
-
- @override
- visitIf(tree_ir.If node) {
- js.Expression condition = visitExpression(node.condition);
- int usesBefore = fallthrough.useCount;
- // Unless the 'else' part ends the method. make sure to terminate any
- // uncompletable code paths in the 'then' part.
- emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement));
- js.Statement thenBody = buildBodyStatement(node.thenStatement);
- emitUnreachableAsReturn.removeLast();
- bool thenHasFallthrough = (fallthrough.useCount > usesBefore);
- if (thenHasFallthrough) {
- js.Statement elseBody = buildBodyStatement(node.elseStatement);
- accumulator.add(new js.If(condition, thenBody, elseBody)
- .withSourceInformation(node.sourceInformation));
- return null;
- } else {
- // The 'then' body cannot complete normally, so emit a short 'if'
- // and put the 'else' body after it.
- accumulator.add(new js.If.noElse(condition, thenBody)
- .withSourceInformation(node.sourceInformation));
- return node.elseStatement;
- }
- }
-
- @override
- visitLabeledStatement(tree_ir.LabeledStatement node) {
- fallthrough.push(node.next);
- js.Statement body = buildBodyStatement(node.body);
- fallthrough.pop();
- accumulator.add(insertLabel(node.label, body));
- return node.next;
- }
-
- /// Creates a name for [label] if it does not already have one.
- ///
- /// This also marks the label as being used.
- String makeLabel(tree_ir.Label label) {
- return labelNames.putIfAbsent(label, () => 'L${labelNames.length}');
- }
-
- /// Wraps a node in a labeled statement unless the label is unused.
- js.Statement insertLabel(tree_ir.Label label, js.Statement node) {
- String name = labelNames[label];
- if (name == null) return node; // Label is unused.
- return new js.LabeledStatement(name, node);
- }
-
- /// Returns the current [accumulator] wrapped in a block if neccessary.
- js.Statement _bodyAsStatement() {
- if (accumulator.length == 0) {
- return new js.EmptyStatement();
- }
- if (accumulator.length == 1) {
- return accumulator.single;
- }
- return new js.Block(accumulator);
- }
-
- /// Builds a nested statement.
- js.Statement buildBodyStatement(tree_ir.Statement statement) {
- List<js.Statement> savedAccumulator = accumulator;
- accumulator = <js.Statement>[];
- while (statement != null) {
- statement = visitStatement(statement);
- }
- js.Statement result = _bodyAsStatement();
- accumulator = savedAccumulator;
- return result;
- }
-
- js.Block buildBodyBlock(tree_ir.Statement statement) {
- List<js.Statement> savedAccumulator = accumulator;
- accumulator = <js.Statement>[];
- while (statement != null) {
- statement = visitStatement(statement);
- }
- js.Statement result = new js.Block(accumulator);
- accumulator = savedAccumulator;
- return result;
- }
-
- js.Expression makeSequence(List<tree_ir.Expression> list) {
- return list.map(visitExpression).reduce((x, y) => new js.Binary(',', x, y));
- }
-
- @override
- visitFor(tree_ir.For node) {
- js.Expression condition = visitExpression(node.condition);
- shortBreak.push(node.next);
- shortContinue.push(node);
- fallthrough.push(node);
- emitUnreachableAsReturn.add(true);
- js.Statement body = buildBodyStatement(node.body);
- emitUnreachableAsReturn.removeLast();
- fallthrough.pop();
- shortContinue.pop();
- shortBreak.pop();
- js.Statement loopNode;
- if (node.updates.isEmpty) {
- loopNode = new js.While(condition, body);
- } else {
- // Compile as a for loop.
- js.Expression init;
- if (accumulator.isNotEmpty &&
- accumulator.last is js.ExpressionStatement) {
- // Take the preceding expression from the accumulator and use
- // it as the initializer expression.
- js.ExpressionStatement initStmt = accumulator.removeLast();
- init = initStmt.expression;
- }
- js.Expression update = makeSequence(node.updates);
- loopNode = new js.For(init, condition, update, body);
- }
- accumulator.add(insertLabel(node.label, loopNode));
- return node.next;
- }
-
- @override
- void visitWhileTrue(tree_ir.WhileTrue node) {
- // A short break in the while will jump to the current fallthrough target.
- shortBreak.push(fallthrough.target);
- shortContinue.push(node);
- fallthrough.push(node);
- emitUnreachableAsReturn.add(true);
- js.Statement jsBody = buildBodyStatement(node.body);
- emitUnreachableAsReturn.removeLast();
- fallthrough.pop();
- shortContinue.pop();
- if (shortBreak.useCount > 0) {
- // Short breaks use the current fallthrough target.
- fallthrough.use();
- }
- shortBreak.pop();
- accumulator
- .add(insertLabel(node.label, new js.For(null, null, null, jsBody)));
- }
-
- bool isNull(tree_ir.Expression node) {
- return node is tree_ir.Constant && node.value.isNull;
- }
-
- @override
- void visitReturn(tree_ir.Return node) {
- if (isNull(node.value) && fallthrough.target == null) {
- // Do nothing. Implicitly return JS undefined by falling over the end.
- registry.registerCompileTimeConstant(new NullConstantValue());
- fallthrough.use();
- } else {
- accumulator.add(new js.Return(visitExpression(node.value))
- .withSourceInformation(node.sourceInformation));
- }
- }
-
- @override
- void visitThrow(tree_ir.Throw node) {
- accumulator.add(new js.Throw(visitExpression(node.value)));
- }
-
- @override
- void visitUnreachable(tree_ir.Unreachable node) {
- if (emitUnreachableAsReturn.last) {
- // Emit a return to assist local analysis in the VM.
- accumulator.add(new js.Return());
- }
- }
-
- @override
- void visitTry(tree_ir.Try node) {
- js.Block tryBlock = buildBodyBlock(node.tryBody);
- tree_ir.Variable exceptionVariable = node.catchParameters.first;
- js.VariableDeclaration exceptionParameter =
- new js.VariableDeclaration(getVariableName(exceptionVariable));
- js.Block catchBlock = buildBodyBlock(node.catchBody);
- js.Catch catchPart = new js.Catch(exceptionParameter, catchBlock);
- accumulator.add(new js.Try(tryBlock, catchPart, null));
- }
-
- @override
- js.Expression visitCreateBox(tree_ir.CreateBox node) {
- return new js.ObjectInitializer(const <js.Property>[]);
- }
-
- @override
- js.Expression visitCreateInstance(tree_ir.CreateInstance node) {
- ClassElement classElement = node.classElement;
- // TODO(asgerf): To allow inlining of InvokeConstructor, CreateInstance must
- // carry a DartType so we can register the instantiated type
- // with its type arguments. Otherwise dataflow analysis is
- // needed to reconstruct the instantiated type.
- registry.registerInstantiation(classElement.rawType);
- if (classElement is ClosureClassElement) {
- registry.registerInstantiatedClosure(classElement.methodElement);
- }
- js.Expression instance = new js.New(glue.constructorAccess(classElement),
- visitExpressionList(node.arguments))
- .withSourceInformation(node.sourceInformation);
-
- tree_ir.Expression typeInformation = node.typeInformation;
- if (typeInformation != null) {
- FunctionElement helper = glue.getAddRuntimeTypeInformation();
- js.Expression typeArguments = visitExpression(typeInformation);
- return buildStaticHelperInvocation(
- helper, <js.Expression>[instance, typeArguments],
- sourceInformation: node.sourceInformation);
- } else {
- return instance;
- }
- }
-
- @override
- js.Expression visitCreateInvocationMirror(
- tree_ir.CreateInvocationMirror node) {
- js.Expression name = js.string(node.selector.name);
- js.Expression internalName =
- js.quoteName(glue.invocationName(node.selector));
- js.Expression kind = js.number(node.selector.invocationMirrorKind);
- js.Expression arguments =
- new js.ArrayInitializer(visitExpressionList(node.arguments));
- js.Expression argumentNames = new js.ArrayInitializer(
- node.selector.namedArguments.map(js.string).toList(growable: false));
- return buildStaticHelperInvocation(glue.createInvocationMirrorMethod,
- <js.Expression>[name, internalName, kind, arguments, argumentNames]);
- }
-
- @override
- js.Expression visitInterceptor(tree_ir.Interceptor node) {
- registry.registerUseInterceptor();
- // Default to all intercepted classes if they have not been computed.
- // This is to ensure we can run codegen without prior optimization passes.
- Set<ClassElement> interceptedClasses = node.interceptedClasses.isEmpty
- ? glue.interceptedClasses
- : node.interceptedClasses;
- registry.registerSpecializedGetInterceptor(interceptedClasses);
- js.Name helperName = glue.getInterceptorName(interceptedClasses);
- js.Expression globalHolder = glue.getInterceptorLibrary();
- return js.js('#.#(#)', [
- globalHolder,
- helperName,
- visitExpression(node.input)
- ]).withSourceInformation(node.sourceInformation);
- }
-
- @override
- js.Expression visitGetField(tree_ir.GetField node) {
- registry.registerStaticUse(new StaticUse.fieldGet(node.field));
- return new js.PropertyAccess(visitExpression(node.object),
- glue.instanceFieldPropertyName(node.field))
- .withSourceInformation(node.sourceInformation);
- }
-
- @override
- js.Expression visitSetField(tree_ir.SetField node) {
- registry.registerStaticUse(new StaticUse.fieldSet(node.field));
- js.PropertyAccess field = new js.PropertyAccess(
- visitExpression(node.object),
- glue.instanceFieldPropertyName(node.field));
- return makeAssignment(field, node.value,
- compound: node.compound, sourceInformation: node.sourceInformation);
- }
-
- @override
- js.Expression visitGetStatic(tree_ir.GetStatic node) {
- assert(node.element is FieldElement || node.element is FunctionElement);
- if (node.element is FunctionElement) {
- // Tear off a method.
- registry.registerStaticUse(
- new StaticUse.staticTearOff(node.element.declaration));
- return glue
- .isolateStaticClosureAccess(node.element)
- .withSourceInformation(node.sourceInformation);
- }
- if (node.useLazyGetter) {
- // Read a lazily initialized field.
- registry.registerStaticUse(
- new StaticUse.staticInit(node.element.declaration));
- js.Expression getter = glue.isolateLazyInitializerAccess(node.element);
- return new js.Call(getter, <js.Expression>[],
- sourceInformation: node.sourceInformation);
- }
- // Read an eagerly initialized field.
- registry
- .registerStaticUse(new StaticUse.staticGet(node.element.declaration));
- return glue
- .staticFieldAccess(node.element)
- .withSourceInformation(node.sourceInformation);
- }
-
- @override
- js.Expression visitSetStatic(tree_ir.SetStatic node) {
- assert(node.element is FieldElement);
- registry
- .registerStaticUse(new StaticUse.staticSet(node.element.declaration));
- js.Expression field = glue.staticFieldAccess(node.element);
- return makeAssignment(field, node.value,
- compound: node.compound, sourceInformation: node.sourceInformation);
- }
-
- @override
- js.Expression visitGetLength(tree_ir.GetLength node) {
- return new js.PropertyAccess.field(visitExpression(node.object), 'length');
- }
-
- @override
- js.Expression visitGetIndex(tree_ir.GetIndex node) {
- return new js.PropertyAccess(
- visitExpression(node.object), visitExpression(node.index));
- }
-
- @override
- js.Expression visitSetIndex(tree_ir.SetIndex node) {
- js.Expression index = new js.PropertyAccess(
- visitExpression(node.object), visitExpression(node.index));
- return makeAssignment(index, node.value, compound: node.compound);
- }
-
- js.Expression buildStaticHelperInvocation(
- FunctionElement helper, List<js.Expression> arguments,
- {SourceInformation sourceInformation}) {
- registry.registerStaticUse(new StaticUse.staticInvoke(
- helper, new CallStructure.unnamed(arguments.length)));
- return buildStaticInvoke(helper, arguments,
- sourceInformation: sourceInformation);
- }
-
- @override
- js.Expression visitReifyRuntimeType(tree_ir.ReifyRuntimeType node) {
- js.Expression typeToString = buildStaticHelperInvocation(
- glue.getRuntimeTypeToString(), [visitExpression(node.value)],
- sourceInformation: node.sourceInformation);
- return buildStaticHelperInvocation(
- glue.getCreateRuntimeType(), [typeToString],
- sourceInformation: node.sourceInformation);
- }
-
- @override
- js.Expression visitReadTypeVariable(tree_ir.ReadTypeVariable node) {
- ClassElement context = node.variable.element.enclosingClass;
- js.Expression index = js.number(glue.getTypeVariableIndex(node.variable));
- if (glue.needsSubstitutionForTypeVariableAccess(context)) {
- js.Expression typeName = glue.getRuntimeTypeName(context);
- return buildStaticHelperInvocation(glue.getRuntimeTypeArgument(),
- [visitExpression(node.target), typeName, index],
- sourceInformation: node.sourceInformation);
- } else {
- return buildStaticHelperInvocation(
- glue.getTypeArgumentByIndex(), [visitExpression(node.target), index],
- sourceInformation: node.sourceInformation);
- }
- }
-
- @override
- js.Expression visitTypeExpression(tree_ir.TypeExpression node) {
- List<js.Expression> arguments = visitExpressionList(node.arguments);
- switch (node.kind) {
- case tree_ir.TypeExpressionKind.COMPLETE:
- return glue.generateTypeRepresentation(
- node.dartType, arguments, registry);
- case tree_ir.TypeExpressionKind.INSTANCE:
- // We expect only flat types for the INSTANCE representation.
- assert(
- node.dartType == (node.dartType.element as ClassElement).thisType);
- registry.registerInstantiatedClass(glue.listClass);
- return new js.ArrayInitializer(arguments);
- }
- }
-
- js.Node handleForeignCode(tree_ir.ForeignCode node) {
- if (node.dependency != null) {
- // Dependency is only used if [node] calls a Dart function. Currently only
- // through foreign function `RAW_DART_FUNCTION_REF`.
- registry.registerStaticUse(new StaticUse.staticInvoke(
- node.dependency, new CallStructure.unnamed(node.arguments.length)));
- }
- // TODO(sra,johnniwinther): Should this be in CodegenRegistry?
- glue.registerNativeBehavior(node.nativeBehavior, node);
- return node.codeTemplate
- .instantiate(visitExpressionList(node.arguments))
- .withSourceInformation(node.sourceInformation);
- }
-
- @override
- js.Expression visitForeignExpression(tree_ir.ForeignExpression node) {
- return handleForeignCode(node);
- }
-
- @override
- void visitForeignStatement(tree_ir.ForeignStatement node) {
- accumulator.add(handleForeignCode(node));
- }
-
- @override
- visitYield(tree_ir.Yield node) {
- js.Expression value = visitExpression(node.input);
- accumulator.add(new js.DartYield(value, node.hasStar));
- return node.next;
- }
-
- @override
- visitReceiverCheck(tree_ir.ReceiverCheck node) {
- js.Expression value = visitExpression(node.value);
- // TODO(sra): Try to use the selector even when [useSelector] is false. The
- // reason we use 'toString' is that it is always defined so avoids a slow
- // lookup (in V8) of an absent property. We could use the property for the
- // selector if we knew it was present. The property is present if the
- // associated method was not inlined away, or if there is a noSuchMethod
- // hook for that selector. We don't know these things here, but the decision
- // could be deferred by creating a deferred property that was resolved after
- // codegen.
- js.Expression access = node.useSelector
- ? js.js('#.#', [value, glue.invocationName(node.selector)])
- : js.js('#.toString', [value]);
- if (node.useInvoke) {
- access = new js.Call(access, []);
- }
- if (node.condition != null) {
- js.Expression condition = visitExpression(node.condition);
- js.Statement body = isNullReturn(node.next)
- ? new js.ExpressionStatement(access)
- : new js.Return(access);
- accumulator.add(new js.If.noElse(condition, body));
- } else {
- accumulator.add(new js.ExpressionStatement(access));
- }
- return node.next;
- }
-
- @override
- js.Expression visitApplyBuiltinOperator(tree_ir.ApplyBuiltinOperator node) {
- List<js.Expression> args = visitExpressionList(node.arguments);
-
- js.Expression createExpression() {
- switch (node.operator) {
- case BuiltinOperator.NumAdd:
- return new js.Binary('+', args[0], args[1]);
- case BuiltinOperator.NumSubtract:
- return new js.Binary('-', args[0], args[1]);
- case BuiltinOperator.NumMultiply:
- return new js.Binary('*', args[0], args[1]);
- case BuiltinOperator.NumDivide:
- return new js.Binary('/', args[0], args[1]);
- case BuiltinOperator.NumRemainder:
- return new js.Binary('%', args[0], args[1]);
- case BuiltinOperator.NumTruncatingDivideToSigned32:
- return js.js('(# / #) | 0', args);
- case BuiltinOperator.NumAnd:
- return normalizeBitOp(js.js('# & #', args), node);
- case BuiltinOperator.NumOr:
- return normalizeBitOp(js.js('# | #', args), node);
- case BuiltinOperator.NumXor:
- return normalizeBitOp(js.js('# ^ #', args), node);
- case BuiltinOperator.NumLt:
- return new js.Binary('<', args[0], args[1]);
- case BuiltinOperator.NumLe:
- return new js.Binary('<=', args[0], args[1]);
- case BuiltinOperator.NumGt:
- return new js.Binary('>', args[0], args[1]);
- case BuiltinOperator.NumGe:
- return new js.Binary('>=', args[0], args[1]);
- case BuiltinOperator.NumShl:
- return normalizeBitOp(js.js('# << #', args), node);
- case BuiltinOperator.NumShr:
- // No normalization required since output is always uint32.
- return js.js('# >>> #', args);
- case BuiltinOperator.NumBitNot:
- return js.js('(~#) >>> 0', args);
- case BuiltinOperator.NumNegate:
- return js.js('-#', args);
- case BuiltinOperator.StringConcatenate:
- if (args.isEmpty) return js.string('');
- return args.reduce((e1, e2) => new js.Binary('+', e1, e2));
- case BuiltinOperator.CharCodeAt:
- return js.js('#.charCodeAt(#)', args);
- case BuiltinOperator.Identical:
- registry.registerStaticUse(new StaticUse.staticInvoke(
- glue.identicalFunction, new CallStructure.unnamed(args.length)));
- return buildStaticHelperInvocation(glue.identicalFunction, args);
- case BuiltinOperator.StrictEq:
- return new js.Binary('===', args[0], args[1]);
- case BuiltinOperator.StrictNeq:
- return new js.Binary('!==', args[0], args[1]);
- case BuiltinOperator.LooseEq:
- return new js.Binary('==', args[0], args[1]);
- case BuiltinOperator.LooseNeq:
- return new js.Binary('!=', args[0], args[1]);
- case BuiltinOperator.IsFalsy:
- return new js.Prefix('!', args[0]);
- case BuiltinOperator.IsNumber:
- return js.js('typeof # === "number"', args);
- case BuiltinOperator.IsNotNumber:
- return js.js('typeof # !== "number"', args);
- case BuiltinOperator.IsFloor:
- return js.js('Math.floor(#) === #', args);
- case BuiltinOperator.IsInteger:
- return js.js('typeof # === "number" && Math.floor(#) === #', args);
- case BuiltinOperator.IsNotInteger:
- return js.js('typeof # !== "number" || Math.floor(#) !== #', args);
- case BuiltinOperator.IsUnsigned32BitInteger:
- return js.js('# >>> 0 === #', args);
- case BuiltinOperator.IsNotUnsigned32BitInteger:
- return js.js('# >>> 0 !== #', args);
- case BuiltinOperator.IsFixedLengthJSArray:
- // TODO(sra): Remove boolify (i.e. !!).
- return js.js(r'!!#.fixed$length', args);
- case BuiltinOperator.IsExtendableJSArray:
- return js.js(r'!#.fixed$length', args);
- case BuiltinOperator.IsModifiableJSArray:
- return js.js(r'!#.immutable$list', args);
- case BuiltinOperator.IsUnmodifiableJSArray:
- // TODO(sra): Remove boolify (i.e. !!).
- return js.js(r'!!#.immutable$list', args);
- }
- }
-
- return createExpression().withSourceInformation(node.sourceInformation);
- }
-
- /// Add a uint32 normalization `op >>> 0` to [op] if it is not in 31-bit
- /// range.
- js.Expression normalizeBitOp(
- js.Expression op, tree_ir.ApplyBuiltinOperator node) {
- const MAX_UINT31 = 0x7fffffff;
- const MAX_UINT32 = 0xffffffff;
-
- int constantValue(tree_ir.Expression e) {
- if (e is tree_ir.Constant) {
- ConstantValue value = e.value;
- if (!value.isInt) return null;
- IntConstantValue intConstant = value;
- if (intConstant.primitiveValue < 0) return null;
- if (intConstant.primitiveValue > MAX_UINT32) return null;
- return intConstant.primitiveValue;
- }
- return null;
- }
-
- /// Returns a value of the form 0b0001xxxx to represent the highest bit set
- /// in the result. This represents the range [0, 0b00011111], up to 32
- /// bits. `null` represents a result possibly outside the uint32 range.
- int maxBitOf(tree_ir.Expression e) {
- if (e is tree_ir.Constant) {
- return constantValue(e);
- }
- if (e is tree_ir.ApplyBuiltinOperator) {
- if (e.operator == BuiltinOperator.NumAnd) {
- int left = maxBitOf(e.arguments[0]);
- int right = maxBitOf(e.arguments[1]);
- if (left == null && right == null) return MAX_UINT32;
- if (left == null) return right;
- if (right == null) return left;
- return (left < right) ? left : right;
- }
- if (e.operator == BuiltinOperator.NumOr ||
- e.operator == BuiltinOperator.NumXor) {
- int left = maxBitOf(e.arguments[0]);
- int right = maxBitOf(e.arguments[1]);
- if (left == null || right == null) return MAX_UINT32;
- return left | right;
- }
- if (e.operator == BuiltinOperator.NumShr) {
- int right = constantValue(e.arguments[1]);
- // NumShr is JavaScript '>>>' so always generates a uint32 result.
- if (right == null || right <= 0 || right > 31) return MAX_UINT32;
- int left = maxBitOf(e.arguments[0]);
- if (left == null) return MAX_UINT32;
- return left >> right;
- }
- if (e.operator == BuiltinOperator.NumShl) {
- int right = constantValue(e.arguments[1]);
- if (right == null || right <= 0 || right > 31) return MAX_UINT32;
- int left = maxBitOf(e.arguments[0]);
- if (left == null) return MAX_UINT32;
- if (left.bitLength + right > 31) return MAX_UINT32;
- return left << right;
- }
- }
- return null;
- }
-
- int maxBit = maxBitOf(node);
- if (maxBit != null && maxBit <= MAX_UINT31) return op;
- return js.js('# >>> 0', [op]);
- }
-
- @override
- js.Expression visitApplyBuiltinMethod(tree_ir.ApplyBuiltinMethod node) {
- js.Expression receiver = visitExpression(node.receiver);
- List<js.Expression> args = visitExpressionList(node.arguments);
- 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
- js.Expression visitAwait(tree_ir.Await node) {
- return new js.Await(visitExpression(node.input));
- }
-
- /// Ensures that parameter defaults will be emitted.
- ///
- /// Ideally, this should be done when generating the relevant stub methods,
- /// since those are the ones that actually reference the constants, but those
- /// are created by the emitter when it is too late to register new constants.
- ///
- /// For non-static methods, we have no way of knowing if the defaults are
- /// actually used, so we conservatively register them all.
- void registerDefaultParameterValues(ExecutableElement element) {
- if (element is! FunctionElement) return;
- FunctionElement function = element;
- if (function.isStatic) return; // Defaults are inlined at call sites.
- function.functionSignature.forEachOptionalParameter((param) {
- ConstantValue constant = glue.getDefaultParameterValue(param);
- registry.registerCompileTimeConstant(constant);
- });
- }
-}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/glue.dart b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
deleted file mode 100644
index 1650174..0000000
--- a/pkg/compiler/lib/src/js_backend/codegen/glue.dart
+++ /dev/null
@@ -1,294 +0,0 @@
-// 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 code_generator_dependencies;
-
-import '../../common.dart';
-import '../../common/codegen.dart' show CodegenRegistry;
-import '../../compiler.dart' show Compiler;
-import '../../constants/values.dart';
-import '../../dart_types.dart' show DartType, TypeVariableType;
-import '../../elements/elements.dart';
-import '../../enqueue.dart' show CodegenEnqueuer;
-import '../../js/js.dart' as js;
-import '../../js_emitter/js_emitter.dart';
-import '../../native/native.dart' show NativeBehavior;
-import '../../types/types.dart';
-import '../../universe/selector.dart' show Selector;
-import '../../world.dart' show ClassWorld;
-import '../backend_helpers.dart' show BackendHelpers;
-import '../js_backend.dart';
-
-/// Encapsulates the dependencies of the function-compiler to the compiler,
-/// backend and emitter.
-// TODO(sigurdm): Should be refactored when we have a better feeling for the
-// interface.
-class Glue {
- final Compiler _compiler;
-
- CodegenEnqueuer get _enqueuer => _compiler.enqueuer.codegen;
-
- FunctionElement get getInterceptorMethod => _helpers.getInterceptorMethod;
-
- JavaScriptBackend get _backend => _compiler.backend;
-
- BackendHelpers get _helpers => _backend.helpers;
-
- CodeEmitterTask get _emitter => _backend.emitter;
-
- Namer get _namer => _backend.namer;
-
- Glue(this._compiler);
-
- ClassWorld get classWorld => _compiler.world;
-
- DiagnosticReporter get reporter => _compiler.reporter;
-
- js.Expression constantReference(ConstantValue value) {
- return _emitter.constantReference(value);
- }
-
- reportInternalError(String message) {
- reporter.internalError(CURRENT_ELEMENT_SPANNABLE, message);
- }
-
- bool isUsedAsMixin(ClassElement classElement) {
- return classWorld.isUsedAsMixin(classElement);
- }
-
- js.Expression staticFunctionAccess(FunctionElement element) {
- return _backend.emitter.staticFunctionAccess(element);
- }
-
- js.Expression isolateStaticClosureAccess(FunctionElement element) {
- return _backend.emitter.isolateStaticClosureAccess(element);
- }
-
- js.Expression staticFieldAccess(FieldElement element) {
- return _backend.emitter.staticFieldAccess(element);
- }
-
- js.Expression isolateLazyInitializerAccess(FieldElement element) {
- return _backend.emitter.isolateLazyInitializerAccess(element);
- }
-
- bool isLazilyInitialized(FieldElement element) {
- return _backend.constants.lazyStatics.contains(element);
- }
-
- String safeVariableName(String name) {
- return _namer.safeVariableName(name);
- }
-
- ClassElement get listClass => _compiler.coreClasses.listClass;
-
- ConstructorElement get mapLiteralConstructor {
- return _helpers.mapLiteralConstructor;
- }
-
- ConstructorElement get mapLiteralConstructorEmpty {
- return _helpers.mapLiteralConstructorEmpty;
- }
-
- FunctionElement get identicalFunction => _compiler.identicalFunction;
-
- js.Name invocationName(Selector selector) {
- return _namer.invocationName(selector);
- }
-
- FunctionElement get createInvocationMirrorMethod {
- return _helpers.createInvocationMirror;
- }
-
- bool isInterceptedSelector(Selector selector) {
- return _backend.isInterceptedSelector(selector);
- }
-
- bool isInterceptedMethod(Element element) {
- return _backend.isInterceptedMethod(element);
- }
-
- bool isInterceptorClass(ClassElement element) {
- return element.isSubclassOf(_helpers.jsInterceptorClass);
- }
-
- Set<ClassElement> getInterceptedClassesOn(Selector selector) {
- return _backend.getInterceptedClassesOn(selector.name);
- }
-
- Set<ClassElement> get interceptedClasses {
- return _backend.interceptedClasses;
- }
-
- void registerSpecializedGetInterceptor(Set<ClassElement> classes) {
- _backend.registerSpecializedGetInterceptor(classes);
- }
-
- js.Expression constructorAccess(ClassElement element) {
- return _backend.emitter.constructorAccess(element);
- }
-
- js.Name instanceFieldPropertyName(Element field) {
- return _namer.instanceFieldPropertyName(field);
- }
-
- js.Name instanceMethodName(FunctionElement element) {
- return _namer.instanceMethodName(element);
- }
-
- js.Expression prototypeAccess(ClassElement e,
- {bool hasBeenInstantiated: false}) {
- return _emitter.prototypeAccess(e,
- hasBeenInstantiated: hasBeenInstantiated);
- }
-
- js.Name getInterceptorName(Set<ClassElement> interceptedClasses) {
- return _backend.namer.nameForGetInterceptor(interceptedClasses);
- }
-
- js.Expression getInterceptorLibrary() {
- return new js.VariableUse(
- _backend.namer.globalObjectFor(_helpers.interceptorsLibrary));
- }
-
- FunctionElement getWrapExceptionHelper() {
- return _helpers.wrapExceptionHelper;
- }
-
- FunctionElement getExceptionUnwrapper() {
- return _helpers.exceptionUnwrapper;
- }
-
- FunctionElement getTraceFromException() {
- return _helpers.traceFromException;
- }
-
- FunctionElement getCreateRuntimeType() {
- return _helpers.createRuntimeType;
- }
-
- FunctionElement getRuntimeTypeToString() {
- return _helpers.runtimeTypeToString;
- }
-
- FunctionElement getRuntimeTypeArgument() {
- return _helpers.getRuntimeTypeArgument;
- }
-
- FunctionElement getTypeArgumentByIndex() {
- return _helpers.getTypeArgumentByIndex;
- }
-
- FunctionElement getAddRuntimeTypeInformation() {
- return _helpers.setRuntimeTypeInfo;
- }
-
- /// checkSubtype(value, $isT, typeArgs, $asT)
- FunctionElement getCheckSubtype() {
- return _helpers.checkSubtype;
- }
-
- /// subtypeCast(value, $isT, typeArgs, $asT)
- FunctionElement getSubtypeCast() {
- return _helpers.subtypeCast;
- }
-
- /// checkSubtypeOfRuntime(value, runtimeType)
- FunctionElement getCheckSubtypeOfRuntimeType() {
- return _helpers.checkSubtypeOfRuntimeType;
- }
-
- /// subtypeOfRuntimeTypeCast(value, runtimeType)
- FunctionElement getSubtypeOfRuntimeTypeCast() {
- return _helpers.subtypeOfRuntimeTypeCast;
- }
-
- js.Expression getRuntimeTypeName(ClassElement cls) {
- return js.quoteName(_namer.runtimeTypeName(cls));
- }
-
- int getTypeVariableIndex(TypeVariableType variable) {
- return variable.element.index;
- }
-
- bool needsSubstitutionForTypeVariableAccess(ClassElement cls) {
- ClassWorld classWorld = _compiler.world;
- if (classWorld.isUsedAsMixin(cls)) return true;
-
- return _compiler.world.anyStrictSubclassOf(cls, (ClassElement subclass) {
- return !_backend.rti.isTrivialSubstitution(subclass, cls);
- });
- }
-
- js.Expression generateTypeRepresentation(DartType dartType,
- List<js.Expression> arguments, CodegenRegistry registry) {
- int variableIndex = 0;
- js.Expression representation = _backend.rtiEncoder
- .getTypeRepresentation(dartType, (_) => arguments[variableIndex++]);
- assert(variableIndex == arguments.length);
- // Representation contains JavaScript Arrays.
- registry.registerInstantiatedClass(_helpers.jsArrayClass);
- return representation;
- }
-
- js.Name getTypeTestTag(DartType type) {
- return _backend.namer.operatorIsType(type);
- }
-
- js.Name getTypeSubstitutionTag(ClassElement element) {
- return _backend.namer.substitutionName(element);
- }
-
- bool operatorEqHandlesNullArgument(FunctionElement element) {
- return _backend.operatorEqHandlesNullArgument(element);
- }
-
- bool hasStrictSubtype(ClassElement element) {
- return _compiler.world.hasAnyStrictSubtype(element);
- }
-
- ClassElement get jsFixedArrayClass => _helpers.jsFixedArrayClass;
- ClassElement get jsExtendableArrayClass => _helpers.jsExtendableArrayClass;
- ClassElement get jsUnmodifiableArrayClass =>
- _helpers.jsUnmodifiableArrayClass;
- ClassElement get jsMutableArrayClass => _helpers.jsMutableArrayClass;
-
- bool isStringClass(ClassElement classElement) =>
- classElement == _helpers.jsStringClass ||
- classElement == _compiler.coreClasses.stringClass;
-
- bool isBoolClass(ClassElement classElement) =>
- classElement == _helpers.jsBoolClass ||
- classElement == _compiler.coreClasses.boolClass;
-
- // TODO(sra,johnniwinther): Should this be part of CodegenRegistry?
- void registerNativeBehavior(NativeBehavior nativeBehavior, node) {
- if (nativeBehavior == null) return;
- _enqueuer.nativeEnqueuer.registerNativeBehavior(nativeBehavior, node);
- }
-
- ConstantValue getDefaultParameterValue(ParameterElement elem) {
- return _backend.constants.getConstantValue(elem.constant);
- }
-
- TypeMask extendMaskIfReachesAll(Selector selector, TypeMask mask) {
- return _compiler.world.extendMaskIfReachesAll(selector, mask);
- }
-
- FunctionElement get closureFromTearOff => _backend.helpers.closureFromTearOff;
-
- js.Name registerOneShotInterceptor(Selector selector) {
- return _backend.registerOneShotInterceptor(selector);
- }
-
- bool mayGenerateInstanceofCheck(DartType type) {
- return _backend.mayGenerateInstanceofCheck(type);
- }
-
- bool methodUsesReceiverArgument(FunctionElement function) {
- assert(isInterceptedMethod(function));
- ClassElement class_ = function.enclosingClass.declaration;
- return isInterceptorClass(class_) || isUsedAsMixin(class_);
- }
-}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
deleted file mode 100644
index 859647a..0000000
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ /dev/null
@@ -1,356 +0,0 @@
-// 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.
-
-/// Generate code using the cps-based IR pipeline.
-library code_generator_task;
-
-import '../../common.dart';
-import '../../common/codegen.dart' show CodegenWorkItem;
-import '../../common/tasks.dart' show CompilerTask, GenericTask;
-import '../../compiler.dart' show Compiler;
-import '../../constants/constant_system.dart';
-import '../../cps_ir/cps_ir_builder_task.dart';
-import '../../cps_ir/cps_ir_integrity.dart';
-import '../../cps_ir/cps_ir_nodes.dart' as cps;
-import '../../cps_ir/cps_ir_nodes_sexpr.dart';
-import '../../cps_ir/finalize.dart' show Finalize;
-import '../../cps_ir/optimizers.dart';
-import '../../cps_ir/optimizers.dart' as cps_opt;
-import '../../cps_ir/type_mask_system.dart';
-import '../../diagnostics/invariant.dart' show DEBUG_MODE;
-import '../../elements/elements.dart';
-import '../../io/source_information.dart' show SourceInformationStrategy;
-import '../../js/js.dart' as js;
-import '../../js_backend/codegen/codegen.dart';
-import '../../ssa/ssa.dart' as ssa;
-import '../../tracer.dart';
-import '../../tree_ir/optimization/optimization.dart';
-import '../../tree_ir/optimization/optimization.dart' as tree_opt;
-import '../../tree_ir/tree_ir_builder.dart' as tree_builder;
-import '../../tree_ir/tree_ir_integrity.dart';
-import '../../tree_ir/tree_ir_nodes.dart' as tree_ir;
-import '../../types/types.dart'
- show FlatTypeMask, ForwardingTypeMask, TypeMask, UnionTypeMask;
-import '../js_backend.dart';
-import 'codegen.dart';
-import 'glue.dart';
-import 'unsugar.dart';
-
-class CpsFunctionCompiler implements FunctionCompiler {
- final ConstantSystem constantSystem;
- // TODO(karlklose): remove the compiler.
- final Compiler compiler;
- final Glue glue;
- final SourceInformationStrategy sourceInformationFactory;
-
- // TODO(karlklose,sigurdm): remove and update dart-doc of [compile].
- final FunctionCompiler fallbackCompiler;
- TypeMaskSystem typeSystem;
-
- Tracer get tracer => compiler.tracer;
-
- final IrBuilderTask cpsBuilderTask;
- final GenericTask cpsOptimizationTask;
- final GenericTask treeBuilderTask;
- final GenericTask treeOptimizationTask;
-
- Inliner inliner;
-
- CpsFunctionCompiler(Compiler compiler, JavaScriptBackend backend,
- SourceInformationStrategy sourceInformationFactory)
- : fallbackCompiler =
- new ssa.SsaFunctionCompiler(backend, sourceInformationFactory),
- cpsBuilderTask = new IrBuilderTask(compiler, sourceInformationFactory),
- sourceInformationFactory = sourceInformationFactory,
- constantSystem = backend.constantSystem,
- compiler = compiler,
- glue = new Glue(compiler),
- cpsOptimizationTask =
- new GenericTask('CPS optimization', compiler.measurer),
- treeBuilderTask = new GenericTask('Tree builder', compiler.measurer),
- treeOptimizationTask =
- new GenericTask('Tree optimization', compiler.measurer) {
- inliner = new Inliner(this);
- }
-
- String get name => 'CPS Ir pipeline';
-
- JavaScriptBackend get backend => compiler.backend;
-
- DiagnosticReporter get reporter => compiler.reporter;
-
- /// Generates JavaScript code for `work.element`.
- js.Fun compile(CodegenWorkItem work) {
- if (typeSystem == null) typeSystem = new TypeMaskSystem(compiler);
- AstElement element = work.element;
- return reporter.withCurrentElement(element, () {
- try {
- // TODO(karlklose): remove this fallback when we do not need it for
- // testing anymore.
- if (false) {
- reporter.log('Using SSA compiler for platform element $element');
- return fallbackCompiler.compile(work);
- }
-
- if (tracer != null) {
- tracer.traceCompilation('$element', null);
- }
- cps.FunctionDefinition cpsFunction = compileToCpsIr(element);
- optimizeCpsBeforeInlining(cpsFunction);
- applyCpsPass(inliner, cpsFunction);
- optimizeCpsAfterInlining(cpsFunction);
- cpsIntegrityChecker = null;
- tree_ir.FunctionDefinition treeFunction = compileToTreeIr(cpsFunction);
- treeFunction = optimizeTreeIr(treeFunction);
- return compileToJavaScript(work, treeFunction);
- } on CodegenBailout catch (e) {
- String message = "Unable to compile $element with the new compiler.\n"
- " Reason: ${e.message}";
- reporter.internalError(element, message);
- }
- });
- }
-
- void giveUp(String reason) {
- throw new CodegenBailout(null, reason);
- }
-
- void traceGraph(String title, var irObject) {
- if (tracer != null) {
- tracer.traceGraph(title, irObject);
- }
- }
-
- String stringify(cps.FunctionDefinition node) {
- return new SExpressionStringifier().withTypes().visit(node);
- }
-
- /// For debugging purposes, replace a call to [applyCpsPass] with a call
- /// to [debugCpsPass] to check that this pass is idempotent.
- ///
- /// This runs [pass] followed by shrinking reductions, and then checks that
- /// one more run of [pass] does not change the IR. The intermediate shrinking
- /// reductions pass is omitted if [pass] itself is shrinking reductions.
- ///
- /// If [targetName] is given, functions whose name contains that substring
- /// will be dumped out if the idempotency test fails.
- void debugCpsPass(cps_opt.Pass makePass(), cps.FunctionDefinition cpsFunction,
- [String targetName]) {
- String original = stringify(cpsFunction);
- cps_opt.Pass pass = makePass();
- pass.rewrite(cpsFunction);
- assert(checkCpsIntegrity(cpsFunction, pass.passName));
- if (pass is! ShrinkingReducer) {
- new ShrinkingReducer().rewrite(cpsFunction);
- }
- String before = stringify(cpsFunction);
- makePass().rewrite(cpsFunction);
- String after = stringify(cpsFunction);
- if (before != after) {
- print('SExpression changed for ${cpsFunction.element}');
- if (targetName != null && '${cpsFunction.element}'.contains(targetName)) {
- print(original);
- print('\n-->\n');
- print(before);
- print('\n-->\n');
- print(after);
- compiler.outputProvider('original', 'dump')
- ..add(original)
- ..close();
- compiler.outputProvider('before', 'dump')
- ..add(before)
- ..close();
- compiler.outputProvider('after', 'dump')
- ..add(after)
- ..close();
- }
- }
- traceGraph(pass.passName, cpsFunction);
- dumpTypedIr(pass.passName, cpsFunction);
- }
-
- void applyCpsPass(cps_opt.Pass pass, cps.FunctionDefinition cpsFunction) {
- cpsOptimizationTask.measureSubtask(pass.passName, () {
- pass.rewrite(cpsFunction);
- });
- traceGraph(pass.passName, cpsFunction);
- dumpTypedIr(pass.passName, cpsFunction);
- assert(checkCpsIntegrity(cpsFunction, pass.passName));
- }
-
- cps.FunctionDefinition compileToCpsIr(AstElement element) {
- cps.FunctionDefinition cpsFunction = inliner.cache.getUnoptimized(element);
- if (cpsFunction != null) return cpsFunction;
-
- cpsFunction = cpsBuilderTask.buildNode(element, typeSystem);
- if (cpsFunction == null) {
- if (cpsBuilderTask.bailoutMessage == null) {
- giveUp('unable to build cps definition of $element');
- } else {
- giveUp(cpsBuilderTask.bailoutMessage);
- }
- }
- ParentVisitor.setParents(cpsFunction);
- traceGraph('IR Builder', cpsFunction);
- dumpTypedIr('IR Builder', cpsFunction);
- // Eliminating redundant phis before the unsugaring pass will make it
- // insert fewer getInterceptor calls.
- applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
- applyCpsPass(new UnsugarVisitor(glue), cpsFunction);
- applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
- applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
- applyCpsPass(new InsertRefinements(typeSystem), cpsFunction);
-
- inliner.cache.putUnoptimized(element, cpsFunction);
- return cpsFunction;
- }
-
- static const Pattern PRINT_TYPED_IR_FILTER = null;
-
- String formatTypeMask(TypeMask type) {
- if (type is UnionTypeMask) {
- return '[${type.disjointMasks.map(formatTypeMask).join(', ')}]';
- } else if (type is FlatTypeMask) {
- if (type.isEmpty) return "empty";
- if (type.isNull) return "null";
- String suffix = (type.isExact ? "" : "+") + (type.isNullable ? "?" : "!");
- return '${type.base.name}$suffix';
- } else if (type is ForwardingTypeMask) {
- return formatTypeMask(type.forwardTo);
- }
- throw 'unsupported: $type';
- }
-
- void dumpTypedIr(String passName, cps.FunctionDefinition cpsFunction) {
- if (PRINT_TYPED_IR_FILTER != null &&
- PRINT_TYPED_IR_FILTER.matchAsPrefix(cpsFunction.element.name) != null) {
- String printType(nodeOrRef, String s) {
- cps.Node node =
- nodeOrRef is cps.Reference ? nodeOrRef.definition : nodeOrRef;
- return node is cps.Variable && node.type != null
- ? '$s:${formatTypeMask(node.type)}'
- : s;
- }
- DEBUG_MODE = true;
- print(';;; ==== After $passName ====');
- print(new SExpressionStringifier(printType).visit(cpsFunction));
- }
- }
-
- CheckCpsIntegrity cpsIntegrityChecker;
-
- bool checkCpsIntegrity(cps.FunctionDefinition node, String previousPass) {
- cpsOptimizationTask.measureSubtask('Check integrity', () {
- if (cpsIntegrityChecker == null) {
- cpsIntegrityChecker = new CheckCpsIntegrity();
- }
- cpsIntegrityChecker.check(node, previousPass);
- });
- return true; // So this can be used from assert().
- }
-
- void optimizeCpsBeforeInlining(cps.FunctionDefinition cpsFunction) {
- cpsOptimizationTask.measure(() {
- applyCpsPass(new TypePropagator(this), cpsFunction);
- applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
- applyCpsPass(new ShrinkingReducer(), cpsFunction);
- });
- }
-
- void optimizeCpsAfterInlining(cps.FunctionDefinition cpsFunction) {
- cpsOptimizationTask.measure(() {
- applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
- applyCpsPass(new ShrinkingReducer(), cpsFunction);
- applyCpsPass(new RedundantRefinementEliminator(typeSystem), cpsFunction);
- applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction);
- applyCpsPass(new TypePropagator(this, recomputeAll: true), cpsFunction);
- applyCpsPass(new ShrinkingReducer(), cpsFunction);
- applyCpsPass(new EagerlyLoadStatics(), cpsFunction);
- applyCpsPass(new GVN(compiler, typeSystem), cpsFunction);
- applyCpsPass(new PathBasedOptimizer(backend, typeSystem), cpsFunction);
- applyCpsPass(new ShrinkingReducer(), cpsFunction);
- applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction);
- applyCpsPass(new BoundsChecker(typeSystem, compiler.world), cpsFunction);
- applyCpsPass(new LoopInvariantBranchMotion(), cpsFunction);
- applyCpsPass(new ShrinkingReducer(), cpsFunction);
- applyCpsPass(new ScalarReplacer(compiler), cpsFunction);
- applyCpsPass(new UseFieldInitializers(backend), cpsFunction);
- applyCpsPass(new MutableVariableEliminator(), cpsFunction);
- applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
- applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
- applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction);
- applyCpsPass(new ShrinkingReducer(), cpsFunction);
- applyCpsPass(new OptimizeInterceptors(backend, typeSystem), cpsFunction);
- applyCpsPass(new BackwardNullCheckRemover(typeSystem), cpsFunction);
- applyCpsPass(new ShrinkingReducer(), cpsFunction);
- });
- }
-
- tree_ir.FunctionDefinition compileToTreeIr(cps.FunctionDefinition cpsNode) {
- applyCpsPass(new Finalize(backend), cpsNode);
- tree_builder.Builder builder =
- new tree_builder.Builder(reporter.internalError, glue);
- tree_ir.FunctionDefinition treeNode =
- treeBuilderTask.measure(() => builder.buildFunction(cpsNode));
- assert(treeNode != null);
- traceGraph('Tree builder', treeNode);
- assert(checkTreeIntegrity(treeNode));
- return treeNode;
- }
-
- bool checkTreeIntegrity(tree_ir.FunctionDefinition node) {
- treeOptimizationTask.measureSubtask('Check integrity', () {
- new CheckTreeIntegrity().check(node);
- });
- return true; // So this can be used from assert().
- }
-
- tree_ir.FunctionDefinition optimizeTreeIr(tree_ir.FunctionDefinition node) {
- void applyTreePass(tree_opt.Pass pass) {
- treeOptimizationTask.measureSubtask(pass.passName, () {
- pass.rewrite(node);
- });
- traceGraph(pass.passName, node);
- assert(checkTreeIntegrity(node));
- }
-
- treeOptimizationTask.measure(() {
- applyTreePass(new StatementRewriter());
- applyTreePass(
- new VariableMerger(minifying: compiler.options.enableMinification));
- applyTreePass(new LoopRewriter());
- applyTreePass(new LogicalRewriter());
- applyTreePass(new PullIntoInitializers());
- });
-
- return node;
- }
-
- js.Fun compileToJavaScript(
- CodegenWorkItem work, tree_ir.FunctionDefinition definition) {
- CodeGenerator codeGen = new CodeGenerator(glue, work.registry);
- Element element = work.element;
- js.Fun code = codeGen.buildFunction(definition);
- if (element is FunctionElement && element.asyncMarker != AsyncMarker.SYNC) {
- code = backend.rewriteAsync(element, code);
- work.registry.registerAsyncMarker(element);
- }
- return attachPosition(code, work.resolvedAst);
- }
-
- Iterable<CompilerTask> get tasks {
- return <CompilerTask>[
- cpsBuilderTask,
- cpsOptimizationTask,
- treeBuilderTask,
- treeOptimizationTask
- ]..addAll(fallbackCompiler.tasks);
- }
-
- js.Node attachPosition(js.Node node, ResolvedAst resolvedAst) {
- return node.withSourceInformation(sourceInformationFactory
- .createBuilderForContext(resolvedAst)
- .buildDeclaration(resolvedAst));
- }
-}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
deleted file mode 100644
index 02db2c4..0000000
--- a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
+++ /dev/null
@@ -1,244 +0,0 @@
-library dart2js.unsugar_cps;
-
-import '../../common/names.dart';
-import '../../constants/values.dart';
-import '../../cps_ir/cps_fragment.dart';
-import '../../cps_ir/cps_ir_nodes.dart';
-import '../../cps_ir/optimizers.dart' show Pass;
-import '../../elements/elements.dart';
-import '../../js_backend/codegen/glue.dart';
-import '../../universe/selector.dart' show Selector;
-
-class ExplicitReceiverParameterEntity implements Local {
- String get name => 'receiver';
- final ExecutableElement executableContext;
- ExplicitReceiverParameterEntity(this.executableContext);
- toString() => 'ExplicitReceiverParameterEntity($executableContext)';
-}
-
-/// Suggested name for an interceptor.
-class InterceptorEntity extends Entity {
- Entity interceptedVariable;
-
- InterceptorEntity(this.interceptedVariable);
-
- String get name => interceptedVariable.name + '_';
-}
-
-/// Rewrites the initial CPS IR to make Dart semantics explicit and inserts
-/// special nodes that respect JavaScript behavior.
-///
-/// Performs the following rewrites:
-/// - Add interceptors at call sites that use interceptor calling convention.
-/// - Add explicit receiver argument for methods that are called in interceptor
-/// calling convention.
-/// - Convert two-parameter exception handlers to one-parameter ones.
-class UnsugarVisitor extends TrampolineRecursiveVisitor implements Pass {
- Glue _glue;
-
- FunctionDefinition function;
-
- Parameter get receiverParameter => function.receiverParameter;
-
- /// The interceptor of the receiver. For some methods, this is the receiver
- /// itself, for others, it is the interceptor parameter.
- Parameter receiverInterceptor;
-
- // In a catch block, rethrow implicitly throws the block's exception
- // parameter. This is the exception parameter when nested in a catch
- // block and null otherwise.
- Parameter _exceptionParameter = null;
-
- UnsugarVisitor(this._glue);
-
- String get passName => 'Unsugaring';
-
- void rewrite(FunctionDefinition function) {
- this.function = function;
- bool inInterceptedMethod = _glue.isInterceptedMethod(function.element);
-
- if (function.element.name == '==' &&
- function.parameters.length == 1 &&
- !_glue.operatorEqHandlesNullArgument(function.element)) {
- // Insert the null check that the language semantics requires us to
- // perform before calling operator ==.
- insertEqNullCheck(function);
- }
-
- if (inInterceptedMethod) {
- function.interceptorParameter = new Parameter(null)..parent = function;
- // Since the receiver won't be compiled to "this", set a hint on it
- // so the parameter gets a meaningful name.
- function.receiverParameter.hint =
- new ExplicitReceiverParameterEntity(function.element);
- // If we need an interceptor for the receiver, use the receiver itself
- // if possible, otherwise the interceptor argument.
- receiverInterceptor = _glue.methodUsesReceiverArgument(function.element)
- ? function.interceptorParameter
- : receiverParameter;
- }
-
- visit(function);
- }
-
- Constant get trueConstant {
- return new Constant(new TrueConstantValue());
- }
-
- Constant get falseConstant {
- return new Constant(new FalseConstantValue());
- }
-
- Constant get nullConstant {
- return new Constant(new NullConstantValue());
- }
-
- void insertEqNullCheck(FunctionDefinition function) {
- // Replace
- //
- // body;
- //
- // with
- //
- // if (identical(arg, null))
- // return false;
- // else
- // body;
- //
- CpsFragment cps = new CpsFragment();
- Primitive isNull = cps.applyBuiltin(BuiltinOperator.Identical,
- <Primitive>[function.parameters.single, cps.makeNull()]);
- CpsFragment trueBranch = cps.ifTruthy(isNull);
- trueBranch.invokeContinuation(
- function.returnContinuation, <Primitive>[trueBranch.makeFalse()]);
- cps.insertAbove(function.body);
- }
-
- /// Insert a static call to [function] immediately above [node].
- Primitive insertStaticCallAbove(
- FunctionElement function, List<Primitive> arguments, Expression node) {
- // TODO(johnniwinther): Come up with an implementation of SourceInformation
- // for calls such as this one that don't appear in the original source.
- InvokeStatic invoke = new InvokeStatic(
- function, new Selector.fromElement(function), arguments, null);
- new LetPrim(invoke).insertAbove(node);
- return invoke;
- }
-
- @override
- Expression traverseLetHandler(LetHandler node) {
- assert(node.handler.parameters.length == 2);
- Parameter previousExceptionParameter = _exceptionParameter;
-
- // BEFORE: Handlers have two parameters, exception and stack trace.
- // AFTER: Handlers have a single parameter, which is unwrapped to get
- // the exception and stack trace.
- _exceptionParameter = node.handler.parameters.first;
- Parameter stackTraceParameter = node.handler.parameters.last;
- Expression body = node.handler.body;
- if (_exceptionParameter.hasAtLeastOneUse ||
- stackTraceParameter.hasAtLeastOneUse) {
- InvokeStatic unwrapped = insertStaticCallAbove(
- _glue.getExceptionUnwrapper(),
- [new Parameter(null)], // Dummy argument, see below.
- body);
- _exceptionParameter.replaceUsesWith(unwrapped);
-
- // Replace the dummy with the exception parameter. It must be set after
- // replacing all uses of [_exceptionParameter].
- unwrapped.argumentRefs[0].changeTo(_exceptionParameter);
-
- if (stackTraceParameter.hasAtLeastOneUse) {
- InvokeStatic stackTraceValue = insertStaticCallAbove(
- _glue.getTraceFromException(), [_exceptionParameter], body);
- stackTraceParameter.replaceUsesWith(stackTraceValue);
- }
- }
-
- assert(stackTraceParameter.hasNoUses);
- node.handler.parameters.removeLast();
-
- visit(node.handler);
- _exceptionParameter = previousExceptionParameter;
-
- return node.body;
- }
-
- processThrow(Throw node) {
- // The subexpression of throw is wrapped in the JavaScript output.
- Primitive wrappedException = insertStaticCallAbove(
- _glue.getWrapExceptionHelper(), [node.value], node);
- node.valueRef.changeTo(wrappedException);
- }
-
- processRethrow(Rethrow node) {
- // Rethrow can only appear in a catch block. It throws that block's
- // (wrapped) caught exception.
- Throw replacement = new Throw(_exceptionParameter);
- InteriorNode parent = node.parent;
- parent.body = replacement;
- replacement.parent = parent;
- // The original rethrow does not have any references that we need to
- // worry about unlinking.
- }
-
- bool isNullConstant(Primitive prim) {
- return prim is Constant && prim.value.isNull;
- }
-
- processInvokeMethod(InvokeMethod node) {
- Selector selector = node.selector;
- if (!_glue.isInterceptedSelector(selector)) return;
-
- // 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.argumentRefs.length == 1 &&
- isNullConstant(node.argument(0))) {
- node.replaceWith(new ApplyBuiltinOperator(BuiltinOperator.Identical,
- [node.receiver, node.argument(0)], node.sourceInformation));
- return;
- }
-
- Primitive receiver = node.receiver;
- Primitive interceptor;
-
- if (receiver == receiverParameter && receiverInterceptor != null) {
- // TODO(asgerf): This could be done by GVN.
- // If the receiver is 'this', we are calling a method in
- // the same interceptor:
- // Change 'receiver.foo()' to 'this.foo(receiver)'.
- interceptor = receiverInterceptor;
- } else {
- interceptor = new Interceptor(receiver, node.sourceInformation);
- if (receiver.hint != null) {
- interceptor.hint = new InterceptorEntity(receiver.hint);
- }
- new LetPrim(interceptor).insertAbove(node.parent);
- }
- assert(node.interceptorRef == null);
- node.makeIntercepted(interceptor);
- }
-
- processInvokeMethodDirectly(InvokeMethodDirectly node) {
- if (!_glue.isInterceptedMethod(node.target)) return;
-
- Primitive receiver = node.receiver;
- Primitive interceptor;
-
- if (receiver == receiverParameter && receiverInterceptor != null) {
- // If the receiver is 'this', we are calling a method in
- // the same interceptor:
- // Change 'receiver.foo()' to 'this.foo(receiver)'.
- interceptor = receiverInterceptor;
- } else {
- interceptor = new Interceptor(receiver, node.sourceInformation);
- if (receiver.hint != null) {
- interceptor.hint = new InterceptorEntity(receiver.hint);
- }
- new LetPrim(interceptor).insertAbove(node.parent);
- }
- assert(node.interceptorRef == null);
- node.makeIntercepted(interceptor);
- }
-}
diff --git a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
index b496a14..11ff3c9 100644
--- a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
@@ -204,6 +204,7 @@
}
}
}
+
classElement.forEachMember(selectGenerativeConstructors,
includeBackendMembers: false, includeSuperAndInjectedMembers: false);
return result;
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 7cc4621..303f52c 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -1179,63 +1179,72 @@
/**
* Returns a proposed name for the given top-level or static element.
- * The returned id is guaranteed to be a valid JS-id.
+ * The returned id is guaranteed to be a valid JavaScript identifier.
*/
String _proposeNameForGlobal(Element element) {
assert(!element.isInstanceMember);
- String name;
if (element.isGenerativeConstructor) {
- name = "${element.enclosingClass.name}\$"
- "${element.name}";
- } else if (element.isFactoryConstructor) {
+ return '${element.enclosingClass.name}\$${element.name}';
+ }
+ if (element.isFactoryConstructor) {
// TODO(johnniwinther): Change factory name encoding as to not include
// the class-name twice.
String className = element.enclosingClass.name;
- name = '${className}_${Elements.reconstructConstructorName(element)}';
- } else if (Elements.isStaticOrTopLevel(element)) {
+ return '${className}_${Elements.reconstructConstructorName(element)}';
+ }
+ if (Elements.isStaticOrTopLevel(element)) {
if (element.isClassMember) {
ClassElement enclosingClass = element.enclosingClass;
- name = "${enclosingClass.name}_"
- "${element.name}";
- } else {
- name = element.name.replaceAll('+', '_');
+ return '${enclosingClass.name}_${element.name}';
}
- } else if (element.isLibrary) {
- LibraryElement library = element;
- name = libraryLongNames[library];
- if (name != null) return name;
- name = library.libraryOrScriptName;
- if (name.contains('.')) {
- // For libraries that have a library tag, we use the last part
- // of the fully qualified name as their base name. For all other
- // libraries, we use the first part of their filename.
- name = library.hasLibraryName
- ? name.substring(name.lastIndexOf('.') + 1)
- : name.substring(0, name.indexOf('.'));
- }
- // The filename based name can contain all kinds of nasty characters. Make
- // sure it is an identifier.
- if (!IDENTIFIER.hasMatch(name)) {
- name = name.replaceAllMapped(NON_IDENTIFIER_CHAR,
- (match) => match[0].codeUnitAt(0).toRadixString(16));
- if (!IDENTIFIER.hasMatch(name)) {
- // e.g. starts with digit.
- name = 'lib_$name';
- }
- }
- // Names constructed based on a libary name will be further disambiguated.
- // However, as names from the same libary should have the same libary
- // name part, we disambiguate the library name here.
- String disambiguated = name;
- for (int c = 0; libraryLongNames.containsValue(disambiguated); c++) {
- disambiguated = "$name$c";
- }
- libraryLongNames[library] = disambiguated;
- name = disambiguated;
- } else {
- name = element.name;
+ return element.name.replaceAll('+', '_');
}
- return name;
+ if (element.isLibrary) {
+ return _proposeNameForLibrary(element);
+ }
+ return element.name;
+ }
+
+ /**
+ * Returns a proposed name for the given [LibraryElement].
+ * The returned id is guaranteed to be a valid JavaScript identifier.
+ */
+ // TODO(sra): Pre-process libraries to assign [libraryLongNames] in a way that
+ // is independent of the order of calls to namer.
+ String _proposeNameForLibrary(LibraryElement library) {
+ String name = libraryLongNames[library];
+ if (name != null) return name;
+ // Use the 'file' name, e.g. "package:expect/expect.dart" -> "expect"
+ name = library.canonicalUri.path;
+ name = name.substring(name.lastIndexOf('/') + 1);
+ if (name.contains('.')) {
+ // Drop file extension.
+ name = name.substring(0, name.lastIndexOf('.'));
+ }
+ // The filename based name can contain all kinds of nasty characters. Make
+ // sure it is an identifier.
+ if (!IDENTIFIER.hasMatch(name)) {
+ String replacer(Match match) {
+ String s = match[0];
+ if (s == '.') return '_';
+ return s.codeUnitAt(0).toRadixString(16);
+ }
+
+ name = name.replaceAllMapped(NON_IDENTIFIER_CHAR, replacer);
+ if (!IDENTIFIER.hasMatch(name)) {
+ // e.g. starts with digit.
+ name = 'lib_$name';
+ }
+ }
+ // Names constructed based on a libary name will be further disambiguated.
+ // However, as names from the same libary should have the same library
+ // name part, we disambiguate the library name here.
+ String disambiguated = name;
+ for (int c = 0; libraryLongNames.containsValue(disambiguated); c++) {
+ disambiguated = "$name$c";
+ }
+ libraryLongNames[library] = disambiguated;
+ return disambiguated;
}
String suffixForGetInterceptor(Iterable<ClassElement> classes) {
@@ -1251,6 +1260,7 @@
if (cls == helpers.jsInterceptorClass) return "I";
return cls.name;
}
+
List<String> names = classes
.where((cls) => !backend.isNativeOrExtendsNative(cls))
.map(abbreviate)
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 1e8cc1c..a28f232 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -298,6 +298,7 @@
methodsNeedingRti.add(method);
}
}
+
compiler.resolverWorld.closuresWithFreeTypeVariables
.forEach(analyzeMethod);
compiler.resolverWorld.callMethodsWithFreeTypeVariables
@@ -314,6 +315,7 @@
methodsNeedingRti.add(method);
}
}
+
compiler.resolverWorld.closuresWithFreeTypeVariables
.forEach(analyzeMethod);
compiler.resolverWorld.callMethodsWithFreeTypeVariables
@@ -417,6 +419,7 @@
functionArgumentCollector.collect(type);
}
}
+
collectFunctionTypeArguments(isChecks);
collectFunctionTypeArguments(checkedBounds);
@@ -432,6 +435,7 @@
}
}
}
+
collectTypeArguments(instantiatedTypes);
collectTypeArguments(checkedTypeArguments, isTypeArgument: true);
@@ -462,6 +466,7 @@
functionArgumentCollector.collect(type);
}
}
+
collectFunctionTypeArguments(instantiatedTypes);
collectFunctionTypeArguments(checkedTypeArguments);
@@ -471,6 +476,7 @@
collector.collect(type, isTypeArgument: isTypeArgument);
}
}
+
collectTypeArguments(isChecks);
collectTypeArguments(checkedBounds, isTypeArgument: true);
@@ -641,6 +647,7 @@
jsAst.Expression onVariable(TypeVariableType v) {
return new jsAst.VariableUse(v.name);
}
+
;
jsAst.Expression encoding = getTypeRepresentation(type, onVariable);
if (contextClass == null && !alwaysGenerateFunction) {
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
index cbc18bc..d918135 100644
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
@@ -222,8 +222,9 @@
return defaultValues;
}
- Map<ParameterElement, ParameterElement> mapRedirectingFactoryConstructorOptionalParameters(
- FunctionSignature source, FunctionSignature target) {
+ Map<ParameterElement, ParameterElement>
+ mapRedirectingFactoryConstructorOptionalParameters(
+ FunctionSignature source, FunctionSignature target) {
var map = <ParameterElement, ParameterElement>{};
if (source.optionalParametersAreNamed !=
@@ -361,6 +362,7 @@
}
return true;
}
+
void countTokensInTypes(Iterable<_BoundMetadataEntry> entries) {
jsAst.TokenCounter counter = new jsAst.TokenCounter();
entries
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index 78f3cda..137f407 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -96,6 +96,7 @@
walk(cls.superclass);
preOrder.add(cls);
}
+
classes.forEach(walk);
// Find which classes are needed and which are non-leaf classes. Any class
@@ -187,6 +188,7 @@
}
cls.nativeExtensions = extensionPoints[cls];
}
+
// Add properties containing the information needed to construct maps used
// by getNativeInterceptor and custom elements.
if (compiler.enqueuer.codegen.nativeEnqueuer
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index c41bfa9..16ada26 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -265,6 +265,7 @@
generateSubstitution(check);
}
}
+
;
tryEmitTest(cls);
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index e8f3340..166e6cf 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -296,6 +296,7 @@
}
return e;
}
+
_annotationCreatesClass = find('Creates');
_annotationReturnsClass = find('Returns');
_annotationJsNameClass = find('JSName');
diff --git a/pkg/compiler/lib/src/native/native.dart b/pkg/compiler/lib/src/native/native.dart
index c0d6a86..2c30a27 100644
--- a/pkg/compiler/lib/src/native/native.dart
+++ b/pkg/compiler/lib/src/native/native.dart
@@ -33,6 +33,7 @@
return scriptName.contains('sdk/tests/compiler/dart2js_native') ||
scriptName.contains('sdk/tests/compiler/dart2js_extra');
}
+
bool allowedDartLibary() {
Uri uri = library.canonicalUri;
if (uri.scheme != 'dart') return false;
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index b1aaeb0..1ee1bd4 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -218,9 +218,6 @@
/// Whether to generate code compliant with content security policy (CSP).
final bool useContentSecurityPolicy;
- /// Use the experimental CPS based backend.
- final bool useCpsIr;
-
/// When obfuscating for minification, whether to use the frequency of a name
/// as an heuristic to pick shorter names.
final bool useFrequencyNamer;
@@ -318,7 +315,6 @@
trustTypeAnnotations: _hasOption(options, Flags.trustTypeAnnotations),
useContentSecurityPolicy:
_hasOption(options, Flags.useContentSecurityPolicy),
- useCpsIr: _hasOption(options, Flags.useCpsIr),
useFrequencyNamer:
!_hasOption(options, Flags.noFrequencyBasedMinification),
useNewSourceInfo: _hasOption(options, Flags.useNewSourceInfo),
@@ -379,7 +375,6 @@
bool trustPrimitives: false,
bool trustTypeAnnotations: false,
bool useContentSecurityPolicy: false,
- bool useCpsIr: false,
bool useFrequencyNamer: true,
bool useNewSourceInfo: false,
bool useStartupEmitter: false,
@@ -452,7 +447,6 @@
trustPrimitives: trustPrimitives,
trustTypeAnnotations: trustTypeAnnotations,
useContentSecurityPolicy: useContentSecurityPolicy,
- useCpsIr: useCpsIr,
useFrequencyNamer: useFrequencyNamer,
useNewSourceInfo: useNewSourceInfo,
useStartupEmitter: useStartupEmitter,
@@ -502,7 +496,6 @@
this.trustPrimitives: false,
this.trustTypeAnnotations: false,
this.useContentSecurityPolicy: false,
- this.useCpsIr: false,
this.useFrequencyNamer: false,
this.useNewSourceInfo: false,
this.useStartupEmitter: false,
@@ -559,7 +552,6 @@
trustPrimitives,
trustTypeAnnotations,
useContentSecurityPolicy,
- useCpsIr,
useFrequencyNamer,
useNewSourceInfo,
useStartupEmitter,
@@ -628,7 +620,6 @@
trustTypeAnnotations ?? options.trustTypeAnnotations,
useContentSecurityPolicy:
useContentSecurityPolicy ?? options.useContentSecurityPolicy,
- useCpsIr: useCpsIr ?? options.useCpsIr,
useFrequencyNamer: useFrequencyNamer ?? options.useFrequencyNamer,
useNewSourceInfo: useNewSourceInfo ?? options.useNewSourceInfo,
useStartupEmitter: useStartupEmitter ?? options.useStartupEmitter,
@@ -701,8 +692,8 @@
return null;
}
-Uri _resolvePlatformConfig(Uri libraryRoot, String platformConfigPath,
- Iterable<String> categories) {
+Uri _resolvePlatformConfig(
+ Uri libraryRoot, String platformConfigPath, Iterable<String> categories) {
if (platformConfigPath != null) {
return libraryRoot.resolve(platformConfigPath);
} else {
diff --git a/pkg/compiler/lib/src/parser/element_listener.dart b/pkg/compiler/lib/src/parser/element_listener.dart
index ae1c592..e5904f0 100644
--- a/pkg/compiler/lib/src/parser/element_listener.dart
+++ b/pkg/compiler/lib/src/parser/element_listener.dart
@@ -321,6 +321,7 @@
void buildFieldElement(Identifier name, VariableList fields) {
pushElement(new FieldElementX(name, compilationUnitElement, fields));
}
+
NodeList variables = makeNodeList(count, null, null, ",");
popNode(); // type
Modifiers modifiers = popNode();
diff --git a/pkg/compiler/lib/src/parser/listener.dart b/pkg/compiler/lib/src/parser/listener.dart
index ce29d16..3115343 100644
--- a/pkg/compiler/lib/src/parser/listener.dart
+++ b/pkg/compiler/lib/src/parser/listener.dart
@@ -619,7 +619,13 @@
}
String closeBraceFor(String openBrace) {
- return const {'(': ')', '[': ']', '{': '}', '<': '>', r'${': '}',}[openBrace];
+ return const {
+ '(': ')',
+ '[': ']',
+ '{': '}',
+ '<': '>',
+ r'${': '}',
+ }[openBrace];
}
class ParserError {
diff --git a/pkg/compiler/lib/src/parser/member_listener.dart b/pkg/compiler/lib/src/parser/member_listener.dart
index b50847e..c21f493 100644
--- a/pkg/compiler/lib/src/parser/member_listener.dart
+++ b/pkg/compiler/lib/src/parser/member_listener.dart
@@ -122,6 +122,7 @@
Element element = new FieldElementX(name, enclosingClass, fields);
addMember(element);
}
+
buildFieldElements(modifiers, variableDefinitions.definitions,
enclosingClass, buildFieldElement, beginToken, endToken, hasParseError);
}
diff --git a/pkg/compiler/lib/src/parser/partial_elements.dart b/pkg/compiler/lib/src/parser/partial_elements.dart
index 8e74bf3..87cb2f1 100644
--- a/pkg/compiler/lib/src/parser/partial_elements.dart
+++ b/pkg/compiler/lib/src/parser/partial_elements.dart
@@ -92,6 +92,7 @@
p.parseFunction(beginToken, getOrSet);
}
}
+
cachedNode = parse(parsing, this, declarationSite, parseFunction);
return cachedNode;
}
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index cdc5c02..ec04ed5 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -91,6 +91,7 @@
bound = element.bound;
}
}
+
addDeferredAction(element, checkTypeVariableBound);
} else {
variableElement.boundCache = objectType;
diff --git a/pkg/compiler/lib/src/resolution/class_members.dart b/pkg/compiler/lib/src/resolution/class_members.dart
index b4ae169..aca4df5 100644
--- a/pkg/compiler/lib/src/resolution/class_members.dart
+++ b/pkg/compiler/lib/src/resolution/class_members.dart
@@ -280,6 +280,7 @@
reporter.reportWarning(warning, infos);
});
}
+
if (interfaceMember.isSetter) {
reportWarning(
MessageKind.UNIMPLEMENTED_SETTER_ONE,
@@ -443,6 +444,7 @@
]);
});
}
+
if (declared.isDeclaredByField) {
if (inherited.isDeclaredByField) {
reportWarning(
@@ -686,7 +688,8 @@
bool allAreGetters = true;
Map<DartType, Setlet<Member>> subtypesOfAllInherited =
new Map<DartType, Setlet<Member>>();
- outer: for (Member inherited in inheritedMembers) {
+ outer:
+ for (Member inherited in inheritedMembers) {
if (inherited.isGetter) {
someAreGetters = true;
if (!allAreGetters) break outer;
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 8ef45c0..d06b967 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -3749,6 +3749,7 @@
reporter.reportErrorMessage(modifierNode, MessageKind.EXTRANEOUS_MODIFIER,
{'modifier': modifier});
}
+
if (modifiers.isFinal && (modifiers.isConst || modifiers.isVar)) {
reportExtraModifier('final');
}
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index 619f748..b33714c 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -350,80 +350,82 @@
}
WorldImpact resolveField(FieldElementX element) {
- VariableDefinitions tree = element.parseNode(parsingContext);
- if (element.modifiers.isStatic && element.isTopLevel) {
- reporter.reportErrorMessage(element.modifiers.getStatic(),
- MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC);
- }
- ResolverVisitor visitor = visitorFor(element);
- ResolutionRegistry registry = visitor.registry;
- // TODO(johnniwinther): Maybe remove this when placeholderCollector migrates
- // to the backend ast.
- registry.defineElement(tree.definitions.nodes.head, element);
- // TODO(johnniwinther): Share the resolved type between all variables
- // declared in the same declaration.
- if (tree.type != null) {
- DartType type = visitor.resolveTypeAnnotation(tree.type);
- assert(invariant(
- element,
- element.variables.type == null ||
- // Crude check but we have no equivalence relation that
- // equates malformed types, like matching creations of type
- // `Foo<Unresolved>`.
- element.variables.type.toString() == type.toString(),
- message: "Unexpected type computed for $element. "
- "Was ${element.variables.type}, computed $type."));
- element.variables.type = type;
- } else if (element.variables.type == null) {
- // Only assign the dynamic type if the element has no known type. This
- // happens for enum fields where the type is known but is not in the
- // synthesized AST.
- element.variables.type = const DynamicType();
- }
-
- Expression initializer = element.initializer;
- Modifiers modifiers = element.modifiers;
- if (initializer != null) {
- // TODO(johnniwinther): Avoid analyzing initializers if
- // [Compiler.analyzeSignaturesOnly] is set.
- ResolutionResult result = visitor.visit(initializer);
- if (result.isConstant) {
- element.constant = result.constant;
+ return reporter.withCurrentElement(element, () {
+ VariableDefinitions tree = element.parseNode(parsingContext);
+ if (element.modifiers.isStatic && element.isTopLevel) {
+ reporter.reportErrorMessage(element.modifiers.getStatic(),
+ MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC);
}
- } else if (modifiers.isConst) {
- reporter.reportErrorMessage(
- element, MessageKind.CONST_WITHOUT_INITIALIZER);
- } else if (modifiers.isFinal && !element.isInstanceMember) {
- reporter.reportErrorMessage(
- element, MessageKind.FINAL_WITHOUT_INITIALIZER);
- } else {
- // TODO(johnniwinther): Register a feature instead.
- registry.registerTypeUse(new TypeUse.instantiation(coreTypes.nullType));
- }
+ ResolverVisitor visitor = visitorFor(element);
+ ResolutionRegistry registry = visitor.registry;
+ // TODO(johnniwinther): Maybe remove this when placeholderCollector migrates
+ // to the backend ast.
+ registry.defineElement(tree.definitions.nodes.head, element);
+ // TODO(johnniwinther): Share the resolved type between all variables
+ // declared in the same declaration.
+ if (tree.type != null) {
+ DartType type = visitor.resolveTypeAnnotation(tree.type);
+ assert(invariant(
+ element,
+ element.variables.type == null ||
+ // Crude check but we have no equivalence relation that
+ // equates malformed types, like matching creations of type
+ // `Foo<Unresolved>`.
+ element.variables.type.toString() == type.toString(),
+ message: "Unexpected type computed for $element. "
+ "Was ${element.variables.type}, computed $type."));
+ element.variables.type = type;
+ } else if (element.variables.type == null) {
+ // Only assign the dynamic type if the element has no known type. This
+ // happens for enum fields where the type is known but is not in the
+ // synthesized AST.
+ element.variables.type = const DynamicType();
+ }
- if (Elements.isStaticOrTopLevelField(element)) {
- visitor.addDeferredAction(element, () {
- if (element.modifiers.isConst) {
- element.constant = constantCompiler.compileConstant(element);
- } else {
- element.constant = constantCompiler.compileVariable(element);
- }
- });
+ Expression initializer = element.initializer;
+ Modifiers modifiers = element.modifiers;
if (initializer != null) {
- if (!element.modifiers.isConst) {
- // TODO(johnniwinther): Determine the const-ness eagerly to avoid
- // unnecessary registrations.
- registry.registerFeature(Feature.LAZY_FIELD);
+ // TODO(johnniwinther): Avoid analyzing initializers if
+ // [Compiler.analyzeSignaturesOnly] is set.
+ ResolutionResult result = visitor.visit(initializer);
+ if (result.isConstant) {
+ element.constant = result.constant;
+ }
+ } else if (modifiers.isConst) {
+ reporter.reportErrorMessage(
+ element, MessageKind.CONST_WITHOUT_INITIALIZER);
+ } else if (modifiers.isFinal && !element.isInstanceMember) {
+ reporter.reportErrorMessage(
+ element, MessageKind.FINAL_WITHOUT_INITIALIZER);
+ } else {
+ // TODO(johnniwinther): Register a feature instead.
+ registry.registerTypeUse(new TypeUse.instantiation(coreTypes.nullType));
+ }
+
+ if (Elements.isStaticOrTopLevelField(element)) {
+ visitor.addDeferredAction(element, () {
+ if (element.modifiers.isConst) {
+ element.constant = constantCompiler.compileConstant(element);
+ } else {
+ element.constant = constantCompiler.compileVariable(element);
+ }
+ });
+ if (initializer != null) {
+ if (!element.modifiers.isConst) {
+ // TODO(johnniwinther): Determine the const-ness eagerly to avoid
+ // unnecessary registrations.
+ registry.registerFeature(Feature.LAZY_FIELD);
+ }
}
}
- }
- // Perform various checks as side effect of "computing" the type.
- element.computeType(resolution);
+ // Perform various checks as side effect of "computing" the type.
+ element.computeType(resolution);
- resolution.target.resolveNativeElement(element, registry.worldImpact);
+ resolution.target.resolveNativeElement(element, registry.worldImpact);
- return registry.worldImpact;
+ return registry.worldImpact;
+ });
}
DartType resolveTypeAnnotation(Element element, TypeAnnotation annotation) {
diff --git a/pkg/compiler/lib/src/resolution/typedefs.dart b/pkg/compiler/lib/src/resolution/typedefs.dart
index eed801b..1c52c93 100644
--- a/pkg/compiler/lib/src/resolution/typedefs.dart
+++ b/pkg/compiler/lib/src/resolution/typedefs.dart
@@ -48,6 +48,7 @@
void checkCyclicReference() {
element.checkCyclicReference(resolution);
}
+
addDeferredAction(element, checkCyclicReference);
}
}
diff --git a/pkg/compiler/lib/src/scanner/scanner.dart b/pkg/compiler/lib/src/scanner/scanner.dart
index 63f4bd0..f069861 100644
--- a/pkg/compiler/lib/src/scanner/scanner.dart
+++ b/pkg/compiler/lib/src/scanner/scanner.dart
@@ -684,7 +684,8 @@
int tokenizeFractionPart(int next, int start) {
bool done = false;
bool hasDigit = false;
- LOOP: while (!done) {
+ LOOP:
+ while (!done) {
if ($0 <= next && next <= $9) {
hasDigit = true;
} else if (identical($e, next) || identical($E, next)) {
@@ -1002,7 +1003,8 @@
bool asciiOnlyLine = true;
int unicodeStart = start;
int next = advance(); // Advance past the (last) quote (of three).
- outer: while (!identical(next, $EOF)) {
+ outer:
+ while (!identical(next, $EOF)) {
while (!identical(next, quoteChar)) {
if (identical(next, $LF)) {
if (!asciiOnlyLine) {
diff --git a/pkg/compiler/lib/src/serialization/equivalence.dart b/pkg/compiler/lib/src/serialization/equivalence.dart
index fccc44e..40cd377 100644
--- a/pkg/compiler/lib/src/serialization/equivalence.dart
+++ b/pkg/compiler/lib/src/serialization/equivalence.dart
@@ -280,7 +280,8 @@
return areElementsEquivalent(ad.prefix, bd.prefix) &&
areSendStructuresEquivalent(ad.sendStructure, bd.sendStructure);
- semantics: case SendStructureKind.GET:
+ semantics:
+ case SendStructureKind.GET:
case SendStructureKind.SET:
case SendStructureKind.INDEX:
case SendStructureKind.INDEX_SET:
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index 22273d4..94052cb 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -352,7 +352,8 @@
/// corresponding bazel location. This way there is no need to create a pub
/// cache prior to invoking dart2js.
///
-/// * We provide a mapping that can make all urls relative to the bazel root.
+/// * We provide an implicit mapping that can make all urls relative to the
+/// bazel root.
/// To the compiler, URIs look like:
/// file:///bazel-root/a/b/c.dart
///
@@ -367,55 +368,41 @@
/// we can use the standard package-resolution mechanism and ignore the
/// internals of how files are organized within bazel.
///
-/// This class is initialized using a dart2js-bazel configuration file. The file
-/// follows the following custom format:
-///
-/// <generated-path-prefix>
-/// <file1-bazel-root-relative-path>
-/// <file2-bazel-root-relative-path>
-/// ...
-/// <fileN-bazel-root-relative-path>
-///
-/// For example:
-///
-/// bazel-bin/123/
-/// a/b/c.dart
-/// bazel-bin/123/a/b/d.dart
-/// a/b/e.dart
-///
-/// The current working directory will be used to resolve the bazel-root and
-/// when invoking the compiler, bazel will use `package:` and
+/// When invoking the compiler, bazel will use `package:` and
/// `file:///bazel-root/` URIs to specify entrypoints.
+///
+/// The mapping is specified using search paths relative to the current
+/// directory. When this provider looks up a file, the bazel-root folder is
+/// replaced by the first directory in the search path containing the file, if
+/// any. For example, given the search path ".,bazel-bin/", and a URL
+/// of the form `file:///bazel-root/a/b.dart`, this provider will check if the
+/// file exists under "./a/b.dart", then check under "bazel-bin/a/b.dart". If
+/// none of the paths matches, it will attempt to load the file from
+/// `/bazel-root/a/b.dart` which will likely fail.
class BazelInputProvider extends SourceFileProvider {
- /// Anything above this root is treated as machine specific and will only be
- /// used to locate files on disk, but otherwise it's abstracted away in the
- /// representation of canonical uris in the compiler.
- final Uri bazelRoot;
+ final List<Uri> dirs;
- /// Path prefix where generated files are located.
- final String genPath;
+ BazelInputProvider(List<String> searchPaths)
+ : dirs = searchPaths.map(_resolve).toList();
- /// Mapping from bazel-root uris to relative paths on top of [bazelRoot].
- final Map<Uri, Uri> mappings = <Uri, Uri>{};
-
- factory BazelInputProvider(String configPath) {
- var config = new File(configPath).readAsLinesSync();
- var bazelRoot = currentDirectory;
- var outPrefix = config[0];
- var files = config.skip(1);
- return new BazelInputProvider._(bazelRoot, outPrefix, files);
- }
-
- BazelInputProvider._(this.bazelRoot, this.genPath, Iterable<String> files) {
- var fakeBazelRoot = Uri.parse('file:///bazel-root/');
- for (var path in files) {
- var absolute = currentDirectory.resolve(path);
- var bazelRelativeUri = fakeBazelRoot.resolve(
- path.startsWith(genPath) ? path.substring(genPath.length) : path);
- mappings[bazelRelativeUri] = absolute;
- }
- }
+ static _resolve(String path) => currentDirectory.resolve(path);
@override
- Future readFromUri(Uri uri) => readUtf8BytesFromUri(mappings[uri] ?? uri);
+ Future readFromUri(Uri uri) async {
+ var resolvedUri = uri;
+ var path = uri.path;
+ if (path.startsWith('/bazel-root')) {
+ path = path.substring('/bazel-root/'.length);
+ for (var dir in dirs) {
+ var file = dir.resolve(path);
+ if (await new File.fromUri(file).exists()) {
+ resolvedUri = file;
+ break;
+ }
+ }
+ }
+ var result = await readUtf8BytesFromUri(resolvedUri);
+ sourceFiles[uri] = sourceFiles[resolvedUri];
+ return result;
+ }
}
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 7148581..77025b0 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -206,8 +206,10 @@
LocalsHandler(
this.builder, this.executableContext, InterfaceType instanceType)
- : this.instanceType = instanceType == null ||
- instanceType.containsTypeVariables ? null : instanceType;
+ : this.instanceType =
+ instanceType == null || instanceType.containsTypeVariables
+ ? null
+ : instanceType;
/// Substituted type variables occurring in [type] into the context of
/// [contextClass].
@@ -2760,11 +2762,13 @@
visit(node.condition);
pushInvokeStatic(node, helpers.assertTest, [pop()]);
}
+
void fail() {
visit(node.message);
pushInvokeStatic(node, helpers.assertThrow, [pop()]);
pop();
}
+
handleIf(node, visitCondition: buildCondition, visitThen: fail);
}
@@ -3098,6 +3102,7 @@
pop();
}
}
+
HInstruction buildCondition() {
if (node.condition == null) {
return graph.addConstantBool(true, compiler);
@@ -3105,6 +3110,7 @@
visit(node.condition);
return popBoolified();
}
+
void buildUpdate() {
for (ast.Expression expression in node.update) {
visit(expression);
@@ -3114,9 +3120,11 @@
pop();
}
}
+
void buildBody() {
visit(node.body);
}
+
handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody);
}
@@ -3126,6 +3134,7 @@
visit(node.condition);
return popBoolified();
}
+
handleLoop(node, () {}, buildCondition, () {}, () {
visit(node.body);
});
@@ -5666,8 +5675,10 @@
// Native behavior effects here are similar to native/behavior.dart.
// The return type is dynamic if we don't trust js-interop type
// declarations.
- nativeBehavior.typesReturned.add(compiler
- .options.trustJSInteropTypeAnnotations ? type : const DynamicType());
+ nativeBehavior.typesReturned.add(
+ compiler.options.trustJSInteropTypeAnnotations
+ ? type
+ : const DynamicType());
// The allocation effects include the declared type if it is native (which
// includes js interop types).
@@ -5801,6 +5812,7 @@
add(buildInvokeSuper(setterSelector, element, setterInputs));
}
}
+
if (identical(node.assignmentOperator.source, '=')) {
addDynamicSendArgumentsToList(node, setterInputs);
generateSuperSendSet();
@@ -6389,6 +6401,7 @@
stack.add(getterInstruction);
}
}
+
if (node.isConditional) {
// generate `e?.x op= e2` as:
// t1 = e
@@ -6639,6 +6652,7 @@
void loadLocal(ParameterElement parameter) {
inputs.add(localsHandler.readLocal(parameter));
}
+
void loadPosition(int position, ParameterElement optionalParameter) {
if (position < redirectingRequireds.length) {
loadLocal(redirectingRequireds[position]);
@@ -6927,6 +6941,7 @@
new TypeMask.subclass(coreClasses.objectClass, compiler.world)));
return popBoolified();
}
+
void buildBody() {
Selector call = Selectors.current;
TypeMask callMask = elements.getCurrentTypeMask(node);
@@ -7341,6 +7356,7 @@
visit(node.expression);
return pop();
}
+
Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) {
List<ConstantValue> constantList = <ConstantValue>[];
for (ast.Node labelOrCase in switchCase.labelsAndCases) {
@@ -7350,12 +7366,15 @@
}
return constantList;
}
+
bool isDefaultCase(ast.SwitchCase switchCase) {
return switchCase.isDefaultCase;
}
+
void buildSwitchCase(ast.SwitchCase node) {
visit(node.statements);
}
+
handleSwitch(node, jumpHandler, buildExpression, node.cases, getConstants,
isDefaultCase, buildSwitchCase);
jumpHandler.close();
@@ -7414,6 +7433,7 @@
visit(node.expression);
return pop();
}
+
Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) {
List<ConstantValue> constantList = <ConstantValue>[];
if (switchCase != null) {
@@ -7425,9 +7445,11 @@
}
return constantList;
}
+
bool isDefaultCase(ast.SwitchCase switchCase) {
return switchCase == null || switchCase.isDefaultCase;
}
+
void buildSwitchCase(ast.SwitchCase switchCase) {
if (switchCase != null) {
// Generate 'target = i; break;' for switch case i.
@@ -7441,6 +7463,7 @@
}
jumpTargets[switchTarget].generateBreak();
}
+
handleSwitch(node, jumpHandler, buildExpression, switchCases, getConstants,
isDefaultCase, buildSwitchCase);
jumpHandler.close();
@@ -7451,9 +7474,11 @@
HInstruction buildExpression() {
return localsHandler.readLocal(switchTarget);
}
+
Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) {
return <ConstantValue>[constantSystem.createInt(caseIndex[switchCase])];
}
+
void buildSwitchCase(ast.SwitchCase switchCase) {
visit(switchCase.statements);
if (!isAborted()) {
@@ -7462,6 +7487,7 @@
jumpTargets[switchTarget].generateBreak();
}
}
+
// Pass a [NullJumpHandler] because the target for the contained break
// is not the generated switch statement but instead the loop generated
// in the call to [handleLoop] below.
@@ -7490,6 +7516,7 @@
code, backend.boolType, [localsHandler.readLocal(switchTarget)],
nativeBehavior: native.NativeBehavior.PURE));
}
+
handleIf(node,
visitCondition: buildCondition,
visitThen: buildLoop,
@@ -7865,6 +7892,7 @@
addOptionalSuccessor(b1, b2) {
if (b2 != null) b1.addSuccessor(b2);
}
+
addExitTrySuccessor(successor) {
if (successor == null) return;
// Iterate over all blocks created inside this try/catch, and
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 9637549..e961485 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -740,6 +740,7 @@
registry.registerInstantiatedClass(classElement);
}
}
+
register(helpers.jsPlainJavaScriptObjectClass);
register(helpers.jsUnknownJavaScriptObjectClass);
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index 6a5c82d..8cc7467 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -185,7 +185,8 @@
HInstruction findDominator(Iterable<HInstruction> instructions) {
HInstruction result;
- L1: for (HInstruction candidate in instructions) {
+ L1:
+ for (HInstruction candidate in instructions) {
for (HInstruction current in instructions) {
if (current != candidate && !candidate.dominates(current)) continue L1;
}
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 3b119bd..01be037 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -674,7 +674,8 @@
if (better.isEmpty) return rewrite(from, to);
- L1: for (HInstruction user in from.usedBy) {
+ L1:
+ for (HInstruction user in from.usedBy) {
for (HCheck check in better) {
if (check.dominates(user)) {
user.rewriteInput(from, check);
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 80f5e16..9dd26ff 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -1223,6 +1223,7 @@
}
return false;
}
+
return instruction.isAllocation &&
instruction.isPure() &&
trivialDeadStoreReceivers.putIfAbsent(
@@ -1275,7 +1276,8 @@
}
void cleanPhis(HGraph graph) {
- L: for (HBasicBlock block in graph.blocks) {
+ L:
+ for (HBasicBlock block in graph.blocks) {
List<HBasicBlock> predecessors = block.predecessors;
// Zap all inputs to phis that correspond to dead blocks.
block.forEachPhi((HPhi phi) {
@@ -1569,6 +1571,7 @@
assert(instruction is HGoto || instruction is HLoopBranch);
return instruction is HGoto || instruction.inputs[0].isConstantTrue();
}
+
bool firstInstructionInLoop = block == loopHeader
// Compensate for lack of code motion.
||
diff --git a/pkg/compiler/lib/src/tracer.dart b/pkg/compiler/lib/src/tracer.dart
index 09b8b98..21d2ed5 100644
--- a/pkg/compiler/lib/src/tracer.dart
+++ b/pkg/compiler/lib/src/tracer.dart
@@ -9,12 +9,8 @@
import '../compiler.dart' as api;
import 'common/work.dart' show ItemCompilationContext;
import 'compiler.dart' show Compiler;
-import 'cps_ir/cps_ir_nodes.dart' as cps_ir;
-import 'cps_ir/cps_ir_tracer.dart' show IRTracer;
import 'ssa/nodes.dart' as ssa show HGraph;
import 'ssa/ssa_tracer.dart' show HTracer;
-import 'tree_ir/tree_ir_nodes.dart' as tree_ir;
-import 'tree_ir/tree_ir_tracer.dart' show TreeTracer;
import 'util/util.dart' show Indentation;
/**
@@ -58,10 +54,6 @@
if (!traceActive) return;
if (irObject is ssa.HGraph) {
new HTracer(output, compiler, context).traceGraph(name, irObject);
- } else if (irObject is cps_ir.FunctionDefinition) {
- new IRTracer(output).traceGraph(name, irObject);
- } else if (irObject is tree_ir.FunctionDefinition) {
- new TreeTracer(output).traceGraph(name, irObject);
}
}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
deleted file mode 100644
index bdfadae..0000000
--- a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
+++ /dev/null
@@ -1,566 +0,0 @@
-// 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 tree_ir.optimization.logical_rewriter;
-
-import '../../constants/values.dart' as values;
-import '../tree_ir_nodes.dart';
-import 'optimization.dart' show Pass;
-
-/// Rewrites logical expressions to be more compact in the Tree IR.
-///
-/// In this class an expression is said to occur in "boolean context" if
-/// its result is immediately applied to boolean conversion.
-///
-/// IF STATEMENTS:
-///
-/// We apply the following two rules to [If] statements (see [visitIf]).
-///
-/// if (E) {} else S ==> if (!E) S else {} (else can be omitted)
-/// if (!E) S1 else S2 ==> if (E) S2 else S1 (unless previous rule applied)
-///
-/// NEGATION:
-///
-/// De Morgan's Laws are used to rewrite negations of logical operators so
-/// negations are closer to the root:
-///
-/// !x && !y --> !(x || y)
-///
-/// This is to enable other rewrites, such as branch swapping in an if. In some
-/// contexts, the rule is reversed because we do not expect to apply a rewrite
-/// rule to the result. For example:
-///
-/// z = !(x || y) ==> z = !x && !y;
-///
-/// CONDITIONALS:
-///
-/// Conditionals with boolean constant operands occur frequently in the input.
-/// They can often the re-written to logical operators, for instance:
-///
-/// if (x ? y : false) S1 else S2
-/// ==>
-/// if (x && y) S1 else S2
-///
-/// Conditionals are tricky to rewrite when they occur out of boolean context.
-/// Here we must apply more conservative rules, such as:
-///
-/// x ? true : false ==> !!x
-///
-/// If the possible falsy values of the condition are known, we can sometimes
-/// introduce a logical operator:
-///
-/// !x ? y : false ==> !x && y
-///
-class LogicalRewriter extends RecursiveTransformer implements Pass {
- String get passName => 'Logical rewriter';
-
- @override
- void rewrite(FunctionDefinition node) {
- node.body = visitStatement(node.body);
- }
-
- final FallthroughStack fallthrough = new FallthroughStack();
-
- /// True if the given statement is equivalent to its fallthrough semantics.
- ///
- /// This means it will ultimately translate to an empty statement.
- bool isFallthrough(Statement node) {
- return node is Break && isFallthroughBreak(node) ||
- node is Continue && isFallthroughContinue(node) ||
- node is Return && isFallthroughReturn(node);
- }
-
- bool isFallthroughBreak(Break node) {
- Statement target = fallthrough.target;
- return node.target.binding.next == target ||
- target is Break && target.target == node.target;
- }
-
- bool isFallthroughContinue(Continue node) {
- Statement target = fallthrough.target;
- return node.target.binding == target ||
- target is Continue && target.target == node.target;
- }
-
- bool isFallthroughReturn(Return node) {
- return isNull(node.value) && fallthrough.target == null;
- }
-
- bool isTerminator(Statement node) {
- return (node is Jump || node is Return) && !isFallthrough(node) ||
- (node is ExpressionStatement && node.next is Unreachable) ||
- node is Throw;
- }
-
- Statement visitIf(If node) {
- // If one of the branches is empty (i.e. just a fallthrough), then that
- // branch should preferably be the 'else' so we won't have to print it.
- // In other words, we wish to perform this rewrite:
- // if (E) {} else {S}
- // ==>
- // if (!E) {S}
- // In the tree language, empty statements do not exist yet, so we must check
- // if one branch contains a break that can be eliminated by fallthrough.
-
- // Rewrite each branch and keep track of which ones might fall through.
- int usesBefore = fallthrough.useCount;
- node.thenStatement = visitStatement(node.thenStatement);
- int usesAfterThen = fallthrough.useCount;
- node.elseStatement = visitStatement(node.elseStatement);
- bool thenHasFallthrough = (fallthrough.useCount > usesBefore);
- bool elseHasFallthrough = (fallthrough.useCount > usesAfterThen);
-
- // Determine which branch is most beneficial as 'then' branch.
- const int THEN = 1;
- const int NEITHER = 0;
- const int ELSE = -1;
- int bestThenBranch = NEITHER;
- if (isFallthrough(node.thenStatement) &&
- !isFallthrough(node.elseStatement)) {
- // Put the empty statement in the 'else' branch.
- // if (E) {} else {S} ==> if (!E) {S}
- bestThenBranch = ELSE;
- } else if (isFallthrough(node.elseStatement) &&
- !isFallthrough(node.thenStatement)) {
- // Keep the empty statement in the 'else' branch.
- // if (E) {S} else {}
- bestThenBranch = THEN;
- } else if (thenHasFallthrough && !elseHasFallthrough) {
- // Put abrupt termination in the 'then' branch to omit 'else'.
- // if (E) {S1} else {S2; return v} ==> if (!E) {S2; return v}; S1
- bestThenBranch = ELSE;
- } else if (!thenHasFallthrough && elseHasFallthrough) {
- // Keep abrupt termination in the 'then' branch to omit 'else'.
- // if (E) {S1; return v}; S2
- bestThenBranch = THEN;
- } else if (isTerminator(node.elseStatement) &&
- !isTerminator(node.thenStatement)) {
- // Put early termination in the 'then' branch to reduce nesting depth.
- // if (E) {S}; return v ==> if (!E) return v; S
- bestThenBranch = ELSE;
- } else if (isTerminator(node.thenStatement) &&
- !isTerminator(node.elseStatement)) {
- // Keep early termination in the 'then' branch to reduce nesting depth.
- // if (E) {return v;} S
- bestThenBranch = THEN;
- }
-
- // Swap branches if 'else' is better as 'then'
- if (bestThenBranch == ELSE) {
- node.condition = new Not(node.condition);
- Statement tmp = node.thenStatement;
- node.thenStatement = node.elseStatement;
- node.elseStatement = tmp;
- }
-
- // If neither branch is better, eliminate a negation in the condition
- // if (!E) S1 else S2
- // ==>
- // if (E) S2 else S1
- node.condition = makeCondition(node.condition, true,
- liftNots: bestThenBranch == NEITHER);
- if (bestThenBranch == NEITHER && node.condition is Not) {
- node.condition = (node.condition as Not).operand;
- Statement tmp = node.thenStatement;
- node.thenStatement = node.elseStatement;
- node.elseStatement = tmp;
- }
-
- return node;
- }
-
- Statement visitLabeledStatement(LabeledStatement node) {
- fallthrough.push(node.next);
- node.body = visitStatement(node.body);
- fallthrough.pop();
- node.next = visitStatement(node.next);
- return node;
- }
-
- Statement visitWhileTrue(WhileTrue node) {
- fallthrough.push(node);
- node.body = visitStatement(node.body);
- fallthrough.pop();
- return node;
- }
-
- Statement visitFor(For node) {
- fallthrough.push(node);
- node.condition = makeCondition(node.condition, true, liftNots: false);
- node.body = visitStatement(node.body);
- fallthrough.pop();
- node.next = visitStatement(node.next);
- return node;
- }
-
- Statement visitBreak(Break node) {
- if (isFallthroughBreak(node)) {
- fallthrough.use();
- }
- return node;
- }
-
- Statement visitContinue(Continue node) {
- if (isFallthroughContinue(node)) {
- fallthrough.use();
- }
- return node;
- }
-
- Statement visitReturn(Return node) {
- node.value = visitExpression(node.value);
- if (isFallthroughReturn(node)) {
- fallthrough.use();
- }
- return node;
- }
-
- Expression visitNot(Not node) {
- return toBoolean(makeCondition(node.operand, false, liftNots: false));
- }
-
- /// True if the only possible falsy return value of [condition] is [value].
- ///
- /// If [value] is `null` or a truthy value, false is returned. This is to make
- /// pattern matching more convenient.
- bool matchesFalsyValue(Expression condition, values.ConstantValue value) {
- if (value == null) return false;
- // TODO(asgerf): Here we could really use some more type information,
- // this is just the best we can do at the moment.
- return isBooleanValued(condition) && value.isFalse;
- }
-
- /// True if the only possible truthy return value of [condition] is [value].
- ///
- /// If [value] is `null` or a falsy value, false is returned. This is to make
- /// pattern matching more convenient.
- bool matchesTruthyValue(Expression condition, values.ConstantValue value) {
- if (value == null) return false;
- // TODO(asgerf): Again, more type information could really beef this up.
- return isBooleanValued(condition) && value.isTrue;
- }
-
- values.ConstantValue getConstant(Expression exp) {
- return exp is Constant ? exp.value : null;
- }
-
- Expression visitConditional(Conditional node) {
- // node.condition will be visited after the then and else parts, because its
- // polarity depends on what rewrite we use.
- node.thenExpression = visitExpression(node.thenExpression);
- node.elseExpression = visitExpression(node.elseExpression);
-
- // In the following, we must take care not to eliminate or introduce a
- // boolean conversion.
-
- // x ? true : false --> !!x
- if (isTrue(node.thenExpression) && isFalse(node.elseExpression)) {
- return toBoolean(makeCondition(node.condition, true, liftNots: false));
- }
- // x ? false : true --> !x
- if (isFalse(node.thenExpression) && isTrue(node.elseExpression)) {
- return toBoolean(makeCondition(node.condition, false, liftNots: false));
- }
-
- // x ? y : false ==> x && y (if x is truthy or false)
- // x ? y : null ==> x && y (if x is truthy or null)
- // x ? y : 0 ==> x && y (if x is truthy or zero) (and so on...)
- if (matchesFalsyValue(node.condition, getConstant(node.elseExpression))) {
- return new LogicalOperator.and(
- visitExpression(node.condition), node.thenExpression);
- }
- // x ? true : y ==> x || y (if x is falsy or true)
- // x ? 1 : y ==> x || y (if x is falsy or one) (and so on...)
- if (matchesTruthyValue(node.condition, getConstant(node.thenExpression))) {
- return new LogicalOperator.or(
- visitExpression(node.condition), node.elseExpression);
- }
- // x ? y : true ==> !x || y
- if (isTrue(node.elseExpression)) {
- return new LogicalOperator.or(
- toBoolean(makeCondition(node.condition, false, liftNots: false)),
- node.thenExpression);
- }
- // x ? false : y ==> !x && y
- if (isFalse(node.thenExpression)) {
- return new LogicalOperator.and(
- toBoolean(makeCondition(node.condition, false, liftNots: false)),
- node.elseExpression);
- }
-
- node.condition = makeCondition(node.condition, true);
-
- // !x ? y : z ==> x ? z : y
- if (node.condition is Not) {
- node.condition = (node.condition as Not).operand;
- Expression tmp = node.thenExpression;
- node.thenExpression = node.elseExpression;
- node.elseExpression = tmp;
- }
-
- // x ? y : x ==> x && y
- if (isSameVariable(node.condition, node.elseExpression)) {
- destroyVariableUse(node.elseExpression);
- return new LogicalOperator.and(node.condition, node.thenExpression);
- }
- // x ? x : y ==> x || y
- if (isSameVariable(node.condition, node.thenExpression)) {
- destroyVariableUse(node.thenExpression);
- return new LogicalOperator.or(node.condition, node.elseExpression);
- }
-
- return node;
- }
-
- Expression visitLogicalOperator(LogicalOperator node) {
- node.left = visitExpression(node.left);
- node.right = visitExpression(node.right);
- return node;
- }
-
- /// True if the given expression is known to evaluate to a boolean.
- /// This will not recursively traverse [Conditional] expressions, but if
- /// applied to the result of [visitExpression] conditionals will have been
- /// rewritten anyway.
- bool isBooleanValued(Expression e) {
- return isTrue(e) ||
- isFalse(e) ||
- e is Not ||
- e is LogicalOperator && isBooleanValuedLogicalOperator(e) ||
- e is ApplyBuiltinOperator && operatorReturnsBool(e.operator) ||
- e is TypeOperator && isBooleanValuedTypeOperator(e);
- }
-
- bool isBooleanValuedLogicalOperator(LogicalOperator e) {
- return isBooleanValued(e.left) && isBooleanValued(e.right);
- }
-
- /// True if the given operator always returns `true` or `false`.
- bool operatorReturnsBool(BuiltinOperator operator) {
- switch (operator) {
- case BuiltinOperator.StrictEq:
- case BuiltinOperator.StrictNeq:
- case BuiltinOperator.LooseEq:
- case BuiltinOperator.LooseNeq:
- case BuiltinOperator.NumLt:
- case BuiltinOperator.NumLe:
- case BuiltinOperator.NumGt:
- case BuiltinOperator.NumGe:
- case BuiltinOperator.IsNumber:
- case BuiltinOperator.IsNotNumber:
- case BuiltinOperator.IsFloor:
- case BuiltinOperator.IsInteger:
- case BuiltinOperator.IsNotInteger:
- case BuiltinOperator.Identical:
- return true;
- default:
- return false;
- }
- }
-
- bool isBooleanValuedTypeOperator(TypeOperator e) {
- return e.isTypeTest;
- }
-
- BuiltinOperator negateBuiltin(BuiltinOperator operator) {
- switch (operator) {
- case BuiltinOperator.StrictEq:
- return BuiltinOperator.StrictNeq;
- case BuiltinOperator.StrictNeq:
- return BuiltinOperator.StrictEq;
- case BuiltinOperator.LooseEq:
- return BuiltinOperator.LooseNeq;
- case BuiltinOperator.LooseNeq:
- return BuiltinOperator.LooseEq;
- case BuiltinOperator.IsNumber:
- return BuiltinOperator.IsNotNumber;
- case BuiltinOperator.IsNotNumber:
- return BuiltinOperator.IsNumber;
- case BuiltinOperator.IsInteger:
- return BuiltinOperator.IsNotInteger;
- case BuiltinOperator.IsNotInteger:
- return BuiltinOperator.IsInteger;
- case BuiltinOperator.IsUnsigned32BitInteger:
- return BuiltinOperator.IsNotUnsigned32BitInteger;
- case BuiltinOperator.IsNotUnsigned32BitInteger:
- return BuiltinOperator.IsUnsigned32BitInteger;
-
- // Because of NaN, these do not have a negated form.
- case BuiltinOperator.NumLt:
- case BuiltinOperator.NumLe:
- case BuiltinOperator.NumGt:
- case BuiltinOperator.NumGe:
- return null;
-
- default:
- return null;
- }
- }
-
- /// Forces a boolean conversion of the given expression.
- Expression toBoolean(Expression e) {
- if (isBooleanValued(e))
- return e;
- else
- return new Not(new Not(e));
- }
-
- /// Creates an equivalent boolean expression. The expression must occur in a
- /// context where its result is immediately subject to boolean conversion.
- /// If [polarity] if false, the negated condition will be created instead.
- /// If [liftNots] is true (default) then Not expressions will be lifted toward
- /// the root of the condition so they can be eliminated by the caller.
- Expression makeCondition(Expression e, bool polarity, {bool liftNots: true}) {
- if (e is Not) {
- // !!E ==> E
- return makeCondition(e.operand, !polarity, liftNots: liftNots);
- }
- if (e is LogicalOperator) {
- // If polarity=false, then apply the rewrite !(x && y) ==> !x || !y
- e.left = makeCondition(e.left, polarity);
- e.right = makeCondition(e.right, polarity);
- if (!polarity) {
- e.isAnd = !e.isAnd;
- }
- // !x && !y ==> !(x || y) (only if lifting nots)
- if (e.left is Not && e.right is Not && liftNots) {
- e.left = (e.left as Not).operand;
- e.right = (e.right as Not).operand;
- e.isAnd = !e.isAnd;
- return new Not(e);
- }
- return e;
- }
- if (e is ApplyBuiltinOperator && polarity == false) {
- BuiltinOperator negated = negateBuiltin(e.operator);
- if (negated != null) {
- e.operator = negated;
- return visitExpression(e);
- } else {
- return new Not(visitExpression(e));
- }
- }
- if (e is Conditional) {
- // Handle polarity by: !(x ? y : z) ==> x ? !y : !z
- // Rewrite individual branches now. The condition will be rewritten
- // when we know what polarity to use (depends on which rewrite is used).
- e.thenExpression = makeCondition(e.thenExpression, polarity);
- e.elseExpression = makeCondition(e.elseExpression, polarity);
-
- // x ? true : false ==> x
- if (isTrue(e.thenExpression) && isFalse(e.elseExpression)) {
- return makeCondition(e.condition, true, liftNots: liftNots);
- }
- // x ? false : true ==> !x
- if (isFalse(e.thenExpression) && isTrue(e.elseExpression)) {
- return makeCondition(e.condition, false, liftNots: liftNots);
- }
- // x ? true : y ==> x || y
- if (isTrue(e.thenExpression)) {
- return makeOr(makeCondition(e.condition, true), e.elseExpression,
- liftNots: liftNots);
- }
- // x ? false : y ==> !x && y
- if (isFalse(e.thenExpression)) {
- return makeAnd(makeCondition(e.condition, false), e.elseExpression,
- liftNots: liftNots);
- }
- // x ? y : true ==> !x || y
- if (isTrue(e.elseExpression)) {
- return makeOr(makeCondition(e.condition, false), e.thenExpression,
- liftNots: liftNots);
- }
- // x ? y : false ==> x && y
- if (isFalse(e.elseExpression)) {
- return makeAnd(makeCondition(e.condition, true), e.thenExpression,
- liftNots: liftNots);
- }
-
- e.condition = makeCondition(e.condition, true);
-
- // !x ? y : z ==> x ? z : y
- if (e.condition is Not) {
- e.condition = (e.condition as Not).operand;
- Expression tmp = e.thenExpression;
- e.thenExpression = e.elseExpression;
- e.elseExpression = tmp;
- }
- // x ? !y : !z ==> !(x ? y : z) (only if lifting nots)
- if (e.thenExpression is Not && e.elseExpression is Not && liftNots) {
- e.thenExpression = (e.thenExpression as Not).operand;
- e.elseExpression = (e.elseExpression as Not).operand;
- return new Not(e);
- }
-
- // x ? y : x ==> x && y
- if (isSameVariable(e.condition, e.elseExpression)) {
- destroyVariableUse(e.elseExpression);
- return new LogicalOperator.and(e.condition, e.thenExpression);
- }
- // x ? x : y ==> x || y
- if (isSameVariable(e.condition, e.thenExpression)) {
- destroyVariableUse(e.thenExpression);
- return new LogicalOperator.or(e.condition, e.elseExpression);
- }
-
- return e;
- }
- if (e is Constant && e.value.isBool) {
- // !true ==> false
- if (!polarity) {
- values.BoolConstantValue value = e.value;
- return new Constant.bool(value.negate());
- }
- return e;
- }
- e = visitExpression(e);
- return polarity ? e : new Not(e);
- }
-
- bool isNull(Expression e) {
- return e is Constant && e.value.isNull;
- }
-
- bool isTrue(Expression e) {
- return e is Constant && e.value.isTrue;
- }
-
- bool isFalse(Expression e) {
- return e is Constant && e.value.isFalse;
- }
-
- Expression makeAnd(Expression e1, Expression e2, {bool liftNots: true}) {
- if (e1 is Not && e2 is Not && liftNots) {
- return new Not(new LogicalOperator.or(e1.operand, e2.operand));
- } else {
- return new LogicalOperator.and(e1, e2);
- }
- }
-
- Expression makeOr(Expression e1, Expression e2, {bool liftNots: true}) {
- if (e1 is Not && e2 is Not && liftNots) {
- return new Not(new LogicalOperator.and(e1.operand, e2.operand));
- } else {
- return new LogicalOperator.or(e1, e2);
- }
- }
-
- /// True if [e2] is known to return the same value as [e1]
- /// (with no additional side effects) if evaluated immediately after [e1].
- ///
- /// Concretely, this is true if [e1] and [e2] are uses of the same variable,
- /// or if [e2] is a use of a variable assigned by [e1].
- bool isSameVariable(Expression e1, Expression e2) {
- if (e1 is VariableUse) {
- return e2 is VariableUse && e1.variable == e2.variable;
- } else if (e1 is Assign) {
- return e2 is VariableUse && e1.variable == e2.variable;
- }
- return false;
- }
-
- void destroyVariableUse(VariableUse node) {
- --node.variable.readCount;
- }
-}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
deleted file mode 100644
index 847d0ca..0000000
--- a/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
+++ /dev/null
@@ -1,195 +0,0 @@
-// 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 tree_ir.optimization.loop_rewriter;
-
-import '../tree_ir_nodes.dart';
-import 'optimization.dart' show Pass;
-
-/// Rewrites [WhileTrue] statements into [For] statements.
-///
-/// Before this phase, loops usually contain a lot of "exit code", that is,
-/// code that happens at a point where a [Continue] can no longer be reached,
-/// and is therefore not really part of the loop.
-/// Exit code is moved down after the loop using the following rewrites rules:
-///
-/// EXTRACT LABELED STATEMENT:
-///
-/// L:
-/// while (true) {
-/// L2: {
-/// S1 (has references to L)
-/// }
-/// S2 (has no references to L)
-/// }
-///
-/// ==>
-///
-/// L2: {
-/// L: while (true) S1
-/// }
-/// S2
-///
-/// INTRODUCE CONDITIONAL LOOP:
-///
-/// L:
-/// while (true) {
-/// if (E) {
-/// S1 (has references to L)
-/// } else {
-/// S2 (has no references to L)
-/// }
-/// }
-/// ==>
-/// L:
-/// while (E) {
-/// S1
-/// };
-/// S2
-///
-/// A similar transformation is used when S2 occurs in the 'then' position.
-///
-/// Note that the pattern above needs no iteration since nested ifs have been
-/// collapsed previously in the [StatementRewriter] phase.
-///
-///
-/// PULL INTO UPDATE EXPRESSION:
-///
-/// Assignment expressions before the unique continue to a [whileCondition] are
-/// pulled into the updates for the loop.
-///
-/// L:
-/// for (; condition; updates) {
-/// S [ x = E; continue L ]
-/// }
-/// ==>
-/// L:
-/// for (; condition; updates, x = E) {
-/// S [ continue L ]
-/// }
-///
-/// The decision to only pull in assignments is a heuristic to balance
-/// readability and stack trace usability versus the modest code size
-/// reduction one might get by aggressively moving expressions into the
-/// updates.
-class LoopRewriter extends RecursiveTransformer implements Pass {
- String get passName => 'Loop rewriter';
-
- Set<Label> usedContinueLabels = new Set<Label>();
-
- /// Maps loop labels to a list, if that loop can accept update expressions.
- /// The list will then be populated while traversing the body of that loop.
- /// If a loop is not in the map, update expressions cannot be hoisted there.
- Map<Label, List<Expression>> updateExpressions = <Label, List<Expression>>{};
-
- void rewrite(FunctionDefinition root) {
- root.body = visitStatement(root.body);
- }
-
- Statement visitContinue(Continue node) {
- usedContinueLabels.add(node.target);
- return node;
- }
-
- Statement visitWhileTrue(WhileTrue node) {
- assert(!usedContinueLabels.contains(node.label));
-
- // Pull labeled statements outside the loop when possible.
- // [head] and [tail] are the first and last labeled statements that were
- // pulled out, and null when none have been pulled out.
- LabeledStatement head, tail;
- while (node.body is LabeledStatement) {
- LabeledStatement inner = node.body;
- inner.next = visitStatement(inner.next);
- bool nextHasContinue = usedContinueLabels.remove(node.label);
- if (nextHasContinue) break;
- node.body = inner.body;
- inner.body = node;
- if (head == null) {
- head = tail = inner;
- } else {
- tail.body = inner;
- tail = inner;
- }
- }
-
- // Rewrite while(true) to for(; condition; updates).
- Statement loop = node;
- if (node.body is If) {
- If body = node.body;
- updateExpressions[node.label] = <Expression>[];
- body.thenStatement = visitStatement(body.thenStatement);
- bool thenHasContinue = usedContinueLabels.remove(node.label);
- body.elseStatement = visitStatement(body.elseStatement);
- bool elseHasContinue = usedContinueLabels.remove(node.label);
- if (thenHasContinue && !elseHasContinue) {
- node.label.binding = null; // Prepare to rebind the label.
- loop = new For(
- node.label,
- body.condition,
- updateExpressions[node.label],
- body.thenStatement,
- body.elseStatement);
- } else if (!thenHasContinue && elseHasContinue) {
- node.label.binding = null;
- loop = new For(
- node.label,
- new Not(body.condition),
- updateExpressions[node.label],
- body.elseStatement,
- body.thenStatement);
- }
- } else if (node.body is LabeledStatement) {
- // If the body is a labeled statement, its .next has already been visited.
- LabeledStatement body = node.body;
- body.body = visitStatement(body.body);
- usedContinueLabels.remove(node.label);
- } else {
- node.body = visitStatement(node.body);
- usedContinueLabels.remove(node.label);
- }
-
- if (head == null) return loop;
- tail.body = loop;
- return head;
- }
-
- Statement visitExpressionStatement(ExpressionStatement node) {
- if (updateExpressions.isEmpty) {
- // Avoid allocating a list if there is no loop.
- return super.visitExpressionStatement(node);
- }
- List<ExpressionStatement> statements = <ExpressionStatement>[];
- while (node.next is ExpressionStatement) {
- statements.add(node);
- node = node.next;
- }
- statements.add(node);
- Statement next = visitStatement(node.next);
- if (next is Continue && next.target.useCount == 1) {
- List<Expression> updates = updateExpressions[next.target];
- if (updates != null) {
- // Pull expressions before the continue into the for loop update.
- // As a heuristic, we only pull in assignment expressions.
- // Determine the index of the first assignment to pull in.
- int index = statements.length;
- while (index > 0 && statements[index - 1].expression is Assign) {
- --index;
- }
- for (ExpressionStatement stmt in statements.skip(index)) {
- updates.add(stmt.expression);
- }
- if (index > 0) {
- statements[index - 1].next = next;
- return statements.first;
- } else {
- return next;
- }
- }
- }
- // The expression statements could not be pulled into a loop update.
- node.next = next;
- return statements.first;
- }
-}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/optimization.dart b/pkg/compiler/lib/src/tree_ir/optimization/optimization.dart
deleted file mode 100644
index ebf201a..0000000
--- a/pkg/compiler/lib/src/tree_ir/optimization/optimization.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-library tree_ir.optimization;
-
-import '../tree_ir_nodes.dart';
-
-export 'logical_rewriter.dart' show LogicalRewriter;
-export 'loop_rewriter.dart' show LoopRewriter;
-export 'pull_into_initializers.dart' show PullIntoInitializers;
-export 'statement_rewriter.dart' show StatementRewriter;
-export 'variable_merger.dart' show VariableMerger;
-
-/// An optimization pass over the Tree IR.
-abstract class Pass {
- /// Applies optimizations to root, rewriting it in the process.
- void rewrite(FunctionDefinition root);
-
- String get passName;
-}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
deleted file mode 100644
index 722230a..0000000
--- a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
+++ /dev/null
@@ -1,378 +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 tree_ir.optimization.pull_into_initializers;
-
-import '../tree_ir_nodes.dart';
-import 'optimization.dart' show Pass;
-
-/// Where a variable has been assigned.
-enum AssignArea {
- /// The variable is only assigned in the initializer block.
- Initializer,
-
- // The variable has at least one assignment outside the initializer block.
- Anywhere,
-}
-
-/// Pulls assignment expressions to the top of the function body so they can be
-/// translated into declaration-site variable initializaters.
-///
-/// This reverts the assignment expression propagation performed by
-/// [StatementRewriter] in cases where it not beneficial.
-///
-/// EXAMPLE:
-///
-/// var x = foo(),
-/// y = bar(x);
-///
-/// ==> [StatementRewriter]
-///
-/// var x,
-/// y = bar(x = foo());
-///
-/// ==> [PullIntoInitializers] restores the initializer for x
-///
-/// var x = foo(),
-/// y = bar(x);
-///
-///
-/// Sometimes the assignment propagation will trigger another optimization
-/// in the [StatementRewriter] which then prevents [PullIntoInitializers] from
-/// restoring the initializer. This is acceptable, since most optimizations
-/// at that level are better than restoring an initializer.
-///
-/// EXAMPLE:
-///
-/// var x = foo(),
-/// y = bar();
-/// baz(x, y, y);
-///
-/// ==> [StatementRewriter]
-///
-/// var y;
-/// baz(foo(), y = bar(), y);
-///
-/// [PullIntoInitializers] cannot pull `y` into an initializer because
-/// the impure expressions `foo()` and `bar()` would then be swapped.
-///
-class PullIntoInitializers extends RecursiveTransformer implements Pass {
- String get passName => 'Pull into initializers';
-
- /// Denotes where each variable is currently assigned.
- ///
- /// Variables without assignments are absent from the map.
- Map<Variable, AssignArea> assignArea = <Variable, AssignArea>{};
-
- /// The fragment between [first] and [last] holds the statements
- /// we pulled into the initializer block.
- ///
- /// The "initializer block" is a sequence of [ExpressionStatement]s with
- /// [Assign]s that we create in the beginning of the body, with the intent
- /// that code generation will convert them to variable initializers.
- ///
- /// The block is empty when both are `null`.
- Statement first, last;
-
- /// The number of impure expressions separating the current program point
- /// from the initializer block.
- ///
- /// A pure expression is an expression that cannot throw, diverge, have side
- /// effects, or depend on mutable state.
- ///
- /// As a special case, variable uses are also considered pure when their only
- /// reaching definition is an assignment in the initializer block.
- int impureCounter = 0;
-
- /// The number of assignments separating the current program point from the
- /// initializer block. Note that these are also counted as impure expressions.
- ///
- /// Assignments are given special treatment because hoisting an assignment
- /// may change the reaching definitions of a variable use. The analysis may
- /// already have considered such a use to be pure, and we must then ensure
- /// that it remains pure.
- int assignCounter = 0;
-
- /// The number of branch points separating the current program point from
- /// the initializer block.
- ///
- /// We do not pull expressions out of branches, not even pure ones, but
- /// we sometimes want to traverse branches to check if they are pure.
- int branchCounter = 0;
-
- /// Appends a statement to the initializer block.
- void append(Statement node) {
- if (first == null) {
- first = last = node;
- } else {
- last.next = node;
- last = node;
- }
- }
-
- void rewrite(FunctionDefinition node) {
- for (Variable param in node.parameters) {
- assignArea[param] = AssignArea.Initializer;
- }
- Statement body = visitStatement(node.body);
- append(body);
- assert(first != null);
- node.body = first;
- }
-
- void destroyVariableUse(VariableUse node) {
- --node.variable.readCount;
- }
-
- Statement visitExpressionStatement(ExpressionStatement node) {
- node.expression = visitExpression(node.expression);
- if (node.expression is VariableUse) {
- // The entire expression was pulled into an initializer.
- // This can happen when the expression was an assignment that was
- // pulled into the initializer block and replaced by a variable use.
- // Discard the statement and try to pull in more initializers from
- // the next statement.
- destroyVariableUse(node.expression);
- return visitStatement(node.next);
- }
- node.next = visitStatement(node.next);
- return node;
- }
-
- Statement visitIf(If node) {
- node.condition = visitExpression(node.condition);
- // We could traverse the branches and pull out pure expressions, but
- // some pure expressions might be too slow for this to pay off.
- // A CPS transform should decide when things get hoisted out of branches.
- return node;
- }
-
- Statement visitLabeledStatement(LabeledStatement node) {
- node.body = visitStatement(node.body);
- // The 'next' statement might not always get reached, so do not try to
- // pull expressions up from there.
- return node;
- }
-
- Statement visitWhileTrue(WhileTrue node) {
- return node;
- }
-
- Statement visitFor(For node) {
- return node;
- }
-
- Statement visitTry(Try node) {
- return node;
- }
-
- Statement visitReceiverCheck(ReceiverCheck node) {
- if (node.condition != null) {
- node.condition = visitExpression(node.condition);
- // The value occurs in conditional context, so don't pull from that.
- } else {
- node.value = visitExpression(node.value);
- }
- return node;
- }
-
- Expression visitAssign(Assign node) {
- bool inImpureContext = impureCounter > 0;
- bool inBranch = branchCounter > 0;
-
- // Remember the number of impure expression seen yet, so we can tell if
- // there are any impure expressions on the right-hand side.
- int impureBefore = impureCounter;
- int assignmentsBefore = assignCounter;
- node.value = visitExpression(node.value);
- bool rightHandSideIsImpure = (impureCounter > impureBefore);
- bool rightHandSideHasAssign = (assignCounter > assignmentsBefore);
-
- bool alreadyAssigned = assignArea.containsKey(node.variable);
-
- // An impure right-hand side cannot be pulled out of impure context.
- // Expressions should not be pulled out of branches.
- // If this is not the first assignment, it cannot be hoisted.
- // If the right-hand side contains an unhoistable assignment, this
- // assignment cannot be hoisted either.
- if (inImpureContext && rightHandSideIsImpure ||
- inBranch ||
- alreadyAssigned ||
- rightHandSideHasAssign) {
- assignArea[node.variable] = AssignArea.Anywhere;
- ++impureCounter;
- ++assignCounter;
- return node;
- }
-
- // Pull the assignment into the initializer. Any side-effects in the
- // right-hand side will move into the initializer block, so reset the
- // impure counter.
- assignArea[node.variable] = AssignArea.Initializer;
- impureCounter = impureBefore;
- append(new ExpressionStatement(node, null));
- return new VariableUse(node.variable);
- }
-
- Expression visitVariableUse(VariableUse node) {
- if (assignArea[node.variable] == AssignArea.Anywhere) {
- // There is a reaching definition outside the initializer block.
- ++impureCounter;
- }
- return node;
- }
-
- void rewriteList(List<Expression> nodes) {
- for (int i = 0; i < nodes.length; ++i) {
- nodes[i] = visitExpression(nodes[i]);
- }
- }
-
- Expression visitInvokeMethod(InvokeMethod node) {
- node.receiver = visitExpression(node.receiver);
- if (!node.receiverIsNotNull) {
- // If the receiver is null, the method lookup throws.
- ++impureCounter;
- }
- rewriteList(node.arguments);
- ++impureCounter;
- return node;
- }
-
- Expression visitInvokeStatic(InvokeStatic node) {
- super.visitInvokeStatic(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- super.visitInvokeMethodDirectly(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitInvokeConstructor(InvokeConstructor node) {
- super.visitInvokeConstructor(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitOneShotInterceptor(OneShotInterceptor node) {
- super.visitOneShotInterceptor(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitAwait(Await node) {
- super.visitAwait(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitConditional(Conditional node) {
- node.condition = visitExpression(node.condition);
- // Visit the branches to detect impure subexpressions, but do not pull
- // expressions out of the branch.
- ++branchCounter;
- node.thenExpression = visitExpression(node.thenExpression);
- node.elseExpression = visitExpression(node.elseExpression);
- --branchCounter;
- return node;
- }
-
- Expression visitLogicalOperator(LogicalOperator node) {
- node.left = visitExpression(node.left);
- ++branchCounter;
- node.right = visitExpression(node.right);
- --branchCounter;
- return node;
- }
-
- Expression visitLiteralList(LiteralList node) {
- super.visitLiteralList(node);
- if (node.type != null) {
- ++impureCounter; // Type casts can throw.
- }
- return node;
- }
-
- Expression visitTypeOperator(TypeOperator node) {
- super.visitTypeOperator(node);
- if (!node.isTypeTest) {
- ++impureCounter; // Type casts can throw.
- }
- return node;
- }
-
- Expression visitGetField(GetField node) {
- super.visitGetField(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitSetField(SetField node) {
- super.visitSetField(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitGetStatic(GetStatic node) {
- ++impureCounter;
- return node;
- }
-
- Expression visitSetStatic(SetStatic node) {
- super.visitSetStatic(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitGetTypeTestProperty(GetTypeTestProperty node) {
- super.visitGetTypeTestProperty(node);
- return node;
- }
-
- Expression visitGetLength(GetLength node) {
- super.visitGetLength(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitGetIndex(GetIndex node) {
- super.visitGetIndex(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitSetIndex(SetIndex node) {
- super.visitSetIndex(node);
- ++impureCounter;
- return node;
- }
-
- Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- rewriteList(node.arguments);
- return node;
- }
-
- Expression visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- node.receiver = visitExpression(node.receiver);
- if (!node.receiverIsNotNull) {
- // If the receiver is null, the method lookup throws.
- ++impureCounter;
- }
- rewriteList(node.arguments);
- ++impureCounter;
- return node;
- }
-
- @override
- Expression visitForeignExpression(ForeignExpression node) {
- rewriteList(node.arguments);
- if (node.nativeBehavior.sideEffects.hasSideEffects()) {
- ++impureCounter;
- }
- return node;
- }
-}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
deleted file mode 100644
index cc2786e..0000000
--- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
+++ /dev/null
@@ -1,1391 +0,0 @@
-// 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 tree_ir.optimization.statement_rewriter;
-
-import '../../elements/elements.dart';
-import '../../io/source_information.dart';
-import '../../js/placeholder_safety.dart';
-import '../tree_ir_nodes.dart';
-import 'optimization.dart' show Pass;
-
-/**
- * Translates to direct-style.
- *
- * In addition to the general IR constraints (see [CheckTreeIntegrity]),
- * the input is assumed to satisfy the following criteria:
- *
- * All expressions other than those nested in [Assign] or [ExpressionStatement]
- * must be simple. A [VariableUse] and [This] is a simple expression.
- * The right-hand of an [Assign] may not be an [Assign].
- *
- * Moreover, every variable must either be an SSA variable or a mutable
- * variable, and must satisfy the corresponding criteria:
- *
- * SSA VARIABLE:
- * An SSA variable must have a unique definition site, which is either an
- * assignment or label. In case of a label, its target must act as the unique
- * reaching definition of that variable at all uses of the variable and at
- * all other label targets where the variable is in scope.
- *
- * (The second criterion is to ensure that we can move a use of an SSA variable
- * across a label without changing its reaching definition).
- *
- * MUTABLE VARIABLE:
- * Uses of mutable variables are considered complex expressions, and hence must
- * not be nested in other expressions. Assignments to mutable variables must
- * have simple right-hand sides.
- *
- * ----
- *
- * This pass performs the following transformations on the tree:
- * - Assignment inlining
- * - Assignment expression propagation
- * - If-to-conditional conversion
- * - Flatten nested ifs
- * - Break inlining
- * - Redirect breaks
- *
- * The above transformations all eliminate statements from the tree, and may
- * introduce redexes of each other.
- *
- *
- * ASSIGNMENT INLINING:
- * Single-use definitions are inlined at their use site when possible.
- * For example:
- *
- * { v0 = foo(); return v0; }
- * ==>
- * return foo()
- *
- * After translating out of CPS, all intermediate values are bound by [Assign].
- * This transformation propagates such definitions to their uses when it is
- * safe and profitable. Bindings are processed "on demand" when their uses are
- * seen, but are only processed once to keep this transformation linear in
- * the size of the tree.
- *
- * The transformation builds an environment containing [Assign] bindings that
- * are in scope. These bindings have yet-untranslated definitions. When a use
- * is encountered the transformation determines if it is safe and profitable
- * to propagate the definition to its use. If so, it is removed from the
- * environment and the definition is recursively processed (in the
- * new environment at the use site) before being propagated.
- *
- * See [visitVariableUse] for the implementation of the heuristic for
- * propagating a definition.
- *
- *
- * ASSIGNMENT EXPRESSION PROPAGATION:
- * Definitions with multiple uses are propagated to their first use site
- * when possible. For example:
- *
- * { v0 = foo(); bar(v0); return v0; }
- * ==>
- * { bar(v0 = foo()); return v0; }
- *
- * Note that the [RestoreInitializers] phase will later undo this rewrite
- * in cases where it prevents an assignment from being pulled into an
- * initializer.
- *
- *
- * IF-TO-CONDITIONAL CONVERSION:
- * If-statement are converted to conditional expressions when possible.
- * For example:
- *
- * if (v0) { v1 = foo(); break L } else { v1 = bar(); break L }
- * ==>
- * { v1 = v0 ? foo() : bar(); break L }
- *
- * This can lead to inlining of L, which in turn can lead to further propagation
- * of the variable v1.
- *
- * See [visitIf].
- *
- *
- * FLATTEN NESTED IFS:
- * An if inside an if is converted to an if with a logical operator.
- * For example:
- *
- * if (E1) { if (E2) {S} else break L } else break L
- * ==>
- * if (E1 && E2) {S} else break L
- *
- * This may lead to inlining of L.
- *
- *
- * BREAK INLINING:
- * Single-use labels are inlined at [Break] statements.
- * For example:
- *
- * L0: { v0 = foo(); break L0 }; return v0;
- * ==>
- * v0 = foo(); return v0;
- *
- * This can lead to propagation of v0.
- *
- * See [visitBreak] and [visitLabeledStatement].
- *
- *
- * REDIRECT BREAKS:
- * Labeled statements whose next is a break become flattened and all breaks
- * to their label are redirected.
- * For example, where 'jump' is either break or continue:
- *
- * L0: {... break L0 ...}; jump L1
- * ==>
- * {... jump L1 ...}
- *
- * This may trigger a flattening of nested ifs in case the eliminated label
- * separated two ifs.
- */
-class StatementRewriter extends Transformer implements Pass {
- String get passName => 'Statement rewriter';
-
- @override
- void rewrite(FunctionDefinition node) {
- node.parameters.forEach(pushDominatingAssignment);
- node.body = visitStatement(node.body);
- node.parameters.forEach(popDominatingAssignment);
- }
-
- /// The most recently evaluated impure expressions, with the most recent
- /// expression being last.
- ///
- /// Most importantly, this contains [Assign] expressions that we attempt to
- /// inline at their use site. It also contains other impure expressions that
- /// we can propagate to a variable use if they are known to return the value
- /// of that variable.
- ///
- /// Assignments with constant right-hand sides (see [isEffectivelyConstant])
- /// are not considered impure and are put in [constantEnvironment] instead.
- ///
- /// Except for [Conditional]s, expressions in the environment have
- /// not been processed, and all their subexpressions must therefore be
- /// variables uses.
- List<Expression> environment = <Expression>[];
-
- /// Binding environment for variables that are assigned to effectively
- /// constant expressions (see [isEffectivelyConstant]).
- Map<Variable, Expression> constantEnvironment = <Variable, Expression>{};
-
- /// Substitution map for labels. Any break to a label L should be substituted
- /// for a break to L' if L maps to L'.
- Map<Label, Jump> labelRedirects = <Label, Jump>{};
-
- /// Number of uses of the given variable that are still unseen.
- /// Used to detect the first use of a variable (since we do backwards
- /// traversal, the first use is the last one seen).
- Map<Variable, int> unseenUses = <Variable, int>{};
-
- /// Number of assignments to a given variable that dominate the current
- /// position.
- ///
- /// Pure expressions will not be inlined if it uses a variable with more than
- /// one dominating assignment, because the reaching definition of the used
- /// variable might have changed since it was put in the environment.
- final Map<Variable, int> dominatingAssignments = <Variable, int>{};
-
- /// A set of labels that can be safely inlined at their use.
- ///
- /// The successor statements for labeled statements that have only one break
- /// from them are normally rewritten inline at the site of the break. This
- /// is not safe if the code would be moved inside the scope of an exception
- /// handler (i.e., if the code would be moved into a try from outside it).
- Set<Label> safeForInlining = new Set<Label>();
-
- /// If the top element is true, assignments of form "x = CONST" may be
- /// propagated into a following occurence of CONST. This may confuse the JS
- /// engine so it is disabled in some cases.
- final List<bool> allowRhsPropagation = <bool>[true];
-
- bool get isRhsPropagationAllowed => allowRhsPropagation.last;
-
- /// Returns the redirect target of [jump] or [jump] itself if it should not
- /// be redirected.
- Jump redirect(Jump jump) {
- Jump newJump = labelRedirects[jump.target];
- return newJump != null ? newJump : jump;
- }
-
- void inEmptyEnvironment(void action(), {bool keepConstants: true}) {
- List oldEnvironment = environment;
- Map oldConstantEnvironment = constantEnvironment;
- environment = <Expression>[];
- if (!keepConstants) {
- constantEnvironment = <Variable, Expression>{};
- }
- action();
- assert(environment.isEmpty);
- environment = oldEnvironment;
- if (!keepConstants) {
- constantEnvironment = oldConstantEnvironment;
- }
- }
-
- /// Left-hand side of the given assignment, or `null` if not an assignment.
- Variable getLeftHand(Expression e) {
- return e is Assign ? e.variable : null;
- }
-
- /// If the given expression always returns the value of one of its
- /// subexpressions, returns that subexpression, otherwise `null`.
- Expression getValueSubexpression(Expression e) {
- if (e is SetField) return e.value;
- return null;
- }
-
- /// If the given expression always returns the value of one of its
- /// subexpressions, and that subexpression is a variable use, returns that
- /// variable. Otherwise `null`.
- Variable getRightHandVariable(Expression e) {
- Expression value = getValueSubexpression(e);
- return value is VariableUse ? value.variable : null;
- }
-
- Constant getRightHandConstant(Expression e) {
- Expression value = getValueSubexpression(e);
- return value is Constant ? value : null;
- }
-
- /// True if the given expression (taken from [constantEnvironment]) uses a
- /// variable that might have been reassigned since [node] was evaluated.
- bool hasUnsafeVariableUse(Expression node) {
- bool wasFound = false;
- VariableUseVisitor.visit(node, (VariableUse use) {
- if (dominatingAssignments[use.variable] > 1) {
- wasFound = true;
- }
- });
- return wasFound;
- }
-
- void pushDominatingAssignment(Variable variable) {
- if (variable != null) {
- dominatingAssignments.putIfAbsent(variable, () => 0);
- ++dominatingAssignments[variable];
- }
- }
-
- void popDominatingAssignment(Variable variable) {
- if (variable != null) {
- --dominatingAssignments[variable];
- }
- }
-
- @override
- Expression visitVariableUse(VariableUse node) {
- // Count of number of unseen uses remaining.
- unseenUses.putIfAbsent(node.variable, () => node.variable.readCount);
- --unseenUses[node.variable];
-
- // We traverse the tree right-to-left, so when we have seen all uses,
- // it means we are looking at the first use.
- assert(unseenUses[node.variable] < node.variable.readCount);
- assert(unseenUses[node.variable] >= 0);
-
- // We cannot reliably find the first dynamic use of a variable that is
- // accessed from a JS function in a foreign code fragment.
- if (node.variable.isCaptured) return node;
-
- bool isFirstUse = unseenUses[node.variable] == 0;
-
- // Propagate constant to use site.
- Expression constant = constantEnvironment[node.variable];
- if (constant != null && !hasUnsafeVariableUse(constant)) {
- --node.variable.readCount;
- return visitExpression(constant);
- }
-
- // Try to propagate another expression into this variable use.
- if (!environment.isEmpty) {
- Expression binding = environment.last;
-
- // Is this variable assigned by the most recently evaluated impure
- // expression?
- //
- // If so, propagate the assignment, e.g:
- //
- // { x = foo(); bar(x, x) } ==> bar(x = foo(), x)
- //
- // We must ensure that no other uses separate this use from the
- // assignment. We therefore only propagate assignments into the first use.
- //
- // Note that if this is only use, `visitAssign` will then remove the
- // redundant assignment.
- if (getLeftHand(binding) == node.variable && isFirstUse) {
- environment.removeLast();
- --node.variable.readCount;
- return visitExpression(binding);
- }
-
- // Is the most recently evaluated impure expression known to have the
- // value of this variable?
- //
- // If so, we can replace this use with the impure expression, e.g:
- //
- // { E.foo = x; bar(x) } ==> bar(E.foo = x)
- //
- if (isRhsPropagationAllowed &&
- getRightHandVariable(binding) == node.variable) {
- environment.removeLast();
- --node.variable.readCount;
- return visitExpression(binding);
- }
- }
-
- // If the definition could not be propagated, leave the variable use.
- return node;
- }
-
- /// True if [exp] contains a use of a variable that was assigned to by the
- /// most recently evaluated impure expression (constant assignments are not
- /// considered impure).
- ///
- /// This implies that the assignment can be propagated into this use unless
- /// the use is moved further away.
- ///
- /// In this case, we will refrain from moving [exp] across other impure
- /// expressions, even when this is safe, because doing so would immediately
- /// prevent the previous expression from propagating, canceling out the
- /// benefit we might otherwise gain from propagating [exp].
- ///
- /// [exp] must be an unprocessed expression, i.e. either a [Conditional] or
- /// an expression whose subexpressions are all variable uses.
- bool usesRecentlyAssignedVariable(Expression exp) {
- if (environment.isEmpty) return false;
- Variable variable = getLeftHand(environment.last);
- if (variable == null) return false;
- IsVariableUsedVisitor visitor = new IsVariableUsedVisitor(variable);
- visitor.visitExpression(exp);
- return visitor.wasFound;
- }
-
- /// Returns true if [exp] has no side effects and has a constant value within
- /// any given activation of the enclosing method.
- bool isEffectivelyConstant(Expression exp) {
- // TODO(asgerf): Can be made more aggressive e.g. by checking conditional
- // expressions recursively. Determine if that is a valuable optimization
- // and/or if it is better handled at the CPS level.
- return exp is Constant ||
- exp is This ||
- exp is CreateInvocationMirror ||
- exp is CreateInstance ||
- exp is CreateBox ||
- exp is TypeExpression ||
- exp is GetStatic && exp.element.isFunction ||
- exp is Interceptor ||
- exp is ApplyBuiltinOperator ||
- exp is VariableUse && constantEnvironment.containsKey(exp.variable);
- }
-
- /// True if [node] is an assignment that can be propagated as a constant.
- bool isEffectivelyConstantAssignment(Expression node) {
- return node is Assign &&
- node.variable.writeCount == 1 &&
- isEffectivelyConstant(node.value);
- }
-
- Statement visitExpressionStatement(ExpressionStatement inputNode) {
- // Analyze chains of expression statements.
- // To avoid deep recursion, [processExpressionStatement] returns a callback
- // to invoke after its successor node has been processed.
- // These callbacks are stored in a list and invoked in reverse at the end.
- List<Function> stack = [];
- Statement node = inputNode;
- while (node is ExpressionStatement) {
- stack.add(processExpressionStatement(node));
- node = node.next;
- }
- Statement result = visitStatement(node);
- for (Function fun in stack.reversed) {
- result = fun(result);
- }
- return result;
- }
-
- /// Attempts to propagate an assignment in an expression statement.
- ///
- /// Returns a callback to be invoked after the sucessor statement has
- /// been processed.
- Function processExpressionStatement(ExpressionStatement stmt) {
- Variable leftHand = getLeftHand(stmt.expression);
- pushDominatingAssignment(leftHand);
- if (isEffectivelyConstantAssignment(stmt.expression) &&
- !usesRecentlyAssignedVariable(stmt.expression)) {
- Assign assign = stmt.expression;
- // Handle constant assignments specially.
- // They are always safe to propagate (though we should avoid duplication).
- // Moreover, they should not prevent other expressions from propagating.
- if (assign.variable.readCount == 1) {
- // A single-use constant should always be propagated to its use site.
- constantEnvironment[assign.variable] = assign.value;
- return (Statement next) {
- popDominatingAssignment(leftHand);
- if (assign.variable.readCount > 0) {
- // The assignment could not be propagated into the successor,
- // either because it [hasUnsafeVariableUse] or because the
- // use is outside the current try block, and we do not currently
- // support constant propagation out of a try block.
- constantEnvironment.remove(assign.variable);
- assign.value = visitExpression(assign.value);
- stmt.next = next;
- return stmt;
- } else {
- --assign.variable.writeCount;
- return next;
- }
- };
- } else {
- // With more than one use, we cannot propagate the constant.
- // Visit the following statement without polluting [environment] so
- // that any preceding non-constant assignments might still propagate.
- return (Statement next) {
- stmt.next = next;
- popDominatingAssignment(leftHand);
- assign.value = visitExpression(assign.value);
- return stmt;
- };
- }
- } else {
- // Try to propagate the expression, and block previous impure expressions
- // until this has propagated.
- environment.add(stmt.expression);
- return (Statement next) {
- stmt.next = next;
- popDominatingAssignment(leftHand);
- if (!environment.isEmpty && environment.last == stmt.expression) {
- // Retain the expression statement.
- environment.removeLast();
- stmt.expression = visitExpression(stmt.expression);
- return stmt;
- } else {
- // Expression was propagated into the successor.
- return stmt.next;
- }
- };
- }
- }
-
- Expression visitAssign(Assign node) {
- allowRhsPropagation.add(true);
- node.value = visitExpression(node.value);
- allowRhsPropagation.removeLast();
- // Remove assignments to variables without any uses. This can happen
- // because the assignment was propagated into its use, e.g:
- //
- // { x = foo(); bar(x) } ==> bar(x = foo()) ==> bar(foo())
- //
- if (node.variable.readCount == 0) {
- --node.variable.writeCount;
- return node.value;
- }
- return node;
- }
-
- /// Process nodes right-to-left, the opposite of evaluation order in the case
- /// of argument lists..
- void _rewriteList(List<Node> nodes, {bool rhsPropagation: true}) {
- allowRhsPropagation.add(rhsPropagation);
- for (int i = nodes.length - 1; i >= 0; --i) {
- nodes[i] = visitExpression(nodes[i]);
- }
- allowRhsPropagation.removeLast();
- }
-
- Expression visitInvokeStatic(InvokeStatic node) {
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitInvokeMethod(InvokeMethod node) {
- if (node.receiverIsNotNull) {
- _rewriteList(node.arguments);
- node.receiver = visitExpression(node.receiver);
- } else {
- // Impure expressions cannot be propagated across the method lookup,
- // because it throws when the receiver is null.
- inEmptyEnvironment(() {
- _rewriteList(node.arguments);
- });
- node.receiver = visitExpression(node.receiver);
- }
- return node;
- }
-
- Expression visitOneShotInterceptor(OneShotInterceptor node) {
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- if (node.receiverIsNotNull) {
- _rewriteList(node.arguments);
- node.receiver = visitExpression(node.receiver);
- } else {
- // Impure expressions cannot be propagated across the method lookup,
- // because it throws when the receiver is null.
- inEmptyEnvironment(() {
- _rewriteList(node.arguments);
- });
- node.receiver = visitExpression(node.receiver);
- }
- return node;
- }
-
- Expression visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- _rewriteList(node.arguments);
- // The target function might not exist before the enclosing class has been
- // instantitated for the first time. If the receiver might be the first
- // instantiation of its class, we cannot propgate it into the receiver
- // expression, because the target function is evaluated before the receiver.
- // Calls to constructor bodies are compiled so that the receiver is
- // evaluated first, so they are safe.
- if (node.target is! ConstructorBodyElement) {
- inEmptyEnvironment(() {
- node.receiver = visitExpression(node.receiver);
- });
- } else {
- node.receiver = visitExpression(node.receiver);
- }
- return node;
- }
-
- Expression visitInvokeConstructor(InvokeConstructor node) {
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitConditional(Conditional node) {
- // Conditional expressions do not exist in the input, but they are
- // introduced by if-to-conditional conversion.
- // Their subexpressions have already been processed; do not reprocess them.
- //
- // Note that this can only happen for conditional expressions. It is an
- // error for any other type of expression to be visited twice or to be
- // created and then visited. We use this special treatment of conditionals
- // to allow for assignment inlining after if-to-conditional conversion.
- //
- // There are several reasons we should not reprocess the subexpressions:
- //
- // - It will mess up the [seenUses] counter, since a single use will be
- // counted twice.
- //
- // - Other visit methods assume that all subexpressions are variable uses
- // because they come fresh out of the tree IR builder.
- //
- // - Reprocessing can be expensive.
- //
- return node;
- }
-
- Expression visitLogicalOperator(LogicalOperator node) {
- // Impure expressions may not propagate across the branch.
- inEmptyEnvironment(() {
- node.right = visitExpression(node.right);
- });
- node.left = visitExpression(node.left);
- return node;
- }
-
- Expression visitNot(Not node) {
- node.operand = visitExpression(node.operand);
- return node;
- }
-
- bool isNullConstant(Expression node) {
- return node is Constant && node.value.isNull;
- }
-
- Statement visitReturn(Return node) {
- if (!isNullConstant(node.value)) {
- // Do not chain assignments into a null return.
- node.value = visitExpression(node.value);
- }
- return node;
- }
-
- Statement visitThrow(Throw node) {
- node.value = visitExpression(node.value);
- return node;
- }
-
- Statement visitUnreachable(Unreachable node) {
- return node;
- }
-
- Statement visitBreak(Break node) {
- // Redirect through chain of breaks.
- // Note that useCount was accounted for at visitLabeledStatement.
- // Note redirect may return either a Break or Continue statement.
- Jump jump = redirect(node);
- if (jump is Break &&
- jump.target.useCount == 1 &&
- safeForInlining.contains(jump.target)) {
- --jump.target.useCount;
- return visitStatement(jump.target.binding.next);
- }
- return jump;
- }
-
- Statement visitContinue(Continue node) {
- return node;
- }
-
- Statement visitLabeledStatement(LabeledStatement node) {
- if (node.next is Jump) {
- // Eliminate label if next is a break or continue statement
- // Breaks to this label are redirected to the outer label.
- // Note that breakCount for the two labels is updated proactively here
- // so breaks can reliably tell if they should inline their target.
- Jump next = node.next;
- Jump newJump = redirect(next);
- labelRedirects[node.label] = newJump;
- newJump.target.useCount += node.label.useCount - 1;
- node.label.useCount = 0;
- Statement result = visitStatement(node.body);
- labelRedirects.remove(node.label); // Save some space.
- return result;
- }
-
- safeForInlining.add(node.label);
- node.body = visitStatement(node.body);
- safeForInlining.remove(node.label);
-
- if (node.label.useCount == 0) {
- // Eliminate the label if next was inlined at a break
- return node.body;
- }
-
- // Do not propagate assignments into the successor statements, since they
- // may be overwritten by assignments in the body.
- inEmptyEnvironment(() {
- node.next = visitStatement(node.next);
- });
-
- return node;
- }
-
- Statement visitIf(If node) {
- // Do not propagate assignments into branches.
- inEmptyEnvironment(() {
- node.thenStatement = visitStatement(node.thenStatement);
- node.elseStatement = visitStatement(node.elseStatement);
- });
-
- node.condition = visitExpression(node.condition);
-
- inEmptyEnvironment(() {
- tryCollapseIf(node);
- });
-
- Statement reduced = combineStatementsInBranches(
- node.thenStatement, node.elseStatement, node.condition);
- if (reduced != null) {
- return reduced;
- }
-
- return node;
- }
-
- Statement visitWhileTrue(WhileTrue node) {
- // Do not propagate assignments into loops. Doing so is not safe for
- // variables modified in the loop (the initial value will be propagated).
- // Do not propagate effective constant expressions into loops, since
- // computing them is not free (e.g. interceptors are expensive).
- inEmptyEnvironment(() {
- node.body = visitStatement(node.body);
- }, keepConstants: false);
- return node;
- }
-
- Statement visitFor(For node) {
- // Not introduced yet
- throw "Unexpected For in StatementRewriter";
- }
-
- Statement visitTry(Try node) {
- inEmptyEnvironment(() {
- Set<Label> saved = safeForInlining;
- safeForInlining = new Set<Label>();
- node.tryBody = visitStatement(node.tryBody);
- safeForInlining = saved;
- node.catchParameters.forEach(pushDominatingAssignment);
- node.catchBody = visitStatement(node.catchBody);
- node.catchParameters.forEach(popDominatingAssignment);
- });
- return node;
- }
-
- Expression visitConstant(Constant node) {
- if (isRhsPropagationAllowed && !environment.isEmpty) {
- Constant constant = getRightHandConstant(environment.last);
- if (constant != null && constant.value == node.value) {
- return visitExpression(environment.removeLast());
- }
- }
- return node;
- }
-
- Expression visitThis(This node) {
- return node;
- }
-
- Expression visitLiteralList(LiteralList node) {
- _rewriteList(node.values);
- return node;
- }
-
- Expression visitTypeOperator(TypeOperator node) {
- _rewriteList(node.typeArguments);
- node.value = visitExpression(node.value);
- return node;
- }
-
- bool isCompoundableBuiltin(Expression e) {
- return e is ApplyBuiltinOperator &&
- e.arguments.length >= 2 &&
- isCompoundableOperator(e.operator);
- }
-
- /// Converts a compoundable operator application into the right-hand side for
- /// use in a compound assignment, discarding the left-hand value.
- ///
- /// For example, for `x + y + z` it returns `y + z`.
- Expression contractCompoundableBuiltin(ApplyBuiltinOperator e) {
- assert(isCompoundableBuiltin(e));
- if (e.arguments.length > 2) {
- assert(e.operator == BuiltinOperator.StringConcatenate);
- return new ApplyBuiltinOperator(
- e.operator, e.arguments.skip(1).toList(), e.sourceInformation);
- } else {
- return e.arguments[1];
- }
- }
-
- void destroyVariableUse(VariableUse node) {
- --node.variable.readCount;
- }
-
- Expression visitSetField(SetField node) {
- allowRhsPropagation.add(true);
- node.value = visitExpression(node.value);
- if (isCompoundableBuiltin(node.value)) {
- ApplyBuiltinOperator rhs = node.value;
- Expression left = rhs.arguments[0];
- if (left is GetField &&
- left.field == node.field &&
- samePrimary(left.object, node.object)) {
- destroyPrimaryExpression(left.object);
- node.compound = rhs.operator;
- node.value = contractCompoundableBuiltin(rhs);
- }
- }
- node.object = visitExpression(node.object);
- allowRhsPropagation.removeLast();
- return node;
- }
-
- Expression visitGetField(GetField node) {
- node.object = visitExpression(node.object);
- return node;
- }
-
- Expression visitGetStatic(GetStatic node) {
- return node;
- }
-
- Expression visitSetStatic(SetStatic node) {
- allowRhsPropagation.add(true);
- node.value = visitExpression(node.value);
- if (isCompoundableBuiltin(node.value)) {
- ApplyBuiltinOperator rhs = node.value;
- Expression left = rhs.arguments[0];
- if (left is GetStatic &&
- left.element == node.element &&
- !left.useLazyGetter) {
- node.compound = rhs.operator;
- node.value = contractCompoundableBuiltin(rhs);
- }
- }
- allowRhsPropagation.removeLast();
- return node;
- }
-
- Expression visitGetTypeTestProperty(GetTypeTestProperty node) {
- node.object = visitExpression(node.object);
- return node;
- }
-
- Expression visitCreateBox(CreateBox node) {
- return node;
- }
-
- Expression visitCreateInstance(CreateInstance node) {
- if (node.typeInformation != null) {
- node.typeInformation = visitExpression(node.typeInformation);
- }
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitReifyRuntimeType(ReifyRuntimeType node) {
- node.value = visitExpression(node.value);
- return node;
- }
-
- Expression visitReadTypeVariable(ReadTypeVariable node) {
- node.target = visitExpression(node.target);
- return node;
- }
-
- Expression visitTypeExpression(TypeExpression node) {
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitCreateInvocationMirror(CreateInvocationMirror node) {
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitInterceptor(Interceptor node) {
- node.input = visitExpression(node.input);
- return node;
- }
-
- Expression visitGetLength(GetLength node) {
- node.object = visitExpression(node.object);
- return node;
- }
-
- Expression visitGetIndex(GetIndex node) {
- node.index = visitExpression(node.index);
- node.object = visitExpression(node.object);
- return node;
- }
-
- Expression visitSetIndex(SetIndex node) {
- node.value = visitExpression(node.value);
- if (isCompoundableBuiltin(node.value)) {
- ApplyBuiltinOperator rhs = node.value;
- Expression left = rhs.arguments[0];
- if (left is GetIndex &&
- samePrimary(left.object, node.object) &&
- samePrimary(left.index, node.index)) {
- destroyPrimaryExpression(left.object);
- destroyPrimaryExpression(left.index);
- node.compound = rhs.operator;
- node.value = contractCompoundableBuiltin(rhs);
- }
- }
- node.index = visitExpression(node.index);
- node.object = visitExpression(node.object);
- return node;
- }
-
- /// True if [operator] is a binary operator that always has the same value
- /// if its arguments are swapped.
- bool isSymmetricOperator(BuiltinOperator operator) {
- switch (operator) {
- case BuiltinOperator.StrictEq:
- case BuiltinOperator.StrictNeq:
- case BuiltinOperator.LooseEq:
- case BuiltinOperator.LooseNeq:
- case BuiltinOperator.NumAnd:
- case BuiltinOperator.NumOr:
- case BuiltinOperator.NumXor:
- case BuiltinOperator.NumAdd:
- case BuiltinOperator.NumMultiply:
- return true;
- default:
- return false;
- }
- }
-
- /// If [operator] is a commutable binary operator, returns the commuted
- /// operator, possibly the operator itself, otherwise returns `null`.
- BuiltinOperator commuteBinaryOperator(BuiltinOperator operator) {
- if (isSymmetricOperator(operator)) {
- // Symmetric operators are their own commutes.
- return operator;
- }
- switch (operator) {
- case BuiltinOperator.NumLt:
- return BuiltinOperator.NumGt;
- case BuiltinOperator.NumLe:
- return BuiltinOperator.NumGe;
- case BuiltinOperator.NumGt:
- return BuiltinOperator.NumLt;
- case BuiltinOperator.NumGe:
- return BuiltinOperator.NumLe;
- default:
- return null;
- }
- }
-
- /// Built-in binary operators are commuted when it is safe and can enable an
- /// assignment propagation. For example:
- ///
- /// var x = foo();
- /// var y = bar();
- /// var z = y < x;
- ///
- /// ==>
- ///
- /// var z = foo() > bar();
- ///
- /// foo() must be evaluated before bar(), so the propagation is only possible
- /// by commuting the operator.
- Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- if (!environment.isEmpty && getLeftHand(environment.last) != null) {
- Variable propagatableVariable = getLeftHand(environment.last);
- BuiltinOperator commuted = commuteBinaryOperator(node.operator);
- if (commuted != null) {
- // Only binary operators can commute.
- assert(node.arguments.length == 2);
- Expression left = node.arguments[0];
- if (left is VariableUse && propagatableVariable == left.variable) {
- Expression right = node.arguments[1];
- if (right is This ||
- (right is VariableUse &&
- propagatableVariable != right.variable &&
- !constantEnvironment.containsKey(right.variable))) {
- // An assignment can be propagated if we commute the operator.
- node.operator = commuted;
- node.arguments[0] = right;
- node.arguments[1] = left;
- }
- }
- }
- }
- // Avoid code like `p == (q.f = null)`. JS operators with a constant operand
- // can sometimes be compiled to a specialized instruction in the JS engine,
- // so retain syntactically constant operands.
- _rewriteList(node.arguments, rhsPropagation: false);
- return node;
- }
-
- /// If [s] and [t] are similar statements we extract their subexpressions
- /// and returns a new statement of the same type using expressions combined
- /// with the [combine] callback. For example:
- ///
- /// combineStatements(Return E1, Return E2) = Return combine(E1, E2)
- ///
- /// If [combine] returns E1 then the unified statement is equivalent to [s],
- /// and if [combine] returns E2 the unified statement is equivalence to [t].
- ///
- /// It is guaranteed that no side effects occur between the beginning of the
- /// statement and the position of the combined expression.
- ///
- /// Returns null if the statements are too different.
- ///
- /// If non-null is returned, the caller MUST discard [s] and [t] and use
- /// the returned statement instead.
- Statement combineStatementsInBranches(
- Statement s, Statement t, Expression condition) {
- if (s is Return && t is Return) {
- return new Return(new Conditional(condition, s.value, t.value));
- }
- if (s is ExpressionStatement && t is ExpressionStatement) {
- // Combine the two expressions and the two successor statements.
- //
- // C ? {E1 ; S1} : {E2 ; S2}
- // ==>
- // (C ? E1 : E2) : combine(S1, S2)
- //
- // If E1 and E2 are assignments, we want to propagate these into the
- // combined statement.
- //
- // It might not be possible to combine the statements, so we combine the
- // expressions, put the result in the environment, and then uncombine the
- // expressions if the statements could not be combined.
-
- // Combine the expressions.
- CombinedExpressions values =
- combineAsConditional(s.expression, t.expression, condition);
-
- // Put this into the environment and try to combine the statements.
- // We are not in risk of reprocessing the original subexpressions because
- // the combined expression will always hide them inside a Conditional.
- environment.add(values.combined);
-
- Variable leftHand = getLeftHand(values.combined);
- pushDominatingAssignment(leftHand);
- Statement next = combineStatements(s.next, t.next);
- popDominatingAssignment(leftHand);
-
- if (next == null) {
- // Statements could not be combined.
- // Restore the environment and uncombine expressions again.
- environment.removeLast();
- values.uncombine();
- return null;
- } else if (!environment.isEmpty && environment.last == values.combined) {
- // Statements were combined but the combined expression could not be
- // propagated. Leave it as an expression statement here.
- environment.removeLast();
- s.expression = values.combined;
- s.next = next;
- return s;
- } else {
- // Statements were combined and the combined expressions were
- // propagated into the combined statement.
- return next;
- }
- }
- return null;
- }
-
- /// Creates the expression `[condition] ? [s] : [t]` or an equivalent
- /// expression if something better can be done.
- ///
- /// In particular, assignments will be merged as follows:
- ///
- /// C ? (v = E1) : (v = E2)
- /// ==>
- /// v = C ? E1 : E2
- ///
- /// The latter form is more compact and can also be inlined.
- CombinedExpressions combineAsConditional(
- Expression s, Expression t, Expression condition) {
- if (s is Assign && t is Assign && s.variable == t.variable) {
- Expression values = new Conditional(condition, s.value, t.value);
- return new CombinedAssigns(s, t, new CombinedExpressions(values));
- }
- return new CombinedExpressions(new Conditional(condition, s, t));
- }
-
- /// Returns a statement equivalent to both [s] and [t], or null if [s] and
- /// [t] are incompatible.
- /// If non-null is returned, the caller MUST discard [s] and [t] and use
- /// the returned statement instead.
- /// If two breaks are combined, the label's break counter will be decremented.
- Statement combineStatements(Statement s, Statement t) {
- if (s is Break && t is Break && s.target == t.target) {
- --t.target.useCount; // Two breaks become one.
- if (s.target.useCount == 1 && safeForInlining.contains(s.target)) {
- // Only one break remains; inline it.
- --s.target.useCount;
- return visitStatement(s.target.binding.next);
- }
- return s;
- }
- if (s is Continue && t is Continue && s.target == t.target) {
- --t.target.useCount; // Two continues become one.
- return s;
- }
- if (s is Return && t is Return) {
- CombinedExpressions values = combineExpressions(s.value, t.value);
- if (values != null) {
- // TODO(johnniwinther): Handle multiple source informations.
- SourceInformation sourceInformation = s.sourceInformation != null
- ? s.sourceInformation
- : t.sourceInformation;
- return new Return(values.combined,
- sourceInformation: sourceInformation);
- }
- }
- if (s is ExpressionStatement && t is ExpressionStatement) {
- CombinedExpressions values =
- combineExpressions(s.expression, t.expression);
- if (values == null) return null;
- environment.add(values.combined);
- Variable leftHand = getLeftHand(values.combined);
- pushDominatingAssignment(leftHand);
- Statement next = combineStatements(s.next, t.next);
- popDominatingAssignment(leftHand);
- if (next == null) {
- // The successors could not be combined.
- // Restore the environment and uncombine the values again.
- assert(environment.last == values.combined);
- environment.removeLast();
- values.uncombine();
- return null;
- } else if (!environment.isEmpty && environment.last == values.combined) {
- // The successors were combined but the combined expressions were not
- // propagated. Leave the combined expression as a statement.
- environment.removeLast();
- s.expression = values.combined;
- s.next = next;
- return s;
- } else {
- // The successors were combined, and the combined expressions were
- // propagated into the successors.
- return next;
- }
- }
- return null;
- }
-
- /// Returns an expression equivalent to both [e1] and [e2].
- /// If non-null is returned, the caller must discard [e1] and [e2] and use
- /// the resulting expression in the tree.
- CombinedExpressions combineExpressions(Expression e1, Expression e2) {
- if (e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable) {
- return new CombinedUses(e1, e2);
- }
- if (e1 is Assign && e2 is Assign && e1.variable == e2.variable) {
- CombinedExpressions values = combineExpressions(e1.value, e2.value);
- if (values != null) {
- return new CombinedAssigns(e1, e2, values);
- }
- }
- if (e1 is Constant && e2 is Constant && e1.value == e2.value) {
- return new CombinedExpressions(e1);
- }
- return null;
- }
-
- /// Try to collapse nested ifs using && and || expressions.
- /// For example:
- ///
- /// if (E1) { if (E2) S else break L } else break L
- /// ==>
- /// if (E1 && E2) S else break L
- ///
- /// [branch1] and [branch2] control the position of the S statement.
- ///
- /// Must be called with an empty environment.
- void tryCollapseIf(If node) {
- assert(environment.isEmpty);
- // Repeatedly try to collapse nested ifs.
- // The transformation is shrinking (destroys an if) so it remains linear.
- // Here is an example where more than one iteration is required:
- //
- // if (E1)
- // if (E2) break L2 else break L1
- // else
- // break L1
- //
- // L1.target ::=
- // if (E3) S else break L2
- //
- // After first collapse:
- //
- // if (E1 && E2)
- // break L2
- // else
- // {if (E3) S else break L2} (inlined from break L1)
- //
- // We can then do another collapse using the inlined nested if.
- bool changed = true;
- while (changed) {
- changed = false;
- if (tryCollapseIfAux(node, true, true)) {
- changed = true;
- }
- if (tryCollapseIfAux(node, true, false)) {
- changed = true;
- }
- if (tryCollapseIfAux(node, false, true)) {
- changed = true;
- }
- if (tryCollapseIfAux(node, false, false)) {
- changed = true;
- }
- }
- }
-
- bool tryCollapseIfAux(If outerIf, bool branch1, bool branch2) {
- // NOTE: We name variables here as if S is in the then-then position.
- Statement outerThen = getBranch(outerIf, branch1);
- Statement outerElse = getBranch(outerIf, !branch1);
- if (outerThen is If) {
- If innerIf = outerThen;
- Statement innerThen = getBranch(innerIf, branch2);
- Statement innerElse = getBranch(innerIf, !branch2);
- Statement combinedElse = combineStatements(innerElse, outerElse);
- if (combinedElse != null) {
- // We always put S in the then branch of the result, and adjust the
- // condition expression if S was actually found in the else branch(es).
- outerIf.condition = new LogicalOperator.and(
- makeCondition(outerIf.condition, branch1),
- makeCondition(innerIf.condition, branch2));
- outerIf.thenStatement = innerThen;
- outerIf.elseStatement = combinedElse;
- return outerIf.elseStatement is If;
- }
- }
- return false;
- }
-
- Expression makeCondition(Expression e, bool polarity) {
- return polarity ? e : new Not(e);
- }
-
- Statement getBranch(If node, bool polarity) {
- return polarity ? node.thenStatement : node.elseStatement;
- }
-
- void handleForeignCode(ForeignCode node) {
- // Some arguments will get inserted in a JS code template. The arguments
- // will not always be evaluated (e.g. the second placeholder in the template
- // '# && #').
- bool isNullable(int position) => node.nullableArguments[position];
-
- int safeArguments =
- PlaceholderSafetyAnalysis.analyze(node.codeTemplate.ast, isNullable);
- inEmptyEnvironment(() {
- for (int i = node.arguments.length - 1; i >= safeArguments; --i) {
- node.arguments[i] = visitExpression(node.arguments[i]);
- }
- });
- for (int i = safeArguments - 1; i >= 0; --i) {
- node.arguments[i] = visitExpression(node.arguments[i]);
- }
- }
-
- @override
- Expression visitForeignExpression(ForeignExpression node) {
- handleForeignCode(node);
- return node;
- }
-
- @override
- Statement visitForeignStatement(ForeignStatement node) {
- handleForeignCode(node);
- return node;
- }
-
- @override
- Expression visitAwait(Await node) {
- node.input = visitExpression(node.input);
- return node;
- }
-
- @override
- Statement visitYield(Yield node) {
- node.next = visitStatement(node.next);
- node.input = visitExpression(node.input);
- return node;
- }
-
- @override
- Statement visitReceiverCheck(ReceiverCheck node) {
- inEmptyEnvironment(() {
- node.next = visitStatement(node.next);
- });
- if (node.condition != null) {
- inEmptyEnvironment(() {
- // Value occurs in conditional context.
- node.value = visitExpression(node.value);
- });
- node.condition = visitExpression(node.condition);
- } else {
- node.value = visitExpression(node.value);
- }
- return node;
- }
-}
-
-/// Result of combining two expressions, with the potential for reverting the
-/// combination.
-///
-/// Reverting a combination is done by calling [uncombine]. In this case,
-/// both the original expressions should remain in the tree, and the [combined]
-/// expression should be orphaned.
-///
-/// Explicitly reverting a combination is necessary to maintain variable
-/// reference counts.
-abstract class CombinedExpressions {
- Expression get combined;
- void uncombine();
-
- factory CombinedExpressions(Expression e) = GenericCombinedExpressions;
-}
-
-/// Combines assignments of form `[variable] := E1` and `[variable] := E2` into
-/// a single assignment of form `[variable] := combine(E1, E2)`.
-class CombinedAssigns implements CombinedExpressions {
- Assign assign1, assign2;
- CombinedExpressions value;
- Expression combined;
-
- CombinedAssigns(this.assign1, this.assign2, this.value) {
- assert(assign1.variable == assign2.variable);
- assign1.variable.writeCount -= 2; // Destroy the two original assignemnts.
- combined = new Assign(assign1.variable, value.combined);
- }
-
- void uncombine() {
- value.uncombine();
- ++assign1.variable.writeCount; // Restore original reference count.
- }
-}
-
-/// Combines two variable uses into one.
-class CombinedUses implements CombinedExpressions {
- VariableUse use1, use2;
- Expression combined;
-
- CombinedUses(this.use1, this.use2) {
- assert(use1.variable == use2.variable);
- use1.variable.readCount -= 2; // Destroy both the original uses.
- combined = new VariableUse(use1.variable);
- }
-
- void uncombine() {
- ++use1.variable.readCount; // Restore original reference count.
- }
-}
-
-/// Result of combining two expressions that do not affect reference counting.
-class GenericCombinedExpressions implements CombinedExpressions {
- Expression combined;
-
- GenericCombinedExpressions(this.combined);
-
- void uncombine() {}
-}
-
-/// Looks for uses of a specific variable.
-///
-/// Note that this visitor is only applied to expressions where all
-/// sub-expressions are known to be variable uses, so there is no risk of
-/// explosive reprocessing.
-class IsVariableUsedVisitor extends RecursiveVisitor {
- Variable variable;
- bool wasFound = false;
-
- IsVariableUsedVisitor(this.variable);
-
- visitVariableUse(VariableUse node) {
- if (node.variable == variable) {
- wasFound = true;
- }
- }
-}
-
-typedef VariableUseCallback(VariableUse use);
-
-class VariableUseVisitor extends RecursiveVisitor {
- VariableUseCallback callback;
-
- VariableUseVisitor(this.callback);
-
- visitVariableUse(VariableUse use) => callback(use);
-
- static void visit(Expression node, VariableUseCallback callback) {
- new VariableUseVisitor(callback).visitExpression(node);
- }
-}
-
-bool sameVariable(Expression e1, Expression e2) {
- return e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable;
-}
-
-/// True if [e1] and [e2] are primary expressions (expressions without
-/// subexpressions) with the same value.
-bool samePrimary(Expression e1, Expression e2) {
- return sameVariable(e1, e2) || (e1 is This && e2 is This);
-}
-
-/// Decrement the reference count for [e] if it is a variable use.
-void destroyPrimaryExpression(Expression e) {
- if (e is VariableUse) {
- --e.variable.readCount;
- } else {
- assert(e is This);
- }
-}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
deleted file mode 100644
index d76bb31..0000000
--- a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
+++ /dev/null
@@ -1,613 +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 tree_ir.optimization.variable_merger;
-
-import '../tree_ir_nodes.dart';
-import 'optimization.dart' show Pass;
-
-/// Merges variables based on liveness and source variable information.
-///
-/// This phase cleans up artifacts introduced by the translation through CPS,
-/// where each source variable is translated into several copies. The copies
-/// are merged again when they are not live simultaneously.
-class VariableMerger implements Pass {
- String get passName => 'Variable merger';
-
- final bool minifying;
-
- VariableMerger({this.minifying: false});
-
- void rewrite(FunctionDefinition node) {
- BlockGraphBuilder builder = new BlockGraphBuilder()..build(node);
- _computeLiveness(builder.blocks);
- PriorityPairs priority = new PriorityPairs()..build(node);
- Map<Variable, Variable> subst = _computeRegisterAllocation(
- builder.blocks, node.parameters, priority,
- minifying: minifying);
- new SubstituteVariables(subst).apply(node);
- }
-}
-
-/// A read or write access to a variable.
-class VariableAccess {
- Variable variable;
- bool isRead;
- bool get isWrite => !isRead;
-
- VariableAccess.read(this.variable) : isRead = true;
- VariableAccess.write(this.variable) : isRead = false;
-}
-
-/// Basic block in a control-flow graph.
-class Block {
- /// List of predecessors in the control-flow graph.
- final List<Block> predecessors = <Block>[];
-
- /// Entry to the catch block for the enclosing try, or `null`.
- final Block catchBlock;
-
- /// List of nodes with this block as [catchBlock].
- final List<Block> catchPredecessors = <Block>[];
-
- /// Sequence of read and write accesses in the block.
- final List<VariableAccess> accesses = <VariableAccess>[];
-
- /// Auxiliary fields used by the liveness analysis.
- bool inWorklist = true;
- Set<Variable> liveIn;
- Set<Variable> liveOut = new Set<Variable>();
- Set<Variable> gen = new Set<Variable>();
- Set<Variable> kill = new Set<Variable>();
-
- /// Adds a read operation to the block and updates gen/kill sets accordingly.
- void addRead(Variable variable) {
- // Operations are seen in forward order.
- // If the read is not preceded by a write, then add it to the GEN set.
- if (!kill.contains(variable)) {
- gen.add(variable);
- }
- accesses.add(new VariableAccess.read(variable));
- }
-
- /// Adds a write operation to the block and updates gen/kill sets accordingly.
- void addWrite(Variable variable) {
- // If the write is not preceded by a read, then add it to the KILL set.
- if (!gen.contains(variable)) {
- kill.add(variable);
- }
- accesses.add(new VariableAccess.write(variable));
- }
-
- Block(this.catchBlock) {
- if (catchBlock != null) {
- catchBlock.catchPredecessors.add(this);
- }
- }
-}
-
-/// Builds a control-flow graph suitable for performing liveness analysis.
-class BlockGraphBuilder extends RecursiveVisitor {
- Map<Label, Block> _jumpTarget = <Label, Block>{};
- Block _currentBlock;
- List<Block> blocks = <Block>[];
-
- /// Variables with an assignment that should be treated as final.
- ///
- /// Such variables cannot be merged with any other variables, so we exclude
- /// them from the control-flow graph entirely.
- Set<Variable> _ignoredVariables = new Set<Variable>();
-
- void build(FunctionDefinition node) {
- _currentBlock = newBlock();
- node.parameters.forEach(write);
- visitStatement(node.body);
- }
-
- /// Creates a new block with the current exception handler or [catchBlock]
- /// if provided.
- Block newBlock({Block catchBlock}) {
- if (catchBlock == null && _currentBlock != null) {
- catchBlock = _currentBlock.catchBlock;
- }
- Block block = new Block(catchBlock);
- blocks.add(block);
- return block;
- }
-
- /// Starts a new block after the end of [block].
- void branchFrom(Block block, {Block catchBlock}) {
- _currentBlock = newBlock(catchBlock: catchBlock)..predecessors.add(block);
- }
-
- /// Starts a new block with the given blocks as predecessors.
- void joinFrom(Block block1, Block block2) {
- assert(block1.catchBlock == block2.catchBlock);
- _currentBlock = newBlock(catchBlock: block1.catchBlock);
- _currentBlock.predecessors.add(block1);
- _currentBlock.predecessors.add(block2);
- }
-
- /// Called when reading from [variable].
- ///
- /// Appends a read operation to the current basic block.
- void read(Variable variable) {
- if (variable.isCaptured) return;
- if (_ignoredVariables.contains(variable)) return;
- _currentBlock.addRead(variable);
- }
-
- /// Called when writing to [variable].
- ///
- /// Appends a write operation to the current basic block.
- void write(Variable variable) {
- if (variable.isCaptured) return;
- if (_ignoredVariables.contains(variable)) return;
- _currentBlock.addWrite(variable);
- }
-
- /// Called to indicate that [variable] should not be merged, and therefore
- /// be excluded from the control-flow graph.
- /// Subsequent calls to [read] and [write] will ignore it.
- void ignoreVariable(Variable variable) {
- _ignoredVariables.add(variable);
- }
-
- visitVariableUse(VariableUse node) {
- read(node.variable);
- }
-
- visitAssign(Assign node) {
- visitExpression(node.value);
- write(node.variable);
- }
-
- visitIf(If node) {
- visitExpression(node.condition);
- Block afterCondition = _currentBlock;
- branchFrom(afterCondition);
- visitStatement(node.thenStatement);
- Block afterThen = _currentBlock;
- branchFrom(afterCondition);
- visitStatement(node.elseStatement);
- joinFrom(_currentBlock, afterThen);
- }
-
- visitLabeledStatement(LabeledStatement node) {
- Block join = _jumpTarget[node.label] = newBlock();
- visitStatement(node.body); // visitBreak will add predecessors to join.
- _currentBlock = join;
- visitStatement(node.next);
- }
-
- visitBreak(Break node) {
- _jumpTarget[node.target].predecessors.add(_currentBlock);
- }
-
- visitContinue(Continue node) {
- _jumpTarget[node.target].predecessors.add(_currentBlock);
- }
-
- visitWhileTrue(WhileTrue node) {
- Block join = _jumpTarget[node.label] = newBlock();
- join.predecessors.add(_currentBlock);
- _currentBlock = join;
- visitStatement(node.body); // visitContinue will add predecessors to join.
- }
-
- visitFor(For node) {
- Block entry = _currentBlock;
- _currentBlock = _jumpTarget[node.label] = newBlock();
- node.updates.forEach(visitExpression);
- joinFrom(entry, _currentBlock);
- visitExpression(node.condition);
- Block afterCondition = _currentBlock;
- branchFrom(afterCondition);
- visitStatement(node.body); // visitContinue will add predecessors to join.
- branchFrom(afterCondition);
- visitStatement(node.next);
- }
-
- visitTry(Try node) {
- Block outerCatchBlock = _currentBlock.catchBlock;
- Block catchBlock = newBlock(catchBlock: outerCatchBlock);
- branchFrom(_currentBlock, catchBlock: catchBlock);
- visitStatement(node.tryBody);
- Block afterTry = _currentBlock;
- _currentBlock = catchBlock;
- // Catch parameters cannot be hoisted to the top of the function, so to
- // avoid complications with scoping, we do not attempt to merge them.
- node.catchParameters.forEach(ignoreVariable);
- visitStatement(node.catchBody);
- Block afterCatch = _currentBlock;
- _currentBlock = newBlock(catchBlock: outerCatchBlock);
- _currentBlock.predecessors.add(afterCatch);
- _currentBlock.predecessors.add(afterTry);
- }
-
- visitConditional(Conditional node) {
- visitExpression(node.condition);
- Block afterCondition = _currentBlock;
- branchFrom(afterCondition);
- visitExpression(node.thenExpression);
- Block afterThen = _currentBlock;
- branchFrom(afterCondition);
- visitExpression(node.elseExpression);
- joinFrom(_currentBlock, afterThen);
- }
-
- visitLogicalOperator(LogicalOperator node) {
- visitExpression(node.left);
- Block afterLeft = _currentBlock;
- branchFrom(afterLeft);
- visitExpression(node.right);
- joinFrom(_currentBlock, afterLeft);
- }
-}
-
-/// Collects prioritized variable pairs -- pairs that lead to significant code
-/// reduction if merged into one variable.
-///
-/// These arise from moving assigments `v1 = v2`, and compoundable assignments
-/// `v1 = v2 [+] E` where [+] is a compoundable operator.
-//
-// TODO(asgerf): We could have a more fine-grained priority level. All pairs
-// are treated as equally important, but some pairs can eliminate more than
-// one assignment.
-// Also, some assignments are more important to remove than others, as they
-// can block a later optimization, such rewriting a loop, or removing the
-// 'else' part of an 'if'.
-//
-class PriorityPairs extends RecursiveVisitor {
- final Map<Variable, List<Variable>> _priority = <Variable, List<Variable>>{};
-
- void build(FunctionDefinition node) {
- visitStatement(node.body);
- }
-
- void _prioritize(Variable x, Variable y) {
- _priority.putIfAbsent(x, () => new List<Variable>()).add(y);
- _priority.putIfAbsent(y, () => new List<Variable>()).add(x);
- }
-
- visitAssign(Assign node) {
- super.visitAssign(node);
- Expression value = node.value;
- if (value is VariableUse) {
- _prioritize(node.variable, value.variable);
- } else if (value is ApplyBuiltinOperator &&
- isCompoundableOperator(value.operator) &&
- value.arguments[0] is VariableUse) {
- VariableUse use = value.arguments[0];
- _prioritize(node.variable, use.variable);
- }
- }
-
- /// Returns the other half of every priority pair containing [variable].
- List<Variable> getPriorityPairsWith(Variable variable) {
- return _priority[variable] ?? const <Variable>[];
- }
-
- bool hasPriorityPairs(Variable variable) {
- return _priority.containsKey(variable);
- }
-}
-
-/// Computes liveness information of the given control-flow graph.
-///
-/// The results are stored in [Block.liveIn] and [Block.liveOut].
-void _computeLiveness(List<Block> blocks) {
- // We use a LIFO queue as worklist. Blocks are given in AST order, so by
- // inserting them in this order, we initially visit them backwards, which
- // is a good ordering.
- // The choice of LIFO for re-inserted blocks is currently arbitrary,
- List<Block> worklist = new List<Block>.from(blocks);
- while (!worklist.isEmpty) {
- Block block = worklist.removeLast();
- block.inWorklist = false;
-
- bool changed = false;
-
- // The liveIn set is computed as:
- //
- // liveIn = (liveOut - kill) + gen
- //
- // We do the computation in two steps:
- //
- // 1. liveIn = gen
- // 2. liveIn += (liveOut - kill)
- //
- // However, since liveIn only grows, and gen never changes, we only have
- // to do the first step at the first iteration. Moreover, the gen set is
- // not needed anywhere else, so we don't even need to copy it.
- if (block.liveIn == null) {
- block.liveIn = block.gen;
- block.gen = null;
- changed = true;
- }
-
- // liveIn += (liveOut - kill)
- for (Variable variable in block.liveOut) {
- if (!block.kill.contains(variable)) {
- if (block.liveIn.add(variable)) {
- changed = true;
- }
- }
- }
-
- // If anything changed, propagate liveness backwards.
- if (changed) {
- // Propagate live variables to predecessors.
- for (Block predecessor in block.predecessors) {
- int lengthBeforeChange = predecessor.liveOut.length;
- predecessor.liveOut.addAll(block.liveIn);
- if (!predecessor.inWorklist &&
- predecessor.liveOut.length != lengthBeforeChange) {
- worklist.add(predecessor);
- predecessor.inWorklist = true;
- }
- }
-
- // Propagate live variables to catch predecessors.
- for (Block pred in block.catchPredecessors) {
- bool changed = false;
- int lengthBeforeChange = pred.liveOut.length;
- pred.liveOut.addAll(block.liveIn);
- if (pred.liveOut.length != lengthBeforeChange) {
- changed = true;
- }
- // Assigning to a variable that is live in the catch block, does not
- // kill the variable, because we conservatively assume that an exception
- // could be thrown immediately before the assignment.
- // Therefore remove live variables from all kill sets inside the try.
- // Since the kill set is only used to subtract live variables from a
- // set, the analysis remains monotone.
- lengthBeforeChange = pred.kill.length;
- pred.kill.removeAll(block.liveIn);
- if (pred.kill.length != lengthBeforeChange) {
- changed = true;
- }
- if (changed && !pred.inWorklist) {
- worklist.add(pred);
- pred.inWorklist = true;
- }
- }
- }
- }
-}
-
-/// Based on liveness information, computes a map of variable substitutions to
-/// merge variables.
-///
-/// Constructs a register interference graph. This is an undirected graph of
-/// variables, with an edge between two variables if they cannot be merged
-/// (because they are live simultaneously).
-///
-/// We then compute a graph coloring, where the color of a node denotes which
-/// variable it will be substituted by.
-Map<Variable, Variable> _computeRegisterAllocation(
- List<Block> blocks, List<Variable> parameters, PriorityPairs priority,
- {bool minifying}) {
- Map<Variable, Set<Variable>> interference = <Variable, Set<Variable>>{};
-
- bool allowUnmotivatedMerge(Variable x, Variable y) {
- if (minifying) return true;
- // Do not allow merging temporaries with named variables if they are
- // not connected by a phi. That would leads to confusing mergings like:
- // var v0 = receiver.length;
- // ==>
- // receiver = receiver.length;
- return x.element?.name == y.element?.name;
- }
-
- bool allowPhiMerge(Variable x, Variable y) {
- if (minifying) return true;
- // Temporaries may be merged with a named variable if this eliminates a phi.
- // The presence of the phi implies that the two variables can contain the
- // same value, so it is not that confusing that they get the same name.
- return x.element == null ||
- y.element == null ||
- x.element.name == y.element.name;
- }
-
- Set<Variable> empty = new Set<Variable>();
-
- // At the assignment to a variable x, add an edge to every variable that is
- // live after the assignment (if it came from the same source variable).
- for (Block block in blocks) {
- // Track the live set while traversing the block.
- Set<Variable> live = new Set<Variable>();
- for (Variable variable in block.liveOut) {
- live.add(variable);
- interference.putIfAbsent(variable, () => new Set<Variable>());
- }
- // Get variables that are live at the catch block.
- Set<Variable> liveCatch =
- block.catchBlock != null ? block.catchBlock.liveIn : empty;
- // Add edges for each variable being assigned here.
- for (VariableAccess access in block.accesses.reversed) {
- Variable variable = access.variable;
- interference.putIfAbsent(variable, () => new Set<Variable>());
- if (access.isRead) {
- live.add(variable);
- } else {
- if (!liveCatch.contains(variable)) {
- // Assignment to a variable that is not live in the catch block.
- live.remove(variable);
- }
- for (Variable other in live) {
- interference[variable].add(other);
- interference[other].add(variable);
- }
- }
- }
- }
-
- // Sort the variables by descending degree.
- // The most constrained variables will be assigned a color first.
- List<Variable> variables = interference.keys.toList();
- variables.sort((x, y) => interference[y].length - interference[x].length);
-
- List<Variable> registers = <Variable>[];
- Map<Variable, Variable> subst = <Variable, Variable>{};
-
- /// Called when [variable] has been assigned [target] as its register/color.
- /// Will immediately try to satisfy its priority pairs by assigning the same
- /// color the other half of each pair.
- void searchPriorityPairs(Variable variable, Variable target) {
- if (!priority.hasPriorityPairs(variable)) {
- return; // Most variables (around 90%) do not have priority pairs.
- }
- List<Variable> worklist = <Variable>[variable];
- while (worklist.isNotEmpty) {
- Variable v1 = worklist.removeLast();
- for (Variable v2 in priority.getPriorityPairsWith(v1)) {
- // If v2 already has a color, we cannot change it.
- if (subst.containsKey(v2)) continue;
-
- // Do not merge differently named variables.
- if (!allowPhiMerge(v1, v2)) continue;
-
- // Ensure the graph coloring remains valid. If a neighbour of v2 already
- // has the desired color, we cannot assign the same color to v2.
- if (interference[v2].any((v3) => subst[v3] == target)) continue;
-
- subst[v2] = target;
- target.element ??= v2.element; // Preserve the name.
- worklist.add(v2);
- }
- }
- }
-
- void assignRegister(Variable variable, Variable registerRepresentative) {
- subst[variable] = registerRepresentative;
- // Ensure this register is never assigned to a variable with another name.
- // This also ensures that named variables keep their name when merged
- // with a temporary.
- registerRepresentative.element ??= variable.element;
- searchPriorityPairs(variable, registerRepresentative);
- }
-
- void assignNewRegister(Variable variable) {
- registers.add(variable);
- subst[variable] = variable;
- searchPriorityPairs(variable, variable);
- }
-
- // Parameters cannot be merged with each other. Ensure that they are not
- // substituted. Other variables can still be substituted by a parameter.
- for (Variable parameter in parameters) {
- if (parameter.isCaptured) continue;
- registers.add(parameter);
- subst[parameter] = parameter;
- }
-
- // Try to merge parameters with locals to eliminate phis.
- for (Variable parameter in parameters) {
- searchPriorityPairs(parameter, parameter);
- }
-
- v1loop: for (Variable v1 in variables) {
- // Ignore if the variable has already been assigned a register.
- if (subst.containsKey(v1)) continue;
-
- // Optimization: If there are no interference edges for this variable,
- // find a color for it without copying the register list.
- Set<Variable> interferenceSet = interference[v1];
- if (interferenceSet.isEmpty) {
- // Use the first register where naming constraints allow the merge.
- for (Variable v2 in registers) {
- if (allowUnmotivatedMerge(v1, v2)) {
- assignRegister(v1, v2);
- continue v1loop;
- }
- }
- // No register allows merging with this one, create a new register.
- assignNewRegister(v1);
- continue;
- }
-
- // Find an unused color.
- Set<Variable> potential = new Set<Variable>.from(
- registers.where((v2) => allowUnmotivatedMerge(v1, v2)));
- for (Variable v2 in interferenceSet) {
- Variable v2subst = subst[v2];
- if (v2subst != null) {
- potential.remove(v2subst);
- if (potential.isEmpty) break;
- }
- }
-
- if (potential.isEmpty) {
- // If no free color was found, add this variable as a new color.
- assignNewRegister(v1);
- } else {
- assignRegister(v1, potential.first);
- }
- }
-
- return subst;
-}
-
-/// Performs variable substitution and removes redundant assignments.
-class SubstituteVariables extends RecursiveTransformer {
- Map<Variable, Variable> mapping;
-
- SubstituteVariables(this.mapping);
-
- Variable replaceRead(Variable variable) {
- Variable w = mapping[variable];
- if (w == null) return variable; // Skip ignored variables.
- w.readCount++;
- variable.readCount--;
- return w;
- }
-
- Variable replaceWrite(Variable variable) {
- Variable w = mapping[variable];
- if (w == null) return variable; // Skip ignored variables.
- w.writeCount++;
- variable.writeCount--;
- return w;
- }
-
- void apply(FunctionDefinition node) {
- for (int i = 0; i < node.parameters.length; ++i) {
- node.parameters[i] = replaceWrite(node.parameters[i]);
- }
- node.body = visitStatement(node.body);
- }
-
- Expression visitVariableUse(VariableUse node) {
- node.variable = replaceRead(node.variable);
- return node;
- }
-
- Expression visitAssign(Assign node) {
- node.variable = replaceWrite(node.variable);
- node.value = visitExpression(node.value);
-
- // Remove assignments of form "x := x"
- if (node.value is VariableUse) {
- VariableUse value = node.value;
- if (value.variable == node.variable) {
- --node.variable.writeCount;
- return value;
- }
- }
-
- return node;
- }
-
- Statement visitExpressionStatement(ExpressionStatement node) {
- node.expression = visitExpression(node.expression);
- node.next = visitStatement(node.next);
- if (node.expression is VariableUse) {
- VariableUse use = node.expression;
- --use.variable.readCount;
- return node.next;
- }
- return node;
- }
-}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
deleted file mode 100644
index a152f3b..0000000
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ /dev/null
@@ -1,773 +0,0 @@
-// 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 tree_ir_builder;
-
-import '../common.dart';
-import '../constants/values.dart';
-import '../cps_ir/cps_ir_nodes.dart' as cps_ir;
-import '../elements/elements.dart';
-import '../io/source_information.dart';
-import '../js_backend/codegen/glue.dart';
-import 'tree_ir_nodes.dart';
-
-typedef Statement NodeCallback(Statement next);
-
-/**
- * Builder translates from CPS-based IR to direct-style Tree.
- *
- * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced
- * non-exit continuation `Cont(v, body)` is translated into a direct-style call
- * whose value is bound in the continuation body:
- *
- * `LetVal(v, Invoke(fun, args), body)`
- *
- * and the continuation definition is eliminated. A similar translation is
- * applied to continuation invocations where the continuation is
- * singly-referenced, though such invocations should not appear in optimized
- * IR.
- *
- * A call `Invoke(fun, cont, args)`, where cont is multiply referenced, is
- * translated into a call followed by a jump with an argument:
- *
- * `Jump L(Invoke(fun, args))`
- *
- * and the continuation is translated into a named block that takes an
- * argument:
- *
- * `LetLabel(L, v, body)`
- *
- * Block arguments are later replaced with data flow during the Tree-to-Tree
- * translation out of SSA. Jumps are eliminated during the Tree-to-Tree
- * control-flow recognition.
- *
- * Otherwise, the output of Builder looks very much like the input. In
- * particular, intermediate values and blocks used for local control flow are
- * still all named.
- */
-class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
- final InternalErrorFunction internalError;
- final Glue glue;
-
- final Map<cps_ir.Primitive, Variable> primitive2variable =
- <cps_ir.Primitive, Variable>{};
- final Map<cps_ir.MutableVariable, Variable> mutable2variable =
- <cps_ir.MutableVariable, Variable>{};
- final Set<cps_ir.Constant> inlinedConstants = new Set<cps_ir.Constant>();
-
- // Continuations with more than one use are replaced with Tree labels. This
- // is the mapping from continuations to labels.
- final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{};
-
- ExecutableElement currentElement;
-
- /// The parameter to be translated to 'this'. This can either be the receiver
- /// parameter, the interceptor parameter, or null if the method has neither.
- cps_ir.Parameter thisParameter;
- cps_ir.Continuation returnContinuation;
-
- Builder(this.internalError, this.glue);
-
- /// Variable used in [buildPhiAssignments] as a temporary when swapping
- /// variables.
- Variable phiTempVar;
-
- Variable addMutableVariable(cps_ir.MutableVariable irVariable) {
- assert(!mutable2variable.containsKey(irVariable));
- Variable variable = new Variable(currentElement, irVariable.hint);
- mutable2variable[irVariable] = variable;
- return variable;
- }
-
- Variable getMutableVariable(cps_ir.MutableVariable mutableVariable) {
- return mutable2variable[mutableVariable];
- }
-
- VariableUse getMutableVariableUse(
- cps_ir.Reference<cps_ir.MutableVariable> reference,
- SourceInformation sourceInformation) {
- Variable variable = getMutableVariable(reference.definition);
- return new VariableUse(variable, sourceInformation: sourceInformation);
- }
-
- /// Obtains the variable representing the given primitive. Returns null for
- /// primitives that have no reference and do not need a variable.
- Variable getVariable(cps_ir.Primitive primitive) {
- primitive = primitive.effectiveDefinition;
- return primitive2variable.putIfAbsent(
- primitive, () => new Variable(currentElement, primitive.hint));
- }
-
- /// Obtains a reference to the tree Variable corresponding to the IR primitive
- /// referred to by [reference].
- /// This increments the reference count for the given variable, so the
- /// returned expression must be used in the tree.
- Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference,
- {SourceInformation sourceInformation}) {
- cps_ir.Primitive prim = reference.definition.effectiveDefinition;
- if (prim is cps_ir.Constant && inlinedConstants.contains(prim)) {
- return new Constant(prim.value);
- }
- if (thisParameter != null && prim == thisParameter) {
- return new This();
- }
- return new VariableUse(getVariable(prim),
- sourceInformation: sourceInformation);
- }
-
- Expression getVariableUseOrNull(
- cps_ir.Reference<cps_ir.Primitive> reference) {
- return reference == null ? null : getVariableUse(reference);
- }
-
- Label getLabel(cps_ir.Continuation cont) {
- return labels.putIfAbsent(cont, () => new Label());
- }
-
- FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) {
- currentElement = node.element;
- List<Variable> parameters = node.parameters.map(getVariable).toList();
- if (node.interceptorParameter != null) {
- parameters.insert(0, getVariable(node.receiverParameter));
- thisParameter = glue.methodUsesReceiverArgument(node.element)
- ? node.interceptorParameter
- : node.receiverParameter;
- } else {
- thisParameter = node.receiverParameter;
- }
- returnContinuation = node.returnContinuation;
- phiTempVar = new Variable(node.element, null);
- Statement body = translateExpression(node.body);
- return new FunctionDefinition(node.element, parameters, body,
- sourceInformation: node.sourceInformation);
- }
-
- /// Returns a list of variables corresponding to the arguments to a method
- /// call or similar construct.
- ///
- /// The `readCount` for these variables will be incremented.
- ///
- /// The list will be typed as a list of [Expression] to allow inplace updates
- /// on the list during the rewrite phases.
- List<Expression> translateArguments(List<cps_ir.Reference> args) {
- return new List<Expression>.generate(
- args.length, (int index) => getVariableUse(args[index]),
- growable: false);
- }
-
- /// Simultaneously assigns each argument to the corresponding parameter,
- /// then continues at the statement created by [buildRest].
- Statement buildPhiAssignments(List<cps_ir.Parameter> parameters,
- List<Expression> arguments, Statement buildRest()) {
- assert(parameters.length == arguments.length);
- // We want a parallel assignment to all parameters simultaneously.
- // Since we do not have parallel assignments in dart_tree, we must linearize
- // the assignments without attempting to read a previously-overwritten
- // value. For example {x,y = y,x} cannot be linearized to {x = y; y = x},
- // for this we must introduce a temporary variable: {t = x; x = y; y = t}.
-
- // [rightHand] is the inverse of [arguments], that is, it maps variables
- // to the assignments on which is occurs as the right-hand side.
- Map<Variable, List<int>> rightHand = <Variable, List<int>>{};
- for (int i = 0; i < parameters.length; i++) {
- Variable param = getVariable(parameters[i]);
- Expression arg = arguments[i];
- if (arg is VariableUse) {
- if (param == null || param == arg.variable) {
- // No assignment necessary.
- --arg.variable.readCount;
- continue;
- }
- // v1 = v0
- List<int> list = rightHand[arg.variable];
- if (list == null) {
- rightHand[arg.variable] = list = <int>[];
- }
- list.add(i);
- } else {
- // v1 = this;
- }
- }
-
- Statement first, current;
- void addAssignment(Variable dst, Expression src) {
- if (first == null) {
- first = current = Assign.makeStatement(dst, src);
- } else {
- current = current.next = Assign.makeStatement(dst, src);
- }
- }
-
- List<Expression> assignmentSrc = new List<Expression>(parameters.length);
- List<bool> done = new List<bool>.filled(parameters.length, false);
- void visitAssignment(int i) {
- if (done[i]) {
- return;
- }
- Variable param = getVariable(parameters[i]);
- Expression arg = arguments[i];
- if (param == null || (arg is VariableUse && param == arg.variable)) {
- return; // No assignment necessary.
- }
- if (assignmentSrc[i] != null) {
- // Cycle found; store argument in a temporary variable.
- // The temporary will then be used as right-hand side when the
- // assignment gets added.
- VariableUse source = assignmentSrc[i];
- if (source.variable != phiTempVar) {
- // Only move to temporary once.
- assignmentSrc[i] = new VariableUse(phiTempVar);
- addAssignment(phiTempVar, arg);
- }
- return;
- }
- assignmentSrc[i] = arg;
- List<int> paramUses = rightHand[param];
- if (paramUses != null) {
- for (int useIndex in paramUses) {
- visitAssignment(useIndex);
- }
- }
- addAssignment(param, assignmentSrc[i]);
- done[i] = true;
- }
-
- for (int i = 0; i < parameters.length; i++) {
- if (!done[i]) {
- visitAssignment(i);
- }
- }
-
- if (first == null) {
- first = buildRest();
- } else {
- current.next = buildRest();
- }
- return first;
- }
-
- visit(cps_ir.Node node) => throw 'Use translateXXX instead of visit';
-
- /// Translates a CPS expression into a tree statement.
- ///
- /// To avoid deep recursion, we traverse each basic blocks without
- /// recursion.
- ///
- /// Non-tail expressions evaluate to a callback to be invoked once the
- /// successor statement has been constructed. These callbacks are stored
- /// in a stack until the block's tail expression has been translated.
- Statement translateExpression(cps_ir.Expression node) {
- List<NodeCallback> stack = <NodeCallback>[];
- while (node is! cps_ir.TailExpression) {
- stack.add(node.accept(this));
- node = node.next;
- }
- Statement result = node.accept(this); // Translate the tail expression.
- for (NodeCallback fun in stack.reversed) {
- result = fun(result);
- }
- return result;
- }
-
- /// Translates a CPS primitive to a tree expression.
- ///
- /// This simply calls the visit method for the primitive.
- translatePrimitive(cps_ir.Primitive prim) {
- return prim.accept(this);
- }
-
- /************************ CONSTANT COPYING *****************************/
-
- /// Estimate of the number of characters needed to emit a use of the given
- /// constant.
- int constantSize(PrimitiveConstantValue value) {
- // TODO(asgerf): We could interface with the emitter to get the exact size.
- if (value is StringConstantValue) {
- // Account for the quotes, but ignore the cost of encoding non-ASCII
- // characters to avoid traversing the string and depending on encoding.
- return value.length + 2;
- } else if (value is BoolConstantValue) {
- return 2; // Printed as !0 and !1 when minified
- } else {
- // TODO(asgerf): Get the exact length of numbers using '1e10' notation.
- return '${value.primitiveValue}'.length;
- }
- }
-
- /// The number of uses [prim] has, or `-1` if it is used in a phi assignment.
- int countNonPhiUses(cps_ir.Primitive prim) {
- int count = 0;
- for (cps_ir.Reference ref = prim.firstRef; ref != null; ref = ref.next) {
- cps_ir.Node use = ref.parent;
- if (use is cps_ir.InvokeContinuation) {
- return -1;
- }
- count++;
- }
- return count;
- }
-
- /// True if the given [constant] should be copied to every use site.
- bool shouldCopyToUses(cps_ir.Constant constant) {
- if (!constant.value.isPrimitive) return false;
- if (constant.hasAtMostOneUse) return true;
- int uses = countNonPhiUses(constant);
- if (uses == -1) return false; // Copying might prevent elimination of a phi.
- int size = constantSize(constant.value);
- // Compare the expected code size output of copying vs sharing.
- const int USE = 2; // Minified locals usually have length 2.
- const int ASSIGN = USE + 2; // Variable and '=' and ';'
- const int BIAS = 2; // Artificial bias to slightly favor copying.
- int costOfSharing = USE * uses + size + ASSIGN + BIAS;
- int costOfCopying = size * uses;
- return costOfCopying <= costOfSharing;
- }
-
- /************************ INTERIOR EXPRESSIONS ************************/
- //
- // Visit methods for interior expressions must return a function:
- //
- // (Statement next) => <result statement>
- //
-
- NodeCallback visitLetPrim(cps_ir.LetPrim node) {
- if (node.primitive is cps_ir.Constant && shouldCopyToUses(node.primitive)) {
- inlinedConstants.add(node.primitive);
- return (Statement next) => next;
- }
- Variable variable = getVariable(node.primitive);
- var value = translatePrimitive(node.primitive);
- if (value is Expression) {
- if (node.primitive.hasAtLeastOneUse) {
- return (Statement next) => Assign.makeStatement(variable, value, next);
- } else {
- return (Statement next) => new ExpressionStatement(value, next);
- }
- } else {
- assert(value is NodeCallback);
- return value;
- }
- }
-
- // Continuations are bound at the same level, but they have to be
- // translated as if nested. This is because the body can invoke any
- // of them from anywhere, so it must be nested inside all of them.
- //
- // The continuation bodies are not always translated directly here because
- // they may have been already translated:
- // * For singly-used continuations, the continuation's body is
- // translated at the site of the continuation invocation.
- // * For recursive continuations, there is a single non-recursive
- // invocation. The continuation's body is translated at the site
- // of the non-recursive continuation invocation.
- // See [visitInvokeContinuation] for the implementation.
- NodeCallback visitLetCont(cps_ir.LetCont node) => (Statement next) {
- for (cps_ir.Continuation continuation in node.continuations) {
- // This happens after the body of the LetCont has been translated.
- // Labels are created on-demand if the continuation could not be inlined,
- // so the existence of the label indicates if a labeled statement should
- // be emitted.
- Label label = labels[continuation];
- if (label != null && !continuation.isRecursive) {
- // Recursively build the body. We only do this for join continuations,
- // so we should not risk overly deep recursion.
- next = new LabeledStatement(
- label, next, translateExpression(continuation.body));
- }
- }
- return next;
- };
-
- NodeCallback visitLetHandler(cps_ir.LetHandler node) => (Statement next) {
- List<Variable> catchParameters =
- node.handler.parameters.map(getVariable).toList();
- Statement catchBody = translateExpression(node.handler.body);
- return new Try(next, catchParameters, catchBody);
- };
-
- NodeCallback visitLetMutable(cps_ir.LetMutable node) {
- Variable variable = addMutableVariable(node.variable);
- Expression value = getVariableUse(node.valueRef);
- return (Statement next) => Assign.makeStatement(variable, value, next);
- }
-
- /************************** TAIL EXPRESSIONS **************************/
- //
- // Visit methods for tail expressions must return a statement directly
- // (not a function like interior and call expressions).
-
- Statement visitThrow(cps_ir.Throw node) {
- Expression value = getVariableUse(node.valueRef);
- return new Throw(value);
- }
-
- Statement visitUnreachable(cps_ir.Unreachable node) {
- return new Unreachable();
- }
-
- Statement visitInvokeContinuation(cps_ir.InvokeContinuation node) {
- // Invocations of the return continuation are translated to returns.
- // Other continuation invocations are replaced with assignments of the
- // 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;
- if (cont == returnContinuation) {
- assert(node.argumentRefs.length == 1);
- return new Return(getVariableUse(node.argumentRefs.single),
- sourceInformation: node.sourceInformation);
- } else {
- List<Expression> arguments = translateArguments(node.argumentRefs);
- return buildPhiAssignments(cont.parameters, arguments, () {
- // Translate invocations of recursive and non-recursive
- // continuations differently.
- // * Non-recursive continuations
- // - If there is one use, translate the continuation body
- // inline at the invocation site.
- // - If there are multiple uses, translate to Break.
- // * Recursive continuations
- // - There is a single non-recursive invocation. Translate
- // the continuation body inline as a labeled loop at the
- // invocation site.
- // - Translate the recursive invocations to Continue.
- if (cont.isRecursive) {
- return node.isRecursive
- ? new Continue(getLabel(cont))
- : new WhileTrue(getLabel(cont), translateExpression(cont.body));
- } else {
- return cont.hasExactlyOneUse && !node.isEscapingTry
- ? translateExpression(cont.body)
- : new Break(getLabel(cont));
- }
- });
- }
- }
-
- /// Translates a branch condition to a tree expression.
- Expression translateCondition(cps_ir.Branch branch) {
- Expression value = getVariableUse(branch.conditionRef,
- sourceInformation: branch.sourceInformation);
- if (branch.isStrictCheck) {
- return new ApplyBuiltinOperator(
- BuiltinOperator.StrictEq,
- <Expression>[value, new Constant(new TrueConstantValue())],
- branch.sourceInformation);
- } else {
- return value;
- }
- }
-
- Statement visitBranch(cps_ir.Branch node) {
- Expression condition = translateCondition(node);
- Statement thenStatement, elseStatement;
- cps_ir.Continuation cont = node.trueContinuation;
- assert(cont.parameters.isEmpty);
- thenStatement = cont.hasExactlyOneUse
- ? translateExpression(cont.body)
- : new Break(labels[cont]);
- cont = node.falseContinuation;
- assert(cont.parameters.isEmpty);
- elseStatement = cont.hasExactlyOneUse
- ? translateExpression(cont.body)
- : new Break(labels[cont]);
- return new If(
- condition, thenStatement, elseStatement, node.sourceInformation);
- }
-
- /************************** PRIMITIVES **************************/
- //
- // Visit methods for primitives must return an expression.
- //
-
- Expression visitSetField(cps_ir.SetField node) {
- return new SetField(getVariableUse(node.objectRef), node.field,
- getVariableUse(node.valueRef), node.sourceInformation);
- }
-
- Expression visitInterceptor(cps_ir.Interceptor node) {
- return new Interceptor(getVariableUse(node.inputRef),
- node.interceptedClasses, node.sourceInformation);
- }
-
- Expression visitCreateInstance(cps_ir.CreateInstance node) {
- return new CreateInstance(
- node.classElement,
- translateArguments(node.argumentRefs),
- getVariableUseOrNull(node.typeInformationRef),
- node.sourceInformation);
- }
-
- Expression visitGetField(cps_ir.GetField node) {
- return new GetField(
- getVariableUse(node.objectRef), node.field, node.sourceInformation,
- objectIsNotNull: !node.object.type.isNullable);
- }
-
- Expression visitCreateBox(cps_ir.CreateBox node) {
- return new CreateBox();
- }
-
- Expression visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
- return new CreateInvocationMirror(
- node.selector, translateArguments(node.argumentRefs));
- }
-
- Expression visitGetMutable(cps_ir.GetMutable node) {
- return getMutableVariableUse(node.variableRef, node.sourceInformation);
- }
-
- Expression visitSetMutable(cps_ir.SetMutable node) {
- Variable variable = getMutableVariable(node.variable);
- Expression value = getVariableUse(node.valueRef);
- return new Assign(variable, value,
- sourceInformation: node.sourceInformation);
- }
-
- Expression visitConstant(cps_ir.Constant node) {
- return new Constant(node.value, sourceInformation: node.sourceInformation);
- }
-
- Expression visitLiteralList(cps_ir.LiteralList node) {
- return new LiteralList(node.dartType, translateArguments(node.valueRefs));
- }
-
- Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
- return new ReifyRuntimeType(
- getVariableUse(node.valueRef), node.sourceInformation);
- }
-
- Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
- return new ReadTypeVariable(
- node.variable, getVariableUse(node.targetRef), node.sourceInformation);
- }
-
- Expression visitTypeExpression(cps_ir.TypeExpression node) {
- return new TypeExpression(node.kind, node.dartType,
- node.argumentRefs.map(getVariableUse).toList());
- }
-
- Expression visitTypeTest(cps_ir.TypeTest node) {
- 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.interceptorRef);
- // TODO(sra): Move !! to cps_ir level.
- return new Not(new Not(new GetTypeTestProperty(value, node.dartType)));
- }
-
- Expression visitGetStatic(cps_ir.GetStatic node) {
- return new GetStatic(node.element, node.sourceInformation);
- }
-
- Expression visitSetStatic(cps_ir.SetStatic node) {
- return new SetStatic(
- node.element, getVariableUse(node.valueRef), node.sourceInformation);
- }
-
- Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
- if (node.operator == BuiltinOperator.IsFalsy) {
- return new Not(getVariableUse(node.argumentRefs.single));
- }
- return new ApplyBuiltinOperator(node.operator,
- translateArguments(node.argumentRefs), node.sourceInformation);
- }
-
- Expression visitApplyBuiltinMethod(cps_ir.ApplyBuiltinMethod node) {
- return new ApplyBuiltinMethod(node.method, getVariableUse(node.receiverRef),
- translateArguments(node.argumentRefs),
- receiverIsNotNull: !node.receiver.type.isNullable);
- }
-
- Expression visitGetLength(cps_ir.GetLength node) {
- return new GetLength(getVariableUse(node.objectRef));
- }
-
- Expression visitGetIndex(cps_ir.GetIndex node) {
- return new GetIndex(
- getVariableUse(node.objectRef), getVariableUse(node.indexRef));
- }
-
- Expression visitSetIndex(cps_ir.SetIndex node) {
- return new SetIndex(getVariableUse(node.objectRef),
- getVariableUse(node.indexRef), getVariableUse(node.valueRef));
- }
-
- Expression visitInvokeStatic(cps_ir.InvokeStatic node) {
- List<Expression> arguments = translateArguments(node.argumentRefs);
- return new InvokeStatic(
- node.target, node.selector, arguments, node.sourceInformation);
- }
-
- List<Expression> insertReceiverArgument(
- Expression receiver, List<Expression> arguments) {
- return new List<Expression>.generate(
- arguments.length + 1, (n) => n == 0 ? receiver : arguments[n - 1],
- growable: false);
- }
-
- Expression visitInvokeMethod(cps_ir.InvokeMethod node) {
- switch (node.callingConvention) {
- case cps_ir.CallingConvention.Normal:
- InvokeMethod invoke = new InvokeMethod(
- getVariableUse(node.receiverRef),
- node.selector,
- node.mask,
- translateArguments(node.argumentRefs),
- node.sourceInformation);
- invoke.receiverIsNotNull = !node.receiver.type.isNullable;
- return invoke;
-
- case cps_ir.CallingConvention.Intercepted:
- List<Expression> arguments = insertReceiverArgument(
- getVariableUse(node.receiverRef),
- translateArguments(node.argumentRefs));
- InvokeMethod invoke = new InvokeMethod(
- getVariableUse(node.interceptorRef),
- node.selector,
- node.mask,
- arguments,
- 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 use-site. Interceptors are not refined, so this information is
- // not always available on the JS receiver.
- // Also check the JS receiver's type, however, because sometimes we know
- // an interceptor is non-null because it intercepts JSNull.
- invoke.receiverIsNotNull =
- !node.receiver.type.isNullable || !node.interceptor.type.isNullable;
- return invoke;
-
- case cps_ir.CallingConvention.DummyIntercepted:
- List<Expression> arguments = insertReceiverArgument(
- new Constant(new IntConstantValue(0)),
- translateArguments(node.argumentRefs));
- InvokeMethod invoke = new InvokeMethod(getVariableUse(node.receiverRef),
- node.selector, node.mask, arguments, node.sourceInformation);
- invoke.receiverIsNotNull = !node.receiver.type.isNullable;
- return invoke;
-
- case cps_ir.CallingConvention.OneShotIntercepted:
- List<Expression> arguments = insertReceiverArgument(
- getVariableUse(node.receiverRef),
- translateArguments(node.argumentRefs));
- return new OneShotInterceptor(
- node.selector, node.mask, arguments, node.sourceInformation);
- }
- }
-
- Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
- if (node.interceptorRef != null) {
- return new InvokeMethodDirectly(
- getVariableUse(node.interceptorRef),
- node.target,
- node.selector,
- insertReceiverArgument(getVariableUse(node.receiverRef),
- translateArguments(node.argumentRefs)),
- node.sourceInformation);
- } else {
- return new InvokeMethodDirectly(
- getVariableUse(node.receiverRef),
- node.target,
- node.selector,
- translateArguments(node.argumentRefs),
- node.sourceInformation);
- }
- }
-
- Expression visitTypeCast(cps_ir.TypeCast node) {
- 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.argumentRefs);
- return new InvokeConstructor(node.dartType, node.target, node.selector,
- arguments, node.sourceInformation);
- }
-
- visitForeignCode(cps_ir.ForeignCode node) {
- List<Expression> 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) {
- return new ForeignExpression(
- node.codeTemplate,
- node.type,
- arguments,
- node.nativeBehavior,
- nullableArguments,
- node.dependency,
- node.sourceInformation);
- } else {
- return (Statement next) {
- assert(next is Unreachable); // We are not using the `next` statement.
- return new ForeignStatement(
- node.codeTemplate,
- node.type,
- arguments,
- node.nativeBehavior,
- nullableArguments,
- node.dependency,
- node.sourceInformation);
- };
- }
- }
-
- visitReceiverCheck(cps_ir.ReceiverCheck node) => (Statement next) {
- // The CPS IR uses 'isNullCheck' because the semantics are important.
- // 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.conditionRef),
- value: getVariableUse(node.valueRef),
- selector: node.selector,
- useSelector: node.useSelector,
- useInvoke: !node.isNullCheck,
- next: next,
- sourceInformation: node.sourceInformation);
- };
-
- Expression visitGetLazyStatic(cps_ir.GetLazyStatic node) {
- return new GetStatic.lazy(node.element, node.sourceInformation);
- }
-
- @override
- NodeCallback visitYield(cps_ir.Yield node) {
- return (Statement next) {
- return new Yield(getVariableUse(node.inputRef), node.hasStar, next);
- };
- }
-
- @override
- Expression visitAwait(cps_ir.Await node) {
- return new Await(getVariableUse(node.inputRef));
- }
-
- @override
- visitRefinement(cps_ir.Refinement node) {
- return (Statement next) => next; // Compile to nothing.
- }
-
- /********** UNUSED VISIT METHODS *************/
-
- unexpectedNode(cps_ir.Node node) {
- internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node');
- }
-
- visitFunctionDefinition(cps_ir.FunctionDefinition node) {
- unexpectedNode(node);
- }
-
- visitParameter(cps_ir.Parameter node) => unexpectedNode(node);
- visitContinuation(cps_ir.Continuation node) => unexpectedNode(node);
- visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node);
- visitRethrow(cps_ir.Rethrow node) => unexpectedNode(node);
- visitBoundsCheck(cps_ir.BoundsCheck node) => unexpectedNode(node);
-}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
deleted file mode 100644
index ea40782..0000000
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
+++ /dev/null
@@ -1,161 +0,0 @@
-library tree_ir.integrity;
-
-import 'tree_ir_nodes.dart';
-
-/// Performs integrity checks on the tree_ir.
-///
-/// Should only be run for debugging purposes, not in production.
-///
-/// - Reference counts on must match the actual number of references.
-/// - Labels must be in scope when referenced.
-/// - Breaks must target a [LabeledStatement].
-/// - Continues must target a [Loop].
-/// - Variables must only be used after their first assignment
-/// (checked on a best-effort basis).
-/// - Variables with a declaration must only be referenced in scope.
-/// - Variables must not have more than one declaration.
-///
-class CheckTreeIntegrity extends RecursiveVisitor {
- FunctionDefinition topLevelNode;
-
- Map<Variable, int> varReads = <Variable, int>{};
- Map<Variable, int> varWrites = <Variable, int>{};
- Map<Label, int> labelUses = <Label, int>{};
- Map<Label, JumpTarget> label2declaration = <Label, JumpTarget>{};
-
- /// Variables that are currently in scope.
- Set<Variable> scope = new Set<Variable>();
-
- /// Variables for which we have seen a declaration.
- Set<Variable> seenDeclaration = new Set<Variable>();
-
- void write(Variable variable) {
- if (!seenDeclaration.contains(variable)) {
- // Implicitly-declared variables are in scope after the first assignment.
- scope.add(variable);
- } else if (!scope.contains(variable)) {
- // There is a declaration for variable but it is no longer in scope.
- error('$variable assigned out of scope');
- }
- varWrites.putIfAbsent(variable, () => 0);
- varWrites[variable]++;
- }
-
- void read(Variable variable) {
- if (!scope.contains(variable)) {
- error('$variable used out of scope');
- }
- varReads.putIfAbsent(variable, () => 0);
- varReads[variable]++;
- }
-
- void declare(Variable variable) {
- if (!scope.add(variable) || !seenDeclaration.add(variable)) {
- error('Redeclared $variable');
- }
- varWrites.putIfAbsent(variable, () => 0);
- varWrites[variable]++;
- }
-
- void undeclare(Variable variable) {
- scope.remove(variable);
- }
-
- visitVariableUse(VariableUse node) {
- read(node.variable);
- }
-
- visitAssign(Assign node) {
- visitExpression(node.value);
- write(node.variable);
- }
-
- visitTry(Try node) {
- visitStatement(node.tryBody);
- node.catchParameters.forEach(declare);
- visitStatement(node.catchBody);
- node.catchParameters.forEach(undeclare);
- }
-
- visitJumpTargetBody(JumpTarget target) {
- Label label = target.label;
- if (label2declaration.containsKey(label)) {
- error('Duplicate declaration of label $label');
- }
- label2declaration[label] = target;
- labelUses[label] = 0;
- visitStatement(target.body);
- label2declaration.remove(label);
-
- if (labelUses[label] != label.useCount) {
- error('Label $label has ${labelUses[label]} uses '
- 'but its reference count is ${label.useCount}');
- }
- }
-
- visitLabeledStatement(LabeledStatement node) {
- visitJumpTargetBody(node);
- visitStatement(node.next);
- }
-
- visitWhileTrue(WhileTrue node) {
- visitJumpTargetBody(node);
- }
-
- visitFor(For node) {
- visitExpression(node.condition);
- visitJumpTargetBody(node);
- node.updates.forEach(visitExpression);
- visitStatement(node.next);
- }
-
- visitBreak(Break node) {
- if (!label2declaration.containsKey(node.target)) {
- error('Break to label that is not in scope');
- }
- if (label2declaration[node.target] is! LabeledStatement) {
- error('Break to non-labeled statement ${label2declaration[node.target]}');
- }
- labelUses[node.target]++;
- }
-
- visitContinue(Continue node) {
- if (!label2declaration.containsKey(node.target)) {
- error('Continue to label that is not in scope');
- }
- if (label2declaration[node.target] is! Loop) {
- error('Continue to non-loop statement ${label2declaration[node.target]}');
- }
- labelUses[node.target]++;
- }
-
- void checkBody(FunctionDefinition node) {
- node.parameters.forEach(declare);
- visitStatement(node.body);
- node.parameters.forEach(undeclare);
- }
-
- dynamic error(String message) {
- throw 'Tree IR integrity violation in ${topLevelNode.element}:\n$message';
- }
-
- void check(FunctionDefinition node) {
- topLevelNode = node;
- checkBody(node);
-
- // Verify reference counters for all variables.
- List<Variable> seenVariables = new List<Variable>();
- seenVariables.addAll(varReads.keys);
- seenVariables.addAll(varWrites.keys);
- for (Variable variable in seenVariables) {
- int reads = varReads.putIfAbsent(variable, () => 0);
- int writes = varWrites.putIfAbsent(variable, () => 0);
- if (reads != variable.readCount || writes != variable.writeCount) {
- error('Invalid reference count for $variable:\n'
- '- Variable has $reads reads and $writes writes\n'
- '- Reference count is ${variable.readCount} reads and '
- '${variable.writeCount} writes');
- }
- }
- }
-}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
deleted file mode 100644
index a1fe55e..0000000
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ /dev/null
@@ -1,1607 +0,0 @@
-// 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 tree_ir_nodes;
-
-import '../constants/values.dart' as values;
-import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType;
-import '../elements/elements.dart';
-import '../io/source_information.dart' show SourceInformation;
-import '../types/types.dart' show TypeMask;
-import '../universe/selector.dart' show Selector;
-
-import '../cps_ir/builtin_operator.dart';
-export '../cps_ir/builtin_operator.dart';
-import '../cps_ir/cps_ir_nodes.dart' show TypeExpressionKind;
-export '../cps_ir/cps_ir_nodes.dart' show TypeExpressionKind;
-
-// 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.
-import '../js/js.dart' as js show Template;
-import '../native/native.dart' as native show NativeBehavior;
-import '../types/types.dart' as types show TypeMask;
-
-// The Tree language is the target of translation out of the CPS-based IR.
-//
-// The translation from CPS to Dart consists of several stages. Among the
-// stages are translation to direct style, translation out of SSA, eliminating
-// unnecessary names, recognizing high-level control constructs. Combining
-// these separate concerns is complicated and the constraints of the CPS-based
-// language do not permit a multi-stage translation.
-//
-// For that reason, CPS is translated to the direct-style language Tree.
-// Translation out of SSA, unnaming, and control-flow, as well as 'instruction
-// selection' are performed on the Tree language.
-//
-// In contrast to the CPS-based IR, non-primitive expressions can be named and
-// arguments (to calls, primitives, and blocks) can be arbitrary expressions.
-//
-// Additionally, variables are considered in scope within inner functions;
-// closure variables are thus handled directly instead of using ref cells.
-
-/**
- * The base class of all Tree nodes.
- */
-abstract class Node {
- /// Workaround for a slow Object.hashCode in the VM.
- static int _usedHashCodes = 0;
- final int hashCode = ++_usedHashCodes;
-}
-
-/**
- * The base class of [Expression]s.
- */
-abstract class Expression extends Node {
- accept(ExpressionVisitor v);
- accept1(ExpressionVisitor1 v, arg);
-
- SourceInformation get sourceInformation => null;
-}
-
-abstract class Statement extends Node {
- Statement get next;
- void set next(Statement s);
- accept(StatementVisitor v);
- accept1(StatementVisitor1 v, arg);
-}
-
-/**
- * Labels name [LabeledStatement]s.
- */
-class Label {
- /// Number of [Break] or [Continue] statements that target this label.
- /// The [Break] constructor will increment this automatically, but the
- /// counter must be decremented by hand when a [Break] becomes orphaned.
- int useCount = 0;
-
- /// The [LabeledStatement] or [WhileTrue] binding this label.
- JumpTarget binding;
-}
-
-/**
- * A local variable in the tree IR.
- *
- * All tree IR variables are mutable.
- *
- * To use a variable as an expression, reference it from a [VariableUse], with
- * one [VariableUse] per expression.
- *
- * [Variable]s are reference counted. The node constructors [VariableUse],
- * [Assign], [FunctionDefinition], and [Try] automatically update the reference
- * count for their variables, but when transforming the tree, the transformer
- * is responsible for updating reference counts.
- */
-class Variable extends Node {
- /// Function that declares this variable.
- ExecutableElement host;
-
- /// [Entity] used for synthesizing a name for the variable.
- /// Different variables may have the same entity. May be null.
- Entity element;
-
- /// Number of places where this variable occurs in a [VariableUse].
- int readCount = 0;
-
- /// Number of places where this variable occurs as:
- /// - left-hand of an [Assign]
- /// - parameter in a [FunctionDefinition]
- /// - catch parameter in a [Try]
- int writeCount = 0;
-
- /// True if an inner JS function might access this variable through a
- /// [ForeignCode] node.
- bool isCaptured = false;
-
- Variable(this.host, this.element) {
- assert(host != null);
- }
-
- String toString() =>
- element == null ? 'Variable.${hashCode}' : element.toString();
-}
-
-/// Read the value of a variable.
-class VariableUse extends Expression {
- Variable variable;
- SourceInformation sourceInformation;
-
- /// Creates a use of [variable] and updates its `readCount`.
- VariableUse(this.variable, {this.sourceInformation}) {
- variable.readCount++;
- }
-
- accept(ExpressionVisitor visitor) => visitor.visitVariableUse(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitVariableUse(this, arg);
- }
-}
-
-class Assign extends Expression {
- Variable variable;
- Expression value;
- SourceInformation sourceInformation;
-
- Assign(this.variable, this.value, {this.sourceInformation}) {
- variable.writeCount++;
- }
-
- accept(ExpressionVisitor v) => v.visitAssign(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitAssign(this, arg);
-
- static ExpressionStatement makeStatement(Variable variable, Expression value,
- [Statement next]) {
- return new ExpressionStatement(new Assign(variable, value), next);
- }
-}
-
-/**
- * Common interface for invocations with arguments.
- */
-abstract class Invoke {
- List<Expression> get arguments;
-}
-
-/**
- * A call to a static function or getter/setter to a static field.
- *
- * In contrast to the CPS-based IR, the arguments can be arbitrary expressions.
- */
-class InvokeStatic extends Expression implements Invoke {
- final Entity target;
- final List<Expression> arguments;
- final Selector selector;
- final SourceInformation sourceInformation;
-
- InvokeStatic(this.target, this.selector, this.arguments,
- [this.sourceInformation]);
-
- accept(ExpressionVisitor visitor) => visitor.visitInvokeStatic(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitInvokeStatic(this, arg);
- }
-}
-
-/**
- * A call to a method, operator, getter, setter or index getter/setter.
- *
- * If [receiver] is `null`, an error is thrown before the arguments are
- * evaluated. This corresponds to the JS evaluation order.
- */
-class InvokeMethod extends Expression implements Invoke {
- Expression receiver;
- final Selector selector;
- final TypeMask mask;
- final List<Expression> arguments;
- final SourceInformation sourceInformation;
-
- /// If true, it is known that the receiver cannot be `null`.
- bool receiverIsNotNull = false;
-
- InvokeMethod(this.receiver, this.selector, this.mask, this.arguments,
- this.sourceInformation) {
- assert(receiver != null);
- }
-
- accept(ExpressionVisitor visitor) => visitor.visitInvokeMethod(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitInvokeMethod(this, arg);
- }
-}
-
-/// Invoke [target] on [receiver], bypassing ordinary dispatch semantics.
-///
-/// Since the [receiver] is not used for method lookup, it may be `null`
-/// without an error being thrown.
-class InvokeMethodDirectly extends Expression implements Invoke {
- Expression receiver;
- final Element target;
- final Selector selector;
- final List<Expression> arguments;
- final SourceInformation sourceInformation;
-
- InvokeMethodDirectly(this.receiver, this.target, this.selector,
- this.arguments, this.sourceInformation);
-
- bool get isTearOff => selector.isGetter && !target.isGetter;
-
- accept(ExpressionVisitor visitor) => visitor.visitInvokeMethodDirectly(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitInvokeMethodDirectly(this, arg);
- }
-}
-
-/**
- * Call to a factory or generative constructor.
- */
-class InvokeConstructor extends Expression implements Invoke {
- final DartType type;
- final FunctionElement target;
- final List<Expression> arguments;
- final Selector selector;
- final SourceInformation sourceInformation;
-
- /// TODO(karlklose): get rid of this field. Instead use the constant's
- /// expression to find the constructor to be called in dart2dart.
- final values.ConstantValue constant;
-
- InvokeConstructor(this.type, this.target, this.selector, this.arguments,
- this.sourceInformation,
- [this.constant]);
-
- ClassElement get targetClass => target.enclosingElement;
-
- accept(ExpressionVisitor visitor) {
- return visitor.visitInvokeConstructor(this);
- }
-
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitInvokeConstructor(this, arg);
- }
-}
-
-/// Call a method using a one-shot interceptor.
-///
-/// There is no explicit receiver, the first argument serves that purpose.
-class OneShotInterceptor extends Expression implements Invoke {
- final Selector selector;
- final TypeMask mask;
- final List<Expression> arguments;
- final SourceInformation sourceInformation;
-
- OneShotInterceptor(
- this.selector, this.mask, this.arguments, this.sourceInformation);
-
- accept(ExpressionVisitor visitor) => visitor.visitOneShotInterceptor(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitOneShotInterceptor(this, arg);
- }
-}
-
-/**
- * A constant.
- */
-class Constant extends Expression {
- final values.ConstantValue value;
- final SourceInformation sourceInformation;
-
- Constant(this.value, {this.sourceInformation});
-
- Constant.bool(values.BoolConstantValue constantValue)
- : value = constantValue,
- sourceInformation = null;
-
- accept(ExpressionVisitor visitor) => visitor.visitConstant(this);
- accept1(ExpressionVisitor1 visitor, arg) => visitor.visitConstant(this, arg);
-
- String toString() => 'Constant(value=${value.toStructuredText()})';
-}
-
-class This extends Expression {
- accept(ExpressionVisitor visitor) => visitor.visitThis(this);
- accept1(ExpressionVisitor1 visitor, arg) => visitor.visitThis(this, arg);
-}
-
-class LiteralList extends Expression {
- final InterfaceType type;
- final List<Expression> values;
-
- LiteralList(this.type, this.values);
-
- accept(ExpressionVisitor visitor) => visitor.visitLiteralList(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitLiteralList(this, arg);
- }
-}
-
-/// Type test or type cast.
-///
-/// Note that if this is a type test, then [type] cannot be `Object`, `dynamic`,
-/// or the `Null` type. These cases are compiled to other node types.
-class TypeOperator extends Expression {
- Expression value;
- final DartType type;
- final List<Expression> typeArguments;
- final bool isTypeTest;
-
- TypeOperator(this.value, this.type, this.typeArguments,
- {bool this.isTypeTest});
-
- accept(ExpressionVisitor visitor) => visitor.visitTypeOperator(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitTypeOperator(this, arg);
- }
-
- String get operator => isTypeTest ? 'is' : 'as';
-}
-
-/**
- * Apply a built-in operator.
- *
- * It must be known that the arguments have the proper types.
- * Null is not a valid argument to any of the built-in operators.
- */
-class ApplyBuiltinOperator extends Expression {
- BuiltinOperator operator;
- List<Expression> arguments;
- SourceInformation sourceInformation;
-
- ApplyBuiltinOperator(this.operator, this.arguments, this.sourceInformation);
-
- accept(ExpressionVisitor visitor) {
- return visitor.visitApplyBuiltinOperator(this);
- }
-
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitApplyBuiltinOperator(this, arg);
- }
-}
-
-class ApplyBuiltinMethod extends Expression {
- BuiltinMethod method;
- Expression receiver;
- List<Expression> arguments;
-
- bool receiverIsNotNull;
-
- ApplyBuiltinMethod(this.method, this.receiver, this.arguments,
- {this.receiverIsNotNull: false});
-
- accept(ExpressionVisitor visitor) {
- return visitor.visitApplyBuiltinMethod(this);
- }
-
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitApplyBuiltinMethod(this, arg);
- }
-}
-
-/// A conditional expression.
-class Conditional extends Expression {
- Expression condition;
- Expression thenExpression;
- Expression elseExpression;
-
- Conditional(this.condition, this.thenExpression, this.elseExpression);
-
- accept(ExpressionVisitor visitor) => visitor.visitConditional(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitConditional(this, arg);
- }
-
- String toString() => 'Conditional(condition=$condition,thenExpression='
- '$thenExpression,elseExpression=$elseExpression)';
-}
-
-/// An && or || expression. The operator is internally represented as a boolean
-/// [isAnd] to simplify rewriting of logical operators.
-/// Note the result of && and || is one of the arguments, which might not be
-/// boolean. 'ShortCircuitOperator' might have been a better name.
-class LogicalOperator extends Expression {
- Expression left;
- bool isAnd;
- Expression right;
-
- LogicalOperator(this.left, this.right, this.isAnd);
- LogicalOperator.and(this.left, this.right) : isAnd = true;
- LogicalOperator.or(this.left, this.right) : isAnd = false;
-
- String get operator => isAnd ? '&&' : '||';
-
- accept(ExpressionVisitor visitor) => visitor.visitLogicalOperator(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitLogicalOperator(this, arg);
- }
-
- String toString() => 'LogicalOperator(left=$left,right=$right,isAnd=$isAnd)';
-}
-
-/// Logical negation.
-// TODO(asgerf): Replace this class with the IsFalsy builtin operator?
-// Right now the tree builder compiles IsFalsy to Not.
-class Not extends Expression {
- Expression operand;
-
- Not(this.operand);
-
- accept(ExpressionVisitor visitor) => visitor.visitNot(this);
- accept1(ExpressionVisitor1 visitor, arg) => visitor.visitNot(this, arg);
-}
-
-/// A [LabeledStatement] or [WhileTrue] or [For].
-abstract class JumpTarget extends Statement {
- Label get label;
- Statement get body;
-}
-
-/**
- * A labeled statement. Breaks to the label within the labeled statement
- * target the successor statement.
- */
-class LabeledStatement extends JumpTarget {
- Statement next;
- final Label label;
- Statement body;
-
- LabeledStatement(this.label, this.body, this.next) {
- assert(label.binding == null);
- label.binding = this;
- }
-
- accept(StatementVisitor visitor) => visitor.visitLabeledStatement(this);
- accept1(StatementVisitor1 visitor, arg) {
- return visitor.visitLabeledStatement(this, arg);
- }
-}
-
-/// A [WhileTrue] or [For] loop.
-abstract class Loop extends JumpTarget {}
-
-/**
- * A labeled while(true) loop.
- */
-class WhileTrue extends Loop {
- final Label label;
- Statement body;
-
- WhileTrue(this.label, this.body) {
- assert(label.binding == null);
- label.binding = this;
- }
-
- Statement get next => null;
- void set next(Statement s) => throw 'UNREACHABLE';
-
- accept(StatementVisitor visitor) => visitor.visitWhileTrue(this);
- accept1(StatementVisitor1 visitor, arg) => visitor.visitWhileTrue(this, arg);
-}
-
-/**
- * A loop with a condition and update expressions. If there are any update
- * expressions, this generates a for loop, otherwise a while loop.
- *
- * When the condition is false, control resumes at the [next] statement.
- *
- * It is NOT valid to target this statement with a [Break].
- * The only way to reach [next] is for the condition to evaluate to false.
- *
- * [For] statements are introduced in the [LoopRewriter] and are
- * assumed not to occur before then.
- */
-class For extends Loop {
- final Label label;
- Expression condition;
- List<Expression> updates;
- Statement body;
- Statement next;
-
- For(this.label, this.condition, this.updates, this.body, this.next) {
- assert(label.binding == null);
- label.binding = this;
- }
-
- accept(StatementVisitor visitor) => visitor.visitFor(this);
- accept1(StatementVisitor1 visitor, arg) {
- return visitor.visitFor(this, arg);
- }
-}
-
-/// A [Break] or [Continue] statement.
-abstract class Jump extends Statement {
- Label get target;
-}
-
-/**
- * A break from an enclosing [LabeledStatement]. The break targets the
- * labeled statement's successor statement.
- */
-class Break extends Jump {
- final Label target;
-
- Statement get next => null;
- void set next(Statement s) => throw 'UNREACHABLE';
-
- Break(this.target) {
- ++target.useCount;
- }
-
- accept(StatementVisitor visitor) => visitor.visitBreak(this);
- accept1(StatementVisitor1 visitor, arg) => visitor.visitBreak(this, arg);
-}
-
-/**
- * A continue to an enclosing [WhileTrue] or [For] loop.
- * The continue targets the loop's body.
- */
-class Continue extends Jump {
- final Label target;
-
- Statement get next => null;
- void set next(Statement s) => throw 'UNREACHABLE';
-
- Continue(this.target) {
- ++target.useCount;
- }
-
- accept(StatementVisitor visitor) => visitor.visitContinue(this);
- accept1(StatementVisitor1 visitor, arg) => visitor.visitContinue(this, arg);
-}
-
-/**
- * A return exit from the function.
- *
- * In contrast to the CPS-based IR, the return value is an arbitrary
- * expression.
- */
-class Return extends Statement {
- /// Should not be null. Use [Constant] with [NullConstantValue] for void
- /// returns.
- /// Even in constructors this holds true. Take special care when translating
- /// back to dart, where `return null;` in a constructor is an error.
- Expression value;
- SourceInformation sourceInformation;
-
- Statement get next => null;
- void set next(Statement s) => throw 'UNREACHABLE';
-
- Return(this.value, {this.sourceInformation});
-
- accept(StatementVisitor visitor) => visitor.visitReturn(this);
- accept1(StatementVisitor1 visitor, arg) => visitor.visitReturn(this, arg);
-}
-
-/// A throw statement.
-///
-/// In the Tree IR, throw is a statement (like JavaScript and unlike Dart).
-/// It does not have a successor statement.
-class Throw extends Statement {
- Expression value;
-
- Statement get next => null;
- void set next(Statement s) => throw 'UNREACHABLE';
-
- Throw(this.value);
-
- accept(StatementVisitor visitor) => visitor.visitThrow(this);
- accept1(StatementVisitor1 visitor, arg) => visitor.visitThrow(this, arg);
-}
-
-/**
- * A conditional branch based on the true value of an [Expression].
- */
-class If extends Statement {
- Expression condition;
- Statement thenStatement;
- Statement elseStatement;
- SourceInformation sourceInformation;
-
- Statement get next => null;
- void set next(Statement s) => throw 'UNREACHABLE';
-
- If(this.condition, this.thenStatement, this.elseStatement,
- this.sourceInformation);
-
- accept(StatementVisitor visitor) => visitor.visitIf(this);
- accept1(StatementVisitor1 visitor, arg) => visitor.visitIf(this, arg);
-}
-
-class ExpressionStatement extends Statement {
- Statement next;
- Expression expression;
-
- ExpressionStatement(this.expression, this.next);
-
- accept(StatementVisitor visitor) => visitor.visitExpressionStatement(this);
- accept1(StatementVisitor1 visitor, arg) {
- return visitor.visitExpressionStatement(this, arg);
- }
-}
-
-class Try extends Statement {
- Statement tryBody;
- List<Variable> catchParameters;
- Statement catchBody;
-
- Statement get next => null;
- void set next(Statement s) => throw 'UNREACHABLE';
-
- Try(this.tryBody, this.catchParameters, this.catchBody) {
- for (Variable variable in catchParameters) {
- variable.writeCount++; // Being a catch parameter counts as a write.
- }
- }
-
- accept(StatementVisitor visitor) => visitor.visitTry(this);
- accept1(StatementVisitor1 visitor, arg) {
- return visitor.visitTry(this, arg);
- }
-}
-
-/// A statement that is known to be unreachable.
-class Unreachable extends Statement {
- Statement get next => null;
- void set next(Statement value) => throw 'UNREACHABLE';
-
- accept(StatementVisitor visitor) => visitor.visitUnreachable(this);
- accept1(StatementVisitor1 visitor, arg) {
- return visitor.visitUnreachable(this, arg);
- }
-}
-
-class FunctionDefinition extends Node {
- final ExecutableElement element;
- final List<Variable> parameters;
- final SourceInformation sourceInformation;
- Statement body;
-
- /// Creates a function definition and updates `writeCount` for [parameters].
- FunctionDefinition(this.element, this.parameters, this.body,
- {this.sourceInformation}) {
- for (Variable param in parameters) {
- param.writeCount++; // Being a parameter counts as a write.
- }
- }
-}
-
-class CreateBox extends Expression {
- accept(ExpressionVisitor visitor) => visitor.visitCreateBox(this);
- accept1(ExpressionVisitor1 visitor, arg) => visitor.visitCreateBox(this, arg);
-}
-
-class CreateInstance extends Expression {
- ClassElement classElement;
- List<Expression> arguments;
- Expression typeInformation;
- SourceInformation sourceInformation;
-
- CreateInstance(this.classElement, this.arguments, this.typeInformation,
- this.sourceInformation);
-
- accept(ExpressionVisitor visitor) => visitor.visitCreateInstance(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitCreateInstance(this, arg);
- }
-}
-
-class GetField extends Expression {
- Expression object;
- Element field;
- bool objectIsNotNull;
- SourceInformation sourceInformation;
-
- GetField(this.object, this.field, this.sourceInformation,
- {this.objectIsNotNull: false});
-
- accept(ExpressionVisitor visitor) => visitor.visitGetField(this);
- accept1(ExpressionVisitor1 visitor, arg) => visitor.visitGetField(this, arg);
-}
-
-class SetField extends Expression {
- Expression object;
- Element field;
- Expression value;
- SourceInformation sourceInformation;
-
- /// If non-null, this is a compound assignment to the field, using the given
- /// operator. The operator must be a compoundable operator.
- BuiltinOperator compound;
-
- SetField(this.object, this.field, this.value, this.sourceInformation,
- {this.compound});
-
- accept(ExpressionVisitor visitor) => visitor.visitSetField(this);
- accept1(ExpressionVisitor1 visitor, arg) => visitor.visitSetField(this, arg);
-}
-
-/// Read the type test property from [object]. The value is truthy/fasly rather
-/// than bool. [object] must not be `null`.
-class GetTypeTestProperty extends Expression {
- Expression object;
- DartType dartType;
-
- GetTypeTestProperty(this.object, this.dartType);
-
- accept(ExpressionVisitor visitor) => visitor.visitGetTypeTestProperty(this);
- accept1(ExpressionVisitor1 visitor, arg) =>
- visitor.visitGetTypeTestProperty(this, arg);
-}
-
-/// Read the value of a field, possibly provoking its initializer to evaluate,
-/// or tear off a static method.
-class GetStatic extends Expression {
- Element element;
- SourceInformation sourceInformation;
- bool useLazyGetter = false;
-
- GetStatic(this.element, this.sourceInformation);
-
- GetStatic.lazy(this.element, this.sourceInformation) : useLazyGetter = true;
-
- accept(ExpressionVisitor visitor) => visitor.visitGetStatic(this);
- accept1(ExpressionVisitor1 visitor, arg) => visitor.visitGetStatic(this, arg);
-}
-
-class SetStatic extends Expression {
- Element element;
- Expression value;
- SourceInformation sourceInformation;
- BuiltinOperator compound;
-
- SetStatic(this.element, this.value, this.sourceInformation, {this.compound});
-
- accept(ExpressionVisitor visitor) => visitor.visitSetStatic(this);
- accept1(ExpressionVisitor1 visitor, arg) => visitor.visitSetStatic(this, arg);
-}
-
-class GetLength extends Expression {
- Expression object;
-
- GetLength(this.object);
-
- accept(ExpressionVisitor v) => v.visitGetLength(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitGetLength(this, arg);
-}
-
-class GetIndex extends Expression {
- Expression object;
- Expression index;
-
- GetIndex(this.object, this.index);
-
- accept(ExpressionVisitor v) => v.visitGetIndex(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitGetIndex(this, arg);
-}
-
-class SetIndex extends Expression {
- Expression object;
- Expression index;
- Expression value;
- BuiltinOperator compound;
-
- SetIndex(this.object, this.index, this.value, {this.compound});
-
- accept(ExpressionVisitor v) => v.visitSetIndex(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitSetIndex(this, arg);
-}
-
-class ReifyRuntimeType extends Expression {
- Expression value;
- SourceInformation sourceInformation;
-
- ReifyRuntimeType(this.value, this.sourceInformation);
-
- accept(ExpressionVisitor visitor) {
- return visitor.visitReifyRuntimeType(this);
- }
-
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitReifyRuntimeType(this, arg);
- }
-}
-
-class ReadTypeVariable extends Expression {
- final TypeVariableType variable;
- Expression target;
- final SourceInformation sourceInformation;
-
- ReadTypeVariable(this.variable, this.target, this.sourceInformation);
-
- accept(ExpressionVisitor visitor) {
- return visitor.visitReadTypeVariable(this);
- }
-
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitReadTypeVariable(this, arg);
- }
-}
-
-class CreateInvocationMirror extends Expression {
- final Selector selector;
- final List<Expression> arguments;
-
- CreateInvocationMirror(this.selector, this.arguments);
-
- accept(ExpressionVisitor visitor) {
- return visitor.visitCreateInvocationMirror(this);
- }
-
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitCreateInvocationMirror(this, arg);
- }
-}
-
-class Interceptor extends Expression {
- Expression input;
- Set<ClassElement> interceptedClasses;
- final SourceInformation sourceInformation;
-
- Interceptor(this.input, this.interceptedClasses, this.sourceInformation);
-
- accept(ExpressionVisitor visitor) {
- return visitor.visitInterceptor(this);
- }
-
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitInterceptor(this, arg);
- }
-}
-
-class ForeignCode extends Node {
- final js.Template codeTemplate;
- final types.TypeMask type;
- final List<Expression> arguments;
- final native.NativeBehavior nativeBehavior;
- final List<bool> nullableArguments; // One 'bit' per argument.
- final Element dependency;
- final SourceInformation sourceInformation;
-
- ForeignCode(this.codeTemplate, this.type, this.arguments, this.nativeBehavior,
- this.nullableArguments, this.dependency, this.sourceInformation) {
- assert(arguments.length == nullableArguments.length);
- }
-}
-
-class ForeignExpression extends ForeignCode implements Expression {
- ForeignExpression(
- js.Template codeTemplate,
- types.TypeMask type,
- List<Expression> arguments,
- native.NativeBehavior nativeBehavior,
- List<bool> nullableArguments,
- Element dependency,
- SourceInformation sourceInformation)
- : super(codeTemplate, type, arguments, nativeBehavior, nullableArguments,
- dependency, sourceInformation);
-
- accept(ExpressionVisitor visitor) {
- return visitor.visitForeignExpression(this);
- }
-
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitForeignExpression(this, arg);
- }
-}
-
-class ForeignStatement extends ForeignCode implements Statement {
- ForeignStatement(
- js.Template codeTemplate,
- types.TypeMask type,
- List<Expression> arguments,
- native.NativeBehavior nativeBehavior,
- List<bool> nullableArguments,
- Element dependency,
- SourceInformation sourceInformation)
- : super(codeTemplate, type, arguments, nativeBehavior, nullableArguments,
- dependency, sourceInformation);
-
- accept(StatementVisitor visitor) {
- return visitor.visitForeignStatement(this);
- }
-
- accept1(StatementVisitor1 visitor, arg) {
- return visitor.visitForeignStatement(this, arg);
- }
-
- @override
- Statement get next => null;
-
- @override
- void set next(Statement s) => throw 'UNREACHABLE';
-}
-
-/// Denotes the internal representation of [dartType], where all type variables
-/// are replaced by the values in [arguments].
-/// (See documentation on the TypeExpression CPS node for more details.)
-class TypeExpression extends Expression {
- final TypeExpressionKind kind;
- final DartType dartType;
- final List<Expression> arguments;
-
- TypeExpression(this.kind, this.dartType, this.arguments);
-
- accept(ExpressionVisitor visitor) {
- return visitor.visitTypeExpression(this);
- }
-
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitTypeExpression(this, arg);
- }
-}
-
-class Await extends Expression {
- Expression input;
-
- Await(this.input);
-
- accept(ExpressionVisitor visitor) {
- return visitor.visitAwait(this);
- }
-
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitAwait(this, arg);
- }
-}
-
-class Yield extends Statement {
- Statement next;
- Expression input;
- final bool hasStar;
-
- Yield(this.input, this.hasStar, this.next);
-
- accept(StatementVisitor visitor) {
- return visitor.visitYield(this);
- }
-
- accept1(StatementVisitor1 visitor, arg) {
- return visitor.visitYield(this, arg);
- }
-}
-
-class ReceiverCheck extends Statement {
- Expression condition;
- Expression value;
- Selector selector;
- bool useSelector;
- bool useInvoke;
- Statement next;
- SourceInformation sourceInformation;
-
- ReceiverCheck(
- {this.condition,
- this.value,
- this.selector,
- this.useSelector,
- this.useInvoke,
- this.next,
- this.sourceInformation});
-
- accept(StatementVisitor visitor) {
- return visitor.visitReceiverCheck(this);
- }
-
- accept1(StatementVisitor1 visitor, arg) {
- return visitor.visitReceiverCheck(this, arg);
- }
-}
-
-abstract class ExpressionVisitor<E> {
- E visitExpression(Expression node) => node.accept(this);
- E visitVariableUse(VariableUse node);
- E visitAssign(Assign node);
- E visitInvokeStatic(InvokeStatic node);
- E visitInvokeMethod(InvokeMethod node);
- E visitInvokeMethodDirectly(InvokeMethodDirectly node);
- E visitInvokeConstructor(InvokeConstructor node);
- E visitOneShotInterceptor(OneShotInterceptor node);
- E visitConstant(Constant node);
- E visitThis(This node);
- E visitConditional(Conditional node);
- E visitLogicalOperator(LogicalOperator node);
- E visitNot(Not node);
- E visitLiteralList(LiteralList node);
- E visitTypeOperator(TypeOperator node);
- E visitGetField(GetField node);
- E visitSetField(SetField node);
- E visitGetStatic(GetStatic node);
- E visitSetStatic(SetStatic node);
- E visitGetTypeTestProperty(GetTypeTestProperty node);
- E visitCreateBox(CreateBox node);
- E visitCreateInstance(CreateInstance node);
- E visitReifyRuntimeType(ReifyRuntimeType node);
- E visitReadTypeVariable(ReadTypeVariable node);
- E visitTypeExpression(TypeExpression node);
- E visitCreateInvocationMirror(CreateInvocationMirror node);
- E visitInterceptor(Interceptor node);
- E visitApplyBuiltinOperator(ApplyBuiltinOperator node);
- E visitApplyBuiltinMethod(ApplyBuiltinMethod node);
- E visitForeignExpression(ForeignExpression node);
- E visitGetLength(GetLength node);
- E visitGetIndex(GetIndex node);
- E visitSetIndex(SetIndex node);
- E visitAwait(Await node);
-}
-
-abstract class ExpressionVisitor1<E, A> {
- E visitExpression(Expression node, A arg) => node.accept1(this, arg);
- E visitVariableUse(VariableUse node, A arg);
- E visitAssign(Assign node, A arg);
- E visitInvokeStatic(InvokeStatic node, A arg);
- E visitInvokeMethod(InvokeMethod node, A arg);
- E visitInvokeMethodDirectly(InvokeMethodDirectly node, A arg);
- E visitInvokeConstructor(InvokeConstructor node, A arg);
- E visitOneShotInterceptor(OneShotInterceptor node, A arg);
- E visitConstant(Constant node, A arg);
- E visitThis(This node, A arg);
- E visitConditional(Conditional node, A arg);
- E visitLogicalOperator(LogicalOperator node, A arg);
- E visitNot(Not node, A arg);
- E visitLiteralList(LiteralList node, A arg);
- E visitTypeOperator(TypeOperator node, A arg);
- E visitGetField(GetField node, A arg);
- E visitSetField(SetField node, A arg);
- E visitGetStatic(GetStatic node, A arg);
- E visitSetStatic(SetStatic node, A arg);
- E visitGetTypeTestProperty(GetTypeTestProperty node, A arg);
- E visitCreateBox(CreateBox node, A arg);
- E visitCreateInstance(CreateInstance node, A arg);
- E visitReifyRuntimeType(ReifyRuntimeType node, A arg);
- E visitReadTypeVariable(ReadTypeVariable node, A arg);
- E visitTypeExpression(TypeExpression node, A arg);
- E visitCreateInvocationMirror(CreateInvocationMirror node, A arg);
- E visitInterceptor(Interceptor node, A arg);
- E visitApplyBuiltinOperator(ApplyBuiltinOperator node, A arg);
- E visitApplyBuiltinMethod(ApplyBuiltinMethod node, A arg);
- E visitForeignExpression(ForeignExpression node, A arg);
- E visitGetLength(GetLength node, A arg);
- E visitGetIndex(GetIndex node, A arg);
- E visitSetIndex(SetIndex node, A arg);
- E visitAwait(Await node, A arg);
-}
-
-abstract class StatementVisitor<S> {
- S visitStatement(Statement node) => node.accept(this);
- S visitLabeledStatement(LabeledStatement node);
- S visitReturn(Return node);
- S visitThrow(Throw node);
- S visitBreak(Break node);
- S visitContinue(Continue node);
- S visitIf(If node);
- S visitWhileTrue(WhileTrue node);
- S visitFor(For node);
- S visitExpressionStatement(ExpressionStatement node);
- S visitTry(Try node);
- S visitUnreachable(Unreachable node);
- S visitForeignStatement(ForeignStatement node);
- S visitYield(Yield node);
- S visitReceiverCheck(ReceiverCheck node);
-}
-
-abstract class StatementVisitor1<S, A> {
- S visitStatement(Statement node, A arg) => node.accept1(this, arg);
- S visitLabeledStatement(LabeledStatement node, A arg);
- S visitReturn(Return node, A arg);
- S visitThrow(Throw node, A arg);
- S visitBreak(Break node, A arg);
- S visitContinue(Continue node, A arg);
- S visitIf(If node, A arg);
- S visitWhileTrue(WhileTrue node, A arg);
- S visitFor(For node, A arg);
- S visitExpressionStatement(ExpressionStatement node, A arg);
- S visitTry(Try node, A arg);
- S visitUnreachable(Unreachable node, A arg);
- S visitForeignStatement(ForeignStatement node, A arg);
- S visitYield(Yield node, A arg);
- S visitReceiverCheck(ReceiverCheck node, A arg);
-}
-
-abstract class RecursiveVisitor implements StatementVisitor, ExpressionVisitor {
- visitExpression(Expression e) => e.accept(this);
- visitStatement(Statement s) => s.accept(this);
-
- visitVariable(Variable variable) {}
-
- visitVariableUse(VariableUse node) {
- visitVariable(node.variable);
- }
-
- visitAssign(Assign node) {
- visitVariable(node.variable);
- visitExpression(node.value);
- }
-
- visitInvokeStatic(InvokeStatic node) {
- node.arguments.forEach(visitExpression);
- }
-
- visitInvokeMethod(InvokeMethod node) {
- visitExpression(node.receiver);
- node.arguments.forEach(visitExpression);
- }
-
- visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- visitExpression(node.receiver);
- node.arguments.forEach(visitExpression);
- }
-
- visitInvokeConstructor(InvokeConstructor node) {
- node.arguments.forEach(visitExpression);
- }
-
- visitOneShotInterceptor(OneShotInterceptor node) {
- node.arguments.forEach(visitExpression);
- }
-
- visitConstant(Constant node) {}
-
- visitThis(This node) {}
-
- visitConditional(Conditional node) {
- visitExpression(node.condition);
- visitExpression(node.thenExpression);
- visitExpression(node.elseExpression);
- }
-
- visitLogicalOperator(LogicalOperator node) {
- visitExpression(node.left);
- visitExpression(node.right);
- }
-
- visitNot(Not node) {
- visitExpression(node.operand);
- }
-
- visitLiteralList(LiteralList node) {
- node.values.forEach(visitExpression);
- }
-
- visitTypeOperator(TypeOperator node) {
- visitExpression(node.value);
- node.typeArguments.forEach(visitExpression);
- }
-
- visitLabeledStatement(LabeledStatement node) {
- visitStatement(node.body);
- visitStatement(node.next);
- }
-
- visitReturn(Return node) {
- visitExpression(node.value);
- }
-
- visitThrow(Throw node) {
- visitExpression(node.value);
- }
-
- visitBreak(Break node) {}
-
- visitContinue(Continue node) {}
-
- visitIf(If node) {
- visitExpression(node.condition);
- visitStatement(node.thenStatement);
- visitStatement(node.elseStatement);
- }
-
- visitWhileTrue(WhileTrue node) {
- visitStatement(node.body);
- }
-
- visitFor(For node) {
- visitExpression(node.condition);
- node.updates.forEach(visitExpression);
- visitStatement(node.body);
- visitStatement(node.next);
- }
-
- visitExpressionStatement(ExpressionStatement inputNode) {
- // Iterate over chains of expression statements to avoid deep recursion.
- Statement node = inputNode;
- while (node is ExpressionStatement) {
- ExpressionStatement stmt = node;
- visitExpression(stmt.expression);
- node = stmt.next;
- }
- visitStatement(node);
- }
-
- visitTry(Try node) {
- visitStatement(node.tryBody);
- visitStatement(node.catchBody);
- }
-
- visitGetField(GetField node) {
- visitExpression(node.object);
- }
-
- visitSetField(SetField node) {
- visitExpression(node.object);
- visitExpression(node.value);
- }
-
- visitGetStatic(GetStatic node) {}
-
- visitSetStatic(SetStatic node) {
- visitExpression(node.value);
- }
-
- visitGetTypeTestProperty(GetTypeTestProperty node) {
- visitExpression(node.object);
- }
-
- visitCreateBox(CreateBox node) {}
-
- visitCreateInstance(CreateInstance node) {
- node.arguments.forEach(visitExpression);
- if (node.typeInformation != null) visitExpression(node.typeInformation);
- }
-
- visitReifyRuntimeType(ReifyRuntimeType node) {
- visitExpression(node.value);
- }
-
- visitReadTypeVariable(ReadTypeVariable node) {
- visitExpression(node.target);
- }
-
- visitTypeExpression(TypeExpression node) {
- node.arguments.forEach(visitExpression);
- }
-
- visitCreateInvocationMirror(CreateInvocationMirror node) {
- node.arguments.forEach(visitExpression);
- }
-
- visitUnreachable(Unreachable node) {}
-
- visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- node.arguments.forEach(visitExpression);
- }
-
- visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- visitExpression(node.receiver);
- node.arguments.forEach(visitExpression);
- }
-
- visitInterceptor(Interceptor node) {
- visitExpression(node.input);
- }
-
- visitForeignCode(ForeignCode node) {
- node.arguments.forEach(visitExpression);
- }
-
- visitForeignExpression(ForeignExpression node) => visitForeignCode(node);
- visitForeignStatement(ForeignStatement node) => visitForeignCode(node);
-
- visitGetLength(GetLength node) {
- visitExpression(node.object);
- }
-
- visitGetIndex(GetIndex node) {
- visitExpression(node.object);
- visitExpression(node.index);
- }
-
- visitSetIndex(SetIndex node) {
- visitExpression(node.object);
- visitExpression(node.index);
- visitExpression(node.value);
- }
-
- visitAwait(Await node) {
- visitExpression(node.input);
- }
-
- visitYield(Yield node) {
- visitExpression(node.input);
- visitStatement(node.next);
- }
-
- visitReceiverCheck(ReceiverCheck node) {
- if (node.condition != null) visitExpression(node.condition);
- visitExpression(node.value);
- visitStatement(node.next);
- }
-}
-
-abstract class Transformer
- implements ExpressionVisitor<Expression>, StatementVisitor<Statement> {
- Expression visitExpression(Expression e) => e.accept(this);
- Statement visitStatement(Statement s) => s.accept(this);
-}
-
-class RecursiveTransformer extends Transformer {
- void _replaceExpressions(List<Expression> list) {
- for (int i = 0; i < list.length; i++) {
- list[i] = visitExpression(list[i]);
- }
- }
-
- visitVariableUse(VariableUse node) => node;
-
- visitAssign(Assign node) {
- node.value = visitExpression(node.value);
- return node;
- }
-
- visitInvokeStatic(InvokeStatic node) {
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitInvokeMethod(InvokeMethod node) {
- node.receiver = visitExpression(node.receiver);
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- node.receiver = visitExpression(node.receiver);
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitInvokeConstructor(InvokeConstructor node) {
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitOneShotInterceptor(OneShotInterceptor node) {
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitConstant(Constant node) => node;
-
- visitThis(This node) => node;
-
- visitConditional(Conditional node) {
- node.condition = visitExpression(node.condition);
- node.thenExpression = visitExpression(node.thenExpression);
- node.elseExpression = visitExpression(node.elseExpression);
- return node;
- }
-
- visitLogicalOperator(LogicalOperator node) {
- node.left = visitExpression(node.left);
- node.right = visitExpression(node.right);
- return node;
- }
-
- visitNot(Not node) {
- node.operand = visitExpression(node.operand);
- return node;
- }
-
- visitLiteralList(LiteralList node) {
- _replaceExpressions(node.values);
- return node;
- }
-
- visitTypeOperator(TypeOperator node) {
- node.value = visitExpression(node.value);
- _replaceExpressions(node.typeArguments);
- return node;
- }
-
- visitLabeledStatement(LabeledStatement node) {
- node.body = visitStatement(node.body);
- node.next = visitStatement(node.next);
- return node;
- }
-
- visitReturn(Return node) {
- node.value = visitExpression(node.value);
- return node;
- }
-
- visitThrow(Throw node) {
- node.value = visitExpression(node.value);
- return node;
- }
-
- visitBreak(Break node) => node;
-
- visitContinue(Continue node) => node;
-
- visitIf(If node) {
- node.condition = visitExpression(node.condition);
- node.thenStatement = visitStatement(node.thenStatement);
- node.elseStatement = visitStatement(node.elseStatement);
- return node;
- }
-
- visitWhileTrue(WhileTrue node) {
- node.body = visitStatement(node.body);
- return node;
- }
-
- visitFor(For node) {
- node.condition = visitExpression(node.condition);
- _replaceExpressions(node.updates);
- node.body = visitStatement(node.body);
- node.next = visitStatement(node.next);
- return node;
- }
-
- visitExpressionStatement(ExpressionStatement node) {
- // Iterate over chains of expression statements to avoid deep recursion.
- Statement first = node;
- while (true) {
- node.expression = visitExpression(node.expression);
- if (node.next is ExpressionStatement) {
- node = node.next;
- } else {
- break;
- }
- }
- node.next = visitStatement(node.next);
- return first;
- }
-
- visitTry(Try node) {
- node.tryBody = visitStatement(node.tryBody);
- node.catchBody = visitStatement(node.catchBody);
- return node;
- }
-
- visitGetField(GetField node) {
- node.object = visitExpression(node.object);
- return node;
- }
-
- visitSetField(SetField node) {
- node.object = visitExpression(node.object);
- node.value = visitExpression(node.value);
- return node;
- }
-
- visitGetStatic(GetStatic node) => node;
-
- visitSetStatic(SetStatic node) {
- node.value = visitExpression(node.value);
- return node;
- }
-
- visitGetTypeTestProperty(GetTypeTestProperty node) {
- node.object = visitExpression(node.object);
- return node;
- }
-
- visitCreateBox(CreateBox node) => node;
-
- visitCreateInstance(CreateInstance node) {
- _replaceExpressions(node.arguments);
- if (node.typeInformation != null) {
- node.typeInformation = visitExpression(node.typeInformation);
- }
- return node;
- }
-
- visitReifyRuntimeType(ReifyRuntimeType node) {
- node.value = visitExpression(node.value);
- return node;
- }
-
- visitReadTypeVariable(ReadTypeVariable node) {
- node.target = visitExpression(node.target);
- return node;
- }
-
- visitTypeExpression(TypeExpression node) {
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitCreateInvocationMirror(CreateInvocationMirror node) {
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitForeignExpression(ForeignExpression node) {
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitForeignStatement(ForeignStatement node) {
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitUnreachable(Unreachable node) {
- return node;
- }
-
- visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- node.receiver = visitExpression(node.receiver);
- _replaceExpressions(node.arguments);
- return node;
- }
-
- visitInterceptor(Interceptor node) {
- node.input = visitExpression(node.input);
- return node;
- }
-
- visitGetLength(GetLength node) {
- node.object = visitExpression(node.object);
- return node;
- }
-
- visitGetIndex(GetIndex node) {
- node.object = visitExpression(node.object);
- node.index = visitExpression(node.index);
- return node;
- }
-
- visitSetIndex(SetIndex node) {
- node.object = visitExpression(node.object);
- node.index = visitExpression(node.index);
- node.value = visitExpression(node.value);
- return node;
- }
-
- visitAwait(Await node) {
- node.input = visitExpression(node.input);
- return node;
- }
-
- visitYield(Yield node) {
- node.input = visitExpression(node.input);
- node.next = visitStatement(node.next);
- return node;
- }
-
- visitReceiverCheck(ReceiverCheck node) {
- if (node.condition != null) {
- node.condition = visitExpression(node.condition);
- }
- node.value = visitExpression(node.value);
- node.next = visitStatement(node.next);
- return node;
- }
-}
-
-class FallthroughTarget {
- final Statement target;
- int useCount = 0;
-
- FallthroughTarget(this.target);
-}
-
-/// A stack machine for tracking fallthrough while traversing the Tree IR.
-class FallthroughStack {
- final List<FallthroughTarget> _stack = <FallthroughTarget>[
- new FallthroughTarget(null)
- ];
-
- /// Set a new fallthrough target.
- void push(Statement newFallthrough) {
- _stack.add(new FallthroughTarget(newFallthrough));
- }
-
- /// Remove the current fallthrough target.
- void pop() {
- _stack.removeLast();
- }
-
- /// The current fallthrough target, or `null` if control will fall over
- /// the end of the method.
- Statement get target => _stack.last.target;
-
- /// Number of uses of the current fallthrough target.
- int get useCount => _stack.last.useCount;
-
- /// Indicate that a statement will fall through to the current fallthrough
- /// target.
- void use() {
- ++_stack.last.useCount;
- }
-}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
deleted file mode 100644
index e93ae0c..0000000
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
+++ /dev/null
@@ -1,621 +0,0 @@
-// 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 tree_ir_tracer;
-
-import 'dart:async' show EventSink;
-
-import '../tracer.dart';
-import 'tree_ir_nodes.dart';
-
-class Block {
- Label label;
- int index;
-
- /// Mixed list of [Statement] and [Block].
- /// A [Block] represents a synthetic goto statement.
- final List statements = [];
- final List<Block> predecessors = <Block>[];
- final List<Block> successors = <Block>[];
-
- /// The catch block associated with the immediately enclosing try block or
- /// `null` if not inside a try block.
- Block catcher;
-
- /// True if this block is the entry point to one of the bodies
- /// (constructors can have multiple bodies).
- bool isEntryPoint = false;
-
- String get name => 'B$index';
-
- Block([this.label]);
-
- void addEdgeTo(Block successor) {
- successors.add(successor);
- successor.predecessors.add(this);
- }
-}
-
-class BlockCollector extends StatementVisitor {
- // Accumulate a list of blocks. The current block is the last block in
- // the list.
- final List<Block> blocks = [];
-
- // Map tree [Label]s (break or continue targets) and [Statement]s
- // (if targets) to blocks.
- final Map<Label, Block> breakTargets = <Label, Block>{};
- final Map<Label, Block> continueTargets = <Label, Block>{};
- final Map<Statement, Block> substatements = <Statement, Block>{};
-
- Block catcher;
-
- void _addStatement(Statement statement) {
- blocks.last.statements.add(statement);
- }
-
- void _addGotoStatement(Block target) {
- blocks.last.statements.add(target);
- }
-
- void _addBlock(Block block) {
- block.index = blocks.length;
- block.catcher = catcher;
- blocks.add(block);
- }
-
- void collect(FunctionDefinition node) {
- _addBlock(new Block()..isEntryPoint = true);
- visitStatement(node.body);
- }
-
- visitLabeledStatement(LabeledStatement node) {
- Block target = new Block(node.label);
- breakTargets[node.label] = target;
- visitStatement(node.body);
- _addBlock(target);
- visitStatement(node.next);
- }
-
- visitReturn(Return node) {
- _addStatement(node);
- }
-
- visitThrow(Throw node) {
- _addStatement(node);
- }
-
- visitUnreachable(Unreachable node) {
- _addStatement(node);
- }
-
- visitBreak(Break node) {
- _addStatement(node);
- if (breakTargets.containsKey(node.target)) {
- blocks.last.addEdgeTo(breakTargets[node.target]);
- }
- }
-
- visitContinue(Continue node) {
- _addStatement(node);
- blocks.last.addEdgeTo(continueTargets[node.target]);
- }
-
- visitIf(If node) {
- _addStatement(node);
- Block thenTarget = new Block();
- Block elseTarget = new Block();
- substatements[node.thenStatement] = thenTarget;
- substatements[node.elseStatement] = elseTarget;
- blocks.last.addEdgeTo(thenTarget);
- blocks.last.addEdgeTo(elseTarget);
- _addBlock(thenTarget);
- visitStatement(node.thenStatement);
- _addBlock(elseTarget);
- visitStatement(node.elseStatement);
- }
-
- visitWhileTrue(WhileTrue node) {
- Block continueTarget = new Block();
- _addGotoStatement(continueTarget);
-
- continueTargets[node.label] = continueTarget;
- blocks.last.addEdgeTo(continueTarget);
- _addBlock(continueTarget);
- _addStatement(node);
- visitStatement(node.body);
- }
-
- visitFor(For node) {
- Block whileBlock = new Block();
- _addGotoStatement(whileBlock);
-
- _addBlock(whileBlock);
- _addStatement(node);
- blocks.last.addEdgeTo(whileBlock);
-
- Block bodyBlock = new Block();
- Block nextBlock = new Block();
- whileBlock.addEdgeTo(bodyBlock);
- whileBlock.addEdgeTo(nextBlock);
-
- continueTargets[node.label] = bodyBlock;
- _addBlock(bodyBlock);
- visitStatement(node.body);
-
- _addBlock(nextBlock);
- visitStatement(node.next);
-
- substatements[node.body] = bodyBlock;
- substatements[node.next] = nextBlock;
- }
-
- visitTry(Try node) {
- _addStatement(node);
- Block tryBlock = new Block();
- Block catchBlock = new Block();
-
- Block oldCatcher = catcher;
- catcher = catchBlock;
- _addBlock(tryBlock);
- visitStatement(node.tryBody);
- catcher = oldCatcher;
-
- _addBlock(catchBlock);
- visitStatement(node.catchBody);
-
- substatements[node.tryBody] = tryBlock;
- substatements[node.catchBody] = catchBlock;
- }
-
- visitExpressionStatement(ExpressionStatement node) {
- _addStatement(node);
- visitStatement(node.next);
- }
-
- visitForeignStatement(ForeignStatement node) {
- _addStatement(node);
- }
-
- visitYield(Yield node) {
- _addStatement(node);
- visitStatement(node.next);
- }
-
- visitReceiverCheck(ReceiverCheck node) {
- _addStatement(node);
- visitStatement(node.next);
- }
-}
-
-class TreeTracer extends TracerUtil with StatementVisitor {
- String get passName => null;
-
- final EventSink<String> output;
-
- TreeTracer(this.output);
-
- List<Variable> parameters;
- Names names;
- BlockCollector collector;
- int statementCounter;
-
- void traceGraph(String name, FunctionDefinition node) {
- parameters = node.parameters;
- tag("cfg", () {
- printProperty("name", name);
- names = new Names();
- statementCounter = 0;
- collector = new BlockCollector();
- collector.collect(node);
- collector.blocks.forEach(printBlock);
- });
- }
-
- void printBlock(Block block) {
- tag("block", () {
- printProperty("name", block.name);
- printProperty("from_bci", -1);
- printProperty("to_bci", -1);
- printProperty("predecessors", block.predecessors.map((b) => b.name));
- printProperty("successors", block.successors.map((b) => b.name));
- printEmptyProperty("xhandlers");
- printEmptyProperty("flags");
- tag("states", () {
- tag("locals", () {
- printProperty("size", 0);
- printProperty("method", "None");
- });
- });
- tag("HIR", () {
- if (block.isEntryPoint) {
- String params = parameters.map(names.varName).join(', ');
- printStatement(null, 'Entry ($params)');
- }
- if (block.label != null) {
- printStatement(
- null, "Label ${block.name}, useCount=${block.label.useCount}");
- }
- if (block.catcher != null) {
- printStatement(null, 'Catch exceptions at ${block.catcher.name}');
- }
- block.statements.forEach(visitBlockMember);
- });
- });
- }
-
- void visitBlockMember(member) {
- if (member is Block) {
- printStatement(null, "goto block B${member.name}");
- } else {
- assert(member is Statement);
- visitStatement(member);
- }
- }
-
- void printStatement(String name, String contents) {
- int bci = 0;
- int uses = 0;
- if (name == null) {
- name = 'x${statementCounter++}';
- }
- addIndent();
- add("$bci $uses $name $contents <|@\n");
- }
-
- visitLabeledStatement(LabeledStatement node) {
- // These do not get added to a block's list of statements.
- }
-
- visitReturn(Return node) {
- printStatement(null, "return ${expr(node.value)}");
- }
-
- visitThrow(Throw node) {
- printStatement(null, "throw ${expr(node.value)}");
- }
-
- visitUnreachable(Unreachable node) {
- printStatement(null, "unreachable");
- }
-
- visitBreak(Break node) {
- Block block = collector.breakTargets[node.target];
- String name = block != null ? block.name : '<missing label>';
- printStatement(null, "break $name");
- }
-
- visitContinue(Continue node) {
- printStatement(
- null, "continue ${collector.continueTargets[node.target].name}");
- }
-
- visitIf(If node) {
- String condition = expr(node.condition);
- String thenTarget = collector.substatements[node.thenStatement].name;
- String elseTarget = collector.substatements[node.elseStatement].name;
- printStatement(null, "if $condition then $thenTarget else $elseTarget");
- }
-
- visitWhileTrue(WhileTrue node) {
- printStatement(null, "while true do");
- }
-
- visitFor(For node) {
- String bodyTarget = collector.substatements[node.body].name;
- String nextTarget = collector.substatements[node.next].name;
- String updates = node.updates.map(expr).join(', ');
- printStatement(null, "while ${expr(node.condition)}");
- printStatement(null, "do $bodyTarget");
- printStatement(null, "updates ($updates)");
- printStatement(null, "then $nextTarget");
- }
-
- visitTry(Try node) {
- String tryTarget = collector.substatements[node.tryBody].name;
- String catchParams = node.catchParameters.map(names.varName).join(',');
- String catchTarget = collector.substatements[node.catchBody].name;
- printStatement(null, 'try $tryTarget catch($catchParams) $catchTarget');
- }
-
- visitExpressionStatement(ExpressionStatement node) {
- printStatement(null, expr(node.expression));
- }
-
- visitSetField(SetField node) {
- String object = expr(node.object);
- String field = node.field.name;
- String value = expr(node.value);
- if (SubexpressionVisitor.usesInfixNotation(node.object)) {
- object = '($object)';
- }
- printStatement(null, '$object.$field = $value');
- }
-
- String expr(Expression e) {
- return e.accept(new SubexpressionVisitor(names));
- }
-
- @override
- visitForeignStatement(ForeignStatement node) {
- printStatement(null, 'foreign ${node.codeTemplate.source}');
- }
-
- @override
- visitYield(Yield node) {
- String name = node.hasStar ? 'yield*' : 'yield';
- printStatement(null, '$name ${expr(node.input)}');
- }
-
- @override
- visitReceiverCheck(ReceiverCheck node) {
- printStatement(null, 'NullCheck ${expr(node.value)}');
- }
-}
-
-class SubexpressionVisitor extends ExpressionVisitor<String> {
- Names names;
-
- SubexpressionVisitor(this.names);
-
- String visitVariableUse(VariableUse node) {
- return names.varName(node.variable);
- }
-
- String visitAssign(Assign node) {
- String variable = names.varName(node.variable);
- String value = visitExpression(node.value);
- return '$variable = $value';
- }
-
- String formatArguments(Invoke node) {
- return node.arguments.map(visitExpression).join(', ');
- }
-
- String visitInvokeStatic(InvokeStatic node) {
- String head = node.target.name;
- String args = formatArguments(node);
- return "$head($args)";
- }
-
- String visitInvokeMethod(InvokeMethod node) {
- String receiver = node.receiver.accept(this);
- String name = node.selector.name;
- String args = formatArguments(node);
- return "$receiver.$name($args)";
- }
-
- String visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- String receiver = visitExpression(node.receiver);
- String host = node.target.enclosingClass.name;
- String name = node.selector.name;
- String args = formatArguments(node);
- return "$receiver.$host::$name($args)";
- }
-
- String visitInvokeConstructor(InvokeConstructor node) {
- String className = node.target.enclosingClass.name;
- String callName;
- if (node.target.name.isEmpty) {
- callName = '${className}';
- } else {
- callName = '${className}.${node.target.name}';
- }
- String args = formatArguments(node);
- String keyword = node.constant != null ? 'const' : 'new';
- return "$keyword $callName($args)";
- }
-
- String visitOneShotInterceptor(OneShotInterceptor node) {
- String name = node.selector.name;
- String args = formatArguments(node);
- return "oneshot $name($args)";
- }
-
- String visitLiteralList(LiteralList node) {
- String values = node.values.map(visitExpression).join(', ');
- return "list [$values]";
- }
-
- String visitConstant(Constant node) {
- return "${node.value.toStructuredText()}";
- }
-
- String visitThis(This node) {
- return "this";
- }
-
- static bool usesInfixNotation(Expression node) {
- return node is Conditional ||
- node is LogicalOperator ||
- node is Assign ||
- node is SetField;
- }
-
- String visitConditional(Conditional node) {
- String condition = visitExpression(node.condition);
- String thenExpr = visitExpression(node.thenExpression);
- String elseExpr = visitExpression(node.elseExpression);
- return "$condition ? $thenExpr : $elseExpr";
- }
-
- String visitLogicalOperator(LogicalOperator node) {
- String left = visitExpression(node.left);
- String right = visitExpression(node.right);
- if (usesInfixNotation(node.left)) {
- left = "($left)";
- }
- if (usesInfixNotation(node.right)) {
- right = "($right)";
- }
- return "$left ${node.operator} $right";
- }
-
- String visitTypeOperator(TypeOperator node) {
- String value = visitExpression(node.value);
- String type = "${node.type}";
- return "TypeOperator $value ${node.operator} $type";
- }
-
- String visitNot(Not node) {
- String operand = visitExpression(node.operand);
- if (usesInfixNotation(node.operand)) {
- operand = '($operand)';
- }
- return '!$operand';
- }
-
- String visitGetField(GetField node) {
- String object = visitExpression(node.object);
- String field = node.field.name;
- if (usesInfixNotation(node.object)) {
- object = '($object)';
- }
- return '$object.$field';
- }
-
- String visitSetField(SetField node) {
- String object = visitExpression(node.object);
- String field = node.field.name;
- if (usesInfixNotation(node.object)) {
- object = '($object)';
- }
- String value = visitExpression(node.value);
- return '$object.$field = $value';
- }
-
- String visitGetStatic(GetStatic node) {
- String element = node.element.name;
- return element;
- }
-
- String visitSetStatic(SetStatic node) {
- String element = node.element.name;
- String value = visitExpression(node.value);
- return '$element = $value';
- }
-
- String visitGetTypeTestProperty(GetTypeTestProperty node) {
- String object = visitExpression(node.object);
- if (usesInfixNotation(node.object)) {
- object = '($object)';
- }
- // TODO(sra): Fix up this.
- return '$object."is-${node.dartType}"';
- }
-
- String visitCreateBox(CreateBox node) {
- return 'CreateBox';
- }
-
- String visitCreateInstance(CreateInstance node) {
- String className = node.classElement.name;
- String arguments = node.arguments.map(visitExpression).join(', ');
- return 'CreateInstance $className($arguments)';
- }
-
- @override
- String visitReadTypeVariable(ReadTypeVariable node) {
- return 'Read ${node.variable.element} ${visitExpression(node.target)}';
- }
-
- @override
- String visitReifyRuntimeType(ReifyRuntimeType node) {
- return 'Reify ${node.value}';
- }
-
- @override
- String visitTypeExpression(TypeExpression node) {
- String kind = '${node.kind}'.split('.').last;
- String args = node.arguments.map(visitExpression).join(', ');
- return 'TypeExpression($kind, ${node.dartType}, $args)';
- }
-
- @override
- String visitCreateInvocationMirror(CreateInvocationMirror node) {
- String args = node.arguments.map(visitExpression).join(', ');
- return 'CreateInvocationMirror(${node.selector.name}, $args)';
- }
-
- @override
- String visitInterceptor(Interceptor node) {
- return 'Interceptor(${visitExpression(node.input)})';
- }
-
- @override
- String visitForeignExpression(ForeignExpression node) {
- String arguments = node.arguments.map(visitExpression).join(', ');
- return 'Foreign "${node.codeTemplate.source}"($arguments)';
- }
-
- @override
- String visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- String args = node.arguments.map(visitExpression).join(', ');
- return 'ApplyBuiltinOperator ${node.operator} ($args)';
- }
-
- @override
- String visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- String receiver = visitExpression(node.receiver);
- String args = node.arguments.map(visitExpression).join(', ');
- return 'ApplyBuiltinMethod ${node.method} $receiver ($args)';
- }
-
- @override
- String visitGetLength(GetLength node) {
- String object = visitExpression(node.object);
- return 'GetLength($object)';
- }
-
- @override
- String visitGetIndex(GetIndex node) {
- String object = visitExpression(node.object);
- String index = visitExpression(node.index);
- return 'GetIndex($object, $index)';
- }
-
- @override
- String visitSetIndex(SetIndex node) {
- String object = visitExpression(node.object);
- String index = visitExpression(node.index);
- String value = visitExpression(node.value);
- return 'SetIndex($object, $index, $value)';
- }
-
- @override
- String visitAwait(Await node) {
- String value = visitExpression(node.input);
- return 'Await($value)';
- }
-
- String visitYield(Yield node) {
- String value = visitExpression(node.input);
- return 'Yield($value)';
- }
-}
-
-/**
- * Invents (and remembers) names for Variables that do not have an associated
- * identifier.
- *
- * In case a variable is named v0, v1, etc, it may be assigned a different
- * name to avoid clashing with a previously synthesized variable name.
- */
-class Names {
- final Map<Variable, String> _names = {};
- final Set<String> _usedNames = new Set();
- int _counter = 0;
-
- String varName(Variable v) {
- String name = _names[v];
- if (name == null) {
- String prefix = v.element == null ? 'v' : '${v.element.name}_';
- while (name == null || _usedNames.contains(name)) {
- name = "$prefix${_counter++}";
- }
- _names[v] = name;
- _usedNames.add(name);
- }
- return name;
- }
-}
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index b4ad1f8..17f9c68 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -815,6 +815,7 @@
foundPrivateMember = true;
}
}
+
// TODO(johnniwinther): Avoid computation of all class members.
MembersCreator.computeAllClassMembers(resolution, interface.element);
if (lookupClassMember) {
diff --git a/pkg/compiler/lib/src/types/union_type_mask.dart b/pkg/compiler/lib/src/types/union_type_mask.dart
index f05880a..5a191db 100644
--- a/pkg/compiler/lib/src/types/union_type_mask.dart
+++ b/pkg/compiler/lib/src/types/union_type_mask.dart
@@ -253,6 +253,7 @@
return other.containsMask(maskDisregardNull, classWorld);
});
}
+
return disjointMasks.every((FlatTypeMask disjointMask) {
bool contained = containedInAnyOf(disjointMask, union.disjointMasks);
if (PERFORM_EXTRA_CONTAINS_CHECK &&
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
index 4a7a035..be69cc2 100644
--- a/pkg/compiler/lib/src/universe/class_set.dart
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -214,6 +214,7 @@
IterationStep wrapper(ClassElement cls) {
return predicate(cls) ? IterationStep.STOP : IterationStep.CONTINUE;
}
+
return forEachSubclass(wrapper, mask, strict: strict) == IterationStep.STOP;
}
@@ -547,6 +548,7 @@
IterationStep wrapper(ClassElement cls) {
return predicate(cls) ? IterationStep.STOP : IterationStep.CONTINUE;
}
+
return forEachSubtype(wrapper, mask, strict: strict) == IterationStep.STOP;
}
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index 468fae3..5e0b379 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -16,8 +16,6 @@
import 'constants/evaluation.dart' as constants;
import 'constants/expressions.dart' as constants;
import 'constants/values.dart' as constants;
-import 'cps_ir/cps_ir_builder.dart' as ir_builder;
-import 'cps_ir/cps_ir_builder_task.dart' as ir_builder;
import 'dart2js.dart' as dart2js;
import 'dart_types.dart' as dart_types;
import 'deferred_load.dart' as deferred;
@@ -42,7 +40,6 @@
import 'source_file_provider.dart' as source_file_provider;
import 'ssa/nodes.dart' as ssa;
import 'tree/tree.dart' as tree;
-import 'tree_ir/tree_ir_nodes.dart' as tree_ir;
import 'util/util.dart' as util;
import 'world.dart';
@@ -71,14 +68,12 @@
useIo();
usedByTests();
useElements();
- useIr(null);
useCompiler(null);
useTypes();
useCodeEmitterTask(null);
useScript(null);
useProgramBuilder(null);
useSemanticVisitor();
- useTreeVisitors();
useDeferred();
}
@@ -283,10 +278,6 @@
l.forEachImport(null);
}
-useIr(ir_builder.IrBuilder builder) {
- builder..buildStringConstant(null);
-}
-
useCompiler(compiler.Compiler c) {
c.libraryLoader
..reset()
@@ -322,16 +313,6 @@
new semantic_visitor.BulkDeclarationVisitor().apply(null, null);
}
-class TreeVisitor1 extends tree_ir.ExpressionVisitor1
- with tree_ir.StatementVisitor1 {
- noSuchMethod(inv) {}
-}
-
-useTreeVisitors() {
- new TreeVisitor1().visitExpression(null, null);
- new TreeVisitor1().visitStatement(null, null);
-}
-
useDeferred([deferred.DeferredLoadTask task]) {
task.dump();
}
diff --git a/pkg/compiler/lib/src/util/enumset.dart b/pkg/compiler/lib/src/util/enumset.dart
index 7d2f600..ab4dcc86 100644
--- a/pkg/compiler/lib/src/util/enumset.dart
+++ b/pkg/compiler/lib/src/util/enumset.dart
@@ -131,6 +131,7 @@
value |= 1 << (enumValue as dynamic).index;
}
}
+
values.forEach(add);
return new _ConstEnumSet(value);
}
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 5bb3f52..96ea689 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -425,7 +425,8 @@
} while (iterator.moveNext());
List<ClassElement> commonSupertypes = <ClassElement>[];
- OUTER: for (Link<DartType> link = typeSet[depth];
+ OUTER:
+ for (Link<DartType> link = typeSet[depth];
link.head.element != objectClass;
link = link.tail) {
ClassElement cls = link.head.element;
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index 99a3924..a9424f9 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -97,6 +97,18 @@
/// corresponding to a named parameter that has this annotation.
const Required required = const Required();
+/// Used to annotate a declaration was made public, so that it is more visible
+/// than otherwise necessary, to make code testable.
+///
+/// Tools, such as the analyzer, can provide feedback if
+///
+/// * the annotation is associated with a declaration not in the `lib` folder
+/// of a package;
+/// or
+/// * the declaration is referenced outside of its the defining library or a
+/// library which is in the `test` folder of the defining package.
+const _VisibleForTesting visibleForTesting = const _VisibleForTesting();
+
/// Used to annotate a named parameter `p` in a method or function `f`.
///
/// See [required] for more details.
@@ -135,3 +147,7 @@
class _Protected {
const _Protected();
}
+
+class _VisibleForTesting {
+ const _VisibleForTesting();
+}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 9e10464..a22b9e1 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -70,9 +70,6 @@
# Unexplained errors only occuring on Safari 6.1 and earlier.
typed_data/test/typed_buffers_test: RuntimeError
-[ $compiler == dart2analyzer ]
-compiler/samples/compile_loop/compile_loop: CompileTimeError # Issue 16524
-
[ $compiler == dart2js && $csp ]
# This test cannot run under CSP because it is injecting a JavaScript polyfill
mutation_observer: Skip
diff --git a/runtime/bin/common_patch.dart b/runtime/bin/common_patch.dart
index aa6e1aa..b485dc9a 100644
--- a/runtime/bin/common_patch.dart
+++ b/runtime/bin/common_patch.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
@patch class _IOCrypto {
- /* @patch */ static Uint8List getRandomBytes(int count)
+ @patch static Uint8List getRandomBytes(int count)
native "Crypto_GetRandomBytes";
}
diff --git a/runtime/bin/directory_patch.dart b/runtime/bin/directory_patch.dart
index c503161..2518283 100644
--- a/runtime/bin/directory_patch.dart
+++ b/runtime/bin/directory_patch.dart
@@ -3,24 +3,24 @@
// BSD-style license that can be found in the LICENSE file.
@patch class _Directory {
- /* @patch */ static _current() native "Directory_Current";
- /* @patch */ static _setCurrent(path) native "Directory_SetCurrent";
- /* @patch */ static _createTemp(String path) native "Directory_CreateTemp";
- /* @patch */ static String _systemTemp() native "Directory_SystemTemp";
- /* @patch */ static _exists(String path) native "Directory_Exists";
- /* @patch */ static _create(String path) native "Directory_Create";
- /* @patch */ static _deleteNative(String path, bool recursive)
+ @patch static _current() native "Directory_Current";
+ @patch static _setCurrent(path) native "Directory_SetCurrent";
+ @patch static _createTemp(String path) native "Directory_CreateTemp";
+ @patch static String _systemTemp() native "Directory_SystemTemp";
+ @patch static _exists(String path) native "Directory_Exists";
+ @patch static _create(String path) native "Directory_Create";
+ @patch static _deleteNative(String path, bool recursive)
native "Directory_Delete";
- /* @patch */ static _rename(String path, String newPath)
+ @patch static _rename(String path, String newPath)
native "Directory_Rename";
- /* @patch */ static void _fillWithDirectoryListing(
+ @patch static void _fillWithDirectoryListing(
List<FileSystemEntity> list, String path, bool recursive,
bool followLinks)
native "Directory_FillWithDirectoryListing";
}
@patch class _AsyncDirectoryListerOps {
- /* @patch */ factory _AsyncDirectoryListerOps(int pointer) =>
+ @patch factory _AsyncDirectoryListerOps(int pointer) =>
new _AsyncDirectoryListerOpsImpl(pointer);
}
diff --git a/runtime/bin/eventhandler.h b/runtime/bin/eventhandler.h
index ab5b590..44b5ec8 100644
--- a/runtime/bin/eventhandler.h
+++ b/runtime/bin/eventhandler.h
@@ -132,6 +132,8 @@
public:
CircularLinkedList() : head_(NULL) {}
+ typedef void (*ClearFun) (void* value);
+
// Returns true if the list was empty.
bool Add(T t) {
Entry* e = new Entry(t);
@@ -151,7 +153,7 @@
}
}
- void RemoveHead() {
+ void RemoveHead(ClearFun clear = NULL) {
ASSERT(head_ != NULL);
Entry* e = head_;
@@ -162,6 +164,9 @@
e->next_->prev_ = e->prev_;
head_ = e->next_;
}
+ if (clear != NULL) {
+ clear(reinterpret_cast<void*>(e->t));
+ }
delete e;
}
@@ -195,9 +200,9 @@
}
}
- void RemoveAll() {
+ void RemoveAll(ClearFun clear = NULL) {
while (HasHead()) {
- RemoveHead();
+ RemoveHead(clear);
}
}
@@ -413,7 +418,9 @@
: DI(fd), tokens_map_(&SamePortValue, kTokenCount),
disable_tokens_(disable_tokens) {}
- virtual ~DescriptorInfoMultipleMixin() {}
+ virtual ~DescriptorInfoMultipleMixin() {
+ RemoveAllPorts();
+ }
virtual bool IsListeningSocket() const { return true; }
@@ -497,14 +504,16 @@
}
virtual void RemoveAllPorts() {
- active_readers_.RemoveAll();
for (HashMap::Entry *entry = tokens_map_.Start();
entry != NULL;
entry = tokens_map_.Next(entry)) {
PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value);
+ entry->value = NULL;
+ active_readers_.Remove(pentry);
delete pentry;
}
tokens_map_.Clear();
+ active_readers_.RemoveAll(DeletePortEntry);
}
virtual Dart_Port NextNotifyDartPort(intptr_t events_ready) {
@@ -585,6 +594,11 @@
}
private:
+ static void DeletePortEntry(void* data) {
+ PortEntry* entry = reinterpret_cast<PortEntry*>(data);
+ delete entry;
+ }
+
// The [Dart_Port]s which are not paused (i.e. are interested in read events,
// i.e. `mask == (1 << kInEvent)`) and we have enough tokens to communicate
// with them.
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index 1b7bbdb..c298a04 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -118,7 +118,15 @@
}
+static void DeleteDescriptorInfo(void* info) {
+ DescriptorInfo* di = reinterpret_cast<DescriptorInfo*>(info);
+ di->Close();
+ delete di;
+}
+
+
EventHandlerImplementation::~EventHandlerImplementation() {
+ socket_map_.Clear(DeleteDescriptorInfo);
VOID_TEMP_FAILURE_RETRY(close(epoll_fd_));
VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[0]));
VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[1]));
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 59cbdcd..bd61e80 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -127,7 +127,15 @@
}
+static void DeleteDescriptorInfo(void* info) {
+ DescriptorInfo* di = reinterpret_cast<DescriptorInfo*>(info);
+ di->Close();
+ delete di;
+}
+
+
EventHandlerImplementation::~EventHandlerImplementation() {
+ socket_map_.Clear(DeleteDescriptorInfo);
VOID_TEMP_FAILURE_RETRY(close(epoll_fd_));
VOID_TEMP_FAILURE_RETRY(close(timer_fd_));
VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[0]));
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index c2b7833..b55ea8e 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -140,7 +140,15 @@
}
+static void DeleteDescriptorInfo(void* info) {
+ DescriptorInfo* di = reinterpret_cast<DescriptorInfo*>(info);
+ di->Close();
+ delete di;
+}
+
+
EventHandlerImplementation::~EventHandlerImplementation() {
+ socket_map_.Clear(DeleteDescriptorInfo);
VOID_TEMP_FAILURE_RETRY(close(kqueue_fd_));
VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[0]));
VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[1]));
diff --git a/runtime/bin/eventhandler_patch.dart b/runtime/bin/eventhandler_patch.dart
index 60be5e5..effe402 100644
--- a/runtime/bin/eventhandler_patch.dart
+++ b/runtime/bin/eventhandler_patch.dart
@@ -5,7 +5,7 @@
import 'dart:nativewrappers';
@patch class _EventHandler {
- /* @patch */ static void _sendData(Object sender,
+ @patch static void _sendData(Object sender,
SendPort sendPort,
int data)
native "EventHandler_SendData";
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 8795b9c..2fe1414 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -3,27 +3,27 @@
// BSD-style license that can be found in the LICENSE file.
@patch class _File {
- /* @patch */ static _exists(String path) native "File_Exists";
- /* @patch */ static _create(String path) native "File_Create";
- /* @patch */ static _createLink(String path, String target)
+ @patch static _exists(String path) native "File_Exists";
+ @patch static _create(String path) native "File_Create";
+ @patch static _createLink(String path, String target)
native "File_CreateLink";
- /* @patch */ static _linkTarget(String path) native "File_LinkTarget";
- /* @patch */ static _deleteNative(String path) native "File_Delete";
- /* @patch */ static _deleteLinkNative(String path) native "File_DeleteLink";
- /* @patch */ static _rename(String oldPath, String newPath)
+ @patch static _linkTarget(String path) native "File_LinkTarget";
+ @patch static _deleteNative(String path) native "File_Delete";
+ @patch static _deleteLinkNative(String path) native "File_DeleteLink";
+ @patch static _rename(String oldPath, String newPath)
native "File_Rename";
- /* @patch */ static _renameLink(String oldPath, String newPath)
+ @patch static _renameLink(String oldPath, String newPath)
native "File_RenameLink";
- /* @patch */ static _copy(String oldPath, String newPath) native "File_Copy";
- /* @patch */ static _lengthFromPath(String path) native "File_LengthFromPath";
- /* @patch */ static _lastModified(String path) native "File_LastModified";
- /* @patch */ static _open(String path, int mode) native "File_Open";
- /* @patch */ static int _openStdio(int fd) native "File_OpenStdio";
+ @patch static _copy(String oldPath, String newPath) native "File_Copy";
+ @patch static _lengthFromPath(String path) native "File_LengthFromPath";
+ @patch static _lastModified(String path) native "File_LastModified";
+ @patch static _open(String path, int mode) native "File_Open";
+ @patch static int _openStdio(int fd) native "File_OpenStdio";
}
@patch class _RandomAccessFileOps {
- /* @patch */ factory _RandomAccessFileOps(int pointer)
+ @patch factory _RandomAccessFileOps(int pointer)
=> new _RandomAccessFileOpsImpl(pointer);
}
@@ -74,7 +74,7 @@
StreamController _broadcastController;
- /* @patch */ static Stream<FileSystemEvent> _watch(
+ @patch static Stream<FileSystemEvent> _watch(
String path, int events, bool recursive) {
if (Platform.isLinux) {
return new _InotifyFileSystemWatcher(path, events, recursive).stream;
@@ -262,7 +262,7 @@
});
}
- /* @patch */ static bool get isSupported
+ @patch static bool get isSupported
native "FileSystemWatcher_IsSupported";
static int _initWatcher() native "FileSystemWatcher_InitWatcher";
diff --git a/runtime/bin/file_system_entity_patch.dart b/runtime/bin/file_system_entity_patch.dart
index dc2b346..c3faefe 100644
--- a/runtime/bin/file_system_entity_patch.dart
+++ b/runtime/bin/file_system_entity_patch.dart
@@ -3,15 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
@patch class FileStat {
- /* @patch */ static _statSync(String path) native "File_Stat";
+ @patch static _statSync(String path) native "File_Stat";
}
@patch class FileSystemEntity {
- /* @patch */ static _getType(String path, bool followLinks)
+ @patch static _getType(String path, bool followLinks)
native "File_GetType";
- /* @patch */ static _identical(String path1, String path2)
+ @patch static _identical(String path1, String path2)
native "File_AreIdentical";
- /* @patch */ static _resolveSymbolicLinks(String path)
+ @patch static _resolveSymbolicLinks(String path)
native "File_ResolveSymbolicLinks";
}
diff --git a/runtime/bin/filter_patch.dart b/runtime/bin/filter_patch.dart
index 11691e8..db086f9 100644
--- a/runtime/bin/filter_patch.dart
+++ b/runtime/bin/filter_patch.dart
@@ -29,14 +29,14 @@
}
@patch class _Filter {
- /* @patch */ static _Filter _newZLibDeflateFilter(bool gzip, int level,
+ @patch static _Filter _newZLibDeflateFilter(bool gzip, int level,
int windowBits, int memLevel,
int strategy,
List<int> dictionary,
bool raw) =>
new _ZLibDeflateFilter(gzip, level, windowBits, memLevel, strategy,
dictionary, raw);
- /* @patch */ static _Filter _newZLibInflateFilter(int windowBits,
+ @patch static _Filter _newZLibInflateFilter(int windowBits,
List<int> dictionary,
bool raw) =>
new _ZLibInflateFilter(windowBits, dictionary, raw);
diff --git a/runtime/bin/io_service_patch.dart b/runtime/bin/io_service_patch.dart
index 94b6346..3ae7d922 100644
--- a/runtime/bin/io_service_patch.dart
+++ b/runtime/bin/io_service_patch.dart
@@ -11,7 +11,7 @@
static Map<int, Completer> _messageMap = {};
static int _id = 0;
- /* @patch */ static Future _dispatch(int request, List data) {
+ @patch static Future _dispatch(int request, List data) {
int id;
do {
id = _getNextId();
diff --git a/runtime/bin/platform_patch.dart b/runtime/bin/platform_patch.dart
index bbd353b..8110ea1 100644
--- a/runtime/bin/platform_patch.dart
+++ b/runtime/bin/platform_patch.dart
@@ -3,32 +3,32 @@
// BSD-style license that can be found in the LICENSE file.
@patch class _Platform {
- /* @patch */ static int _numberOfProcessors()
+ @patch static int _numberOfProcessors()
native "Platform_NumberOfProcessors";
- /* @patch */ static String _pathSeparator()
+ @patch static String _pathSeparator()
native "Platform_PathSeparator";
- /* @patch */ static String _operatingSystem()
+ @patch static String _operatingSystem()
native "Platform_OperatingSystem";
- /* @patch */ static _localHostname()
+ @patch static _localHostname()
native "Platform_LocalHostname";
- /* @patch */ static _executable()
+ @patch static _executable()
native "Platform_ExecutableName";
- /* @patch */ static _resolvedExecutable()
+ @patch static _resolvedExecutable()
native "Platform_ResolvedExecutableName";
- /* @patch */ static _environment()
+ @patch static _environment()
native "Platform_Environment";
- /* @patch */ static List<String> _executableArguments()
+ @patch static List<String> _executableArguments()
native "Platform_ExecutableArguments";
- /* @patch */ static String _version()
+ @patch static String _version()
native "Platform_GetVersion";
- /* @patch */ static String _packageRoot()
+ @patch static String _packageRoot()
=> VMLibraryHooks.packageRootString;
- /* @patch */ static String _packageConfig()
+ @patch static String _packageConfig()
=> VMLibraryHooks.packageConfigString;
// This script singleton is written to by the embedder if applicable.
- /* @patch */ static void set _nativeScript(String path) {
+ @patch static void set _nativeScript(String path) {
if (path.startsWith('http:') ||
path.startsWith('https:') ||
path.startsWith('package:') ||
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index 2e3d2fb..bfb09db 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -3,19 +3,19 @@
// BSD-style license that can be found in the LICENSE file.
@patch class _WindowsCodePageDecoder {
- /* @patch */ static String _decodeBytes(List<int> bytes)
+ @patch static String _decodeBytes(List<int> bytes)
native "SystemEncodingToString";
}
@patch class _WindowsCodePageEncoder {
- /* @patch */ static List<int> _encodeString(String string)
+ @patch static List<int> _encodeString(String string)
native "StringToSystemEncoding";
}
@patch class Process {
- /* @patch */ static Future<Process> start(
+ @patch static Future<Process> start(
String executable,
List<String> arguments,
{String workingDirectory,
@@ -33,7 +33,7 @@
return process._start();
}
- /* @patch */ static Future<ProcessResult> run(
+ @patch static Future<ProcessResult> run(
String executable,
List<String> arguments,
{String workingDirectory,
@@ -52,7 +52,7 @@
stderrEncoding);
}
- /* @patch */ static ProcessResult runSync(
+ @patch static ProcessResult runSync(
String executable,
List<String> arguments,
{String workingDirectory,
@@ -71,7 +71,7 @@
stderrEncoding);
}
- /* @patch */ static bool killPid(
+ @patch static bool killPid(
int pid, [ProcessSignal signal = ProcessSignal.SIGTERM]) {
if (signal is! ProcessSignal) {
throw new ArgumentError(
@@ -125,9 +125,9 @@
}
}
- /* @patch */ static _setSignalHandler(int signal)
+ @patch static _setSignalHandler(int signal)
native "Process_SetSignalHandler";
- /* @patch */ static int _clearSignalHandler(int signal)
+ @patch static int _clearSignalHandler(int signal)
native "Process_ClearSignalHandler";
}
@@ -135,15 +135,15 @@
@patch class _ProcessUtils {
- /* @patch */ static void _exit(int status) native "Process_Exit";
- /* @patch */ static void _setExitCode(int status)
+ @patch static void _exit(int status) native "Process_Exit";
+ @patch static void _setExitCode(int status)
native "Process_SetExitCode";
- /* @patch */ static int _getExitCode() native "Process_GetExitCode";
- /* @patch */ static void _sleep(int millis) native "Process_Sleep";
- /* @patch */ static int _pid(Process process) native "Process_Pid";
+ @patch static int _getExitCode() native "Process_GetExitCode";
+ @patch static void _sleep(int millis) native "Process_Sleep";
+ @patch static int _pid(Process process) native "Process_Pid";
static bool _killPid(int pid, int signal)
native "Process_KillPid";
- /* @patch */ static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
+ @patch static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
if (signal != ProcessSignal.SIGHUP &&
signal != ProcessSignal.SIGINT &&
signal != ProcessSignal.SIGTERM &&
diff --git a/runtime/bin/run_vm_tests_fuchsia.cc b/runtime/bin/run_vm_tests_fuchsia.cc
index a7839a9..fddba5e 100644
--- a/runtime/bin/run_vm_tests_fuchsia.cc
+++ b/runtime/bin/run_vm_tests_fuchsia.cc
@@ -156,7 +156,7 @@
argv[1] = old_gen_arg;
argv[2] = test_name;
- mx_handle_t p = launchpad_launch(argv[0], kArgc, argv);
+ mx_handle_t p = launchpad_launch_mxio(argv[0], kArgc, argv);
if (p < 0) {
fprintf(stderr, "process failed to start\n");
return -1;
diff --git a/runtime/bin/secure_socket_patch.dart b/runtime/bin/secure_socket_patch.dart
index b3fde05..ad29bd5 100644
--- a/runtime/bin/secure_socket_patch.dart
+++ b/runtime/bin/secure_socket_patch.dart
@@ -3,17 +3,17 @@
// BSD-style license that can be found in the LICENSE file.
@patch class SecureSocket {
- /* @patch */ factory SecureSocket._(RawSecureSocket rawSocket) =>
+ @patch factory SecureSocket._(RawSecureSocket rawSocket) =>
new _SecureSocket(rawSocket);
}
@patch class _SecureFilter {
- /* @patch */ factory _SecureFilter() => new _SecureFilterImpl();
+ @patch factory _SecureFilter() => new _SecureFilterImpl();
}
@patch class X509Certificate {
- /* @patch */ factory X509Certificate._() => new _X509CertificateImpl();
+ @patch factory X509Certificate._() => new _X509CertificateImpl();
}
class _SecureSocket extends _Socket implements SecureSocket {
@@ -116,15 +116,15 @@
}
@patch class SecurityContext {
- /* @patch */ factory SecurityContext() {
+ @patch factory SecurityContext() {
return new _SecurityContext();
}
- /* @patch */ static SecurityContext get defaultContext {
+ @patch static SecurityContext get defaultContext {
return _SecurityContext.defaultContext;
}
- /* @patch */ static bool get alpnSupported {
+ @patch static bool get alpnSupported {
return _SecurityContext.alpnSupported;
}
}
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index 745306d..1e9d94e 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -23,10 +23,8 @@
static const int kSocketIdNativeField = 0;
-
ListeningSocketRegistry *globalTcpListeningSocketRegistry = NULL;
-
void ListeningSocketRegistry::Initialize() {
ASSERT(globalTcpListeningSocketRegistry == NULL);
globalTcpListeningSocketRegistry = new ListeningSocketRegistry();
@@ -44,6 +42,60 @@
}
+ListeningSocketRegistry::OSSocket* ListeningSocketRegistry::LookupByPort(
+ intptr_t port) {
+ HashMap::Entry* entry =
+ sockets_by_port_.Lookup(GetHashmapKeyFromIntptr(port),
+ GetHashmapHashFromIntptr(port), false);
+ if (entry == NULL) {
+ return NULL;
+ }
+ return reinterpret_cast<OSSocket*>(entry->value);
+}
+
+
+void ListeningSocketRegistry::InsertByPort(intptr_t port, OSSocket* socket) {
+ HashMap::Entry* entry =
+ sockets_by_port_.Lookup(GetHashmapKeyFromIntptr(port),
+ GetHashmapHashFromIntptr(port), true);
+ ASSERT(entry != NULL);
+ entry->value = reinterpret_cast<void*>(socket);
+}
+
+
+void ListeningSocketRegistry::RemoveByPort(intptr_t port) {
+ sockets_by_port_.Remove(
+ GetHashmapKeyFromIntptr(port), GetHashmapHashFromIntptr(port));
+}
+
+
+ListeningSocketRegistry::OSSocket* ListeningSocketRegistry::LookupByFd(
+ intptr_t fd) {
+ HashMap::Entry* entry =
+ sockets_by_fd_.Lookup(GetHashmapKeyFromIntptr(fd),
+ GetHashmapHashFromIntptr(fd), false);
+ if (entry == NULL) {
+ return NULL;
+ }
+ return reinterpret_cast<OSSocket*>(entry->value);
+}
+
+
+void ListeningSocketRegistry::InsertByFd(intptr_t fd, OSSocket* socket) {
+ HashMap::Entry* entry =
+ sockets_by_fd_.Lookup(GetHashmapKeyFromIntptr(fd),
+ GetHashmapHashFromIntptr(fd), true);
+ ASSERT(entry != NULL);
+ entry->value = reinterpret_cast<void*>(socket);
+}
+
+
+void ListeningSocketRegistry::RemoveByFd(intptr_t fd) {
+ sockets_by_fd_.Remove(
+ GetHashmapKeyFromIntptr(fd), GetHashmapHashFromIntptr(fd));
+}
+
+
Dart_Handle ListeningSocketRegistry::CreateBindListen(Dart_Handle socket_object,
RawAddr addr,
intptr_t backlog,
@@ -52,18 +104,12 @@
MutexLocker ml(ListeningSocketRegistry::mutex_);
intptr_t port = SocketAddress::GetAddrPort(addr);
-
- SocketsIterator it = sockets_by_port_.find(port);
- OSSocket *first_os_socket = NULL;
- if (it != sockets_by_port_.end()) {
- first_os_socket = it->second;
- }
-
+ OSSocket* first_os_socket = LookupByPort(port);
if (first_os_socket != NULL) {
// There is already a socket listening on this port. We need to ensure
// that if there is one also listening on the same address, it was created
// with `shared = true`, ...
- OSSocket *os_socket = it->second;
+ OSSocket *os_socket = first_os_socket;
OSSocket *os_socket_same_addr = findOSSocketWithAddress(os_socket, addr);
if (os_socket_same_addr != NULL) {
@@ -117,8 +163,9 @@
new OSSocket(addr, allocated_port, v6_only, shared, socketfd);
os_socket->ref_count = 1;
os_socket->next = first_os_socket;
- sockets_by_port_[allocated_port] = os_socket;
- sockets_by_fd_[socketfd] = os_socket;
+
+ InsertByPort(allocated_port, os_socket);
+ InsertByFd(socketfd, os_socket);
// We set as a side-effect the port on the dart socket_object.
Socket::SetSocketIdNativeField(socket_object, socketfd);
@@ -127,42 +174,57 @@
}
+bool ListeningSocketRegistry::CloseOneSafe(OSSocket* os_socket) {
+ ASSERT(!mutex_->TryLock());
+ ASSERT(os_socket != NULL);
+ ASSERT(os_socket->ref_count > 0);
+ os_socket->ref_count--;
+ if (os_socket->ref_count > 0) {
+ return false;
+ }
+ // We free the OS socket by removing it from two datastructures.
+ RemoveByFd(os_socket->socketfd);
+
+ OSSocket* prev = NULL;
+ OSSocket* current = LookupByPort(os_socket->port);
+ while (current != os_socket) {
+ ASSERT(current != NULL);
+ prev = current;
+ current = current->next;
+ }
+
+ if ((prev == NULL) && (current->next == NULL)) {
+ // Remove last element from the list.
+ RemoveByPort(os_socket->port);
+ } else if (prev == NULL) {
+ // Remove first element of the list.
+ InsertByPort(os_socket->port, current->next);
+ } else {
+ // Remove element from the list which is not the first one.
+ prev->next = os_socket->next;
+ }
+
+ ASSERT(os_socket->ref_count == 0);
+ delete os_socket;
+ return true;
+}
+
+
+void ListeningSocketRegistry::CloseAllSafe() {
+ MutexLocker ml(mutex_);
+ for (HashMap::Entry* p = sockets_by_fd_.Start();
+ p != NULL;
+ p = sockets_by_fd_.Next(p)) {
+ CloseOneSafe(reinterpret_cast<OSSocket*>(p->value));
+ }
+}
+
+
bool ListeningSocketRegistry::CloseSafe(intptr_t socketfd) {
ASSERT(!mutex_->TryLock());
-
- SocketsIterator it = sockets_by_fd_.find(socketfd);
- if (it != sockets_by_fd_.end()) {
- OSSocket *os_socket = it->second;
-
- ASSERT(os_socket->ref_count > 0);
- os_socket->ref_count--;
- if (os_socket->ref_count == 0) {
- // We free the OS socket by removing it from two datastructures.
- sockets_by_fd_.erase(socketfd);
-
- OSSocket *prev = NULL;
- OSSocket *current = sockets_by_port_[os_socket->port];
- while (current != os_socket) {
- ASSERT(current != NULL);
- prev = current;
- current = current->next;
- }
-
- if ((prev == NULL) && (current->next == NULL)) {
- // Remove last element from the list.
- sockets_by_port_.erase(os_socket->port);
- } else if (prev == NULL) {
- // Remove first element of the list.
- sockets_by_port_[os_socket->port] = current->next;
- } else {
- // Remove element from the list which is not the first one.
- prev->next = os_socket->next;
- }
-
- delete os_socket;
- return true;
- }
- return false;
+ OSSocket* os_socket = LookupByFd(socketfd);
+ if (os_socket != NULL) {
+ return CloseOneSafe(os_socket);
} else {
// It should be impossible for the event handler to close something that
// hasn't been created before.
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 6a50d79..ea8dade 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -25,12 +25,11 @@
#error Unknown target os.
#endif
-#include <map>
-
#include "bin/builtin.h"
#include "bin/dartutils.h"
#include "bin/thread.h"
#include "bin/utils.h"
+#include "platform/hashmap.h"
namespace dart {
namespace bin {
@@ -372,40 +371,24 @@
class ListeningSocketRegistry {
- private:
- struct OSSocket {
- RawAddr address;
- int port;
- bool v6_only;
- bool shared;
- int ref_count;
- intptr_t socketfd;
-
- // Singly linked lists of OSSocket instances which listen on the same port
- // but on different addresses.
- OSSocket *next;
-
- OSSocket(RawAddr address, int port, bool v6_only, bool shared,
- intptr_t socketfd)
- : address(address), port(port), v6_only(v6_only), shared(shared),
- ref_count(0), socketfd(socketfd), next(NULL) {}
- };
-
public:
+ ListeningSocketRegistry() :
+ sockets_by_port_(SameIntptrValue, kInitialSocketsCount),
+ sockets_by_fd_(SameIntptrValue, kInitialSocketsCount),
+ mutex_(new Mutex()) {}
+
+ ~ListeningSocketRegistry() {
+ CloseAllSafe();
+ delete mutex_;
+ mutex_ = NULL;
+ }
+
static void Initialize();
static ListeningSocketRegistry *Instance();
static void Cleanup();
-
- ListeningSocketRegistry() : mutex_(new Mutex()) {}
-
- ~ListeningSocketRegistry() {
- delete mutex_;
- mutex_ = NULL;
- }
-
// This function should be called from a dart runtime call in order to create
// a new (potentially shared) socket.
Dart_Handle CreateBindListen(Dart_Handle socket_object,
@@ -427,6 +410,26 @@
Mutex *mutex() { return mutex_; }
private:
+ struct OSSocket {
+ RawAddr address;
+ int port;
+ bool v6_only;
+ bool shared;
+ int ref_count;
+ intptr_t socketfd;
+
+ // Singly linked lists of OSSocket instances which listen on the same port
+ // but on different addresses.
+ OSSocket *next;
+
+ OSSocket(RawAddr address, int port, bool v6_only, bool shared,
+ intptr_t socketfd)
+ : address(address), port(port), v6_only(v6_only), shared(shared),
+ ref_count(0), socketfd(socketfd), next(NULL) {}
+ };
+
+ static const intptr_t kInitialSocketsCount = 8;
+
OSSocket *findOSSocketWithAddress(OSSocket *current, const RawAddr& addr) {
while (current != NULL) {
if (SocketAddress::AreAddressesEqual(current->address, addr)) {
@@ -437,13 +440,35 @@
return NULL;
}
- std::map<intptr_t, OSSocket*> sockets_by_port_;
- std::map<intptr_t, OSSocket*> sockets_by_fd_;
+ static bool SameIntptrValue(void* key1, void* key2) {
+ return reinterpret_cast<intptr_t>(key1) == reinterpret_cast<intptr_t>(key2);
+ }
+
+ static uint32_t GetHashmapHashFromIntptr(intptr_t i) {
+ return static_cast<uint32_t>((i + 1) & 0xFFFFFFFF);
+ }
+
+
+ static void* GetHashmapKeyFromIntptr(intptr_t i) {
+ return reinterpret_cast<void*>(i + 1);
+ }
+
+ OSSocket* LookupByPort(intptr_t port);
+ void InsertByPort(intptr_t port, OSSocket* socket);
+ void RemoveByPort(intptr_t port);
+
+ OSSocket* LookupByFd(intptr_t fd);
+ void InsertByFd(intptr_t fd, OSSocket* socket);
+ void RemoveByFd(intptr_t fd);
+
+ bool CloseOneSafe(OSSocket* os_socket);
+ void CloseAllSafe();
+
+ HashMap sockets_by_port_;
+ HashMap sockets_by_fd_;
+
Mutex *mutex_;
- typedef std::map<intptr_t, OSSocket*>::iterator SocketsIterator;
-
- private:
DISALLOW_COPY_AND_ASSIGN(ListeningSocketRegistry);
};
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index e4bcb9f..0244e79 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
@patch class RawServerSocket {
- /* @patch */ static Future<RawServerSocket> bind(address,
+ @patch static Future<RawServerSocket> bind(address,
int port,
{int backlog: 0,
bool v6Only: false,
@@ -14,7 +14,7 @@
@patch class RawSocket {
- /* @patch */ static Future<RawSocket> connect(
+ @patch static Future<RawSocket> connect(
host, int port, {sourceAddress}) {
return _RawSocket.connect(host, port, sourceAddress);
}
@@ -22,43 +22,43 @@
@patch class InternetAddress {
- /* @patch */ static InternetAddress get LOOPBACK_IP_V4 {
+ @patch static InternetAddress get LOOPBACK_IP_V4 {
return _InternetAddress.LOOPBACK_IP_V4;
}
- /* @patch */ static InternetAddress get LOOPBACK_IP_V6 {
+ @patch static InternetAddress get LOOPBACK_IP_V6 {
return _InternetAddress.LOOPBACK_IP_V6;
}
- /* @patch */ static InternetAddress get ANY_IP_V4 {
+ @patch static InternetAddress get ANY_IP_V4 {
return _InternetAddress.ANY_IP_V4;
}
- /* @patch */ static InternetAddress get ANY_IP_V6 {
+ @patch static InternetAddress get ANY_IP_V6 {
return _InternetAddress.ANY_IP_V6;
}
- /* @patch */ factory InternetAddress(String address) {
+ @patch factory InternetAddress(String address) {
return new _InternetAddress.parse(address);
}
- /* @patch */ static Future<List<InternetAddress>> lookup(
+ @patch static Future<List<InternetAddress>> lookup(
String host, {InternetAddressType type: InternetAddressType.ANY}) {
return _NativeSocket.lookup(host, type: type);
}
- /* @patch */ static InternetAddress _cloneWithNewHost(
+ @patch static InternetAddress _cloneWithNewHost(
InternetAddress address, String host) {
return (address as _InternetAddress)._cloneWithNewHost(host);
}
}
@patch class NetworkInterface {
- /* @patch */ static bool get listSupported {
+ @patch static bool get listSupported {
return _listSupported();
}
- /* @patch */ static Future<List<NetworkInterface>> list({
+ @patch static Future<List<NetworkInterface>> list({
bool includeLoopback: false,
bool includeLinkLocal: false,
InternetAddressType type: InternetAddressType.ANY}) {
@@ -1361,7 +1361,7 @@
@patch class ServerSocket {
- /* @patch */ static Future<ServerSocket> bind(address,
+ @patch static Future<ServerSocket> bind(address,
int port,
{int backlog: 0,
bool v6Only: false,
@@ -1408,7 +1408,7 @@
@patch class Socket {
- /* @patch */ static Future<Socket> connect(host, int port, {sourceAddress}) {
+ @patch static Future<Socket> connect(host, int port, {sourceAddress}) {
return RawSocket.connect(host, port, sourceAddress: sourceAddress).then(
(socket) => new _Socket(socket));
}
@@ -1721,7 +1721,7 @@
@patch class RawDatagramSocket {
- /* @patch */ static Future<RawDatagramSocket> bind(
+ @patch static Future<RawDatagramSocket> bind(
host, int port, {bool reuseAddress: true}) {
return _RawDatagramSocket.bind(host, port, reuseAddress);
}
diff --git a/runtime/bin/stdio_patch.dart b/runtime/bin/stdio_patch.dart
index 3c258c5..b3dc68e 100644
--- a/runtime/bin/stdio_patch.dart
+++ b/runtime/bin/stdio_patch.dart
@@ -47,13 +47,13 @@
}
@patch class Stdin {
- /* @patch */ int readByteSync() native "Stdin_ReadByte";
+ @patch int readByteSync() native "Stdin_ReadByte";
- /* @patch */ bool get echoMode => _echoMode;
- /* @patch */ void set echoMode(bool enabled) { _echoMode = enabled; }
+ @patch bool get echoMode => _echoMode;
+ @patch void set echoMode(bool enabled) { _echoMode = enabled; }
- /* @patch */ bool get lineMode => _lineMode;
- /* @patch */ void set lineMode(bool enabled) { _lineMode = enabled; }
+ @patch bool get lineMode => _lineMode;
+ @patch void set lineMode(bool enabled) { _lineMode = enabled; }
static bool get _echoMode native "Stdin_GetEchoMode";
static void set _echoMode(bool enabled) native "Stdin_SetEchoMode";
@@ -62,7 +62,7 @@
}
@patch class Stdout {
- /* @patch */ bool _hasTerminal(int fd) {
+ @patch bool _hasTerminal(int fd) {
try {
_terminalSize(fd);
return true;
@@ -71,8 +71,8 @@
}
}
- /* @patch */ int _terminalColumns(int fd) => _terminalSize(fd)[0];
- /* @patch */ int _terminalLines(int fd) => _terminalSize(fd)[1];
+ @patch int _terminalColumns(int fd) => _terminalSize(fd)[0];
+ @patch int _terminalLines(int fd) => _terminalSize(fd)[1];
static List _terminalSize(int fd) {
var size = _getTerminalSize(fd);
diff --git a/runtime/lib/array_patch.dart b/runtime/lib/array_patch.dart
index 95eeaa8..e62524b 100644
--- a/runtime/lib/array_patch.dart
+++ b/runtime/lib/array_patch.dart
@@ -11,7 +11,7 @@
const _GROWABLE_ARRAY_MARKER = const _GrowableArrayMarker();
@patch class List<E> {
- /* @patch */ factory List([int length = _GROWABLE_ARRAY_MARKER]) {
+ @patch factory List([int length = _GROWABLE_ARRAY_MARKER]) {
if (identical(length, _GROWABLE_ARRAY_MARKER)) {
return new _GrowableList<E>(0);
}
@@ -20,7 +20,7 @@
return new _List<E>(length);
}
- /* @patch */ factory List.filled(int length, E fill, {bool growable: false}) {
+ @patch factory List.filled(int length, E fill, {bool growable: false}) {
// All error handling on the length parameter is done at the implementation
// of new _List.
var result = growable ? new _GrowableList<E>(length) : new _List<E>(length);
@@ -32,7 +32,7 @@
return result;
}
- /* @patch */ factory List.from(Iterable elements, { bool growable: true }) {
+ @patch factory List.from(Iterable elements, { bool growable: true }) {
if (elements is EfficientLength) {
int length = elements.length;
var list = growable ? new _GrowableList<E>(length) : new _List<E>(length);
@@ -54,7 +54,7 @@
return makeListFixedLength(list);
}
- /* @patch */ factory List.unmodifiable(Iterable elements) {
+ @patch factory List.unmodifiable(Iterable elements) {
List result = new List<E>.from(elements, growable: false);
return makeFixedListUnmodifiable(result);
}
diff --git a/runtime/lib/bool_patch.dart b/runtime/lib/bool_patch.dart
index 1a5eb6c..5b5f4ff 100644
--- a/runtime/lib/bool_patch.dart
+++ b/runtime/lib/bool_patch.dart
@@ -6,8 +6,8 @@
@patch class bool {
- /* @patch */ const factory bool.fromEnvironment(String name,
- {bool defaultValue: false})
+ @patch const factory bool.fromEnvironment(String name,
+ {bool defaultValue: false})
native "Bool_fromEnvironment";
int get hashCode => this ? 1231 : 1237;
diff --git a/runtime/lib/collection_patch.dart b/runtime/lib/collection_patch.dart
index 000e0bc..ed76535 100644
--- a/runtime/lib/collection_patch.dart
+++ b/runtime/lib/collection_patch.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
@patch class HashMap<K, V> {
- /* @patch */ factory HashMap({ bool equals(K key1, K key2),
+ @patch factory HashMap({ bool equals(K key1, K key2),
int hashCode(K key),
bool isValidKey(potentialKey) }) {
if (isValidKey == null) {
@@ -32,7 +32,7 @@
return new _CustomHashMap<K, V>(equals, hashCode, isValidKey);
}
- /* patch */ factory HashMap.identity() = _IdentityHashMap<K, V>;
+ @patch factory HashMap.identity() = _IdentityHashMap<K, V>;
Set<K> _newKeySet();
}
@@ -519,9 +519,9 @@
}
@patch class HashSet<E> {
- /* @patch */ factory HashSet({ bool equals(E e1, E e2),
- int hashCode(E e),
- bool isValidKey(potentialKey) }) {
+ @patch factory HashSet({ bool equals(E e1, E e2),
+ int hashCode(E e),
+ bool isValidKey(potentialKey) }) {
if (isValidKey == null) {
if (hashCode == null) {
if (equals == null) {
@@ -548,7 +548,7 @@
return new _CustomHashSet<E>(equals, hashCode, isValidKey);
}
- /* @patch */ factory HashSet.identity() = _IdentityHashSet<E>;
+ @patch factory HashSet.identity() = _IdentityHashSet<E>;
}
class _HashSet<E> extends _HashSetBase<E> implements HashSet<E> {
@@ -910,7 +910,7 @@
var _nextEntry;
var _previousEntry;
- /* @patch */ factory LinkedHashMap({ bool equals(K key1, K key2),
+ @patch factory LinkedHashMap({ bool equals(K key1, K key2),
int hashCode(K key),
bool isValidKey(potentialKey) }) {
if (isValidKey == null) {
@@ -939,12 +939,12 @@
return new _CompactLinkedCustomHashMap<K, V>(equals, hashCode, isValidKey);
}
- /* @patch */ factory LinkedHashMap.identity() =
+ @patch factory LinkedHashMap.identity() =
_CompactLinkedIdentityHashMap<K, V>;
}
@patch class LinkedHashSet<E> {
- /* @patch */ factory LinkedHashSet({ bool equals(E e1, E e2),
+ @patch factory LinkedHashSet({ bool equals(E e1, E e2),
int hashCode(E e),
bool isValidKey(potentialKey) }) {
if (isValidKey == null) {
@@ -973,6 +973,6 @@
return new _CompactLinkedCustomHashSet<E>(equals, hashCode, isValidKey);
}
- /* @patch */ factory LinkedHashSet.identity() =
+ @patch factory LinkedHashSet.identity() =
_CompactLinkedIdentityHashSet<E>;
}
diff --git a/runtime/lib/convert_patch.dart b/runtime/lib/convert_patch.dart
index 6bf0a2c..25a8dc5 100644
--- a/runtime/lib/convert_patch.dart
+++ b/runtime/lib/convert_patch.dart
@@ -22,7 +22,7 @@
}
@patch class Utf8Decoder {
- /* @patch */
+ @patch
Converter<List<int>, dynamic/*=T*/> fuse/*<T>*/(
Converter<String, dynamic/*=T*/> next) {
if (next is JsonDecoder) {
@@ -34,7 +34,7 @@
}
// Allow intercepting of UTF-8 decoding when built-in lists are passed.
- /* @patch */
+ @patch
static String _convertIntercepted(
bool allowMalformed, List<int> codeUnits, int start, int end) {
return null; // This call was not intercepted.
@@ -1377,7 +1377,7 @@
}
@patch class JsonDecoder {
- /* @patch */ StringConversionSink startChunkedConversion(Sink<Object> sink) {
+ @patch StringConversionSink startChunkedConversion(Sink<Object> sink) {
return new _JsonStringDecoderSink(this._reviver, sink);
}
}
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 5fd883e..f06c98b 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -76,5 +76,5 @@
}
@patch class StackTrace {
- /* @patch */ static StackTrace get current native "StackTrace_current";
+ @patch static StackTrace get current native "StackTrace_current";
}
diff --git a/runtime/lib/date_patch.dart b/runtime/lib/date_patch.dart
index 0f7837e..d1fced2 100644
--- a/runtime/lib/date_patch.dart
+++ b/runtime/lib/date_patch.dart
@@ -30,17 +30,17 @@
List __parts;
- /* @patch */ DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
- {bool isUtc: false})
+ @patch DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
+ {bool isUtc: false})
: this._withValue(
millisecondsSinceEpoch * Duration.MICROSECONDS_PER_MILLISECOND,
isUtc: isUtc);
- /* @patch */ DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
- {bool isUtc: false})
+ @patch DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
+ {bool isUtc: false})
: this._withValue(microsecondsSinceEpoch, isUtc: isUtc);
- /* @patch */ DateTime._internal(int year,
+ @patch DateTime._internal(int year,
int month,
int day,
int hour,
@@ -57,17 +57,17 @@
if (isUtc == null) throw new ArgumentError();
}
- /* @patch */ DateTime._now()
+ @patch DateTime._now()
: isUtc = false,
_value = _getCurrentMicros() {
}
- /* @patch */ String get timeZoneName {
+ @patch String get timeZoneName {
if (isUtc) return "UTC";
return _timeZoneName(microsecondsSinceEpoch);
}
- /* @patch */ Duration get timeZoneOffset {
+ @patch Duration get timeZoneOffset {
if (isUtc) return new Duration();
int offsetInSeconds = _timeZoneOffsetInSeconds(microsecondsSinceEpoch);
return new Duration(seconds: offsetInSeconds);
@@ -165,42 +165,42 @@
return __parts;
}
- /* @patch */ DateTime add(Duration duration) {
+ @patch DateTime add(Duration duration) {
return new DateTime._withValue(
_value + duration.inMicroseconds, isUtc: isUtc);
}
- /* @patch */ DateTime subtract(Duration duration) {
+ @patch DateTime subtract(Duration duration) {
return new DateTime._withValue(
_value - duration.inMicroseconds, isUtc: isUtc);
}
- /* @patch */ Duration difference(DateTime other) {
+ @patch Duration difference(DateTime other) {
return new Duration(microseconds: _value - other._value);
}
- /* @patch */ int get millisecondsSinceEpoch =>
+ @patch int get millisecondsSinceEpoch =>
_value ~/ Duration.MICROSECONDS_PER_MILLISECOND;
- /* @patch */ int get microsecondsSinceEpoch => _value;
+ @patch int get microsecondsSinceEpoch => _value;
- /* @patch */ int get microsecond => _parts[_MICROSECOND_INDEX];
+ @patch int get microsecond => _parts[_MICROSECOND_INDEX];
- /* @patch */ int get millisecond => _parts[_MILLISECOND_INDEX];
+ @patch int get millisecond => _parts[_MILLISECOND_INDEX];
- /* @patch */ int get second => _parts[_SECOND_INDEX];
+ @patch int get second => _parts[_SECOND_INDEX];
- /* @patch */ int get minute => _parts[_MINUTE_INDEX];
+ @patch int get minute => _parts[_MINUTE_INDEX];
- /* @patch */ int get hour => _parts[_HOUR_INDEX];
+ @patch int get hour => _parts[_HOUR_INDEX];
- /* @patch */ int get day => _parts[_DAY_INDEX];
+ @patch int get day => _parts[_DAY_INDEX];
- /* @patch */ int get weekday => _parts[_WEEKDAY_INDEX];
+ @patch int get weekday => _parts[_WEEKDAY_INDEX];
- /* @patch */ int get month => _parts[_MONTH_INDEX];
+ @patch int get month => _parts[_MONTH_INDEX];
- /* @patch */ int get year => _parts[_YEAR_INDEX];
+ @patch int get year => _parts[_YEAR_INDEX];
/**
* Returns the amount of microseconds in UTC that represent the same values
@@ -244,7 +244,7 @@
}
/// Converts the given broken down date to microseconds.
- /* @patch */ static int _brokenDownDateToValue(
+ @patch static int _brokenDownDateToValue(
int year, int month, int day,
int hour, int minute, int second, int millisecond, int microsecond,
bool isUtc) {
diff --git a/runtime/lib/deferred_load_patch.dart b/runtime/lib/deferred_load_patch.dart
index 32f233b..5c8a597 100644
--- a/runtime/lib/deferred_load_patch.dart
+++ b/runtime/lib/deferred_load_patch.dart
@@ -5,7 +5,7 @@
final Set<String> _loadedLibraries = new Set<String>();
@patch class DeferredLibrary {
- /* @patch */ Future<Null> load() {
+ @patch Future<Null> load() {
// Dummy implementation that should eventually be replaced by real
// implementation.
Future future =
diff --git a/runtime/lib/double_patch.dart b/runtime/lib/double_patch.dart
index cc3c605..b0b7054 100644
--- a/runtime/lib/double_patch.dart
+++ b/runtime/lib/double_patch.dart
@@ -101,7 +101,7 @@
return _nativeParse(str, start, end);
}
- /* @patch */ static double parse(String str,
+ @patch static double parse(String str,
[double onError(String str)]) {
var result = _parse(str);
if (result == null) {
diff --git a/runtime/lib/errors_patch.dart b/runtime/lib/errors_patch.dart
index 2deb7f9..89ade45 100644
--- a/runtime/lib/errors_patch.dart
+++ b/runtime/lib/errors_patch.dart
@@ -6,15 +6,15 @@
import 'dart:convert' show JSON;
@patch class Error {
- /* @patch */ static String _objectToString(Object object) {
+ @patch static String _objectToString(Object object) {
return Object._toString(object);
}
- /* @patch */ static String _stringToSafeString(String string) {
+ @patch static String _stringToSafeString(String string) {
return JSON.encode(string);
}
- /* @patch */ StackTrace get stackTrace => _stackTrace;
+ @patch StackTrace get stackTrace => _stackTrace;
StackTrace _stackTrace;
}
@@ -100,7 +100,7 @@
static _throwNew(int case_clause_pos) native "FallThroughError_throwNew";
- /* @patch */ String toString() {
+ @patch String toString() {
return "'$_url': Switch case fall-through at line $_line.";
}
@@ -135,7 +135,7 @@
static _throwNew(int case_clause_pos, String className)
native "AbstractClassInstantiationError_throwNew";
- /* @patch */ String toString() {
+ @patch String toString() {
return "Cannot instantiate abstract class $_className: "
"_url '$_url' line $_line";
}
@@ -284,7 +284,7 @@
return "$msg\n\n";
}
- /* @patch */ String toString() {
+ @patch String toString() {
StringBuffer actual_buf = new StringBuffer();
int i = 0;
if (_arguments == null) {
diff --git a/runtime/lib/expando_patch.dart b/runtime/lib/expando_patch.dart
index abdefab..ac5f706 100644
--- a/runtime/lib/expando_patch.dart
+++ b/runtime/lib/expando_patch.dart
@@ -3,14 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
@patch class Expando<T> {
- /* @patch */ Expando([String this.name])
+ @patch Expando([String this.name])
: _data = new List(_minSize),
_used = 0;
static const _minSize = 8;
static final _deletedEntry = new _WeakProperty(null, null);
- /* @patch */ T operator[](Object object) {
+ @patch T operator[](Object object) {
_checkType(object);
var mask = _size - 1;
@@ -31,7 +31,7 @@
return null;
}
- /* @patch */ void operator[]=(Object object, T value) {
+ @patch void operator[]=(Object object, T value) {
_checkType(object);
var mask = _size - 1;
diff --git a/runtime/lib/function_patch.dart b/runtime/lib/function_patch.dart
index 7ed74c8..5acd4f9 100644
--- a/runtime/lib/function_patch.dart
+++ b/runtime/lib/function_patch.dart
@@ -6,9 +6,9 @@
static _apply(List arguments, List names)
native "Function_apply";
- /* @patch */ static apply(Function function,
- List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]) {
+ @patch static apply(Function function,
+ List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
int numPositionalArguments = 1 + // Function is first implicit argument.
(positionalArguments != null ? positionalArguments.length : 0);
int numNamedArguments = namedArguments != null ? namedArguments.length : 0;
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index 271c71a..9e942e4 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -112,8 +112,19 @@
int get length native "GrowableList_getLength";
void set length(int new_length) {
- int new_capacity = (new_length == 0) ? _kDefaultCapacity : new_length;
- if (new_capacity > _capacity) {
+ int old_capacity = _capacity;
+ int new_capacity = new_length;
+ if (new_length == 0) {
+ // Ensure that we use _kDefaultCapacity only when the old_capacity
+ // is greater than _kDefaultCapacity otherwise we end up growing the
+ // the array.
+ if (old_capacity < _kDefaultCapacity) {
+ new_capacity = old_capacity;
+ } else {
+ new_capacity = _kDefaultCapacity;
+ }
+ }
+ if (new_capacity > old_capacity) {
_grow(new_capacity);
_setLength(new_length);
return;
@@ -203,8 +214,7 @@
T removeLast() {
var len = length - 1;
var elem = this[len];
- this[len] = null;
- _setLength(len);
+ this.length = len;
return elem;
}
diff --git a/runtime/lib/integers_patch.dart b/runtime/lib/integers_patch.dart
index 6aa072b..67db176 100644
--- a/runtime/lib/integers_patch.dart
+++ b/runtime/lib/integers_patch.dart
@@ -9,8 +9,8 @@
@patch class int {
- /* @patch */ const factory int.fromEnvironment(String name,
- {int defaultValue})
+ @patch const factory int.fromEnvironment(String name,
+ {int defaultValue})
native "Integer_fromEnvironment";
@@ -42,9 +42,9 @@
return sign * result;
}
- /* @patch */ static int parse(String source,
- { int radix,
- int onError(String str) }) {
+ @patch static int parse(String source,
+ { int radix,
+ int onError(String str) }) {
if (source == null) throw new ArgumentError("The source must not be null");
if (source.isEmpty) return _throwFormatException(onError, source, 0, radix);
if (radix == null || radix == 10) {
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index 6ea2ef5..7e4579a 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -6,14 +6,14 @@
import "dart:_internal";
@patch class ReceivePort {
- /* @patch */ factory ReceivePort() = _ReceivePortImpl;
+ @patch factory ReceivePort() = _ReceivePortImpl;
- /* @patch */ factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) =
+ @patch factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) =
_ReceivePortImpl.fromRawReceivePort;
}
@patch class Capability {
- /* @patch */ factory Capability() = _CapabilityImpl;
+ @patch factory Capability() = _CapabilityImpl;
}
class _CapabilityImpl implements Capability {
@@ -39,7 +39,7 @@
* can not be paused. The data-handler must be set before the first
* event is received.
*/
- /* @patch */ factory RawReceivePort([void handler(event)]) {
+ @patch factory RawReceivePort([void handler(event)]) {
_RawReceivePortImpl result = new _RawReceivePortImpl();
result.handler = handler;
return result;
@@ -272,9 +272,9 @@
static final _currentIsolate = _getCurrentIsolate();
static final _rootUri = _getCurrentRootUri();
- /* @patch */ static Isolate get current => _currentIsolate;
+ @patch static Isolate get current => _currentIsolate;
- /* @patch */ static Future<Uri> get packageRoot {
+ @patch static Future<Uri> get packageRoot {
var hook = VMLibraryHooks.packageRootUriFuture;
if (hook == null) {
throw new UnsupportedError("Isolate.packageRoot");
@@ -282,7 +282,7 @@
return hook();
}
- /* @patch */ static Future<Uri> get packageConfig {
+ @patch static Future<Uri> get packageConfig {
var hook = VMLibraryHooks.packageConfigUriFuture;
if (hook == null) {
throw new UnsupportedError("Isolate.packageConfig");
@@ -290,7 +290,7 @@
return hook();
}
- /* @patch */ static Future<Uri> resolvePackageUri(Uri packageUri) {
+ @patch static Future<Uri> resolvePackageUri(Uri packageUri) {
var hook = VMLibraryHooks.resolvePackageUriFuture;
if (hook == null) {
throw new UnsupportedError("Isolate.resolvePackageUri");
@@ -303,7 +303,7 @@
(VMLibraryHooks.packageConfigUriFuture != null) &&
(VMLibraryHooks.resolvePackageUriFuture != null);
- /* @patch */ static Future<Isolate> spawn(
+ @patch static Future<Isolate> spawn(
void entryPoint(message), var message,
{bool paused: false, bool errorsAreFatal,
SendPort onExit, SendPort onError}) async {
@@ -340,7 +340,7 @@
}
}
- /* @patch */ static Future<Isolate> spawnUri(
+ @patch static Future<Isolate> spawnUri(
Uri uri, List<String> args, var message,
{bool paused: false,
SendPort onExit,
@@ -478,7 +478,7 @@
static void _sendOOB(port, msg) native "Isolate_sendOOB";
- /* @patch */ void _pause(Capability resumeCapability) {
+ @patch void _pause(Capability resumeCapability) {
var msg = new List(4)
..[0] = 0 // Make room for OOB message type.
..[1] = _PAUSE
@@ -487,7 +487,7 @@
_sendOOB(controlPort, msg);
}
- /* @patch */ void resume(Capability resumeCapability) {
+ @patch void resume(Capability resumeCapability) {
var msg = new List(4)
..[0] = 0 // Make room for OOB message type.
..[1] = _RESUME
@@ -496,8 +496,8 @@
_sendOOB(controlPort, msg);
}
- /* @patch */ void addOnExitListener(SendPort responsePort,
- {Object response}) {
+ @patch void addOnExitListener(SendPort responsePort,
+ {Object response}) {
var msg = new List(4)
..[0] = 0 // Make room for OOB message type.
..[1] = _ADD_EXIT
@@ -506,7 +506,7 @@
_sendOOB(controlPort, msg);
}
- /* @patch */ void removeOnExitListener(SendPort responsePort) {
+ @patch void removeOnExitListener(SendPort responsePort) {
var msg = new List(3)
..[0] = 0 // Make room for OOB message type.
..[1] = _DEL_EXIT
@@ -514,7 +514,7 @@
_sendOOB(controlPort, msg);
}
- /* @patch */ void setErrorsFatal(bool errorsAreFatal) {
+ @patch void setErrorsFatal(bool errorsAreFatal) {
var msg = new List(4)
..[0] = 0 // Make room for OOB message type.
..[1] = _ERROR_FATAL
@@ -523,7 +523,7 @@
_sendOOB(controlPort, msg);
}
- /* @patch */ void kill({int priority: BEFORE_NEXT_EVENT}) {
+ @patch void kill({int priority: BEFORE_NEXT_EVENT}) {
var msg = new List(4)
..[0] = 0 // Make room for OOB message type.
..[1] = _KILL
@@ -532,8 +532,8 @@
_sendOOB(controlPort, msg);
}
- /* @patch */ void ping(SendPort responsePort, {Object response,
- int priority: IMMEDIATE}) {
+ @patch void ping(SendPort responsePort, {Object response,
+ int priority: IMMEDIATE}) {
var msg = new List(5)
..[0] = 0 // Make room for OOM message type.
..[1] = _PING
@@ -543,7 +543,7 @@
_sendOOB(controlPort, msg);
}
- /* @patch */ void addErrorListener(SendPort port) {
+ @patch void addErrorListener(SendPort port) {
var msg = new List(3)
..[0] = 0 // Make room for OOB message type.
..[1] = _ADD_ERROR
@@ -551,7 +551,7 @@
_sendOOB(controlPort, msg);
}
- /* @patch */ void removeErrorListener(SendPort port) {
+ @patch void removeErrorListener(SendPort port) {
var msg = new List(3)
..[0] = 0 // Make room for OOB message type.
..[1] = _DEL_ERROR
diff --git a/runtime/lib/map_patch.dart b/runtime/lib/map_patch.dart
index 333f62a..6e2f14d 100644
--- a/runtime/lib/map_patch.dart
+++ b/runtime/lib/map_patch.dart
@@ -17,9 +17,9 @@
return map;
}
- /* @patch */ factory Map.unmodifiable(Map other) {
+ @patch factory Map.unmodifiable(Map other) {
return new UnmodifiableMapView<K, V>(new Map.from(other));
}
- /* @patch */ factory Map() = LinkedHashMap<K, V>;
+ @patch factory Map() = LinkedHashMap<K, V>;
}
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart
index 5cf80c9..1be57ac 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.dart
@@ -82,7 +82,7 @@
// TODO(iposva): Handle patch methods within a patch class correctly.
@patch class Random {
- /*@patch*/ factory Random([int seed]) {
+ @patch factory Random([int seed]) {
var state = _Random._setupSeed((seed == null) ? _Random._nextSeed() : seed);
// Crank a couple of times to distribute the seed bits a bit further.
return new _Random._withState(state).._nextState()
@@ -91,7 +91,7 @@
.._nextState();
}
- /*@patch*/ factory Random.secure() {
+ @patch factory Random.secure() {
return new _SecureRandom();
}
}
diff --git a/runtime/lib/mirrors_patch.dart b/runtime/lib/mirrors_patch.dart
index d66ce82..2e2da5b 100644
--- a/runtime/lib/mirrors_patch.dart
+++ b/runtime/lib/mirrors_patch.dart
@@ -36,7 +36,7 @@
}
@patch class MirrorSystem {
- /* @patch */ LibraryMirror findLibrary(Symbol libraryName) {
+ @patch LibraryMirror findLibrary(Symbol libraryName) {
var candidates =
libraries.values.where((lib) => lib.simpleName == libraryName);
if (candidates.length == 1) {
@@ -50,11 +50,11 @@
throw new Exception("There is no library named '${getName(libraryName)}'");
}
- /* @patch */ static String getName(Symbol symbol) {
+ @patch static String getName(Symbol symbol) {
return internal.Symbol.getUnmangledName(symbol);
}
- /* @patch */ static Symbol getSymbol(String name, [LibraryMirror library]) {
+ @patch static Symbol getSymbol(String name, [LibraryMirror library]) {
if ((library != null && library is! _LocalLibraryMirror) ||
((name.length > 0) && (name[0] == '_') && (library == null))) {
throw new ArgumentError(library);
diff --git a/runtime/lib/object_patch.dart b/runtime/lib/object_patch.dart
index 7de335b..0af593d 100644
--- a/runtime/lib/object_patch.dart
+++ b/runtime/lib/object_patch.dart
@@ -29,10 +29,10 @@
return result;
}
- /* @patch */ int get hashCode => _objectHashCode(this);
+ @patch int get hashCode => _objectHashCode(this);
int get _identityHashCode => _objectHashCode(this);
- /* @patch */ String toString() native "Object_toString";
+ @patch String toString() native "Object_toString";
// A statically dispatched version of Object.toString.
static String _toString(obj) native "Object_toString";
@@ -43,7 +43,7 @@
Map<String, dynamic> namedArguments)
native "Object_noSuchMethod";
- /* @patch */ noSuchMethod(Invocation invocation) {
+ @patch noSuchMethod(Invocation invocation) {
return _noSuchMethod(invocation.isMethod,
internal.Symbol.getName(invocation.memberName),
invocation._type,
@@ -51,7 +51,7 @@
_symbolMapToStringMap(invocation.namedArguments));
}
- /* @patch */ Type get runtimeType native "Object_runtimeType";
+ @patch Type get runtimeType native "Object_runtimeType";
// Call this function instead of inlining instanceof, thus collecting
// type feedback and reducing code size of unoptimized code.
diff --git a/runtime/lib/profiler.dart b/runtime/lib/profiler.dart
index 9b4ce97..2a085c2 100644
--- a/runtime/lib/profiler.dart
+++ b/runtime/lib/profiler.dart
@@ -5,10 +5,10 @@
import 'dart:_internal';
@patch class UserTag {
- /* @patch */ factory UserTag(String label) {
+ @patch factory UserTag(String label) {
return new _UserTag(label);
}
- /* @patch */ static UserTag get defaultTag => _getDefaultTag();
+ @patch static UserTag get defaultTag => _getDefaultTag();
}
diff --git a/runtime/lib/regexp_patch.dart b/runtime/lib/regexp_patch.dart
index 9b23430..7e8bc19 100644
--- a/runtime/lib/regexp_patch.dart
+++ b/runtime/lib/regexp_patch.dart
@@ -5,7 +5,7 @@
import "dart:collection" show LinkedList, LinkedListEntry;
@patch class RegExp {
- /* @patch */ factory RegExp(String source,
+ @patch factory RegExp(String source,
{bool multiLine: false,
bool caseSensitive: true}) {
_RegExpHashKey key = new _RegExpHashKey(
diff --git a/runtime/lib/resource_patch.dart b/runtime/lib/resource_patch.dart
index e0db212..76a7a9c 100644
--- a/runtime/lib/resource_patch.dart
+++ b/runtime/lib/resource_patch.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
@patch class Resource {
- /* @patch */ const factory Resource(String uri) = _Resource;
+ @patch const factory Resource(String uri) = _Resource;
}
class _Resource implements Resource {
diff --git a/runtime/lib/schedule_microtask_patch.dart b/runtime/lib/schedule_microtask_patch.dart
index 9384c1e..739f1f8 100644
--- a/runtime/lib/schedule_microtask_patch.dart
+++ b/runtime/lib/schedule_microtask_patch.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
@patch class _AsyncRun {
- /* @patch */ static void _scheduleImmediate(void callback()) {
+ @patch static void _scheduleImmediate(void callback()) {
if (_ScheduleImmediate._closure == null) {
throw new UnsupportedError("Microtasks are not supported");
}
diff --git a/runtime/lib/stacktrace.cc b/runtime/lib/stacktrace.cc
index a63d66d..12d6058 100644
--- a/runtime/lib/stacktrace.cc
+++ b/runtime/lib/stacktrace.cc
@@ -25,7 +25,7 @@
skip_frames--;
} else {
code = frame->LookupDartCode();
- offset = Smi::New(frame->pc() - code.EntryPoint());
+ offset = Smi::New(frame->pc() - code.PayloadStart());
code_list.Add(code);
pc_offset_list.Add(offset);
}
diff --git a/runtime/lib/stopwatch_patch.dart b/runtime/lib/stopwatch_patch.dart
index e3749e8..2560243 100644
--- a/runtime/lib/stopwatch_patch.dart
+++ b/runtime/lib/stopwatch_patch.dart
@@ -5,14 +5,14 @@
// A VM patch of the stopwatch part of dart:core.
@patch class Stopwatch {
- /* @patch */ static void _initTicker() {
+ @patch static void _initTicker() {
if (_frequency == null) {
_frequency = _computeFrequency();
}
}
// Returns the current clock tick.
- /* @patch */ static int _now() native "Stopwatch_now";
+ @patch static int _now() native "Stopwatch_now";
// Returns the frequency of clock ticks in Hz.
static int _computeFrequency() native "Stopwatch_frequency";
diff --git a/runtime/lib/string_buffer_patch.dart b/runtime/lib/string_buffer_patch.dart
index c4fab5c..80dddd5 100644
--- a/runtime/lib/string_buffer_patch.dart
+++ b/runtime/lib/string_buffer_patch.dart
@@ -48,20 +48,20 @@
int _bufferCodeUnitMagnitude = 0;
/// Creates the string buffer with an initial content.
- /* @patch */ StringBuffer([Object content = ""]) {
+ @patch StringBuffer([Object content = ""]) {
write(content);
}
- /* @patch */ int get length => _partsCodeUnits + _bufferPosition;
+ @patch int get length => _partsCodeUnits + _bufferPosition;
- /* @patch */ void write(Object obj) {
+ @patch void write(Object obj) {
String str = '$obj';
if (str.isEmpty) return;
_consumeBuffer();
_addPart(str);
}
- /* @patch */ void writeCharCode(int charCode) {
+ @patch void writeCharCode(int charCode) {
if (charCode <= 0xFFFF) {
if (charCode < 0) {
throw new RangeError.range(charCode, 0, 0x10FFFF);
@@ -81,7 +81,7 @@
}
}
- /* @patch */ void writeAll(Iterable objects, [String separator = ""]) {
+ @patch void writeAll(Iterable objects, [String separator = ""]) {
Iterator iterator = objects.iterator;
if (!iterator.moveNext()) return;
if (separator.isEmpty) {
@@ -97,19 +97,19 @@
}
}
- /* @patch */ void writeln([Object obj = ""]) {
+ @patch void writeln([Object obj = ""]) {
write(obj);
write("\n");
}
/** Makes the buffer empty. */
- /* @patch */ void clear() {
+ @patch void clear() {
_parts = null;
_partsCodeUnits = _bufferPosition = _bufferCodeUnitMagnitude = 0;
}
/** Returns the contents of buffer as a string. */
- /* @patch */ String toString() {
+ @patch String toString() {
_consumeBuffer();
return (_partsCodeUnits == 0) ?
"" :
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart
index e8b3642..17962df 100644
--- a/runtime/lib/string_patch.dart
+++ b/runtime/lib/string_patch.dart
@@ -8,15 +8,15 @@
const int _maxUnicode = 0x10ffff;
@patch class String {
- /* @patch */ factory String.fromCharCodes(Iterable<int> charCodes,
- [int start = 0, int end]) {
+ @patch factory String.fromCharCodes(Iterable<int> charCodes,
+ [int start = 0, int end]) {
if (charCodes is! Iterable) throw new ArgumentError.value(charCodes, "charCodes");
if (start is! int) throw new ArgumentError.value(start, "start");
if (end != null && end is! int) throw new ArgumentError.value(end, "end");
return _StringBase.createFromCharCodes(charCodes, start, end, null);
}
- /* @patch */ factory String.fromCharCode(int charCode) {
+ @patch factory String.fromCharCode(int charCode) {
if (charCode >= 0) {
if (charCode <= 0xff) {
return _OneByteString._allocate(1).._setAt(0, charCode);
@@ -37,8 +37,8 @@
throw new RangeError.range(charCode, 0, 0x10ffff);
}
- /* @patch */ const factory String.fromEnvironment(String name,
- {String defaultValue})
+ @patch const factory String.fromEnvironment(String name,
+ {String defaultValue})
native "String_fromEnvironment";
}
diff --git a/runtime/lib/symbol_patch.dart b/runtime/lib/symbol_patch.dart
index 4c70daa..ee52cfc 100644
--- a/runtime/lib/symbol_patch.dart
+++ b/runtime/lib/symbol_patch.dart
@@ -3,10 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
@patch class Symbol {
- /* @patch */ const Symbol(String name)
+ @patch const Symbol(String name)
: this._name = name;
- /* @patch */ toString() => 'Symbol("${getUnmangledName(this)}")';
+ @patch toString() => 'Symbol("${getUnmangledName(this)}")';
static getUnmangledName(Symbol symbol) {
String string = Symbol.getName(symbol);
@@ -52,7 +52,7 @@
return result.toString();
}
- /* @patch */ int get hashCode {
+ @patch int get hashCode {
const arbitraryPrime = 664597;
return 0x1fffffff & (arbitraryPrime * _name.hashCode);
}
diff --git a/runtime/lib/timer_patch.dart b/runtime/lib/timer_patch.dart
index a92db40..2351d1b 100644
--- a/runtime/lib/timer_patch.dart
+++ b/runtime/lib/timer_patch.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
@patch class Timer {
- /*@patch*/ static Timer _createTimer(Duration duration, void callback()) {
+ @patch static Timer _createTimer(Duration duration, void callback()) {
// TODO(iposva): Remove _TimerFactory and use VMLibraryHooks exclusively.
if (_TimerFactory._factory == null) {
_TimerFactory._factory = VMLibraryHooks.timerFactory;
@@ -16,7 +16,7 @@
return _TimerFactory._factory(milliseconds, (_) { callback(); }, false);
}
- /*@patch*/ static Timer _createPeriodicTimer(Duration duration,
+ @patch static Timer _createPeriodicTimer(Duration duration,
void callback(Timer timer)) {
// TODO(iposva): Remove _TimerFactory and use VMLibraryHooks exclusively.
if (_TimerFactory._factory == null) {
diff --git a/runtime/lib/uri_patch.dart b/runtime/lib/uri_patch.dart
index d4eb712..d309531 100644
--- a/runtime/lib/uri_patch.dart
+++ b/runtime/lib/uri_patch.dart
@@ -18,13 +18,13 @@
@patch class Uri {
static final bool _isWindowsCached = _isWindowsPlatform;
- /* @patch */ static bool get _isWindows => _isWindowsCached;
+ @patch static bool get _isWindows => _isWindowsCached;
- /* @patch */ static Uri get base => _uriBaseClosure();
+ @patch static Uri get base => _uriBaseClosure();
static bool get _isWindowsPlatform native "Uri_isWindowsPlatform";
- /* @patch */ static String _uriEncode(List<int> canonicalTable,
+ @patch static String _uriEncode(List<int> canonicalTable,
String text,
Encoding encoding,
bool spaceToPlus) {
diff --git a/runtime/lib/vmservice_patch.dart b/runtime/lib/vmservice_patch.dart
index e0a2e02..9e2dae6 100644
--- a/runtime/lib/vmservice_patch.dart
+++ b/runtime/lib/vmservice_patch.dart
@@ -4,7 +4,7 @@
@patch class Asset {
/// Call to request assets from the embedder.
- /* @patch */ static HashMap<String, Asset> request() {
+ @patch static HashMap<String, Asset> request() {
HashMap<String, Asset> assets = new HashMap<String, Asset>();
Uint8List tarBytes = _requestAssets();
if (tarBytes == null) {
diff --git a/runtime/observatory/lib/src/elements/class_view.dart b/runtime/observatory/lib/src/elements/class_view.dart
index 9f860a9..b101fbf 100644
--- a/runtime/observatory/lib/src/elements/class_view.dart
+++ b/runtime/observatory/lib/src/elements/class_view.dart
@@ -93,7 +93,7 @@
})
];
if (M.isSampleProcessRunning(progress.status)) {
- progress = await stream.last;
+ progress = (await stream.last).progress;
}
if (progress.status == M.SampleProfileLoadingStatus.loaded) {
shadowRoot.querySelector('#stackTraceTreeConfig')..children = [
diff --git a/runtime/observatory/lib/src/elements/containers/virtual_collection.dart b/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
index e45a143..049081d 100644
--- a/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
+++ b/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
@@ -106,8 +106,8 @@
_top = (scrollTop / _itemHeight).floor();
_scroller.style.height = '${_itemHeight*(_items.length)}px';
- _shifter.style.top = '${_itemHeight*_top}px';
final tail_length = (_height / _itemHeight / _preload).ceil();
+ _shifter.style.top = '${_itemHeight*(_top - tail_length)}px';
final length = tail_length * 2 + tail_length * _preload;
if (_shifter.children.length < length) {
@@ -116,7 +116,6 @@
e..style.display = 'hidden';
_shifter.children.add(e);
}
- _shifter.style.height = '${_itemHeight*length}px';
children = [
_scroller
..children = [_shifter]
@@ -152,7 +151,10 @@
}
void _onResize(_) {
- _height = getBoundingClientRect().height;
- _r.dirty();
+ final newHeight = getBoundingClientRect().height;
+ if (newHeight > _height) {
+ _height = newHeight;
+ _r.dirty();
+ }
}
}
diff --git a/runtime/observatory/lib/src/elements/css/shared.css b/runtime/observatory/lib/src/elements/css/shared.css
index 9e4a0f5..a72de8b 100644
--- a/runtime/observatory/lib/src/elements/css/shared.css
+++ b/runtime/observatory/lib/src/elements/css/shared.css
@@ -447,6 +447,7 @@
}
cpu-profile-virtual-tree .tree-item {
+ box-sizing: border-box;
line-height: 30px;
height: 30px;
padding-left: 5%;
@@ -753,6 +754,10 @@
/* sample-buffer-control */
+sample-buffer-control {
+ white-space: nowrap;
+}
+
sample-buffer-control .statusMessage {
font-size: 150%;
font-weight: bold;
@@ -781,6 +786,12 @@
0 2px 5px 0 rgba(0, 0, 0, 0.26);
}
+/* stack-trace-tree-config */
+
+stack-trace-tree-config {
+ white-space: nowrap;
+}
+
/* view-footer */
view-footer {
@@ -808,27 +819,22 @@
}
virtual-collection .scroller {
- position: relative;
overflow: hidden;
background: transparent;
+ display: inline-block;
+ min-width: 100%;
}
virtual-collection .shifter {
background: transparent;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
+ position: relative;
+ display: inline-block;
+ min-width: 100%;
}
virtual-collection .shifter > * {
- display: block;
- position: relative;
- top: -25%;
- width: 100%;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow-x: hidden;
+ display: inline-block;
+ min-width: 100%;
white-space: nowrap;
}
diff --git a/runtime/observatory/lib/src/elements/object_common.html b/runtime/observatory/lib/src/elements/object_common.html
index 0235248..299470c 100644
--- a/runtime/observatory/lib/src/elements/object_common.html
+++ b/runtime/observatory/lib/src/elements/object_common.html
@@ -65,7 +65,7 @@
</template>
<template repeat="{{ element in path['elements'] }}">
<div class="memberItem">
- <div class="memberName">[{{ element['index']}}]</div>
+ <div class="memberName">[{{ path['elements'].indexOf(element) }}]</div>
<div class="memberValue">
<template if="{{ element['parentField'] != null }}">
from <any-service-ref ref="{{ element['parentField'] }}"></any-service-ref> of
@@ -73,6 +73,9 @@
<template if="{{ element['parentListIndex'] != null }}">
from [{{ element['parentListIndex'] }}] of
</template>
+ <template if="{{ element['parentMapKey'] != null }}">
+ from [<any-service-ref ref="{{ element['parentMapKey'] }}"></any-service-ref>] of
+ </template>
<template if="{{ element['_parentWordOffset'] != null }}">
from word[{{ element['_parentWordOffset'] }}] of
</template>
diff --git a/runtime/observatory/tests/observatory_ui/observatory_ui.status b/runtime/observatory/tests/observatory_ui/observatory_ui.status
index 0675fff..fa2f2fd 100644
--- a/runtime/observatory/tests/observatory_ui/observatory_ui.status
+++ b/runtime/observatory/tests/observatory_ui/observatory_ui.status
@@ -4,3 +4,6 @@
[ $browser == false || $runtime == drt ]
*: SkipByDesign
+
+[ $runtime == dartium ]
+isolate/*: Skip
diff --git a/runtime/observatory/tests/service/eval_internal_class_test.dart b/runtime/observatory/tests/service/eval_internal_class_test.dart
new file mode 100644
index 0000000..1b08482
--- /dev/null
+++ b/runtime/observatory/tests/service/eval_internal_class_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+var tests = [
+
+(Isolate isolate) async {
+ Library root = await isolate.rootLibrary.load();
+
+ Class classLibrary = await root.clazz.load();
+ print(classLibrary);
+ var result = await classLibrary.evaluate('3 + 4');
+ print(result);
+ expect(result is DartError, isTrue);
+ expect(result.message, contains('Cannot evaluate'));
+
+ Class classClass = await classLibrary.clazz.load();
+ print(classClass);
+ result = await classClass.evaluate('3 + 4');
+ print(result);
+ expect(result is DartError, isTrue);
+ expect(result.message, contains('Cannot evaluate'));
+
+ var someArray = await root.evaluate("new List(2)");
+ print(someArray);
+ expect(someArray is Instance, isTrue);
+ Class classArray = await someArray.clazz.load();
+ print(classArray);
+ result = await classArray.evaluate('3 + 4');
+ print(result);
+ expect(result is Instance, isTrue);
+ expect(result.valueAsString, equals('7'));
+},
+
+];
+
+main(args) => runIsolateTests(args, tests);
diff --git a/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart b/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
index 74e98c9..c2b7fc1 100644
--- a/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
@@ -9,25 +9,27 @@
import 'test_helper.dart';
class _TestClass {
- _TestClass(this.x, this.y);
+ _TestClass();
var x;
var y;
}
-var target1;
-var target2;
-var target3;
-var globalObject;
-var globalList;
+var target1 = new _TestClass();
+var target2 = new _TestClass();
+var target3 = new _TestClass();
+var target4 = new _TestClass();
+var target5 = new _TestClass();
+var globalObject = new _TestClass();
+var globalList = new List(100);
+var globalMap1 = new Map();
+var globalMap2 = new Map();
void warmup() {
- target1 = new _TestClass(null, null);
- target2 = new _TestClass(null, null);
- globalObject = new _TestClass(target1, target2);
-
- target3 = new _TestClass(null, null);
- globalList = new List(100);
+ globalObject.x = target1;
+ globalObject.y = target2;
globalList[12] = target3;
+ globalMap1['key'] = target4;
+ globalMap2[target5] = 'value';
}
eval(Isolate isolate, String expression) async {
@@ -44,9 +46,10 @@
var obj = await eval(isolate, 'globalObject');
var params = {
'targetId': obj['id'],
- 'limit': 4,
+ 'limit': 100,
};
var result = await isolate.invokeRpcNoUpgrade('_getRetainingPath', params);
+ expect(result['elements'].length, equals(2));
expect(result['elements'][1]['value']['name'], equals('globalObject'));
},
@@ -74,10 +77,11 @@
isolate, '() { var tmp = target1; target1 = null; return tmp;} ()');
var params = {
'targetId': target1['id'],
- 'limit': 4,
+ 'limit': 100,
};
var result = await isolate.invokeRpcNoUpgrade('_getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
+ expect(result['elements'].length, equals(3));
expect(result['elements'][1]['parentField']['name'], equals('x'));
expect(result['elements'][2]['value']['name'], equals('globalObject'));
},
@@ -87,10 +91,11 @@
isolate, '() { var tmp = target2; target2 = null; return tmp;} ()');
var params = {
'targetId': target2['id'],
- 'limit': 4,
+ 'limit': 100,
};
var result = await isolate.invokeRpcNoUpgrade('_getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
+ expect(result['elements'].length, equals(3));
expect(result['elements'][1]['parentField']['name'], equals('y'));
expect(result['elements'][2]['value']['name'], equals('globalObject'));
},
@@ -100,13 +105,44 @@
isolate, '() { var tmp = target3; target3 = null; return tmp;} ()');
var params = {
'targetId': target3['id'],
- 'limit': 4,
+ 'limit': 100,
};
var result = await isolate.invokeRpcNoUpgrade('_getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
+ expect(result['elements'].length, equals(3));
expect(result['elements'][1]['parentListIndex'], equals(12));
expect(result['elements'][2]['value']['name'], equals('globalList'));
},
+
+ (Isolate isolate) async {
+ var target4 = await eval(
+ isolate, '() { var tmp = target4; target4 = null; return tmp;} ()');
+ var params = {
+ 'targetId': target4['id'],
+ 'limit': 100,
+ };
+ var result = await isolate.invokeRpcNoUpgrade('_getRetainingPath', params);
+ expect(result['type'], equals('RetainingPath'));
+ expect(result['elements'].length, equals(3));
+ expect(result['elements'][1]['parentMapKey']['valueAsString'],
+ equals('key'));
+ expect(result['elements'][2]['value']['name'], equals('globalMap1'));
+ },
+
+ (Isolate isolate) async {
+ var target5 = await eval(
+ isolate, '() { var tmp = target5; target5 = null; return tmp;} ()');
+ var params = {
+ 'targetId': target5['id'],
+ 'limit': 100,
+ };
+ var result = await isolate.invokeRpcNoUpgrade('_getRetainingPath', params);
+ expect(result['type'], equals('RetainingPath'));
+ expect(result['elements'].length, equals(3));
+ expect(result['elements'][1]['parentMapKey']['class']['name'],
+ equals('_TestClass'));
+ expect(result['elements'][2]['value']['name'], equals('globalMap2'));
+ }
];
main(args) async => runIsolateTests(args, tests, testeeBefore:warmup);
diff --git a/runtime/platform/hashmap.cc b/runtime/platform/hashmap.cc
index 693367f..34f7ea1 100644
--- a/runtime/platform/hashmap.cc
+++ b/runtime/platform/hashmap.cc
@@ -15,7 +15,7 @@
HashMap::~HashMap() {
- free(map_);
+ delete[] map_;
}
@@ -106,14 +106,19 @@
// Clear the candidate which will not break searching the hash table.
candidate->key = NULL;
+ candidate->value = NULL;
occupancy_--;
}
-void HashMap::Clear() {
+void HashMap::Clear(ClearFun clear) {
// Mark all entries as empty.
const Entry* end = map_end();
for (Entry* p = map_; p < end; p++) {
+ if ((clear != NULL) && (p->key != NULL)) {
+ clear(p->value);
+ }
+ p->value = NULL;
p->key = NULL;
}
occupancy_ = 0;
@@ -159,14 +164,14 @@
void HashMap::Initialize(uint32_t capacity) {
ASSERT(dart::Utils::IsPowerOfTwo(capacity));
- map_ = reinterpret_cast<Entry*>(malloc(capacity * sizeof(Entry)));
+ map_ = new Entry[capacity];
if (map_ == NULL) {
// TODO(sgjesse): Handle out of memory.
FATAL("Cannot allocate memory for hashmap");
return;
}
capacity_ = capacity;
- Clear();
+ occupancy_ = 0;
}
@@ -186,7 +191,7 @@
}
// Delete old map.
- free(map);
+ delete[] map;
}
} // namespace dart
diff --git a/runtime/platform/hashmap.h b/runtime/platform/hashmap.h
index d5a0293..185c75f 100644
--- a/runtime/platform/hashmap.h
+++ b/runtime/platform/hashmap.h
@@ -13,6 +13,14 @@
public:
typedef bool (*MatchFun) (void* key1, void* key2);
+ typedef void (*ClearFun) (void* value);
+
+ // initial_capacity is the size of the initial hash map;
+ // it must be a power of 2 (and thus must not be 0).
+ HashMap(MatchFun match, uint32_t initial_capacity);
+
+ ~HashMap();
+
static bool SamePointerValue(void* key1, void* key2) {
return key1 == key2;
}
@@ -37,17 +45,11 @@
reinterpret_cast<char*>(key2)) == 0;
}
-
- // initial_capacity is the size of the initial hash map;
- // it must be a power of 2 (and thus must not be 0).
- HashMap(MatchFun match, uint32_t initial_capacity);
-
- ~HashMap();
-
// HashMap entries are (key, value, hash) triplets.
// Some clients may not need to use the value slot
// (e.g. implementers of sets, where the key is the value).
struct Entry {
+ Entry() : key(NULL), value(NULL), hash(0) {}
void* key;
void* value;
uint32_t hash; // The full hash value for key.
@@ -63,8 +65,12 @@
// Removes the entry with matching key.
void Remove(void* key, uint32_t hash);
- // Empties the hash map (occupancy() == 0).
- void Clear();
+ // Empties the hash map (occupancy() == 0), and calls the function 'clear' on
+ // each of the values if given.
+ void Clear(ClearFun clear = NULL);
+
+ // The number of entries stored in the table.
+ intptr_t size() const { return occupancy_; }
// The capacity of the table. The implementation
// makes sure that occupancy is at most 80% of
@@ -94,6 +100,7 @@
void Resize();
friend class IntSet; // From hashmap_test.cc
+ DISALLOW_COPY_AND_ASSIGN(HashMap);
};
} // namespace dart
diff --git a/runtime/vm/assembler.h b/runtime/vm/assembler.h
index ceaadaa..36279fb 100644
--- a/runtime/vm/assembler.h
+++ b/runtime/vm/assembler.h
@@ -175,6 +175,8 @@
// Returns the position in the instruction stream.
intptr_t GetPosition() const { return cursor_ - contents_; }
+ void Reset() { cursor_ = contents_; }
+
private:
// The limit is set to kMinimumGap bytes before the end of the data area.
// This leaves enough space for the longest possible instruction and allows
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index db7881d..e768806 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -3222,7 +3222,9 @@
ldr(PP, Address(FP, kSavedCallerPpSlotFromFp * kWordSize));
set_constant_pool_allowed(false);
}
- Drop(2); // Drop saved PP, PC marker.
+
+ // This will implicitly drop saved PP, PC marker due to restoring SP from FP
+ // first.
LeaveFrame((1 << FP) | (1 << LR));
}
@@ -3237,6 +3239,44 @@
}
+void Assembler::NoMonomorphicCheckedEntry() {
+ buffer_.Reset();
+ bkpt(0);
+ bkpt(0);
+ bkpt(0);
+ ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
+}
+
+
+// R0 receiver, R9 guarded cid as Smi
+void Assembler::MonomorphicCheckedEntry() {
+#if defined(TESTING) || defined(DEBUG)
+ bool saved_use_far_branches = use_far_branches();
+ set_use_far_branches(false);
+#endif
+
+ Label miss;
+ Bind(&miss);
+ ldr(CODE_REG, Address(THR, Thread::monomorphic_miss_stub_offset()));
+ ldr(IP, FieldAddress(CODE_REG, Code::entry_point_offset()));
+ bx(IP);
+
+ Comment("MonomorphicCheckedEntry");
+ ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
+ LoadClassIdMayBeSmi(R4, R0);
+ SmiUntag(R9);
+ cmp(R4, Operand(R9));
+ b(&miss, NE);
+
+ // Fall through to unchecked entry.
+ ASSERT(CodeSize() == Instructions::kUncheckedEntryOffset);
+
+#if defined(TESTING) || defined(DEBUG)
+ set_use_far_branches(saved_use_far_branches);
+#endif
+}
+
+
#ifndef PRODUCT
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 184f28d..3afce46 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -368,7 +368,9 @@
prologue_offset_(-1),
use_far_branches_(use_far_branches),
comments_(),
- constant_pool_allowed_(false) { }
+ constant_pool_allowed_(false) {
+ MonomorphicCheckedEntry();
+ }
~Assembler() { }
@@ -944,6 +946,9 @@
void EnterStubFrame();
void LeaveStubFrame();
+ void NoMonomorphicCheckedEntry();
+ void MonomorphicCheckedEntry();
+
// The register into which the allocation stats table is loaded with
// LoadAllocationStatsAddress should be passed to
// IncrementAllocationStats(WithSize) as stats_addr_reg to update the
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 705d8c8..72278e9 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -27,6 +27,7 @@
use_far_branches_(use_far_branches),
comments_(),
constant_pool_allowed_(false) {
+ MonomorphicCheckedEntry();
}
@@ -1237,6 +1238,53 @@
}
+void Assembler::NoMonomorphicCheckedEntry() {
+ buffer_.Reset();
+ brk(0);
+ brk(0);
+ brk(0);
+ brk(0);
+ brk(0);
+ brk(0);
+ ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
+}
+
+
+// R0 receiver, R5 guarded cid as Smi
+void Assembler::MonomorphicCheckedEntry() {
+ bool saved_use_far_branches = use_far_branches();
+ set_use_far_branches(false);
+
+ Label immediate, have_cid, miss;
+ Bind(&miss);
+ ldr(CODE_REG, Address(THR, Thread::monomorphic_miss_stub_offset()));
+ ldr(IP0, FieldAddress(CODE_REG, Code::entry_point_offset()));
+ br(IP0);
+ brk(0);
+
+ Bind(&immediate);
+ movz(R4, Immediate(kSmiCid), 0);
+ b(&have_cid);
+
+ Comment("MonomorphicCheckedEntry");
+ ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
+ tsti(R0, Immediate(kSmiTagMask));
+ SmiUntag(R5);
+ b(&immediate, EQ);
+
+ LoadClassId(R4, R0);
+
+ Bind(&have_cid);
+ cmp(R4, Operand(R5));
+ b(&miss, NE);
+
+ // Fall through to unchecked entry.
+ ASSERT(CodeSize() == Instructions::kUncheckedEntryOffset);
+
+ set_use_far_branches(saved_use_far_branches);
+}
+
+
#ifndef PRODUCT
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index c39e8e3..1f8edfa 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -488,7 +488,6 @@
}
void set_use_far_branches(bool b) {
- ASSERT(buffer_.Size() == 0);
use_far_branches_ = b;
}
@@ -1364,6 +1363,9 @@
void EnterStubFrame();
void LeaveStubFrame();
+ void NoMonomorphicCheckedEntry();
+ void MonomorphicCheckedEntry();
+
void UpdateAllocationStats(intptr_t cid,
Heap::Space space);
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index 954cea6..a85aa08 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -860,6 +860,40 @@
}
+void Assembler::NoMonomorphicCheckedEntry() {
+ buffer_.Reset();
+ break_(0);
+ break_(0);
+ break_(0);
+ break_(0);
+ ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
+}
+
+
+// T0 receiver, S5 guarded cid as Smi
+void Assembler::MonomorphicCheckedEntry() {
+ bool saved_use_far_branches = use_far_branches();
+ set_use_far_branches(false);
+
+ Label have_cid, miss;
+ Bind(&miss);
+ lw(CODE_REG, Address(THR, Thread::monomorphic_miss_stub_offset()));
+ lw(T9, FieldAddress(CODE_REG, Code::entry_point_offset()));
+ jr(T9);
+
+ Comment("MonomorphicCheckedEntry");
+ ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
+ SmiUntag(S5);
+ LoadClassIdMayBeSmi(S4, T0);
+ bne(S4, S5, &miss);
+
+ // Fall through to unchecked entry.
+ ASSERT(CodeSize() == Instructions::kUncheckedEntryOffset);
+
+ set_use_far_branches(saved_use_far_branches);
+}
+
+
#ifndef PRODUCT
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 87717b6..095fa74 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -243,7 +243,9 @@
delay_slot_available_(false),
in_delay_slot_(false),
comments_(),
- constant_pool_allowed_(true) { }
+ constant_pool_allowed_(true) {
+ MonomorphicCheckedEntry();
+ }
~Assembler() { }
void PopRegister(Register r) { Pop(r); }
@@ -280,7 +282,6 @@
}
void set_use_far_branches(bool b) {
- ASSERT(buffer_.Size() == 0);
use_far_branches_ = b;
}
@@ -295,6 +296,9 @@
// the branch delay slot.
void LeaveStubFrameAndReturn(Register ra = RA);
+ void NoMonomorphicCheckedEntry();
+ void MonomorphicCheckedEntry();
+
void UpdateAllocationStats(intptr_t cid,
Register temp_reg,
Heap::Space space);
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 1902779..74f0ece 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -28,6 +28,7 @@
constant_pool_allowed_(false) {
// Far branching mode is only needed and implemented for MIPS and ARM.
ASSERT(!use_far_branches);
+ MonomorphicCheckedEntry();
}
@@ -3321,6 +3322,45 @@
}
+void Assembler::NoMonomorphicCheckedEntry() {
+ buffer_.Reset();
+ for (intptr_t i = 0; i < Instructions::kCheckedEntryOffset; i++) {
+ int3();
+ }
+ ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
+}
+
+
+// RDI receiver, RBX guarded cid as Smi
+void Assembler::MonomorphicCheckedEntry() {
+ Label immediate, have_cid, miss;
+ Bind(&miss);
+ movq(CODE_REG, Address(THR, Thread::monomorphic_miss_stub_offset()));
+ movq(RCX, FieldAddress(CODE_REG, Code::entry_point_offset()));
+ jmp(RCX);
+
+ Bind(&immediate);
+ movq(R10, Immediate(kSmiCid));
+ jmp(&have_cid, kNearJump);
+
+ Comment("MonomorphicCheckedEntry");
+ ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
+ SmiUntag(RBX);
+ testq(RDI, Immediate(kSmiTagMask));
+ j(ZERO, &immediate, kNearJump);
+
+ LoadClassId(R10, RDI);
+
+ Bind(&have_cid);
+ cmpq(R10, RBX);
+ j(NOT_EQUAL, &miss, Assembler::kNearJump);
+
+ // Fall through to unchecked entry.
+ ASSERT(CodeSize() == Instructions::kUncheckedEntryOffset);
+ ASSERT((CodeSize() & kSmiTagMask) == kSmiTag);
+}
+
+
#ifndef PRODUCT
void Assembler::MaybeTraceAllocation(intptr_t cid,
Label* trace,
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index f4ce132..651fcd5 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -949,6 +949,10 @@
void EnterStubFrame();
void LeaveStubFrame();
+ void RawEntry() { buffer_.Reset(); }
+ void NoMonomorphicCheckedEntry();
+ void MonomorphicCheckedEntry();
+
void UpdateAllocationStats(intptr_t cid,
Heap::Space space);
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index 681a599..8a3c373 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -3113,6 +3113,8 @@
ASSEMBLER_TEST_GENERATE(TestNop, assembler) {
+ __ RawEntry();
+
__ nop(1);
__ nop(2);
__ nop(3);
@@ -3128,12 +3130,14 @@
ASSEMBLER_TEST_RUN(TestNop, test) {
typedef int (*TestNop)();
- int res = reinterpret_cast<TestNop>(test->entry())();
+ int res = reinterpret_cast<TestNop>(test->payload_start())();
EXPECT_EQ(36, res); // 36 nop bytes emitted.
}
ASSEMBLER_TEST_GENERATE(TestAlign0, assembler) {
+ __ RawEntry();
+
__ Align(4, 0);
__ movq(RAX, Immediate(assembler->CodeSize())); // Return code size.
__ ret();
@@ -3142,12 +3146,14 @@
ASSEMBLER_TEST_RUN(TestAlign0, test) {
typedef int (*TestAlign0)();
- int res = reinterpret_cast<TestAlign0>(test->entry())();
+ int res = reinterpret_cast<TestAlign0>(test->payload_start())();
EXPECT_EQ(0, res); // 0 bytes emitted.
}
ASSEMBLER_TEST_GENERATE(TestAlign1, assembler) {
+ __ RawEntry();
+
__ nop(1);
__ Align(4, 0);
__ movq(RAX, Immediate(assembler->CodeSize())); // Return code size.
@@ -3157,12 +3163,14 @@
ASSEMBLER_TEST_RUN(TestAlign1, test) {
typedef int (*TestAlign1)();
- int res = reinterpret_cast<TestAlign1>(test->entry())();
+ int res = reinterpret_cast<TestAlign1>(test->payload_start())();
EXPECT_EQ(4, res); // 4 bytes emitted.
}
ASSEMBLER_TEST_GENERATE(TestAlign1Offset1, assembler) {
+ __ RawEntry();
+
__ nop(1);
__ Align(4, 1);
__ movq(RAX, Immediate(assembler->CodeSize())); // Return code size.
@@ -3172,12 +3180,14 @@
ASSEMBLER_TEST_RUN(TestAlign1Offset1, test) {
typedef int (*TestAlign1Offset1)();
- int res = reinterpret_cast<TestAlign1Offset1>(test->entry())();
+ int res = reinterpret_cast<TestAlign1Offset1>(test->payload_start())();
EXPECT_EQ(3, res); // 3 bytes emitted.
}
ASSEMBLER_TEST_GENERATE(TestAlignLarge, assembler) {
+ __ RawEntry();
+
__ nop(1);
__ Align(16, 0);
__ movq(RAX, Immediate(assembler->CodeSize())); // Return code size.
@@ -3187,7 +3197,7 @@
ASSEMBLER_TEST_RUN(TestAlignLarge, test) {
typedef int (*TestAlignLarge)();
- int res = reinterpret_cast<TestAlignLarge>(test->entry())();
+ int res = reinterpret_cast<TestAlignLarge>(test->payload_start())();
EXPECT_EQ(16, res); // 16 bytes emitted.
}
diff --git a/runtime/vm/become.cc b/runtime/vm/become.cc
index accca31..0850584 100644
--- a/runtime/vm/become.cc
+++ b/runtime/vm/become.cc
@@ -192,6 +192,35 @@
}
+void Become::CrashDump(RawObject* before_obj, RawObject* after_obj) {
+ OS::PrintErr("DETECTED FATAL ISSUE IN BECOME MAPPINGS\n");
+
+ OS::PrintErr("BEFORE ADDRESS: %p\n", before_obj);
+ OS::PrintErr("BEFORE IS HEAP OBJECT: %s",
+ before_obj->IsHeapObject() ? "YES" : "NO");
+ OS::PrintErr("BEFORE IS VM HEAP OBJECT: %s",
+ before_obj->IsVMHeapObject() ? "YES" : "NO");
+
+ OS::PrintErr("AFTER ADDRESS: %p\n", after_obj);
+ OS::PrintErr("AFTER IS HEAP OBJECT: %s",
+ after_obj->IsHeapObject() ? "YES" : "NO");
+ OS::PrintErr("AFTER IS VM HEAP OBJECT: %s",
+ after_obj->IsVMHeapObject() ? "YES" : "NO");
+
+ if (before_obj->IsHeapObject()) {
+ OS::PrintErr("BEFORE OBJECT CLASS ID=%" Pd "\n", before_obj->GetClassId());
+ const Object& obj = Object::Handle(before_obj);
+ OS::PrintErr("BEFORE OBJECT AS STRING=%s\n", obj.ToCString());
+ }
+
+ if (after_obj->IsHeapObject()) {
+ OS::PrintErr("AFTER OBJECT CLASS ID=%" Pd "\n", after_obj->GetClassId());
+ const Object& obj = Object::Handle(after_obj);
+ OS::PrintErr("AFTER OBJECT AS STRING=%s\n", obj.ToCString());
+ }
+}
+
+
void Become::ElementsForwardIdentity(const Array& before, const Array& after) {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
@@ -210,12 +239,15 @@
FATAL("become: Cannot self-forward");
}
if (!before_obj->IsHeapObject()) {
+ CrashDump(before_obj, after_obj);
FATAL("become: Cannot forward immediates");
}
if (!after_obj->IsHeapObject()) {
- FATAL("become: Cannot become an immediates");
+ CrashDump(before_obj, after_obj);
+ FATAL("become: Cannot become immediates");
}
if (before_obj->IsVMHeapObject()) {
+ CrashDump(before_obj, after_obj);
FATAL("become: Cannot forward VM heap objects");
}
if (before_obj->IsForwardingCorpse() && !IsDummyObject(before_obj)) {
diff --git a/runtime/vm/become.h b/runtime/vm/become.h
index 8ce164e..12ab764 100644
--- a/runtime/vm/become.h
+++ b/runtime/vm/become.h
@@ -85,6 +85,9 @@
// making the instance independent of its class.
// (used for morphic instances during reload).
static void MakeDummyObject(const Instance& instance);
+
+ private:
+ static void CrashDump(RawObject* before_obj, RawObject* after_obj);
};
} // namespace dart
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index ed2ea00..334bca9 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -83,6 +83,12 @@
}
+void ClassTable::AddOldTable(RawClass** old_table) {
+ ASSERT(Thread::Current()->IsMutatorThread());
+ old_tables_->Add(old_table);
+}
+
+
void ClassTable::FreeOldTables() {
while (old_tables_->length() > 0) {
free(old_tables_->RemoveLast());
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index a7e38ba..1722dec 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -238,6 +238,7 @@
void PrintToJSONObject(JSONObject* object);
#endif // !PRODUCT
+ void AddOldTable(RawClass** old_table);
// Deallocates table copies. Do not call during concurrent access to table.
void FreeOldTables();
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 6f958fd..afacd26 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1519,9 +1519,10 @@
int32_t text_offset = d->Read<int32_t>();
RawInstructions* instr = reinterpret_cast<RawInstructions*>(
d->GetInstructionsAt(text_offset) + kHeapObjectTag);
- uword entry_point = Instructions::EntryPoint(instr);
- code->ptr()->entry_point_ = entry_point;
+ code->ptr()->entry_point_ = Instructions::UncheckedEntryPoint(instr);
+ code->ptr()->checked_entry_point_ =
+ Instructions::CheckedEntryPoint(instr);
code->ptr()->active_instructions_ = instr;
code->ptr()->instructions_ = instr;
code->ptr()->object_pool_ =
@@ -2141,7 +2142,7 @@
funcOrCode = ic.GetTargetOrCodeAt(j);
if (funcOrCode.IsCode()) {
code ^= funcOrCode.raw();
- entry_point = Smi::FromAlignedAddress(code.EntryPoint());
+ entry_point = Smi::FromAlignedAddress(code.UncheckedEntryPoint());
ic.SetEntryPointAt(j, entry_point);
}
}
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index bc9689c..ca1ba0b 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -671,7 +671,7 @@
" to '%s' new entry point %#" Px " (%s)\n",
caller_frame->pc(),
target_function.ToFullyQualifiedCString(),
- target_code.EntryPoint(),
+ target_code.UncheckedEntryPoint(),
target_code.is_optimized() ? "optimized" : "unoptimized");
}
arguments.SetReturn(target_code);
@@ -1028,12 +1028,88 @@
// Handle a miss of a megamorphic cache.
// Arg0: Receiver.
+// Returns: the ICData used to continue with a polymorphic call.
+DEFINE_RUNTIME_ENTRY(MonomorphicMiss, 1) {
+#if defined(TARGET_ARCH_DBC)
+ // DBC does not use switchable calls.
+ UNREACHABLE();
+#else
+ const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
+
+ DartFrameIterator iterator;
+ StackFrame* caller_frame = iterator.NextFrame();
+ ASSERT(caller_frame->IsDartFrame());
+ const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode());
+ const Function& caller_function =
+ Function::Handle(zone, caller_frame->LookupDartFunction());
+
+ Smi& old_expected_cid = Smi::Handle(zone);
+ old_expected_cid ^= CodePatcher::GetSwitchableCallDataAt(caller_frame->pc(),
+ caller_code);
+ const Code& old_target_code =
+ Code::Handle(CodePatcher::GetSwitchableCallTargetAt(caller_frame->pc(),
+ caller_code));
+ Function& old_target = Function::Handle(zone);
+ old_target ^= old_target_code.owner();
+
+ // We lost the original ICData when we patched to the monomorphic case.
+ const String& name = String::Handle(zone, old_target.name());
+ ASSERT(!old_target.HasOptionalParameters());
+ const Array& descriptor = Array::Handle(zone,
+ ArgumentsDescriptor::New(old_target.num_fixed_parameters()));
+ const ICData& ic_data =
+ ICData::Handle(zone, ICData::New(caller_function,
+ name,
+ descriptor,
+ Thread::kNoDeoptId,
+ 1, /* args_tested */
+ false /* static_call */));
+
+ // Add the first target.
+ ic_data.AddReceiverCheck(old_expected_cid.Value(), old_target);
+
+ // Maybe add the new target.
+ Class& cls = Class::Handle(zone, receiver.clazz());
+ ArgumentsDescriptor args_desc(descriptor);
+ Function& target_function = Function::Handle(zone,
+ Resolver::ResolveDynamicForReceiverClass(cls,
+ name,
+ args_desc));
+ if (target_function.IsNull()) {
+ target_function = InlineCacheMissHelper(receiver, descriptor, name);
+ }
+ if (target_function.IsNull()) {
+ ASSERT(!FLAG_lazy_dispatchers);
+ } else {
+ ic_data.AddReceiverCheck(receiver.GetClassId(), target_function);
+ }
+
+ // Patch to call through stub.
+ const Code& stub =
+ Code::Handle(zone, StubCode::ICLookupThroughCode_entry()->code());
+ ASSERT(!Isolate::Current()->compilation_allowed());
+ CodePatcher::PatchSwitchableCallAt(caller_frame->pc(),
+ caller_code,
+ ic_data,
+ stub);
+
+ // Return the ICData. The miss stub will jump to continue in the IC lookup
+ // stub.
+ arguments.SetReturn(ic_data);
+#endif // !defined(TARGET_ARCH_DBC)
+}
+
+
+// Handle a miss of a megamorphic cache.
+// Arg0: Receiver.
// Arg1: ICData or MegamorphicCache.
// Arg2: Arguments descriptor array.
// Returns: target function to call.
DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) {
-// DBC does not use megamorphic calls right now.
-#if !defined(TARGET_ARCH_DBC)
+#if defined(TARGET_ARCH_DBC)
+ // DBC does not use megamorphic calls right now.
+ UNREACHABLE();
+#else
const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
const Object& ic_data_or_cache = Object::Handle(zone, arguments.ArgAt(1));
const Array& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(2));
@@ -1067,21 +1143,58 @@
if (ic_data_or_cache.IsICData()) {
const ICData& ic_data = ICData::Cast(ic_data_or_cache);
- ic_data.AddReceiverCheck(receiver.GetClassId(), target_function);
- if (ic_data.NumberOfChecks() > FLAG_max_polymorphic_checks) {
- // Switch to megamorphic call.
- const MegamorphicCache& cache = MegamorphicCache::Handle(zone,
- MegamorphicCacheTable::Lookup(isolate, name, descriptor));
+
+ if ((ic_data.NumberOfChecks() == 0) &&
+ !target_function.HasOptionalParameters() &&
+ !Isolate::Current()->compilation_allowed()) {
+ // This call site is unlinked: transition to a monomorphic direct call.
+ // Note we cannot do this if the target has optional parameters because
+ // the monomorphic direct call does not load the arguments descriptor.
+ // We cannot do this if we are still in the middle of precompiling because
+ // the monomorphic case hides an live instance selector from the
+ // treeshaker.
+
+ if (!target_function.HasCode()) {
+ const Error& error =
+ Error::Handle(Compiler::CompileFunction(thread, target_function));
+ if (!error.IsNull()) {
+ Exceptions::PropagateError(error);
+ }
+ }
+
DartFrameIterator iterator;
StackFrame* miss_function_frame = iterator.NextFrame();
ASSERT(miss_function_frame->IsDartFrame());
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame->IsDartFrame());
- const Code& code = Code::Handle(zone, caller_frame->LookupDartCode());
- const Code& stub =
- Code::Handle(zone, StubCode::MegamorphicLookup_entry()->code());
- CodePatcher::PatchSwitchableCallAt(caller_frame->pc(),
- code, ic_data, cache, stub);
+ const Code& caller_code =
+ Code::Handle(zone, caller_frame->LookupDartCode());
+ const Code& target_code =
+ Code::Handle(zone, target_function.CurrentCode());
+ const Smi& expected_cid =
+ Smi::Handle(zone, Smi::New(receiver.GetClassId()));
+
+ CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code,
+ expected_cid, target_code);
+ } else {
+ ic_data.AddReceiverCheck(receiver.GetClassId(), target_function);
+ if (ic_data.NumberOfChecks() > FLAG_max_polymorphic_checks) {
+ // Switch to megamorphic call.
+ const MegamorphicCache& cache = MegamorphicCache::Handle(zone,
+ MegamorphicCacheTable::Lookup(isolate, name, descriptor));
+ DartFrameIterator iterator;
+ StackFrame* miss_function_frame = iterator.NextFrame();
+ ASSERT(miss_function_frame->IsDartFrame());
+ StackFrame* caller_frame = iterator.NextFrame();
+ ASSERT(caller_frame->IsDartFrame());
+ const Code& caller_code =
+ Code::Handle(zone, caller_frame->LookupDartCode());
+ const Code& stub =
+ Code::Handle(zone, StubCode::MegamorphicLookup_entry()->code());
+
+ CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code,
+ cache, stub);
+ }
}
} else {
const MegamorphicCache& cache = MegamorphicCache::Cast(ic_data_or_cache);
@@ -1091,8 +1204,6 @@
cache.Insert(class_id, target_function);
}
arguments.SetReturn(target_function);
-#else
- UNREACHABLE();
#endif // !defined(TARGET_ARCH_DBC)
}
@@ -1461,7 +1572,7 @@
// unoptimized code. Patch the stack frame to return into the OSR
// code.
uword optimized_entry =
- Instructions::Handle(optimized_code.instructions()).EntryPoint();
+ Instructions::UncheckedEntryPoint(optimized_code.instructions());
function.AttachCode(original_code);
frame->set_pc(optimized_entry);
frame->set_pc_marker(optimized_code.raw());
@@ -1596,7 +1707,7 @@
"target '%s' -> %#" Px "\n",
frame->pc(),
target_function.ToFullyQualifiedCString(),
- current_target_code.EntryPoint());
+ current_target_code.UncheckedEntryPoint());
}
arguments.SetReturn(current_target_code);
}
@@ -1638,7 +1749,7 @@
" -> %#" Px "\n",
frame->pc(),
alloc_class.ToCString(),
- alloc_stub.EntryPoint());
+ alloc_stub.UncheckedEntryPoint());
}
arguments.SetReturn(alloc_stub);
#else
@@ -1690,7 +1801,7 @@
const Instructions& instrs =
Instructions::Handle(zone, optimized_code.instructions());
{
- WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
+ WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size());
CodePatcher::InsertDeoptimizationCallAt(pc, lazy_deopt_jump);
}
if (FLAG_trace_patching) {
diff --git a/runtime/vm/code_patcher.h b/runtime/vm/code_patcher.h
index ebcdeaa..bde916f 100644
--- a/runtime/vm/code_patcher.h
+++ b/runtime/vm/code_patcher.h
@@ -75,10 +75,13 @@
const Code& new_target);
static void PatchSwitchableCallAt(uword return_address,
- const Code& code,
- const ICData& ic_data,
- const MegamorphicCache& new_cache,
- const Code& lookup_stub);
+ const Code& caller_code,
+ const Object& data,
+ const Code& target);
+ static RawObject* GetSwitchableCallDataAt(uword return_address,
+ const Code& caller_code);
+ static RawCode* GetSwitchableCallTargetAt(uword return_address,
+ const Code& caller_code);
static RawCode* GetNativeCallAt(uword return_address,
const Code& code,
diff --git a/runtime/vm/code_patcher_arm.cc b/runtime/vm/code_patcher_arm.cc
index 7e0e8ea..62775bf 100644
--- a/runtime/vm/code_patcher_arm.cc
+++ b/runtime/vm/code_patcher_arm.cc
@@ -70,15 +70,29 @@
void CodePatcher::PatchSwitchableCallAt(uword return_address,
- const Code& code,
- const ICData& ic_data,
- const MegamorphicCache& cache,
- const Code& lookup_stub) {
- ASSERT(code.ContainsInstructionAt(return_address));
- SwitchableCallPattern call(return_address, code);
- ASSERT(call.cache() == ic_data.raw());
- call.SetLookupStub(lookup_stub);
- call.SetCache(cache);
+ const Code& caller_code,
+ const Object& data,
+ const Code& target) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ call.SetData(data);
+ call.SetTarget(target);
+}
+
+
+RawCode* CodePatcher::GetSwitchableCallTargetAt(uword return_address,
+ const Code& caller_code) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ return call.target();
+}
+
+
+RawObject* CodePatcher::GetSwitchableCallDataAt(uword return_address,
+ const Code& caller_code) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ return call.data();
}
diff --git a/runtime/vm/code_patcher_arm64.cc b/runtime/vm/code_patcher_arm64.cc
index 53f26ed..76b959b 100644
--- a/runtime/vm/code_patcher_arm64.cc
+++ b/runtime/vm/code_patcher_arm64.cc
@@ -110,15 +110,29 @@
void CodePatcher::PatchSwitchableCallAt(uword return_address,
- const Code& code,
- const ICData& ic_data,
- const MegamorphicCache& cache,
- const Code& lookup_stub) {
- ASSERT(code.ContainsInstructionAt(return_address));
- SwitchableCallPattern call(return_address, code);
- ASSERT(call.cache() == ic_data.raw());
- call.SetLookupStub(lookup_stub);
- call.SetCache(cache);
+ const Code& caller_code,
+ const Object& data,
+ const Code& target) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ call.SetData(data);
+ call.SetTarget(target);
+}
+
+
+RawCode* CodePatcher::GetSwitchableCallTargetAt(uword return_address,
+ const Code& caller_code) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ return call.target();
+}
+
+
+RawObject* CodePatcher::GetSwitchableCallDataAt(uword return_address,
+ const Code& caller_code) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ return call.data();
}
diff --git a/runtime/vm/code_patcher_arm64_test.cc b/runtime/vm/code_patcher_arm64_test.cc
index b1cdfdd..af3417f 100644
--- a/runtime/vm/code_patcher_arm64_test.cc
+++ b/runtime/vm/code_patcher_arm64_test.cc
@@ -53,8 +53,8 @@
ASSEMBLER_TEST_RUN(IcDataAccess, test) {
- uword return_address =
- test->entry() + test->code().Size() - Instr::kInstrSize;
+ uword end = test->payload_start() + test->code().Size();
+ uword return_address = end - Instr::kInstrSize;
ICData& ic_data = ICData::Handle();
CodePatcher::GetInstanceCallAt(return_address, test->code(), &ic_data);
EXPECT_STREQ("targetFunction",
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index 3671eb8..f63c546 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -53,8 +53,8 @@
ASSEMBLER_TEST_RUN(IcDataAccess, test) {
- uword return_address =
- test->entry() + test->code().Size() - Instr::kInstrSize;
+ uword end = test->payload_start() + test->code().Size();
+ uword return_address = end - Instr::kInstrSize;
ICData& ic_data = ICData::Handle();
CodePatcher::GetInstanceCallAt(return_address, test->code(), &ic_data);
EXPECT_STREQ("targetFunction",
diff --git a/runtime/vm/code_patcher_dbc.cc b/runtime/vm/code_patcher_dbc.cc
index 6a273ac..327b27f 100644
--- a/runtime/vm/code_patcher_dbc.cc
+++ b/runtime/vm/code_patcher_dbc.cc
@@ -68,15 +68,29 @@
void CodePatcher::PatchSwitchableCallAt(uword return_address,
- const Code& code,
- const ICData& ic_data,
- const MegamorphicCache& cache,
- const Code& lookup_stub) {
- ASSERT(code.ContainsInstructionAt(return_address));
- SwitchableCallPattern call(return_address, code);
- ASSERT(call.cache() == ic_data.raw());
- call.SetLookupStub(lookup_stub);
- call.SetCache(cache);
+ const Code& caller_code,
+ const Object& data,
+ const Code& target) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ call.SetData(data);
+ call.SetTarget(target);
+}
+
+
+RawCode* CodePatcher::GetSwitchableCallTargetAt(uword return_address,
+ const Code& caller_code) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ return call.target();
+}
+
+
+RawObject* CodePatcher::GetSwitchableCallDataAt(uword return_address,
+ const Code& caller_code) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ return call.data();
}
diff --git a/runtime/vm/code_patcher_ia32.cc b/runtime/vm/code_patcher_ia32.cc
index 90f1876..db04cdf 100644
--- a/runtime/vm/code_patcher_ia32.cc
+++ b/runtime/vm/code_patcher_ia32.cc
@@ -170,7 +170,7 @@
const Code& code,
const Code& new_target) {
const Instructions& instrs = Instructions::Handle(code.instructions());
- WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
+ WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size());
ASSERT(code.ContainsInstructionAt(return_address));
StaticCall call(return_address);
call.set_target(new_target);
@@ -212,15 +212,30 @@
void CodePatcher::PatchSwitchableCallAt(uword return_address,
- const Code& code,
- const ICData& ic_data,
- const MegamorphicCache& cache,
- const Code& lookup_stub) {
+ const Code& caller_code,
+ const Object& data,
+ const Code& target) {
// Switchable instance calls only generated for precompilation.
UNREACHABLE();
}
+RawCode* CodePatcher::GetSwitchableCallTargetAt(uword return_address,
+ const Code& caller_code) {
+ // Switchable instance calls only generated for precompilation.
+ UNREACHABLE();
+ return Code::null();
+}
+
+
+RawObject* CodePatcher::GetSwitchableCallDataAt(uword return_address,
+ const Code& caller_code) {
+ // Switchable instance calls only generated for precompilation.
+ UNREACHABLE();
+ return Object::null();
+}
+
+
void CodePatcher::PatchNativeCallAt(uword return_address,
const Code& code,
NativeFunction target,
diff --git a/runtime/vm/code_patcher_mips.cc b/runtime/vm/code_patcher_mips.cc
index 4c8ab99..a4d0433 100644
--- a/runtime/vm/code_patcher_mips.cc
+++ b/runtime/vm/code_patcher_mips.cc
@@ -69,15 +69,29 @@
void CodePatcher::PatchSwitchableCallAt(uword return_address,
- const Code& code,
- const ICData& ic_data,
- const MegamorphicCache& cache,
- const Code& lookup_stub) {
- ASSERT(code.ContainsInstructionAt(return_address));
- SwitchableCallPattern call(return_address, code);
- ASSERT(call.cache() == ic_data.raw());
- call.SetLookupStub(lookup_stub);
- call.SetCache(cache);
+ const Code& caller_code,
+ const Object& data,
+ const Code& target) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ call.SetData(data);
+ call.SetTarget(target);
+}
+
+
+RawCode* CodePatcher::GetSwitchableCallTargetAt(uword return_address,
+ const Code& caller_code) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ return call.target();
+}
+
+
+RawObject* CodePatcher::GetSwitchableCallDataAt(uword return_address,
+ const Code& caller_code) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, caller_code);
+ return call.data();
}
diff --git a/runtime/vm/code_patcher_mips_test.cc b/runtime/vm/code_patcher_mips_test.cc
index b6d4109..8e07b77 100644
--- a/runtime/vm/code_patcher_mips_test.cc
+++ b/runtime/vm/code_patcher_mips_test.cc
@@ -50,8 +50,8 @@
ASSEMBLER_TEST_RUN(IcDataAccess, test) {
- uword return_address =
- test->entry() + test->code().Size() - 2 * Instr::kInstrSize;
+ uword end = test->payload_start() + test->code().Size();
+ uword return_address = end - 2 * Instr::kInstrSize;
ICData& ic_data = ICData::Handle();
CodePatcher::GetInstanceCallAt(return_address, test->code(), &ic_data);
EXPECT_STREQ("targetFunction",
diff --git a/runtime/vm/code_patcher_x64.cc b/runtime/vm/code_patcher_x64.cc
index b8863dc..0e18f6f 100644
--- a/runtime/vm/code_patcher_x64.cc
+++ b/runtime/vm/code_patcher_x64.cc
@@ -190,10 +190,11 @@
};
-// Instance call that can switch from an IC call to a megamorphic call
-// load ICData load MegamorphicCache
-// call ICLookup stub -> call MegamorphicLookup stub
-// call target call target
+// Instance call that can switch between a direct monomorphic call, an IC call,
+// and a megamorphic call.
+// load guarded cid load ICData load MegamorphicCache
+// load monomorphic target <-> load ICLookup stub -> load MMLookup stub
+// call target.entry call stub.entry call stub.entry
class SwitchableCall : public ValueObject {
public:
SwitchableCall(uword return_address, const Code& code)
@@ -202,39 +203,42 @@
ASSERT(IsValid());
}
- static const int kCallPatternSize = 24;
+ static const int kCallPatternSize = 21;
bool IsValid() const {
static int16_t pattern[kCallPatternSize] = {
0x49, 0x8b, 0x9f, -1, -1, -1, -1, // movq rbx, [PP + cache_offs]
0x4d, 0x8b, 0xa7, -1, -1, -1, -1, // movq r12, [PP + code_offs]
- 0x4d, 0x8b, 0x5c, 0x24, 0x07, // movq r11, [r12 + entrypoint_off]
- 0x41, 0xff, 0xd3, // call r11
+ 0x49, 0x8b, 0x4c, 0x24, 0x0f, // movq rcx, [r12 + entrypoint_off]
0xff, 0xd1, // call rcx
};
+ ASSERT(ARRAY_SIZE(pattern) == kCallPatternSize);
return MatchesPattern(start_, pattern, kCallPatternSize);
}
- intptr_t cache_index() const {
+ intptr_t data_index() const {
return IndexFromPPLoad(start_ + 3);
}
- intptr_t lookup_stub_index() const {
+ intptr_t target_index() const {
return IndexFromPPLoad(start_ + 10);
}
- RawObject* cache() const {
- return object_pool_.ObjectAt(cache_index());
+ RawObject* data() const {
+ return object_pool_.ObjectAt(data_index());
+ }
+ RawCode* target() const {
+ return reinterpret_cast<RawCode*>(object_pool_.ObjectAt(target_index()));
}
- void SetCache(const MegamorphicCache& cache) const {
- ASSERT(Object::Handle(object_pool_.ObjectAt(cache_index())).IsICData());
- object_pool_.SetObjectAt(cache_index(), cache);
+ void SetData(const Object& data) const {
+ ASSERT(!Object::Handle(object_pool_.ObjectAt(data_index())).IsCode());
+ object_pool_.SetObjectAt(data_index(), data);
// No need to flush the instruction cache, since the code is not modified.
}
- void SetLookupStub(const Code& lookup_stub) const {
- ASSERT(Object::Handle(object_pool_.ObjectAt(lookup_stub_index())).IsCode());
- object_pool_.SetObjectAt(lookup_stub_index(), lookup_stub);
+ void SetTarget(const Code& target) const {
+ ASSERT(Object::Handle(object_pool_.ObjectAt(target_index())).IsCode());
+ object_pool_.SetObjectAt(target_index(), target);
// No need to flush the instruction cache, since the code is not modified.
}
@@ -313,15 +317,29 @@
void CodePatcher::PatchSwitchableCallAt(uword return_address,
- const Code& code,
- const ICData& ic_data,
- const MegamorphicCache& cache,
- const Code& lookup_stub) {
- ASSERT(code.ContainsInstructionAt(return_address));
- SwitchableCall call(return_address, code);
- ASSERT(call.cache() == ic_data.raw());
- call.SetLookupStub(lookup_stub);
- call.SetCache(cache);
+ const Code& caller_code,
+ const Object& data,
+ const Code& target) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCall call(return_address, caller_code);
+ call.SetData(data);
+ call.SetTarget(target);
+}
+
+
+RawCode* CodePatcher::GetSwitchableCallTargetAt(uword return_address,
+ const Code& caller_code) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCall call(return_address, caller_code);
+ return call.target();
+}
+
+
+RawObject* CodePatcher::GetSwitchableCallDataAt(uword return_address,
+ const Code& caller_code) {
+ ASSERT(caller_code.ContainsInstructionAt(return_address));
+ SwitchableCall call(return_address, caller_code);
+ return call.data();
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index ca099b5..ace33b0 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -1324,7 +1324,7 @@
if (trace_compiler && success) {
THR_Print("--> '%s' entry: %#" Px " size: %" Pd " time: %" Pd64 " us\n",
function.ToFullyQualifiedCString(),
- Code::Handle(function.CurrentCode()).EntryPoint(),
+ Code::Handle(function.CurrentCode()).PayloadStart(),
Code::Handle(function.CurrentCode()).Size(),
per_compile_timer.TotalElapsedTime());
}
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index b7348e4..d8a9299 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -6842,39 +6842,39 @@
"external void set topLevelSetter(int value);\n";
const char* kPatchChars =
- "patch class A {\n"
+ "@patch class A {\n"
" var _g;\n"
" A() : fvalue = 13;\n"
" get _field => _g;\n"
- " /*patch*/ void method(var value) {\n"
+ " @patch void method(var value) {\n"
" int closeYourEyes(var eggs) { return eggs * -1; }\n"
" value = callFunc(closeYourEyes, value);\n"
" _g = value * 5;\n"
" }\n"
"}\n"
- "patch class B {\n"
+ "@patch class B {\n"
" B._internal(x) : val = x;\n"
- " /*patch*/ factory B.named(x) { return new B._internal(x); }\n"
- " /*patch*/ factory B(v) native \"const_B_factory\";\n"
+ " @patch factory B.named(x) { return new B._internal(x); }\n"
+ " @patch factory B(v) native \"const_B_factory\";\n"
"}\n"
"var _topLevelValue = -1;\n"
- "patch int topLevel(var value) => value * value;\n"
- "patch int set topLevelSetter(value) { _topLevelValue = value; }\n"
- "patch int get topLevelGetter => 2 * _topLevelValue;\n"
+ "@patch int topLevel(var value) => value * value;\n"
+ "@patch int set topLevelSetter(value) { _topLevelValue = value; }\n"
+ "@patch int get topLevelGetter => 2 * _topLevelValue;\n"
// Allow top level methods named patch.
"patch(x) => x*3;\n"
; // NOLINT
const char* kPatchClassOnlyChars =
- "patch class C {\n"
- " /*patch*/ int method() {\n"
+ "@patch class C {\n"
+ " @patch int method() {\n"
" return 42;\n"
" }\n"
"}\n"
; // NOLINT
const char* kPatchNoClassChars =
- "patch topLevel2(x) => x * 2;\n";
+ "@patch topLevel2(x) => x * 2;\n";
const char* kScriptChars =
"import 'theLibrary';\n"
@@ -10059,9 +10059,9 @@
"foomoo() { A.moo(); }\n";
const char* kScriptChars2 =
- "patch class A {\n"
- " /* patch */ int zoo() { return 1; }\n"
- " /* patch */ static int moo() { return 1; }\n"
+ "@patch class A {\n"
+ " @patch int zoo() { return 1; }\n"
+ " @patch static int moo() { return 1; }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars1, NULL);
@@ -10099,9 +10099,9 @@
"foozoo() { new A().zoo(); }\n";
const char* kScriptChars2 =
- "patch class A {\n"
- " /* patch */ int zoo() { return 1; }\n"
- " /* patch */ int fld1;\n"
+ "@patch class A {\n"
+ " @patch int zoo() { return 1; }\n"
+ " @patch int fld1;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars1, NULL);
@@ -10136,8 +10136,8 @@
"foozoo() { new A().zoo(); }\n";
const char* kScriptChars2 =
- "patch class A {\n"
- " /* patch */ int zoo() { return 1; }\n"
+ "@patch class A {\n"
+ " @patch int zoo() { return 1; }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars1, NULL);
@@ -10173,8 +10173,8 @@
"foozoo() { new A().zoo(); }\n";
const char* kScriptChars2 =
- "patch class A {\n"
- " /* patch */ int zoo() { return 1; }\n"
+ "@patch class A {\n"
+ " @patch int zoo() { return 1; }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars1, NULL);
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 6b50583..155512a 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -519,7 +519,7 @@
token_pos_ = TokenPosition::kNoSource;
GetPcDescriptors();
PcDescriptors::Iterator iter(pc_desc_, RawPcDescriptors::kAnyKind);
- uword pc_offset = pc_ - code().EntryPoint();
+ uword pc_offset = pc_ - code().PayloadStart();
while (iter.MoveNext()) {
if (iter.PcOffset() == pc_offset) {
try_index_ = iter.TryIndex();
@@ -1528,7 +1528,7 @@
if (!function.IsNull() && function.is_visible()) {
code = ex_trace.CodeAtFrame(i);
ASSERT(function.raw() == code.function());
- uword pc = code.EntryPoint() + Smi::Value(ex_trace.PcOffsetAtFrame(i));
+ uword pc = code.PayloadStart() + Smi::Value(ex_trace.PcOffsetAtFrame(i));
if (code.is_optimized() && ex_trace.expand_inlined()) {
// Traverse inlined frames.
for (InlinedFunctionsIterator it(code, pc); !it.Done(); it.Advance()) {
@@ -1537,8 +1537,8 @@
ASSERT(function.raw() == code.function());
uword pc = it.pc();
ASSERT(pc != 0);
- ASSERT(code.EntryPoint() <= pc);
- ASSERT(pc < (code.EntryPoint() + code.Size()));
+ ASSERT(code.PayloadStart() <= pc);
+ ASSERT(pc < (code.PayloadStart() + code.Size()));
ActivationFrame* activation = new ActivationFrame(
pc, fp, sp, code, deopt_frame, deopt_frame_offset);
@@ -1828,7 +1828,7 @@
if (lowest_pc_offset == kUwordMax) {
return;
}
- uword lowest_pc = code.EntryPoint() + lowest_pc_offset;
+ uword lowest_pc = code.PayloadStart() + lowest_pc_offset;
CodeBreakpoint* code_bpt = GetCodeBreakpoint(lowest_pc);
if (code_bpt == NULL) {
// No code breakpoint for this code exists; create one.
diff --git a/runtime/vm/debugger_dbc.cc b/runtime/vm/debugger_dbc.cc
index b4b6c1f..ac21678 100644
--- a/runtime/vm/debugger_dbc.cc
+++ b/runtime/vm/debugger_dbc.cc
@@ -35,7 +35,7 @@
const Code& code = Code::Handle(code_);
const Instructions& instrs = Instructions::Handle(code.instructions());
{
- WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
+ WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size());
saved_value_ = *CallInstructionFromReturnAddress(pc_);
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
@@ -80,7 +80,7 @@
const Code& code = Code::Handle(code_);
const Instructions& instrs = Instructions::Handle(code.instructions());
{
- WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
+ WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size());
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall:
diff --git a/runtime/vm/debugger_ia32.cc b/runtime/vm/debugger_ia32.cc
index 9c4473b..c900f75 100644
--- a/runtime/vm/debugger_ia32.cc
+++ b/runtime/vm/debugger_ia32.cc
@@ -30,7 +30,7 @@
const Instructions& instrs = Instructions::Handle(code.instructions());
Code& stub_target = Code::Handle();
{
- WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
+ WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size());
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall: {
@@ -57,7 +57,7 @@
const Code& code = Code::Handle(code_);
const Instructions& instrs = Instructions::Handle(code.instructions());
{
- WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
+ WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size());
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall:
diff --git a/runtime/vm/disassembler.cc b/runtime/vm/disassembler.cc
index a735289..abf9c84 100644
--- a/runtime/vm/disassembler.cc
+++ b/runtime/vm/disassembler.cc
@@ -176,7 +176,7 @@
// Pointer offsets are stored in descending order.
Object& obj = Object::Handle();
for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) {
- const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint();
+ const uword addr = code.GetPointerOffsetAt(i) + code.PayloadStart();
obj = *reinterpret_cast<RawObject**>(addr);
THR_Print(" %d : %#" Px " '%s'\n",
code.GetPointerOffsetAt(i), addr, obj.ToCString());
@@ -195,7 +195,7 @@
PcDescriptors::Handle(code.pc_descriptors());
THR_Print("%s}\n", descriptors.ToCString());
- uword start = Instructions::Handle(code.instructions()).EntryPoint();
+ uword start = Instructions::Handle(code.instructions()).PayloadStart();
const Array& deopt_table = Array::Handle(code.deopt_info_array());
intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
if (deopt_table_length > 0) {
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index 8f3d7f6..d0252d3 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -1816,7 +1816,7 @@
if (!code.IsNull() && code.is_alive()) {
intptr_t offsets_length = code.pointer_offsets_length();
for (intptr_t i = 0; i < offsets_length; i++) {
- uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint();
+ uword addr = code.GetPointerOffsetAt(i) + code.PayloadStart();
if ((pc <= addr) && (addr < (pc + instruction_length))) {
*object = &Object::Handle(*reinterpret_cast<RawObject**>(addr));
break;
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 2cb67e1..37a99f2 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -127,7 +127,7 @@
while (frame != NULL) {
if (frame->IsDartFrame()) {
code = frame->LookupDartCode();
- offset = Smi::New(frame->pc() - code.EntryPoint());
+ offset = Smi::New(frame->pc() - code.PayloadStart());
builder->AddFrame(code, offset);
}
frame = frames.NextFrame();
diff --git a/runtime/vm/find_code_object_test.cc b/runtime/vm/find_code_object_test.cc
index 2f53147..75ffa2b 100644
--- a/runtime/vm/find_code_object_test.cc
+++ b/runtime/vm/find_code_object_test.cc
@@ -133,7 +133,7 @@
EXPECT(!function.IsNull());
code = function.CurrentCode();
EXPECT(code.Size() > 16);
- pc = code.EntryPoint() + 16;
+ pc = code.PayloadStart() + 16;
EXPECT(Code::LookupCode(pc) == code.raw());
OS::SNPrint(buffer, 256, "moo%d", 54);
@@ -142,7 +142,7 @@
EXPECT(!function.IsNull());
code = function.CurrentCode();
EXPECT(code.Size() > 16);
- pc = code.EntryPoint() + 16;
+ pc = code.PayloadStart() + 16;
EXPECT(Code::LookupCode(pc) == code.raw());
// Lookup the large function
@@ -152,11 +152,11 @@
EXPECT(!function.IsNull());
code = function.CurrentCode();
EXPECT(code.Size() > 16);
- pc = code.EntryPoint() + 16;
+ pc = code.PayloadStart() + 16;
EXPECT(code.Size() > (PageSpace::kPageSizeInWords << kWordSizeLog2));
EXPECT(Code::LookupCode(pc) == code.raw());
EXPECT(code.Size() > (1 * MB));
- pc = code.EntryPoint() + (1 * MB);
+ pc = code.PayloadStart() + (1 * MB);
EXPECT(Code::LookupCode(pc) == code.raw());
}
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index b98a3fc..3a1bc7d 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -1006,7 +1006,7 @@
void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) {
ASSERT(exception_handlers_list_ != NULL);
const ExceptionHandlers& handlers = ExceptionHandlers::Handle(
- exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint()));
+ exception_handlers_list_->FinalizeExceptionHandlers(code.PayloadStart()));
code.set_exception_handlers(handlers);
if (FLAG_compiler_stats) {
Thread* thread = Thread::Current();
@@ -1020,7 +1020,7 @@
void FlowGraphCompiler::FinalizePcDescriptors(const Code& code) {
ASSERT(pc_descriptors_list_ != NULL);
const PcDescriptors& descriptors = PcDescriptors::Handle(
- pc_descriptors_list_->FinalizePcDescriptors(code.EntryPoint()));
+ pc_descriptors_list_->FinalizePcDescriptors(code.PayloadStart()));
if (!is_optimizing_) descriptors.Verify(parsed_function_.function());
code.set_pc_descriptors(descriptors);
code.set_lazy_deopt_pc_offset(lazy_deopt_pc_offset_);
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 8d8626c..09be30f 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1332,9 +1332,8 @@
__ Comment("Slow case: megamorphic call");
}
__ LoadObject(R9, cache);
- __ ldr(LR, Address(THR, Thread::megamorphic_lookup_entry_point_offset()));
+ __ ldr(LR, Address(THR, Thread::megamorphic_lookup_checked_entry_offset()));
__ blx(LR);
- __ blx(R1);
__ Bind(&done);
RecordSafepoint(locs, slow_path_argument_count);
@@ -1372,12 +1371,17 @@
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
- __ Comment("SwitchableCall");
- __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize);
ASSERT(ic_data.NumArgsTested() == 1);
+ const Code& initial_stub = Code::ZoneHandle(
+ StubCode::ICLookupThroughFunction_entry()->code());
+
+ __ Comment("SwitchableCall");
+
+ __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize);
__ LoadUniqueObject(R9, ic_data);
- __ BranchLinkPatchable(*StubCode::ICLookupThroughFunction_entry());
- __ blx(R1);
+ __ LoadUniqueObject(CODE_REG, initial_stub);
+ __ ldr(LR, FieldAddress(CODE_REG, Code::checked_entry_point_offset()));
+ __ blx(LR);
AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, token_pos);
RecordSafepoint(locs);
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 178482a..5dd2308 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -1314,9 +1314,8 @@
}
__ LoadObject(R5, cache);
- __ ldr(LR, Address(THR, Thread::megamorphic_lookup_entry_point_offset()));
+ __ ldr(LR, Address(THR, Thread::megamorphic_lookup_checked_entry_offset()));
__ blr(LR);
- __ blr(R1);
__ Bind(&done);
RecordSafepoint(locs, slow_path_argument_count);
@@ -1353,12 +1352,16 @@
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
- __ Comment("SwitchableCall");
- __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize);
ASSERT(ic_data.NumArgsTested() == 1);
+ const Code& initial_stub = Code::ZoneHandle(
+ StubCode::ICLookupThroughFunction_entry()->code());
+ __ Comment("SwitchableCall");
+
+ __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize);
__ LoadUniqueObject(R5, ic_data);
- __ BranchLinkPatchable(*StubCode::ICLookupThroughFunction_entry());
- __ blr(R1);
+ __ LoadUniqueObject(CODE_REG, initial_stub);
+ __ ldr(TMP, FieldAddress(CODE_REG, Code::checked_entry_point_offset()));
+ __ blr(TMP);
AddCurrentDescriptor(RawPcDescriptors::kOther,
Thread::kNoDeoptId, token_pos);
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 4fc5628..fbfe34c 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -1309,7 +1309,7 @@
__ Comment("Slow case: megamorphic call");
}
__ LoadObject(ECX, cache);
- __ call(Address(THR, Thread::megamorphic_lookup_entry_point_offset()));
+ __ call(Address(THR, Thread::megamorphic_lookup_checked_entry_offset()));
__ call(EBX);
__ Bind(&done);
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index a6f3f14..8e568c9 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1339,9 +1339,8 @@
__ Comment("Slow case: megamorphic call");
}
__ LoadObject(S5, cache);
- __ lw(T9, Address(THR, Thread::megamorphic_lookup_entry_point_offset()));
+ __ lw(T9, Address(THR, Thread::megamorphic_lookup_checked_entry_offset()));
__ jalr(T9);
- __ jalr(T1);
__ Bind(&done);
RecordSafepoint(locs, slow_path_argument_count);
@@ -1378,12 +1377,16 @@
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
+ ASSERT(ic_data.NumArgsTested() == 1);
+ const Code& initial_stub = Code::ZoneHandle(
+ StubCode::ICLookupThroughFunction_entry()->code());
+
__ Comment("SwitchableCall");
__ lw(T0, Address(SP, (argument_count - 1) * kWordSize));
- ASSERT(ic_data.NumArgsTested() == 1);
__ LoadUniqueObject(S5, ic_data);
- __ BranchLinkPatchable(*StubCode::ICLookupThroughFunction_entry());
- __ jalr(T1);
+ __ LoadUniqueObject(CODE_REG, initial_stub);
+ __ lw(T9, FieldAddress(CODE_REG, Code::checked_entry_point_offset()));
+ __ jalr(T9);
AddCurrentDescriptor(RawPcDescriptors::kOther,
Thread::kNoDeoptId, token_pos);
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 4c60d20..9118bb12 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -1339,8 +1339,7 @@
__ Comment("Slow case: megamorphic call");
}
__ LoadObject(RBX, cache);
- __ call(Address(THR, Thread::megamorphic_lookup_entry_point_offset()));
- __ call(RCX);
+ __ call(Address(THR, Thread::megamorphic_lookup_checked_entry_offset()));
__ Bind(&done);
RecordSafepoint(locs, slow_path_argument_count);
@@ -1377,11 +1376,15 @@
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
+ ASSERT(ic_data.NumArgsTested() == 1);
+ const Code& initial_stub = Code::ZoneHandle(
+ StubCode::ICLookupThroughFunction_entry()->code());
+
__ Comment("SwitchableCall");
__ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize));
- ASSERT(ic_data.NumArgsTested() == 1);
__ LoadUniqueObject(RBX, ic_data);
- __ CallPatchable(*StubCode::ICLookupThroughFunction_entry());
+ __ LoadUniqueObject(CODE_REG, initial_stub);
+ __ movq(RCX, FieldAddress(CODE_REG, Code::checked_entry_point_offset()));
__ call(RCX);
AddCurrentDescriptor(RawPcDescriptors::kOther,
diff --git a/runtime/vm/instructions_arm.cc b/runtime/vm/instructions_arm.cc
index 36281df..0e5cfb2 100644
--- a/runtime/vm/instructions_arm.cc
+++ b/runtime/vm/instructions_arm.cc
@@ -309,40 +309,45 @@
SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code)
: object_pool_(ObjectPool::Handle(code.GetObjectPool())),
- cache_pool_index_(-1),
- stub_pool_index_(-1) {
+ data_pool_index_(-1),
+ target_pool_index_(-1) {
ASSERT(code.ContainsInstructionAt(pc));
- // Last instruction: blx r1.
- ASSERT(*(reinterpret_cast<uword*>(pc) - 1) == 0xe12fff31);
+ // Last instruction: blx lr.
+ ASSERT(*(reinterpret_cast<uword*>(pc) - 1) == 0xe12fff3e);
Register reg;
uword stub_load_end =
- InstructionPattern::DecodeLoadWordFromPool(pc - 3 * Instr::kInstrSize,
+ InstructionPattern::DecodeLoadWordFromPool(pc - 2 * Instr::kInstrSize,
®,
- &stub_pool_index_);
+ &target_pool_index_);
ASSERT(reg == CODE_REG);
InstructionPattern::DecodeLoadWordFromPool(stub_load_end,
®,
- &cache_pool_index_);
+ &data_pool_index_);
ASSERT(reg == R9);
}
-RawObject* SwitchableCallPattern::cache() const {
+RawObject* SwitchableCallPattern::data() const {
+ return object_pool_.ObjectAt(data_pool_index_);
+}
+
+
+RawCode* SwitchableCallPattern::target() const {
return reinterpret_cast<RawCode*>(
- object_pool_.ObjectAt(cache_pool_index_));
+ object_pool_.ObjectAt(target_pool_index_));
}
-void SwitchableCallPattern::SetCache(const MegamorphicCache& cache) const {
- ASSERT(Object::Handle(object_pool_.ObjectAt(cache_pool_index_)).IsICData());
- object_pool_.SetObjectAt(cache_pool_index_, cache);
+void SwitchableCallPattern::SetData(const Object& data) const {
+ ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode());
+ object_pool_.SetObjectAt(data_pool_index_, data);
}
-void SwitchableCallPattern::SetLookupStub(const Code& lookup_stub) const {
- ASSERT(Object::Handle(object_pool_.ObjectAt(stub_pool_index_)).IsCode());
- object_pool_.SetObjectAt(stub_pool_index_, lookup_stub);
+void SwitchableCallPattern::SetTarget(const Code& target) const {
+ ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode());
+ object_pool_.SetObjectAt(target_pool_index_, target);
}
diff --git a/runtime/vm/instructions_arm.h b/runtime/vm/instructions_arm.h
index 57d4824..86d81a7 100644
--- a/runtime/vm/instructions_arm.h
+++ b/runtime/vm/instructions_arm.h
@@ -98,22 +98,24 @@
};
-// Instance call that can switch from an IC call to a megamorphic call
-// load ICData load MegamorphicCache
-// call ICLookup stub -> call MegamorphicLookup stub
-// call target call target
+// Instance call that can switch between a direct monomorphic call, an IC call,
+// and a megamorphic call.
+// load guarded cid load ICData load MegamorphicCache
+// load monomorphic target <-> load ICLookup stub -> load MMLookup stub
+// call target.entry call stub.entry call stub.entry
class SwitchableCallPattern : public ValueObject {
public:
SwitchableCallPattern(uword pc, const Code& code);
- RawObject* cache() const;
- void SetCache(const MegamorphicCache& cache) const;
- void SetLookupStub(const Code& stub) const;
+ RawObject* data() const;
+ RawCode* target() const;
+ void SetData(const Object& data) const;
+ void SetTarget(const Code& target) const;
private:
const ObjectPool& object_pool_;
- intptr_t cache_pool_index_;
- intptr_t stub_pool_index_;
+ intptr_t data_pool_index_;
+ intptr_t target_pool_index_;
DISALLOW_COPY_AND_ASSIGN(SwitchableCallPattern);
};
diff --git a/runtime/vm/instructions_arm64.cc b/runtime/vm/instructions_arm64.cc
index 99c57ba..60ef9bf 100644
--- a/runtime/vm/instructions_arm64.cc
+++ b/runtime/vm/instructions_arm64.cc
@@ -359,40 +359,45 @@
SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code)
: object_pool_(ObjectPool::Handle(code.GetObjectPool())),
- cache_pool_index_(-1),
- stub_pool_index_(-1) {
+ data_pool_index_(-1),
+ target_pool_index_(-1) {
ASSERT(code.ContainsInstructionAt(pc));
- // Last instruction: blr r1.
- ASSERT(*(reinterpret_cast<uint32_t*>(pc) - 1) == 0xd63f0020);
+ // Last instruction: blr ip0.
+ ASSERT(*(reinterpret_cast<uint32_t*>(pc) - 1) == 0xd63f0200);
Register reg;
uword stub_load_end =
- InstructionPattern::DecodeLoadWordFromPool(pc - 3 * Instr::kInstrSize,
+ InstructionPattern::DecodeLoadWordFromPool(pc - 2 * Instr::kInstrSize,
®,
- &stub_pool_index_);
+ &target_pool_index_);
ASSERT(reg == CODE_REG);
InstructionPattern::DecodeLoadWordFromPool(stub_load_end,
®,
- &cache_pool_index_);
+ &data_pool_index_);
ASSERT(reg == R5);
}
-RawObject* SwitchableCallPattern::cache() const {
+RawObject* SwitchableCallPattern::data() const {
+ return object_pool_.ObjectAt(data_pool_index_);
+}
+
+
+RawCode* SwitchableCallPattern::target() const {
return reinterpret_cast<RawCode*>(
- object_pool_.ObjectAt(cache_pool_index_));
+ object_pool_.ObjectAt(target_pool_index_));
}
-void SwitchableCallPattern::SetCache(const MegamorphicCache& cache) const {
- ASSERT(Object::Handle(object_pool_.ObjectAt(cache_pool_index_)).IsICData());
- object_pool_.SetObjectAt(cache_pool_index_, cache);
+void SwitchableCallPattern::SetData(const Object& data) const {
+ ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode());
+ object_pool_.SetObjectAt(data_pool_index_, data);
}
-void SwitchableCallPattern::SetLookupStub(const Code& lookup_stub) const {
- ASSERT(Object::Handle(object_pool_.ObjectAt(stub_pool_index_)).IsCode());
- object_pool_.SetObjectAt(stub_pool_index_, lookup_stub);
+void SwitchableCallPattern::SetTarget(const Code& target) const {
+ ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode());
+ object_pool_.SetObjectAt(target_pool_index_, target);
}
diff --git a/runtime/vm/instructions_arm64.h b/runtime/vm/instructions_arm64.h
index 6195d52..80de324 100644
--- a/runtime/vm/instructions_arm64.h
+++ b/runtime/vm/instructions_arm64.h
@@ -106,22 +106,24 @@
};
-// Instance call that can switch from an IC call to a megamorphic call
-// load ICData load MegamorphicCache
-// call ICLookup stub -> call MegamorphicLookup stub
-// call target call target
+// Instance call that can switch between a direct monomorphic call, an IC call,
+// and a megamorphic call.
+// load guarded cid load ICData load MegamorphicCache
+// load monomorphic target <-> load ICLookup stub -> load MMLookup stub
+// call target.entry call stub.entry call stub.entry
class SwitchableCallPattern : public ValueObject {
public:
SwitchableCallPattern(uword pc, const Code& code);
- RawObject* cache() const;
- void SetCache(const MegamorphicCache& cache) const;
- void SetLookupStub(const Code& stub) const;
+ RawObject* data() const;
+ RawCode* target() const;
+ void SetData(const Object& data) const;
+ void SetTarget(const Code& target) const;
private:
const ObjectPool& object_pool_;
- intptr_t cache_pool_index_;
- intptr_t stub_pool_index_;
+ intptr_t data_pool_index_;
+ intptr_t target_pool_index_;
DISALLOW_COPY_AND_ASSIGN(SwitchableCallPattern);
};
diff --git a/runtime/vm/instructions_arm64_test.cc b/runtime/vm/instructions_arm64_test.cc
index 970d271..7ad4fb9 100644
--- a/runtime/vm/instructions_arm64_test.cc
+++ b/runtime/vm/instructions_arm64_test.cc
@@ -27,7 +27,8 @@
// The return address, which must be the address of an instruction contained
// in the code, points to the Ret instruction above, i.e. one instruction
// before the end of the code buffer.
- CallPattern call(test->entry() + test->code().Size() - Instr::kInstrSize,
+ uword end = test->payload_start() + test->code().Size();
+ CallPattern call(end - Instr::kInstrSize,
test->code());
EXPECT_EQ(StubCode::InvokeDartCode_entry()->code(),
call.TargetCode());
diff --git a/runtime/vm/instructions_arm_test.cc b/runtime/vm/instructions_arm_test.cc
index de3ff6f..24effd8 100644
--- a/runtime/vm/instructions_arm_test.cc
+++ b/runtime/vm/instructions_arm_test.cc
@@ -27,8 +27,8 @@
// The return address, which must be the address of an instruction contained
// in the code, points to the Ret instruction above, i.e. one instruction
// before the end of the code buffer.
- CallPattern call(test->entry() + test->code().Size() - Instr::kInstrSize,
- test->code());
+ uword end = test->payload_start() + test->code().Size();
+ CallPattern call(end - Instr::kInstrSize, test->code());
EXPECT_EQ(StubCode::InvokeDartCode_entry()->code(), call.TargetCode());
}
diff --git a/runtime/vm/instructions_dbc.cc b/runtime/vm/instructions_dbc.cc
index d648d511..7d8dab7 100644
--- a/runtime/vm/instructions_dbc.cc
+++ b/runtime/vm/instructions_dbc.cc
@@ -190,27 +190,32 @@
SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code)
: object_pool_(ObjectPool::Handle(code.GetObjectPool())),
- cache_pool_index_(-1),
- stub_pool_index_(-1) {
+ data_pool_index_(-1),
+ target_pool_index_(-1) {
UNIMPLEMENTED();
}
-RawObject* SwitchableCallPattern::cache() const {
+RawObject* SwitchableCallPattern::data() const {
+ return object_pool_.ObjectAt(data_pool_index_);
+}
+
+
+RawCode* SwitchableCallPattern::target() const {
return reinterpret_cast<RawCode*>(
- object_pool_.ObjectAt(cache_pool_index_));
+ object_pool_.ObjectAt(target_pool_index_));
}
-void SwitchableCallPattern::SetCache(const MegamorphicCache& cache) const {
- ASSERT(Object::Handle(object_pool_.ObjectAt(cache_pool_index_)).IsICData());
- object_pool_.SetObjectAt(cache_pool_index_, cache);
+void SwitchableCallPattern::SetData(const Object& data) const {
+ ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode());
+ object_pool_.SetObjectAt(data_pool_index_, data);
}
-void SwitchableCallPattern::SetLookupStub(const Code& lookup_stub) const {
- ASSERT(Object::Handle(object_pool_.ObjectAt(stub_pool_index_)).IsCode());
- object_pool_.SetObjectAt(stub_pool_index_, lookup_stub);
+void SwitchableCallPattern::SetTarget(const Code& target) const {
+ ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode());
+ object_pool_.SetObjectAt(target_pool_index_, target);
}
diff --git a/runtime/vm/instructions_dbc.h b/runtime/vm/instructions_dbc.h
index 5eb0c6e..6db5205 100644
--- a/runtime/vm/instructions_dbc.h
+++ b/runtime/vm/instructions_dbc.h
@@ -98,19 +98,24 @@
};
-// Instance call that can switch from an IC call to a megamorphic call
+// Instance call that can switch between a direct monomorphic call, an IC call,
+// and a megamorphic call.
+// load guarded cid load ICData load MegamorphicCache
+// load monomorphic target <-> load ICLookup stub -> load MMLookup stub
+// call target.entry call stub.entry call stub.entry
class SwitchableCallPattern : public ValueObject {
public:
SwitchableCallPattern(uword pc, const Code& code);
- RawObject* cache() const;
- void SetCache(const MegamorphicCache& cache) const;
- void SetLookupStub(const Code& stub) const;
+ RawObject* data() const;
+ RawCode* target() const;
+ void SetData(const Object& data) const;
+ void SetTarget(const Code& target) const;
private:
const ObjectPool& object_pool_;
- intptr_t cache_pool_index_;
- intptr_t stub_pool_index_;
+ intptr_t data_pool_index_;
+ intptr_t target_pool_index_;
DISALLOW_COPY_AND_ASSIGN(SwitchableCallPattern);
};
diff --git a/runtime/vm/instructions_mips.cc b/runtime/vm/instructions_mips.cc
index cdb2cbe..70fff9d 100644
--- a/runtime/vm/instructions_mips.cc
+++ b/runtime/vm/instructions_mips.cc
@@ -237,41 +237,46 @@
SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code)
: object_pool_(ObjectPool::Handle(code.GetObjectPool())),
- cache_pool_index_(-1),
- stub_pool_index_(-1) {
+ data_pool_index_(-1),
+ target_pool_index_(-1) {
ASSERT(code.ContainsInstructionAt(pc));
- // Last instruction: jalr t1.
+ // Last instruction: jalr t9.
ASSERT(*(reinterpret_cast<uword*>(pc) - 1) == 0); // Delay slot.
- ASSERT(*(reinterpret_cast<uword*>(pc) - 2) == 0x0120f809);
+ ASSERT(*(reinterpret_cast<uword*>(pc) - 2) == 0x0320f809);
Register reg;
uword stub_load_end =
- InstructionPattern::DecodeLoadWordFromPool(pc - 5 * Instr::kInstrSize,
+ InstructionPattern::DecodeLoadWordFromPool(pc - 3 * Instr::kInstrSize,
®,
- &stub_pool_index_);
+ &target_pool_index_);
ASSERT(reg == CODE_REG);
InstructionPattern::DecodeLoadWordFromPool(stub_load_end,
®,
- &cache_pool_index_);
+ &data_pool_index_);
ASSERT(reg == S5);
}
-RawObject* SwitchableCallPattern::cache() const {
+RawObject* SwitchableCallPattern::data() const {
+ return object_pool_.ObjectAt(data_pool_index_);
+}
+
+
+RawCode* SwitchableCallPattern::target() const {
return reinterpret_cast<RawCode*>(
- object_pool_.ObjectAt(cache_pool_index_));
+ object_pool_.ObjectAt(target_pool_index_));
}
-void SwitchableCallPattern::SetCache(const MegamorphicCache& cache) const {
- ASSERT(Object::Handle(object_pool_.ObjectAt(cache_pool_index_)).IsICData());
- object_pool_.SetObjectAt(cache_pool_index_, cache);
+void SwitchableCallPattern::SetData(const Object& data) const {
+ ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode());
+ object_pool_.SetObjectAt(data_pool_index_, data);
}
-void SwitchableCallPattern::SetLookupStub(const Code& lookup_stub) const {
- ASSERT(Object::Handle(object_pool_.ObjectAt(stub_pool_index_)).IsCode());
- object_pool_.SetObjectAt(stub_pool_index_, lookup_stub);
+void SwitchableCallPattern::SetTarget(const Code& target) const {
+ ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode());
+ object_pool_.SetObjectAt(target_pool_index_, target);
}
diff --git a/runtime/vm/instructions_mips.h b/runtime/vm/instructions_mips.h
index 607e835..a5a398f 100644
--- a/runtime/vm/instructions_mips.h
+++ b/runtime/vm/instructions_mips.h
@@ -97,22 +97,24 @@
};
-// Instance call that can switch from an IC call to a megamorphic call
-// load ICData load MegamorphicCache
-// call ICLookup stub -> call MegamorphicLookup stub
-// call target call target
+// Instance call that can switch between a direct monomorphic call, an IC call,
+// and a megamorphic call.
+// load guarded cid load ICData load MegamorphicCache
+// load monomorphic target <-> load ICLookup stub -> load MMLookup stub
+// call target.entry call stub.entry call stub.entry
class SwitchableCallPattern : public ValueObject {
public:
SwitchableCallPattern(uword pc, const Code& code);
- RawObject* cache() const;
- void SetCache(const MegamorphicCache& cache) const;
- void SetLookupStub(const Code& stub) const;
+ RawObject* data() const;
+ RawCode* target() const;
+ void SetData(const Object& data) const;
+ void SetTarget(const Code& target) const;
private:
const ObjectPool& object_pool_;
- intptr_t cache_pool_index_;
- intptr_t stub_pool_index_;
+ intptr_t data_pool_index_;
+ intptr_t target_pool_index_;
DISALLOW_COPY_AND_ASSIGN(SwitchableCallPattern);
};
diff --git a/runtime/vm/instructions_mips_test.cc b/runtime/vm/instructions_mips_test.cc
index cf2f7f2..38d5936 100644
--- a/runtime/vm/instructions_mips_test.cc
+++ b/runtime/vm/instructions_mips_test.cc
@@ -25,8 +25,8 @@
// in the code, points to the Ret instruction above, i.e. two instructions
// before the end of the code buffer, including the delay slot for the
// return jump.
- CallPattern call(test->entry() + test->code().Size() - (2*Instr::kInstrSize),
- test->code());
+ uword end = test->payload_start() + test->code().Size();
+ CallPattern call(end - (2 * Instr::kInstrSize), test->code());
EXPECT_EQ(StubCode::InvokeDartCode_entry()->code(), call.TargetCode());
}
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 2daafed..7e9dc7c 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -521,7 +521,6 @@
ASSERT(kSmiTagShift == 1);
ASSERT(kSmiTag == 0);
Label fall_through;
- __ Push(R6);
TestBothArgumentsSmis(assembler, &fall_through);
__ CompareImmediate(R0, Smi::RawValue(Smi::kBits));
__ b(&fall_through, HI);
@@ -549,10 +548,10 @@
__ LoadImmediate(NOTFP, 1);
__ mov(NOTFP, Operand(NOTFP, LSL, R0)); // NOTFP <- 1 << R0
__ sub(NOTFP, NOTFP, Operand(1)); // NOTFP <- NOTFP - 1
- __ rsb(R6, R0, Operand(32)); // R6 <- 32 - R0
- __ mov(NOTFP, Operand(NOTFP, LSL, R6)); // NOTFP <- NOTFP << R6
+ __ rsb(R3, R0, Operand(32)); // R3 <- 32 - R0
+ __ mov(NOTFP, Operand(NOTFP, LSL, R3)); // NOTFP <- NOTFP << R3
__ and_(NOTFP, R1, Operand(NOTFP)); // NOTFP <- NOTFP & R1
- __ mov(NOTFP, Operand(NOTFP, LSR, R6)); // NOTFP <- NOTFP >> R6
+ __ mov(NOTFP, Operand(NOTFP, LSR, R3)); // NOTFP <- NOTFP >> R3
// Now NOTFP has the bits that fall off of R1 on a left shift.
__ mov(R1, Operand(R1, LSL, R0)); // R1 gets the low bits.
@@ -563,11 +562,8 @@
__ str(R1, FieldAddress(R0, Mint::value_offset()));
__ str(NOTFP, FieldAddress(R0, Mint::value_offset() + kWordSize));
- __ Pop(R6);
__ Ret();
__ Bind(&fall_through);
- ASSERT(CODE_REG == R6);
- __ Pop(R6);
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 028a130..362d276 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1109,6 +1109,10 @@
void Isolate::DeleteReloadContext() {
+ // Another thread may be in the middle of GetClassForHeapWalkAt.
+ Thread* thread = Thread::Current();
+ SafepointOperationScope safepoint_scope(thread);
+
delete reload_context_;
reload_context_ = NULL;
}
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 0957f6f..81ba9a8 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -924,9 +924,13 @@
class_table->SetAt(i, saved_class_table_[i]);
}
}
- free(saved_class_table_);
+
+ RawClass** local_saved_class_table = saved_class_table_;
saved_class_table_ = NULL;
- saved_num_cids_ = 0;
+ // Can't free this table immediately as another thread (e.g., the sweeper) may
+ // be suspended between loading the table pointer and loading the table
+ // element. Table will be freed at the next major GC or isolate shutdown.
+ class_table->AddOldTable(local_saved_class_table);
}
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index b6a6c98..57455b4 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -1835,6 +1835,116 @@
}
+TEST_CASE(IsolateReload_TearOff_AddArguments) {
+ const char* kScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class C {\n"
+ " foo(x) => x;\n"
+ "}\n"
+ "invoke(f, a) {\n"
+ " try {\n"
+ " return f(a);\n"
+ " } catch (e) {\n"
+ " return e.toString().split('\\n').first;\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " var c = new C();\n"
+ " var f = c#foo;\n"
+ " var r1 = invoke(f, 1);\n"
+ " reloadTest();\n"
+ " var r2 = invoke(f, 1);\n"
+ " return '$r1 $r2';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class C {\n"
+ " foo(x, y, z) => x + y + z;\n"
+ "}\n"
+ "invoke(f, a) {\n"
+ " try {\n"
+ " return f(a);\n"
+ " } catch (e) {\n"
+ " return e.toString().split('\\n').first;\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " var c = new C();\n"
+ " var f = c#foo;\n"
+ " var r1 = invoke(f, 1);\n"
+ " reloadTest();\n"
+ " var r2 = invoke(f, 1);\n"
+ " return '$r1 $r2';\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_STREQ("1 Class 'C' has no instance method 'foo' with matching"
+ " arguments.", SimpleInvokeStr(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+}
+
+
+TEST_CASE(IsolateReload_TearOff_AddArguments2) {
+ const char* kScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class C {\n"
+ " static foo(x) => x;\n"
+ "}\n"
+ "invoke(f, a) {\n"
+ " try {\n"
+ " return f(a);\n"
+ " } catch (e) {\n"
+ " return e.toString().split('\\n').first;\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " var f = C#foo;\n"
+ " var r1 = invoke(f, 1);\n"
+ " reloadTest();\n"
+ " var r2 = invoke(f, 1);\n"
+ " return '$r1 $r2';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class C {\n"
+ " static foo(x, y, z) => x + y + z;\n"
+ "}\n"
+ "invoke(f, a) {\n"
+ " try {\n"
+ " return f(a);\n"
+ " } catch (e) {\n"
+ " return e.toString().split('\\n').first;\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " var f = C#foo;\n"
+ " var r1 = invoke(f, 1);\n"
+ " reloadTest();\n"
+ " var r2 = invoke(f, 1);\n"
+ " return '$r1 $r2';\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_STREQ("1 Closure call with mismatched arguments: function 'C.foo'",
+ SimpleInvokeStr(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+}
+
+
TEST_CASE(IsolateReload_EnumEquality) {
const char* kScript =
"enum Fruit {\n"
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index cf185cf..47620c6 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -361,7 +361,7 @@
V(_GrowableList, get:length, GrowableArrayLength, 0x18dc9df6) \
V(_GrowableList, get:_capacity, GrowableArrayCapacity, 0x02734d82) \
V(_GrowableList, add, GrowableListAdd, 0x0d1358ed) \
- V(_GrowableList, removeLast, GrowableListRemoveLast, 0x135d7384) \
+ V(_GrowableList, removeLast, GrowableListRemoveLast, 0x7add0363) \
V(_StringBase, get:length, StringBaseLength, 0x2a2c1b13) \
V(ListIterator, moveNext, ListIteratorMoveNext, 0x3f892e71) \
V(_FixedSizeArrayIterator, moveNext, FixedListIteratorMoveNext, 0x5681c902) \
@@ -421,19 +421,11 @@
V(_ByteDataView, getUint64, ByteDataViewGetUint64, 0x2fab992e) \
V(_ByteDataView, getFloat32, ByteDataViewGetFloat32, 0x387e9fc6) \
V(_ByteDataView, getFloat64, ByteDataViewGetFloat64, 0x5396432d) \
- V(::, asin, MathAsin, 0x661ff68b) \
- V(::, acos, MathAcos, 0x44e71d5f) \
- V(::, atan, MathAtan, 0x4436a657) \
- V(::, atan2, MathAtan2, 0x60a40743) \
- V(::, cos, MathCos, 0x79a7611c) \
V(::, exp, MathExp, 0x5b894d7b) \
V(::, log, MathLog, 0x2e25132c) \
V(::, max, MathMax, 0x54121d6a) \
V(::, min, MathMin, 0x4276561c) \
V(::, pow, MathPow, 0x438e3089) \
- V(::, sin, MathSin, 0x0213abe6) \
- V(::, sqrt, MathSqrt, 0x1afb83d4) \
- V(::, tan, MathTan, 0x4e2e20db) \
V(Lists, copy, ListsCopy, 0x21a194fa) \
V(_Bigint, get:_neg, Bigint_getNeg, 0x7bf17a57) \
V(_Bigint, get:_used, Bigint_getUsed, 0x55041013) \
@@ -451,6 +443,14 @@
// A list of core function that should never be inlined.
#define INLINE_BLACK_LIST(V) \
+ V(::, asin, MathAsin, 0x661ff68b) \
+ V(::, acos, MathAcos, 0x44e71d5f) \
+ V(::, atan, MathAtan, 0x4436a657) \
+ V(::, atan2, MathAtan2, 0x60a40743) \
+ V(::, cos, MathCos, 0x79a7611c) \
+ V(::, sin, MathSin, 0x0213abe6) \
+ V(::, sqrt, MathSqrt, 0x1afb83d4) \
+ V(::, tan, MathTan, 0x4e2e20db) \
V(_Bigint, _lsh, Bigint_lsh, 0x5cd95513) \
V(_Bigint, _rsh, Bigint_rsh, 0x2d68d0e1) \
V(_Bigint, _absAdd, Bigint_absAdd, 0x492f4865) \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 0886a30..1481f63 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -3088,6 +3088,13 @@
const Array& param_names,
const Array& param_values) const {
ASSERT(Thread::Current()->IsMutatorThread());
+ if (id() < kInstanceCid) {
+ const Instance& exception = Instance::Handle(String::New(
+ "Cannot evaluate against a VM internal class"));
+ const Instance& stacktrace = Instance::Handle();
+ return UnhandledException::New(exception, stacktrace);
+ }
+
const Function& eval_func =
Function::Handle(EvaluateHelper(*this, expr, param_names, true));
const Object& result =
@@ -5265,7 +5272,7 @@
void Function::SetInstructionsSafe(const Code& value) const {
StorePointer(&raw_ptr()->code_, value.raw());
- StoreNonPointer(&raw_ptr()->entry_point_, value.EntryPoint());
+ StoreNonPointer(&raw_ptr()->entry_point_, value.UncheckedEntryPoint());
}
@@ -5316,7 +5323,7 @@
if (FLAG_trace_deoptimization_verbose) {
THR_Print("Disabling optimized code: '%s' entry: %#" Px "\n",
ToFullyQualifiedCString(),
- current_code.EntryPoint());
+ current_code.UncheckedEntryPoint());
}
current_code.DisableDartCode();
const Error& error = Error::Handle(zone,
@@ -6582,7 +6589,7 @@
/* is_const = */ false,
/* is_abstract = */ false,
/* is_external = */ false,
- parent.is_native(),
+ /* is_native = */ false,
parent_owner,
token_pos));
result.set_parent_function(parent);
@@ -13006,7 +13013,7 @@
ASSERT(target.HasCode());
const Code& code = Code::Handle(target.CurrentCode());
const Smi& entry_point =
- Smi::Handle(Smi::FromAlignedAddress(code.EntryPoint()));
+ Smi::Handle(Smi::FromAlignedAddress(code.UncheckedEntryPoint()));
data.SetAt(data_pos + 1, code);
data.SetAt(data_pos + 2, entry_point);
}
@@ -13676,7 +13683,7 @@
uint32_t* deopt_flags) const {
ASSERT(is_optimized());
const Instructions& instrs = Instructions::Handle(instructions());
- uword code_entry = instrs.EntryPoint();
+ uword code_entry = instrs.PayloadStart();
const Array& table = Array::Handle(deopt_info_array());
if (table.IsNull()) {
ASSERT(Dart::snapshot_kind() == Snapshot::kAppNoJIT);
@@ -13704,7 +13711,7 @@
intptr_t Code::BinarySearchInSCallTable(uword pc) const {
NoSafepointScope no_safepoint;
const Array& table = Array::Handle(raw_ptr()->static_calls_target_table_);
- RawObject* key = reinterpret_cast<RawObject*>(Smi::New(pc - EntryPoint()));
+ RawObject* key = reinterpret_cast<RawObject*>(Smi::New(pc - PayloadStart()));
intptr_t imin = 0;
intptr_t imax = table.Length() / kSCallTableEntryLength;
while (imax >= imin) {
@@ -13783,7 +13790,7 @@
return;
}
const Instructions& instr = Instructions::Handle(instructions());
- uword start = instr.EntryPoint();
+ uword start = instr.PayloadStart();
if (formatter == NULL) {
Disassembler::Disassemble(start, start + instr.size(), *this);
} else {
@@ -13968,15 +13975,15 @@
// Copy the instructions into the instruction area and apply all fixups.
// Embedded pointers are still in handles at this point.
- MemoryRegion region(reinterpret_cast<void*>(instrs.EntryPoint()),
+ MemoryRegion region(reinterpret_cast<void*>(instrs.PayloadStart()),
instrs.size());
assembler->FinalizeInstructions(region);
- CPU::FlushICache(instrs.EntryPoint(), instrs.size());
+ CPU::FlushICache(instrs.PayloadStart(), instrs.size());
code.set_compile_timestamp(OS::GetCurrentMonotonicMicros());
#ifndef PRODUCT
CodeObservers::NotifyAll(name,
- instrs.EntryPoint(),
+ instrs.PayloadStart(),
assembler->prologue_offset(),
instrs.size(),
optimized);
@@ -14082,13 +14089,13 @@
RawCode* Code::FindCode(uword pc, int64_t timestamp) {
Code& code = Code::Handle(Code::LookupCode(pc));
if (!code.IsNull() && (code.compile_timestamp() == timestamp) &&
- (code.EntryPoint() == pc)) {
+ (code.PayloadStart() == pc)) {
// Found code in isolate.
return code.raw();
}
code ^= Code::LookupCodeInVmIsolate(pc);
if (!code.IsNull() && (code.compile_timestamp() == timestamp) &&
- (code.EntryPoint() == pc)) {
+ (code.PayloadStart() == pc)) {
// Found code in VM isolate.
return code.raw();
}
@@ -14097,7 +14104,7 @@
TokenPosition Code::GetTokenIndexOfPC(uword pc) const {
- uword pc_offset = pc - EntryPoint();
+ uword pc_offset = pc - PayloadStart();
const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
while (iter.MoveNext()) {
@@ -14116,7 +14123,7 @@
while (iter.MoveNext()) {
if (iter.DeoptId() == deopt_id) {
uword pc_offset = iter.PcOffset();
- uword pc = EntryPoint() + pc_offset;
+ uword pc = PayloadStart() + pc_offset;
ASSERT(ContainsInstructionAt(pc));
return pc;
}
@@ -14126,7 +14133,7 @@
intptr_t Code::GetDeoptIdForOsr(uword pc) const {
- uword pc_offset = pc - EntryPoint();
+ uword pc_offset = pc - PayloadStart();
const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kOsrEntry);
while (iter.MoveNext()) {
@@ -14141,10 +14148,10 @@
const char* Code::ToCString() const {
Zone* zone = Thread::Current()->zone();
if (IsStubCode()) {
- const char* name = StubCode::NameOfStub(EntryPoint());
+ const char* name = StubCode::NameOfStub(UncheckedEntryPoint());
return zone->PrintToString("[stub: %s]", name);
} else {
- return zone->PrintToString("Code entry:%" Px, EntryPoint());
+ return zone->PrintToString("Code entry:%" Px, UncheckedEntryPoint());
}
}
@@ -14155,7 +14162,7 @@
// Regular stub.
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
- const char* name = StubCode::NameOfStub(EntryPoint());
+ const char* name = StubCode::NameOfStub(UncheckedEntryPoint());
ASSERT(name != NULL);
char* stub_name = OS::SCreate(zone,
"%s%s", Symbols::StubPrefix().ToCString(), name);
@@ -14234,14 +14241,15 @@
// store buffer update is not needed here.
StorePointer(&raw_ptr()->active_instructions_, instructions);
StoreNonPointer(&raw_ptr()->entry_point_,
- reinterpret_cast<uword>(instructions->ptr()) +
- Instructions::HeaderSize());
+ Instructions::UncheckedEntryPoint(instructions));
+ StoreNonPointer(&raw_ptr()->checked_entry_point_,
+ Instructions::CheckedEntryPoint(instructions));
}
uword Code::GetLazyDeoptPc() const {
return (lazy_deopt_pc_offset() != kInvalidPc)
- ? EntryPoint() + lazy_deopt_pc_offset() : 0;
+ ? PayloadStart() + lazy_deopt_pc_offset() : 0;
}
@@ -22355,7 +22363,7 @@
} else {
code = CodeAtFrame(i);
ASSERT(function.raw() == code.function());
- uword pc = code.EntryPoint() + Smi::Value(PcOffsetAtFrame(i));
+ uword pc = code.PayloadStart() + Smi::Value(PcOffsetAtFrame(i));
if (code.is_optimized() &&
expand_inlined() &&
!FLAG_precompiled_runtime) {
@@ -22368,8 +22376,8 @@
ASSERT(function.raw() == code.function());
uword pc = it.pc();
ASSERT(pc != 0);
- ASSERT(code.EntryPoint() <= pc);
- ASSERT(pc < (code.EntryPoint() + code.Size()));
+ ASSERT(code.PayloadStart() <= pc);
+ ASSERT(pc < (code.PayloadStart() + code.Size()));
total_len += PrintOneStacktrace(
zone, &frame_strings, pc, function, code, *frame_index);
(*frame_index)++; // To account for inlined frames.
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 6be932d..d66c764 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3960,13 +3960,48 @@
public:
intptr_t size() const { return raw_ptr()->size_; } // Excludes HeaderSize().
- uword EntryPoint() const {
- return EntryPoint(raw());
+ uword PayloadStart() const {
+ return PayloadStart(raw());
}
- static uword EntryPoint(RawInstructions* instr) {
+ uword UncheckedEntryPoint() const {
+ return UncheckedEntryPoint(raw());
+ }
+ uword CheckedEntryPoint() const {
+ return CheckedEntryPoint(raw());
+ }
+ static uword PayloadStart(RawInstructions* instr) {
return reinterpret_cast<uword>(instr->ptr()) + HeaderSize();
}
+#if defined(TARGET_ARCH_IA32)
+ static const intptr_t kCheckedEntryOffset = 0;
+ static const intptr_t kUncheckedEntryOffset = 0;
+#elif defined(TARGET_ARCH_X64)
+ static const intptr_t kCheckedEntryOffset = 23;
+ static const intptr_t kUncheckedEntryOffset = 44;
+#elif defined(TARGET_ARCH_ARM)
+ static const intptr_t kCheckedEntryOffset = 12;
+ static const intptr_t kUncheckedEntryOffset = 36;
+#elif defined(TARGET_ARCH_ARM64)
+ static const intptr_t kCheckedEntryOffset = 24;
+ static const intptr_t kUncheckedEntryOffset = 48;
+#elif defined(TARGET_ARCH_MIPS)
+ static const intptr_t kCheckedEntryOffset = 16;
+ static const intptr_t kUncheckedEntryOffset = 56;
+#elif defined(TARGET_ARCH_DBC)
+ static const intptr_t kCheckedEntryOffset = 0;
+ static const intptr_t kUncheckedEntryOffset = 0;
+#else
+#error Missing entry offsets for current architecture
+#endif
+
+ static uword UncheckedEntryPoint(RawInstructions* instr) {
+ return PayloadStart(instr) + kUncheckedEntryOffset;
+ }
+ static uword CheckedEntryPoint(RawInstructions* instr) {
+ return PayloadStart(instr) + kCheckedEntryOffset;
+ }
+
static const intptr_t kMaxElements = (kMaxInt32 -
(sizeof(RawInstructions) +
sizeof(RawObject) +
@@ -3991,9 +4026,9 @@
return Utils::RoundUp(sizeof(RawInstructions), alignment);
}
- static RawInstructions* FromEntryPoint(uword entry_point) {
+ static RawInstructions* FromUncheckedEntryPoint(uword entry_point) {
return reinterpret_cast<RawInstructions*>(
- entry_point - HeaderSize() + kHeapObjectTag);
+ entry_point - HeaderSize() - kUncheckedEntryOffset + kHeapObjectTag);
}
bool Equals(const Instructions& other) const {
@@ -4445,6 +4480,9 @@
static intptr_t entry_point_offset() {
return OFFSET_OF(RawCode, entry_point_);
}
+ static intptr_t checked_entry_point_offset() {
+ return OFFSET_OF(RawCode, checked_entry_point_);
+ }
RawObjectPool* object_pool() const { return raw_ptr()->object_pool_; }
static intptr_t object_pool_offset() {
@@ -4464,8 +4502,14 @@
}
void set_is_alive(bool value) const;
- uword EntryPoint() const {
- return Instructions::Handle(instructions()).EntryPoint();
+ uword PayloadStart() const {
+ return Instructions::PayloadStart(instructions());
+ }
+ uword UncheckedEntryPoint() const {
+ return Instructions::UncheckedEntryPoint(instructions());
+ }
+ uword CheckedEntryPoint() const {
+ return Instructions::CheckedEntryPoint(instructions());
}
intptr_t Size() const {
const Instructions& instr = Instructions::Handle(instructions());
@@ -4476,7 +4520,7 @@
}
bool ContainsInstructionAt(uword addr) const {
const Instructions& instr = Instructions::Handle(instructions());
- const uword offset = addr - instr.EntryPoint();
+ const uword offset = addr - instr.PayloadStart();
return offset < static_cast<uword>(instr.size());
}
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index bbecac7..b5a5cac 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -319,6 +319,36 @@
}
}
+ bool ShouldStop(RawObject* obj) {
+ // A static field is considered a root from a language point of view.
+ if (obj->IsField()) {
+ const Field& field = Field::Handle(static_cast<RawField*>(obj));
+ return field.is_static();
+ }
+ return false;
+ }
+
+ void StartList() {
+ was_last_array_ = false;
+ }
+
+ intptr_t HideNDescendant(RawObject* obj) {
+ // A GrowableObjectArray overwrites its internal storage.
+ // Keeping both of them in the list is redundant.
+ if (was_last_array_ && obj->IsGrowableObjectArray()) {
+ was_last_array_ = false;
+ return 1;
+ }
+ // A LinkedHasMap overwrites its internal storage.
+ // Keeping both of them in the list is redundant.
+ if (was_last_array_ && obj->IsLinkedHashMap()) {
+ was_last_array_ = false;
+ return 1;
+ }
+ was_last_array_ = obj->IsArray();
+ return 0;
+ }
+
virtual Direction VisitObject(ObjectGraph::StackIterator* it) {
if (it->Get() != obj_) {
if (ShouldSkip(it->Get())) {
@@ -330,7 +360,10 @@
HANDLESCOPE(thread_);
Object& current = Object::Handle();
Smi& offset_from_parent = Smi::Handle();
+ StartList();
do {
+ // We collapse the backingstore of some internal objects.
+ length_ -= HideNDescendant(it->Get());
intptr_t obj_index = length_ * 2;
intptr_t offset_index = obj_index + 1;
if (!path_.IsNull() && offset_index < path_.Length()) {
@@ -340,7 +373,7 @@
path_.SetAt(offset_index, offset_from_parent);
}
++length_;
- } while (it->MoveToParent());
+ } while (!ShouldStop(it->Get()) && it->MoveToParent());
return kAbort;
}
}
@@ -350,6 +383,7 @@
RawObject* obj_;
const Array& path_;
intptr_t length_;
+ bool was_last_array_;
};
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index 31fdfed..dd15a1f 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -67,7 +67,7 @@
}
const Instructions& instrs = Instructions::Handle(zone, instructions());
ASSERT(!instrs.IsNull());
- uword base_address = instrs.EntryPoint();
+ uword base_address = instrs.PayloadStart();
Object& object = Object::Handle(zone);
intptr_t offsets_length = pointer_offsets_length();
const int32_t* offsets = raw_ptr()->data();
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 84708d7..322d856 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -834,7 +834,7 @@
AddCommonObjectProperties(&jsobj, "Code", ref);
jsobj.AddFixedServiceId("code/%" Px64"-%" Px "",
compile_timestamp(),
- EntryPoint());
+ PayloadStart());
const String& qualified_name = String::Handle(QualifiedName());
const String& vm_name = String::Handle(Name());
AddNameProperties(&jsobj, qualified_name, vm_name);
@@ -868,8 +868,8 @@
func.AddProperty("name", vm_name.ToCString());
AddNameProperties(&func, vm_name, vm_name);
}
- jsobj.AddPropertyF("_startAddress", "%" Px "", EntryPoint());
- jsobj.AddPropertyF("_endAddress", "%" Px "", EntryPoint() + Size());
+ jsobj.AddPropertyF("_startAddress", "%" Px "", PayloadStart());
+ jsobj.AddPropertyF("_endAddress", "%" Px "", PayloadStart() + Size());
jsobj.AddProperty("_alive", is_alive());
const ObjectPool& object_pool = ObjectPool::Handle(GetObjectPool());
jsobj.AddProperty("_objectPool", object_pool);
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 05ddd32..52ab426 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -2713,8 +2713,9 @@
Code& code = Code::Handle(Code::FinalizeCode(function, &_assembler_));
function.AttachCode(code);
const Instructions& instructions = Instructions::Handle(code.instructions());
- uword entry_point = instructions.EntryPoint();
- EXPECT_EQ(instructions.raw(), Instructions::FromEntryPoint(entry_point));
+ uword entry_point = instructions.UncheckedEntryPoint();
+ EXPECT_EQ(instructions.raw(),
+ Instructions::FromUncheckedEntryPoint(entry_point));
const Object& result = Object::Handle(
DartEntry::InvokeFunction(function, Array::empty_array()));
EXPECT_EQ(1, Smi::Cast(result).Value());
@@ -2731,8 +2732,9 @@
Code& code = Code::Handle(Code::FinalizeCode(function, &_assembler_));
function.AttachCode(code);
Instructions& instructions = Instructions::Handle(code.instructions());
- uword entry_point = instructions.EntryPoint();
- EXPECT_EQ(instructions.raw(), Instructions::FromEntryPoint(entry_point));
+ uword entry_point = instructions.UncheckedEntryPoint();
+ EXPECT_EQ(instructions.raw(),
+ Instructions::FromUncheckedEntryPoint(entry_point));
// Try writing into the generated code, expected to crash.
*(reinterpret_cast<char*>(entry_point) + 1) = 1;
if (!FLAG_write_protect_code) {
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 0543a07..3dc119a 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -1614,14 +1614,19 @@
}
AstNode* call = NULL;
- if (!target.IsNull()) {
+ // Check the target still exists and has compatible parameters. If not,
+ // throw NSME/call nSM instead of forwarding the call. Note we compare the
+ // parent not func because func has an extra parameter for the closure
+ // receiver.
+ if (!target.IsNull() &&
+ (parent.num_fixed_parameters() == target.num_fixed_parameters())) {
call = new StaticCallNode(token_pos, target, func_args);
} else if (!parent.is_static()) {
ASSERT(Isolate::Current()->HasAttemptedReload());
// If a subsequent reload reintroduces the target in the middle of the
// Invocation object being constructed, we won't be able to successfully
// deopt because the generated AST will change.
- current_function().SetIsOptimizable(false);
+ func.SetIsOptimizable(false);
ArgumentListNode* arguments = BuildNoSuchMethodArguments(
token_pos, func_name, *func_args, NULL, false);
@@ -1645,7 +1650,7 @@
// If a subsequent reload reintroduces the target in the middle of the
// arguments array being constructed, we won't be able to successfully
// deopt because the generated AST will change.
- current_function().SetIsOptimizable(false);
+ func.SetIsOptimizable(false);
InvocationMirror::Type im_type;
if (parent.IsImplicitGetterFunction()) {
@@ -4034,6 +4039,12 @@
if (library_.is_dart_scheme() && library_.IsPrivate(*method->name)) {
func.set_is_reflectable(false);
}
+ if (is_patch_source() && IsPatchAnnotation(method->metadata_pos)) {
+ // Currently, we just ignore the patch annotation. If the function
+ // name already exists in the patched class, this function will replace
+ // the one in the patched class.
+ method->metadata_pos = TokenPosition::kNoSource;
+ }
if (FLAG_enable_mirrors && (method->metadata_pos.IsReal())) {
library_.AddFunctionMetadata(func, method->metadata_pos);
}
@@ -4134,6 +4145,11 @@
class_field.set_has_initializer(has_initializer);
members->AddField(class_field);
field->field_ = &class_field;
+ if (is_patch_source() && IsPatchAnnotation(field->metadata_pos)) {
+ // Currently, we just ignore the patch annotation on fields.
+ // All fields in the patch class are added to the patched class.
+ field->metadata_pos = TokenPosition::kNoSource;
+ }
if (FLAG_enable_mirrors && (field->metadata_pos.IsReal())) {
library_.AddFieldMetadata(class_field, field->metadata_pos);
}
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 657af55..5f0a33e 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -1875,7 +1875,7 @@
// stub.
ASSERT(target_.HasCode());
target_code_ ^= target_.CurrentCode();
- uword pc = pc_offset_.Value() + code_.EntryPoint();
+ uword pc = pc_offset_.Value() + code_.PayloadStart();
CodePatcher::PatchStaticCallAt(pc, code_, target_code_);
}
}
@@ -1932,10 +1932,6 @@
if (entry_.IsICData()) {
ic_ ^= entry_.raw();
- // Only single check ICs are SwitchableCalls that use the ICLookup
- // stubs. Some operators like + have ICData that check the types of
- // arguments in addition to the receiver and use special stubs
- // with fast paths for Smi operations.
if (ic_.NumArgsTested() != 1) continue;
for (intptr_t j = 0; j < ic_.NumberOfChecks(); j++) {
@@ -1944,7 +1940,8 @@
target_ ^= entry_.raw();
ASSERT(target_.HasCode());
target_code_ = target_.CurrentCode();
- entry_point_ = Smi::FromAlignedAddress(target_code_.EntryPoint());
+ entry_point_ =
+ Smi::FromAlignedAddress(target_code_.UncheckedEntryPoint());
ic_.SetCodeAt(j, target_code_);
ic_.SetEntryPointAt(j, entry_point_);
} else {
@@ -2911,7 +2908,7 @@
if (trace_compiler) {
THR_Print("--> '%s' entry: %#" Px " size: %" Pd " time: %" Pd64 " us\n",
function.ToFullyQualifiedCString(),
- Code::Handle(function.CurrentCode()).EntryPoint(),
+ Code::Handle(function.CurrentCode()).PayloadStart(),
Code::Handle(function.CurrentCode()).Size(),
per_compile_timer.TotalElapsedTime());
}
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index b8827c58..ddd5b26 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -203,14 +203,14 @@
// Returns offset into code object.
intptr_t RelativePC() {
- ASSERT(pc() >= code_.EntryPoint());
- return static_cast<intptr_t>(pc() - code_.EntryPoint());
+ ASSERT(pc() >= code_.PayloadStart());
+ return static_cast<intptr_t>(pc() - code_.PayloadStart());
}
uint8_t* CodePointer(intptr_t offset) {
const intptr_t size = code_.Size();
ASSERT(offset < size);
- uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code_.EntryPoint());
+ uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code_.PayloadStart());
code_pointer += offset;
return code_pointer;
}
@@ -948,6 +948,14 @@
void Profiler::DumpStackTrace(bool native_stack_trace) {
+ // Allow only one stack trace to prevent recursively printing stack traces if
+ // we hit an assert while printing the stack.
+ static uintptr_t started_dump = 0;
+ if (AtomicOperations::FetchAndIncrement(&started_dump) != 0) {
+ OS::PrintErr("Aborting re-entrant request for stack trace.\n");
+ return;
+ }
+
Thread* thread = Thread::Current();
if (thread == NULL) {
return;
@@ -1261,8 +1269,8 @@
}
-uword CodeDescriptor::Entry() const {
- return code_.EntryPoint();
+uword CodeDescriptor::Start() const {
+ return code_.PayloadStart();
}
@@ -1337,11 +1345,11 @@
for (intptr_t i = 0; i < length() - 1; i++) {
const CodeDescriptor* a = At(i);
const CodeDescriptor* b = At(i + 1);
- ASSERT(a->Entry() < b->Entry());
- ASSERT(FindCode(a->Entry()) == a);
- ASSERT(FindCode(b->Entry()) == b);
- ASSERT(FindCode(a->Entry() + a->Size() - 1) == a);
- ASSERT(FindCode(b->Entry() + b->Size() - 1) == b);
+ ASSERT(a->Start() < b->Start());
+ ASSERT(FindCode(a->Start()) == a);
+ ASSERT(FindCode(b->Start()) == b);
+ ASSERT(FindCode(a->Start() + a->Size() - 1) == a);
+ ASSERT(FindCode(b->Start() + b->Size() - 1) == b);
}
#endif
}
@@ -1362,7 +1370,7 @@
intptr_t step = count / 2;
current += step;
const CodeDescriptor* cd = At(current);
- if (pc >= cd->Entry()) {
+ if (pc >= cd->Start()) {
first = ++current;
count -= step + 1;
} else {
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index dcea1d4..be4f049 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -423,7 +423,7 @@
public:
explicit CodeDescriptor(const Code& code);
- uword Entry() const;
+ uword Start() const;
uword Size() const;
@@ -439,8 +439,8 @@
}
bool Contains(uword pc) const {
- uword end = Entry() + Size();
- return (pc >= Entry()) && (pc < end);
+ uword end = Start() + Size();
+ return (pc >= Start()) && (pc < end);
}
static int Compare(CodeDescriptor* const* a,
@@ -448,12 +448,12 @@
ASSERT(a != NULL);
ASSERT(b != NULL);
- uword a_entry = (*a)->Entry();
- uword b_entry = (*b)->Entry();
+ uword a_start = (*a)->Start();
+ uword b_start = (*b)->Start();
- if (a_entry < b_entry) {
+ if (a_start < b_start) {
return -1;
- } else if (a_entry > b_entry) {
+ } else if (a_start > b_start) {
return 1;
} else {
return 0;
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index f17f38f..eb99c43 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -1181,7 +1181,7 @@
const Code& code,
ProcessedSample* sample,
intptr_t frame_index) {
- intptr_t offset = pc - code.EntryPoint();
+ intptr_t offset = pc - code.PayloadStart();
if (frame_index != 0) {
// 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.
@@ -1341,8 +1341,8 @@
ASSERT(!code.IsNull());
RegisterLiveProfileCode(
new ProfileCode(ProfileCode::kDartCode,
- code.EntryPoint(),
- code.EntryPoint() + code.Size(),
+ code.PayloadStart(),
+ code.PayloadStart() + code.Size(),
code.compile_timestamp(),
code));
}
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 4ab49bd..8bb6232 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -2393,7 +2393,7 @@
while (it.MoveNext()) {
if (it.TokenPos() == tp) {
- return it.PcOffset() + code.EntryPoint();
+ return it.PcOffset() + code.PayloadStart();
}
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 52c424c..1e975d7 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -593,6 +593,7 @@
friend class ApiMessageReader; // GetClassId
friend class Serializer; // GetClassId
friend class Array;
+ friend class Become; // GetClassId
friend class Bigint;
friend class ByteBuffer;
friend class Closure;
@@ -1103,6 +1104,7 @@
RAW_HEAP_OBJECT_IMPLEMENTATION(Code);
uword entry_point_;
+ uword checked_entry_point_;
RawObject** from() {
return reinterpret_cast<RawObject**>(&ptr()->active_instructions_);
diff --git a/runtime/vm/runtime_entry_list.h b/runtime/vm/runtime_entry_list.h
index a63f9bb..51ac960 100644
--- a/runtime/vm/runtime_entry_list.h
+++ b/runtime/vm/runtime_entry_list.h
@@ -44,6 +44,7 @@
V(InitStaticField) \
V(GrowRegExpStack) \
V(CompileFunction) \
+ V(MonomorphicMiss) \
#define LEAF_RUNTIME_ENTRY_LIST(V) \
V(void, PrintStopMessage, const char*) \
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index c57890a..d5468da 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -2006,21 +2006,37 @@
Smi& slot_offset = Smi::Handle();
Class& element_class = Class::Handle();
Array& element_field_map = Array::Handle();
+ LinkedHashMap& map = LinkedHashMap::Handle();
+ Array& map_data = Array::Handle();
Field& field = Field::Handle();
limit = Utils::Minimum(limit, length);
for (intptr_t i = 0; i < limit; ++i) {
JSONObject jselement(&elements);
element = path.At(i * 2);
- jselement.AddProperty("index", i);
jselement.AddProperty("value", element);
- // Interpret the word offset from parent as list index or instance field.
- // TODO(koda): User-friendly interpretation for map entries.
+ // Interpret the word offset from parent as list index, map key
+ // or instance field.
if (i > 0) {
slot_offset ^= path.At((i * 2) - 1);
- if (element.IsArray()) {
+ jselement.AddProperty("offset", slot_offset.Value());
+ if (element.IsArray() || element.IsGrowableObjectArray()) {
intptr_t element_index = slot_offset.Value() -
(Array::element_offset(0) >> kWordSizeLog2);
jselement.AddProperty("parentListIndex", element_index);
+ } else if (element.IsLinkedHashMap()) {
+ map = static_cast<RawLinkedHashMap*>(path.At(i * 2));
+ map_data = map.data();
+ intptr_t element_index = slot_offset.Value() -
+ (Array::element_offset(0) >> kWordSizeLog2);
+ LinkedHashMap::Iterator iterator(map);
+ while (iterator.MoveNext()) {
+ if (iterator.CurrentKey() == map_data.At(element_index) ||
+ iterator.CurrentValue() == map_data.At(element_index)) {
+ element = iterator.CurrentKey();
+ jselement.AddProperty("parentMapKey", element);
+ break;
+ }
+ }
} else if (element.IsInstance()) {
element_class ^= element.clazz();
element_field_map = element_class.OffsetToFieldMap();
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 4ec886d..8a19298 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -228,7 +228,7 @@
const Code& code_c = Code::Handle(function_c.CurrentCode());
EXPECT(!code_c.IsNull());
// Use the entry of the code object as it's reference.
- uword entry = code_c.EntryPoint();
+ uword entry = code_c.PayloadStart();
int64_t compile_timestamp = code_c.compile_timestamp();
EXPECT_GT(code_c.Size(), 16);
uword last = entry + code_c.Size();
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 0ef9308..3077c8b6 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -247,7 +247,7 @@
TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
uword pc) {
TokenPosition token_pos = TokenPosition::kNoSource;
- uword pc_offset = pc - code.EntryPoint();
+ uword pc_offset = pc - code.PayloadStart();
const PcDescriptors& descriptors =
PcDescriptors::Handle(code.pc_descriptors());
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index e517fa4..610b857 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -265,7 +265,7 @@
TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
uword pc) {
TokenPosition token_pos = TokenPosition::kNoSource;
- uword pc_offset = pc - code.EntryPoint();
+ uword pc_offset = pc - code.PayloadStart();
const PcDescriptors& descriptors =
PcDescriptors::Handle(code.pc_descriptors());
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index 8eff9ed..eb03c49 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -258,7 +258,7 @@
TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
uword pc) {
TokenPosition token_pos = TokenPosition::kNoSource;
- uword pc_offset = pc - code.EntryPoint();
+ uword pc_offset = pc - code.PayloadStart();
const PcDescriptors& descriptors =
PcDescriptors::Handle(code.pc_descriptors());
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 6a4371f..d6891e2 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -776,7 +776,7 @@
// 2. Write a label at the entry point.
owner = code.owner();
if (owner.IsNull()) {
- const char* name = StubCode::NameOfStub(insns.EntryPoint());
+ const char* name = StubCode::NameOfStub(insns.UncheckedEntryPoint());
assembly_stream_.Print("Precompiled_Stub_%s:\n", name);
} else if (owner.IsClass()) {
str = Class::Cast(owner).Name();
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index d9bd0fa..f93111e 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -108,9 +108,8 @@
Array maps;
maps = Array::null();
Stackmap map;
- const uword entry = reinterpret_cast<uword>(code.instructions()->ptr()) +
- Instructions::HeaderSize();
- map = code.GetStackmap(pc() - entry, &maps, &map);
+ const uword start = Instructions::PayloadStart(code.instructions());
+ map = code.GetStackmap(pc() - start, &maps, &map);
if (!map.IsNull()) {
#if !defined(TARGET_ARCH_DBC)
RawObject** first = reinterpret_cast<RawObject**>(sp());
@@ -260,7 +259,7 @@
if (code.IsNull()) {
return false; // Stub frames do not have exception handlers.
}
- uword pc_offset = pc() - code.EntryPoint();
+ uword pc_offset = pc() - code.PayloadStart();
REUSABLE_EXCEPTION_HANDLERS_HANDLESCOPE(thread);
ExceptionHandlers& handlers = reused_exception_handlers_handle.Handle();
@@ -279,7 +278,7 @@
if ((iter.PcOffset() == pc_offset) && (current_try_index != -1)) {
RawExceptionHandlers::HandlerInfo handler_info;
handlers.GetHandlerInfo(current_try_index, &handler_info);
- *handler_pc = code.EntryPoint() + handler_info.handler_pc_offset;
+ *handler_pc = code.PayloadStart() + handler_info.handler_pc_offset;
*needs_stacktrace = handler_info.needs_stacktrace;
*has_catch_all = handler_info.has_catch_all;
return true;
@@ -294,7 +293,7 @@
if (code.IsNull()) {
return TokenPosition::kNoSource; // Stub frames do not have token_pos.
}
- uword pc_offset = pc() - code.EntryPoint();
+ uword pc_offset = pc() - code.PayloadStart();
const PcDescriptors& descriptors =
PcDescriptors::Handle(code.pc_descriptors());
ASSERT(!descriptors.IsNull());
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index 53a06cb..f0eaf6d 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -28,9 +28,10 @@
StubEntry::StubEntry(const Code& code)
: code_(code.raw()),
- entry_point_(code.EntryPoint()),
+ entry_point_(code.UncheckedEntryPoint()),
+ checked_entry_point_(code.CheckedEntryPoint()),
size_(code.Size()),
- label_(code.EntryPoint()) {
+ label_(code.UncheckedEntryPoint()) {
}
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index d5103e6..bb971e2 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -40,6 +40,7 @@
V(ICLookupThroughFunction) \
V(ICLookupThroughCode) \
V(MegamorphicLookup) \
+ V(MonomorphicMiss) \
V(FixAllocationStubTarget) \
V(Deoptimize) \
V(DeoptimizeLazy) \
@@ -90,6 +91,7 @@
const ExternalLabel& label() const { return label_; }
uword EntryPoint() const { return entry_point_; }
+ uword CheckedEntryPoint() const { return checked_entry_point_; }
RawCode* code() const { return code_; }
intptr_t Size() const { return size_; }
@@ -99,6 +101,7 @@
private:
RawCode* code_;
uword entry_point_;
+ uword checked_entry_point_;
intptr_t size_;
ExternalLabel label_;
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 370711b..59bd06f 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -1990,10 +1990,11 @@
// R0: receiver
// R9: MegamorphicCache (preserved)
// Result:
-// R1: target entry point
// CODE_REG: target Code
// R4: arguments descriptor
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
__ LoadTaggedClassIdMayBeSmi(R0, R0);
// R0: receiver cid as Smi.
__ ldr(R2, FieldAddress(R9, MegamorphicCache::buckets_offset()));
@@ -2028,7 +2029,7 @@
__ ldr(R4, FieldAddress(R9, MegamorphicCache::arguments_descriptor_offset()));
__ ldr(R1, FieldAddress(R0, Function::entry_point_offset()));
__ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
- __ Ret();
+ __ bx(R1);
// Probe failed, check if it is a miss.
__ Bind(&probe_failed);
@@ -2046,10 +2047,11 @@
// R0: receiver
// R9: ICData (preserved)
// Result:
-// R1: target entry point
// CODE_REG: target Code object
// R4: arguments descriptor
void StubCode::GenerateICLookupThroughFunctionStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
Label loop, found, miss;
__ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset()));
__ ldr(R8, FieldAddress(R9, ICData::ic_data_offset()));
@@ -2074,17 +2076,19 @@
__ LoadFromOffset(kWord, R0, R8, target_offset);
__ ldr(R1, FieldAddress(R0, Function::entry_point_offset()));
__ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
- __ Ret();
+ __ bx(R1);
__ Bind(&miss);
__ LoadIsolate(R2);
__ ldr(CODE_REG, Address(R2, Isolate::ic_miss_code_offset()));
__ ldr(R1, FieldAddress(CODE_REG, Code::entry_point_offset()));
- __ Ret();
+ __ bx(R1);
}
void StubCode::GenerateICLookupThroughCodeStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
Label loop, found, miss;
__ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset()));
__ ldr(R8, FieldAddress(R9, ICData::ic_data_offset()));
@@ -2109,13 +2113,34 @@
const intptr_t entry_offset = ICData::EntryPointIndexFor(1) * kWordSize;
__ ldr(R1, Address(R8, entry_offset));
__ ldr(CODE_REG, Address(R8, code_offset));
- __ Ret();
+ __ bx(R1);
__ Bind(&miss);
__ LoadIsolate(R2);
__ ldr(CODE_REG, Address(R2, Isolate::ic_miss_code_offset()));
__ ldr(R1, FieldAddress(CODE_REG, Code::entry_point_offset()));
- __ Ret();
+ __ bx(R1);
+}
+
+
+// Called from the monomorphic checked entry.
+// R0: receiver
+void StubCode::GenerateMonomorphicMissStub(Assembler* assembler) {
+ __ EnterStubFrame();
+ __ Push(R0); // Preserve receiver.
+
+ __ PushObject(Object::null_object()); // Result.
+ __ Push(R0); // Arg0: Receiver
+ __ CallRuntime(kMonomorphicMissRuntimeEntry, 1);
+ __ Drop(1);
+ __ Pop(R9); // result = IC
+
+ __ Pop(R0); // Restore receiver.
+ __ LeaveStubFrame();
+
+ __ ldr(CODE_REG, Address(THR, Thread::ic_lookup_through_code_stub_offset()));
+ __ ldr(R1, FieldAddress(CODE_REG, Code::checked_entry_point_offset()));
+ __ bx(R1);
}
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 9034730..fc092bd 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -2032,10 +2032,11 @@
// R0: receiver
// R5: MegamorphicCache (preserved)
// Result:
-// R1: target entry point
// CODE_REG: target Code
// R4: arguments descriptor
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
// Jump if receiver is a smi.
Label smi_case;
__ TestImmediate(R0, kSmiTagMask);
@@ -2083,7 +2084,7 @@
__ ldr(R4, FieldAddress(R5, MegamorphicCache::arguments_descriptor_offset()));
__ ldr(R1, FieldAddress(R0, Function::entry_point_offset()));
__ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
- __ ret();
+ __ br(R1);
// Probe failed, check if it is a miss.
__ Bind(&probe_failed);
@@ -2106,10 +2107,11 @@
// R0: receiver
// R5: ICData (preserved)
// Result:
-// R1: target entry point
// CODE_REG: target Code object
// R4: arguments descriptor
void StubCode::GenerateICLookupThroughFunctionStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
Label loop, found, miss;
__ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset()));
__ ldr(R8, FieldAddress(R5, ICData::ic_data_offset()));
@@ -2134,17 +2136,19 @@
__ ldr(R0, Address(R8, target_offset));
__ ldr(R1, FieldAddress(R0, Function::entry_point_offset()));
__ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
- __ ret();
+ __ br(R1);
__ Bind(&miss);
__ LoadIsolate(R2);
__ ldr(CODE_REG, Address(R2, Isolate::ic_miss_code_offset()));
__ ldr(R1, FieldAddress(CODE_REG, Code::entry_point_offset()));
- __ ret();
+ __ br(R1);
}
void StubCode::GenerateICLookupThroughCodeStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
Label loop, found, miss;
__ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset()));
__ ldr(R8, FieldAddress(R5, ICData::ic_data_offset()));
@@ -2169,13 +2173,34 @@
const intptr_t entry_offset = ICData::EntryPointIndexFor(1) * kWordSize;
__ ldr(R1, Address(R8, entry_offset));
__ ldr(CODE_REG, Address(R8, code_offset));
- __ ret();
+ __ br(R1);
__ Bind(&miss);
__ LoadIsolate(R2);
__ ldr(CODE_REG, Address(R2, Isolate::ic_miss_code_offset()));
__ ldr(R1, FieldAddress(CODE_REG, Code::entry_point_offset()));
- __ ret();
+ __ br(R1);
+}
+
+
+// Called from the monomorphic checked entry.
+// R0: receiver
+void StubCode::GenerateMonomorphicMissStub(Assembler* assembler) {
+ __ EnterStubFrame();
+ __ Push(R0); // Preserve receiver.
+
+ __ PushObject(Object::null_object()); // Result.
+ __ Push(R0); // Arg0: Receiver
+ __ CallRuntime(kMonomorphicMissRuntimeEntry, 1);
+ __ Drop(1);
+ __ Pop(R5); // result = IC
+
+ __ Pop(R0); // Restore receiver.
+ __ LeaveStubFrame();
+
+ __ ldr(CODE_REG, Address(THR, Thread::ic_lookup_through_code_stub_offset()));
+ __ ldr(R1, FieldAddress(CODE_REG, Code::checked_entry_point_offset()));
+ __ br(R1);
}
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 71cf786..15b8aa9 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -2033,7 +2033,6 @@
// EBX: receiver
// ECX: ICData (preserved)
// Result:
-// EBX: target entry point
// EDX: arguments descriptor
void StubCode::GenerateICLookupThroughFunctionStub(Assembler* assembler) {
__ int3();
@@ -2045,6 +2044,10 @@
}
+void StubCode::GenerateMonomorphicMissStub(Assembler* assembler) {
+ __ int3();
+}
+
void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) {
__ int3();
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index f40dd22..dc5788b 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -2150,10 +2150,10 @@
// T0: receiver
// S5: MegamorphicCache (preserved)
// Result:
-// T1: target entry point
-// CODE_REG: target Code
// S4: arguments descriptor
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
__ LoadTaggedClassIdMayBeSmi(T0, T0);
// T0: class ID of the receiver (smi).
__ lw(S4, FieldAddress(S5, MegamorphicCache::arguments_descriptor_offset()));
@@ -2194,7 +2194,7 @@
__ lw(T1, FieldAddress(T0, Function::entry_point_offset()));
__ lw(CODE_REG, FieldAddress(T0, Function::code_offset()));
- __ Ret();
+ __ jr(T1);
}
@@ -2202,10 +2202,11 @@
// T0: receiver
// S5: ICData (preserved)
// Result:
-// T1: target entry point
// CODE_REG: target Code object
// S4: arguments descriptor
void StubCode::GenerateICLookupThroughFunctionStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
Label loop, found, miss;
__ lw(T6, FieldAddress(S5, ICData::ic_data_offset()));
__ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset()));
@@ -2229,17 +2230,19 @@
__ lw(T0, Address(T6, target_offset));
__ lw(T1, FieldAddress(T0, Function::entry_point_offset()));
__ lw(CODE_REG, FieldAddress(T0, Function::code_offset()));
- __ Ret();
+ __ jr(T1);
__ Bind(&miss);
__ LoadIsolate(T2);
__ lw(CODE_REG, Address(T2, Isolate::ic_miss_code_offset()));
__ lw(T1, FieldAddress(CODE_REG, Code::entry_point_offset()));
- __ Ret();
+ __ jr(T1);
}
void StubCode::GenerateICLookupThroughCodeStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
Label loop, found, miss;
__ lw(T6, FieldAddress(S5, ICData::ic_data_offset()));
__ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset()));
@@ -2263,13 +2266,34 @@
const intptr_t entry_offset = ICData::EntryPointIndexFor(1) * kWordSize;
__ lw(T1, Address(T6, entry_offset));
__ lw(CODE_REG, Address(T6, code_offset));
- __ Ret();
+ __ jr(T1);
__ Bind(&miss);
__ LoadIsolate(T2);
__ lw(CODE_REG, Address(T2, Isolate::ic_miss_code_offset()));
__ lw(T1, FieldAddress(CODE_REG, Code::entry_point_offset()));
- __ Ret();
+ __ jr(T1);
+}
+
+
+// Called from the monomorphic checked entry.
+// T0: receiver
+void StubCode::GenerateMonomorphicMissStub(Assembler* assembler) {
+ __ EnterStubFrame();
+ __ Push(T0); // Preserve receiver.
+
+ __ PushObject(Object::null_object()); // Result.
+ __ Push(T0); // Arg0: Receiver
+ __ CallRuntime(kMonomorphicMissRuntimeEntry, 1);
+ __ Drop(1);
+ __ Pop(S5); // result = IC
+
+ __ Pop(T0); // Restore receiver.
+ __ LeaveStubFrame();
+
+ __ lw(CODE_REG, Address(THR, Thread::ic_lookup_through_code_stub_offset()));
+ __ lw(T1, FieldAddress(CODE_REG, Code::checked_entry_point_offset()));
+ __ jr(T1);
}
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 99393ac..251d463 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -2012,10 +2012,11 @@
// RDI: receiver
// RBX: MegamorphicCache (preserved)
// Result:
-// RCX: target entry point
// CODE_REG: target Code
// R10: arguments descriptor
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
// Jump if receiver is a smi.
Label smi_case;
__ testq(RDI, Immediate(kSmiTagMask));
@@ -2062,8 +2063,7 @@
FieldAddress(RBX, MegamorphicCache::arguments_descriptor_offset()));
__ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
__ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
-
- __ ret();
+ __ jmp(RCX);
// Probe failed, check if it is a miss.
__ Bind(&probe_failed);
@@ -2085,10 +2085,11 @@
// RDI: receiver
// RBX: ICData (preserved)
// Result:
-// RCX: target entry point
// CODE_REG: target Code object
// R10: arguments descriptor
void StubCode::GenerateICLookupThroughFunctionStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
Label loop, found, miss;
__ movq(R13, FieldAddress(RBX, ICData::ic_data_offset()));
@@ -2116,17 +2117,19 @@
__ movq(RAX, Address(R13, target_offset));
__ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
__ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
- __ ret();
+ __ jmp(RCX);
__ Bind(&miss);
__ LoadIsolate(RAX);
__ movq(CODE_REG, Address(RAX, Isolate::ic_miss_code_offset()));
__ movq(RCX, FieldAddress(CODE_REG, Code::entry_point_offset()));
- __ ret();
+ __ jmp(RCX);
}
void StubCode::GenerateICLookupThroughCodeStub(Assembler* assembler) {
+ __ NoMonomorphicCheckedEntry();
+
Label loop, found, miss;
__ movq(R13, FieldAddress(RBX, ICData::ic_data_offset()));
@@ -2154,13 +2157,34 @@
const intptr_t entry_offset = ICData::EntryPointIndexFor(1) * kWordSize;
__ movq(RCX, Address(R13, entry_offset));
__ movq(CODE_REG, Address(R13, code_offset));
- __ ret();
+ __ jmp(RCX);
__ Bind(&miss);
__ LoadIsolate(RAX);
__ movq(CODE_REG, Address(RAX, Isolate::ic_miss_code_offset()));
__ movq(RCX, FieldAddress(CODE_REG, Code::entry_point_offset()));
- __ ret();
+ __ jmp(RCX);
+}
+
+
+// Called from the monomorphic checked entry.
+// RDI: receiver
+void StubCode::GenerateMonomorphicMissStub(Assembler* assembler) {
+ __ EnterStubFrame();
+ __ pushq(RDI); // Preserve receiver.
+
+ __ PushObject(Object::null_object()); // Result.
+ __ pushq(RDI); // Arg0: Receiver
+ __ CallRuntime(kMonomorphicMissRuntimeEntry, 1);
+ __ popq(RBX);
+ __ popq(RBX); // result = IC
+
+ __ popq(RDI); // Restore receiver.
+ __ LeaveStubFrame();
+
+ __ movq(CODE_REG, Address(THR, Thread::ic_lookup_through_code_stub_offset()));
+ __ movq(RCX, FieldAddress(CODE_REG, Code::checked_entry_point_offset()));
+ __ jmp(RCX);
}
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index d9bef66..2e56a8e 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -87,6 +87,10 @@
StubCode::InvokeDartCode_entry()->code(), NULL) \
V(RawCode*, call_to_runtime_stub_, \
StubCode::CallToRuntime_entry()->code(), NULL) \
+ V(RawCode*, monomorphic_miss_stub_, \
+ StubCode::MonomorphicMiss_entry()->code(), NULL) \
+ V(RawCode*, ic_lookup_through_code_stub_, \
+ StubCode::ICLookupThroughCode_entry()->code(), NULL) \
#endif
@@ -105,8 +109,8 @@
StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0) \
V(uword, call_to_runtime_entry_point_, \
StubCode::CallToRuntime_entry()->EntryPoint(), 0) \
- V(uword, megamorphic_lookup_entry_point_, \
- StubCode::MegamorphicLookup_entry()->EntryPoint(), 0) \
+ V(uword, megamorphic_lookup_checked_entry_, \
+ StubCode::MegamorphicLookup_entry()->CheckedEntryPoint(), 0) \
#endif
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index a877a1a..b507c00 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -331,9 +331,13 @@
result = GetReloadErrorOrRootLibrary();
- Isolate* isolate = Isolate::Current();
- if (isolate->reload_context() != NULL) {
- isolate->DeleteReloadContext();
+ {
+ Thread* thread = Thread::Current();
+ TransitionNativeToVM transition(thread);
+ Isolate* isolate = thread->isolate();
+ if (isolate->reload_context() != NULL) {
+ isolate->DeleteReloadContext();
+ }
}
return result;
@@ -403,7 +407,7 @@
OS::Print("Code for test '%s' {\n", name_);
const Instructions& instructions =
Instructions::Handle(code_.instructions());
- uword start = instructions.EntryPoint();
+ uword start = instructions.PayloadStart();
Disassembler::Disassemble(start, start + assembler_->CodeSize());
OS::Print("}\n");
}
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 8622a4f..189515f 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -380,7 +380,8 @@
const Code& code() const { return code_; }
- uword entry() const { return code_.EntryPoint(); }
+ uword payload_start() const { return code_.PayloadStart(); }
+ uword entry() const { return code_.UncheckedEntryPoint(); }
// Invoke/InvokeWithCodeAndThread is used to call assembler test functions
// using the ABI calling convention.
diff --git a/sdk/lib/js/dartium/cached_patches.dart b/sdk/lib/js/dartium/cached_patches.dart
index f9a46f2..fd9453e 100644
--- a/sdk/lib/js/dartium/cached_patches.dart
+++ b/sdk/lib/js/dartium/cached_patches.dart
@@ -16,7 +16,7 @@
*/
const _UNDEFINED_JS_CONST = const Object();
-patch class AbstractWorker {
+@patch class AbstractWorker {
static Type get instanceRuntimeType => AbstractWorkerImpl;
}
@@ -25,7 +25,7 @@
get runtimeType => AbstractWorker;
toString() => super.toString();
}
-patch class AnchorElement {
+@patch class AnchorElement {
static Type get instanceRuntimeType => AnchorElementImpl;
}
@@ -34,7 +34,7 @@
get runtimeType => AnchorElement;
toString() => super.toString();
}
-patch class Animation {
+@patch class Animation {
static Type get instanceRuntimeType => AnimationImpl;
}
@@ -43,7 +43,7 @@
get runtimeType => Animation;
toString() => super.toString();
}
-patch class AnimationEffectReadOnly {
+@patch class AnimationEffectReadOnly {
static Type get instanceRuntimeType => AnimationEffectReadOnlyImpl;
}
@@ -52,7 +52,7 @@
get runtimeType => AnimationEffectReadOnly;
toString() => super.toString();
}
-patch class AnimationEffectTiming {
+@patch class AnimationEffectTiming {
static Type get instanceRuntimeType => AnimationEffectTimingImpl;
}
@@ -61,7 +61,7 @@
get runtimeType => AnimationEffectTiming;
toString() => super.toString();
}
-patch class AnimationEvent {
+@patch class AnimationEvent {
static Type get instanceRuntimeType => AnimationEventImpl;
}
@@ -70,7 +70,7 @@
get runtimeType => AnimationEvent;
toString() => super.toString();
}
-patch class AnimationPlayerEvent {
+@patch class AnimationPlayerEvent {
static Type get instanceRuntimeType => AnimationPlayerEventImpl;
}
@@ -79,7 +79,7 @@
get runtimeType => AnimationPlayerEvent;
toString() => super.toString();
}
-patch class AnimationTimeline {
+@patch class AnimationTimeline {
static Type get instanceRuntimeType => AnimationTimelineImpl;
}
@@ -88,7 +88,7 @@
get runtimeType => AnimationTimeline;
toString() => super.toString();
}
-patch class AppBannerPromptResult {
+@patch class AppBannerPromptResult {
static Type get instanceRuntimeType => AppBannerPromptResultImpl;
}
@@ -97,7 +97,7 @@
get runtimeType => AppBannerPromptResult;
toString() => super.toString();
}
-patch class ApplicationCache {
+@patch class ApplicationCache {
static Type get instanceRuntimeType => ApplicationCacheImpl;
}
@@ -106,7 +106,7 @@
get runtimeType => ApplicationCache;
toString() => super.toString();
}
-patch class ApplicationCacheErrorEvent {
+@patch class ApplicationCacheErrorEvent {
static Type get instanceRuntimeType => ApplicationCacheErrorEventImpl;
}
@@ -115,7 +115,7 @@
get runtimeType => ApplicationCacheErrorEvent;
toString() => super.toString();
}
-patch class AreaElement {
+@patch class AreaElement {
static Type get instanceRuntimeType => AreaElementImpl;
}
@@ -124,7 +124,7 @@
get runtimeType => AreaElement;
toString() => super.toString();
}
-patch class AudioElement {
+@patch class AudioElement {
static Type get instanceRuntimeType => AudioElementImpl;
}
@@ -133,7 +133,7 @@
get runtimeType => AudioElement;
toString() => super.toString();
}
-patch class AudioTrack {
+@patch class AudioTrack {
static Type get instanceRuntimeType => AudioTrackImpl;
}
@@ -142,7 +142,7 @@
get runtimeType => AudioTrack;
toString() => super.toString();
}
-patch class AudioTrackList {
+@patch class AudioTrackList {
static Type get instanceRuntimeType => AudioTrackListImpl;
}
@@ -151,7 +151,7 @@
get runtimeType => AudioTrackList;
toString() => super.toString();
}
-patch class AutocompleteErrorEvent {
+@patch class AutocompleteErrorEvent {
static Type get instanceRuntimeType => AutocompleteErrorEventImpl;
}
@@ -160,7 +160,7 @@
get runtimeType => AutocompleteErrorEvent;
toString() => super.toString();
}
-patch class BRElement {
+@patch class BRElement {
static Type get instanceRuntimeType => BRElementImpl;
}
@@ -169,7 +169,7 @@
get runtimeType => BRElement;
toString() => super.toString();
}
-patch class BarProp {
+@patch class BarProp {
static Type get instanceRuntimeType => BarPropImpl;
}
@@ -178,7 +178,7 @@
get runtimeType => BarProp;
toString() => super.toString();
}
-patch class BaseElement {
+@patch class BaseElement {
static Type get instanceRuntimeType => BaseElementImpl;
}
@@ -187,7 +187,7 @@
get runtimeType => BaseElement;
toString() => super.toString();
}
-patch class BatteryManager {
+@patch class BatteryManager {
static Type get instanceRuntimeType => BatteryManagerImpl;
}
@@ -196,7 +196,7 @@
get runtimeType => BatteryManager;
toString() => super.toString();
}
-patch class BeforeInstallPromptEvent {
+@patch class BeforeInstallPromptEvent {
static Type get instanceRuntimeType => BeforeInstallPromptEventImpl;
}
@@ -205,7 +205,7 @@
get runtimeType => BeforeInstallPromptEvent;
toString() => super.toString();
}
-patch class BeforeUnloadEvent {
+@patch class BeforeUnloadEvent {
static Type get instanceRuntimeType => BeforeUnloadEventImpl;
}
@@ -214,7 +214,7 @@
get runtimeType => BeforeUnloadEvent;
toString() => super.toString();
}
-patch class Blob {
+@patch class Blob {
static Type get instanceRuntimeType => BlobImpl;
}
@@ -223,7 +223,7 @@
get runtimeType => Blob;
toString() => super.toString();
}
-patch class Bluetooth {
+@patch class Bluetooth {
static Type get instanceRuntimeType => BluetoothImpl;
}
@@ -232,7 +232,7 @@
get runtimeType => Bluetooth;
toString() => super.toString();
}
-patch class BluetoothDevice {
+@patch class BluetoothDevice {
static Type get instanceRuntimeType => BluetoothDeviceImpl;
}
@@ -241,7 +241,7 @@
get runtimeType => BluetoothDevice;
toString() => super.toString();
}
-patch class BluetoothGattCharacteristic {
+@patch class BluetoothGattCharacteristic {
static Type get instanceRuntimeType => BluetoothGattCharacteristicImpl;
}
@@ -250,7 +250,7 @@
get runtimeType => BluetoothGattCharacteristic;
toString() => super.toString();
}
-patch class BluetoothGattRemoteServer {
+@patch class BluetoothGattRemoteServer {
static Type get instanceRuntimeType => BluetoothGattRemoteServerImpl;
}
@@ -259,7 +259,7 @@
get runtimeType => BluetoothGattRemoteServer;
toString() => super.toString();
}
-patch class BluetoothGattService {
+@patch class BluetoothGattService {
static Type get instanceRuntimeType => BluetoothGattServiceImpl;
}
@@ -268,7 +268,7 @@
get runtimeType => BluetoothGattService;
toString() => super.toString();
}
-patch class BluetoothUuid {
+@patch class BluetoothUuid {
static Type get instanceRuntimeType => BluetoothUuidImpl;
}
@@ -277,7 +277,7 @@
get runtimeType => BluetoothUuid;
toString() => super.toString();
}
-patch class Body {
+@patch class Body {
static Type get instanceRuntimeType => BodyImpl;
}
@@ -286,7 +286,7 @@
get runtimeType => Body;
toString() => super.toString();
}
-patch class BodyElement {
+@patch class BodyElement {
static Type get instanceRuntimeType => BodyElementImpl;
}
@@ -295,7 +295,7 @@
get runtimeType => BodyElement;
toString() => super.toString();
}
-patch class ButtonElement {
+@patch class ButtonElement {
static Type get instanceRuntimeType => ButtonElementImpl;
}
@@ -304,7 +304,7 @@
get runtimeType => ButtonElement;
toString() => super.toString();
}
-patch class CDataSection {
+@patch class CDataSection {
static Type get instanceRuntimeType => CDataSectionImpl;
}
@@ -313,7 +313,7 @@
get runtimeType => CDataSection;
toString() => super.toString();
}
-patch class CacheStorage {
+@patch class CacheStorage {
static Type get instanceRuntimeType => CacheStorageImpl;
}
@@ -322,7 +322,7 @@
get runtimeType => CacheStorage;
toString() => super.toString();
}
-patch class CanvasElement {
+@patch class CanvasElement {
static Type get instanceRuntimeType => CanvasElementImpl;
}
@@ -331,7 +331,7 @@
get runtimeType => CanvasElement;
toString() => super.toString();
}
-patch class CanvasGradient {
+@patch class CanvasGradient {
static Type get instanceRuntimeType => CanvasGradientImpl;
}
@@ -340,7 +340,7 @@
get runtimeType => CanvasGradient;
toString() => super.toString();
}
-patch class CanvasPattern {
+@patch class CanvasPattern {
static Type get instanceRuntimeType => CanvasPatternImpl;
}
@@ -349,7 +349,7 @@
get runtimeType => CanvasPattern;
toString() => super.toString();
}
-patch class CanvasRenderingContext2D {
+@patch class CanvasRenderingContext2D {
static Type get instanceRuntimeType => CanvasRenderingContext2DImpl;
}
@@ -358,7 +358,7 @@
get runtimeType => CanvasRenderingContext2D;
toString() => super.toString();
}
-patch class CharacterData {
+@patch class CharacterData {
static Type get instanceRuntimeType => CharacterDataImpl;
}
@@ -367,7 +367,7 @@
get runtimeType => CharacterData;
toString() => super.toString();
}
-patch class ChildNode {
+@patch class ChildNode {
static Type get instanceRuntimeType => ChildNodeImpl;
}
@@ -376,7 +376,7 @@
get runtimeType => ChildNode;
toString() => super.toString();
}
-patch class ChromiumValuebuffer {
+@patch class ChromiumValuebuffer {
static Type get instanceRuntimeType => ChromiumValuebufferImpl;
}
@@ -385,7 +385,7 @@
get runtimeType => ChromiumValuebuffer;
toString() => super.toString();
}
-patch class CircularGeofencingRegion {
+@patch class CircularGeofencingRegion {
static Type get instanceRuntimeType => CircularGeofencingRegionImpl;
}
@@ -394,7 +394,7 @@
get runtimeType => CircularGeofencingRegion;
toString() => super.toString();
}
-patch class Client {
+@patch class Client {
static Type get instanceRuntimeType => ClientImpl;
}
@@ -403,7 +403,7 @@
get runtimeType => Client;
toString() => super.toString();
}
-patch class Clients {
+@patch class Clients {
static Type get instanceRuntimeType => ClientsImpl;
}
@@ -412,7 +412,7 @@
get runtimeType => Clients;
toString() => super.toString();
}
-patch class ClipboardEvent {
+@patch class ClipboardEvent {
static Type get instanceRuntimeType => ClipboardEventImpl;
}
@@ -421,7 +421,7 @@
get runtimeType => ClipboardEvent;
toString() => super.toString();
}
-patch class CloseEvent {
+@patch class CloseEvent {
static Type get instanceRuntimeType => CloseEventImpl;
}
@@ -430,7 +430,7 @@
get runtimeType => CloseEvent;
toString() => super.toString();
}
-patch class Comment {
+@patch class Comment {
static Type get instanceRuntimeType => CommentImpl;
}
@@ -439,7 +439,7 @@
get runtimeType => Comment;
toString() => super.toString();
}
-patch class CompositionEvent {
+@patch class CompositionEvent {
static Type get instanceRuntimeType => CompositionEventImpl;
}
@@ -448,7 +448,7 @@
get runtimeType => CompositionEvent;
toString() => super.toString();
}
-patch class CompositorProxy {
+@patch class CompositorProxy {
static Type get instanceRuntimeType => CompositorProxyImpl;
}
@@ -457,7 +457,7 @@
get runtimeType => CompositorProxy;
toString() => super.toString();
}
-patch class CompositorWorker {
+@patch class CompositorWorker {
static Type get instanceRuntimeType => CompositorWorkerImpl;
}
@@ -466,7 +466,7 @@
get runtimeType => CompositorWorker;
toString() => super.toString();
}
-patch class CompositorWorkerGlobalScope {
+@patch class CompositorWorkerGlobalScope {
static Type get instanceRuntimeType => CompositorWorkerGlobalScopeImpl;
}
@@ -475,7 +475,7 @@
get runtimeType => CompositorWorkerGlobalScope;
toString() => super.toString();
}
-patch class Console {
+@patch class Console {
static Type get instanceRuntimeType => ConsoleImpl;
}
@@ -484,7 +484,7 @@
get runtimeType => Console;
toString() => super.toString();
}
-patch class ConsoleBase {
+@patch class ConsoleBase {
static Type get instanceRuntimeType => ConsoleBaseImpl;
}
@@ -493,7 +493,7 @@
get runtimeType => ConsoleBase;
toString() => super.toString();
}
-patch class ContentElement {
+@patch class ContentElement {
static Type get instanceRuntimeType => ContentElementImpl;
}
@@ -502,7 +502,7 @@
get runtimeType => ContentElement;
toString() => super.toString();
}
-patch class Coordinates {
+@patch class Coordinates {
static Type get instanceRuntimeType => CoordinatesImpl;
}
@@ -511,7 +511,7 @@
get runtimeType => Coordinates;
toString() => super.toString();
}
-patch class Credential {
+@patch class Credential {
static Type get instanceRuntimeType => CredentialImpl;
}
@@ -520,7 +520,7 @@
get runtimeType => Credential;
toString() => super.toString();
}
-patch class CredentialsContainer {
+@patch class CredentialsContainer {
static Type get instanceRuntimeType => CredentialsContainerImpl;
}
@@ -529,7 +529,7 @@
get runtimeType => CredentialsContainer;
toString() => super.toString();
}
-patch class CrossOriginConnectEvent {
+@patch class CrossOriginConnectEvent {
static Type get instanceRuntimeType => CrossOriginConnectEventImpl;
}
@@ -538,7 +538,7 @@
get runtimeType => CrossOriginConnectEvent;
toString() => super.toString();
}
-patch class CrossOriginServiceWorkerClient {
+@patch class CrossOriginServiceWorkerClient {
static Type get instanceRuntimeType => CrossOriginServiceWorkerClientImpl;
}
@@ -547,7 +547,7 @@
get runtimeType => CrossOriginServiceWorkerClient;
toString() => super.toString();
}
-patch class Crypto {
+@patch class Crypto {
static Type get instanceRuntimeType => CryptoImpl;
}
@@ -556,7 +556,7 @@
get runtimeType => Crypto;
toString() => super.toString();
}
-patch class CryptoKey {
+@patch class CryptoKey {
static Type get instanceRuntimeType => CryptoKeyImpl;
}
@@ -565,7 +565,7 @@
get runtimeType => CryptoKey;
toString() => super.toString();
}
-patch class Css {
+@patch class Css {
static Type get instanceRuntimeType => CssImpl;
}
@@ -574,7 +574,7 @@
get runtimeType => Css;
toString() => super.toString();
}
-patch class CssCharsetRule {
+@patch class CssCharsetRule {
static Type get instanceRuntimeType => CssCharsetRuleImpl;
}
@@ -583,7 +583,7 @@
get runtimeType => CssCharsetRule;
toString() => super.toString();
}
-patch class CssFontFaceRule {
+@patch class CssFontFaceRule {
static Type get instanceRuntimeType => CssFontFaceRuleImpl;
}
@@ -592,7 +592,7 @@
get runtimeType => CssFontFaceRule;
toString() => super.toString();
}
-patch class CssGroupingRule {
+@patch class CssGroupingRule {
static Type get instanceRuntimeType => CssGroupingRuleImpl;
}
@@ -601,7 +601,7 @@
get runtimeType => CssGroupingRule;
toString() => super.toString();
}
-patch class CssImportRule {
+@patch class CssImportRule {
static Type get instanceRuntimeType => CssImportRuleImpl;
}
@@ -610,7 +610,7 @@
get runtimeType => CssImportRule;
toString() => super.toString();
}
-patch class CssKeyframeRule {
+@patch class CssKeyframeRule {
static Type get instanceRuntimeType => CssKeyframeRuleImpl;
}
@@ -619,7 +619,7 @@
get runtimeType => CssKeyframeRule;
toString() => super.toString();
}
-patch class CssKeyframesRule {
+@patch class CssKeyframesRule {
static Type get instanceRuntimeType => CssKeyframesRuleImpl;
}
@@ -628,7 +628,7 @@
get runtimeType => CssKeyframesRule;
toString() => super.toString();
}
-patch class CssMediaRule {
+@patch class CssMediaRule {
static Type get instanceRuntimeType => CssMediaRuleImpl;
}
@@ -637,7 +637,7 @@
get runtimeType => CssMediaRule;
toString() => super.toString();
}
-patch class CssPageRule {
+@patch class CssPageRule {
static Type get instanceRuntimeType => CssPageRuleImpl;
}
@@ -646,7 +646,7 @@
get runtimeType => CssPageRule;
toString() => super.toString();
}
-patch class CssRule {
+@patch class CssRule {
static Type get instanceRuntimeType => CssRuleImpl;
}
@@ -655,7 +655,7 @@
get runtimeType => CssRule;
toString() => super.toString();
}
-patch class CssStyleDeclaration {
+@patch class CssStyleDeclaration {
static Type get instanceRuntimeType => CssStyleDeclarationImpl;
}
@@ -664,7 +664,7 @@
get runtimeType => CssStyleDeclaration;
toString() => super.toString();
}
-patch class CssStyleRule {
+@patch class CssStyleRule {
static Type get instanceRuntimeType => CssStyleRuleImpl;
}
@@ -673,7 +673,7 @@
get runtimeType => CssStyleRule;
toString() => super.toString();
}
-patch class CssStyleSheet {
+@patch class CssStyleSheet {
static Type get instanceRuntimeType => CssStyleSheetImpl;
}
@@ -682,7 +682,7 @@
get runtimeType => CssStyleSheet;
toString() => super.toString();
}
-patch class CssSupportsRule {
+@patch class CssSupportsRule {
static Type get instanceRuntimeType => CssSupportsRuleImpl;
}
@@ -691,7 +691,7 @@
get runtimeType => CssSupportsRule;
toString() => super.toString();
}
-patch class CssViewportRule {
+@patch class CssViewportRule {
static Type get instanceRuntimeType => CssViewportRuleImpl;
}
@@ -700,7 +700,7 @@
get runtimeType => CssViewportRule;
toString() => super.toString();
}
-patch class CustomEvent {
+@patch class CustomEvent {
static Type get instanceRuntimeType => CustomEventImpl;
}
@@ -709,7 +709,7 @@
get runtimeType => CustomEvent;
toString() => super.toString();
}
-patch class DListElement {
+@patch class DListElement {
static Type get instanceRuntimeType => DListElementImpl;
}
@@ -718,7 +718,7 @@
get runtimeType => DListElement;
toString() => super.toString();
}
-patch class DataListElement {
+@patch class DataListElement {
static Type get instanceRuntimeType => DataListElementImpl;
}
@@ -727,7 +727,7 @@
get runtimeType => DataListElement;
toString() => super.toString();
}
-patch class DataTransfer {
+@patch class DataTransfer {
static Type get instanceRuntimeType => DataTransferImpl;
}
@@ -736,7 +736,7 @@
get runtimeType => DataTransfer;
toString() => super.toString();
}
-patch class DataTransferItem {
+@patch class DataTransferItem {
static Type get instanceRuntimeType => DataTransferItemImpl;
}
@@ -745,7 +745,7 @@
get runtimeType => DataTransferItem;
toString() => super.toString();
}
-patch class DataTransferItemList {
+@patch class DataTransferItemList {
static Type get instanceRuntimeType => DataTransferItemListImpl;
}
@@ -754,7 +754,7 @@
get runtimeType => DataTransferItemList;
toString() => super.toString();
}
-patch class DedicatedWorkerGlobalScope {
+@patch class DedicatedWorkerGlobalScope {
static Type get instanceRuntimeType => DedicatedWorkerGlobalScopeImpl;
}
@@ -763,7 +763,7 @@
get runtimeType => DedicatedWorkerGlobalScope;
toString() => super.toString();
}
-patch class DefaultSessionStartEvent {
+@patch class DefaultSessionStartEvent {
static Type get instanceRuntimeType => DefaultSessionStartEventImpl;
}
@@ -772,7 +772,7 @@
get runtimeType => DefaultSessionStartEvent;
toString() => super.toString();
}
-patch class DeprecatedStorageInfo {
+@patch class DeprecatedStorageInfo {
static Type get instanceRuntimeType => DeprecatedStorageInfoImpl;
}
@@ -781,7 +781,7 @@
get runtimeType => DeprecatedStorageInfo;
toString() => super.toString();
}
-patch class DeprecatedStorageQuota {
+@patch class DeprecatedStorageQuota {
static Type get instanceRuntimeType => DeprecatedStorageQuotaImpl;
}
@@ -790,7 +790,7 @@
get runtimeType => DeprecatedStorageQuota;
toString() => super.toString();
}
-patch class DetailsElement {
+@patch class DetailsElement {
static Type get instanceRuntimeType => DetailsElementImpl;
}
@@ -799,7 +799,7 @@
get runtimeType => DetailsElement;
toString() => super.toString();
}
-patch class DeviceAcceleration {
+@patch class DeviceAcceleration {
static Type get instanceRuntimeType => DeviceAccelerationImpl;
}
@@ -808,7 +808,7 @@
get runtimeType => DeviceAcceleration;
toString() => super.toString();
}
-patch class DeviceLightEvent {
+@patch class DeviceLightEvent {
static Type get instanceRuntimeType => DeviceLightEventImpl;
}
@@ -817,7 +817,7 @@
get runtimeType => DeviceLightEvent;
toString() => super.toString();
}
-patch class DeviceMotionEvent {
+@patch class DeviceMotionEvent {
static Type get instanceRuntimeType => DeviceMotionEventImpl;
}
@@ -826,7 +826,7 @@
get runtimeType => DeviceMotionEvent;
toString() => super.toString();
}
-patch class DeviceOrientationEvent {
+@patch class DeviceOrientationEvent {
static Type get instanceRuntimeType => DeviceOrientationEventImpl;
}
@@ -835,7 +835,7 @@
get runtimeType => DeviceOrientationEvent;
toString() => super.toString();
}
-patch class DeviceRotationRate {
+@patch class DeviceRotationRate {
static Type get instanceRuntimeType => DeviceRotationRateImpl;
}
@@ -844,7 +844,7 @@
get runtimeType => DeviceRotationRate;
toString() => super.toString();
}
-patch class DialogElement {
+@patch class DialogElement {
static Type get instanceRuntimeType => DialogElementImpl;
}
@@ -853,7 +853,7 @@
get runtimeType => DialogElement;
toString() => super.toString();
}
-patch class DirectoryEntry {
+@patch class DirectoryEntry {
static Type get instanceRuntimeType => DirectoryEntryImpl;
}
@@ -862,7 +862,7 @@
get runtimeType => DirectoryEntry;
toString() => super.toString();
}
-patch class DirectoryReader {
+@patch class DirectoryReader {
static Type get instanceRuntimeType => DirectoryReaderImpl;
}
@@ -871,7 +871,7 @@
get runtimeType => DirectoryReader;
toString() => super.toString();
}
-patch class DivElement {
+@patch class DivElement {
static Type get instanceRuntimeType => DivElementImpl;
}
@@ -880,7 +880,7 @@
get runtimeType => DivElement;
toString() => super.toString();
}
-patch class Document {
+@patch class Document {
static Type get instanceRuntimeType => DocumentImpl;
}
@@ -889,7 +889,7 @@
get runtimeType => Document;
toString() => super.toString();
}
-patch class DocumentFragment {
+@patch class DocumentFragment {
static Type get instanceRuntimeType => DocumentFragmentImpl;
}
@@ -898,7 +898,7 @@
get runtimeType => DocumentFragment;
toString() => super.toString();
}
-patch class DomError {
+@patch class DomError {
static Type get instanceRuntimeType => DomErrorImpl;
}
@@ -907,7 +907,7 @@
get runtimeType => DomError;
toString() => super.toString();
}
-patch class DomException {
+@patch class DomException {
static Type get instanceRuntimeType => DomExceptionImpl;
}
@@ -916,7 +916,7 @@
get runtimeType => DomException;
toString() => super.toString();
}
-patch class DomImplementation {
+@patch class DomImplementation {
static Type get instanceRuntimeType => DomImplementationImpl;
}
@@ -925,7 +925,7 @@
get runtimeType => DomImplementation;
toString() => super.toString();
}
-patch class DomIterator {
+@patch class DomIterator {
static Type get instanceRuntimeType => DomIteratorImpl;
}
@@ -934,7 +934,7 @@
get runtimeType => DomIterator;
toString() => super.toString();
}
-patch class DomMatrix {
+@patch class DomMatrix {
static Type get instanceRuntimeType => DomMatrixImpl;
}
@@ -943,7 +943,7 @@
get runtimeType => DomMatrix;
toString() => super.toString();
}
-patch class DomMatrixReadOnly {
+@patch class DomMatrixReadOnly {
static Type get instanceRuntimeType => DomMatrixReadOnlyImpl;
}
@@ -952,7 +952,7 @@
get runtimeType => DomMatrixReadOnly;
toString() => super.toString();
}
-patch class DomParser {
+@patch class DomParser {
static Type get instanceRuntimeType => DomParserImpl;
}
@@ -961,7 +961,7 @@
get runtimeType => DomParser;
toString() => super.toString();
}
-patch class DomPoint {
+@patch class DomPoint {
static Type get instanceRuntimeType => DomPointImpl;
}
@@ -970,7 +970,7 @@
get runtimeType => DomPoint;
toString() => super.toString();
}
-patch class DomPointReadOnly {
+@patch class DomPointReadOnly {
static Type get instanceRuntimeType => DomPointReadOnlyImpl;
}
@@ -979,7 +979,7 @@
get runtimeType => DomPointReadOnly;
toString() => super.toString();
}
-patch class DomRectReadOnly {
+@patch class DomRectReadOnly {
static Type get instanceRuntimeType => DomRectReadOnlyImpl;
}
@@ -988,7 +988,7 @@
get runtimeType => DomRectReadOnly;
toString() => super.toString();
}
-patch class DomSettableTokenList {
+@patch class DomSettableTokenList {
static Type get instanceRuntimeType => DomSettableTokenListImpl;
}
@@ -997,7 +997,7 @@
get runtimeType => DomSettableTokenList;
toString() => super.toString();
}
-patch class DomStringList {
+@patch class DomStringList {
static Type get instanceRuntimeType => DomStringListImpl;
}
@@ -1006,7 +1006,7 @@
get runtimeType => DomStringList;
toString() => super.toString();
}
-patch class DomStringMap {
+@patch class DomStringMap {
static Type get instanceRuntimeType => DomStringMapImpl;
}
@@ -1015,7 +1015,7 @@
get runtimeType => DomStringMap;
toString() => super.toString();
}
-patch class DomTokenList {
+@patch class DomTokenList {
static Type get instanceRuntimeType => DomTokenListImpl;
}
@@ -1024,7 +1024,7 @@
get runtimeType => DomTokenList;
toString() => super.toString();
}
-patch class EffectModel {
+@patch class EffectModel {
static Type get instanceRuntimeType => EffectModelImpl;
}
@@ -1033,7 +1033,7 @@
get runtimeType => EffectModel;
toString() => super.toString();
}
-patch class Element {
+@patch class Element {
static Type get instanceRuntimeType => ElementImpl;
}
@@ -1042,7 +1042,7 @@
get runtimeType => Element;
toString() => super.toString();
}
-patch class EmbedElement {
+@patch class EmbedElement {
static Type get instanceRuntimeType => EmbedElementImpl;
}
@@ -1051,7 +1051,7 @@
get runtimeType => EmbedElement;
toString() => super.toString();
}
-patch class Entry {
+@patch class Entry {
static Type get instanceRuntimeType => EntryImpl;
}
@@ -1060,7 +1060,7 @@
get runtimeType => Entry;
toString() => super.toString();
}
-patch class ErrorEvent {
+@patch class ErrorEvent {
static Type get instanceRuntimeType => ErrorEventImpl;
}
@@ -1069,7 +1069,7 @@
get runtimeType => ErrorEvent;
toString() => super.toString();
}
-patch class Event {
+@patch class Event {
static Type get instanceRuntimeType => EventImpl;
}
@@ -1078,7 +1078,7 @@
get runtimeType => Event;
toString() => super.toString();
}
-patch class EventSource {
+@patch class EventSource {
static Type get instanceRuntimeType => EventSourceImpl;
}
@@ -1087,7 +1087,7 @@
get runtimeType => EventSource;
toString() => super.toString();
}
-patch class EventTarget {
+@patch class EventTarget {
static Type get instanceRuntimeType => EventTargetImpl;
}
@@ -1096,7 +1096,7 @@
get runtimeType => EventTarget;
toString() => super.toString();
}
-patch class ExtendableEvent {
+@patch class ExtendableEvent {
static Type get instanceRuntimeType => ExtendableEventImpl;
}
@@ -1105,7 +1105,7 @@
get runtimeType => ExtendableEvent;
toString() => super.toString();
}
-patch class FederatedCredential {
+@patch class FederatedCredential {
static Type get instanceRuntimeType => FederatedCredentialImpl;
}
@@ -1114,7 +1114,7 @@
get runtimeType => FederatedCredential;
toString() => super.toString();
}
-patch class FetchEvent {
+@patch class FetchEvent {
static Type get instanceRuntimeType => FetchEventImpl;
}
@@ -1123,7 +1123,7 @@
get runtimeType => FetchEvent;
toString() => super.toString();
}
-patch class FieldSetElement {
+@patch class FieldSetElement {
static Type get instanceRuntimeType => FieldSetElementImpl;
}
@@ -1132,7 +1132,7 @@
get runtimeType => FieldSetElement;
toString() => super.toString();
}
-patch class File {
+@patch class File {
static Type get instanceRuntimeType => FileImpl;
}
@@ -1141,7 +1141,7 @@
get runtimeType => File;
toString() => super.toString();
}
-patch class FileEntry {
+@patch class FileEntry {
static Type get instanceRuntimeType => FileEntryImpl;
}
@@ -1150,7 +1150,7 @@
get runtimeType => FileEntry;
toString() => super.toString();
}
-patch class FileError {
+@patch class FileError {
static Type get instanceRuntimeType => FileErrorImpl;
}
@@ -1159,7 +1159,7 @@
get runtimeType => FileError;
toString() => super.toString();
}
-patch class FileList {
+@patch class FileList {
static Type get instanceRuntimeType => FileListImpl;
}
@@ -1168,7 +1168,7 @@
get runtimeType => FileList;
toString() => super.toString();
}
-patch class FileReader {
+@patch class FileReader {
static Type get instanceRuntimeType => FileReaderImpl;
}
@@ -1177,7 +1177,7 @@
get runtimeType => FileReader;
toString() => super.toString();
}
-patch class FileStream {
+@patch class FileStream {
static Type get instanceRuntimeType => FileStreamImpl;
}
@@ -1186,7 +1186,7 @@
get runtimeType => FileStream;
toString() => super.toString();
}
-patch class FileSystem {
+@patch class FileSystem {
static Type get instanceRuntimeType => FileSystemImpl;
}
@@ -1195,7 +1195,7 @@
get runtimeType => FileSystem;
toString() => super.toString();
}
-patch class FileWriter {
+@patch class FileWriter {
static Type get instanceRuntimeType => FileWriterImpl;
}
@@ -1204,7 +1204,7 @@
get runtimeType => FileWriter;
toString() => super.toString();
}
-patch class FocusEvent {
+@patch class FocusEvent {
static Type get instanceRuntimeType => FocusEventImpl;
}
@@ -1213,7 +1213,7 @@
get runtimeType => FocusEvent;
toString() => super.toString();
}
-patch class FontFace {
+@patch class FontFace {
static Type get instanceRuntimeType => FontFaceImpl;
}
@@ -1222,7 +1222,7 @@
get runtimeType => FontFace;
toString() => super.toString();
}
-patch class FontFaceSet {
+@patch class FontFaceSet {
static Type get instanceRuntimeType => FontFaceSetImpl;
}
@@ -1231,7 +1231,7 @@
get runtimeType => FontFaceSet;
toString() => super.toString();
}
-patch class FontFaceSetLoadEvent {
+@patch class FontFaceSetLoadEvent {
static Type get instanceRuntimeType => FontFaceSetLoadEventImpl;
}
@@ -1240,7 +1240,7 @@
get runtimeType => FontFaceSetLoadEvent;
toString() => super.toString();
}
-patch class FormData {
+@patch class FormData {
static Type get instanceRuntimeType => FormDataImpl;
}
@@ -1249,7 +1249,7 @@
get runtimeType => FormData;
toString() => super.toString();
}
-patch class FormElement {
+@patch class FormElement {
static Type get instanceRuntimeType => FormElementImpl;
}
@@ -1258,7 +1258,7 @@
get runtimeType => FormElement;
toString() => super.toString();
}
-patch class Gamepad {
+@patch class Gamepad {
static Type get instanceRuntimeType => GamepadImpl;
}
@@ -1267,7 +1267,7 @@
get runtimeType => Gamepad;
toString() => super.toString();
}
-patch class GamepadButton {
+@patch class GamepadButton {
static Type get instanceRuntimeType => GamepadButtonImpl;
}
@@ -1276,7 +1276,7 @@
get runtimeType => GamepadButton;
toString() => super.toString();
}
-patch class GamepadEvent {
+@patch class GamepadEvent {
static Type get instanceRuntimeType => GamepadEventImpl;
}
@@ -1285,7 +1285,7 @@
get runtimeType => GamepadEvent;
toString() => super.toString();
}
-patch class Geofencing {
+@patch class Geofencing {
static Type get instanceRuntimeType => GeofencingImpl;
}
@@ -1294,7 +1294,7 @@
get runtimeType => Geofencing;
toString() => super.toString();
}
-patch class GeofencingEvent {
+@patch class GeofencingEvent {
static Type get instanceRuntimeType => GeofencingEventImpl;
}
@@ -1303,7 +1303,7 @@
get runtimeType => GeofencingEvent;
toString() => super.toString();
}
-patch class GeofencingRegion {
+@patch class GeofencingRegion {
static Type get instanceRuntimeType => GeofencingRegionImpl;
}
@@ -1312,7 +1312,7 @@
get runtimeType => GeofencingRegion;
toString() => super.toString();
}
-patch class Geolocation {
+@patch class Geolocation {
static Type get instanceRuntimeType => GeolocationImpl;
}
@@ -1321,7 +1321,7 @@
get runtimeType => Geolocation;
toString() => super.toString();
}
-patch class Geoposition {
+@patch class Geoposition {
static Type get instanceRuntimeType => GeopositionImpl;
}
@@ -1330,7 +1330,7 @@
get runtimeType => Geoposition;
toString() => super.toString();
}
-patch class GlobalEventHandlers {
+@patch class GlobalEventHandlers {
static Type get instanceRuntimeType => GlobalEventHandlersImpl;
}
@@ -1339,7 +1339,7 @@
get runtimeType => GlobalEventHandlers;
toString() => super.toString();
}
-patch class HRElement {
+@patch class HRElement {
static Type get instanceRuntimeType => HRElementImpl;
}
@@ -1348,7 +1348,7 @@
get runtimeType => HRElement;
toString() => super.toString();
}
-patch class HashChangeEvent {
+@patch class HashChangeEvent {
static Type get instanceRuntimeType => HashChangeEventImpl;
}
@@ -1357,7 +1357,7 @@
get runtimeType => HashChangeEvent;
toString() => super.toString();
}
-patch class HeadElement {
+@patch class HeadElement {
static Type get instanceRuntimeType => HeadElementImpl;
}
@@ -1366,7 +1366,7 @@
get runtimeType => HeadElement;
toString() => super.toString();
}
-patch class Headers {
+@patch class Headers {
static Type get instanceRuntimeType => HeadersImpl;
}
@@ -1375,7 +1375,7 @@
get runtimeType => Headers;
toString() => super.toString();
}
-patch class HeadingElement {
+@patch class HeadingElement {
static Type get instanceRuntimeType => HeadingElementImpl;
}
@@ -1384,7 +1384,7 @@
get runtimeType => HeadingElement;
toString() => super.toString();
}
-patch class History {
+@patch class History {
static Type get instanceRuntimeType => HistoryImpl;
}
@@ -1393,7 +1393,7 @@
get runtimeType => History;
toString() => super.toString();
}
-patch class HmdvrDevice {
+@patch class HmdvrDevice {
static Type get instanceRuntimeType => HmdvrDeviceImpl;
}
@@ -1402,7 +1402,7 @@
get runtimeType => HmdvrDevice;
toString() => super.toString();
}
-patch class HtmlCollection {
+@patch class HtmlCollection {
static Type get instanceRuntimeType => HtmlCollectionImpl;
}
@@ -1411,7 +1411,7 @@
get runtimeType => HtmlCollection;
toString() => super.toString();
}
-patch class HtmlDocument {
+@patch class HtmlDocument {
static Type get instanceRuntimeType => HtmlDocumentImpl;
}
@@ -1420,7 +1420,7 @@
get runtimeType => HtmlDocument;
toString() => super.toString();
}
-patch class HtmlElement {
+@patch class HtmlElement {
static Type get instanceRuntimeType => HtmlElementImpl;
}
@@ -1429,7 +1429,7 @@
get runtimeType => HtmlElement;
toString() => super.toString();
}
-patch class HtmlFormControlsCollection {
+@patch class HtmlFormControlsCollection {
static Type get instanceRuntimeType => HtmlFormControlsCollectionImpl;
}
@@ -1438,7 +1438,7 @@
get runtimeType => HtmlFormControlsCollection;
toString() => super.toString();
}
-patch class HtmlHtmlElement {
+@patch class HtmlHtmlElement {
static Type get instanceRuntimeType => HtmlHtmlElementImpl;
}
@@ -1447,7 +1447,7 @@
get runtimeType => HtmlHtmlElement;
toString() => super.toString();
}
-patch class HtmlOptionsCollection {
+@patch class HtmlOptionsCollection {
static Type get instanceRuntimeType => HtmlOptionsCollectionImpl;
}
@@ -1456,7 +1456,7 @@
get runtimeType => HtmlOptionsCollection;
toString() => super.toString();
}
-patch class HttpRequest {
+@patch class HttpRequest {
static Type get instanceRuntimeType => HttpRequestImpl;
}
@@ -1465,7 +1465,7 @@
get runtimeType => HttpRequest;
toString() => super.toString();
}
-patch class HttpRequestEventTarget {
+@patch class HttpRequestEventTarget {
static Type get instanceRuntimeType => HttpRequestEventTargetImpl;
}
@@ -1474,7 +1474,7 @@
get runtimeType => HttpRequestEventTarget;
toString() => super.toString();
}
-patch class HttpRequestUpload {
+@patch class HttpRequestUpload {
static Type get instanceRuntimeType => HttpRequestUploadImpl;
}
@@ -1483,7 +1483,7 @@
get runtimeType => HttpRequestUpload;
toString() => super.toString();
}
-patch class IFrameElement {
+@patch class IFrameElement {
static Type get instanceRuntimeType => IFrameElementImpl;
}
@@ -1492,7 +1492,7 @@
get runtimeType => IFrameElement;
toString() => super.toString();
}
-patch class ImageBitmap {
+@patch class ImageBitmap {
static Type get instanceRuntimeType => ImageBitmapImpl;
}
@@ -1501,7 +1501,7 @@
get runtimeType => ImageBitmap;
toString() => super.toString();
}
-patch class ImageData {
+@patch class ImageData {
static Type get instanceRuntimeType => ImageDataImpl;
}
@@ -1510,7 +1510,7 @@
get runtimeType => ImageData;
toString() => super.toString();
}
-patch class ImageElement {
+@patch class ImageElement {
static Type get instanceRuntimeType => ImageElementImpl;
}
@@ -1519,7 +1519,7 @@
get runtimeType => ImageElement;
toString() => super.toString();
}
-patch class InjectedScriptHost {
+@patch class InjectedScriptHost {
static Type get instanceRuntimeType => InjectedScriptHostImpl;
}
@@ -1528,7 +1528,7 @@
get runtimeType => InjectedScriptHost;
toString() => super.toString();
}
-patch class InputDevice {
+@patch class InputDevice {
static Type get instanceRuntimeType => InputDeviceImpl;
}
@@ -1537,7 +1537,7 @@
get runtimeType => InputDevice;
toString() => super.toString();
}
-patch class InputElement {
+@patch class InputElement {
static Type get instanceRuntimeType => InputElementImpl;
}
@@ -1546,7 +1546,7 @@
get runtimeType => InputElement;
toString() => super.toString();
}
-patch class KeyboardEvent {
+@patch class KeyboardEvent {
static Type get instanceRuntimeType => KeyboardEventImpl;
}
@@ -1555,7 +1555,7 @@
get runtimeType => KeyboardEvent;
toString() => super.toString();
}
-patch class KeyframeEffect {
+@patch class KeyframeEffect {
static Type get instanceRuntimeType => KeyframeEffectImpl;
}
@@ -1564,7 +1564,7 @@
get runtimeType => KeyframeEffect;
toString() => super.toString();
}
-patch class KeygenElement {
+@patch class KeygenElement {
static Type get instanceRuntimeType => KeygenElementImpl;
}
@@ -1573,7 +1573,7 @@
get runtimeType => KeygenElement;
toString() => super.toString();
}
-patch class LIElement {
+@patch class LIElement {
static Type get instanceRuntimeType => LIElementImpl;
}
@@ -1582,7 +1582,7 @@
get runtimeType => LIElement;
toString() => super.toString();
}
-patch class LabelElement {
+@patch class LabelElement {
static Type get instanceRuntimeType => LabelElementImpl;
}
@@ -1591,7 +1591,7 @@
get runtimeType => LabelElement;
toString() => super.toString();
}
-patch class LegendElement {
+@patch class LegendElement {
static Type get instanceRuntimeType => LegendElementImpl;
}
@@ -1600,7 +1600,7 @@
get runtimeType => LegendElement;
toString() => super.toString();
}
-patch class LinkElement {
+@patch class LinkElement {
static Type get instanceRuntimeType => LinkElementImpl;
}
@@ -1609,7 +1609,7 @@
get runtimeType => LinkElement;
toString() => super.toString();
}
-patch class Location {
+@patch class Location {
static Type get instanceRuntimeType => LocationImpl;
}
@@ -1618,7 +1618,7 @@
get runtimeType => Location;
toString() => super.toString();
}
-patch class MapElement {
+@patch class MapElement {
static Type get instanceRuntimeType => MapElementImpl;
}
@@ -1627,7 +1627,7 @@
get runtimeType => MapElement;
toString() => super.toString();
}
-patch class MediaController {
+@patch class MediaController {
static Type get instanceRuntimeType => MediaControllerImpl;
}
@@ -1636,7 +1636,7 @@
get runtimeType => MediaController;
toString() => super.toString();
}
-patch class MediaDeviceInfo {
+@patch class MediaDeviceInfo {
static Type get instanceRuntimeType => MediaDeviceInfoImpl;
}
@@ -1645,7 +1645,7 @@
get runtimeType => MediaDeviceInfo;
toString() => super.toString();
}
-patch class MediaDevices {
+@patch class MediaDevices {
static Type get instanceRuntimeType => MediaDevicesImpl;
}
@@ -1654,7 +1654,7 @@
get runtimeType => MediaDevices;
toString() => super.toString();
}
-patch class MediaElement {
+@patch class MediaElement {
static Type get instanceRuntimeType => MediaElementImpl;
}
@@ -1663,7 +1663,7 @@
get runtimeType => MediaElement;
toString() => super.toString();
}
-patch class MediaEncryptedEvent {
+@patch class MediaEncryptedEvent {
static Type get instanceRuntimeType => MediaEncryptedEventImpl;
}
@@ -1672,7 +1672,7 @@
get runtimeType => MediaEncryptedEvent;
toString() => super.toString();
}
-patch class MediaError {
+@patch class MediaError {
static Type get instanceRuntimeType => MediaErrorImpl;
}
@@ -1681,7 +1681,7 @@
get runtimeType => MediaError;
toString() => super.toString();
}
-patch class MediaKeyError {
+@patch class MediaKeyError {
static Type get instanceRuntimeType => MediaKeyErrorImpl;
}
@@ -1690,7 +1690,7 @@
get runtimeType => MediaKeyError;
toString() => super.toString();
}
-patch class MediaKeyEvent {
+@patch class MediaKeyEvent {
static Type get instanceRuntimeType => MediaKeyEventImpl;
}
@@ -1699,7 +1699,7 @@
get runtimeType => MediaKeyEvent;
toString() => super.toString();
}
-patch class MediaKeyMessageEvent {
+@patch class MediaKeyMessageEvent {
static Type get instanceRuntimeType => MediaKeyMessageEventImpl;
}
@@ -1708,7 +1708,7 @@
get runtimeType => MediaKeyMessageEvent;
toString() => super.toString();
}
-patch class MediaKeySession {
+@patch class MediaKeySession {
static Type get instanceRuntimeType => MediaKeySessionImpl;
}
@@ -1717,7 +1717,7 @@
get runtimeType => MediaKeySession;
toString() => super.toString();
}
-patch class MediaKeyStatusMap {
+@patch class MediaKeyStatusMap {
static Type get instanceRuntimeType => MediaKeyStatusMapImpl;
}
@@ -1726,7 +1726,7 @@
get runtimeType => MediaKeyStatusMap;
toString() => super.toString();
}
-patch class MediaKeySystemAccess {
+@patch class MediaKeySystemAccess {
static Type get instanceRuntimeType => MediaKeySystemAccessImpl;
}
@@ -1735,7 +1735,7 @@
get runtimeType => MediaKeySystemAccess;
toString() => super.toString();
}
-patch class MediaKeys {
+@patch class MediaKeys {
static Type get instanceRuntimeType => MediaKeysImpl;
}
@@ -1744,7 +1744,7 @@
get runtimeType => MediaKeys;
toString() => super.toString();
}
-patch class MediaList {
+@patch class MediaList {
static Type get instanceRuntimeType => MediaListImpl;
}
@@ -1753,7 +1753,7 @@
get runtimeType => MediaList;
toString() => super.toString();
}
-patch class MediaQueryList {
+@patch class MediaQueryList {
static Type get instanceRuntimeType => MediaQueryListImpl;
}
@@ -1762,7 +1762,7 @@
get runtimeType => MediaQueryList;
toString() => super.toString();
}
-patch class MediaQueryListEvent {
+@patch class MediaQueryListEvent {
static Type get instanceRuntimeType => MediaQueryListEventImpl;
}
@@ -1771,7 +1771,7 @@
get runtimeType => MediaQueryListEvent;
toString() => super.toString();
}
-patch class MediaSession {
+@patch class MediaSession {
static Type get instanceRuntimeType => MediaSessionImpl;
}
@@ -1780,7 +1780,7 @@
get runtimeType => MediaSession;
toString() => super.toString();
}
-patch class MediaSource {
+@patch class MediaSource {
static Type get instanceRuntimeType => MediaSourceImpl;
}
@@ -1789,7 +1789,7 @@
get runtimeType => MediaSource;
toString() => super.toString();
}
-patch class MediaStream {
+@patch class MediaStream {
static Type get instanceRuntimeType => MediaStreamImpl;
}
@@ -1798,7 +1798,7 @@
get runtimeType => MediaStream;
toString() => super.toString();
}
-patch class MediaStreamEvent {
+@patch class MediaStreamEvent {
static Type get instanceRuntimeType => MediaStreamEventImpl;
}
@@ -1807,7 +1807,7 @@
get runtimeType => MediaStreamEvent;
toString() => super.toString();
}
-patch class MediaStreamTrack {
+@patch class MediaStreamTrack {
static Type get instanceRuntimeType => MediaStreamTrackImpl;
}
@@ -1816,7 +1816,7 @@
get runtimeType => MediaStreamTrack;
toString() => super.toString();
}
-patch class MediaStreamTrackEvent {
+@patch class MediaStreamTrackEvent {
static Type get instanceRuntimeType => MediaStreamTrackEventImpl;
}
@@ -1825,7 +1825,7 @@
get runtimeType => MediaStreamTrackEvent;
toString() => super.toString();
}
-patch class MemoryInfo {
+@patch class MemoryInfo {
static Type get instanceRuntimeType => MemoryInfoImpl;
}
@@ -1834,7 +1834,7 @@
get runtimeType => MemoryInfo;
toString() => super.toString();
}
-patch class MenuElement {
+@patch class MenuElement {
static Type get instanceRuntimeType => MenuElementImpl;
}
@@ -1843,7 +1843,7 @@
get runtimeType => MenuElement;
toString() => super.toString();
}
-patch class MenuItemElement {
+@patch class MenuItemElement {
static Type get instanceRuntimeType => MenuItemElementImpl;
}
@@ -1852,7 +1852,7 @@
get runtimeType => MenuItemElement;
toString() => super.toString();
}
-patch class MessageChannel {
+@patch class MessageChannel {
static Type get instanceRuntimeType => MessageChannelImpl;
}
@@ -1861,7 +1861,7 @@
get runtimeType => MessageChannel;
toString() => super.toString();
}
-patch class MessageEvent {
+@patch class MessageEvent {
static Type get instanceRuntimeType => MessageEventImpl;
}
@@ -1870,7 +1870,7 @@
get runtimeType => MessageEvent;
toString() => super.toString();
}
-patch class MessagePort {
+@patch class MessagePort {
static Type get instanceRuntimeType => MessagePortImpl;
}
@@ -1879,7 +1879,7 @@
get runtimeType => MessagePort;
toString() => super.toString();
}
-patch class MetaElement {
+@patch class MetaElement {
static Type get instanceRuntimeType => MetaElementImpl;
}
@@ -1888,7 +1888,7 @@
get runtimeType => MetaElement;
toString() => super.toString();
}
-patch class Metadata {
+@patch class Metadata {
static Type get instanceRuntimeType => MetadataImpl;
}
@@ -1897,7 +1897,7 @@
get runtimeType => Metadata;
toString() => super.toString();
}
-patch class MeterElement {
+@patch class MeterElement {
static Type get instanceRuntimeType => MeterElementImpl;
}
@@ -1906,7 +1906,7 @@
get runtimeType => MeterElement;
toString() => super.toString();
}
-patch class MidiAccess {
+@patch class MidiAccess {
static Type get instanceRuntimeType => MidiAccessImpl;
}
@@ -1915,7 +1915,7 @@
get runtimeType => MidiAccess;
toString() => super.toString();
}
-patch class MidiConnectionEvent {
+@patch class MidiConnectionEvent {
static Type get instanceRuntimeType => MidiConnectionEventImpl;
}
@@ -1924,7 +1924,7 @@
get runtimeType => MidiConnectionEvent;
toString() => super.toString();
}
-patch class MidiInput {
+@patch class MidiInput {
static Type get instanceRuntimeType => MidiInputImpl;
}
@@ -1933,7 +1933,7 @@
get runtimeType => MidiInput;
toString() => super.toString();
}
-patch class MidiInputMap {
+@patch class MidiInputMap {
static Type get instanceRuntimeType => MidiInputMapImpl;
}
@@ -1942,7 +1942,7 @@
get runtimeType => MidiInputMap;
toString() => super.toString();
}
-patch class MidiMessageEvent {
+@patch class MidiMessageEvent {
static Type get instanceRuntimeType => MidiMessageEventImpl;
}
@@ -1951,7 +1951,7 @@
get runtimeType => MidiMessageEvent;
toString() => super.toString();
}
-patch class MidiOutput {
+@patch class MidiOutput {
static Type get instanceRuntimeType => MidiOutputImpl;
}
@@ -1960,7 +1960,7 @@
get runtimeType => MidiOutput;
toString() => super.toString();
}
-patch class MidiOutputMap {
+@patch class MidiOutputMap {
static Type get instanceRuntimeType => MidiOutputMapImpl;
}
@@ -1969,7 +1969,7 @@
get runtimeType => MidiOutputMap;
toString() => super.toString();
}
-patch class MidiPort {
+@patch class MidiPort {
static Type get instanceRuntimeType => MidiPortImpl;
}
@@ -1978,7 +1978,7 @@
get runtimeType => MidiPort;
toString() => super.toString();
}
-patch class MimeType {
+@patch class MimeType {
static Type get instanceRuntimeType => MimeTypeImpl;
}
@@ -1987,7 +1987,7 @@
get runtimeType => MimeType;
toString() => super.toString();
}
-patch class MimeTypeArray {
+@patch class MimeTypeArray {
static Type get instanceRuntimeType => MimeTypeArrayImpl;
}
@@ -1996,7 +1996,7 @@
get runtimeType => MimeTypeArray;
toString() => super.toString();
}
-patch class ModElement {
+@patch class ModElement {
static Type get instanceRuntimeType => ModElementImpl;
}
@@ -2005,7 +2005,7 @@
get runtimeType => ModElement;
toString() => super.toString();
}
-patch class MouseEvent {
+@patch class MouseEvent {
static Type get instanceRuntimeType => MouseEventImpl;
}
@@ -2014,7 +2014,7 @@
get runtimeType => MouseEvent;
toString() => super.toString();
}
-patch class MutationObserver {
+@patch class MutationObserver {
static Type get instanceRuntimeType => MutationObserverImpl;
}
@@ -2023,7 +2023,7 @@
get runtimeType => MutationObserver;
toString() => super.toString();
}
-patch class MutationRecord {
+@patch class MutationRecord {
static Type get instanceRuntimeType => MutationRecordImpl;
}
@@ -2032,7 +2032,7 @@
get runtimeType => MutationRecord;
toString() => super.toString();
}
-patch class Navigator {
+@patch class Navigator {
static Type get instanceRuntimeType => NavigatorImpl;
}
@@ -2041,7 +2041,7 @@
get runtimeType => Navigator;
toString() => super.toString();
}
-patch class NavigatorCpu {
+@patch class NavigatorCpu {
static Type get instanceRuntimeType => NavigatorCpuImpl;
}
@@ -2050,7 +2050,7 @@
get runtimeType => NavigatorCpu;
toString() => super.toString();
}
-patch class NavigatorID {
+@patch class NavigatorID {
static Type get instanceRuntimeType => NavigatorIDImpl;
}
@@ -2059,7 +2059,7 @@
get runtimeType => NavigatorID;
toString() => super.toString();
}
-patch class NavigatorLanguage {
+@patch class NavigatorLanguage {
static Type get instanceRuntimeType => NavigatorLanguageImpl;
}
@@ -2068,7 +2068,7 @@
get runtimeType => NavigatorLanguage;
toString() => super.toString();
}
-patch class NavigatorOnLine {
+@patch class NavigatorOnLine {
static Type get instanceRuntimeType => NavigatorOnLineImpl;
}
@@ -2077,7 +2077,7 @@
get runtimeType => NavigatorOnLine;
toString() => super.toString();
}
-patch class NavigatorStorageUtils {
+@patch class NavigatorStorageUtils {
static Type get instanceRuntimeType => NavigatorStorageUtilsImpl;
}
@@ -2086,7 +2086,7 @@
get runtimeType => NavigatorStorageUtils;
toString() => super.toString();
}
-patch class NavigatorUserMediaError {
+@patch class NavigatorUserMediaError {
static Type get instanceRuntimeType => NavigatorUserMediaErrorImpl;
}
@@ -2095,7 +2095,7 @@
get runtimeType => NavigatorUserMediaError;
toString() => super.toString();
}
-patch class NetworkInformation {
+@patch class NetworkInformation {
static Type get instanceRuntimeType => NetworkInformationImpl;
}
@@ -2104,7 +2104,7 @@
get runtimeType => NetworkInformation;
toString() => super.toString();
}
-patch class Node {
+@patch class Node {
static Type get instanceRuntimeType => NodeImpl;
}
@@ -2113,7 +2113,7 @@
get runtimeType => Node;
toString() => super.toString();
}
-patch class NodeFilter {
+@patch class NodeFilter {
static Type get instanceRuntimeType => NodeFilterImpl;
}
@@ -2122,7 +2122,7 @@
get runtimeType => NodeFilter;
toString() => super.toString();
}
-patch class NodeIterator {
+@patch class NodeIterator {
static Type get instanceRuntimeType => NodeIteratorImpl;
}
@@ -2131,7 +2131,7 @@
get runtimeType => NodeIterator;
toString() => super.toString();
}
-patch class NodeList {
+@patch class NodeList {
static Type get instanceRuntimeType => NodeListImpl;
}
@@ -2140,7 +2140,7 @@
get runtimeType => NodeList;
toString() => super.toString();
}
-patch class NonDocumentTypeChildNode {
+@patch class NonDocumentTypeChildNode {
static Type get instanceRuntimeType => NonDocumentTypeChildNodeImpl;
}
@@ -2149,7 +2149,7 @@
get runtimeType => NonDocumentTypeChildNode;
toString() => super.toString();
}
-patch class NonElementParentNode {
+@patch class NonElementParentNode {
static Type get instanceRuntimeType => NonElementParentNodeImpl;
}
@@ -2158,7 +2158,7 @@
get runtimeType => NonElementParentNode;
toString() => super.toString();
}
-patch class Notification {
+@patch class Notification {
static Type get instanceRuntimeType => NotificationImpl;
}
@@ -2167,7 +2167,7 @@
get runtimeType => Notification;
toString() => super.toString();
}
-patch class NotificationEvent {
+@patch class NotificationEvent {
static Type get instanceRuntimeType => NotificationEventImpl;
}
@@ -2176,7 +2176,7 @@
get runtimeType => NotificationEvent;
toString() => super.toString();
}
-patch class OListElement {
+@patch class OListElement {
static Type get instanceRuntimeType => OListElementImpl;
}
@@ -2185,7 +2185,7 @@
get runtimeType => OListElement;
toString() => super.toString();
}
-patch class ObjectElement {
+@patch class ObjectElement {
static Type get instanceRuntimeType => ObjectElementImpl;
}
@@ -2194,7 +2194,7 @@
get runtimeType => ObjectElement;
toString() => super.toString();
}
-patch class OptGroupElement {
+@patch class OptGroupElement {
static Type get instanceRuntimeType => OptGroupElementImpl;
}
@@ -2203,7 +2203,7 @@
get runtimeType => OptGroupElement;
toString() => super.toString();
}
-patch class OptionElement {
+@patch class OptionElement {
static Type get instanceRuntimeType => OptionElementImpl;
}
@@ -2212,7 +2212,7 @@
get runtimeType => OptionElement;
toString() => super.toString();
}
-patch class OutputElement {
+@patch class OutputElement {
static Type get instanceRuntimeType => OutputElementImpl;
}
@@ -2221,7 +2221,7 @@
get runtimeType => OutputElement;
toString() => super.toString();
}
-patch class PageTransitionEvent {
+@patch class PageTransitionEvent {
static Type get instanceRuntimeType => PageTransitionEventImpl;
}
@@ -2230,7 +2230,7 @@
get runtimeType => PageTransitionEvent;
toString() => super.toString();
}
-patch class ParagraphElement {
+@patch class ParagraphElement {
static Type get instanceRuntimeType => ParagraphElementImpl;
}
@@ -2239,7 +2239,7 @@
get runtimeType => ParagraphElement;
toString() => super.toString();
}
-patch class ParamElement {
+@patch class ParamElement {
static Type get instanceRuntimeType => ParamElementImpl;
}
@@ -2248,7 +2248,7 @@
get runtimeType => ParamElement;
toString() => super.toString();
}
-patch class ParentNode {
+@patch class ParentNode {
static Type get instanceRuntimeType => ParentNodeImpl;
}
@@ -2257,7 +2257,7 @@
get runtimeType => ParentNode;
toString() => super.toString();
}
-patch class PasswordCredential {
+@patch class PasswordCredential {
static Type get instanceRuntimeType => PasswordCredentialImpl;
}
@@ -2266,7 +2266,7 @@
get runtimeType => PasswordCredential;
toString() => super.toString();
}
-patch class Path2D {
+@patch class Path2D {
static Type get instanceRuntimeType => Path2DImpl;
}
@@ -2275,7 +2275,7 @@
get runtimeType => Path2D;
toString() => super.toString();
}
-patch class Performance {
+@patch class Performance {
static Type get instanceRuntimeType => PerformanceImpl;
}
@@ -2284,7 +2284,7 @@
get runtimeType => Performance;
toString() => super.toString();
}
-patch class PerformanceCompositeTiming {
+@patch class PerformanceCompositeTiming {
static Type get instanceRuntimeType => PerformanceCompositeTimingImpl;
}
@@ -2293,7 +2293,7 @@
get runtimeType => PerformanceCompositeTiming;
toString() => super.toString();
}
-patch class PerformanceEntry {
+@patch class PerformanceEntry {
static Type get instanceRuntimeType => PerformanceEntryImpl;
}
@@ -2302,7 +2302,7 @@
get runtimeType => PerformanceEntry;
toString() => super.toString();
}
-patch class PerformanceMark {
+@patch class PerformanceMark {
static Type get instanceRuntimeType => PerformanceMarkImpl;
}
@@ -2311,7 +2311,7 @@
get runtimeType => PerformanceMark;
toString() => super.toString();
}
-patch class PerformanceMeasure {
+@patch class PerformanceMeasure {
static Type get instanceRuntimeType => PerformanceMeasureImpl;
}
@@ -2320,7 +2320,7 @@
get runtimeType => PerformanceMeasure;
toString() => super.toString();
}
-patch class PerformanceNavigation {
+@patch class PerformanceNavigation {
static Type get instanceRuntimeType => PerformanceNavigationImpl;
}
@@ -2329,7 +2329,7 @@
get runtimeType => PerformanceNavigation;
toString() => super.toString();
}
-patch class PerformanceRenderTiming {
+@patch class PerformanceRenderTiming {
static Type get instanceRuntimeType => PerformanceRenderTimingImpl;
}
@@ -2338,7 +2338,7 @@
get runtimeType => PerformanceRenderTiming;
toString() => super.toString();
}
-patch class PerformanceResourceTiming {
+@patch class PerformanceResourceTiming {
static Type get instanceRuntimeType => PerformanceResourceTimingImpl;
}
@@ -2347,7 +2347,7 @@
get runtimeType => PerformanceResourceTiming;
toString() => super.toString();
}
-patch class PerformanceTiming {
+@patch class PerformanceTiming {
static Type get instanceRuntimeType => PerformanceTimingImpl;
}
@@ -2356,7 +2356,7 @@
get runtimeType => PerformanceTiming;
toString() => super.toString();
}
-patch class PeriodicSyncEvent {
+@patch class PeriodicSyncEvent {
static Type get instanceRuntimeType => PeriodicSyncEventImpl;
}
@@ -2365,7 +2365,7 @@
get runtimeType => PeriodicSyncEvent;
toString() => super.toString();
}
-patch class PeriodicSyncManager {
+@patch class PeriodicSyncManager {
static Type get instanceRuntimeType => PeriodicSyncManagerImpl;
}
@@ -2374,7 +2374,7 @@
get runtimeType => PeriodicSyncManager;
toString() => super.toString();
}
-patch class PeriodicSyncRegistration {
+@patch class PeriodicSyncRegistration {
static Type get instanceRuntimeType => PeriodicSyncRegistrationImpl;
}
@@ -2383,7 +2383,7 @@
get runtimeType => PeriodicSyncRegistration;
toString() => super.toString();
}
-patch class PermissionStatus {
+@patch class PermissionStatus {
static Type get instanceRuntimeType => PermissionStatusImpl;
}
@@ -2392,7 +2392,7 @@
get runtimeType => PermissionStatus;
toString() => super.toString();
}
-patch class Permissions {
+@patch class Permissions {
static Type get instanceRuntimeType => PermissionsImpl;
}
@@ -2401,7 +2401,7 @@
get runtimeType => Permissions;
toString() => super.toString();
}
-patch class PictureElement {
+@patch class PictureElement {
static Type get instanceRuntimeType => PictureElementImpl;
}
@@ -2410,7 +2410,7 @@
get runtimeType => PictureElement;
toString() => super.toString();
}
-patch class Plugin {
+@patch class Plugin {
static Type get instanceRuntimeType => PluginImpl;
}
@@ -2419,7 +2419,7 @@
get runtimeType => Plugin;
toString() => super.toString();
}
-patch class PluginArray {
+@patch class PluginArray {
static Type get instanceRuntimeType => PluginArrayImpl;
}
@@ -2428,7 +2428,7 @@
get runtimeType => PluginArray;
toString() => super.toString();
}
-patch class PluginPlaceholderElement {
+@patch class PluginPlaceholderElement {
static Type get instanceRuntimeType => PluginPlaceholderElementImpl;
}
@@ -2437,7 +2437,7 @@
get runtimeType => PluginPlaceholderElement;
toString() => super.toString();
}
-patch class PointerEvent {
+@patch class PointerEvent {
static Type get instanceRuntimeType => PointerEventImpl;
}
@@ -2446,7 +2446,7 @@
get runtimeType => PointerEvent;
toString() => super.toString();
}
-patch class PopStateEvent {
+@patch class PopStateEvent {
static Type get instanceRuntimeType => PopStateEventImpl;
}
@@ -2455,7 +2455,7 @@
get runtimeType => PopStateEvent;
toString() => super.toString();
}
-patch class PositionError {
+@patch class PositionError {
static Type get instanceRuntimeType => PositionErrorImpl;
}
@@ -2464,7 +2464,7 @@
get runtimeType => PositionError;
toString() => super.toString();
}
-patch class PositionSensorVRDevice {
+@patch class PositionSensorVRDevice {
static Type get instanceRuntimeType => PositionSensorVRDeviceImpl;
}
@@ -2473,7 +2473,7 @@
get runtimeType => PositionSensorVRDevice;
toString() => super.toString();
}
-patch class PreElement {
+@patch class PreElement {
static Type get instanceRuntimeType => PreElementImpl;
}
@@ -2482,7 +2482,7 @@
get runtimeType => PreElement;
toString() => super.toString();
}
-patch class Presentation {
+@patch class Presentation {
static Type get instanceRuntimeType => PresentationImpl;
}
@@ -2491,7 +2491,7 @@
get runtimeType => Presentation;
toString() => super.toString();
}
-patch class PresentationAvailability {
+@patch class PresentationAvailability {
static Type get instanceRuntimeType => PresentationAvailabilityImpl;
}
@@ -2500,7 +2500,7 @@
get runtimeType => PresentationAvailability;
toString() => super.toString();
}
-patch class PresentationSession {
+@patch class PresentationSession {
static Type get instanceRuntimeType => PresentationSessionImpl;
}
@@ -2509,7 +2509,7 @@
get runtimeType => PresentationSession;
toString() => super.toString();
}
-patch class ProcessingInstruction {
+@patch class ProcessingInstruction {
static Type get instanceRuntimeType => ProcessingInstructionImpl;
}
@@ -2518,7 +2518,7 @@
get runtimeType => ProcessingInstruction;
toString() => super.toString();
}
-patch class ProgressElement {
+@patch class ProgressElement {
static Type get instanceRuntimeType => ProgressElementImpl;
}
@@ -2527,7 +2527,7 @@
get runtimeType => ProgressElement;
toString() => super.toString();
}
-patch class ProgressEvent {
+@patch class ProgressEvent {
static Type get instanceRuntimeType => ProgressEventImpl;
}
@@ -2536,7 +2536,7 @@
get runtimeType => ProgressEvent;
toString() => super.toString();
}
-patch class PromiseRejectionEvent {
+@patch class PromiseRejectionEvent {
static Type get instanceRuntimeType => PromiseRejectionEventImpl;
}
@@ -2545,7 +2545,7 @@
get runtimeType => PromiseRejectionEvent;
toString() => super.toString();
}
-patch class PushEvent {
+@patch class PushEvent {
static Type get instanceRuntimeType => PushEventImpl;
}
@@ -2554,7 +2554,7 @@
get runtimeType => PushEvent;
toString() => super.toString();
}
-patch class PushManager {
+@patch class PushManager {
static Type get instanceRuntimeType => PushManagerImpl;
}
@@ -2563,7 +2563,7 @@
get runtimeType => PushManager;
toString() => super.toString();
}
-patch class PushMessageData {
+@patch class PushMessageData {
static Type get instanceRuntimeType => PushMessageDataImpl;
}
@@ -2572,7 +2572,7 @@
get runtimeType => PushMessageData;
toString() => super.toString();
}
-patch class PushSubscription {
+@patch class PushSubscription {
static Type get instanceRuntimeType => PushSubscriptionImpl;
}
@@ -2581,7 +2581,7 @@
get runtimeType => PushSubscription;
toString() => super.toString();
}
-patch class QuoteElement {
+@patch class QuoteElement {
static Type get instanceRuntimeType => QuoteElementImpl;
}
@@ -2590,7 +2590,7 @@
get runtimeType => QuoteElement;
toString() => super.toString();
}
-patch class Range {
+@patch class Range {
static Type get instanceRuntimeType => RangeImpl;
}
@@ -2599,7 +2599,7 @@
get runtimeType => Range;
toString() => super.toString();
}
-patch class ReadableByteStream {
+@patch class ReadableByteStream {
static Type get instanceRuntimeType => ReadableByteStreamImpl;
}
@@ -2608,7 +2608,7 @@
get runtimeType => ReadableByteStream;
toString() => super.toString();
}
-patch class ReadableByteStreamReader {
+@patch class ReadableByteStreamReader {
static Type get instanceRuntimeType => ReadableByteStreamReaderImpl;
}
@@ -2617,7 +2617,7 @@
get runtimeType => ReadableByteStreamReader;
toString() => super.toString();
}
-patch class ReadableStream {
+@patch class ReadableStream {
static Type get instanceRuntimeType => ReadableStreamImpl;
}
@@ -2626,7 +2626,7 @@
get runtimeType => ReadableStream;
toString() => super.toString();
}
-patch class ReadableStreamReader {
+@patch class ReadableStreamReader {
static Type get instanceRuntimeType => ReadableStreamReaderImpl;
}
@@ -2635,7 +2635,7 @@
get runtimeType => ReadableStreamReader;
toString() => super.toString();
}
-patch class RelatedEvent {
+@patch class RelatedEvent {
static Type get instanceRuntimeType => RelatedEventImpl;
}
@@ -2644,7 +2644,7 @@
get runtimeType => RelatedEvent;
toString() => super.toString();
}
-patch class RtcDataChannel {
+@patch class RtcDataChannel {
static Type get instanceRuntimeType => RtcDataChannelImpl;
}
@@ -2653,7 +2653,7 @@
get runtimeType => RtcDataChannel;
toString() => super.toString();
}
-patch class RtcDataChannelEvent {
+@patch class RtcDataChannelEvent {
static Type get instanceRuntimeType => RtcDataChannelEventImpl;
}
@@ -2662,7 +2662,7 @@
get runtimeType => RtcDataChannelEvent;
toString() => super.toString();
}
-patch class RtcDtmfSender {
+@patch class RtcDtmfSender {
static Type get instanceRuntimeType => RtcDtmfSenderImpl;
}
@@ -2671,7 +2671,7 @@
get runtimeType => RtcDtmfSender;
toString() => super.toString();
}
-patch class RtcDtmfToneChangeEvent {
+@patch class RtcDtmfToneChangeEvent {
static Type get instanceRuntimeType => RtcDtmfToneChangeEventImpl;
}
@@ -2680,7 +2680,7 @@
get runtimeType => RtcDtmfToneChangeEvent;
toString() => super.toString();
}
-patch class RtcIceCandidate {
+@patch class RtcIceCandidate {
static Type get instanceRuntimeType => RtcIceCandidateImpl;
}
@@ -2689,7 +2689,7 @@
get runtimeType => RtcIceCandidate;
toString() => super.toString();
}
-patch class RtcIceCandidateEvent {
+@patch class RtcIceCandidateEvent {
static Type get instanceRuntimeType => RtcIceCandidateEventImpl;
}
@@ -2698,7 +2698,7 @@
get runtimeType => RtcIceCandidateEvent;
toString() => super.toString();
}
-patch class RtcPeerConnection {
+@patch class RtcPeerConnection {
static Type get instanceRuntimeType => RtcPeerConnectionImpl;
}
@@ -2707,7 +2707,7 @@
get runtimeType => RtcPeerConnection;
toString() => super.toString();
}
-patch class RtcSessionDescription {
+@patch class RtcSessionDescription {
static Type get instanceRuntimeType => RtcSessionDescriptionImpl;
}
@@ -2716,7 +2716,7 @@
get runtimeType => RtcSessionDescription;
toString() => super.toString();
}
-patch class RtcStatsReport {
+@patch class RtcStatsReport {
static Type get instanceRuntimeType => RtcStatsReportImpl;
}
@@ -2725,7 +2725,7 @@
get runtimeType => RtcStatsReport;
toString() => super.toString();
}
-patch class RtcStatsResponse {
+@patch class RtcStatsResponse {
static Type get instanceRuntimeType => RtcStatsResponseImpl;
}
@@ -2734,7 +2734,7 @@
get runtimeType => RtcStatsResponse;
toString() => super.toString();
}
-patch class Screen {
+@patch class Screen {
static Type get instanceRuntimeType => ScreenImpl;
}
@@ -2743,7 +2743,7 @@
get runtimeType => Screen;
toString() => super.toString();
}
-patch class ScreenOrientation {
+@patch class ScreenOrientation {
static Type get instanceRuntimeType => ScreenOrientationImpl;
}
@@ -2752,7 +2752,7 @@
get runtimeType => ScreenOrientation;
toString() => super.toString();
}
-patch class ScriptElement {
+@patch class ScriptElement {
static Type get instanceRuntimeType => ScriptElementImpl;
}
@@ -2761,7 +2761,7 @@
get runtimeType => ScriptElement;
toString() => super.toString();
}
-patch class ScrollState {
+@patch class ScrollState {
static Type get instanceRuntimeType => ScrollStateImpl;
}
@@ -2770,7 +2770,7 @@
get runtimeType => ScrollState;
toString() => super.toString();
}
-patch class SecurityPolicyViolationEvent {
+@patch class SecurityPolicyViolationEvent {
static Type get instanceRuntimeType => SecurityPolicyViolationEventImpl;
}
@@ -2779,7 +2779,7 @@
get runtimeType => SecurityPolicyViolationEvent;
toString() => super.toString();
}
-patch class SelectElement {
+@patch class SelectElement {
static Type get instanceRuntimeType => SelectElementImpl;
}
@@ -2788,7 +2788,7 @@
get runtimeType => SelectElement;
toString() => super.toString();
}
-patch class Selection {
+@patch class Selection {
static Type get instanceRuntimeType => SelectionImpl;
}
@@ -2797,7 +2797,7 @@
get runtimeType => Selection;
toString() => super.toString();
}
-patch class ServicePort {
+@patch class ServicePort {
static Type get instanceRuntimeType => ServicePortImpl;
}
@@ -2806,7 +2806,7 @@
get runtimeType => ServicePort;
toString() => super.toString();
}
-patch class ServicePortCollection {
+@patch class ServicePortCollection {
static Type get instanceRuntimeType => ServicePortCollectionImpl;
}
@@ -2815,7 +2815,7 @@
get runtimeType => ServicePortCollection;
toString() => super.toString();
}
-patch class ServicePortConnectEvent {
+@patch class ServicePortConnectEvent {
static Type get instanceRuntimeType => ServicePortConnectEventImpl;
}
@@ -2824,7 +2824,7 @@
get runtimeType => ServicePortConnectEvent;
toString() => super.toString();
}
-patch class ServiceWorkerContainer {
+@patch class ServiceWorkerContainer {
static Type get instanceRuntimeType => ServiceWorkerContainerImpl;
}
@@ -2833,7 +2833,7 @@
get runtimeType => ServiceWorkerContainer;
toString() => super.toString();
}
-patch class ServiceWorkerGlobalScope {
+@patch class ServiceWorkerGlobalScope {
static Type get instanceRuntimeType => ServiceWorkerGlobalScopeImpl;
}
@@ -2842,7 +2842,7 @@
get runtimeType => ServiceWorkerGlobalScope;
toString() => super.toString();
}
-patch class ServiceWorkerMessageEvent {
+@patch class ServiceWorkerMessageEvent {
static Type get instanceRuntimeType => ServiceWorkerMessageEventImpl;
}
@@ -2851,7 +2851,7 @@
get runtimeType => ServiceWorkerMessageEvent;
toString() => super.toString();
}
-patch class ServiceWorkerRegistration {
+@patch class ServiceWorkerRegistration {
static Type get instanceRuntimeType => ServiceWorkerRegistrationImpl;
}
@@ -2860,7 +2860,7 @@
get runtimeType => ServiceWorkerRegistration;
toString() => super.toString();
}
-patch class ShadowElement {
+@patch class ShadowElement {
static Type get instanceRuntimeType => ShadowElementImpl;
}
@@ -2869,7 +2869,7 @@
get runtimeType => ShadowElement;
toString() => super.toString();
}
-patch class ShadowRoot {
+@patch class ShadowRoot {
static Type get instanceRuntimeType => ShadowRootImpl;
}
@@ -2878,7 +2878,7 @@
get runtimeType => ShadowRoot;
toString() => super.toString();
}
-patch class SharedArrayBuffer {
+@patch class SharedArrayBuffer {
static Type get instanceRuntimeType => SharedArrayBufferImpl;
}
@@ -2887,7 +2887,7 @@
get runtimeType => SharedArrayBuffer;
toString() => super.toString();
}
-patch class SharedWorker {
+@patch class SharedWorker {
static Type get instanceRuntimeType => SharedWorkerImpl;
}
@@ -2896,7 +2896,7 @@
get runtimeType => SharedWorker;
toString() => super.toString();
}
-patch class SharedWorkerGlobalScope {
+@patch class SharedWorkerGlobalScope {
static Type get instanceRuntimeType => SharedWorkerGlobalScopeImpl;
}
@@ -2905,7 +2905,7 @@
get runtimeType => SharedWorkerGlobalScope;
toString() => super.toString();
}
-patch class SourceBuffer {
+@patch class SourceBuffer {
static Type get instanceRuntimeType => SourceBufferImpl;
}
@@ -2914,7 +2914,7 @@
get runtimeType => SourceBuffer;
toString() => super.toString();
}
-patch class SourceBufferList {
+@patch class SourceBufferList {
static Type get instanceRuntimeType => SourceBufferListImpl;
}
@@ -2923,7 +2923,7 @@
get runtimeType => SourceBufferList;
toString() => super.toString();
}
-patch class SourceElement {
+@patch class SourceElement {
static Type get instanceRuntimeType => SourceElementImpl;
}
@@ -2932,7 +2932,7 @@
get runtimeType => SourceElement;
toString() => super.toString();
}
-patch class SourceInfo {
+@patch class SourceInfo {
static Type get instanceRuntimeType => SourceInfoImpl;
}
@@ -2941,7 +2941,7 @@
get runtimeType => SourceInfo;
toString() => super.toString();
}
-patch class SpanElement {
+@patch class SpanElement {
static Type get instanceRuntimeType => SpanElementImpl;
}
@@ -2950,7 +2950,7 @@
get runtimeType => SpanElement;
toString() => super.toString();
}
-patch class SpeechGrammar {
+@patch class SpeechGrammar {
static Type get instanceRuntimeType => SpeechGrammarImpl;
}
@@ -2959,7 +2959,7 @@
get runtimeType => SpeechGrammar;
toString() => super.toString();
}
-patch class SpeechGrammarList {
+@patch class SpeechGrammarList {
static Type get instanceRuntimeType => SpeechGrammarListImpl;
}
@@ -2968,7 +2968,7 @@
get runtimeType => SpeechGrammarList;
toString() => super.toString();
}
-patch class SpeechRecognition {
+@patch class SpeechRecognition {
static Type get instanceRuntimeType => SpeechRecognitionImpl;
}
@@ -2977,7 +2977,7 @@
get runtimeType => SpeechRecognition;
toString() => super.toString();
}
-patch class SpeechRecognitionAlternative {
+@patch class SpeechRecognitionAlternative {
static Type get instanceRuntimeType => SpeechRecognitionAlternativeImpl;
}
@@ -2986,7 +2986,7 @@
get runtimeType => SpeechRecognitionAlternative;
toString() => super.toString();
}
-patch class SpeechRecognitionError {
+@patch class SpeechRecognitionError {
static Type get instanceRuntimeType => SpeechRecognitionErrorImpl;
}
@@ -2995,7 +2995,7 @@
get runtimeType => SpeechRecognitionError;
toString() => super.toString();
}
-patch class SpeechRecognitionEvent {
+@patch class SpeechRecognitionEvent {
static Type get instanceRuntimeType => SpeechRecognitionEventImpl;
}
@@ -3004,7 +3004,7 @@
get runtimeType => SpeechRecognitionEvent;
toString() => super.toString();
}
-patch class SpeechRecognitionResult {
+@patch class SpeechRecognitionResult {
static Type get instanceRuntimeType => SpeechRecognitionResultImpl;
}
@@ -3013,7 +3013,7 @@
get runtimeType => SpeechRecognitionResult;
toString() => super.toString();
}
-patch class SpeechSynthesis {
+@patch class SpeechSynthesis {
static Type get instanceRuntimeType => SpeechSynthesisImpl;
}
@@ -3022,7 +3022,7 @@
get runtimeType => SpeechSynthesis;
toString() => super.toString();
}
-patch class SpeechSynthesisEvent {
+@patch class SpeechSynthesisEvent {
static Type get instanceRuntimeType => SpeechSynthesisEventImpl;
}
@@ -3031,7 +3031,7 @@
get runtimeType => SpeechSynthesisEvent;
toString() => super.toString();
}
-patch class SpeechSynthesisUtterance {
+@patch class SpeechSynthesisUtterance {
static Type get instanceRuntimeType => SpeechSynthesisUtteranceImpl;
}
@@ -3040,7 +3040,7 @@
get runtimeType => SpeechSynthesisUtterance;
toString() => super.toString();
}
-patch class SpeechSynthesisVoice {
+@patch class SpeechSynthesisVoice {
static Type get instanceRuntimeType => SpeechSynthesisVoiceImpl;
}
@@ -3049,7 +3049,7 @@
get runtimeType => SpeechSynthesisVoice;
toString() => super.toString();
}
-patch class StashedMessagePort {
+@patch class StashedMessagePort {
static Type get instanceRuntimeType => StashedMessagePortImpl;
}
@@ -3058,7 +3058,7 @@
get runtimeType => StashedMessagePort;
toString() => super.toString();
}
-patch class StashedPortCollection {
+@patch class StashedPortCollection {
static Type get instanceRuntimeType => StashedPortCollectionImpl;
}
@@ -3067,7 +3067,7 @@
get runtimeType => StashedPortCollection;
toString() => super.toString();
}
-patch class Storage {
+@patch class Storage {
static Type get instanceRuntimeType => StorageImpl;
}
@@ -3076,7 +3076,7 @@
get runtimeType => Storage;
toString() => super.toString();
}
-patch class StorageEvent {
+@patch class StorageEvent {
static Type get instanceRuntimeType => StorageEventImpl;
}
@@ -3085,7 +3085,7 @@
get runtimeType => StorageEvent;
toString() => super.toString();
}
-patch class StorageInfo {
+@patch class StorageInfo {
static Type get instanceRuntimeType => StorageInfoImpl;
}
@@ -3094,7 +3094,7 @@
get runtimeType => StorageInfo;
toString() => super.toString();
}
-patch class StorageQuota {
+@patch class StorageQuota {
static Type get instanceRuntimeType => StorageQuotaImpl;
}
@@ -3103,7 +3103,7 @@
get runtimeType => StorageQuota;
toString() => super.toString();
}
-patch class StyleElement {
+@patch class StyleElement {
static Type get instanceRuntimeType => StyleElementImpl;
}
@@ -3112,7 +3112,7 @@
get runtimeType => StyleElement;
toString() => super.toString();
}
-patch class StyleMedia {
+@patch class StyleMedia {
static Type get instanceRuntimeType => StyleMediaImpl;
}
@@ -3121,7 +3121,7 @@
get runtimeType => StyleMedia;
toString() => super.toString();
}
-patch class StyleSheet {
+@patch class StyleSheet {
static Type get instanceRuntimeType => StyleSheetImpl;
}
@@ -3130,7 +3130,7 @@
get runtimeType => StyleSheet;
toString() => super.toString();
}
-patch class SyncEvent {
+@patch class SyncEvent {
static Type get instanceRuntimeType => SyncEventImpl;
}
@@ -3139,7 +3139,7 @@
get runtimeType => SyncEvent;
toString() => super.toString();
}
-patch class SyncManager {
+@patch class SyncManager {
static Type get instanceRuntimeType => SyncManagerImpl;
}
@@ -3148,7 +3148,7 @@
get runtimeType => SyncManager;
toString() => super.toString();
}
-patch class SyncRegistration {
+@patch class SyncRegistration {
static Type get instanceRuntimeType => SyncRegistrationImpl;
}
@@ -3157,7 +3157,7 @@
get runtimeType => SyncRegistration;
toString() => super.toString();
}
-patch class TableCaptionElement {
+@patch class TableCaptionElement {
static Type get instanceRuntimeType => TableCaptionElementImpl;
}
@@ -3166,7 +3166,7 @@
get runtimeType => TableCaptionElement;
toString() => super.toString();
}
-patch class TableCellElement {
+@patch class TableCellElement {
static Type get instanceRuntimeType => TableCellElementImpl;
}
@@ -3175,7 +3175,7 @@
get runtimeType => TableCellElement;
toString() => super.toString();
}
-patch class TableColElement {
+@patch class TableColElement {
static Type get instanceRuntimeType => TableColElementImpl;
}
@@ -3184,7 +3184,7 @@
get runtimeType => TableColElement;
toString() => super.toString();
}
-patch class TableElement {
+@patch class TableElement {
static Type get instanceRuntimeType => TableElementImpl;
}
@@ -3193,7 +3193,7 @@
get runtimeType => TableElement;
toString() => super.toString();
}
-patch class TableRowElement {
+@patch class TableRowElement {
static Type get instanceRuntimeType => TableRowElementImpl;
}
@@ -3202,7 +3202,7 @@
get runtimeType => TableRowElement;
toString() => super.toString();
}
-patch class TableSectionElement {
+@patch class TableSectionElement {
static Type get instanceRuntimeType => TableSectionElementImpl;
}
@@ -3211,7 +3211,7 @@
get runtimeType => TableSectionElement;
toString() => super.toString();
}
-patch class TemplateElement {
+@patch class TemplateElement {
static Type get instanceRuntimeType => TemplateElementImpl;
}
@@ -3220,7 +3220,7 @@
get runtimeType => TemplateElement;
toString() => super.toString();
}
-patch class Text {
+@patch class Text {
static Type get instanceRuntimeType => TextImpl;
}
@@ -3229,7 +3229,7 @@
get runtimeType => Text;
toString() => super.toString();
}
-patch class TextAreaElement {
+@patch class TextAreaElement {
static Type get instanceRuntimeType => TextAreaElementImpl;
}
@@ -3238,7 +3238,7 @@
get runtimeType => TextAreaElement;
toString() => super.toString();
}
-patch class TextEvent {
+@patch class TextEvent {
static Type get instanceRuntimeType => TextEventImpl;
}
@@ -3247,7 +3247,7 @@
get runtimeType => TextEvent;
toString() => super.toString();
}
-patch class TextMetrics {
+@patch class TextMetrics {
static Type get instanceRuntimeType => TextMetricsImpl;
}
@@ -3256,7 +3256,7 @@
get runtimeType => TextMetrics;
toString() => super.toString();
}
-patch class TextTrack {
+@patch class TextTrack {
static Type get instanceRuntimeType => TextTrackImpl;
}
@@ -3265,7 +3265,7 @@
get runtimeType => TextTrack;
toString() => super.toString();
}
-patch class TextTrackCue {
+@patch class TextTrackCue {
static Type get instanceRuntimeType => TextTrackCueImpl;
}
@@ -3274,7 +3274,7 @@
get runtimeType => TextTrackCue;
toString() => super.toString();
}
-patch class TextTrackCueList {
+@patch class TextTrackCueList {
static Type get instanceRuntimeType => TextTrackCueListImpl;
}
@@ -3283,7 +3283,7 @@
get runtimeType => TextTrackCueList;
toString() => super.toString();
}
-patch class TextTrackList {
+@patch class TextTrackList {
static Type get instanceRuntimeType => TextTrackListImpl;
}
@@ -3292,7 +3292,7 @@
get runtimeType => TextTrackList;
toString() => super.toString();
}
-patch class TimeRanges {
+@patch class TimeRanges {
static Type get instanceRuntimeType => TimeRangesImpl;
}
@@ -3301,7 +3301,7 @@
get runtimeType => TimeRanges;
toString() => super.toString();
}
-patch class TitleElement {
+@patch class TitleElement {
static Type get instanceRuntimeType => TitleElementImpl;
}
@@ -3310,7 +3310,7 @@
get runtimeType => TitleElement;
toString() => super.toString();
}
-patch class Touch {
+@patch class Touch {
static Type get instanceRuntimeType => TouchImpl;
}
@@ -3319,7 +3319,7 @@
get runtimeType => Touch;
toString() => super.toString();
}
-patch class TouchEvent {
+@patch class TouchEvent {
static Type get instanceRuntimeType => TouchEventImpl;
}
@@ -3328,7 +3328,7 @@
get runtimeType => TouchEvent;
toString() => super.toString();
}
-patch class TouchList {
+@patch class TouchList {
static Type get instanceRuntimeType => TouchListImpl;
}
@@ -3337,7 +3337,7 @@
get runtimeType => TouchList;
toString() => super.toString();
}
-patch class TrackDefault {
+@patch class TrackDefault {
static Type get instanceRuntimeType => TrackDefaultImpl;
}
@@ -3346,7 +3346,7 @@
get runtimeType => TrackDefault;
toString() => super.toString();
}
-patch class TrackDefaultList {
+@patch class TrackDefaultList {
static Type get instanceRuntimeType => TrackDefaultListImpl;
}
@@ -3355,7 +3355,7 @@
get runtimeType => TrackDefaultList;
toString() => super.toString();
}
-patch class TrackElement {
+@patch class TrackElement {
static Type get instanceRuntimeType => TrackElementImpl;
}
@@ -3364,7 +3364,7 @@
get runtimeType => TrackElement;
toString() => super.toString();
}
-patch class TrackEvent {
+@patch class TrackEvent {
static Type get instanceRuntimeType => TrackEventImpl;
}
@@ -3373,7 +3373,7 @@
get runtimeType => TrackEvent;
toString() => super.toString();
}
-patch class TransitionEvent {
+@patch class TransitionEvent {
static Type get instanceRuntimeType => TransitionEventImpl;
}
@@ -3382,7 +3382,7 @@
get runtimeType => TransitionEvent;
toString() => super.toString();
}
-patch class TreeWalker {
+@patch class TreeWalker {
static Type get instanceRuntimeType => TreeWalkerImpl;
}
@@ -3391,7 +3391,7 @@
get runtimeType => TreeWalker;
toString() => super.toString();
}
-patch class UIEvent {
+@patch class UIEvent {
static Type get instanceRuntimeType => UIEventImpl;
}
@@ -3400,7 +3400,7 @@
get runtimeType => UIEvent;
toString() => super.toString();
}
-patch class UListElement {
+@patch class UListElement {
static Type get instanceRuntimeType => UListElementImpl;
}
@@ -3409,7 +3409,7 @@
get runtimeType => UListElement;
toString() => super.toString();
}
-patch class UnknownElement {
+@patch class UnknownElement {
static Type get instanceRuntimeType => UnknownElementImpl;
}
@@ -3418,7 +3418,7 @@
get runtimeType => UnknownElement;
toString() => super.toString();
}
-patch class Url {
+@patch class Url {
static Type get instanceRuntimeType => UrlImpl;
}
@@ -3427,7 +3427,7 @@
get runtimeType => Url;
toString() => super.toString();
}
-patch class UrlUtils {
+@patch class UrlUtils {
static Type get instanceRuntimeType => UrlUtilsImpl;
}
@@ -3436,7 +3436,7 @@
get runtimeType => UrlUtils;
toString() => super.toString();
}
-patch class UrlUtilsReadOnly {
+@patch class UrlUtilsReadOnly {
static Type get instanceRuntimeType => UrlUtilsReadOnlyImpl;
}
@@ -3445,7 +3445,7 @@
get runtimeType => UrlUtilsReadOnly;
toString() => super.toString();
}
-patch class VRDevice {
+@patch class VRDevice {
static Type get instanceRuntimeType => VRDeviceImpl;
}
@@ -3454,7 +3454,7 @@
get runtimeType => VRDevice;
toString() => super.toString();
}
-patch class VREyeParameters {
+@patch class VREyeParameters {
static Type get instanceRuntimeType => VREyeParametersImpl;
}
@@ -3463,7 +3463,7 @@
get runtimeType => VREyeParameters;
toString() => super.toString();
}
-patch class VRFieldOfView {
+@patch class VRFieldOfView {
static Type get instanceRuntimeType => VRFieldOfViewImpl;
}
@@ -3472,7 +3472,7 @@
get runtimeType => VRFieldOfView;
toString() => super.toString();
}
-patch class VRPositionState {
+@patch class VRPositionState {
static Type get instanceRuntimeType => VRPositionStateImpl;
}
@@ -3481,7 +3481,7 @@
get runtimeType => VRPositionState;
toString() => super.toString();
}
-patch class ValidityState {
+@patch class ValidityState {
static Type get instanceRuntimeType => ValidityStateImpl;
}
@@ -3490,7 +3490,7 @@
get runtimeType => ValidityState;
toString() => super.toString();
}
-patch class VideoElement {
+@patch class VideoElement {
static Type get instanceRuntimeType => VideoElementImpl;
}
@@ -3499,7 +3499,7 @@
get runtimeType => VideoElement;
toString() => super.toString();
}
-patch class VideoPlaybackQuality {
+@patch class VideoPlaybackQuality {
static Type get instanceRuntimeType => VideoPlaybackQualityImpl;
}
@@ -3508,7 +3508,7 @@
get runtimeType => VideoPlaybackQuality;
toString() => super.toString();
}
-patch class VideoTrack {
+@patch class VideoTrack {
static Type get instanceRuntimeType => VideoTrackImpl;
}
@@ -3517,7 +3517,7 @@
get runtimeType => VideoTrack;
toString() => super.toString();
}
-patch class VideoTrackList {
+@patch class VideoTrackList {
static Type get instanceRuntimeType => VideoTrackListImpl;
}
@@ -3526,7 +3526,7 @@
get runtimeType => VideoTrackList;
toString() => super.toString();
}
-patch class VttCue {
+@patch class VttCue {
static Type get instanceRuntimeType => VttCueImpl;
}
@@ -3535,7 +3535,7 @@
get runtimeType => VttCue;
toString() => super.toString();
}
-patch class VttRegion {
+@patch class VttRegion {
static Type get instanceRuntimeType => VttRegionImpl;
}
@@ -3544,7 +3544,7 @@
get runtimeType => VttRegion;
toString() => super.toString();
}
-patch class VttRegionList {
+@patch class VttRegionList {
static Type get instanceRuntimeType => VttRegionListImpl;
}
@@ -3553,7 +3553,7 @@
get runtimeType => VttRegionList;
toString() => super.toString();
}
-patch class WebSocket {
+@patch class WebSocket {
static Type get instanceRuntimeType => WebSocketImpl;
}
@@ -3562,7 +3562,7 @@
get runtimeType => WebSocket;
toString() => super.toString();
}
-patch class WheelEvent {
+@patch class WheelEvent {
static Type get instanceRuntimeType => WheelEventImpl;
}
@@ -3571,7 +3571,7 @@
get runtimeType => WheelEvent;
toString() => super.toString();
}
-patch class Window {
+@patch class Window {
static Type get instanceRuntimeType => WindowImpl;
}
@@ -3580,7 +3580,7 @@
get runtimeType => Window;
toString() => super.toString();
}
-patch class WindowBase64 {
+@patch class WindowBase64 {
static Type get instanceRuntimeType => WindowBase64Impl;
}
@@ -3589,7 +3589,7 @@
get runtimeType => WindowBase64;
toString() => super.toString();
}
-patch class WindowClient {
+@patch class WindowClient {
static Type get instanceRuntimeType => WindowClientImpl;
}
@@ -3598,7 +3598,7 @@
get runtimeType => WindowClient;
toString() => super.toString();
}
-patch class WindowEventHandlers {
+@patch class WindowEventHandlers {
static Type get instanceRuntimeType => WindowEventHandlersImpl;
}
@@ -3607,7 +3607,7 @@
get runtimeType => WindowEventHandlers;
toString() => super.toString();
}
-patch class Worker {
+@patch class Worker {
static Type get instanceRuntimeType => WorkerImpl;
}
@@ -3616,7 +3616,7 @@
get runtimeType => Worker;
toString() => super.toString();
}
-patch class WorkerConsole {
+@patch class WorkerConsole {
static Type get instanceRuntimeType => WorkerConsoleImpl;
}
@@ -3625,7 +3625,7 @@
get runtimeType => WorkerConsole;
toString() => super.toString();
}
-patch class WorkerGlobalScope {
+@patch class WorkerGlobalScope {
static Type get instanceRuntimeType => WorkerGlobalScopeImpl;
}
@@ -3634,7 +3634,7 @@
get runtimeType => WorkerGlobalScope;
toString() => super.toString();
}
-patch class WorkerPerformance {
+@patch class WorkerPerformance {
static Type get instanceRuntimeType => WorkerPerformanceImpl;
}
@@ -3643,7 +3643,7 @@
get runtimeType => WorkerPerformance;
toString() => super.toString();
}
-patch class XPathEvaluator {
+@patch class XPathEvaluator {
static Type get instanceRuntimeType => XPathEvaluatorImpl;
}
@@ -3652,7 +3652,7 @@
get runtimeType => XPathEvaluator;
toString() => super.toString();
}
-patch class XPathExpression {
+@patch class XPathExpression {
static Type get instanceRuntimeType => XPathExpressionImpl;
}
@@ -3661,7 +3661,7 @@
get runtimeType => XPathExpression;
toString() => super.toString();
}
-patch class XPathNSResolver {
+@patch class XPathNSResolver {
static Type get instanceRuntimeType => XPathNSResolverImpl;
}
@@ -3670,7 +3670,7 @@
get runtimeType => XPathNSResolver;
toString() => super.toString();
}
-patch class XPathResult {
+@patch class XPathResult {
static Type get instanceRuntimeType => XPathResultImpl;
}
@@ -3679,7 +3679,7 @@
get runtimeType => XPathResult;
toString() => super.toString();
}
-patch class XmlDocument {
+@patch class XmlDocument {
static Type get instanceRuntimeType => XmlDocumentImpl;
}
@@ -3688,7 +3688,7 @@
get runtimeType => XmlDocument;
toString() => super.toString();
}
-patch class XmlSerializer {
+@patch class XmlSerializer {
static Type get instanceRuntimeType => XmlSerializerImpl;
}
@@ -3697,7 +3697,7 @@
get runtimeType => XmlSerializer;
toString() => super.toString();
}
-patch class XsltProcessor {
+@patch class XsltProcessor {
static Type get instanceRuntimeType => XsltProcessorImpl;
}
@@ -3706,7 +3706,7 @@
get runtimeType => XsltProcessor;
toString() => super.toString();
}
-patch class _Attr {
+@patch class _Attr {
static Type get instanceRuntimeType => _AttrImpl;
}
@@ -3715,7 +3715,7 @@
get runtimeType => _Attr;
toString() => super.toString();
}
-patch class _Cache {
+@patch class _Cache {
static Type get instanceRuntimeType => _CacheImpl;
}
@@ -3724,7 +3724,7 @@
get runtimeType => _Cache;
toString() => super.toString();
}
-patch class _CanvasPathMethods {
+@patch class _CanvasPathMethods {
static Type get instanceRuntimeType => _CanvasPathMethodsImpl;
}
@@ -3733,7 +3733,7 @@
get runtimeType => _CanvasPathMethods;
toString() => super.toString();
}
-patch class _ClientRect {
+@patch class _ClientRect {
static Type get instanceRuntimeType => _ClientRectImpl;
}
@@ -3742,7 +3742,7 @@
get runtimeType => _ClientRect;
toString() => super.toString();
}
-patch class _ClientRectList {
+@patch class _ClientRectList {
static Type get instanceRuntimeType => _ClientRectListImpl;
}
@@ -3751,7 +3751,7 @@
get runtimeType => _ClientRectList;
toString() => super.toString();
}
-patch class _CssRuleList {
+@patch class _CssRuleList {
static Type get instanceRuntimeType => _CssRuleListImpl;
}
@@ -3760,7 +3760,7 @@
get runtimeType => _CssRuleList;
toString() => super.toString();
}
-patch class _DOMFileSystemSync {
+@patch class _DOMFileSystemSync {
static Type get instanceRuntimeType => _DOMFileSystemSyncImpl;
}
@@ -3769,7 +3769,7 @@
get runtimeType => _DOMFileSystemSync;
toString() => super.toString();
}
-patch class _DirectoryEntrySync {
+@patch class _DirectoryEntrySync {
static Type get instanceRuntimeType => _DirectoryEntrySyncImpl;
}
@@ -3778,7 +3778,7 @@
get runtimeType => _DirectoryEntrySync;
toString() => super.toString();
}
-patch class _DirectoryReaderSync {
+@patch class _DirectoryReaderSync {
static Type get instanceRuntimeType => _DirectoryReaderSyncImpl;
}
@@ -3787,7 +3787,7 @@
get runtimeType => _DirectoryReaderSync;
toString() => super.toString();
}
-patch class _DocumentType {
+@patch class _DocumentType {
static Type get instanceRuntimeType => _DocumentTypeImpl;
}
@@ -3796,7 +3796,7 @@
get runtimeType => _DocumentType;
toString() => super.toString();
}
-patch class _DomRect {
+@patch class _DomRect {
static Type get instanceRuntimeType => _DomRectImpl;
}
@@ -3805,7 +3805,7 @@
get runtimeType => _DomRect;
toString() => super.toString();
}
-patch class _EntrySync {
+@patch class _EntrySync {
static Type get instanceRuntimeType => _EntrySyncImpl;
}
@@ -3814,7 +3814,7 @@
get runtimeType => _EntrySync;
toString() => super.toString();
}
-patch class _FileEntrySync {
+@patch class _FileEntrySync {
static Type get instanceRuntimeType => _FileEntrySyncImpl;
}
@@ -3823,7 +3823,7 @@
get runtimeType => _FileEntrySync;
toString() => super.toString();
}
-patch class _FileReaderSync {
+@patch class _FileReaderSync {
static Type get instanceRuntimeType => _FileReaderSyncImpl;
}
@@ -3832,7 +3832,7 @@
get runtimeType => _FileReaderSync;
toString() => super.toString();
}
-patch class _FileWriterSync {
+@patch class _FileWriterSync {
static Type get instanceRuntimeType => _FileWriterSyncImpl;
}
@@ -3841,7 +3841,7 @@
get runtimeType => _FileWriterSync;
toString() => super.toString();
}
-patch class _GamepadList {
+@patch class _GamepadList {
static Type get instanceRuntimeType => _GamepadListImpl;
}
@@ -3850,7 +3850,7 @@
get runtimeType => _GamepadList;
toString() => super.toString();
}
-patch class _HTMLAllCollection {
+@patch class _HTMLAllCollection {
static Type get instanceRuntimeType => _HTMLAllCollectionImpl;
}
@@ -3859,7 +3859,7 @@
get runtimeType => _HTMLAllCollection;
toString() => super.toString();
}
-patch class _HTMLAppletElement {
+@patch class _HTMLAppletElement {
static Type get instanceRuntimeType => _HTMLAppletElementImpl;
}
@@ -3868,7 +3868,7 @@
get runtimeType => _HTMLAppletElement;
toString() => super.toString();
}
-patch class _HTMLDirectoryElement {
+@patch class _HTMLDirectoryElement {
static Type get instanceRuntimeType => _HTMLDirectoryElementImpl;
}
@@ -3877,7 +3877,7 @@
get runtimeType => _HTMLDirectoryElement;
toString() => super.toString();
}
-patch class _HTMLFontElement {
+@patch class _HTMLFontElement {
static Type get instanceRuntimeType => _HTMLFontElementImpl;
}
@@ -3886,7 +3886,7 @@
get runtimeType => _HTMLFontElement;
toString() => super.toString();
}
-patch class _HTMLFrameElement {
+@patch class _HTMLFrameElement {
static Type get instanceRuntimeType => _HTMLFrameElementImpl;
}
@@ -3895,7 +3895,7 @@
get runtimeType => _HTMLFrameElement;
toString() => super.toString();
}
-patch class _HTMLFrameSetElement {
+@patch class _HTMLFrameSetElement {
static Type get instanceRuntimeType => _HTMLFrameSetElementImpl;
}
@@ -3904,7 +3904,7 @@
get runtimeType => _HTMLFrameSetElement;
toString() => super.toString();
}
-patch class _HTMLMarqueeElement {
+@patch class _HTMLMarqueeElement {
static Type get instanceRuntimeType => _HTMLMarqueeElementImpl;
}
@@ -3913,7 +3913,7 @@
get runtimeType => _HTMLMarqueeElement;
toString() => super.toString();
}
-patch class _NamedNodeMap {
+@patch class _NamedNodeMap {
static Type get instanceRuntimeType => _NamedNodeMapImpl;
}
@@ -3922,7 +3922,7 @@
get runtimeType => _NamedNodeMap;
toString() => super.toString();
}
-patch class _PagePopupController {
+@patch class _PagePopupController {
static Type get instanceRuntimeType => _PagePopupControllerImpl;
}
@@ -3931,7 +3931,7 @@
get runtimeType => _PagePopupController;
toString() => super.toString();
}
-patch class _RadioNodeList {
+@patch class _RadioNodeList {
static Type get instanceRuntimeType => _RadioNodeListImpl;
}
@@ -3940,7 +3940,7 @@
get runtimeType => _RadioNodeList;
toString() => super.toString();
}
-patch class _Request {
+@patch class _Request {
static Type get instanceRuntimeType => _RequestImpl;
}
@@ -3949,7 +3949,7 @@
get runtimeType => _Request;
toString() => super.toString();
}
-patch class _ResourceProgressEvent {
+@patch class _ResourceProgressEvent {
static Type get instanceRuntimeType => _ResourceProgressEventImpl;
}
@@ -3958,7 +3958,7 @@
get runtimeType => _ResourceProgressEvent;
toString() => super.toString();
}
-patch class _Response {
+@patch class _Response {
static Type get instanceRuntimeType => _ResponseImpl;
}
@@ -3967,7 +3967,7 @@
get runtimeType => _Response;
toString() => super.toString();
}
-patch class _ServiceWorker {
+@patch class _ServiceWorker {
static Type get instanceRuntimeType => _ServiceWorkerImpl;
}
@@ -3976,7 +3976,7 @@
get runtimeType => _ServiceWorker;
toString() => super.toString();
}
-patch class _SpeechRecognitionResultList {
+@patch class _SpeechRecognitionResultList {
static Type get instanceRuntimeType => _SpeechRecognitionResultListImpl;
}
@@ -3985,7 +3985,7 @@
get runtimeType => _SpeechRecognitionResultList;
toString() => super.toString();
}
-patch class _StyleSheetList {
+@patch class _StyleSheetList {
static Type get instanceRuntimeType => _StyleSheetListImpl;
}
@@ -3994,7 +3994,7 @@
get runtimeType => _StyleSheetList;
toString() => super.toString();
}
-patch class _SubtleCrypto {
+@patch class _SubtleCrypto {
static Type get instanceRuntimeType => _SubtleCryptoImpl;
}
@@ -4003,7 +4003,7 @@
get runtimeType => _SubtleCrypto;
toString() => super.toString();
}
-patch class _WebKitCSSMatrix {
+@patch class _WebKitCSSMatrix {
static Type get instanceRuntimeType => _WebKitCSSMatrixImpl;
}
@@ -4012,7 +4012,7 @@
get runtimeType => _WebKitCSSMatrix;
toString() => super.toString();
}
-patch class _WindowTimers {
+@patch class _WindowTimers {
static Type get instanceRuntimeType => _WindowTimersImpl;
}
@@ -4021,7 +4021,7 @@
get runtimeType => _WindowTimers;
toString() => super.toString();
}
-patch class _WorkerLocation {
+@patch class _WorkerLocation {
static Type get instanceRuntimeType => _WorkerLocationImpl;
}
@@ -4030,7 +4030,7 @@
get runtimeType => _WorkerLocation;
toString() => super.toString();
}
-patch class _WorkerNavigator {
+@patch class _WorkerNavigator {
static Type get instanceRuntimeType => _WorkerNavigatorImpl;
}
@@ -4039,7 +4039,7 @@
get runtimeType => _WorkerNavigator;
toString() => super.toString();
}
-patch class _XMLHttpRequestProgressEvent {
+@patch class _XMLHttpRequestProgressEvent {
static Type get instanceRuntimeType => _XMLHttpRequestProgressEventImpl;
}
@@ -4058,7 +4058,7 @@
*/
const _UNDEFINED_JS_CONST = const Object();
-patch class Cursor {
+@patch class Cursor {
static Type get instanceRuntimeType => CursorImpl;
}
@@ -4067,7 +4067,7 @@
get runtimeType => Cursor;
toString() => super.toString();
}
-patch class CursorWithValue {
+@patch class CursorWithValue {
static Type get instanceRuntimeType => CursorWithValueImpl;
}
@@ -4076,7 +4076,7 @@
get runtimeType => CursorWithValue;
toString() => super.toString();
}
-patch class Database {
+@patch class Database {
static Type get instanceRuntimeType => DatabaseImpl;
}
@@ -4085,7 +4085,7 @@
get runtimeType => Database;
toString() => super.toString();
}
-patch class IdbFactory {
+@patch class IdbFactory {
static Type get instanceRuntimeType => IdbFactoryImpl;
}
@@ -4094,7 +4094,7 @@
get runtimeType => IdbFactory;
toString() => super.toString();
}
-patch class Index {
+@patch class Index {
static Type get instanceRuntimeType => IndexImpl;
}
@@ -4103,7 +4103,7 @@
get runtimeType => Index;
toString() => super.toString();
}
-patch class KeyRange {
+@patch class KeyRange {
static Type get instanceRuntimeType => KeyRangeImpl;
}
@@ -4112,7 +4112,7 @@
get runtimeType => KeyRange;
toString() => super.toString();
}
-patch class ObjectStore {
+@patch class ObjectStore {
static Type get instanceRuntimeType => ObjectStoreImpl;
}
@@ -4121,7 +4121,7 @@
get runtimeType => ObjectStore;
toString() => super.toString();
}
-patch class OpenDBRequest {
+@patch class OpenDBRequest {
static Type get instanceRuntimeType => OpenDBRequestImpl;
}
@@ -4130,7 +4130,7 @@
get runtimeType => OpenDBRequest;
toString() => super.toString();
}
-patch class Request {
+@patch class Request {
static Type get instanceRuntimeType => RequestImpl;
}
@@ -4139,7 +4139,7 @@
get runtimeType => Request;
toString() => super.toString();
}
-patch class Transaction {
+@patch class Transaction {
static Type get instanceRuntimeType => TransactionImpl;
}
@@ -4148,7 +4148,7 @@
get runtimeType => Transaction;
toString() => super.toString();
}
-patch class VersionChangeEvent {
+@patch class VersionChangeEvent {
static Type get instanceRuntimeType => VersionChangeEventImpl;
}
@@ -4167,7 +4167,7 @@
*/
const _UNDEFINED_JS_CONST = const Object();
-patch class ActiveInfo {
+@patch class ActiveInfo {
static Type get instanceRuntimeType => ActiveInfoImpl;
}
@@ -4176,7 +4176,7 @@
get runtimeType => ActiveInfo;
toString() => super.toString();
}
-patch class AngleInstancedArrays {
+@patch class AngleInstancedArrays {
static Type get instanceRuntimeType => AngleInstancedArraysImpl;
}
@@ -4185,7 +4185,7 @@
get runtimeType => AngleInstancedArrays;
toString() => super.toString();
}
-patch class Buffer {
+@patch class Buffer {
static Type get instanceRuntimeType => BufferImpl;
}
@@ -4194,7 +4194,7 @@
get runtimeType => Buffer;
toString() => super.toString();
}
-patch class ChromiumSubscribeUniform {
+@patch class ChromiumSubscribeUniform {
static Type get instanceRuntimeType => ChromiumSubscribeUniformImpl;
}
@@ -4203,7 +4203,7 @@
get runtimeType => ChromiumSubscribeUniform;
toString() => super.toString();
}
-patch class CompressedTextureAtc {
+@patch class CompressedTextureAtc {
static Type get instanceRuntimeType => CompressedTextureAtcImpl;
}
@@ -4212,7 +4212,7 @@
get runtimeType => CompressedTextureAtc;
toString() => super.toString();
}
-patch class CompressedTextureETC1 {
+@patch class CompressedTextureETC1 {
static Type get instanceRuntimeType => CompressedTextureETC1Impl;
}
@@ -4221,7 +4221,7 @@
get runtimeType => CompressedTextureETC1;
toString() => super.toString();
}
-patch class CompressedTexturePvrtc {
+@patch class CompressedTexturePvrtc {
static Type get instanceRuntimeType => CompressedTexturePvrtcImpl;
}
@@ -4230,7 +4230,7 @@
get runtimeType => CompressedTexturePvrtc;
toString() => super.toString();
}
-patch class CompressedTextureS3TC {
+@patch class CompressedTextureS3TC {
static Type get instanceRuntimeType => CompressedTextureS3TCImpl;
}
@@ -4239,7 +4239,7 @@
get runtimeType => CompressedTextureS3TC;
toString() => super.toString();
}
-patch class ContextEvent {
+@patch class ContextEvent {
static Type get instanceRuntimeType => ContextEventImpl;
}
@@ -4248,7 +4248,7 @@
get runtimeType => ContextEvent;
toString() => super.toString();
}
-patch class DebugRendererInfo {
+@patch class DebugRendererInfo {
static Type get instanceRuntimeType => DebugRendererInfoImpl;
}
@@ -4257,7 +4257,7 @@
get runtimeType => DebugRendererInfo;
toString() => super.toString();
}
-patch class DebugShaders {
+@patch class DebugShaders {
static Type get instanceRuntimeType => DebugShadersImpl;
}
@@ -4266,7 +4266,7 @@
get runtimeType => DebugShaders;
toString() => super.toString();
}
-patch class DepthTexture {
+@patch class DepthTexture {
static Type get instanceRuntimeType => DepthTextureImpl;
}
@@ -4275,7 +4275,7 @@
get runtimeType => DepthTexture;
toString() => super.toString();
}
-patch class DrawBuffers {
+@patch class DrawBuffers {
static Type get instanceRuntimeType => DrawBuffersImpl;
}
@@ -4284,7 +4284,7 @@
get runtimeType => DrawBuffers;
toString() => super.toString();
}
-patch class EXTsRgb {
+@patch class EXTsRgb {
static Type get instanceRuntimeType => EXTsRgbImpl;
}
@@ -4293,7 +4293,7 @@
get runtimeType => EXTsRgb;
toString() => super.toString();
}
-patch class ExtBlendMinMax {
+@patch class ExtBlendMinMax {
static Type get instanceRuntimeType => ExtBlendMinMaxImpl;
}
@@ -4302,7 +4302,7 @@
get runtimeType => ExtBlendMinMax;
toString() => super.toString();
}
-patch class ExtFragDepth {
+@patch class ExtFragDepth {
static Type get instanceRuntimeType => ExtFragDepthImpl;
}
@@ -4311,7 +4311,7 @@
get runtimeType => ExtFragDepth;
toString() => super.toString();
}
-patch class ExtShaderTextureLod {
+@patch class ExtShaderTextureLod {
static Type get instanceRuntimeType => ExtShaderTextureLodImpl;
}
@@ -4320,7 +4320,7 @@
get runtimeType => ExtShaderTextureLod;
toString() => super.toString();
}
-patch class ExtTextureFilterAnisotropic {
+@patch class ExtTextureFilterAnisotropic {
static Type get instanceRuntimeType => ExtTextureFilterAnisotropicImpl;
}
@@ -4329,7 +4329,7 @@
get runtimeType => ExtTextureFilterAnisotropic;
toString() => super.toString();
}
-patch class Framebuffer {
+@patch class Framebuffer {
static Type get instanceRuntimeType => FramebufferImpl;
}
@@ -4338,7 +4338,7 @@
get runtimeType => Framebuffer;
toString() => super.toString();
}
-patch class LoseContext {
+@patch class LoseContext {
static Type get instanceRuntimeType => LoseContextImpl;
}
@@ -4347,7 +4347,7 @@
get runtimeType => LoseContext;
toString() => super.toString();
}
-patch class OesElementIndexUint {
+@patch class OesElementIndexUint {
static Type get instanceRuntimeType => OesElementIndexUintImpl;
}
@@ -4356,7 +4356,7 @@
get runtimeType => OesElementIndexUint;
toString() => super.toString();
}
-patch class OesStandardDerivatives {
+@patch class OesStandardDerivatives {
static Type get instanceRuntimeType => OesStandardDerivativesImpl;
}
@@ -4365,7 +4365,7 @@
get runtimeType => OesStandardDerivatives;
toString() => super.toString();
}
-patch class OesTextureFloat {
+@patch class OesTextureFloat {
static Type get instanceRuntimeType => OesTextureFloatImpl;
}
@@ -4374,7 +4374,7 @@
get runtimeType => OesTextureFloat;
toString() => super.toString();
}
-patch class OesTextureFloatLinear {
+@patch class OesTextureFloatLinear {
static Type get instanceRuntimeType => OesTextureFloatLinearImpl;
}
@@ -4383,7 +4383,7 @@
get runtimeType => OesTextureFloatLinear;
toString() => super.toString();
}
-patch class OesTextureHalfFloat {
+@patch class OesTextureHalfFloat {
static Type get instanceRuntimeType => OesTextureHalfFloatImpl;
}
@@ -4392,7 +4392,7 @@
get runtimeType => OesTextureHalfFloat;
toString() => super.toString();
}
-patch class OesTextureHalfFloatLinear {
+@patch class OesTextureHalfFloatLinear {
static Type get instanceRuntimeType => OesTextureHalfFloatLinearImpl;
}
@@ -4401,7 +4401,7 @@
get runtimeType => OesTextureHalfFloatLinear;
toString() => super.toString();
}
-patch class OesVertexArrayObject {
+@patch class OesVertexArrayObject {
static Type get instanceRuntimeType => OesVertexArrayObjectImpl;
}
@@ -4410,7 +4410,7 @@
get runtimeType => OesVertexArrayObject;
toString() => super.toString();
}
-patch class Program {
+@patch class Program {
static Type get instanceRuntimeType => ProgramImpl;
}
@@ -4419,7 +4419,7 @@
get runtimeType => Program;
toString() => super.toString();
}
-patch class Query {
+@patch class Query {
static Type get instanceRuntimeType => QueryImpl;
}
@@ -4428,7 +4428,7 @@
get runtimeType => Query;
toString() => super.toString();
}
-patch class Renderbuffer {
+@patch class Renderbuffer {
static Type get instanceRuntimeType => RenderbufferImpl;
}
@@ -4437,7 +4437,7 @@
get runtimeType => Renderbuffer;
toString() => super.toString();
}
-patch class RenderingContext {
+@patch class RenderingContext {
static Type get instanceRuntimeType => RenderingContextImpl;
}
@@ -4446,7 +4446,7 @@
get runtimeType => RenderingContext;
toString() => super.toString();
}
-patch class RenderingContext2 {
+@patch class RenderingContext2 {
static Type get instanceRuntimeType => RenderingContext2Impl;
}
@@ -4455,7 +4455,7 @@
get runtimeType => RenderingContext2;
toString() => super.toString();
}
-patch class Sampler {
+@patch class Sampler {
static Type get instanceRuntimeType => SamplerImpl;
}
@@ -4464,7 +4464,7 @@
get runtimeType => Sampler;
toString() => super.toString();
}
-patch class Shader {
+@patch class Shader {
static Type get instanceRuntimeType => ShaderImpl;
}
@@ -4473,7 +4473,7 @@
get runtimeType => Shader;
toString() => super.toString();
}
-patch class ShaderPrecisionFormat {
+@patch class ShaderPrecisionFormat {
static Type get instanceRuntimeType => ShaderPrecisionFormatImpl;
}
@@ -4482,7 +4482,7 @@
get runtimeType => ShaderPrecisionFormat;
toString() => super.toString();
}
-patch class Sync {
+@patch class Sync {
static Type get instanceRuntimeType => SyncImpl;
}
@@ -4491,7 +4491,7 @@
get runtimeType => Sync;
toString() => super.toString();
}
-patch class Texture {
+@patch class Texture {
static Type get instanceRuntimeType => TextureImpl;
}
@@ -4500,7 +4500,7 @@
get runtimeType => Texture;
toString() => super.toString();
}
-patch class TransformFeedback {
+@patch class TransformFeedback {
static Type get instanceRuntimeType => TransformFeedbackImpl;
}
@@ -4509,7 +4509,7 @@
get runtimeType => TransformFeedback;
toString() => super.toString();
}
-patch class UniformLocation {
+@patch class UniformLocation {
static Type get instanceRuntimeType => UniformLocationImpl;
}
@@ -4518,7 +4518,7 @@
get runtimeType => UniformLocation;
toString() => super.toString();
}
-patch class VertexArrayObject {
+@patch class VertexArrayObject {
static Type get instanceRuntimeType => VertexArrayObjectImpl;
}
@@ -4527,7 +4527,7 @@
get runtimeType => VertexArrayObject;
toString() => super.toString();
}
-patch class VertexArrayObjectOes {
+@patch class VertexArrayObjectOes {
static Type get instanceRuntimeType => VertexArrayObjectOesImpl;
}
@@ -4536,7 +4536,7 @@
get runtimeType => VertexArrayObjectOes;
toString() => super.toString();
}
-patch class _WebGL2RenderingContextBase {
+@patch class _WebGL2RenderingContextBase {
static Type get instanceRuntimeType => _WebGL2RenderingContextBaseImpl;
}
@@ -4545,7 +4545,7 @@
get runtimeType => _WebGL2RenderingContextBase;
toString() => super.toString();
}
-patch class _WebGLRenderingContextBase {
+@patch class _WebGLRenderingContextBase {
static Type get instanceRuntimeType => _WebGLRenderingContextBaseImpl;
}
@@ -4564,7 +4564,7 @@
*/
const _UNDEFINED_JS_CONST = const Object();
-patch class SqlDatabase {
+@patch class SqlDatabase {
static Type get instanceRuntimeType => SqlDatabaseImpl;
}
@@ -4573,7 +4573,7 @@
get runtimeType => SqlDatabase;
toString() => super.toString();
}
-patch class SqlError {
+@patch class SqlError {
static Type get instanceRuntimeType => SqlErrorImpl;
}
@@ -4582,7 +4582,7 @@
get runtimeType => SqlError;
toString() => super.toString();
}
-patch class SqlResultSet {
+@patch class SqlResultSet {
static Type get instanceRuntimeType => SqlResultSetImpl;
}
@@ -4591,7 +4591,7 @@
get runtimeType => SqlResultSet;
toString() => super.toString();
}
-patch class SqlResultSetRowList {
+@patch class SqlResultSetRowList {
static Type get instanceRuntimeType => SqlResultSetRowListImpl;
}
@@ -4600,7 +4600,7 @@
get runtimeType => SqlResultSetRowList;
toString() => super.toString();
}
-patch class SqlTransaction {
+@patch class SqlTransaction {
static Type get instanceRuntimeType => SqlTransactionImpl;
}
@@ -4619,7 +4619,7 @@
*/
const _UNDEFINED_JS_CONST = const Object();
-patch class AElement {
+@patch class AElement {
static Type get instanceRuntimeType => AElementImpl;
}
@@ -4628,7 +4628,7 @@
get runtimeType => AElement;
toString() => super.toString();
}
-patch class Angle {
+@patch class Angle {
static Type get instanceRuntimeType => AngleImpl;
}
@@ -4637,7 +4637,7 @@
get runtimeType => Angle;
toString() => super.toString();
}
-patch class AnimateElement {
+@patch class AnimateElement {
static Type get instanceRuntimeType => AnimateElementImpl;
}
@@ -4646,7 +4646,7 @@
get runtimeType => AnimateElement;
toString() => super.toString();
}
-patch class AnimateMotionElement {
+@patch class AnimateMotionElement {
static Type get instanceRuntimeType => AnimateMotionElementImpl;
}
@@ -4655,7 +4655,7 @@
get runtimeType => AnimateMotionElement;
toString() => super.toString();
}
-patch class AnimateTransformElement {
+@patch class AnimateTransformElement {
static Type get instanceRuntimeType => AnimateTransformElementImpl;
}
@@ -4664,7 +4664,7 @@
get runtimeType => AnimateTransformElement;
toString() => super.toString();
}
-patch class AnimatedAngle {
+@patch class AnimatedAngle {
static Type get instanceRuntimeType => AnimatedAngleImpl;
}
@@ -4673,7 +4673,7 @@
get runtimeType => AnimatedAngle;
toString() => super.toString();
}
-patch class AnimatedBoolean {
+@patch class AnimatedBoolean {
static Type get instanceRuntimeType => AnimatedBooleanImpl;
}
@@ -4682,7 +4682,7 @@
get runtimeType => AnimatedBoolean;
toString() => super.toString();
}
-patch class AnimatedEnumeration {
+@patch class AnimatedEnumeration {
static Type get instanceRuntimeType => AnimatedEnumerationImpl;
}
@@ -4691,7 +4691,7 @@
get runtimeType => AnimatedEnumeration;
toString() => super.toString();
}
-patch class AnimatedInteger {
+@patch class AnimatedInteger {
static Type get instanceRuntimeType => AnimatedIntegerImpl;
}
@@ -4700,7 +4700,7 @@
get runtimeType => AnimatedInteger;
toString() => super.toString();
}
-patch class AnimatedLength {
+@patch class AnimatedLength {
static Type get instanceRuntimeType => AnimatedLengthImpl;
}
@@ -4709,7 +4709,7 @@
get runtimeType => AnimatedLength;
toString() => super.toString();
}
-patch class AnimatedLengthList {
+@patch class AnimatedLengthList {
static Type get instanceRuntimeType => AnimatedLengthListImpl;
}
@@ -4718,7 +4718,7 @@
get runtimeType => AnimatedLengthList;
toString() => super.toString();
}
-patch class AnimatedNumber {
+@patch class AnimatedNumber {
static Type get instanceRuntimeType => AnimatedNumberImpl;
}
@@ -4727,7 +4727,7 @@
get runtimeType => AnimatedNumber;
toString() => super.toString();
}
-patch class AnimatedNumberList {
+@patch class AnimatedNumberList {
static Type get instanceRuntimeType => AnimatedNumberListImpl;
}
@@ -4736,7 +4736,7 @@
get runtimeType => AnimatedNumberList;
toString() => super.toString();
}
-patch class AnimatedPreserveAspectRatio {
+@patch class AnimatedPreserveAspectRatio {
static Type get instanceRuntimeType => AnimatedPreserveAspectRatioImpl;
}
@@ -4745,7 +4745,7 @@
get runtimeType => AnimatedPreserveAspectRatio;
toString() => super.toString();
}
-patch class AnimatedRect {
+@patch class AnimatedRect {
static Type get instanceRuntimeType => AnimatedRectImpl;
}
@@ -4754,7 +4754,7 @@
get runtimeType => AnimatedRect;
toString() => super.toString();
}
-patch class AnimatedString {
+@patch class AnimatedString {
static Type get instanceRuntimeType => AnimatedStringImpl;
}
@@ -4763,7 +4763,7 @@
get runtimeType => AnimatedString;
toString() => super.toString();
}
-patch class AnimatedTransformList {
+@patch class AnimatedTransformList {
static Type get instanceRuntimeType => AnimatedTransformListImpl;
}
@@ -4772,7 +4772,7 @@
get runtimeType => AnimatedTransformList;
toString() => super.toString();
}
-patch class AnimationElement {
+@patch class AnimationElement {
static Type get instanceRuntimeType => AnimationElementImpl;
}
@@ -4781,7 +4781,7 @@
get runtimeType => AnimationElement;
toString() => super.toString();
}
-patch class CircleElement {
+@patch class CircleElement {
static Type get instanceRuntimeType => CircleElementImpl;
}
@@ -4790,7 +4790,7 @@
get runtimeType => CircleElement;
toString() => super.toString();
}
-patch class ClipPathElement {
+@patch class ClipPathElement {
static Type get instanceRuntimeType => ClipPathElementImpl;
}
@@ -4799,7 +4799,7 @@
get runtimeType => ClipPathElement;
toString() => super.toString();
}
-patch class DefsElement {
+@patch class DefsElement {
static Type get instanceRuntimeType => DefsElementImpl;
}
@@ -4808,7 +4808,7 @@
get runtimeType => DefsElement;
toString() => super.toString();
}
-patch class DescElement {
+@patch class DescElement {
static Type get instanceRuntimeType => DescElementImpl;
}
@@ -4817,7 +4817,7 @@
get runtimeType => DescElement;
toString() => super.toString();
}
-patch class DiscardElement {
+@patch class DiscardElement {
static Type get instanceRuntimeType => DiscardElementImpl;
}
@@ -4826,7 +4826,7 @@
get runtimeType => DiscardElement;
toString() => super.toString();
}
-patch class EllipseElement {
+@patch class EllipseElement {
static Type get instanceRuntimeType => EllipseElementImpl;
}
@@ -4835,7 +4835,7 @@
get runtimeType => EllipseElement;
toString() => super.toString();
}
-patch class FEBlendElement {
+@patch class FEBlendElement {
static Type get instanceRuntimeType => FEBlendElementImpl;
}
@@ -4844,7 +4844,7 @@
get runtimeType => FEBlendElement;
toString() => super.toString();
}
-patch class FEColorMatrixElement {
+@patch class FEColorMatrixElement {
static Type get instanceRuntimeType => FEColorMatrixElementImpl;
}
@@ -4853,7 +4853,7 @@
get runtimeType => FEColorMatrixElement;
toString() => super.toString();
}
-patch class FEComponentTransferElement {
+@patch class FEComponentTransferElement {
static Type get instanceRuntimeType => FEComponentTransferElementImpl;
}
@@ -4862,7 +4862,7 @@
get runtimeType => FEComponentTransferElement;
toString() => super.toString();
}
-patch class FECompositeElement {
+@patch class FECompositeElement {
static Type get instanceRuntimeType => FECompositeElementImpl;
}
@@ -4871,7 +4871,7 @@
get runtimeType => FECompositeElement;
toString() => super.toString();
}
-patch class FEConvolveMatrixElement {
+@patch class FEConvolveMatrixElement {
static Type get instanceRuntimeType => FEConvolveMatrixElementImpl;
}
@@ -4880,7 +4880,7 @@
get runtimeType => FEConvolveMatrixElement;
toString() => super.toString();
}
-patch class FEDiffuseLightingElement {
+@patch class FEDiffuseLightingElement {
static Type get instanceRuntimeType => FEDiffuseLightingElementImpl;
}
@@ -4889,7 +4889,7 @@
get runtimeType => FEDiffuseLightingElement;
toString() => super.toString();
}
-patch class FEDisplacementMapElement {
+@patch class FEDisplacementMapElement {
static Type get instanceRuntimeType => FEDisplacementMapElementImpl;
}
@@ -4898,7 +4898,7 @@
get runtimeType => FEDisplacementMapElement;
toString() => super.toString();
}
-patch class FEDistantLightElement {
+@patch class FEDistantLightElement {
static Type get instanceRuntimeType => FEDistantLightElementImpl;
}
@@ -4907,7 +4907,7 @@
get runtimeType => FEDistantLightElement;
toString() => super.toString();
}
-patch class FEFloodElement {
+@patch class FEFloodElement {
static Type get instanceRuntimeType => FEFloodElementImpl;
}
@@ -4916,7 +4916,7 @@
get runtimeType => FEFloodElement;
toString() => super.toString();
}
-patch class FEFuncAElement {
+@patch class FEFuncAElement {
static Type get instanceRuntimeType => FEFuncAElementImpl;
}
@@ -4925,7 +4925,7 @@
get runtimeType => FEFuncAElement;
toString() => super.toString();
}
-patch class FEFuncBElement {
+@patch class FEFuncBElement {
static Type get instanceRuntimeType => FEFuncBElementImpl;
}
@@ -4934,7 +4934,7 @@
get runtimeType => FEFuncBElement;
toString() => super.toString();
}
-patch class FEFuncGElement {
+@patch class FEFuncGElement {
static Type get instanceRuntimeType => FEFuncGElementImpl;
}
@@ -4943,7 +4943,7 @@
get runtimeType => FEFuncGElement;
toString() => super.toString();
}
-patch class FEFuncRElement {
+@patch class FEFuncRElement {
static Type get instanceRuntimeType => FEFuncRElementImpl;
}
@@ -4952,7 +4952,7 @@
get runtimeType => FEFuncRElement;
toString() => super.toString();
}
-patch class FEGaussianBlurElement {
+@patch class FEGaussianBlurElement {
static Type get instanceRuntimeType => FEGaussianBlurElementImpl;
}
@@ -4961,7 +4961,7 @@
get runtimeType => FEGaussianBlurElement;
toString() => super.toString();
}
-patch class FEImageElement {
+@patch class FEImageElement {
static Type get instanceRuntimeType => FEImageElementImpl;
}
@@ -4970,7 +4970,7 @@
get runtimeType => FEImageElement;
toString() => super.toString();
}
-patch class FEMergeElement {
+@patch class FEMergeElement {
static Type get instanceRuntimeType => FEMergeElementImpl;
}
@@ -4979,7 +4979,7 @@
get runtimeType => FEMergeElement;
toString() => super.toString();
}
-patch class FEMergeNodeElement {
+@patch class FEMergeNodeElement {
static Type get instanceRuntimeType => FEMergeNodeElementImpl;
}
@@ -4988,7 +4988,7 @@
get runtimeType => FEMergeNodeElement;
toString() => super.toString();
}
-patch class FEMorphologyElement {
+@patch class FEMorphologyElement {
static Type get instanceRuntimeType => FEMorphologyElementImpl;
}
@@ -4997,7 +4997,7 @@
get runtimeType => FEMorphologyElement;
toString() => super.toString();
}
-patch class FEOffsetElement {
+@patch class FEOffsetElement {
static Type get instanceRuntimeType => FEOffsetElementImpl;
}
@@ -5006,7 +5006,7 @@
get runtimeType => FEOffsetElement;
toString() => super.toString();
}
-patch class FEPointLightElement {
+@patch class FEPointLightElement {
static Type get instanceRuntimeType => FEPointLightElementImpl;
}
@@ -5015,7 +5015,7 @@
get runtimeType => FEPointLightElement;
toString() => super.toString();
}
-patch class FESpecularLightingElement {
+@patch class FESpecularLightingElement {
static Type get instanceRuntimeType => FESpecularLightingElementImpl;
}
@@ -5024,7 +5024,7 @@
get runtimeType => FESpecularLightingElement;
toString() => super.toString();
}
-patch class FESpotLightElement {
+@patch class FESpotLightElement {
static Type get instanceRuntimeType => FESpotLightElementImpl;
}
@@ -5033,7 +5033,7 @@
get runtimeType => FESpotLightElement;
toString() => super.toString();
}
-patch class FETileElement {
+@patch class FETileElement {
static Type get instanceRuntimeType => FETileElementImpl;
}
@@ -5042,7 +5042,7 @@
get runtimeType => FETileElement;
toString() => super.toString();
}
-patch class FETurbulenceElement {
+@patch class FETurbulenceElement {
static Type get instanceRuntimeType => FETurbulenceElementImpl;
}
@@ -5051,7 +5051,7 @@
get runtimeType => FETurbulenceElement;
toString() => super.toString();
}
-patch class FilterElement {
+@patch class FilterElement {
static Type get instanceRuntimeType => FilterElementImpl;
}
@@ -5060,7 +5060,7 @@
get runtimeType => FilterElement;
toString() => super.toString();
}
-patch class FilterPrimitiveStandardAttributes {
+@patch class FilterPrimitiveStandardAttributes {
static Type get instanceRuntimeType => FilterPrimitiveStandardAttributesImpl;
}
@@ -5069,7 +5069,7 @@
get runtimeType => FilterPrimitiveStandardAttributes;
toString() => super.toString();
}
-patch class FitToViewBox {
+@patch class FitToViewBox {
static Type get instanceRuntimeType => FitToViewBoxImpl;
}
@@ -5078,7 +5078,7 @@
get runtimeType => FitToViewBox;
toString() => super.toString();
}
-patch class ForeignObjectElement {
+@patch class ForeignObjectElement {
static Type get instanceRuntimeType => ForeignObjectElementImpl;
}
@@ -5087,7 +5087,7 @@
get runtimeType => ForeignObjectElement;
toString() => super.toString();
}
-patch class GElement {
+@patch class GElement {
static Type get instanceRuntimeType => GElementImpl;
}
@@ -5096,7 +5096,7 @@
get runtimeType => GElement;
toString() => super.toString();
}
-patch class GeometryElement {
+@patch class GeometryElement {
static Type get instanceRuntimeType => GeometryElementImpl;
}
@@ -5105,7 +5105,7 @@
get runtimeType => GeometryElement;
toString() => super.toString();
}
-patch class GraphicsElement {
+@patch class GraphicsElement {
static Type get instanceRuntimeType => GraphicsElementImpl;
}
@@ -5114,7 +5114,7 @@
get runtimeType => GraphicsElement;
toString() => super.toString();
}
-patch class ImageElement {
+@patch class ImageElement {
static Type get instanceRuntimeType => ImageElementImpl;
}
@@ -5123,7 +5123,7 @@
get runtimeType => ImageElement;
toString() => super.toString();
}
-patch class Length {
+@patch class Length {
static Type get instanceRuntimeType => LengthImpl;
}
@@ -5132,7 +5132,7 @@
get runtimeType => Length;
toString() => super.toString();
}
-patch class LengthList {
+@patch class LengthList {
static Type get instanceRuntimeType => LengthListImpl;
}
@@ -5141,7 +5141,7 @@
get runtimeType => LengthList;
toString() => super.toString();
}
-patch class LineElement {
+@patch class LineElement {
static Type get instanceRuntimeType => LineElementImpl;
}
@@ -5150,7 +5150,7 @@
get runtimeType => LineElement;
toString() => super.toString();
}
-patch class LinearGradientElement {
+@patch class LinearGradientElement {
static Type get instanceRuntimeType => LinearGradientElementImpl;
}
@@ -5159,7 +5159,7 @@
get runtimeType => LinearGradientElement;
toString() => super.toString();
}
-patch class MarkerElement {
+@patch class MarkerElement {
static Type get instanceRuntimeType => MarkerElementImpl;
}
@@ -5168,7 +5168,7 @@
get runtimeType => MarkerElement;
toString() => super.toString();
}
-patch class MaskElement {
+@patch class MaskElement {
static Type get instanceRuntimeType => MaskElementImpl;
}
@@ -5177,7 +5177,7 @@
get runtimeType => MaskElement;
toString() => super.toString();
}
-patch class Matrix {
+@patch class Matrix {
static Type get instanceRuntimeType => MatrixImpl;
}
@@ -5186,7 +5186,7 @@
get runtimeType => Matrix;
toString() => super.toString();
}
-patch class MetadataElement {
+@patch class MetadataElement {
static Type get instanceRuntimeType => MetadataElementImpl;
}
@@ -5195,7 +5195,7 @@
get runtimeType => MetadataElement;
toString() => super.toString();
}
-patch class Number {
+@patch class Number {
static Type get instanceRuntimeType => NumberImpl;
}
@@ -5204,7 +5204,7 @@
get runtimeType => Number;
toString() => super.toString();
}
-patch class NumberList {
+@patch class NumberList {
static Type get instanceRuntimeType => NumberListImpl;
}
@@ -5213,7 +5213,7 @@
get runtimeType => NumberList;
toString() => super.toString();
}
-patch class PathElement {
+@patch class PathElement {
static Type get instanceRuntimeType => PathElementImpl;
}
@@ -5222,7 +5222,7 @@
get runtimeType => PathElement;
toString() => super.toString();
}
-patch class PathSeg {
+@patch class PathSeg {
static Type get instanceRuntimeType => PathSegImpl;
}
@@ -5231,7 +5231,7 @@
get runtimeType => PathSeg;
toString() => super.toString();
}
-patch class PathSegArcAbs {
+@patch class PathSegArcAbs {
static Type get instanceRuntimeType => PathSegArcAbsImpl;
}
@@ -5240,7 +5240,7 @@
get runtimeType => PathSegArcAbs;
toString() => super.toString();
}
-patch class PathSegArcRel {
+@patch class PathSegArcRel {
static Type get instanceRuntimeType => PathSegArcRelImpl;
}
@@ -5249,7 +5249,7 @@
get runtimeType => PathSegArcRel;
toString() => super.toString();
}
-patch class PathSegClosePath {
+@patch class PathSegClosePath {
static Type get instanceRuntimeType => PathSegClosePathImpl;
}
@@ -5258,7 +5258,7 @@
get runtimeType => PathSegClosePath;
toString() => super.toString();
}
-patch class PathSegCurvetoCubicAbs {
+@patch class PathSegCurvetoCubicAbs {
static Type get instanceRuntimeType => PathSegCurvetoCubicAbsImpl;
}
@@ -5267,7 +5267,7 @@
get runtimeType => PathSegCurvetoCubicAbs;
toString() => super.toString();
}
-patch class PathSegCurvetoCubicRel {
+@patch class PathSegCurvetoCubicRel {
static Type get instanceRuntimeType => PathSegCurvetoCubicRelImpl;
}
@@ -5276,7 +5276,7 @@
get runtimeType => PathSegCurvetoCubicRel;
toString() => super.toString();
}
-patch class PathSegCurvetoCubicSmoothAbs {
+@patch class PathSegCurvetoCubicSmoothAbs {
static Type get instanceRuntimeType => PathSegCurvetoCubicSmoothAbsImpl;
}
@@ -5285,7 +5285,7 @@
get runtimeType => PathSegCurvetoCubicSmoothAbs;
toString() => super.toString();
}
-patch class PathSegCurvetoCubicSmoothRel {
+@patch class PathSegCurvetoCubicSmoothRel {
static Type get instanceRuntimeType => PathSegCurvetoCubicSmoothRelImpl;
}
@@ -5294,7 +5294,7 @@
get runtimeType => PathSegCurvetoCubicSmoothRel;
toString() => super.toString();
}
-patch class PathSegCurvetoQuadraticAbs {
+@patch class PathSegCurvetoQuadraticAbs {
static Type get instanceRuntimeType => PathSegCurvetoQuadraticAbsImpl;
}
@@ -5303,7 +5303,7 @@
get runtimeType => PathSegCurvetoQuadraticAbs;
toString() => super.toString();
}
-patch class PathSegCurvetoQuadraticRel {
+@patch class PathSegCurvetoQuadraticRel {
static Type get instanceRuntimeType => PathSegCurvetoQuadraticRelImpl;
}
@@ -5312,7 +5312,7 @@
get runtimeType => PathSegCurvetoQuadraticRel;
toString() => super.toString();
}
-patch class PathSegCurvetoQuadraticSmoothAbs {
+@patch class PathSegCurvetoQuadraticSmoothAbs {
static Type get instanceRuntimeType => PathSegCurvetoQuadraticSmoothAbsImpl;
}
@@ -5321,7 +5321,7 @@
get runtimeType => PathSegCurvetoQuadraticSmoothAbs;
toString() => super.toString();
}
-patch class PathSegCurvetoQuadraticSmoothRel {
+@patch class PathSegCurvetoQuadraticSmoothRel {
static Type get instanceRuntimeType => PathSegCurvetoQuadraticSmoothRelImpl;
}
@@ -5330,7 +5330,7 @@
get runtimeType => PathSegCurvetoQuadraticSmoothRel;
toString() => super.toString();
}
-patch class PathSegLinetoAbs {
+@patch class PathSegLinetoAbs {
static Type get instanceRuntimeType => PathSegLinetoAbsImpl;
}
@@ -5339,7 +5339,7 @@
get runtimeType => PathSegLinetoAbs;
toString() => super.toString();
}
-patch class PathSegLinetoHorizontalAbs {
+@patch class PathSegLinetoHorizontalAbs {
static Type get instanceRuntimeType => PathSegLinetoHorizontalAbsImpl;
}
@@ -5348,7 +5348,7 @@
get runtimeType => PathSegLinetoHorizontalAbs;
toString() => super.toString();
}
-patch class PathSegLinetoHorizontalRel {
+@patch class PathSegLinetoHorizontalRel {
static Type get instanceRuntimeType => PathSegLinetoHorizontalRelImpl;
}
@@ -5357,7 +5357,7 @@
get runtimeType => PathSegLinetoHorizontalRel;
toString() => super.toString();
}
-patch class PathSegLinetoRel {
+@patch class PathSegLinetoRel {
static Type get instanceRuntimeType => PathSegLinetoRelImpl;
}
@@ -5366,7 +5366,7 @@
get runtimeType => PathSegLinetoRel;
toString() => super.toString();
}
-patch class PathSegLinetoVerticalAbs {
+@patch class PathSegLinetoVerticalAbs {
static Type get instanceRuntimeType => PathSegLinetoVerticalAbsImpl;
}
@@ -5375,7 +5375,7 @@
get runtimeType => PathSegLinetoVerticalAbs;
toString() => super.toString();
}
-patch class PathSegLinetoVerticalRel {
+@patch class PathSegLinetoVerticalRel {
static Type get instanceRuntimeType => PathSegLinetoVerticalRelImpl;
}
@@ -5384,7 +5384,7 @@
get runtimeType => PathSegLinetoVerticalRel;
toString() => super.toString();
}
-patch class PathSegList {
+@patch class PathSegList {
static Type get instanceRuntimeType => PathSegListImpl;
}
@@ -5393,7 +5393,7 @@
get runtimeType => PathSegList;
toString() => super.toString();
}
-patch class PathSegMovetoAbs {
+@patch class PathSegMovetoAbs {
static Type get instanceRuntimeType => PathSegMovetoAbsImpl;
}
@@ -5402,7 +5402,7 @@
get runtimeType => PathSegMovetoAbs;
toString() => super.toString();
}
-patch class PathSegMovetoRel {
+@patch class PathSegMovetoRel {
static Type get instanceRuntimeType => PathSegMovetoRelImpl;
}
@@ -5411,7 +5411,7 @@
get runtimeType => PathSegMovetoRel;
toString() => super.toString();
}
-patch class PatternElement {
+@patch class PatternElement {
static Type get instanceRuntimeType => PatternElementImpl;
}
@@ -5420,7 +5420,7 @@
get runtimeType => PatternElement;
toString() => super.toString();
}
-patch class Point {
+@patch class Point {
static Type get instanceRuntimeType => PointImpl;
}
@@ -5429,7 +5429,7 @@
get runtimeType => Point;
toString() => super.toString();
}
-patch class PointList {
+@patch class PointList {
static Type get instanceRuntimeType => PointListImpl;
}
@@ -5438,7 +5438,7 @@
get runtimeType => PointList;
toString() => super.toString();
}
-patch class PolygonElement {
+@patch class PolygonElement {
static Type get instanceRuntimeType => PolygonElementImpl;
}
@@ -5447,7 +5447,7 @@
get runtimeType => PolygonElement;
toString() => super.toString();
}
-patch class PolylineElement {
+@patch class PolylineElement {
static Type get instanceRuntimeType => PolylineElementImpl;
}
@@ -5456,7 +5456,7 @@
get runtimeType => PolylineElement;
toString() => super.toString();
}
-patch class PreserveAspectRatio {
+@patch class PreserveAspectRatio {
static Type get instanceRuntimeType => PreserveAspectRatioImpl;
}
@@ -5465,7 +5465,7 @@
get runtimeType => PreserveAspectRatio;
toString() => super.toString();
}
-patch class RadialGradientElement {
+@patch class RadialGradientElement {
static Type get instanceRuntimeType => RadialGradientElementImpl;
}
@@ -5474,7 +5474,7 @@
get runtimeType => RadialGradientElement;
toString() => super.toString();
}
-patch class Rect {
+@patch class Rect {
static Type get instanceRuntimeType => RectImpl;
}
@@ -5483,7 +5483,7 @@
get runtimeType => Rect;
toString() => super.toString();
}
-patch class RectElement {
+@patch class RectElement {
static Type get instanceRuntimeType => RectElementImpl;
}
@@ -5492,7 +5492,7 @@
get runtimeType => RectElement;
toString() => super.toString();
}
-patch class ScriptElement {
+@patch class ScriptElement {
static Type get instanceRuntimeType => ScriptElementImpl;
}
@@ -5501,7 +5501,7 @@
get runtimeType => ScriptElement;
toString() => super.toString();
}
-patch class SetElement {
+@patch class SetElement {
static Type get instanceRuntimeType => SetElementImpl;
}
@@ -5510,7 +5510,7 @@
get runtimeType => SetElement;
toString() => super.toString();
}
-patch class StopElement {
+@patch class StopElement {
static Type get instanceRuntimeType => StopElementImpl;
}
@@ -5519,7 +5519,7 @@
get runtimeType => StopElement;
toString() => super.toString();
}
-patch class StringList {
+@patch class StringList {
static Type get instanceRuntimeType => StringListImpl;
}
@@ -5528,7 +5528,7 @@
get runtimeType => StringList;
toString() => super.toString();
}
-patch class StyleElement {
+@patch class StyleElement {
static Type get instanceRuntimeType => StyleElementImpl;
}
@@ -5537,7 +5537,7 @@
get runtimeType => StyleElement;
toString() => super.toString();
}
-patch class SvgElement {
+@patch class SvgElement {
static Type get instanceRuntimeType => SvgElementImpl;
}
@@ -5546,7 +5546,7 @@
get runtimeType => SvgElement;
toString() => super.toString();
}
-patch class SvgSvgElement {
+@patch class SvgSvgElement {
static Type get instanceRuntimeType => SvgSvgElementImpl;
}
@@ -5555,7 +5555,7 @@
get runtimeType => SvgSvgElement;
toString() => super.toString();
}
-patch class SwitchElement {
+@patch class SwitchElement {
static Type get instanceRuntimeType => SwitchElementImpl;
}
@@ -5564,7 +5564,7 @@
get runtimeType => SwitchElement;
toString() => super.toString();
}
-patch class SymbolElement {
+@patch class SymbolElement {
static Type get instanceRuntimeType => SymbolElementImpl;
}
@@ -5573,7 +5573,7 @@
get runtimeType => SymbolElement;
toString() => super.toString();
}
-patch class TSpanElement {
+@patch class TSpanElement {
static Type get instanceRuntimeType => TSpanElementImpl;
}
@@ -5582,7 +5582,7 @@
get runtimeType => TSpanElement;
toString() => super.toString();
}
-patch class Tests {
+@patch class Tests {
static Type get instanceRuntimeType => TestsImpl;
}
@@ -5591,7 +5591,7 @@
get runtimeType => Tests;
toString() => super.toString();
}
-patch class TextContentElement {
+@patch class TextContentElement {
static Type get instanceRuntimeType => TextContentElementImpl;
}
@@ -5600,7 +5600,7 @@
get runtimeType => TextContentElement;
toString() => super.toString();
}
-patch class TextElement {
+@patch class TextElement {
static Type get instanceRuntimeType => TextElementImpl;
}
@@ -5609,7 +5609,7 @@
get runtimeType => TextElement;
toString() => super.toString();
}
-patch class TextPathElement {
+@patch class TextPathElement {
static Type get instanceRuntimeType => TextPathElementImpl;
}
@@ -5618,7 +5618,7 @@
get runtimeType => TextPathElement;
toString() => super.toString();
}
-patch class TextPositioningElement {
+@patch class TextPositioningElement {
static Type get instanceRuntimeType => TextPositioningElementImpl;
}
@@ -5627,7 +5627,7 @@
get runtimeType => TextPositioningElement;
toString() => super.toString();
}
-patch class TitleElement {
+@patch class TitleElement {
static Type get instanceRuntimeType => TitleElementImpl;
}
@@ -5636,7 +5636,7 @@
get runtimeType => TitleElement;
toString() => super.toString();
}
-patch class Transform {
+@patch class Transform {
static Type get instanceRuntimeType => TransformImpl;
}
@@ -5645,7 +5645,7 @@
get runtimeType => Transform;
toString() => super.toString();
}
-patch class TransformList {
+@patch class TransformList {
static Type get instanceRuntimeType => TransformListImpl;
}
@@ -5654,7 +5654,7 @@
get runtimeType => TransformList;
toString() => super.toString();
}
-patch class UnitTypes {
+@patch class UnitTypes {
static Type get instanceRuntimeType => UnitTypesImpl;
}
@@ -5663,7 +5663,7 @@
get runtimeType => UnitTypes;
toString() => super.toString();
}
-patch class UriReference {
+@patch class UriReference {
static Type get instanceRuntimeType => UriReferenceImpl;
}
@@ -5672,7 +5672,7 @@
get runtimeType => UriReference;
toString() => super.toString();
}
-patch class UseElement {
+@patch class UseElement {
static Type get instanceRuntimeType => UseElementImpl;
}
@@ -5681,7 +5681,7 @@
get runtimeType => UseElement;
toString() => super.toString();
}
-patch class ViewElement {
+@patch class ViewElement {
static Type get instanceRuntimeType => ViewElementImpl;
}
@@ -5690,7 +5690,7 @@
get runtimeType => ViewElement;
toString() => super.toString();
}
-patch class ViewSpec {
+@patch class ViewSpec {
static Type get instanceRuntimeType => ViewSpecImpl;
}
@@ -5699,7 +5699,7 @@
get runtimeType => ViewSpec;
toString() => super.toString();
}
-patch class ZoomAndPan {
+@patch class ZoomAndPan {
static Type get instanceRuntimeType => ZoomAndPanImpl;
}
@@ -5708,7 +5708,7 @@
get runtimeType => ZoomAndPan;
toString() => super.toString();
}
-patch class ZoomEvent {
+@patch class ZoomEvent {
static Type get instanceRuntimeType => ZoomEventImpl;
}
@@ -5717,7 +5717,7 @@
get runtimeType => ZoomEvent;
toString() => super.toString();
}
-patch class _GradientElement {
+@patch class _GradientElement {
static Type get instanceRuntimeType => _GradientElementImpl;
}
@@ -5726,7 +5726,7 @@
get runtimeType => _GradientElement;
toString() => super.toString();
}
-patch class _SVGComponentTransferFunctionElement {
+@patch class _SVGComponentTransferFunctionElement {
static Type get instanceRuntimeType => _SVGComponentTransferFunctionElementImpl;
}
@@ -5735,7 +5735,7 @@
get runtimeType => _SVGComponentTransferFunctionElement;
toString() => super.toString();
}
-patch class _SVGCursorElement {
+@patch class _SVGCursorElement {
static Type get instanceRuntimeType => _SVGCursorElementImpl;
}
@@ -5744,7 +5744,7 @@
get runtimeType => _SVGCursorElement;
toString() => super.toString();
}
-patch class _SVGFEDropShadowElement {
+@patch class _SVGFEDropShadowElement {
static Type get instanceRuntimeType => _SVGFEDropShadowElementImpl;
}
@@ -5753,7 +5753,7 @@
get runtimeType => _SVGFEDropShadowElement;
toString() => super.toString();
}
-patch class _SVGMPathElement {
+@patch class _SVGMPathElement {
static Type get instanceRuntimeType => _SVGMPathElementImpl;
}
@@ -5772,7 +5772,7 @@
*/
const _UNDEFINED_JS_CONST = const Object();
-patch class AnalyserNode {
+@patch class AnalyserNode {
static Type get instanceRuntimeType => AnalyserNodeImpl;
}
@@ -5781,7 +5781,7 @@
get runtimeType => AnalyserNode;
toString() => super.toString();
}
-patch class AudioBuffer {
+@patch class AudioBuffer {
static Type get instanceRuntimeType => AudioBufferImpl;
}
@@ -5790,7 +5790,7 @@
get runtimeType => AudioBuffer;
toString() => super.toString();
}
-patch class AudioBufferSourceNode {
+@patch class AudioBufferSourceNode {
static Type get instanceRuntimeType => AudioBufferSourceNodeImpl;
}
@@ -5799,7 +5799,7 @@
get runtimeType => AudioBufferSourceNode;
toString() => super.toString();
}
-patch class AudioContext {
+@patch class AudioContext {
static Type get instanceRuntimeType => AudioContextImpl;
}
@@ -5808,7 +5808,7 @@
get runtimeType => AudioContext;
toString() => super.toString();
}
-patch class AudioDestinationNode {
+@patch class AudioDestinationNode {
static Type get instanceRuntimeType => AudioDestinationNodeImpl;
}
@@ -5817,7 +5817,7 @@
get runtimeType => AudioDestinationNode;
toString() => super.toString();
}
-patch class AudioListener {
+@patch class AudioListener {
static Type get instanceRuntimeType => AudioListenerImpl;
}
@@ -5826,7 +5826,7 @@
get runtimeType => AudioListener;
toString() => super.toString();
}
-patch class AudioNode {
+@patch class AudioNode {
static Type get instanceRuntimeType => AudioNodeImpl;
}
@@ -5835,7 +5835,7 @@
get runtimeType => AudioNode;
toString() => super.toString();
}
-patch class AudioParam {
+@patch class AudioParam {
static Type get instanceRuntimeType => AudioParamImpl;
}
@@ -5844,7 +5844,7 @@
get runtimeType => AudioParam;
toString() => super.toString();
}
-patch class AudioProcessingEvent {
+@patch class AudioProcessingEvent {
static Type get instanceRuntimeType => AudioProcessingEventImpl;
}
@@ -5853,7 +5853,7 @@
get runtimeType => AudioProcessingEvent;
toString() => super.toString();
}
-patch class AudioSourceNode {
+@patch class AudioSourceNode {
static Type get instanceRuntimeType => AudioSourceNodeImpl;
}
@@ -5862,7 +5862,7 @@
get runtimeType => AudioSourceNode;
toString() => super.toString();
}
-patch class BiquadFilterNode {
+@patch class BiquadFilterNode {
static Type get instanceRuntimeType => BiquadFilterNodeImpl;
}
@@ -5871,7 +5871,7 @@
get runtimeType => BiquadFilterNode;
toString() => super.toString();
}
-patch class ChannelMergerNode {
+@patch class ChannelMergerNode {
static Type get instanceRuntimeType => ChannelMergerNodeImpl;
}
@@ -5880,7 +5880,7 @@
get runtimeType => ChannelMergerNode;
toString() => super.toString();
}
-patch class ChannelSplitterNode {
+@patch class ChannelSplitterNode {
static Type get instanceRuntimeType => ChannelSplitterNodeImpl;
}
@@ -5889,7 +5889,7 @@
get runtimeType => ChannelSplitterNode;
toString() => super.toString();
}
-patch class ConvolverNode {
+@patch class ConvolverNode {
static Type get instanceRuntimeType => ConvolverNodeImpl;
}
@@ -5898,7 +5898,7 @@
get runtimeType => ConvolverNode;
toString() => super.toString();
}
-patch class DelayNode {
+@patch class DelayNode {
static Type get instanceRuntimeType => DelayNodeImpl;
}
@@ -5907,7 +5907,7 @@
get runtimeType => DelayNode;
toString() => super.toString();
}
-patch class DynamicsCompressorNode {
+@patch class DynamicsCompressorNode {
static Type get instanceRuntimeType => DynamicsCompressorNodeImpl;
}
@@ -5916,7 +5916,7 @@
get runtimeType => DynamicsCompressorNode;
toString() => super.toString();
}
-patch class GainNode {
+@patch class GainNode {
static Type get instanceRuntimeType => GainNodeImpl;
}
@@ -5925,7 +5925,7 @@
get runtimeType => GainNode;
toString() => super.toString();
}
-patch class MediaElementAudioSourceNode {
+@patch class MediaElementAudioSourceNode {
static Type get instanceRuntimeType => MediaElementAudioSourceNodeImpl;
}
@@ -5934,7 +5934,7 @@
get runtimeType => MediaElementAudioSourceNode;
toString() => super.toString();
}
-patch class MediaStreamAudioDestinationNode {
+@patch class MediaStreamAudioDestinationNode {
static Type get instanceRuntimeType => MediaStreamAudioDestinationNodeImpl;
}
@@ -5943,7 +5943,7 @@
get runtimeType => MediaStreamAudioDestinationNode;
toString() => super.toString();
}
-patch class MediaStreamAudioSourceNode {
+@patch class MediaStreamAudioSourceNode {
static Type get instanceRuntimeType => MediaStreamAudioSourceNodeImpl;
}
@@ -5952,7 +5952,7 @@
get runtimeType => MediaStreamAudioSourceNode;
toString() => super.toString();
}
-patch class OfflineAudioCompletionEvent {
+@patch class OfflineAudioCompletionEvent {
static Type get instanceRuntimeType => OfflineAudioCompletionEventImpl;
}
@@ -5961,7 +5961,7 @@
get runtimeType => OfflineAudioCompletionEvent;
toString() => super.toString();
}
-patch class OfflineAudioContext {
+@patch class OfflineAudioContext {
static Type get instanceRuntimeType => OfflineAudioContextImpl;
}
@@ -5970,7 +5970,7 @@
get runtimeType => OfflineAudioContext;
toString() => super.toString();
}
-patch class OscillatorNode {
+@patch class OscillatorNode {
static Type get instanceRuntimeType => OscillatorNodeImpl;
}
@@ -5979,7 +5979,7 @@
get runtimeType => OscillatorNode;
toString() => super.toString();
}
-patch class PannerNode {
+@patch class PannerNode {
static Type get instanceRuntimeType => PannerNodeImpl;
}
@@ -5988,7 +5988,7 @@
get runtimeType => PannerNode;
toString() => super.toString();
}
-patch class PeriodicWave {
+@patch class PeriodicWave {
static Type get instanceRuntimeType => PeriodicWaveImpl;
}
@@ -5997,7 +5997,7 @@
get runtimeType => PeriodicWave;
toString() => super.toString();
}
-patch class ScriptProcessorNode {
+@patch class ScriptProcessorNode {
static Type get instanceRuntimeType => ScriptProcessorNodeImpl;
}
@@ -6006,7 +6006,7 @@
get runtimeType => ScriptProcessorNode;
toString() => super.toString();
}
-patch class StereoPannerNode {
+@patch class StereoPannerNode {
static Type get instanceRuntimeType => StereoPannerNodeImpl;
}
@@ -6015,7 +6015,7 @@
get runtimeType => StereoPannerNode;
toString() => super.toString();
}
-patch class WaveShaperNode {
+@patch class WaveShaperNode {
static Type get instanceRuntimeType => WaveShaperNodeImpl;
}
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
index a8f0661..fbda496 100644
--- a/sdk/lib/js/dartium/js_dartium.dart
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -514,7 +514,7 @@
} else if (isStatic) {
sb.write("static");
} else {
- sb.write("patch");
+ sb.write("@patch");
}
sb.write(" ");
if (declaration.isGetter) {
@@ -729,7 +729,7 @@
'<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>';
}
sb.write("""
-patch class $className$typeVariablesClause {
+@patch class $className$typeVariablesClause {
$sbPatch
}
""");
@@ -884,15 +884,15 @@
abstract class JSObjectInterfacesDom $implementsClauseDom {
}
-patch class JSObject {
+@patch class JSObject {
static Type get instanceRuntimeType => JSObjectImpl;
}
-patch class JSFunction {
+@patch class JSFunction {
static Type get instanceRuntimeType => JSFunctionImpl;
}
-patch class JSArray {
+@patch class JSArray {
static Type get instanceRuntimeType => JSArrayImpl;
}
diff --git a/tests/compiler/dart2js/analyze_test_test.dart b/tests/compiler/dart2js/analyze_test_test.dart
index ea2524d..43d490d 100644
--- a/tests/compiler/dart2js/analyze_test_test.dart
+++ b/tests/compiler/dart2js/analyze_test_test.dart
@@ -35,12 +35,9 @@
const List<String> SKIP_LIST = const <String>[
// Helper files:
"/data/",
- "http_launch_data/",
+ "quarantined/http_launch_data/",
"mirrors_helper.dart",
"path%20with%20spaces/",
- "cps_ir/input/",
- // No longer maintained:
- "backend_dart/",
// Broken tests:
"quarantined/http_test.dart",
// Package directory
diff --git a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
index a17914e..292c2c9 100644
--- a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
+++ b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
@@ -40,25 +40,9 @@
"lib/src/serialization/": const [
"is never"],
- // Nested functions are currently kept alive in the IR.
- "lib/src/tree_ir/": const [
- "accept", "FunctionExpression", "CreateFunction"
- ],
-
"lib/src/universe/universe.dart": const [
"The method 'getterInvocationsByName' is never called.",
"The method 'setterInvocationsByName' is never called."],
-
- "lib/src/cps_ir/": const [
- "accept", "CreateFunction",
- ],
-
- // Useful utility functions that are not currently used.
- "lib/src/cps_ir/cps_fragment.dart": const [
- "The method 'beginLoop' is never called.",
- "The method 'continueLoop' is never called.",
- "The method 'invokeMethod' is never called.",
- ],
};
void main() {
diff --git a/tests/compiler/dart2js/cps_ir/README.md b/tests/compiler/dart2js/cps_ir/README.md
deleted file mode 100644
index 1106a72..0000000
--- a/tests/compiler/dart2js/cps_ir/README.md
+++ /dev/null
@@ -1,78 +0,0 @@
-# CPS IR unit tests
-
-This folder contains unit tests of the CPS IR. These tests run the compiler with
-the cps IR and check for the output of a specific function (typically main).
-
-To make our lives easier, most files here are autogenerated. You should never
-have to edit a file under `expected/` or any file with an `AUTOGENERATED` header
-(including the `_test.dart` files).
-
-See instructions below to add or update tests.
-
-### Adding a new test
-
-Every test has 3 files: an input file, a test runner file, and an expectation
-file. The last two are auto-generated. Here is how:
-
-* add a file under `input/` with a unique name, such as `foo_bar.dart`. Do not
- include `_test` in the name of this file, otherwise the test framework will
- think this test needs to be run directly in the vm and in a browser, that's
- not our goal.
-
-* generate the corresponding test file, by running the `up_to_date_test.dart`
- passing `update` as an argument:
-
-```bash
-dart tests/compiler/dart2js/cps_ir/up_to_date_test.dart update
-```
-
- This will generate a file `foo_bar_test.dart` on this folder.
-
-* generate the expectations of the test file by running the generated test file
- with `update` as an argument:
-
-```bash
-dart --package-root=out/ReleaseX64/packages tests/compiler/dart2js/cps_ir/foo_bar_test.dart update
-```
-
- This will generate a file `expected/foo_bar.js` with the expected output.
-
-### Checking a method other than main
-
-By default, the test expectations will be generated to contain just the body of
-the main function. If you wish to check for a different element, include a
-comment at the top of the input test like this:
-```dart
-// Method to test: function(foo)
-```
-The trailing text should match the string representation of a compiler element.
-
-**Note**: this format will likely change in the future. We would like to have a
-canonical way to refer to elements that is independent of the internal compiler
-implementation, we also want a way to specify more than just one element, and a
-way to specify that an element has been tree-shaken.
-
-### Updating a single test expectation
-
-To update the expectations of a test, simply regenerate it by running the test
-file with `update` as an argument:
-
-```bash
-dart --package-root=out/ReleaseX64/packages tests/compiler/dart2js/cps_ir/foo_bar_test.dart update
-```
-
-This will override the file `expected/foo_bar.js` file with the new output.
-
-If a test fails because the expectations are out of date, you'll see this
-suggestion in the failure message too.
-
-### Updating all test expectations
-
-For convenience, we also provide a script to update all expectations at once.
-
-```bash
-dart --package-root=out/ReleaseX64/packages tests/compiler/dart2js/cps_ir/update_all.dart
-```
-
-It is equivalent to update each test individually. This script can be handy when
-making cross-cutting changes that affect the output of most tests.
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_10_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_10_test.dart
deleted file mode 100644
index 7e6129f..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_10_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_10.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_10.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_11_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_11_test.dart
deleted file mode 100644
index 90e4293..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_11_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_11.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_11.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_12_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_12_test.dart
deleted file mode 100644
index a170a0a..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_12_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_12.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_12.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_13_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_13_test.dart
deleted file mode 100644
index 262f833..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_13_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_13.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_13.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_14_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_14_test.dart
deleted file mode 100644
index 5e081e0..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_14_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_14.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_14.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_15_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_15_test.dart
deleted file mode 100644
index 32a89c7..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_15_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_15.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_15.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_16_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_16_test.dart
deleted file mode 100644
index 7ec112f..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_16_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_16.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_16.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_17_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_17_test.dart
deleted file mode 100644
index 41533c9..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_17_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_17.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_17.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_18_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_18_test.dart
deleted file mode 100644
index abda443..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_18_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_18.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_18.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_19_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_19_test.dart
deleted file mode 100644
index 03d2e0d..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_19_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_19.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_19.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_1_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_1_test.dart
deleted file mode 100644
index cbd95ce..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_20_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_20_test.dart
deleted file mode 100644
index 8421f29..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_20_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_20.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_20.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_21_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_21_test.dart
deleted file mode 100644
index d65f1d2..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_21_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_21.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_21.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_22_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_22_test.dart
deleted file mode 100644
index b6fff18..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_22_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_22.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_22.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_23_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_23_test.dart
deleted file mode 100644
index 71083d4..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_23_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_23.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_23.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_24_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_24_test.dart
deleted file mode 100644
index ed56ade..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_24_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_24.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_24.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_25_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_25_test.dart
deleted file mode 100644
index d3aa3a8..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_25_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_25.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_25.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_26_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_26_test.dart
deleted file mode 100644
index 348162f..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_26_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_26.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_26.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_27_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_27_test.dart
deleted file mode 100644
index 545ed60..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_27_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_27.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_27.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_28_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_28_test.dart
deleted file mode 100644
index 4777d3d..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_28_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_28.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_28.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_2_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_2_test.dart
deleted file mode 100644
index 82dfbed..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_3_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_3_test.dart
deleted file mode 100644
index 3fa5714..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_3_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_3.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_3.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_4_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_4_test.dart
deleted file mode 100644
index f254f71..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_4_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_4.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_4.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_5_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_5_test.dart
deleted file mode 100644
index d90713c..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_5_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_5.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_5.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_6_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_6_test.dart
deleted file mode 100644
index 1a35cbe..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_6_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_6.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_6.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_7_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_7_test.dart
deleted file mode 100644
index 6069711..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_7_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_7.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_7.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_8_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_8_test.dart
deleted file mode 100644
index 082bb9b..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_8_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_8.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_8.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_9_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_9_test.dart
deleted file mode 100644
index 49c5202..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_9_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_9.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_9.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_10_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_10_test.dart
deleted file mode 100644
index 4b2600c..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_10_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_10.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_10.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_11_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_11_test.dart
deleted file mode 100644
index e8f6b2c..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_11_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_11.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_11.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_12_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_12_test.dart
deleted file mode 100644
index 5a5810c..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_12_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_12.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_12.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_13_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_13_test.dart
deleted file mode 100644
index a72d96b..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_13_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_13.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_13.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_14_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_14_test.dart
deleted file mode 100644
index 9453955..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_14_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_14.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_14.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_15_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_15_test.dart
deleted file mode 100644
index 3fcdc5d..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_15_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_15.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_15.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_16_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_16_test.dart
deleted file mode 100644
index 6c55492..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_16_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_16.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_16.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_17_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_17_test.dart
deleted file mode 100644
index 59f9881..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_17_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_17.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_17.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_1_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_1_test.dart
deleted file mode 100644
index 89d6903..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_2_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_2_test.dart
deleted file mode 100644
index 9aaee58..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_3_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_3_test.dart
deleted file mode 100644
index 1f2613c..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_3_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_3.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_3.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_4_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_4_test.dart
deleted file mode 100644
index 5248eae..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_4_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_4.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_4.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_5_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_5_test.dart
deleted file mode 100644
index ae259b3..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_5_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_5.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_5.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_6_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_6_test.dart
deleted file mode 100644
index 315b8ba..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_6_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_6.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_6.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_7_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_7_test.dart
deleted file mode 100644
index b3b060d..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_7_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_7.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_7.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_8_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_8_test.dart
deleted file mode 100644
index 803d019..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_8_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_8.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_8.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_9 b/tests/compiler/dart2js/cps_ir/argument_refinement_num_9
deleted file mode 100644
index 86963e3..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_9
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.cps_ir_test;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_9", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/argument_refinement_num_9_test.dart b/tests/compiler/dart2js/cps_ir/argument_refinement_num_9_test.dart
deleted file mode 100644
index f6cbe34..0000000
--- a/tests/compiler/dart2js/cps_ir/argument_refinement_num_9_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.argument_refinement_num_9.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("argument_refinement_num_9.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_10_test.dart b/tests/compiler/dart2js/cps_ir/basic_10_test.dart
deleted file mode 100644
index 3d6ab6f..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_10_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_10.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_10.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_11_test.dart b/tests/compiler/dart2js/cps_ir/basic_11_test.dart
deleted file mode 100644
index eed3081..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_11_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_11.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_11.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_12_test.dart b/tests/compiler/dart2js/cps_ir/basic_12_test.dart
deleted file mode 100644
index cbdbd19..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_12_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_12.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_12.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_13_test.dart b/tests/compiler/dart2js/cps_ir/basic_13_test.dart
deleted file mode 100644
index e867b76..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_13_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_13.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_13.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_14_test.dart b/tests/compiler/dart2js/cps_ir/basic_14_test.dart
deleted file mode 100644
index 814bf20..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_14_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_14.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_14.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_15_test.dart b/tests/compiler/dart2js/cps_ir/basic_15_test.dart
deleted file mode 100644
index 72c06fe..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_15_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_15.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_15.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_16_test.dart b/tests/compiler/dart2js/cps_ir/basic_16_test.dart
deleted file mode 100644
index 559ad5c..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_16_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_16.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_16.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_1_test.dart b/tests/compiler/dart2js/cps_ir/basic_1_test.dart
deleted file mode 100644
index 711cb33..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_2_test.dart b/tests/compiler/dart2js/cps_ir/basic_2_test.dart
deleted file mode 100644
index f5eb5b3..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_3_test.dart b/tests/compiler/dart2js/cps_ir/basic_3_test.dart
deleted file mode 100644
index 5476c1f..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_3_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_3.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_3.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_4_test.dart b/tests/compiler/dart2js/cps_ir/basic_4_test.dart
deleted file mode 100644
index 9cd8d85..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_4_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_4.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_4.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_5_test.dart b/tests/compiler/dart2js/cps_ir/basic_5_test.dart
deleted file mode 100644
index e38ea0b..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_5_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_5.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_5.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_6_test.dart b/tests/compiler/dart2js/cps_ir/basic_6_test.dart
deleted file mode 100644
index 0a79e84..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_6_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_6.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_6.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_7_test.dart b/tests/compiler/dart2js/cps_ir/basic_7_test.dart
deleted file mode 100644
index b411ab8..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_7_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_7.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_7.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_8_test.dart b/tests/compiler/dart2js/cps_ir/basic_8_test.dart
deleted file mode 100644
index 03bc57c..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_8_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_8.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_8.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/basic_9_test.dart b/tests/compiler/dart2js/cps_ir/basic_9_test.dart
deleted file mode 100644
index dd02afb..0000000
--- a/tests/compiler/dart2js/cps_ir/basic_9_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.basic_9.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("basic_9.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_10_test.dart b/tests/compiler/dart2js/cps_ir/closures_10_test.dart
deleted file mode 100644
index e5d99a8..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_10_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_10.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_10.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_11_test.dart b/tests/compiler/dart2js/cps_ir/closures_11_test.dart
deleted file mode 100644
index 6012079..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_11_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_11.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_11.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_12_test.dart b/tests/compiler/dart2js/cps_ir/closures_12_test.dart
deleted file mode 100644
index 4bf040d..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_12_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_12.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_12.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_13_test.dart b/tests/compiler/dart2js/cps_ir/closures_13_test.dart
deleted file mode 100644
index f4c83b9..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_13_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_13.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_13.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_14_test.dart b/tests/compiler/dart2js/cps_ir/closures_14_test.dart
deleted file mode 100644
index c5198e2..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_14_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_14.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_14.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_15_test.dart b/tests/compiler/dart2js/cps_ir/closures_15_test.dart
deleted file mode 100644
index f78f7a9..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_15_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_15.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_15.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_16_test.dart b/tests/compiler/dart2js/cps_ir/closures_16_test.dart
deleted file mode 100644
index 6b359ec..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_16_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_16.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_16.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_1_test.dart b/tests/compiler/dart2js/cps_ir/closures_1_test.dart
deleted file mode 100644
index 9eb7749..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_2_test.dart b/tests/compiler/dart2js/cps_ir/closures_2_test.dart
deleted file mode 100644
index ff5b698..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_3_test.dart b/tests/compiler/dart2js/cps_ir/closures_3_test.dart
deleted file mode 100644
index cb19e78..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_3_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_3.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_3.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_4_test.dart b/tests/compiler/dart2js/cps_ir/closures_4_test.dart
deleted file mode 100644
index 66142a4..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_4_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_4.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_4.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_5_test.dart b/tests/compiler/dart2js/cps_ir/closures_5_test.dart
deleted file mode 100644
index 5910347..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_5_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_5.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_5.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_6_test.dart b/tests/compiler/dart2js/cps_ir/closures_6_test.dart
deleted file mode 100644
index 9616d62..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_6_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_6.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_6.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_7_test.dart b/tests/compiler/dart2js/cps_ir/closures_7_test.dart
deleted file mode 100644
index a95b1b2..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_7_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_7.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_7.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_8_test.dart b/tests/compiler/dart2js/cps_ir/closures_8_test.dart
deleted file mode 100644
index 03b05f1..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_8_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_8.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_8.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/closures_9_test.dart b/tests/compiler/dart2js/cps_ir/closures_9_test.dart
deleted file mode 100644
index 3cf10ca..0000000
--- a/tests/compiler/dart2js/cps_ir/closures_9_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.closures_9.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("closures_9.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/codeUnitAt_1_test.dart b/tests/compiler/dart2js/cps_ir/codeUnitAt_1_test.dart
deleted file mode 100644
index e765c1d..0000000
--- a/tests/compiler/dart2js/cps_ir/codeUnitAt_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.codeUnitAt_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("codeUnitAt_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/codeUnitAt_2_test.dart b/tests/compiler/dart2js/cps_ir/codeUnitAt_2_test.dart
deleted file mode 100644
index 9838b61..0000000
--- a/tests/compiler/dart2js/cps_ir/codeUnitAt_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.codeUnitAt_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("codeUnitAt_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_10_test.dart b/tests/compiler/dart2js/cps_ir/constructor_10_test.dart
deleted file mode 100644
index ee3d425..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_10_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_10.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_10.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_11_test.dart b/tests/compiler/dart2js/cps_ir/constructor_11_test.dart
deleted file mode 100644
index 0b3002d..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_11_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_11.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_11.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_12_test.dart b/tests/compiler/dart2js/cps_ir/constructor_12_test.dart
deleted file mode 100644
index 16442e3..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_12_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_12.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_12.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_13_test.dart b/tests/compiler/dart2js/cps_ir/constructor_13_test.dart
deleted file mode 100644
index 084f2ef..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_13_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_13.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_13.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_14_test.dart b/tests/compiler/dart2js/cps_ir/constructor_14_test.dart
deleted file mode 100644
index 41903ef..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_14_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_14.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_14.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_15_test.dart b/tests/compiler/dart2js/cps_ir/constructor_15_test.dart
deleted file mode 100644
index d745e08..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_15_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_15.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_15.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_1_test.dart b/tests/compiler/dart2js/cps_ir/constructor_1_test.dart
deleted file mode 100644
index 1acf661..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_2_test.dart b/tests/compiler/dart2js/cps_ir/constructor_2_test.dart
deleted file mode 100644
index 11fd0f8..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_3_test.dart b/tests/compiler/dart2js/cps_ir/constructor_3_test.dart
deleted file mode 100644
index 46c02be..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_3_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_3.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_3.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_4_test.dart b/tests/compiler/dart2js/cps_ir/constructor_4_test.dart
deleted file mode 100644
index 11a392b..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_4_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_4.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_4.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_5_test.dart b/tests/compiler/dart2js/cps_ir/constructor_5_test.dart
deleted file mode 100644
index f95c26b..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_5_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_5.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_5.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_6_test.dart b/tests/compiler/dart2js/cps_ir/constructor_6_test.dart
deleted file mode 100644
index c37314b..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_6_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_6.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_6.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_7_test.dart b/tests/compiler/dart2js/cps_ir/constructor_7_test.dart
deleted file mode 100644
index 0aeca1c..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_7_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_7.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_7.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_8_test.dart b/tests/compiler/dart2js/cps_ir/constructor_8_test.dart
deleted file mode 100644
index b22a96d..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_8_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_8.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_8.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_9_test.dart b/tests/compiler/dart2js/cps_ir/constructor_9_test.dart
deleted file mode 100644
index 9fe1d90..0000000
--- a/tests/compiler/dart2js/cps_ir/constructor_9_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.constructor_9.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("constructor_9.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/control_flow_1_test.dart b/tests/compiler/dart2js/cps_ir/control_flow_1_test.dart
deleted file mode 100644
index 3efea51..0000000
--- a/tests/compiler/dart2js/cps_ir/control_flow_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.control_flow_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("control_flow_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/control_flow_2_test.dart b/tests/compiler/dart2js/cps_ir/control_flow_2_test.dart
deleted file mode 100644
index 04ab770..0000000
--- a/tests/compiler/dart2js/cps_ir/control_flow_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.control_flow_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("control_flow_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/control_flow_3_test.dart b/tests/compiler/dart2js/cps_ir/control_flow_3_test.dart
deleted file mode 100644
index c3cd858..0000000
--- a/tests/compiler/dart2js/cps_ir/control_flow_3_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.control_flow_3.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("control_flow_3.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/control_flow_4_test.dart b/tests/compiler/dart2js/cps_ir/control_flow_4_test.dart
deleted file mode 100644
index b355d84..0000000
--- a/tests/compiler/dart2js/cps_ir/control_flow_4_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.control_flow_4.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("control_flow_4.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/control_flow_5_test.dart b/tests/compiler/dart2js/cps_ir/control_flow_5_test.dart
deleted file mode 100644
index 37ab62c..0000000
--- a/tests/compiler/dart2js/cps_ir/control_flow_5_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.control_flow_5.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("control_flow_5.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/control_flow_6_test.dart b/tests/compiler/dart2js/cps_ir/control_flow_6_test.dart
deleted file mode 100644
index 341be8e..0000000
--- a/tests/compiler/dart2js/cps_ir/control_flow_6_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.control_flow_6.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("control_flow_6.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/control_flow_7_test.dart b/tests/compiler/dart2js/cps_ir/control_flow_7_test.dart
deleted file mode 100644
index 3b9f94c..0000000
--- a/tests/compiler/dart2js/cps_ir/control_flow_7_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.control_flow_7.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("control_flow_7.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/control_flow_8_test.dart b/tests/compiler/dart2js/cps_ir/control_flow_8_test.dart
deleted file mode 100644
index 9a64a8c..0000000
--- a/tests/compiler/dart2js/cps_ir/control_flow_8_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.control_flow_8.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("control_flow_8.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/control_flow_9_test.dart b/tests/compiler/dart2js/cps_ir/control_flow_9_test.dart
deleted file mode 100644
index 7328a45..0000000
--- a/tests/compiler/dart2js/cps_ir/control_flow_9_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.control_flow_9.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("control_flow_9.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_1.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_1.js
deleted file mode 100644
index be268f4..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_1.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x - y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$sub$n(x, y);
- P.print(x - y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_10.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_10.js
deleted file mode 100644
index 9c4c3f3..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_10.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x > y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$gt$n(x, y);
- P.print(x > y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_11.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_11.js
deleted file mode 100644
index 23f5fca..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_11.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x < y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$lt$n(x, y);
- P.print(x < y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_12.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_12.js
deleted file mode 100644
index 0fd94d2..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_12.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x >= y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$ge$n(x, y);
- P.print(x >= y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_13.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_13.js
deleted file mode 100644
index 481395c..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_13.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x <= y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$le$n(x, y);
- P.print(x <= y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_14.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_14.js
deleted file mode 100644
index 642f48b..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_14.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x.remainder(y));
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(J.remainder$1$n(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_15.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_15.js
deleted file mode 100644
index aa6f727..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_15.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// var z = int.parse('1235');
-// print(x is num);
-// print(y is num);
-// print(z is num);
-// print(x.clamp(y, z));
-// print(x is num);
-// print(y is num);
-// print(z is num);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), z = P.int_parse("1235", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(typeof z === "number");
- P.print(J.clamp$2$n(x, y, z));
- P.print(true);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_16.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_16.js
deleted file mode 100644
index 0ba4b75..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_16.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x + y);
-// print(x is num);
-// print(y is num);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), v0 = typeof x === "number", v1 = typeof y === "number";
- P.print(v0);
- P.print(v1);
- P.print(J.$add$ns(x, y));
- P.print(v0);
- P.print(v1);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_17.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_17.js
deleted file mode 100644
index 1fb2867..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_17.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x * y);
-// print(x is num);
-// print(y is num);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), v0 = typeof x === "number", v1 = typeof y === "number";
- P.print(v0);
- P.print(v1);
- P.print(J.$mul$ns(x, y));
- P.print(v0);
- P.print(v1);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_18.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_18.js
deleted file mode 100644
index 0e73f85..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_18.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x.compareTo(y));
-// print(x is num);
-// print(y is num);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), v0 = typeof x === "number", v1 = typeof y === "number";
- P.print(v0);
- P.print(v1);
- P.print(J.compareTo$1$ns(x, y));
- P.print(v0);
- P.print(v1);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_19.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_19.js
deleted file mode 100644
index 5125dcb..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_19.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x / 2);
-// print(x is num);
-// print(y is num);
-// print(x + y);
-// print(y is num);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- if (typeof x !== "number")
- return x.$div();
- P.print(x / 2);
- P.print(true);
- P.print(typeof y === "number");
- if (typeof y !== "number")
- return H.iae(y);
- P.print(x + y);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_2.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_2.js
deleted file mode 100644
index 0de632e..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_2.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x / y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$div$n(x, y);
- P.print(x / y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_20.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_20.js
deleted file mode 100644
index 13b3053..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_20.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x / 2);
-// print(x is num);
-// print(y is num);
-// print(x * y);
-// print(y is num);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- if (typeof x !== "number")
- return x.$div();
- P.print(x / 2);
- P.print(true);
- P.print(typeof y === "number");
- if (typeof y !== "number")
- return H.iae(y);
- P.print(x * y);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js
deleted file mode 100644
index 26cfc95..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x / 2);
-// print(x is num);
-// print(y is num);
-// print(x.compareTo(y));
-// print(y is num);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), v0;
- if (typeof x !== "number")
- return x.$div();
- P.print(x / 2);
- P.print(true);
- v0 = typeof y === "number";
- P.print(v0);
- if (!v0)
- throw H.wrapException(H.argumentErrorValue(y));
- P.print(x < y ? -1 : x > y ? 1 : x === y ? x === 0 ? 1 / x < 0 === (y === 0 ? 1 / y < 0 : y < 0) ? 0 : 1 / x < 0 ? -1 : 1 : 0 : isNaN(x) ? isNaN(y) ? 0 : 1 : -1);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_22.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_22.js
deleted file mode 100644
index 3948378..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_22.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is int);
-// print(y is int);
-// print(x.toSigned(y));
-// print(x is int);
-// print(y is int);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number" && Math.floor(x) === x);
- P.print(typeof y === "number" && Math.floor(y) === y);
- P.print(J.toSigned$1$i(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_23.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_23.js
deleted file mode 100644
index e2e290d..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_23.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is int);
-// print(y is int);
-// print(x.toUnsigned(y));
-// print(x is int);
-// print(y is int);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number" && Math.floor(x) === x);
- P.print(typeof y === "number" && Math.floor(y) === y);
- P.print(J.toUnsigned$1$i(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_24.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_24.js
deleted file mode 100644
index f251917..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_24.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is int);
-// print(y is int);
-// print(x.modInverse(y));
-// print(x is int);
-// print(y is int);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number" && Math.floor(x) === x);
- P.print(typeof y === "number" && Math.floor(y) === y);
- P.print(J.modInverse$1$i(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_25.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_25.js
deleted file mode 100644
index 9ebb55a..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_25.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is int);
-// print(y is int);
-// print(x.gcd(y));
-// print(x is int);
-// print(y is int);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number" && Math.floor(x) === x);
- P.print(typeof y === "number" && Math.floor(y) === y);
- P.print(J.gcd$1$i(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_26.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_26.js
deleted file mode 100644
index 9294a75..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_26.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// var z = int.parse('1235');
-// print(x is int);
-// print(y is int);
-// print(z is int);
-// print(x.modPow(y, z));
-// print(x is int);
-// print(y is int);
-// print(z is int);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), z = P.int_parse("1235", null, null);
- P.print(typeof x === "number" && Math.floor(x) === x);
- P.print(typeof y === "number" && Math.floor(y) === y);
- P.print(typeof z === "number" && Math.floor(z) === z);
- P.print(J.modPow$2$i(x, y, z));
- P.print(true);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_27.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_27.js
deleted file mode 100644
index 484f6a1..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_27.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('3');
-// var y = int.parse('a', onError: (e) => 'abcde');
-// print(x is int);
-// print(y is String);
-// print(y.codeUnitAt(x));
-// print(x is int);
-// print(y is String);
-// }
-
-function() {
- var x = P.int_parse("3", null, null), y = P.int_parse("a", new V.main_closure(), null);
- P.print(typeof x === "number" && Math.floor(x) === x);
- P.print(typeof y === "string");
- P.print(J.codeUnitAt$1$s(y, x));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_28.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_28.js
deleted file mode 100644
index b5ab697..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_28.js
+++ /dev/null
@@ -1,47 +0,0 @@
-// Expectation for test:
-// import 'dart:math';
-// main() {
-// var x = int.parse('3');
-// var y = int.parse('1234');
-// var z = int.parse('1236');
-// var w = int.parse('2');
-// print(x is num);
-// print(sin(x));
-// print(x is num);
-//
-// print(y is num);
-// print(log(y));
-// print(y is num);
-//
-// print(z is num);
-// print(w is num);
-// print(pow(z, w));
-// print(z is num);
-// print(w is num);
-// }
-
-function() {
- var x = P.int_parse("3", null, null), y = P.int_parse("1234", null, null), z = P.int_parse("1236", null, null), w = P.int_parse("2", null, null), v0 = typeof x === "number", v1;
- P.print(v0);
- if (!v0)
- throw H.wrapException(H.argumentErrorValue(x));
- P.print(Math.sin(x));
- P.print(true);
- v0 = typeof y === "number";
- P.print(v0);
- if (!v0)
- throw H.wrapException(H.argumentErrorValue(y));
- P.print(Math.log(y));
- P.print(true);
- v1 = typeof z === "number";
- P.print(v1);
- v0 = typeof w === "number";
- P.print(v0);
- if (!v1)
- throw H.wrapException(H.argumentErrorValue(z));
- if (!v0)
- throw H.wrapException(H.argumentErrorValue(w));
- P.print(Math.pow(z, w));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_3.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_3.js
deleted file mode 100644
index 5d7d8a8..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_3.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x % y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(J.$mod$n(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_4.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_4.js
deleted file mode 100644
index 43dfc17..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_4.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x ~/ y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(J.$tdiv$n(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_5.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_5.js
deleted file mode 100644
index 049ef54..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_5.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x >> y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(J.$shr$n(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_6.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_6.js
deleted file mode 100644
index 953fc10..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_6.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x << y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(J.$shl$n(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_7.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_7.js
deleted file mode 100644
index cb58cd3..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_7.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x & y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$and$n(x, y);
- P.print((x & y) >>> 0);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_8.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_8.js
deleted file mode 100644
index 7c0109d..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_8.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x | y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$or$n(x, y);
- P.print((x | y) >>> 0);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_9.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_9.js
deleted file mode 100644
index c1c6bec..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_9.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x ^ y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$xor$n(x, y);
- P.print((x ^ y) >>> 0);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_1.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_1.js
deleted file mode 100644
index be268f4..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_1.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x - y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$sub$n(x, y);
- P.print(x - y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_10.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_10.js
deleted file mode 100644
index 23f5fca..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_10.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x < y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$lt$n(x, y);
- P.print(x < y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_11.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_11.js
deleted file mode 100644
index 9c4c3f3..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_11.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x > y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$gt$n(x, y);
- P.print(x > y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_12.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_12.js
deleted file mode 100644
index 481395c..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_12.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x <= y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$le$n(x, y);
- P.print(x <= y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_13.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_13.js
deleted file mode 100644
index 0fd94d2..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_13.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x >= y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$ge$n(x, y);
- P.print(x >= y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_14.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_14.js
deleted file mode 100644
index 642f48b..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_14.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x.remainder(y));
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(J.remainder$1$n(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_15.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_15.js
deleted file mode 100644
index 3ce06f4..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_15.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// var z = int.parse('1236');
-// print(x is num);
-// print(y is num);
-// print(z is num);
-// print(x.clamp(y, z));
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// print(z is num);
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), z = P.int_parse("1236", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(typeof z === "number");
- P.print(J.clamp$2$n(x, y, z));
- P.print(true);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_16.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_16.js
deleted file mode 100644
index 10c7792..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_16.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x + y);
-// print(x is num);
-// print(y is num); // will stay as is-num because String could be a target of +
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), v0 = typeof x === "number", v1 = typeof y === "number";
- P.print(v0);
- P.print(v1);
- P.print(J.$add$ns(x, y));
- P.print(v0);
- P.print(v1);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_17.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_17.js
deleted file mode 100644
index 4fa1574..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_17.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x * y);
-// print(x is num);
-// print(y is num); // will stay as is-num because String could be a target of *
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), v0 = typeof x === "number", v1 = typeof y === "number";
- P.print(v0);
- P.print(v1);
- P.print(J.$mul$ns(x, y));
- P.print(v0);
- P.print(v1);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_2.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_2.js
deleted file mode 100644
index 0de632e..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_2.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x / y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$div$n(x, y);
- P.print(x / y);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_3.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_3.js
deleted file mode 100644
index 5d7d8a8..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_3.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x % y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(J.$mod$n(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_4.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_4.js
deleted file mode 100644
index 43dfc17..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_4.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x ~/ y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(J.$tdiv$n(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_5.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_5.js
deleted file mode 100644
index 049ef54..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_5.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x >> y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(J.$shr$n(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_6.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_6.js
deleted file mode 100644
index 953fc10..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_6.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x << y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- P.print(J.$shl$n(x, y));
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_7.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_7.js
deleted file mode 100644
index cb58cd3..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_7.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x & y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$and$n(x, y);
- P.print((x & y) >>> 0);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_8.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_8.js
deleted file mode 100644
index 7c0109d..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_8.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x | y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$or$n(x, y);
- P.print((x | y) >>> 0);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_9.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_9.js
deleted file mode 100644
index c1c6bec..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_9.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = int.parse('1233');
-// var y = int.parse('1234');
-// print(x is num);
-// print(y is num);
-// print(x ^ y);
-// print(x is num);
-// print(y is num); // will be compiled to `true` if we know the type of `y`.
-// }
-
-function() {
- var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
- P.print(typeof x === "number");
- P.print(typeof y === "number");
- if (typeof x !== "number" || typeof y !== "number")
- return J.$xor$n(x, y);
- P.print((x ^ y) >>> 0);
- P.print(true);
- P.print(true);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_1.js b/tests/compiler/dart2js/cps_ir/expected/basic_1.js
deleted file mode 100644
index f8384d4..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_1.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// Expectation for test:
-// main() {
-// var e = 1;
-// var l = [1, 2, 3];
-// var m = {'s': 1};
-//
-// print('(' ')');
-// print('(${true})');
-// print('(${1})');
-// print('(${[1, 2, 3]})');
-// print('(${{'s': 1}})');
-// print('($e)');
-// print('($l)');
-// print('($m)');
-// }
-
-function() {
- var l = [1, 2, 3], m = P.LinkedHashMap__makeLiteral(["s", 1]);
- P.print("()");
- P.print("(true)");
- P.print("(1)");
- P.print("(" + H.S([1, 2, 3]) + ")");
- P.print("(" + P.Maps_mapToString(P.LinkedHashMap__makeLiteral(["s", 1])) + ")");
- P.print("(1)");
- P.print("(" + H.S(l) + ")");
- P.print("(" + P.Maps_mapToString(m) + ")");
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_10.js b/tests/compiler/dart2js/cps_ir/expected/basic_10.js
deleted file mode 100644
index 745bc50..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_10.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Expectation for test:
-// main() {
-// print(new DateTime.now().isBefore(new DateTime.now()));
-// }
-
-function() {
- var line = H.S(Date.now() < Date.now());
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_11.js b/tests/compiler/dart2js/cps_ir/expected/basic_11.js
deleted file mode 100644
index 68995ca..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_11.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Expectation for test:
-// foo() { print(42); }
-// main() { foo(); }
-
-function() {
- if (typeof dartPrint == "function")
- dartPrint("42");
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log("42");
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String("42");
- print("42");
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_12.js b/tests/compiler/dart2js/cps_ir/expected/basic_12.js
deleted file mode 100644
index ac9e1d3..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_12.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Expectation for test:
-// var foo = 42;
-// main() { print(foo); }
-
-function() {
- var line = H.S($.foo);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_13.js b/tests/compiler/dart2js/cps_ir/expected/basic_13.js
deleted file mode 100644
index e8db598..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_13.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Expectation for test:
-// get foo { print(42); }
-// main() { foo; }
-
-function() {
- if (typeof dartPrint == "function")
- dartPrint("42");
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log("42");
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String("42");
- print("42");
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_14.js b/tests/compiler/dart2js/cps_ir/expected/basic_14.js
deleted file mode 100644
index 068816d..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_14.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Expectation for test:
-// var foo = 0;
-// main() { print(foo = 42); }
-
-function() {
- $.foo = 42;
- if (typeof dartPrint == "function")
- dartPrint("42");
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log("42");
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String("42");
- print("42");
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_15.js b/tests/compiler/dart2js/cps_ir/expected/basic_15.js
deleted file mode 100644
index 92ba7b0..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_15.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Expectation for test:
-// set foo(x) { print(x); }
-// main() { foo = 42; }
-
-function() {
- if (typeof dartPrint == "function")
- dartPrint("42");
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log("42");
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String("42");
- print("42");
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_16.js b/tests/compiler/dart2js/cps_ir/expected/basic_16.js
deleted file mode 100644
index 0442443..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_16.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Expectation for test:
-// foo() { print('X'); }
-// main() {
-// assert(true);
-// assert(false);
-// assert(foo());
-// print('Done');
-// }
-
-function() {
- P.print("Done");
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_2.js b/tests/compiler/dart2js/cps_ir/expected/basic_2.js
deleted file mode 100644
index 3f579fc..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_2.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Expectation for test:
-// foo(a, [b = "b"]) { print(b); return b; }
-// bar(a, {b: "b", c: "c"}) { print(c); return c; }
-// main() {
-// foo(0);
-// foo(1, 2);
-// bar(3);
-// bar(4, b: 5);
-// bar(6, c: 7);
-// bar(8, b: 9, c: 10);
-// }
-
-function() {
- P.print("b");
- P.print(2);
- P.print("c");
- P.print("c");
- P.print(7);
- P.print(10);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_3.js b/tests/compiler/dart2js/cps_ir/expected/basic_3.js
deleted file mode 100644
index 3d8269f..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_3.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Expectation for test:
-// foo(a) {
-// print(a);
-// return a;
-// }
-// main() {
-// var a = 10;
-// var b = 1;
-// var t;
-// t = a;
-// a = b;
-// b = t;
-// print(a);
-// print(b);
-// print(b);
-// print(foo(a));
-// }
-
-function() {
- P.print(1);
- P.print(10);
- P.print(10);
- P.print(1);
- P.print(1);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_4.js b/tests/compiler/dart2js/cps_ir/expected/basic_4.js
deleted file mode 100644
index 8ce632a..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_4.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Expectation for test:
-// foo() { print(42); return 42; }
-// main() { return foo(); }
-
-function() {
- if (typeof dartPrint == "function")
- dartPrint("42");
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log("42");
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String("42");
- print("42");
- }
- return 42;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_5.js b/tests/compiler/dart2js/cps_ir/expected/basic_5.js
deleted file mode 100644
index 9027244..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_5.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Expectation for test:
-// main() {}
-
-function() {
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_6.js b/tests/compiler/dart2js/cps_ir/expected/basic_6.js
deleted file mode 100644
index a6a2296..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_6.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// Expectation for test:
-// main() { return 42; }
-
-function() {
- return 42;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_7.js b/tests/compiler/dart2js/cps_ir/expected/basic_7.js
deleted file mode 100644
index cd112ad..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_7.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Expectation for test:
-// main() { return; }
-
-function() {
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_8.js b/tests/compiler/dart2js/cps_ir/expected/basic_8.js
deleted file mode 100644
index 1d8cccd..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_8.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// Expectation for test:
-// main() {
-// print(new Set());
-// print(new Set.from([1, 2, 3]));
-// }
-
-function() {
- P.print(P._LinkedHashSet$(null));
- P.print(P.LinkedHashSet_LinkedHashSet$from([1, 2, 3], null));
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_9.js b/tests/compiler/dart2js/cps_ir/expected/basic_9.js
deleted file mode 100644
index c23788a..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/basic_9.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// Expectation for test:
-// class C {}
-// main() {
-// print(new C());
-// }
-
-function() {
- var line = "Instance of '" + H.Primitives_objectTypeName(V.C$()) + "'";
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_1.js b/tests/compiler/dart2js/cps_ir/expected/closures_1.js
deleted file mode 100644
index e8cc7ab..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_1.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Expectation for test:
-// main(x) {
-// a() {
-// return x;
-// }
-// x = x + '1';
-// print(a());
-// }
-
-function(x) {
- P.print(J.$add$ns(x, "1"));
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_10.js b/tests/compiler/dart2js/cps_ir/expected/closures_10.js
deleted file mode 100644
index 64e5e31..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_10.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// class A {
-// a() => 1;
-// b() => () => a();
-// }
-// main() {
-// print(new A().b()());
-// }
-
-function() {
- var line = H.S(V.A$().a$0());
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_11.js b/tests/compiler/dart2js/cps_ir/expected/closures_11.js
deleted file mode 100644
index e547d06..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_11.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Expectation for test:
-// staticMethod(x) { print(x); return x; }
-// main(x) {
-// var tearOff = staticMethod;
-// print(tearOff(123));
-// }
-
-function(x) {
- P.print(123);
- P.print(123);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_12.js b/tests/compiler/dart2js/cps_ir/expected/closures_12.js
deleted file mode 100644
index 5078169..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_12.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Expectation for test:
-// class Foo {
-// instanceMethod(x) => x;
-// }
-// main(x) {
-// var tearOff = new Foo().instanceMethod;
-// print(tearOff(123));
-// }
-
-function(x) {
- V.Foo$();
- P.print(123);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_13.js b/tests/compiler/dart2js/cps_ir/expected/closures_13.js
deleted file mode 100644
index 5a61827..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_13.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Expectation for test:
-// class Foo {
-// instanceMethod(x) => x;
-// }
-// main(x) {
-// var tearOff = new Foo().instanceMethod;
-// print(tearOff(123));
-// print(tearOff(321));
-// }
-
-function(x) {
- V.Foo$();
- P.print(123);
- P.print(321);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_14.js b/tests/compiler/dart2js/cps_ir/expected/closures_14.js
deleted file mode 100644
index 5c27c7b..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_14.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Expectation for test:
-// class Foo {
-// get getter {
-// print('getter');
-// return (x) => x;
-// }
-// }
-// main(x) {
-// var notTearOff = new Foo().getter;
-// print(notTearOff(123));
-// print(notTearOff(321));
-// }
-
-function(x) {
- var notTearOff = new V.Foo_getter_closure();
- V.Foo$();
- P.print("getter");
- P.print(notTearOff.call$1(123));
- P.print(notTearOff.call$1(321));
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_15.js b/tests/compiler/dart2js/cps_ir/expected/closures_15.js
deleted file mode 100644
index cf37dd2..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_15.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Expectation for test:
-// class Foo {
-// get getter {
-// print('getter');
-// return (x) => x;
-// }
-// }
-// main(x) {
-// var notTearOff = new Foo().getter;
-// print(notTearOff(123));
-// }
-
-function(x) {
- V.Foo$();
- P.print("getter");
- P.print(123);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_16.js b/tests/compiler/dart2js/cps_ir/expected/closures_16.js
deleted file mode 100644
index e589971..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_16.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Expectation for test:
-// class Foo {
-// get getter {
-// print('getter');
-// return (x) { try { return x; } finally { } }; // Inhibit inlining.
-// }
-// }
-// main(x) {
-// // Getter may or may not be inlined.
-// var notTearOff = new Foo().getter;
-// // Closure is not inlined.
-// print(notTearOff(123));
-// }
-
-function(x) {
- P.print(V.Foo$().get$getter().call$1(123));
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_2.js b/tests/compiler/dart2js/cps_ir/expected/closures_2.js
deleted file mode 100644
index b5ffeebd..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_2.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Expectation for test:
-// main(x) {
-// a() {
-// return x;
-// }
-// x = x + '1';
-// print(a());
-// return a;
-// }
-
-function(x) {
- var _box_0 = {}, a = new V.main_a(_box_0);
- _box_0.x = x;
- _box_0.x = J.$add$ns(_box_0.x, "1");
- P.print(a.call$0());
- return a;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_3.js b/tests/compiler/dart2js/cps_ir/expected/closures_3.js
deleted file mode 100644
index 69425f1..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_3.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Expectation for test:
-// main(x) {
-// a() {
-// return x;
-// }
-// print(a());
-// }
-
-function(x) {
- P.print(x);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_4.js b/tests/compiler/dart2js/cps_ir/expected/closures_4.js
deleted file mode 100644
index 02027fe..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_4.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// Expectation for test:
-// main(x) {
-// a() {
-// return x;
-// }
-// print(a());
-// return a;
-// }
-
-function(x) {
- var a = new V.main_a(x);
- P.print(a.call$0());
- return a;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_5.js b/tests/compiler/dart2js/cps_ir/expected/closures_5.js
deleted file mode 100644
index 3c61ff5..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_5.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = 122;
-// var a = () => x;
-// x = x + 1;
-// print(a());
-// }
-
-function() {
- var line = H.S(122 + 1);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_6.js b/tests/compiler/dart2js/cps_ir/expected/closures_6.js
deleted file mode 100644
index 3ff087a..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_6.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = 122;
-// var a = () => x;
-// x = x + 1;
-// print(a());
-// return a;
-// }
-
-function() {
- var _box_0 = {}, a = new V.main_closure(_box_0), line;
- _box_0.x = 122;
- ++_box_0.x;
- line = H.S(a.call$0());
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
- return a;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_7.js b/tests/compiler/dart2js/cps_ir/expected/closures_7.js
deleted file mode 100644
index 62f16ad..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_7.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = 122;
-// var a = () {
-// var y = x;
-// return () => y;
-// };
-// x = x + 1;
-// print(a()());
-// }
-
-function() {
- var line = H.S(122 + 1);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_8.js b/tests/compiler/dart2js/cps_ir/expected/closures_8.js
deleted file mode 100644
index 35d033f..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_8.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Expectation for test:
-// main() {
-// var x = 122;
-// var a = () {
-// var y = x;
-// return () => y;
-// };
-// x = x + 1;
-// print(a()());
-// return a;
-// }
-
-function() {
- var _box_0 = {}, a = new V.main_closure(_box_0), line;
- _box_0.x = 122;
- ++_box_0.x;
- line = H.S(a.call$0().call$0());
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
- return a;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_9.js b/tests/compiler/dart2js/cps_ir/expected/closures_9.js
deleted file mode 100644
index c11aa2d..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/closures_9.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Expectation for test:
-// main() {
-// var a;
-// for (var i=0; i<10; i++) {
-// a = () => i;
-// }
-// print(a());
-// }
-
-function() {
- var a = null, i = 0, line;
- for (; i < 10; a = new V.main_closure(i), ++i)
- ;
- line = H.S(a.call$0());
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_1.js b/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_1.js
deleted file mode 100644
index 9043a3f..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_1.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Expectation for test:
-// // Constant folding
-// main() {
-// print('A'.codeUnitAt(0));
-// }
-
-function() {
- if (typeof dartPrint == "function")
- dartPrint("65");
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log("65");
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String("65");
- print("65");
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js b/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js
deleted file mode 100644
index 4fdd8a2..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// Expectation for test:
-// // Bounds checking
-// foo(s) {
-// var sum = 0;
-// for (int i = 0; i < s.length; i++) sum += s.codeUnitAt(i);
-// return sum;
-// }
-// main() {
-// print(foo('ABC'));
-// print(foo('Hello'));
-// }
-
-function() {
- var sum = 0, i = 0;
- for (; i < 3; sum += "ABC".charCodeAt(i), ++i)
- ;
- P.print(sum);
- sum = 0;
- for (i = 0; i < 5; sum += "Hello".charCodeAt(i), ++i)
- ;
- P.print(sum);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_1.js b/tests/compiler/dart2js/cps_ir/expected/constructor_1.js
deleted file mode 100644
index 6afa3a3..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_1.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Expectation for test:
-// class Base {
-// var x;
-// Base(this.x);
-// }
-// class Sub extends Base {
-// var y;
-// Sub(x, this.y) : super(x);
-// }
-// main() {
-// print(new Sub(1, 2).x);
-// }
-
-function() {
- var line = H.S(1);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_10.js b/tests/compiler/dart2js/cps_ir/expected/constructor_10.js
deleted file mode 100644
index c2148d0..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_10.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Expectation for test:
-// // Method to test: generative_constructor(C#)
-// class C<T> {
-// var x;
-// C() : x = new D<T>();
-// }
-// class D<T> {
-// foo() => T;
-// }
-// main() {
-// print(new C<int>().x.foo());
-// }
-
-function($T) {
- return H.setRuntimeTypeInfo(new V.C(V.D$($T)), [$T]);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_11.js b/tests/compiler/dart2js/cps_ir/expected/constructor_11.js
deleted file mode 100644
index 3221867..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_11.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// Expectation for test:
-// class A {
-// var x;
-// A() : this.b(1);
-// A.b(this.x);
-// }
-// main() {
-// print(new A().x);
-// }
-
-function() {
- var line = H.S(1);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_12.js b/tests/compiler/dart2js/cps_ir/expected/constructor_12.js
deleted file mode 100644
index d892327..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_12.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Expectation for test:
-// class Foo {
-// factory Foo.make(x) {
-// print('Foo');
-// return new Foo.create(x);
-// }
-// var x;
-// Foo.create(this.x);
-// }
-// main() {
-// print(new Foo.make(5));
-// }
-
-function() {
- P.print("Foo");
- P.print(new V.Foo(5));
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_13.js b/tests/compiler/dart2js/cps_ir/expected/constructor_13.js
deleted file mode 100644
index a95670c..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_13.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// Expectation for test:
-// class Foo {
-// factory Foo.make(x) = Foo.create;
-// var x;
-// Foo.create(this.x);
-// }
-// main() {
-// print(new Foo.make(5));
-// }
-
-function() {
- var line = "Instance of '" + H.Primitives_objectTypeName(new V.Foo(5)) + "'";
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_14.js b/tests/compiler/dart2js/cps_ir/expected/constructor_14.js
deleted file mode 100644
index fe479f9..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_14.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// Expectation for test:
-// class A {
-// factory A(x) = B<int>;
-// get typevar;
-// }
-// class B<T> implements A {
-// var x;
-// B(this.x);
-//
-// get typevar => T;
-// }
-// main() {
-// new A(5).typevar;
-// }
-
-function() {
- V.B$(5, P.$int);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_15.js b/tests/compiler/dart2js/cps_ir/expected/constructor_15.js
deleted file mode 100644
index 22c0973..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_15.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// // Method to test: generative_constructor(A#)
-// class A {
-// var x, y, z;
-// A(x, y) {
-// this.x = x;
-// this.y = y;
-// this.z = this.x / 2;
-// }
-// }
-//
-// main() {
-// print(new A(123, 'sdf').y);
-// try {} finally {} // Do not inline into main.
-// }
-
-function(x, y) {
- return new V.A(x, y, x / 2);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_2.js b/tests/compiler/dart2js/cps_ir/expected/constructor_2.js
deleted file mode 100644
index 94d3b4e..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_2.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// class Base {
-// var x;
-// Base(this.x);
-// }
-// class Sub extends Base {
-// var y;
-// Sub(x, this.y) : super(x) {
-// print(x);
-// }
-// }
-// main() {
-// print(new Sub(1, 2).x);
-// }
-
-function() {
- P.print(1);
- P.print(1);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_3.js b/tests/compiler/dart2js/cps_ir/expected/constructor_3.js
deleted file mode 100644
index 0f14d28..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_3.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Expectation for test:
-// class Base0 {
-// Base0() {
-// print('Base0');
-// }
-// }
-// class Base extends Base0 {
-// var x;
-// Base(this.x);
-// }
-// class Sub extends Base {
-// var y;
-// Sub(x, this.y) : super(x) {
-// print(x);
-// }
-// }
-// main() {
-// print(new Sub(1, 2).x);
-// }
-
-function() {
- P.print("Base0");
- P.print(1);
- P.print(1);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_4.js b/tests/compiler/dart2js/cps_ir/expected/constructor_4.js
deleted file mode 100644
index 7253134..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_4.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// Expectation for test:
-// class Base0 {
-// Base0() {
-// print('Base0');
-// }
-// }
-// class Base extends Base0 {
-// var x;
-// Base(x1) : x = (() => ++x1) {
-// print(x1); // use boxed x1
-// }
-// }
-// class Sub extends Base {
-// var y;
-// Sub(x, this.y) : super(x) {
-// print(x);
-// }
-// }
-// main() {
-// print(new Sub(1, 2).x);
-// }
-
-function() {
- var _box_0 = {};
- _box_0.x1 = 1;
- P.print("Base0");
- P.print(_box_0.x1);
- P.print(1);
- P.print(new V.Base_closure(_box_0));
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_5.js b/tests/compiler/dart2js/cps_ir/expected/constructor_5.js
deleted file mode 100644
index ed704e1..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_5.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Expectation for test:
-// foo(x) {
-// print(x);
-// }
-// class Base {
-// var x1 = foo('x1');
-// var x2;
-// var x3 = foo('x3');
-// Base() : x2 = foo('x2');
-// }
-// class Sub extends Base {
-// var y1 = foo('y1');
-// var y2;
-// var y3;
-// Sub() : y2 = foo('y2'), super(), y3 = foo('y3');
-// }
-// main() {
-// new Sub();
-// }
-
-function() {
- V.foo("y1");
- V.foo("y2");
- V.foo("x1");
- V.foo("x3");
- V.foo("x2");
- V.foo("y3");
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_6.js b/tests/compiler/dart2js/cps_ir/expected/constructor_6.js
deleted file mode 100644
index 66d5ae5..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_6.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Expectation for test:
-// class Bar {
-// Bar(x, {y, z: 'z', w: '_', q}) {
-// print(x);
-// print(y);
-// print(z);
-// print(w);
-// print(q);
-// }
-// }
-// class Foo extends Bar {
-// Foo() : super('x', y: 'y', w: 'w');
-// }
-// main() {
-// new Foo();
-// }
-
-function() {
- P.print("x");
- P.print("y");
- P.print("z");
- P.print("w");
- P.print(null);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_7.js b/tests/compiler/dart2js/cps_ir/expected/constructor_7.js
deleted file mode 100644
index 8474ee4..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_7.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Expectation for test:
-// class C<T> {
-// foo() => T;
-// }
-// main() {
-// print(new C<int>().foo());
-// }
-
-function() {
- var line = H.S(H.createRuntimeType(H.runtimeTypeToString(H.getTypeArgumentByIndex(V.C$(P.$int), 0))));
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_8.js b/tests/compiler/dart2js/cps_ir/expected/constructor_8.js
deleted file mode 100644
index e4a2ea6..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_8.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// Expectation for test:
-// class C<T> {
-// foo() => C;
-// }
-// main() {
-// print(new C<int>().foo());
-// }
-
-function() {
- var line;
- V.C$();
- line = H.S(C.Type_C_cdS);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_9.js b/tests/compiler/dart2js/cps_ir/expected/constructor_9.js
deleted file mode 100644
index 6240573..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_9.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Expectation for test:
-// // Method to test: generative_constructor(C#)
-// class C<T> {
-// C() { print(T); }
-// foo() => print(T);
-// }
-// main() {
-// new C<int>();
-// }
-
-function($T) {
- var line = H.S(H.createRuntimeType(H.runtimeTypeToString($T)));
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
- return H.setRuntimeTypeInfo(new V.C(), [$T]);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js
deleted file mode 100644
index 7fd9aff..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Expectation for test:
-// main() {
-// while (true);
-// }
-
-function() {
- for (;;)
- ;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js
deleted file mode 100644
index 3cb9718..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// Expectation for test:
-// foo(a) { try { print(a); } finally { return a; } }
-//
-// main() {
-// while (true) {
-// l: while (true) {
-// while (foo(true)) {
-// if (foo(false)) break l;
-// }
-// print(1);
-// }
-// print(2);
-// }
-// }
-
-function() {
- L0:
- for (;;)
- for (;;) {
- while (V.foo(true))
- if (V.foo(false)) {
- P.print(2);
- continue L0;
- }
- P.print(1);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js
deleted file mode 100644
index f7c0900..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Expectation for test:
-// foo(a) { try { print(a); } finally { return a; } }
-//
-// main() {
-// for (int i = 0; foo(true); i = foo(i)) {
-// print(1);
-// if (foo(false)) break;
-// }
-// print(2);
-// }
-
-function() {
- var i = 0;
- for (; V.foo(true) === true; i = V.foo(i)) {
- P.print(1);
- if (V.foo(false) === true)
- break;
- }
- P.print(2);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js
deleted file mode 100644
index dae4cc7..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// Expectation for test:
-// foo(a) { try { print(a); } finally { return a; } }
-//
-// main() {
-// foo(false);
-// if (foo(true)) {
-// print(1);
-// } else {
-// print(2);
-// }
-// print(3);
-// }
-
-function() {
- V.foo(false);
- V.foo(true) ? P.print(1) : P.print(2);
- P.print(3);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js
deleted file mode 100644
index 0f28201..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// Expectation for test:
-// foo(a) { try { print(a); } finally { return a; } }
-//
-// main() {
-// foo(false);
-// if (foo(true)) {
-// print(1);
-// print(1);
-// } else {
-// print(2);
-// print(2);
-// }
-// print(3);
-// }
-
-function() {
- V.foo(false);
- if (V.foo(true)) {
- P.print(1);
- P.print(1);
- } else {
- P.print(2);
- P.print(2);
- }
- P.print(3);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_6.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_6.js
deleted file mode 100644
index 4530b7e..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_6.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Expectation for test:
-// main() {
-// if (1) {
-// print('bad');
-// } else {
-// print('good');
-// }
-// }
-
-function() {
- P.print("good");
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_7.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_7.js
deleted file mode 100644
index e4f20e1..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_7.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// Expectation for test:
-// foo() { print('2'); return 2; }
-// main() {
-// if (foo()) {
-// print('bad');
-// } else {
-// print('good');
-// }
-// }
-
-function() {
- P.print("2");
- P.print("good");
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_8.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_8.js
deleted file mode 100644
index bcb67d3..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_8.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Expectation for test:
-// main() {
-// var list = [1,2,3,4,5,6];
-// for (var x in list) {
-// print(x);
-// }
-// }
-
-function() {
- var list = [1, 2, 3, 4, 5, 6], i = 0, line;
- for (; i < 6; ++i) {
- line = H.S(list[i]);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_9.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_9.js
deleted file mode 100644
index 637d654..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_9.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var xs = ['x', 'y', 'z'], ys = ['A', 'B', 'C'];
-// var xit = xs.iterator, yit = ys.iterator;
-// while (xit.moveNext() && yit.moveNext()) {
-// print(xit.current);
-// print(yit.current);
-// }
-// }
-
-function() {
- var xs = ["x", "y", "z"], ys = ["A", "B", "C"], i = 0, i1 = 0, current, current1;
- for (; i < 3; ++i, ++i1) {
- current = xs[i];
- if (!(i1 < 3))
- break;
- current1 = ys[i1];
- P.print(current);
- P.print(current1);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/gvn_1.js b/tests/compiler/dart2js/cps_ir/expected/gvn_1.js
deleted file mode 100644
index 5e14c5c..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/gvn_1.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Expectation for test:
-// foo(x, list) {
-// var sum = 0;
-// for (int k = 0; k < 10; k++) {
-// // Everything can be hoisted out up to the index access which is
-// // blocked by the bounds check.
-// var a = x.left.left;
-// var b = x.left.right;
-// var c = x.right.left;
-// var d = x.right.right;
-// var i = a.value + c.value;
-// var j = b.value + d.value;
-// var z = list[i * j] + i;
-// sum += z;
-// }
-// return sum;
-// }
-// // Use a different class for each level in the tree, so type inference
-// // is not confused.
-// class Root {
-// Branch left, right;
-// Root(this.left, this.right);
-// }
-// class Branch {
-// Leaf left, right;
-// Branch(this.left, this.right);
-// }
-// class Leaf {
-// int value;
-// Leaf(this.value);
-// }
-// main() {
-// var x1 = new Leaf(1);
-// var x2 = new Leaf(10);
-// var x3 = new Leaf(20);
-// var x4 = new Leaf(-10);
-// var y1 = new Branch(x1, x2);
-// var y2 = new Branch(x3, x4);
-// var z = new Root(y1, y2);
-// print(foo(z, [1,2,3,4,5,6,7,8,9,10]));
-// }
-
-function() {
- var v0 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], i = 1 + 20, v1 = i * (10 + -10), sum = 0, k = 0, line;
- for (; k < 10; sum += i + v0[v1], ++k)
- if (v1 < 0 || v1 >= 10)
- return H.ioore(v0, v1);
- line = H.S(sum);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/interceptors_1.js b/tests/compiler/dart2js/cps_ir/expected/interceptors_1.js
deleted file mode 100644
index a8df9d1..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/interceptors_1.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Expectation for test:
-// main() {
-// var g = 1;
-//
-// var x = g + 3;
-// print(x);
-// }
-
-function() {
- if (typeof dartPrint == "function")
- dartPrint("4");
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log("4");
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String("4");
- print("4");
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/interceptors_2.js b/tests/compiler/dart2js/cps_ir/expected/interceptors_2.js
deleted file mode 100644
index fdb0701..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/interceptors_2.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Expectation for test:
-// main() {
-// var l = ['hest', ['h', 'e', 's', 't']];
-// print(l.length);
-// for (int i = 0; i < l.length; i++) {
-// var x = l[i];
-// for (int j = 0; j < x.length; j++) {
-// print(x[j]);
-// }
-// }
-// }
-
-function() {
- var l = ["hest", ["h", "e", "s", "t"]], i = 0, x, j;
- for (P.print(2); i < 2; ++i) {
- x = l[i];
- for (j = 0; j < x.length; ++j)
- P.print(x[j]);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/literals_1.js b/tests/compiler/dart2js/cps_ir/expected/literals_1.js
deleted file mode 100644
index d70ebf8..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/literals_1.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Expectation for test:
-// main() {
-// print([]);
-// print([1]);
-// print([1, 2]);
-// print([1, [1, 2]]);
-// print({});
-// print({1: 2});
-// print({[1, 2]: [3, 4]});
-// }
-
-function() {
- P.print([]);
- P.print([1]);
- P.print([1, 2]);
- P.print([1, [1, 2]]);
- P.print(P.LinkedHashMap__makeEmpty());
- P.print(P.LinkedHashMap__makeLiteral([1, 2]));
- P.print(P.LinkedHashMap__makeLiteral([[1, 2], [3, 4]]));
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_1.js b/tests/compiler/dart2js/cps_ir/expected/operators2_1.js
deleted file mode 100644
index 71a1da5..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_1.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Expectation for test:
-// // Method to test: function(foo)
-// foo(a, b) => ((a & 0xff0000) >> 1) & b;
-// main() {
-// print(foo.toString());
-// print(foo(123, 234));
-// print(foo(0, 2));
-// }
-
-function(a, b) {
- return (a & 16711680) >>> 1 & b;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_2.js b/tests/compiler/dart2js/cps_ir/expected/operators2_2.js
deleted file mode 100644
index 7858649..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_2.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Expectation for test:
-// // Method to test: function(foo)
-// foo(a) => ~a;
-// main() {
-// print(foo.toString());
-// print(foo(1));
-// print(foo(10));
-// }
-
-function(a) {
- return ~a >>> 0;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_3.js b/tests/compiler/dart2js/cps_ir/expected/operators2_3.js
deleted file mode 100644
index 0ec8440..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_3.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// Expectation for test:
-// // Method to test: function(foo)
-// import 'package:expect/expect.dart';
-//
-// @NoInline() foo(a) => a % 13;
-//
-// main() {
-// print(foo(5));
-// print(foo(-100));
-// }
-
-function(a) {
- return C.JSInt_methods.$mod(a, 13);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_4.js b/tests/compiler/dart2js/cps_ir/expected/operators2_4.js
deleted file mode 100644
index 4f5c0f0..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_4.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Expectation for test:
-// foo(a) => a % 13;
-// main() {
-// print(foo(5));
-// print(foo(100));
-// }
-
-function() {
- P.print(5 % 13);
- P.print(100 % 13);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_5.js b/tests/compiler/dart2js/cps_ir/expected/operators2_5.js
deleted file mode 100644
index a07d368..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_5.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Expectation for test:
-// foo(a) => a.remainder(13);
-// main() {
-// print(foo(5));
-// print(foo(-100));
-// }
-
-function() {
- P.print(5 % 13);
- P.print(-100 % 13);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_6.js b/tests/compiler/dart2js/cps_ir/expected/operators2_6.js
deleted file mode 100644
index d9cfe87..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_6.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// Expectation for test:
-// // Method to test: function(foo)
-// import 'package:expect/expect.dart';
-//
-// @NoInline() foo(a) => a ~/ 13;
-//
-// main() {
-// print(foo(5));
-// print(foo(-100));
-// }
-
-function(a) {
- return C.JSInt_methods.$tdiv(a, 13);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_7.js b/tests/compiler/dart2js/cps_ir/expected/operators2_7.js
deleted file mode 100644
index 403b831..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_7.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Expectation for test:
-// // Method to test: function(foo)
-// import 'package:expect/expect.dart';
-//
-// @NoInline() foo(a) => a ~/ 13;
-//
-// main() {
-// print(foo.toString());
-// print(foo(5));
-// print(foo(100));
-// }
-
-function(a) {
- return a / 13 | 0;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_8.js b/tests/compiler/dart2js/cps_ir/expected/operators2_8.js
deleted file mode 100644
index b322ba0..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_8.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// Expectation for test:
-// // Method to test: function(foo)
-// import 'package:expect/expect.dart';
-//
-// @NoInline() foo(a) => a ~/ 13;
-//
-// main() {
-// print(foo(5));
-// print(foo(8000000000));
-// }
-
-function(a) {
- return C.JSInt_methods.$tdiv(a, 13);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_1.js b/tests/compiler/dart2js/cps_ir/expected/operators_1.js
deleted file mode 100644
index dd0ddca..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators_1.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// Expectation for test:
-// main() { return true ? 42 : 'foo'; }
-
-function() {
- return 42;
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_2.js b/tests/compiler/dart2js/cps_ir/expected/operators_2.js
deleted file mode 100644
index 4b6236b..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators_2.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// var x = 1;
-// foo() => ++x > 10;
-// main() {
-// print(foo() ? "hello world" : "bad bad");
-// }
-
-function() {
- var v0 = $.x + 1;
- $.x = v0;
- v0 = v0 > 10 ? "hello world" : "bad bad";
- if (typeof dartPrint == "function")
- dartPrint(v0);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(v0);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(v0);
- print(v0);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_3.js b/tests/compiler/dart2js/cps_ir/expected/operators_3.js
deleted file mode 100644
index 525b95f..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators_3.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// var x = 1;
-// get foo => ++x > 10;
-// main() {
-// print(foo ? "hello world" : "bad bad");
-// }
-
-function() {
- var v0 = $.x + 1;
- $.x = v0;
- v0 = v0 > 10 ? "hello world" : "bad bad";
- if (typeof dartPrint == "function")
- dartPrint(v0);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(v0);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(v0);
- print(v0);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_4.js b/tests/compiler/dart2js/cps_ir/expected/operators_4.js
deleted file mode 100644
index 65acae6..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators_4.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Expectation for test:
-// var x = 1;
-// get foo => ++x > 10;
-// main() { print(foo && foo); }
-
-function() {
- var v0 = $.x + 1, line;
- $.x = v0;
- if (v0 > 10) {
- $.x = v0 = $.x + 1;
- v0 = v0 > 10;
- } else
- v0 = false;
- line = H.S(v0);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_5.js b/tests/compiler/dart2js/cps_ir/expected/operators_5.js
deleted file mode 100644
index df02418..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators_5.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Expectation for test:
-// var x = 1;
-// get foo => ++x > 10;
-// main() { print(foo || foo); }
-
-function() {
- var v0 = $.x + 1, line;
- $.x = v0;
- if (v0 > 10)
- v0 = true;
- else {
- $.x = v0 = $.x + 1;
- v0 = v0 > 10;
- }
- line = H.S(v0);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_6.js b/tests/compiler/dart2js/cps_ir/expected/operators_6.js
deleted file mode 100644
index 10e71da..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators_6.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// Expectation for test:
-// get foo => foo;
-// main() { print(foo || foo); }
-
-function() {
- V.foo();
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_7.js b/tests/compiler/dart2js/cps_ir/expected/operators_7.js
deleted file mode 100644
index 9b278bf..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators_7.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Expectation for test:
-// class Foo {
-// operator[]=(index, value) {
-// print(value);
-// }
-// }
-// main() {
-// var foo = new Foo();
-// foo[5] = 6;
-// }
-
-function() {
- V.Foo$();
- if (typeof dartPrint == "function")
- dartPrint("6");
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log("6");
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String("6");
- print("6");
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_8.js b/tests/compiler/dart2js/cps_ir/expected/operators_8.js
deleted file mode 100644
index 908c5f3..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/operators_8.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// main() {
-// var list = [1, 2, 3];
-// list[1] = 6;
-// print(list);
-// }
-
-function() {
- var list = [1, 2, 3], line;
- list[1] = 6;
- line = H.S(list);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/optimize_indexers.js b/tests/compiler/dart2js/cps_ir/expected/optimize_indexers.js
deleted file mode 100644
index 1b8c351..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/optimize_indexers.js
+++ /dev/null
@@ -1,43 +0,0 @@
-// Expectation for test:
-// // Method to test: function(test)
-// import 'package:expect/expect.dart';
-//
-// // This example illustrates a case we wish to do better in terms of inlining and
-// // code generation.
-// //
-// // Naively this function would be compiled without inlining Wrapper.[],
-// // JSArray.[] and Wrapper.[]= because:
-// // JSArray.[] is too big (14 nodes)
-// // Wrapper.[] is too big if we force inlining of JSArray (15 nodes)
-// // Wrapper.[]= is even bigger (46 nodes)
-// //
-// // We now do specialization of [] and []= by adding guards and injecting builtin
-// // operators. This made it possible to inline []. We still don't see []= inlined
-// // yet, that might require that we improve the inlining counting heuristics a
-// // bit.
-// @NoInline()
-// test(data, x) {
-// data[x + 1] = data[x];
-// }
-//
-// main() {
-// var wrapper = new Wrapper();
-// wrapper[33] = wrapper[1]; // make Wrapper.[]= and [] used more than once.
-// print(test(new Wrapper(), int.parse('2')));
-// }
-//
-// class Wrapper {
-// final List arr = <bool>[true, false, false, true];
-// operator[](int i) => this.arr[i];
-// operator[]=(int i, v) {
-// if (i > arr.length - 1) arr.length = i + 1;
-// return arr[i] = v;
-// }
-// }
-
-function(data, x) {
- var v0 = J.$add$ns(x, 1), v1 = data.arr;
- if (x >>> 0 !== x || x >= v1.length)
- return H.ioore(v1, x);
- data.$indexSet(0, v0, v1[x]);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/redundant_condition.js b/tests/compiler/dart2js/cps_ir/expected/redundant_condition.js
deleted file mode 100644
index 211aec6..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/redundant_condition.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// Expectation for test:
-// // This test illustrates an opportunity to remove redundant code by
-// // propagating inforamtion after inlining.
-// //
-// // The code below inlines `foo` twice, but we don't propagate that we already
-// // know from the first `foo` that `a` is an int, so the second check can be
-// // removed entirely.
-//
-// import 'package:expect/expect.dart';
-//
-// main() {
-// var a = nextNumber();
-// action(foo(a));
-// action(foo(a));
-// }
-//
-// foo(x) {
-// if (x is! int) throw "error 1";
-// return x + 5 % 100;
-// }
-//
-// @NoInline() @AssumeDynamic()
-// nextNumber() => int.parse('33');
-//
-// @NoInline()
-// action(v) => print(v);
-
-function() {
- var a = V.nextNumber();
- if (typeof a !== "number" || Math.floor(a) !== a)
- throw H.wrapException("error 1");
- a += 5;
- V.action(a);
- V.action(a);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/runtime_types_1.js b/tests/compiler/dart2js/cps_ir/expected/runtime_types_1.js
deleted file mode 100644
index 914008d..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/runtime_types_1.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Expectation for test:
-// class C<T> {
-// foo() => print(T);
-// }
-//
-// main() {
-// new C<int>().foo();
-// }
-
-function() {
- var line = H.S(H.createRuntimeType(H.runtimeTypeToString(H.getTypeArgumentByIndex(V.C$(P.$int), 0))));
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/runtime_types_2.js b/tests/compiler/dart2js/cps_ir/expected/runtime_types_2.js
deleted file mode 100644
index d22895f..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/runtime_types_2.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Expectation for test:
-// class C<T, U> {
-// foo() => print(U);
-// }
-//
-// class D extends C<int, double> {}
-//
-// main() {
-// new D().foo();
-// }
-
-function() {
- var line = H.S(H.createRuntimeType(H.runtimeTypeToString(H.getRuntimeTypeArgument(V.D$(), "C", 1))));
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/runtime_types_3.js b/tests/compiler/dart2js/cps_ir/expected/runtime_types_3.js
deleted file mode 100644
index 435bb62..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/runtime_types_3.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Expectation for test:
-// class C<T> {
-// foo() => new D<C<T>>();
-// }
-// class D<T> {
-// bar() => T;
-// }
-// main() {
-// print(new C<int>().foo().bar());
-// }
-
-function() {
- var line = H.S(H.createRuntimeType(H.runtimeTypeToString(H.getTypeArgumentByIndex(V.D$([V.C, H.getTypeArgumentByIndex(V.C$(P.$int), 0)]), 0))));
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/runtime_types_4.js b/tests/compiler/dart2js/cps_ir/expected/runtime_types_4.js
deleted file mode 100644
index 823dbe9..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/runtime_types_4.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Expectation for test:
-// // Method to test: generative_constructor(C#)
-// class C<X, Y, Z> {
-// foo() => 'C<$X $Y, $Z>';
-// }
-// main() {
-// new C<C, int, String>().foo();
-// }
-
-function($X, $Y, $Z) {
- return H.setRuntimeTypeInfo(new V.C(), [$X, $Y, $Z]);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/supercall_1.js b/tests/compiler/dart2js/cps_ir/expected/supercall_1.js
deleted file mode 100644
index cc601dd..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/supercall_1.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Expectation for test:
-// class Base {
-// m(x) {
-// try { print(x+1); } finally { }
-// }
-// }
-// class Sub extends Base {
-// m(x) => super.m(x+10);
-// }
-// main() {
-// new Sub().m(100);
-// }
-
-function() {
- var v0 = V.Sub$();
- V.Base.prototype.m$1.call(v0, 110);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/supercall_2.js b/tests/compiler/dart2js/cps_ir/expected/supercall_2.js
deleted file mode 100644
index 27f6c2b..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/supercall_2.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// Expectation for test:
-// // TODO(sigmund): change this to check method "function(Sub#+)" once we provide
-// // a way to disable inlining of Sub#+, which is compiled to something like:
-// // function(x) {
-// // var v0, v1, v2;
-// // v0 = 1;
-// // v1 = J.getInterceptor$ns(x).$add(x, v0);
-// // v2 = this;
-// // return V.Base.prototype.$add.call(null, v2, v1);
-// // }
-//
-// class Base {
-// m(x) {
-// print(x+1000);
-// }
-// operator+(x) => m(x+10);
-// }
-// class Sub extends Base {
-// m(x) => super.m(x+100);
-// operator+(x) => super + (x+1);
-// }
-// main() {
-// new Sub() + 10000;
-// }
-
-function() {
- var v0 = V.Sub$();
- V.Base.prototype.$add.call(v0, v0, 10001);
-}
diff --git a/tests/compiler/dart2js/cps_ir/expected/supercall_3.js b/tests/compiler/dart2js/cps_ir/expected/supercall_3.js
deleted file mode 100644
index f45afaf..0000000
--- a/tests/compiler/dart2js/cps_ir/expected/supercall_3.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Expectation for test:
-// class Base {
-// var field = 123;
-// }
-// class Sub extends Base {
-// m(x) => x + super.field;
-// }
-// main() {
-// print(new Sub().m(10));
-// }
-
-function() {
- var line = H.S(10 + V.Sub$().field);
- if (typeof dartPrint == "function")
- dartPrint(line);
- else if (typeof console == "object" && typeof console.log != "undefined")
- console.log(line);
- else if (!(typeof window == "object")) {
- if (!(typeof print == "function"))
- throw "Unable to print message: " + String(line);
- print(line);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/gvn_1_test.dart b/tests/compiler/dart2js/cps_ir/gvn_1_test.dart
deleted file mode 100644
index e341e5d..0000000
--- a/tests/compiler/dart2js/cps_ir/gvn_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.gvn_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("gvn_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_1.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_1.dart
deleted file mode 100644
index e807927..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_1.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x - y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_10.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_10.dart
deleted file mode 100644
index 85143eb..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_10.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x > y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_11.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_11.dart
deleted file mode 100644
index eca7811..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_11.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x < y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_12.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_12.dart
deleted file mode 100644
index 7ad1e67..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_12.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x >= y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_13.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_13.dart
deleted file mode 100644
index 6083767..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_13.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x <= y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_14.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_14.dart
deleted file mode 100644
index 09c8e76..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_14.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x.remainder(y));
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_15.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_15.dart
deleted file mode 100644
index 5724188..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_15.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- var z = int.parse('1235');
- print(x is num);
- print(y is num);
- print(z is num);
- print(x.clamp(y, z));
- print(x is num);
- print(y is num);
- print(z is num);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_16.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_16.dart
deleted file mode 100644
index f7655f4..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_16.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x + y);
- print(x is num);
- print(y is num);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_17.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_17.dart
deleted file mode 100644
index 20dd689..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_17.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x * y);
- print(x is num);
- print(y is num);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_18.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_18.dart
deleted file mode 100644
index aae68b8..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_18.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x.compareTo(y));
- print(x is num);
- print(y is num);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_19.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_19.dart
deleted file mode 100644
index a61936e..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_19.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x / 2);
- print(x is num);
- print(y is num);
- print(x + y);
- print(y is num);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_2.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_2.dart
deleted file mode 100644
index 2021ca9..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_2.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x / y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_20.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_20.dart
deleted file mode 100644
index d8a5b4d..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_20.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x / 2);
- print(x is num);
- print(y is num);
- print(x * y);
- print(y is num);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_21.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_21.dart
deleted file mode 100644
index ae28a0e..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_21.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x / 2);
- print(x is num);
- print(y is num);
- print(x.compareTo(y));
- print(y is num);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_22.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_22.dart
deleted file mode 100644
index 988edd7..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_22.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is int);
- print(y is int);
- print(x.toSigned(y));
- print(x is int);
- print(y is int);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_23.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_23.dart
deleted file mode 100644
index c727aa8..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_23.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is int);
- print(y is int);
- print(x.toUnsigned(y));
- print(x is int);
- print(y is int);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_24.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_24.dart
deleted file mode 100644
index 1b2aef6..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_24.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is int);
- print(y is int);
- print(x.modInverse(y));
- print(x is int);
- print(y is int);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_25.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_25.dart
deleted file mode 100644
index 740bb92..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_25.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is int);
- print(y is int);
- print(x.gcd(y));
- print(x is int);
- print(y is int);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_26.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_26.dart
deleted file mode 100644
index dfdd56b..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_26.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- var z = int.parse('1235');
- print(x is int);
- print(y is int);
- print(z is int);
- print(x.modPow(y, z));
- print(x is int);
- print(y is int);
- print(z is int);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_27.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_27.dart
deleted file mode 100644
index b53d2df..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_27.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('3');
- var y = int.parse('a', onError: (e) => 'abcde');
- print(x is int);
- print(y is String);
- print(y.codeUnitAt(x));
- print(x is int);
- print(y is String);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_28.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_28.dart
deleted file mode 100644
index cbea9617..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_28.dart
+++ /dev/null
@@ -1,20 +0,0 @@
-import 'dart:math';
-main() {
- var x = int.parse('3');
- var y = int.parse('1234');
- var z = int.parse('1236');
- var w = int.parse('2');
- print(x is num);
- print(sin(x));
- print(x is num);
-
- print(y is num);
- print(log(y));
- print(y is num);
-
- print(z is num);
- print(w is num);
- print(pow(z, w));
- print(z is num);
- print(w is num);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_3.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_3.dart
deleted file mode 100644
index 8353ddf..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_3.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x % y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_4.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_4.dart
deleted file mode 100644
index 958363a..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_4.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x ~/ y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_5.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_5.dart
deleted file mode 100644
index c46235b..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_5.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x >> y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_6.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_6.dart
deleted file mode 100644
index 461da84..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_6.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x << y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_7.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_7.dart
deleted file mode 100644
index c5f7d72..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_7.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x & y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_8.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_8.dart
deleted file mode 100644
index 9aef9e2..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_8.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x | y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_9.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_9.dart
deleted file mode 100644
index 22266c7..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_9.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x ^ y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_1.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_1.dart
deleted file mode 100644
index e807927..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_1.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x - y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_10.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_10.dart
deleted file mode 100644
index eca7811..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_10.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x < y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_11.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_11.dart
deleted file mode 100644
index 85143eb..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_11.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x > y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_12.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_12.dart
deleted file mode 100644
index 6083767..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_12.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x <= y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_13.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_13.dart
deleted file mode 100644
index 7ad1e67..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_13.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x >= y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_14.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_14.dart
deleted file mode 100644
index 09c8e76..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_14.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x.remainder(y));
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_15.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_15.dart
deleted file mode 100644
index 227e62e..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_15.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- var z = int.parse('1236');
- print(x is num);
- print(y is num);
- print(z is num);
- print(x.clamp(y, z));
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
- print(z is num);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_16.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_16.dart
deleted file mode 100644
index c757d08..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_16.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x + y);
- print(x is num);
- print(y is num); // will stay as is-num because String could be a target of +
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_17.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_17.dart
deleted file mode 100644
index 9dd57c3..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_17.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x * y);
- print(x is num);
- print(y is num); // will stay as is-num because String could be a target of *
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_2.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_2.dart
deleted file mode 100644
index 2021ca9..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_2.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x / y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_3.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_3.dart
deleted file mode 100644
index 8353ddf..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_3.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x % y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_4.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_4.dart
deleted file mode 100644
index 958363a..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_4.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x ~/ y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_5.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_5.dart
deleted file mode 100644
index c46235b..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_5.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x >> y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_6.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_6.dart
deleted file mode 100644
index 461da84..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_6.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x << y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_7.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_7.dart
deleted file mode 100644
index c5f7d72..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_7.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x & y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_8.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_8.dart
deleted file mode 100644
index 9aef9e2..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_8.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x | y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_9.dart b/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_9.dart
deleted file mode 100644
index 22266c7..0000000
--- a/tests/compiler/dart2js/cps_ir/input/argument_refinement_num_9.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main() {
- var x = int.parse('1233');
- var y = int.parse('1234');
- print(x is num);
- print(y is num);
- print(x ^ y);
- print(x is num);
- print(y is num); // will be compiled to `true` if we know the type of `y`.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_1.dart b/tests/compiler/dart2js/cps_ir/input/basic_1.dart
deleted file mode 100644
index ee77081..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_1.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-main() {
- var e = 1;
- var l = [1, 2, 3];
- var m = {'s': 1};
-
- print('(' ')');
- print('(${true})');
- print('(${1})');
- print('(${[1, 2, 3]})');
- print('(${{'s': 1}})');
- print('($e)');
- print('($l)');
- print('($m)');
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_10.dart b/tests/compiler/dart2js/cps_ir/input/basic_10.dart
deleted file mode 100644
index e5a56a0..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_10.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-main() {
- print(new DateTime.now().isBefore(new DateTime.now()));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_11.dart b/tests/compiler/dart2js/cps_ir/input/basic_11.dart
deleted file mode 100644
index 34c8802..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_11.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-foo() { print(42); }
-main() { foo(); }
-
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_12.dart b/tests/compiler/dart2js/cps_ir/input/basic_12.dart
deleted file mode 100644
index d48fb05..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_12.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-var foo = 42;
-main() { print(foo); }
-
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_13.dart b/tests/compiler/dart2js/cps_ir/input/basic_13.dart
deleted file mode 100644
index 3582183..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_13.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-get foo { print(42); }
-main() { foo; }
-
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_14.dart b/tests/compiler/dart2js/cps_ir/input/basic_14.dart
deleted file mode 100644
index f39e531..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_14.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-var foo = 0;
-main() { print(foo = 42); }
-
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_15.dart b/tests/compiler/dart2js/cps_ir/input/basic_15.dart
deleted file mode 100644
index 5ecc7ac..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_15.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-set foo(x) { print(x); }
-main() { foo = 42; }
-
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_16.dart b/tests/compiler/dart2js/cps_ir/input/basic_16.dart
deleted file mode 100644
index 749ce68..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_16.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-foo() { print('X'); }
-main() {
- assert(true);
- assert(false);
- assert(foo());
- print('Done');
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_2.dart b/tests/compiler/dart2js/cps_ir/input/basic_2.dart
deleted file mode 100644
index 6305610..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_2.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-foo(a, [b = "b"]) { print(b); return b; }
-bar(a, {b: "b", c: "c"}) { print(c); return c; }
-main() {
- foo(0);
- foo(1, 2);
- bar(3);
- bar(4, b: 5);
- bar(6, c: 7);
- bar(8, b: 9, c: 10);
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_3.dart b/tests/compiler/dart2js/cps_ir/input/basic_3.dart
deleted file mode 100644
index 95ffd22..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_3.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-foo(a) {
- print(a);
- return a;
-}
-main() {
- var a = 10;
- var b = 1;
- var t;
- t = a;
- a = b;
- b = t;
- print(a);
- print(b);
- print(b);
- print(foo(a));
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_4.dart b/tests/compiler/dart2js/cps_ir/input/basic_4.dart
deleted file mode 100644
index 1e74c32..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_4.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-foo() { print(42); return 42; }
-main() { return foo(); }
-
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_5.dart b/tests/compiler/dart2js/cps_ir/input/basic_5.dart
deleted file mode 100644
index bae895a..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_5.dart
+++ /dev/null
@@ -1 +0,0 @@
-main() {}
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_6.dart b/tests/compiler/dart2js/cps_ir/input/basic_6.dart
deleted file mode 100644
index f55f628..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_6.dart
+++ /dev/null
@@ -1 +0,0 @@
-main() { return 42; }
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_7.dart b/tests/compiler/dart2js/cps_ir/input/basic_7.dart
deleted file mode 100644
index 98b304d..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_7.dart
+++ /dev/null
@@ -1 +0,0 @@
-main() { return; }
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_8.dart b/tests/compiler/dart2js/cps_ir/input/basic_8.dart
deleted file mode 100644
index e6ebb66..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_8.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-main() {
- print(new Set());
- print(new Set.from([1, 2, 3]));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/basic_9.dart b/tests/compiler/dart2js/cps_ir/input/basic_9.dart
deleted file mode 100644
index 15a7643..0000000
--- a/tests/compiler/dart2js/cps_ir/input/basic_9.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-class C {}
-main() {
- print(new C());
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_1.dart b/tests/compiler/dart2js/cps_ir/input/closures_1.dart
deleted file mode 100644
index f47a0a0..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_1.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-main(x) {
- a() {
- return x;
- }
- x = x + '1';
- print(a());
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_10.dart b/tests/compiler/dart2js/cps_ir/input/closures_10.dart
deleted file mode 100644
index 542d012..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_10.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-class A {
- a() => 1;
- b() => () => a();
-}
-main() {
- print(new A().b()());
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_11.dart b/tests/compiler/dart2js/cps_ir/input/closures_11.dart
deleted file mode 100644
index cd8e049..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_11.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-staticMethod(x) { print(x); return x; }
-main(x) {
- var tearOff = staticMethod;
- print(tearOff(123));
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_12.dart b/tests/compiler/dart2js/cps_ir/input/closures_12.dart
deleted file mode 100644
index 9e787fa..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_12.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-class Foo {
- instanceMethod(x) => x;
-}
-main(x) {
- var tearOff = new Foo().instanceMethod;
- print(tearOff(123));
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_13.dart b/tests/compiler/dart2js/cps_ir/input/closures_13.dart
deleted file mode 100644
index 9994ca3..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_13.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-class Foo {
- instanceMethod(x) => x;
-}
-main(x) {
- var tearOff = new Foo().instanceMethod;
- print(tearOff(123));
- print(tearOff(321));
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_14.dart b/tests/compiler/dart2js/cps_ir/input/closures_14.dart
deleted file mode 100644
index 5ef8e6c..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_14.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-class Foo {
- get getter {
- print('getter');
- return (x) => x;
- }
-}
-main(x) {
- var notTearOff = new Foo().getter;
- print(notTearOff(123));
- print(notTearOff(321));
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_15.dart b/tests/compiler/dart2js/cps_ir/input/closures_15.dart
deleted file mode 100644
index 55e1263..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_15.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-class Foo {
- get getter {
- print('getter');
- return (x) => x;
- }
-}
-main(x) {
- var notTearOff = new Foo().getter;
- print(notTearOff(123));
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_16.dart b/tests/compiler/dart2js/cps_ir/input/closures_16.dart
deleted file mode 100644
index 0d57270..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_16.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-class Foo {
- get getter {
- print('getter');
- return (x) { try { return x; } finally { } }; // Inhibit inlining.
- }
-}
-main(x) {
- // Getter may or may not be inlined.
- var notTearOff = new Foo().getter;
- // Closure is not inlined.
- print(notTearOff(123));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_2.dart b/tests/compiler/dart2js/cps_ir/input/closures_2.dart
deleted file mode 100644
index 7c8ad36..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_2.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-main(x) {
- a() {
- return x;
- }
- x = x + '1';
- print(a());
- return a;
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_3.dart b/tests/compiler/dart2js/cps_ir/input/closures_3.dart
deleted file mode 100644
index 6e4f5d9..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_3.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-main(x) {
- a() {
- return x;
- }
- print(a());
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_4.dart b/tests/compiler/dart2js/cps_ir/input/closures_4.dart
deleted file mode 100644
index e6be22c..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_4.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-main(x) {
- a() {
- return x;
- }
- print(a());
- return a;
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_5.dart b/tests/compiler/dart2js/cps_ir/input/closures_5.dart
deleted file mode 100644
index 3e35ec0..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_5.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-main() {
- var x = 122;
- var a = () => x;
- x = x + 1;
- print(a());
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_6.dart b/tests/compiler/dart2js/cps_ir/input/closures_6.dart
deleted file mode 100644
index e9ff65b..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_6.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-main() {
- var x = 122;
- var a = () => x;
- x = x + 1;
- print(a());
- return a;
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_7.dart b/tests/compiler/dart2js/cps_ir/input/closures_7.dart
deleted file mode 100644
index 05087ca..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_7.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-main() {
- var x = 122;
- var a = () {
- var y = x;
- return () => y;
- };
- x = x + 1;
- print(a()());
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_8.dart b/tests/compiler/dart2js/cps_ir/input/closures_8.dart
deleted file mode 100644
index 2b6e8c5..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_8.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-main() {
- var x = 122;
- var a = () {
- var y = x;
- return () => y;
- };
- x = x + 1;
- print(a()());
- return a;
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_9.dart b/tests/compiler/dart2js/cps_ir/input/closures_9.dart
deleted file mode 100644
index 185576a..0000000
--- a/tests/compiler/dart2js/cps_ir/input/closures_9.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-main() {
- var a;
- for (var i=0; i<10; i++) {
- a = () => i;
- }
- print(a());
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/codeUnitAt_1.dart b/tests/compiler/dart2js/cps_ir/input/codeUnitAt_1.dart
deleted file mode 100644
index c39bc74..0000000
--- a/tests/compiler/dart2js/cps_ir/input/codeUnitAt_1.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-// Constant folding
-main() {
- print('A'.codeUnitAt(0));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/codeUnitAt_2.dart b/tests/compiler/dart2js/cps_ir/input/codeUnitAt_2.dart
deleted file mode 100644
index a26c359..0000000
--- a/tests/compiler/dart2js/cps_ir/input/codeUnitAt_2.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-// Bounds checking
-foo(s) {
- var sum = 0;
- for (int i = 0; i < s.length; i++) sum += s.codeUnitAt(i);
- return sum;
-}
-main() {
- print(foo('ABC'));
- print(foo('Hello'));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_1.dart b/tests/compiler/dart2js/cps_ir/input/constructor_1.dart
deleted file mode 100644
index 1cc265a..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_1.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-class Base {
- var x;
- Base(this.x);
-}
-class Sub extends Base {
- var y;
- Sub(x, this.y) : super(x);
-}
-main() {
- print(new Sub(1, 2).x);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_10.dart b/tests/compiler/dart2js/cps_ir/input/constructor_10.dart
deleted file mode 100644
index 1e3dddc..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_10.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-// Method to test: generative_constructor(C#)
-class C<T> {
- var x;
- C() : x = new D<T>();
-}
-class D<T> {
- foo() => T;
-}
-main() {
- print(new C<int>().x.foo());
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_11.dart b/tests/compiler/dart2js/cps_ir/input/constructor_11.dart
deleted file mode 100644
index c4ee04c..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_11.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-class A {
- var x;
- A() : this.b(1);
- A.b(this.x);
-}
-main() {
- print(new A().x);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_12.dart b/tests/compiler/dart2js/cps_ir/input/constructor_12.dart
deleted file mode 100644
index efafb99..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_12.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-class Foo {
- factory Foo.make(x) {
- print('Foo');
- return new Foo.create(x);
- }
- var x;
- Foo.create(this.x);
-}
-main() {
- print(new Foo.make(5));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_13.dart b/tests/compiler/dart2js/cps_ir/input/constructor_13.dart
deleted file mode 100644
index dcba070..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_13.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-class Foo {
- factory Foo.make(x) = Foo.create;
- var x;
- Foo.create(this.x);
-}
-main() {
- print(new Foo.make(5));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_14.dart b/tests/compiler/dart2js/cps_ir/input/constructor_14.dart
deleted file mode 100644
index b22bbcb..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_14.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-class A {
- factory A(x) = B<int>;
- get typevar;
-}
-class B<T> implements A {
- var x;
- B(this.x);
-
- get typevar => T;
-}
-main() {
- new A(5).typevar;
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_15.dart b/tests/compiler/dart2js/cps_ir/input/constructor_15.dart
deleted file mode 100644
index 898b04f..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_15.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Method to test: generative_constructor(A#)
-class A {
- var x, y, z;
- A(x, y) {
- this.x = x;
- this.y = y;
- this.z = this.x / 2;
- }
-}
-
-main() {
- print(new A(123, 'sdf').y);
- try {} finally {} // Do not inline into main.
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_2.dart b/tests/compiler/dart2js/cps_ir/input/constructor_2.dart
deleted file mode 100644
index 23ac512..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_2.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-class Base {
- var x;
- Base(this.x);
-}
-class Sub extends Base {
- var y;
- Sub(x, this.y) : super(x) {
- print(x);
- }
-}
-main() {
- print(new Sub(1, 2).x);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_3.dart b/tests/compiler/dart2js/cps_ir/input/constructor_3.dart
deleted file mode 100644
index 7a532a3..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_3.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-class Base0 {
- Base0() {
- print('Base0');
- }
-}
-class Base extends Base0 {
- var x;
- Base(this.x);
-}
-class Sub extends Base {
- var y;
- Sub(x, this.y) : super(x) {
- print(x);
- }
-}
-main() {
- print(new Sub(1, 2).x);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_4.dart b/tests/compiler/dart2js/cps_ir/input/constructor_4.dart
deleted file mode 100644
index 5f14854..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_4.dart
+++ /dev/null
@@ -1,20 +0,0 @@
-class Base0 {
- Base0() {
- print('Base0');
- }
-}
-class Base extends Base0 {
- var x;
- Base(x1) : x = (() => ++x1) {
- print(x1); // use boxed x1
- }
-}
-class Sub extends Base {
- var y;
- Sub(x, this.y) : super(x) {
- print(x);
- }
-}
-main() {
- print(new Sub(1, 2).x);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_5.dart b/tests/compiler/dart2js/cps_ir/input/constructor_5.dart
deleted file mode 100644
index f615668..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_5.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-foo(x) {
- print(x);
-}
-class Base {
- var x1 = foo('x1');
- var x2;
- var x3 = foo('x3');
- Base() : x2 = foo('x2');
-}
-class Sub extends Base {
- var y1 = foo('y1');
- var y2;
- var y3;
- Sub() : y2 = foo('y2'), super(), y3 = foo('y3');
-}
-main() {
- new Sub();
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_6.dart b/tests/compiler/dart2js/cps_ir/input/constructor_6.dart
deleted file mode 100644
index f1c6b51..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_6.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-class Bar {
- Bar(x, {y, z: 'z', w: '_', q}) {
- print(x);
- print(y);
- print(z);
- print(w);
- print(q);
- }
-}
-class Foo extends Bar {
- Foo() : super('x', y: 'y', w: 'w');
-}
-main() {
- new Foo();
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_7.dart b/tests/compiler/dart2js/cps_ir/input/constructor_7.dart
deleted file mode 100644
index 32af53c..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_7.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-class C<T> {
- foo() => T;
-}
-main() {
- print(new C<int>().foo());
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_8.dart b/tests/compiler/dart2js/cps_ir/input/constructor_8.dart
deleted file mode 100644
index 3e72ab1..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_8.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-class C<T> {
- foo() => C;
-}
-main() {
- print(new C<int>().foo());
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_9.dart b/tests/compiler/dart2js/cps_ir/input/constructor_9.dart
deleted file mode 100644
index fe8dfbf..0000000
--- a/tests/compiler/dart2js/cps_ir/input/constructor_9.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-// Method to test: generative_constructor(C#)
-class C<T> {
- C() { print(T); }
- foo() => print(T);
-}
-main() {
- new C<int>();
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_1.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_1.dart
deleted file mode 100644
index 72e7e7c..0000000
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_1.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-main() {
- while (true);
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart
deleted file mode 100644
index a7baf52..0000000
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-foo(a) { try { print(a); } finally { return a; } }
-
-main() {
- while (true) {
- l: while (true) {
- while (foo(true)) {
- if (foo(false)) break l;
- }
- print(1);
- }
- print(2);
- }
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart
deleted file mode 100644
index 8335da4..0000000
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-foo(a) { try { print(a); } finally { return a; } }
-
-main() {
- for (int i = 0; foo(true); i = foo(i)) {
- print(1);
- if (foo(false)) break;
- }
- print(2);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart
deleted file mode 100644
index dd9fa9c..0000000
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-foo(a) { try { print(a); } finally { return a; } }
-
-main() {
- foo(false);
- if (foo(true)) {
- print(1);
- } else {
- print(2);
- }
- print(3);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart
deleted file mode 100644
index ee75818..0000000
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-foo(a) { try { print(a); } finally { return a; } }
-
-main() {
- foo(false);
- if (foo(true)) {
- print(1);
- print(1);
- } else {
- print(2);
- print(2);
- }
- print(3);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_6.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_6.dart
deleted file mode 100644
index 58550fe..0000000
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_6.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-main() {
- if (1) {
- print('bad');
- } else {
- print('good');
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_7.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_7.dart
deleted file mode 100644
index 66709ff..0000000
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_7.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-foo() { print('2'); return 2; }
-main() {
- if (foo()) {
- print('bad');
- } else {
- print('good');
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_8.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_8.dart
deleted file mode 100644
index 62c6fed..0000000
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_8.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-main() {
- var list = [1,2,3,4,5,6];
- for (var x in list) {
- print(x);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_9.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_9.dart
deleted file mode 100644
index 7e59e5a..0000000
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_9.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-main() {
- var xs = ['x', 'y', 'z'], ys = ['A', 'B', 'C'];
- var xit = xs.iterator, yit = ys.iterator;
- while (xit.moveNext() && yit.moveNext()) {
- print(xit.current);
- print(yit.current);
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/gvn_1.dart b/tests/compiler/dart2js/cps_ir/input/gvn_1.dart
deleted file mode 100644
index 4953cb9..0000000
--- a/tests/compiler/dart2js/cps_ir/input/gvn_1.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-foo(x, list) {
- var sum = 0;
- for (int k = 0; k < 10; k++) {
- // Everything can be hoisted out up to the index access which is
- // blocked by the bounds check.
- var a = x.left.left;
- var b = x.left.right;
- var c = x.right.left;
- var d = x.right.right;
- var i = a.value + c.value;
- var j = b.value + d.value;
- var z = list[i * j] + i;
- sum += z;
- }
- return sum;
-}
-// Use a different class for each level in the tree, so type inference
-// is not confused.
-class Root {
- Branch left, right;
- Root(this.left, this.right);
-}
-class Branch {
- Leaf left, right;
- Branch(this.left, this.right);
-}
-class Leaf {
- int value;
- Leaf(this.value);
-}
-main() {
- var x1 = new Leaf(1);
- var x2 = new Leaf(10);
- var x3 = new Leaf(20);
- var x4 = new Leaf(-10);
- var y1 = new Branch(x1, x2);
- var y2 = new Branch(x3, x4);
- var z = new Root(y1, y2);
- print(foo(z, [1,2,3,4,5,6,7,8,9,10]));
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/interceptors_1.dart b/tests/compiler/dart2js/cps_ir/input/interceptors_1.dart
deleted file mode 100644
index 6363521..0000000
--- a/tests/compiler/dart2js/cps_ir/input/interceptors_1.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-main() {
- var g = 1;
-
- var x = g + 3;
- print(x);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/interceptors_2.dart b/tests/compiler/dart2js/cps_ir/input/interceptors_2.dart
deleted file mode 100644
index 7853486..0000000
--- a/tests/compiler/dart2js/cps_ir/input/interceptors_2.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-main() {
- var l = ['hest', ['h', 'e', 's', 't']];
- print(l.length);
- for (int i = 0; i < l.length; i++) {
- var x = l[i];
- for (int j = 0; j < x.length; j++) {
- print(x[j]);
- }
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/literals_1.dart b/tests/compiler/dart2js/cps_ir/input/literals_1.dart
deleted file mode 100644
index a5d7294..0000000
--- a/tests/compiler/dart2js/cps_ir/input/literals_1.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-main() {
- print([]);
- print([1]);
- print([1, 2]);
- print([1, [1, 2]]);
- print({});
- print({1: 2});
- print({[1, 2]: [3, 4]});
-}
-
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_1.dart b/tests/compiler/dart2js/cps_ir/input/operators2_1.dart
deleted file mode 100644
index 38b8f4f..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators2_1.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-// Method to test: function(foo)
-foo(a, b) => ((a & 0xff0000) >> 1) & b;
-main() {
- print(foo.toString());
- print(foo(123, 234));
- print(foo(0, 2));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_2.dart b/tests/compiler/dart2js/cps_ir/input/operators2_2.dart
deleted file mode 100644
index f38e967..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators2_2.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-// Method to test: function(foo)
-foo(a) => ~a;
-main() {
- print(foo.toString());
- print(foo(1));
- print(foo(10));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_3.dart b/tests/compiler/dart2js/cps_ir/input/operators2_3.dart
deleted file mode 100644
index 2cd9a53..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators2_3.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Method to test: function(foo)
-import 'package:expect/expect.dart';
-
-@NoInline() foo(a) => a % 13;
-
-main() {
- print(foo(5));
- print(foo(-100));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_4.dart b/tests/compiler/dart2js/cps_ir/input/operators2_4.dart
deleted file mode 100644
index b9f5be2..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators2_4.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-foo(a) => a % 13;
-main() {
- print(foo(5));
- print(foo(100));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_5.dart b/tests/compiler/dart2js/cps_ir/input/operators2_5.dart
deleted file mode 100644
index 3ece837..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators2_5.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-foo(a) => a.remainder(13);
-main() {
- print(foo(5));
- print(foo(-100));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_6.dart b/tests/compiler/dart2js/cps_ir/input/operators2_6.dart
deleted file mode 100644
index 88bd137..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators2_6.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Method to test: function(foo)
-import 'package:expect/expect.dart';
-
-@NoInline() foo(a) => a ~/ 13;
-
-main() {
- print(foo(5));
- print(foo(-100));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_7.dart b/tests/compiler/dart2js/cps_ir/input/operators2_7.dart
deleted file mode 100644
index f8fe827..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators2_7.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-// Method to test: function(foo)
-import 'package:expect/expect.dart';
-
-@NoInline() foo(a) => a ~/ 13;
-
-main() {
- print(foo.toString());
- print(foo(5));
- print(foo(100));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_8.dart b/tests/compiler/dart2js/cps_ir/input/operators2_8.dart
deleted file mode 100644
index ec9b8b3..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators2_8.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Method to test: function(foo)
-import 'package:expect/expect.dart';
-
-@NoInline() foo(a) => a ~/ 13;
-
-main() {
- print(foo(5));
- print(foo(8000000000));
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators_1.dart b/tests/compiler/dart2js/cps_ir/input/operators_1.dart
deleted file mode 100644
index 52e587e..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators_1.dart
+++ /dev/null
@@ -1 +0,0 @@
-main() { return true ? 42 : 'foo'; }
diff --git a/tests/compiler/dart2js/cps_ir/input/operators_2.dart b/tests/compiler/dart2js/cps_ir/input/operators_2.dart
deleted file mode 100644
index c9049ed..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators_2.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-var x = 1;
-foo() => ++x > 10;
-main() {
- print(foo() ? "hello world" : "bad bad");
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators_3.dart b/tests/compiler/dart2js/cps_ir/input/operators_3.dart
deleted file mode 100644
index 42ceb0e..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators_3.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-var x = 1;
-get foo => ++x > 10;
-main() {
- print(foo ? "hello world" : "bad bad");
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators_4.dart b/tests/compiler/dart2js/cps_ir/input/operators_4.dart
deleted file mode 100644
index 3f07752..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators_4.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-var x = 1;
-get foo => ++x > 10;
-main() { print(foo && foo); }
-
diff --git a/tests/compiler/dart2js/cps_ir/input/operators_5.dart b/tests/compiler/dart2js/cps_ir/input/operators_5.dart
deleted file mode 100644
index 98756b6..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators_5.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-var x = 1;
-get foo => ++x > 10;
-main() { print(foo || foo); }
-
diff --git a/tests/compiler/dart2js/cps_ir/input/operators_6.dart b/tests/compiler/dart2js/cps_ir/input/operators_6.dart
deleted file mode 100644
index 36e7d9f..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators_6.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-get foo => foo;
-main() { print(foo || foo); }
-
diff --git a/tests/compiler/dart2js/cps_ir/input/operators_7.dart b/tests/compiler/dart2js/cps_ir/input/operators_7.dart
deleted file mode 100644
index 8838126..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators_7.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-class Foo {
- operator[]=(index, value) {
- print(value);
- }
-}
-main() {
- var foo = new Foo();
- foo[5] = 6;
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/operators_8.dart b/tests/compiler/dart2js/cps_ir/input/operators_8.dart
deleted file mode 100644
index c5b66d3..0000000
--- a/tests/compiler/dart2js/cps_ir/input/operators_8.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-main() {
- var list = [1, 2, 3];
- list[1] = 6;
- print(list);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/optimize_indexers.dart b/tests/compiler/dart2js/cps_ir/input/optimize_indexers.dart
deleted file mode 100644
index 8150653..0000000
--- a/tests/compiler/dart2js/cps_ir/input/optimize_indexers.dart
+++ /dev/null
@@ -1,35 +0,0 @@
-// Method to test: function(test)
-import 'package:expect/expect.dart';
-
-// This example illustrates a case we wish to do better in terms of inlining and
-// code generation.
-//
-// Naively this function would be compiled without inlining Wrapper.[],
-// JSArray.[] and Wrapper.[]= because:
-// JSArray.[] is too big (14 nodes)
-// Wrapper.[] is too big if we force inlining of JSArray (15 nodes)
-// Wrapper.[]= is even bigger (46 nodes)
-//
-// We now do specialization of [] and []= by adding guards and injecting builtin
-// operators. This made it possible to inline []. We still don't see []= inlined
-// yet, that might require that we improve the inlining counting heuristics a
-// bit.
-@NoInline()
-test(data, x) {
- data[x + 1] = data[x];
-}
-
-main() {
- var wrapper = new Wrapper();
- wrapper[33] = wrapper[1]; // make Wrapper.[]= and [] used more than once.
- print(test(new Wrapper(), int.parse('2')));
-}
-
-class Wrapper {
- final List arr = <bool>[true, false, false, true];
- operator[](int i) => this.arr[i];
- operator[]=(int i, v) {
- if (i > arr.length - 1) arr.length = i + 1;
- return arr[i] = v;
- }
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/redundant_condition.dart b/tests/compiler/dart2js/cps_ir/input/redundant_condition.dart
deleted file mode 100644
index 913dfc5..0000000
--- a/tests/compiler/dart2js/cps_ir/input/redundant_condition.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-// This test illustrates an opportunity to remove redundant code by
-// propagating inforamtion after inlining.
-//
-// The code below inlines `foo` twice, but we don't propagate that we already
-// know from the first `foo` that `a` is an int, so the second check can be
-// removed entirely.
-
-import 'package:expect/expect.dart';
-
-main() {
- var a = nextNumber();
- action(foo(a));
- action(foo(a));
-}
-
-foo(x) {
- if (x is! int) throw "error 1";
- return x + 5 % 100;
-}
-
-@NoInline() @AssumeDynamic()
-nextNumber() => int.parse('33');
-
-@NoInline()
-action(v) => print(v);
diff --git a/tests/compiler/dart2js/cps_ir/input/runtime_types_1.dart b/tests/compiler/dart2js/cps_ir/input/runtime_types_1.dart
deleted file mode 100644
index f67e4d3a..0000000
--- a/tests/compiler/dart2js/cps_ir/input/runtime_types_1.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-class C<T> {
- foo() => print(T);
-}
-
-main() {
- new C<int>().foo();
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/runtime_types_2.dart b/tests/compiler/dart2js/cps_ir/input/runtime_types_2.dart
deleted file mode 100644
index a225509..0000000
--- a/tests/compiler/dart2js/cps_ir/input/runtime_types_2.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-class C<T, U> {
- foo() => print(U);
-}
-
-class D extends C<int, double> {}
-
-main() {
- new D().foo();
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/runtime_types_3.dart b/tests/compiler/dart2js/cps_ir/input/runtime_types_3.dart
deleted file mode 100644
index c9253bb..0000000
--- a/tests/compiler/dart2js/cps_ir/input/runtime_types_3.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-class C<T> {
- foo() => new D<C<T>>();
-}
-class D<T> {
- bar() => T;
-}
-main() {
- print(new C<int>().foo().bar());
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/runtime_types_4.dart b/tests/compiler/dart2js/cps_ir/input/runtime_types_4.dart
deleted file mode 100644
index f45e59c..0000000
--- a/tests/compiler/dart2js/cps_ir/input/runtime_types_4.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-// Method to test: generative_constructor(C#)
-class C<X, Y, Z> {
- foo() => 'C<$X $Y, $Z>';
-}
-main() {
- new C<C, int, String>().foo();
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/supercall_1.dart b/tests/compiler/dart2js/cps_ir/input/supercall_1.dart
deleted file mode 100644
index 0ac95c8d..0000000
--- a/tests/compiler/dart2js/cps_ir/input/supercall_1.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-class Base {
- m(x) {
- try { print(x+1); } finally { }
- }
-}
-class Sub extends Base {
- m(x) => super.m(x+10);
-}
-main() {
- new Sub().m(100);
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/supercall_2.dart b/tests/compiler/dart2js/cps_ir/input/supercall_2.dart
deleted file mode 100644
index 1a2f726..0000000
--- a/tests/compiler/dart2js/cps_ir/input/supercall_2.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// TODO(sigmund): change this to check method "function(Sub#+)" once we provide
-// a way to disable inlining of Sub#+, which is compiled to something like:
-// function(x) {
-// var v0, v1, v2;
-// v0 = 1;
-// v1 = J.getInterceptor$ns(x).$add(x, v0);
-// v2 = this;
-// return V.Base.prototype.$add.call(null, v2, v1);
-// }
-
-class Base {
- m(x) {
- print(x+1000);
- }
- operator+(x) => m(x+10);
-}
-class Sub extends Base {
- m(x) => super.m(x+100);
- operator+(x) => super + (x+1);
-}
-main() {
- new Sub() + 10000;
-}
diff --git a/tests/compiler/dart2js/cps_ir/input/supercall_3.dart b/tests/compiler/dart2js/cps_ir/input/supercall_3.dart
deleted file mode 100644
index dd2edfc..0000000
--- a/tests/compiler/dart2js/cps_ir/input/supercall_3.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-class Base {
- var field = 123;
-}
-class Sub extends Base {
- m(x) => x + super.field;
-}
-main() {
- print(new Sub().m(10));
-}
diff --git a/tests/compiler/dart2js/cps_ir/interceptors_1_test.dart b/tests/compiler/dart2js/cps_ir/interceptors_1_test.dart
deleted file mode 100644
index 98d813a..0000000
--- a/tests/compiler/dart2js/cps_ir/interceptors_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.interceptors_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("interceptors_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/interceptors_2_test.dart b/tests/compiler/dart2js/cps_ir/interceptors_2_test.dart
deleted file mode 100644
index 2562d63..0000000
--- a/tests/compiler/dart2js/cps_ir/interceptors_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.interceptors_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("interceptors_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/literals_1_test.dart b/tests/compiler/dart2js/cps_ir/literals_1_test.dart
deleted file mode 100644
index 86e1f1d5..0000000
--- a/tests/compiler/dart2js/cps_ir/literals_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.literals_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("literals_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators2_1_test.dart b/tests/compiler/dart2js/cps_ir/operators2_1_test.dart
deleted file mode 100644
index acf42c2..0000000
--- a/tests/compiler/dart2js/cps_ir/operators2_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators2_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators2_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators2_2_test.dart b/tests/compiler/dart2js/cps_ir/operators2_2_test.dart
deleted file mode 100644
index 75f6bb7..0000000
--- a/tests/compiler/dart2js/cps_ir/operators2_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators2_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators2_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators2_3_test.dart b/tests/compiler/dart2js/cps_ir/operators2_3_test.dart
deleted file mode 100644
index 7fc2f50..0000000
--- a/tests/compiler/dart2js/cps_ir/operators2_3_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators2_3.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators2_3.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators2_4_test.dart b/tests/compiler/dart2js/cps_ir/operators2_4_test.dart
deleted file mode 100644
index 9315168..0000000
--- a/tests/compiler/dart2js/cps_ir/operators2_4_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators2_4.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators2_4.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators2_5_test.dart b/tests/compiler/dart2js/cps_ir/operators2_5_test.dart
deleted file mode 100644
index 03544c1..0000000
--- a/tests/compiler/dart2js/cps_ir/operators2_5_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators2_5.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators2_5.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators2_6_test.dart b/tests/compiler/dart2js/cps_ir/operators2_6_test.dart
deleted file mode 100644
index e11bd8a..0000000
--- a/tests/compiler/dart2js/cps_ir/operators2_6_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators2_6.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators2_6.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators2_7_test.dart b/tests/compiler/dart2js/cps_ir/operators2_7_test.dart
deleted file mode 100644
index 13480a4..0000000
--- a/tests/compiler/dart2js/cps_ir/operators2_7_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators2_7.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators2_7.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators2_8_test.dart b/tests/compiler/dart2js/cps_ir/operators2_8_test.dart
deleted file mode 100644
index d39aa5f..0000000
--- a/tests/compiler/dart2js/cps_ir/operators2_8_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators2_8.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators2_8.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators_1_test.dart b/tests/compiler/dart2js/cps_ir/operators_1_test.dart
deleted file mode 100644
index 9e457ac..0000000
--- a/tests/compiler/dart2js/cps_ir/operators_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators_2_test.dart b/tests/compiler/dart2js/cps_ir/operators_2_test.dart
deleted file mode 100644
index 99dd439..0000000
--- a/tests/compiler/dart2js/cps_ir/operators_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators_3_test.dart b/tests/compiler/dart2js/cps_ir/operators_3_test.dart
deleted file mode 100644
index 57ebc5a..0000000
--- a/tests/compiler/dart2js/cps_ir/operators_3_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators_3.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators_3.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators_4_test.dart b/tests/compiler/dart2js/cps_ir/operators_4_test.dart
deleted file mode 100644
index c7fed55..0000000
--- a/tests/compiler/dart2js/cps_ir/operators_4_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators_4.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators_4.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators_5_test.dart b/tests/compiler/dart2js/cps_ir/operators_5_test.dart
deleted file mode 100644
index c412522..0000000
--- a/tests/compiler/dart2js/cps_ir/operators_5_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators_5.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators_5.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators_6_test.dart b/tests/compiler/dart2js/cps_ir/operators_6_test.dart
deleted file mode 100644
index 01246e2..0000000
--- a/tests/compiler/dart2js/cps_ir/operators_6_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators_6.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators_6.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators_7_test.dart b/tests/compiler/dart2js/cps_ir/operators_7_test.dart
deleted file mode 100644
index 2864e6f..0000000
--- a/tests/compiler/dart2js/cps_ir/operators_7_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators_7.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators_7.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/operators_8_test.dart b/tests/compiler/dart2js/cps_ir/operators_8_test.dart
deleted file mode 100644
index 6c2d67c..0000000
--- a/tests/compiler/dart2js/cps_ir/operators_8_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.operators_8.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("operators_8.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/optimize_indexers_test.dart b/tests/compiler/dart2js/cps_ir/optimize_indexers_test.dart
deleted file mode 100644
index eaf0b4a..0000000
--- a/tests/compiler/dart2js/cps_ir/optimize_indexers_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.optimize_indexers.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("optimize_indexers.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/redundant_condition_test.dart b/tests/compiler/dart2js/cps_ir/redundant_condition_test.dart
deleted file mode 100644
index e97e0ac..0000000
--- a/tests/compiler/dart2js/cps_ir/redundant_condition_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.redundant_condition.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("redundant_condition.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/runner.dart b/tests/compiler/dart2js/cps_ir/runner.dart
deleted file mode 100644
index 9f76482..0000000
--- a/tests/compiler/dart2js/cps_ir/runner.dart
+++ /dev/null
@@ -1,146 +0,0 @@
-// 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.
-
-// Test that the CPS IR code generator compiles programs and produces the
-// the expected output.
-
-import 'dart:io';
-
-import 'package:async_helper/async_helper.dart';
-import 'package:expect/expect.dart';
-import 'package:compiler/src/apiimpl.dart' show
- CompilerImpl;
-import '../memory_compiler.dart';
-import 'package:compiler/src/js/js.dart' as js;
-import 'package:compiler/src/elements/elements.dart' show
- ClassElement,
- Element;
-
-// Regular experession used to extract the method name that is used to match the
-// test output. By default we match the output of main.
-final RegExp elementNameRegExp = new RegExp(r'^// Method to test: (.*)$',
- multiLine: true);
-
-runTest(String filename, {bool update: false}) {
- var outputname = filename.replaceFirst('.dart', '.js');
- String source = new File.fromUri(Platform.script.resolve('input/$filename'))
- .readAsStringSync();
- var expectedFile =
- new File.fromUri(Platform.script.resolve('expected/$outputname'));
- String expected = '';
- if (expectedFile.existsSync()) {
- expected = expectedFile.readAsStringSync()
- .replaceAll(new RegExp('^//.*\n', multiLine: true), '')
- .trim();
- }
-
- var match = elementNameRegExp.firstMatch(source);
- var elementName = match?.group(1);
-
- Map files = {
- TEST_MAIN_FILE: source,
- 'package:expect/expect.dart': '''
- class NoInline {
- const NoInline();
- }
- class TrustTypeAnnotations {
- const TrustTypeAnnotations();
- }
- class AssumeDynamic {
- const AssumeDynamic();
- }
- ''',
- };
- asyncTest(() async {
- Uri uri = Uri.parse('memory:$TEST_MAIN_FILE');
- String found = null;
- try {
- CompilationResult result = await runCompiler(
- entryPoint: uri,
- memorySourceFiles: files,
- options: <String>['--use-cps-ir']);
- Expect.isTrue(result.isSuccess);
- CompilerImpl compiler = result.compiler;
- if (expected != null) {
- found = elementName == null
- ? _getCodeForMain(compiler)
- : _getCodeForMethod(compiler, elementName);
- }
- } catch (e, st) {
- print(e);
- print(st);
- var message = 'The following test failed to compile:\n'
- '${_formatTest(files)}';
- if (update) {
- print('\n\n$message\n');
- return;
- } else {
- Expect.fail(message);
- }
- }
- if (expected != found) {
- if (update) {
- // Include the input in a comment of the expected file to make it easier
- // to see the relation between input and output in code reviews.
- String comment = source.trim().replaceAll('\n', '\n// ');
- expectedFile.writeAsStringSync('// Expectation for test: \n'
- '// ${comment}\n\n${found}\n');
- print('INFO: $expectedFile was updated');
- } else {
- Expect.fail('Unexpected output for test:\n '
- '${_formatTest(files).replaceAll('\n', '\n ')}\n'
- 'Expected:\n ${expected.replaceAll('\n', '\n ')}\n\n'
- 'but found:\n ${found?.replaceAll('\n', '\n ')}\n'
- '$regenerateCommand');
- }
- }
- });
-}
-
-String get regenerateCommand {
- var flags = Platform.packageRoot == null
- ? '' : '--package-root=${Platform.packageRoot} ';
- return '''
-If you wish to update the test expectations, rerun this test passing "update" as
-an argument, as follows:
-
- dart $flags${Platform.script} update
-
-If you want to update more than one test at once, run:
- dart $flags${Platform.script.resolve('update_all.dart')}
-
-''';
-}
-
-const String TEST_MAIN_FILE = 'test.dart';
-
-String _formatTest(Map test) {
- return test[TEST_MAIN_FILE];
-}
-
-String _getCodeForMain(CompilerImpl compiler) {
- Element mainFunction = compiler.mainFunction;
- js.Node ast = compiler.enqueuer.codegen.generatedCode[mainFunction];
- return js.prettyPrint(ast, compiler);
-}
-
-String _getCodeForMethod(CompilerImpl compiler,
- String name) {
- Element foundElement;
- for (Element element in compiler.enqueuer.codegen.generatedCode.keys) {
- if (element.toString() == name) {
- if (foundElement != null) {
- Expect.fail('Multiple compiled elements are called $name');
- }
- foundElement = element;
- }
- }
-
- if (foundElement == null) {
- Expect.fail('There is no compiled element called $name');
- }
-
- js.Node ast = compiler.enqueuer.codegen.generatedCode[foundElement];
- return js.prettyPrint(ast, compiler);
-}
diff --git a/tests/compiler/dart2js/cps_ir/runtime_types_1_test.dart b/tests/compiler/dart2js/cps_ir/runtime_types_1_test.dart
deleted file mode 100644
index f5336f1..0000000
--- a/tests/compiler/dart2js/cps_ir/runtime_types_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.runtime_types_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("runtime_types_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/runtime_types_2_test.dart b/tests/compiler/dart2js/cps_ir/runtime_types_2_test.dart
deleted file mode 100644
index 978f612..0000000
--- a/tests/compiler/dart2js/cps_ir/runtime_types_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.runtime_types_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("runtime_types_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/runtime_types_3_test.dart b/tests/compiler/dart2js/cps_ir/runtime_types_3_test.dart
deleted file mode 100644
index 43a3349..0000000
--- a/tests/compiler/dart2js/cps_ir/runtime_types_3_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.runtime_types_3.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("runtime_types_3.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/runtime_types_4_test.dart b/tests/compiler/dart2js/cps_ir/runtime_types_4_test.dart
deleted file mode 100644
index eaf7937..0000000
--- a/tests/compiler/dart2js/cps_ir/runtime_types_4_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.runtime_types_4.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("runtime_types_4.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/supercall_1_test.dart b/tests/compiler/dart2js/cps_ir/supercall_1_test.dart
deleted file mode 100644
index caf3030..0000000
--- a/tests/compiler/dart2js/cps_ir/supercall_1_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.supercall_1.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("supercall_1.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/supercall_2_test.dart b/tests/compiler/dart2js/cps_ir/supercall_2_test.dart
deleted file mode 100644
index 6f40662..0000000
--- a/tests/compiler/dart2js/cps_ir/supercall_2_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.supercall_2.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("supercall_2.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/supercall_3_test.dart b/tests/compiler/dart2js/cps_ir/supercall_3_test.dart
deleted file mode 100644
index 9b96977..0000000
--- a/tests/compiler/dart2js/cps_ir/supercall_3_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.supercall_3.dart;
-
-import 'runner.dart';
-
-main(args) {
- runTest("supercall_3.dart", update: args.length > 0 && args[0] == "update");
-}
diff --git a/tests/compiler/dart2js/cps_ir/up_to_date_test.dart b/tests/compiler/dart2js/cps_ir/up_to_date_test.dart
deleted file mode 100644
index a9508a4..0000000
--- a/tests/compiler/dart2js/cps_ir/up_to_date_test.dart
+++ /dev/null
@@ -1,112 +0,0 @@
-// 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.
-
-/// Test that cps_ir/update_all.dart and every cps_ir/*_test.dart file are up to
-/// date. There should be a line in update_all and a file in the cps_ir folder
-/// for each test file in the `input/` folder.
-library tests.compiler.dart2js.cps_ir.up_to_date_test;
-
-import 'dart:io';
-
-main(args) {
- bool update = args.length > 0 && args[0] == 'update';
- var inputDir = new Directory.fromUri(Platform.script.resolve('input'));
-
- bool errorsFound = false;
-
- // Note: we create a test file per input file because invoking dart2js many
- // times on a single test often makes test.py timeout.
- //
- // We tried using multi-tests for this, but it is unfortunately brittle. For
- // example, multi-tests can't import code from one folder above the current
- // directory, which prevents us from putting generated tests under a different
- // folder than the rest of the helpers (like memory_compiler.dart)
- var files = inputDir.listSync().map((f) => f.uri.pathSegments.last).toList();
- files.sort();
- for (var file in files) {
- var testFilename = file.replaceAll('.dart', '_test.dart');
- var contents = generateTestFile(file);
- if (checkAndMaybeUpdate(testFilename, contents, update)) errorsFound = true;
- }
-
- var updateAllContents = generateUpdateAllFile(files);
- if (checkAndMaybeUpdate('update_all.dart', updateAllContents, update)) {
- errorsFound = true;
- }
-
- if (errorsFound) {
- print(regenerateMessage);
- exit(1);
- }
-}
-
-/// Checks and if [update] is true, updates an autogenerated test file.
-///
-/// This doesn't update an actual test expectation, that's done by executing the
-/// files that we generate here.
-bool checkAndMaybeUpdate(String filename, String contents,
- bool update) {
- var testFile = new File.fromUri(Platform.script.resolve(filename));
- bool exists = testFile.existsSync();
- var isUpToDate = exists && testFile.readAsStringSync() == contents;
- if (isUpToDate) {
- print('PASS: ${filename} is up to date.');
- } else if (update) {
- testFile.writeAsStringSync(contents);
- print('INFO: ${filename} was updated.');
- } else {
- print("FAILED: ${filename} is ${exists ? 'out of date' : 'missing'}");
- return true;
- }
- return false;
-}
-
-String generateUpdateAllFile(List<String> files) {
- var lines = files.map((f) => "runTest('$f', update: true);");
- return '''
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/${Platform.script.pathSegments.last} update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.update_all;
-
-import 'runner.dart';
-
-main(args) {
- ${lines.join('\n ')}
-}
-''';
-}
-
-String generateTestFile(String file) => '''
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/${Platform.script.pathSegments.last} update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.$file;
-
-import 'runner.dart';
-
-main(args) {
- runTest("$file", update: args.length > 0 && args[0] == "update");
-}
-''';
-
-
-String get regenerateMessage {
- var flags = Platform.packageRoot == null
- ? '' : '--package-root=${Platform.packageRoot} ';
- return '''
-
-To regenerate the test files, please run:
- dart $flags${Platform.script} update''';
-}
diff --git a/tests/compiler/dart2js/cps_ir/update_all.dart b/tests/compiler/dart2js/cps_ir/update_all.dart
deleted file mode 100644
index 59c0bc3..0000000
--- a/tests/compiler/dart2js/cps_ir/update_all.dart
+++ /dev/null
@@ -1,146 +0,0 @@
-// ---- AUTO-GENERATED -------------------
-// This file was autogenerated by running:
-//
-// dart path/to/up_to_date_test.dart update
-//
-// Do not edit this file by hand.
-// ---------------------------------------
-
-library tests.compiler.dart2js.cps_ir.update_all;
-
-import 'runner.dart';
-
-main(args) {
- runTest('argument_refinement_1.dart', update: true);
- runTest('argument_refinement_10.dart', update: true);
- runTest('argument_refinement_11.dart', update: true);
- runTest('argument_refinement_12.dart', update: true);
- runTest('argument_refinement_13.dart', update: true);
- runTest('argument_refinement_14.dart', update: true);
- runTest('argument_refinement_15.dart', update: true);
- runTest('argument_refinement_16.dart', update: true);
- runTest('argument_refinement_17.dart', update: true);
- runTest('argument_refinement_18.dart', update: true);
- runTest('argument_refinement_19.dart', update: true);
- runTest('argument_refinement_2.dart', update: true);
- runTest('argument_refinement_20.dart', update: true);
- runTest('argument_refinement_21.dart', update: true);
- runTest('argument_refinement_22.dart', update: true);
- runTest('argument_refinement_23.dart', update: true);
- runTest('argument_refinement_24.dart', update: true);
- runTest('argument_refinement_25.dart', update: true);
- runTest('argument_refinement_26.dart', update: true);
- runTest('argument_refinement_27.dart', update: true);
- runTest('argument_refinement_28.dart', update: true);
- runTest('argument_refinement_3.dart', update: true);
- runTest('argument_refinement_4.dart', update: true);
- runTest('argument_refinement_5.dart', update: true);
- runTest('argument_refinement_6.dart', update: true);
- runTest('argument_refinement_7.dart', update: true);
- runTest('argument_refinement_8.dart', update: true);
- runTest('argument_refinement_9.dart', update: true);
- runTest('argument_refinement_num_1.dart', update: true);
- runTest('argument_refinement_num_10.dart', update: true);
- runTest('argument_refinement_num_11.dart', update: true);
- runTest('argument_refinement_num_12.dart', update: true);
- runTest('argument_refinement_num_13.dart', update: true);
- runTest('argument_refinement_num_14.dart', update: true);
- runTest('argument_refinement_num_15.dart', update: true);
- runTest('argument_refinement_num_16.dart', update: true);
- runTest('argument_refinement_num_17.dart', update: true);
- runTest('argument_refinement_num_2.dart', update: true);
- runTest('argument_refinement_num_3.dart', update: true);
- runTest('argument_refinement_num_4.dart', update: true);
- runTest('argument_refinement_num_5.dart', update: true);
- runTest('argument_refinement_num_6.dart', update: true);
- runTest('argument_refinement_num_7.dart', update: true);
- runTest('argument_refinement_num_8.dart', update: true);
- runTest('argument_refinement_num_9.dart', update: true);
- runTest('basic_1.dart', update: true);
- runTest('basic_10.dart', update: true);
- runTest('basic_11.dart', update: true);
- runTest('basic_12.dart', update: true);
- runTest('basic_13.dart', update: true);
- runTest('basic_14.dart', update: true);
- runTest('basic_15.dart', update: true);
- runTest('basic_16.dart', update: true);
- runTest('basic_2.dart', update: true);
- runTest('basic_3.dart', update: true);
- runTest('basic_4.dart', update: true);
- runTest('basic_5.dart', update: true);
- runTest('basic_6.dart', update: true);
- runTest('basic_7.dart', update: true);
- runTest('basic_8.dart', update: true);
- runTest('basic_9.dart', update: true);
- runTest('closures_1.dart', update: true);
- runTest('closures_10.dart', update: true);
- runTest('closures_11.dart', update: true);
- runTest('closures_12.dart', update: true);
- runTest('closures_13.dart', update: true);
- runTest('closures_14.dart', update: true);
- runTest('closures_15.dart', update: true);
- runTest('closures_16.dart', update: true);
- runTest('closures_2.dart', update: true);
- runTest('closures_3.dart', update: true);
- runTest('closures_4.dart', update: true);
- runTest('closures_5.dart', update: true);
- runTest('closures_6.dart', update: true);
- runTest('closures_7.dart', update: true);
- runTest('closures_8.dart', update: true);
- runTest('closures_9.dart', update: true);
- runTest('codeUnitAt_1.dart', update: true);
- runTest('codeUnitAt_2.dart', update: true);
- runTest('constructor_1.dart', update: true);
- runTest('constructor_10.dart', update: true);
- runTest('constructor_11.dart', update: true);
- runTest('constructor_12.dart', update: true);
- runTest('constructor_13.dart', update: true);
- runTest('constructor_14.dart', update: true);
- runTest('constructor_15.dart', update: true);
- runTest('constructor_2.dart', update: true);
- runTest('constructor_3.dart', update: true);
- runTest('constructor_4.dart', update: true);
- runTest('constructor_5.dart', update: true);
- runTest('constructor_6.dart', update: true);
- runTest('constructor_7.dart', update: true);
- runTest('constructor_8.dart', update: true);
- runTest('constructor_9.dart', update: true);
- runTest('control_flow_1.dart', update: true);
- runTest('control_flow_2.dart', update: true);
- runTest('control_flow_3.dart', update: true);
- runTest('control_flow_4.dart', update: true);
- runTest('control_flow_5.dart', update: true);
- runTest('control_flow_6.dart', update: true);
- runTest('control_flow_7.dart', update: true);
- runTest('control_flow_8.dart', update: true);
- runTest('control_flow_9.dart', update: true);
- runTest('gvn_1.dart', update: true);
- runTest('interceptors_1.dart', update: true);
- runTest('interceptors_2.dart', update: true);
- runTest('literals_1.dart', update: true);
- runTest('operators2_1.dart', update: true);
- runTest('operators2_2.dart', update: true);
- runTest('operators2_3.dart', update: true);
- runTest('operators2_4.dart', update: true);
- runTest('operators2_5.dart', update: true);
- runTest('operators2_6.dart', update: true);
- runTest('operators2_7.dart', update: true);
- runTest('operators2_8.dart', update: true);
- runTest('operators_1.dart', update: true);
- runTest('operators_2.dart', update: true);
- runTest('operators_3.dart', update: true);
- runTest('operators_4.dart', update: true);
- runTest('operators_5.dart', update: true);
- runTest('operators_6.dart', update: true);
- runTest('operators_7.dart', update: true);
- runTest('operators_8.dart', update: true);
- runTest('optimize_indexers.dart', update: true);
- runTest('redundant_condition.dart', update: true);
- runTest('runtime_types_1.dart', update: true);
- runTest('runtime_types_2.dart', update: true);
- runTest('runtime_types_3.dart', update: true);
- runTest('runtime_types_4.dart', update: true);
- runTest('supercall_1.dart', update: true);
- runTest('supercall_2.dart', update: true);
- runTest('supercall_3.dart', update: true);
-}
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 0bb4d7d..78ca3fa 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -38,18 +38,7 @@
quarantined/http_test: Pass, Slow
-# These tests are for the now-deleted dart2dart variant of the CPS IR.
-# We want to adapt them to test the JS variant of the CPS IR instead,
-# but for now they are disabled.
-backend_dart/end2end_test: Skip
-backend_dart/sexpr2_test: Skip
-backend_dart/sexpr_test: Skip
-backend_dart/opt_constprop_test: Skip
-backend_dart/opt_shrinking_test: Skip
-backend_dart/opt_redundant_phi_test: Skip
-
# Source information is not correct due to inlining.
-js_backend_cps_ir_source_information_test: Fail
sourcemaps/source_mapping_operators_test: Pass, Slow
sourcemaps/source_mapping_invokes_test: Pass, Slow
diff --git a/tests/compiler/dart2js/dart2js_batch_test.dart b/tests/compiler/dart2js/dart2js_batch_test.dart
index 04b3ad6..55f8ca7 100644
--- a/tests/compiler/dart2js/dart2js_batch_test.dart
+++ b/tests/compiler/dart2js/dart2js_batch_test.dart
@@ -10,6 +10,8 @@
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
+import 'launch_helper.dart' show dart2JsCommand;
+
var tmpDir;
copyDirectory(Directory sourceDir, Directory destinationDir) {
@@ -51,12 +53,11 @@
}
Future launchDart2Js(_) {
- String ext = Platform.isWindows ? '.bat' : '';
- String command =
- path.normalize(path.join(path.fromUri(Platform.script),
- '../../../../sdk/bin/dart2js${ext}'));
- print("Running '$command --batch' from '${tmpDir}'.");
- return Process.start(command, ['--batch'], workingDirectory: tmpDir.path);
+ return Process.start(
+ // Use an absolute path because we are changing the cwd below.
+ path.fromUri(Uri.base.resolve(Platform.executable)),
+ dart2JsCommand(['--batch']),
+ workingDirectory: tmpDir.path);
}
Future runTests(Process process) {
diff --git a/tests/compiler/dart2js/generate_code_with_compile_time_errors_test.dart b/tests/compiler/dart2js/generate_code_with_compile_time_errors_test.dart
index 92910dc..a1814d7 100644
--- a/tests/compiler/dart2js/generate_code_with_compile_time_errors_test.dart
+++ b/tests/compiler/dart2js/generate_code_with_compile_time_errors_test.dart
@@ -86,26 +86,5 @@
['--generate-code-with-compile-time-errors', '--test-mode'],
expectedCodeGenerated: true,
expectedOutput: false);
-
- await test(
- ['--use-cps-ir'],
- expectedCodeGenerated: false,
- expectedOutput: false);
- await test(
- ['--use-cps-ir', '--test-mode'],
- expectedCodeGenerated: false,
- expectedOutput: false);
- await test(
- ['--use-cps-ir', '--generate-code-with-compile-time-errors'],
- expectedCodeGenerated: false,
- expectedOutput: false,
- expectHint: true);
- await test(
- ['--use-cps-ir',
- '--generate-code-with-compile-time-errors',
- '--test-mode'],
- expectedCodeGenerated: false,
- expectedOutput: false,
- expectHint: true);
});
}
diff --git a/tests/compiler/dart2js/http_launch_data/packages/simple/simple.dart b/tests/compiler/dart2js/http_launch_data/packages/simple/simple.dart
deleted file mode 100644
index 7e4ab7e..0000000
--- a/tests/compiler/dart2js/http_launch_data/packages/simple/simple.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-// 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.
-
-foo() => "hello http tester";
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
deleted file mode 100644
index 781ef91..0000000
--- a/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
+++ /dev/null
@@ -1,152 +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.
-
-// Test that the CPS IR code generator generates source information.
-
-library source_information_tests;
-
-import 'package:async_helper/async_helper.dart';
-import 'package:expect/expect.dart';
-import 'package:compiler/src/apiimpl.dart'
- show CompilerImpl;
-import 'memory_compiler.dart';
-import 'package:compiler/src/cps_ir/cps_ir_nodes.dart' as ir;
-import 'package:compiler/src/cps_ir/cps_ir_nodes_sexpr.dart' as ir;
-import 'package:compiler/src/js/js.dart' as js;
-import 'package:compiler/src/js_backend/js_backend.dart';
-import 'package:compiler/src/elements/elements.dart';
-
-const String TEST_MAIN_FILE = 'test.dart';
-
-class TestEntry {
- final String source;
- final List<String> expectation;
- final String elementName;
-
- const TestEntry(this.source, this.expectation)
- : elementName = null;
-
- const TestEntry.forMethod(this.elementName,
- this.source, this.expectation);
-}
-
-String formatTest(Map test) {
- return test[TEST_MAIN_FILE];
-}
-
-js.Node getCodeForMain(CompilerImpl compiler) {
- Element mainFunction = compiler.mainFunction;
- return compiler.enqueuer.codegen.generatedCode[mainFunction];
-}
-
-js.Node getJsNodeForElement(CompilerImpl compiler, Element element) {
- return compiler.enqueuer.codegen.generatedCode[element];
-}
-
-String getCodeForMethod(CompilerImpl compiler, String name) {
- Element foundElement;
- for (Element element in compiler.enqueuer.codegen.generatedCode.keys) {
- if (element.toString() == name) {
- if (foundElement != null) {
- Expect.fail('Multiple compiled elements are called $name');
- }
- foundElement = element;
- }
- }
-
- if (foundElement == null) {
- Expect.fail('There is no compiled element called $name');
- }
-
- js.Node ast = compiler.enqueuer.codegen.generatedCode[foundElement];
- return js.prettyPrint(ast, compiler);
-}
-
-runTests(List<TestEntry> tests) {
- for (TestEntry test in tests) {
- Map files = {TEST_MAIN_FILE: test.source};
- asyncTest(() {
- CompilerImpl compiler = compilerFor(
- memorySourceFiles: files, options: <String>['--use-cps-ir']);
- ir.FunctionDefinition irNodeForMain;
-
- void cacheIrNodeForMain(Element function, ir.FunctionDefinition irNode) {
- if (function == compiler.mainFunction) {
- assert(irNodeForMain == null);
- irNodeForMain = irNode;
- }
- }
-
- Uri uri = Uri.parse('memory:$TEST_MAIN_FILE');
- JavaScriptBackend backend = compiler.backend;
- var functionCompiler = backend.functionCompiler;
- functionCompiler.cpsBuilderTask.builderCallback = cacheIrNodeForMain;
-
- return compiler.run(uri).then((bool success) {
- Expect.isTrue(success);
-
- IrSourceInformationVisitor irVisitor = new IrSourceInformationVisitor();
- irNodeForMain.accept(irVisitor);
-
- js.Node jsNode = getJsNodeForElement(compiler, compiler.mainFunction);
- JsSourceInformationVisitor jsVisitor = new JsSourceInformationVisitor();
- jsNode.accept(jsVisitor);
-
- List<String> expectation = test.expectation;
- // Visiting of CPS is in structural order so we check for set equality.
- Expect.setEquals(expectation, irVisitor.sourceInformation,
- 'Unexpected IR source information. '
- 'Expected:\n$expectation\n'
- 'but found\n${irVisitor.sourceInformation}\n'
- 'in\n${test.source}'
- 'CPS:\n${irNodeForMain.accept(new ir.SExpressionStringifier())}');
- Expect.listEquals(expectation, jsVisitor.sourceInformation,
- 'Unexpected JS source information. '
- 'Expected:\n$expectation\n'
- 'but found\n${jsVisitor.sourceInformation}\n'
- 'in\n${test.source}');
- }).catchError((e) {
- print(e);
- Expect.fail('The following test failed to compile:\n'
- '${formatTest(files)}');
- });
- });
- }
-}
-
-class JsSourceInformationVisitor extends js.BaseVisitor {
- List<String> sourceInformation = <String>[];
-
- @override
- visitCall(js.Call node) {
- sourceInformation.add('${node.sourceInformation}');
- super.visitCall(node);
- }
-}
-
-class IrSourceInformationVisitor extends ir.TrampolineRecursiveVisitor {
- List<String> sourceInformation = <String>[];
-
- @override
- processInvokeStatic(ir.InvokeStatic node) {
- sourceInformation.add('${node.sourceInformation}');
- }
-}
-
-const List<TestEntry> tests = const [
- const TestEntry("""
-main() { print('Hello World'); }
-""", const ['memory:test.dart:[1,10]']),
-const TestEntry("""
-main() {
- print('Hello');
- print('World');
-}
-""", const ['memory:test.dart:[2,3]',
- 'memory:test.dart:[3,3]']),
-];
-
-void main() {
- runTests(tests);
-}
diff --git a/tests/compiler/dart2js/launch_helper.dart b/tests/compiler/dart2js/launch_helper.dart
new file mode 100644
index 0000000..671d412
--- /dev/null
+++ b/tests/compiler/dart2js/launch_helper.dart
@@ -0,0 +1,30 @@
+import 'dart:async';
+import 'dart:io';
+import 'package:path/path.dart' as path;
+
+List<String> dart2JsCommand(List<String> args) {
+ String basePath = path.fromUri(Platform.script);
+ while (path.basename(basePath) != 'sdk') {
+ basePath = path.dirname(basePath);
+ }
+ String dart2jsPath =
+ path.normalize(path.join(basePath, 'pkg/compiler/lib/src/dart2js.dart'));
+ List command = <String>[];
+ if (Platform.packageRoot != null) {
+ command.add('--package-root=${Platform.packageRoot}');
+ } else if (Platform.packageConfig != null) {
+ command.add('--packages=${Platform.packageConfig}');
+ }
+ command.add(dart2jsPath);
+ command.addAll(args);
+ return command;
+}
+
+Future launchDart2Js(args, {bool noStdoutEncoding: false}) {
+ if (noStdoutEncoding) {
+ return Process.run(Platform.executable, dart2JsCommand(args),
+ stdoutEncoding: null);
+ } else {
+ return Process.run(Platform.executable, dart2JsCommand(args));
+ }
+}
diff --git a/tests/compiler/dart2js/octagon_test.dart b/tests/compiler/dart2js/octagon_test.dart
deleted file mode 100644
index 59ea0c0..0000000
--- a/tests/compiler/dart2js/octagon_test.dart
+++ /dev/null
@@ -1,283 +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.
-
-import 'package:compiler/src/cps_ir/octagon.dart';
-import 'package:expect/expect.dart';
-
-Octagon octagon;
-SignedVariable v1, v2, v3, v4;
-
-setup() {
- octagon = new Octagon();
- v1 = octagon.makeVariable();
- v2 = octagon.makeVariable();
- v3 = octagon.makeVariable();
- v4 = octagon.makeVariable();
-}
-
-Constraint pushConstraint(SignedVariable w1, SignedVariable w2, int k) {
- Constraint c = new Constraint(w1, w2, k);
- octagon.pushConstraint(c);
- return c;
-}
-
-void popConstraint(Constraint c) {
- octagon.popConstraint(c);
-}
-
-negative_loop1() {
- setup();
- // Create the contradictory constraint:
- // v1 <= v2 <= v1 - 1 (loop weight = -1)
- //
- // As difference bounds:
- // v1 - v2 <= 0
- // v2 - v1 <= -1
- pushConstraint(v1, v2.negated, 0);
- Expect.isTrue(octagon.isSolvable, 'v1 <= v2: should be solvable');
- var c = pushConstraint(v2, v1.negated, -1);
- Expect.isTrue(octagon.isUnsolvable, 'v2 <= v1 - 1: should become unsolvable');
-
- // Check that pop restores solvability.
- popConstraint(c);
- Expect.isTrue(octagon.isSolvable, 'Should be solvable without v2 <= v1 - 1');
-}
-
-negative_loop2() {
- setup();
- // Create a longer contradiction, and add the middle constraint last:
- // v1 <= v2 <= v3 <= v1 - 1
- pushConstraint(v1, v2.negated, 0);
- Expect.isTrue(octagon.isSolvable, 'v1 <= v2: should be solvable');
- pushConstraint(v3, v1.negated, -1);
- Expect.isTrue(octagon.isSolvable, 'v3 <= v1 - 1: should be solvable');
- var c = pushConstraint(v2, v3.negated, 0);
- Expect.isTrue(octagon.isUnsolvable, 'v2 <= v3: should become unsolvable');
-
- // Check that pop restores solvability.
- popConstraint(c);
- Expect.isTrue(octagon.isSolvable, 'Should be solvable without v2 <= v3');
-}
-
-negative_loop3() {
- setup();
- // Add a circular constraint with offsets and negative weight:
- // v1 <= v2 - 1 <= v3 + 2 <= v1 - 1
- // As difference bounds:
- // v1 - v2 <= -1
- // v2 - v3 <= 3
- // v3 - v1 <= -3
- pushConstraint(v1, v2.negated, -1);
- Expect.isTrue(octagon.isSolvable, 'v1 <= v2 - 1: should be solvable');
- pushConstraint(v2, v3.negated, 3);
- Expect.isTrue(octagon.isSolvable, 'v2 - 1 <= v3 + 2: should be solvable');
- var c = pushConstraint(v3, v1.negated, -3);
- Expect.isTrue(octagon.isUnsolvable, 'v3 + 2 <= v1 - 1: should become unsolvable');
-
- // Check that pop restores solvability.
- popConstraint(c);
- Expect.isTrue(octagon.isSolvable, 'Should be solvable without v3 + 2 <= v1 - 1');
-}
-
-zero_loop1() {
- setup();
- // Add the circular constraint with zero weight:
- // v1 <= v2 <= v3 <= v1
- pushConstraint(v1, v2.negated, 0);
- Expect.isTrue(octagon.isSolvable, 'v1 <= v2: should be solvable');
- pushConstraint(v2, v3.negated, 0);
- Expect.isTrue(octagon.isSolvable, 'v2 <= v3: should be solvable');
- pushConstraint(v3, v1.negated, 0);
- Expect.isTrue(octagon.isSolvable, 'v3 <= v1: should be solvable');
-}
-
-zero_loop2() {
- setup();
- // Add a circular constraint with offsets:
- // v1 <= v2 - 1 <= v3 + 2 <= v1
- // As difference bounds:
- // v1 - v2 <= -1
- // v2 - v3 <= 3
- // v3 - v1 <= -2
- pushConstraint(v1, v2.negated, -1);
- Expect.isTrue(octagon.isSolvable, 'v1 <= v2 - 1: should be solvable');
- pushConstraint(v2, v3.negated, 3);
- Expect.isTrue(octagon.isSolvable, 'v2 - 1 <= v3 + 2: should be solvable');
- pushConstraint(v3, v1.negated, -2);
- Expect.isTrue(octagon.isSolvable, 'v3 + 2 <= v1: should be solvable');
-}
-
-positive_loop1() {
- setup();
- // Add constraints with some slack (positive-weight loop):
- // v1 <= v2 <= v3 <= v1 + 1
- pushConstraint(v1, v2.negated, 0);
- Expect.isTrue(octagon.isSolvable, 'v1 <= v2: should be solvable');
- pushConstraint(v2, v3.negated, 0);
- Expect.isTrue(octagon.isSolvable, 'v2 <= v3: should be solvable');
- pushConstraint(v3, v1.negated, 1);
- Expect.isTrue(octagon.isSolvable, 'v3 <= v1 + 1: should be solvable');
-}
-
-positive_loop2() {
- setup();
- // Add constraints with offsets and slack at the end:
- // v1 <= v2 - 1 <= v3 + 2 <= v1 + 1
- // As difference bounds:
- // v1 - v2 <= -1
- // v2 - v3 <= 3
- // v3 - v1 <= -1
- pushConstraint(v1, v2.negated, -1);
- Expect.isTrue(octagon.isSolvable, 'v1 <= v2 - 1: should be solvable');
- pushConstraint(v2, v3.negated, 3);
- Expect.isTrue(octagon.isSolvable, 'v2 - 1 <= v3 + 2: should be solvable');
- pushConstraint(v3, v1.negated, -1);
- Expect.isTrue(octagon.isSolvable, 'v3 + 2 <= v1: should be solvable');
-}
-
-positive_and_negative_loops1() {
- setup();
- // v1 <= v2 <= v3 <= v1 + 1
- // v2 <= v3 - 2 (unsolvable: v3 - 2 <= (v1 + 1) - 2 = v1 - 1)
- pushConstraint(v1, v2.negated, 0);
- pushConstraint(v2, v3.negated, 0);
- pushConstraint(v3, v1.negated, 1);
- Expect.isTrue(octagon.isSolvable, 'should be solvable');
- pushConstraint(v2, v3.negated, -2);
- Expect.isTrue(octagon.isUnsolvable, 'v2 <= v3 - 2: should become unsolvable');
-}
-
-positive_and_negative_loops2() {
- setup();
- // Same as above, but constraints are added in a different order.
- pushConstraint(v2, v3.negated, -2);
- pushConstraint(v2, v3.negated, 0);
- pushConstraint(v3, v1.negated, 1);
- Expect.isTrue(octagon.isSolvable, 'should be solvable');
- pushConstraint(v1, v2.negated, 0);
- Expect.isTrue(octagon.isUnsolvable, 'v1 <= v2: should become unsolvable');
-}
-
-positive_and_negative_loops3() {
- setup();
- // Same as above, but constraints are added in a different order.
- pushConstraint(v2, v3.negated, 0);
- pushConstraint(v2, v3.negated, -2);
- pushConstraint(v3, v1.negated, 1);
- Expect.isTrue(octagon.isSolvable, 'should be solvable');
- pushConstraint(v1, v2.negated, 0);
- Expect.isTrue(octagon.isUnsolvable, 'v1 <= v2: should become unsolvable');
-}
-
-plus_minus1() {
- setup();
- // Given:
- // v1 = v2 + 1 (modeled as: v1 <= v2 + 1 <= v1)
- // v3 = v4 + 1
- // v1 <= v3
- // prove:
- // v2 <= v4
- pushConstraint(v1, v2.negated, 1); // v1 <= v2 + 1
- pushConstraint(v2, v1.negated, -1); // v2 <= v1 - 1
- pushConstraint(v3, v4.negated, 1); // v3 <= v4 + 1
- pushConstraint(v4, v3.negated, -1); // v4 <= v3 - 1
- pushConstraint(v1, v3.negated, 0); // v1 <= v3
- Expect.isTrue(octagon.isSolvable, 'should be solvable');
- // Push the negated constraint: v2 > v4 <=> v4 - v2 <= -1
- pushConstraint(v4, v2.negated, -1);
- Expect.isTrue(octagon.isUnsolvable, 'should be unsolvable');
-}
-
-constant1() {
- setup();
- // Given:
- // v1 = 10
- // v2 <= v3
- // v3 + v1 <= 3 (i.e. v2 <= v3 <= -v1 + 3 = 7)
- // prove:
- // v2 <= 7 (modeled as: v2 + v2 <= 14)
- pushConstraint(v1, v1, 20); // v1 + v1 <= 20
- pushConstraint(v1.negated, v1.negated, -20); // -v1 - v1 <= -20
- pushConstraint(v2, v3.negated, 0); // v2 <= v3
- pushConstraint(v3, v1, 3); // v3 + v1 <= 3
- Expect.isTrue(octagon.isSolvable, 'should be solvable');
- // Push the negated constraint: v2 + v2 > 14 <=> -v2 - v2 <= -15
- var c = pushConstraint(v2.negated, v2.negated, -15);
- Expect.isTrue(octagon.isUnsolvable, 'should be unsolvable');
- popConstraint(c);
- // Push the thing we are trying to prove.
- pushConstraint(v2, v2, 14);
- Expect.isTrue(octagon.isSolvable, 'v2 + v2 <= 14: should be solvable');
-}
-
-contradict1() {
- setup();
- // v1 < v1 (v1 - v1 <= -1)
- pushConstraint(v1, v1.negated, -1);
- Expect.isTrue(octagon.isUnsolvable, 'v1 < v1: should be unsolvable');
-}
-
-contradict2() {
- setup();
- // v1 = 2
- // v2 = 0
- // v1 <= v2
- pushConstraint(v1, v1, 2);
- pushConstraint(v1.negated, v1.negated, -2);
- pushConstraint(v2, v2, 0);
- pushConstraint(v2.negated, v2.negated, 0);
- Expect.isTrue(octagon.isSolvable, 'should be solvable');
- pushConstraint(v1, v2.negated, 0);
- Expect.isTrue(octagon.isUnsolvable, 'v1 <= v2: should be unsolvable');
-}
-
-lower_bounds_check() {
- setup();
- SignedVariable w = octagon.makeVariable(0, 1000);
- pushConstraint(w, w, -1);
- Expect.isTrue(octagon.isUnsolvable, 'Value in range 0..1000 is not <= -1');
-}
-
-upper_bounds_check() {
- setup();
- SignedVariable w = octagon.makeVariable(0, 1000);
- pushConstraint(w.negated, w.negated, -5000);
- Expect.isTrue(octagon.isUnsolvable, 'Value in range 0..1000 is not >= 5000');
-}
-
-diamond_graph() {
- setup();
- pushConstraint(v1, v2.negated, 10);
- pushConstraint(v1, v3.negated, 1);
- pushConstraint(v2, v3.negated, 1);
- pushConstraint(v2, v4.negated, 2);
- pushConstraint(v3, v2.negated, 0);
- pushConstraint(v3, v4.negated, 100);
- Expect.isTrue(octagon.isSolvable, 'v1 <= v4 + 3');
- var c = pushConstraint(v4, v1.negated, -4);
- Expect.isTrue(octagon.isUnsolvable, 'v4 <= v1 - 4 should be a contradiction');
- popConstraint(c);
- pushConstraint(v1.negated, v4, -4); // Check converse constraint.
- Expect.isTrue(octagon.isUnsolvable, 'v4 <= v1 - 4 should be a contradiction');
-}
-
-void main() {
- negative_loop1();
- negative_loop2();
- negative_loop3();
- zero_loop1();
- zero_loop2();
- positive_loop1();
- positive_loop2();
- positive_and_negative_loops1();
- positive_and_negative_loops2();
- positive_and_negative_loops3();
- plus_minus1();
- constant1();
- contradict1();
- contradict2();
- lower_bounds_check();
- upper_bounds_check();
- diamond_graph();
-}
diff --git a/tests/compiler/dart2js/http_launch_data/http_launch_main.dart b/tests/compiler/dart2js/quarantined/http_launch_data/http_launch_main.dart
similarity index 100%
rename from tests/compiler/dart2js/http_launch_data/http_launch_main.dart
rename to tests/compiler/dart2js/quarantined/http_launch_data/http_launch_main.dart
diff --git a/tests/compiler/dart2js/http_launch_data/http_launch_main_package.dart b/tests/compiler/dart2js/quarantined/http_launch_data/http_launch_main_package.dart
similarity index 100%
rename from tests/compiler/dart2js/http_launch_data/http_launch_main_package.dart
rename to tests/compiler/dart2js/quarantined/http_launch_data/http_launch_main_package.dart
diff --git a/tests/compiler/dart2js/http_launch_data/lib1.dart b/tests/compiler/dart2js/quarantined/http_launch_data/lib1.dart
similarity index 100%
rename from tests/compiler/dart2js/http_launch_data/lib1.dart
rename to tests/compiler/dart2js/quarantined/http_launch_data/lib1.dart
diff --git a/tests/compiler/dart2js/http_launch_data/pkcert/README b/tests/compiler/dart2js/quarantined/http_launch_data/pkcert/README
similarity index 100%
rename from tests/compiler/dart2js/http_launch_data/pkcert/README
rename to tests/compiler/dart2js/quarantined/http_launch_data/pkcert/README
diff --git a/tests/compiler/dart2js/http_launch_data/pkcert/cert9.db b/tests/compiler/dart2js/quarantined/http_launch_data/pkcert/cert9.db
similarity index 100%
rename from tests/compiler/dart2js/http_launch_data/pkcert/cert9.db
rename to tests/compiler/dart2js/quarantined/http_launch_data/pkcert/cert9.db
Binary files differ
diff --git a/tests/compiler/dart2js/http_launch_data/pkcert/key4.db b/tests/compiler/dart2js/quarantined/http_launch_data/pkcert/key4.db
similarity index 100%
rename from tests/compiler/dart2js/http_launch_data/pkcert/key4.db
rename to tests/compiler/dart2js/quarantined/http_launch_data/pkcert/key4.db
Binary files differ
diff --git a/tests/compiler/dart2js/quarantined/http_test.dart b/tests/compiler/dart2js/quarantined/http_test.dart
index cdb1348..328cea3 100644
--- a/tests/compiler/dart2js/quarantined/http_test.dart
+++ b/tests/compiler/dart2js/quarantined/http_test.dart
@@ -15,7 +15,9 @@
import 'package:expect/expect.dart';
import 'package:path/path.dart' as path;
-Uri pathOfData = Platform.script.resolve('../http_launch_data/');
+import '../launch_helper.dart' show launchDart2Js;
+
+Uri pathOfData = Platform.script.resolve('http_launch_data/');
Directory tempDir;
String outFilePath;
@@ -39,14 +41,6 @@
});
}
-Future launchDart2Js(args) {
- String ext = Platform.isWindows ? '.bat' : '';
- String command =
- path.normalize(path.join(path.fromUri(Platform.script),
- '../../../../../sdk/bin/dart2js${ext}'));
- return Process.run(command, args);
-}
-
void check(ProcessResult result) {
Expect.equals(0, result.exitCode);
File outFile = new File(outFilePath);
diff --git a/tests/compiler/dart2js/serialization/analysis5_test.dart b/tests/compiler/dart2js/serialization/analysis5_test.dart
new file mode 100644
index 0000000..4e44643
--- /dev/null
+++ b/tests/compiler/dart2js/serialization/analysis5_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.serialization.analysis5_test;
+
+import 'analysis_test_helper.dart' as test;
+import 'test_helper.dart';
+
+main() {
+ test.main(testSegment(5, test.SPLIT_COUNT, test.SKIP_COUNT));
+}
diff --git a/tests/compiler/dart2js/serialization/analysis_test_helper.dart b/tests/compiler/dart2js/serialization/analysis_test_helper.dart
index 17926c6..82be8ee 100644
--- a/tests/compiler/dart2js/serialization/analysis_test_helper.dart
+++ b/tests/compiler/dart2js/serialization/analysis_test_helper.dart
@@ -18,7 +18,7 @@
int SKIP_COUNT = 0;
/// Number of groups that the [TESTS] are split into.
-int SPLIT_COUNT = 4;
+int SPLIT_COUNT = 5;
main(List<String> args) {
asyncTest(() async {
diff --git a/tests/compiler/dart2js/serialization/compilation5_test.dart b/tests/compiler/dart2js/serialization/compilation5_test.dart
new file mode 100644
index 0000000..10ce5eb
--- /dev/null
+++ b/tests/compiler/dart2js/serialization/compilation5_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.serialization.compilation5_test;
+
+import 'compilation_test_helper.dart' as test;
+import 'test_helper.dart';
+
+main() {
+ test.main(testSegment(5, test.SPLIT_COUNT, test.SKIP_COUNT));
+}
diff --git a/tests/compiler/dart2js/serialization/compilation_test_helper.dart b/tests/compiler/dart2js/serialization/compilation_test_helper.dart
index 5eda517..0a44ce2e 100644
--- a/tests/compiler/dart2js/serialization/compilation_test_helper.dart
+++ b/tests/compiler/dart2js/serialization/compilation_test_helper.dart
@@ -17,7 +17,7 @@
int SKIP_COUNT = 2;
/// Number of groups that the [TESTS] are split into.
-int SPLIT_COUNT = 4;
+int SPLIT_COUNT = 5;
main(List<String> args) {
asyncTest(() async {
diff --git a/tests/compiler/dart2js/serialization/model5_test.dart b/tests/compiler/dart2js/serialization/model5_test.dart
new file mode 100644
index 0000000..9cf0596
--- /dev/null
+++ b/tests/compiler/dart2js/serialization/model5_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.serialization.model5_test;
+
+import 'model_test_helper.dart' as test;
+import 'test_helper.dart';
+
+main() {
+ test.main(testSegment(5, test.SPLIT_COUNT, test.SKIP_COUNT));
+}
diff --git a/tests/compiler/dart2js/serialization/model_test_helper.dart b/tests/compiler/dart2js/serialization/model_test_helper.dart
index 18fd88c..ef92303 100644
--- a/tests/compiler/dart2js/serialization/model_test_helper.dart
+++ b/tests/compiler/dart2js/serialization/model_test_helper.dart
@@ -29,7 +29,7 @@
int SKIP_COUNT = 2;
/// Number of groups that the [TESTS] are split into.
-int SPLIT_COUNT = 4;
+int SPLIT_COUNT = 5;
main(List<String> args) {
asyncTest(() async {
@@ -413,4 +413,4 @@
'OutputUnit.imports $message',
outputUnit1.imports, outputUnit2.imports,
(a, b) => areElementsEquivalent(a.declaration, b.declaration));
-}
\ No newline at end of file
+}
diff --git a/tests/compiler/dart2js/sourcemaps/diff_view.dart b/tests/compiler/dart2js/sourcemaps/diff_view.dart
index 1c1090a..adeb641 100644
--- a/tests/compiler/dart2js/sourcemaps/diff_view.dart
+++ b/tests/compiler/dart2js/sourcemaps/diff_view.dart
@@ -65,11 +65,13 @@
List<String> commonArguments = optionSegments[0];
List<List<String>> options = <List<String>>[];
if (optionSegments.length == 1) {
+ // TODO(sigmund, johnniwinther): change default options now that CPS is
+ // deleted.
// Use default options; comparing SSA and CPS output using the new
// source information strategy.
options.add([Flags.useNewSourceInfo]..addAll(commonArguments));
- options.add(
- [Flags.useNewSourceInfo, Flags.useCpsIr]..addAll(commonArguments));
+ options.add([Flags.useNewSourceInfo]..addAll(commonArguments));
+ throw "missing options: please specify options for the second column";
} else if (optionSegments.length == 2) {
// Use alternative options for the second output column.
options.add(commonArguments);
diff --git a/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart b/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart
index 6134d20..713814a 100644
--- a/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart
+++ b/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart
@@ -98,7 +98,6 @@
const Map<String, List<String>> TEST_CONFIGURATIONS = const {
'ssa': const ['--use-new-source-info', ],
- 'cps': const ['--use-new-source-info', '--use-cps-ir'],
'old': const [],
};
diff --git a/tests/compiler/dart2js/zero_termination_test.dart b/tests/compiler/dart2js/zero_termination_test.dart
index fbfeab7..7599bc5 100644
--- a/tests/compiler/dart2js/zero_termination_test.dart
+++ b/tests/compiler/dart2js/zero_termination_test.dart
@@ -15,6 +15,8 @@
import 'package:expect/expect.dart';
import 'package:path/path.dart' as path;
+import 'launch_helper.dart' show launchDart2Js;
+
Uri pathOfData = Platform.script;
Directory tempDir;
String outFilePath;
@@ -46,14 +48,6 @@
}
}
-Future launchDart2Js(args) {
- String ext = Platform.isWindows ? '.bat' : '';
- String command =
- path.normalize(path.join(path.fromUri(Platform.script),
- '../../../../sdk/bin/dart2js${ext}'));
- return Process.run(command, args, stdoutEncoding: null);
-}
-
void check(ProcessResult result) {
Expect.notEquals(0, result.exitCode);
List<int> stdout = result.stdout;
@@ -72,7 +66,7 @@
List<String> args = [inFilePath, "--out=" + outFilePath];
await cleanup();
- check(await launchDart2Js(args));
+ check(await launchDart2Js(args, noStdoutEncoding: true));
await cleanup();
}
@@ -84,7 +78,7 @@
server.listen(handleRequest);
try {
await cleanup();
- check(await launchDart2Js(args));
+ check(await launchDart2Js(args, noStdoutEncoding: true));
} finally {
await server.close();
await cleanup();
diff --git a/tests/language/final_initializer_instance_reference_test.dart b/tests/language/final_initializer_instance_reference_test.dart
new file mode 100644
index 0000000..65580e7
--- /dev/null
+++ b/tests/language/final_initializer_instance_reference_test.dart
@@ -0,0 +1,17 @@
+// 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.
+
+// Dart2js regression test. Error in initializer might be report with the wrong
+// current element.
+
+class C {
+ const C();
+
+ final x = 1;
+ final y = x; /// 01: compile-time error
+}
+
+main() {
+ const C().y; /// 01: continued
+}
diff --git a/tools/FAKE_COMMITS b/tools/FAKE_COMMITS
index 65dee12..cc5aa2f 100644
--- a/tools/FAKE_COMMITS
+++ b/tools/FAKE_COMMITS
@@ -17,4 +17,5 @@
googlecode back up
CIT outage - all slaves rebooted
Authentication failure flake - rerun all bots
-Trigger bots after master restart - switch dart2js bots to use downloaded sdk.
\ No newline at end of file
+Trigger bots after master restart - switch dart2js bots to use downloaded sdk.
+Trigger bots after master restart.
\ No newline at end of file
diff --git a/tools/VERSION b/tools/VERSION
index 020fe18..5085af9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 19
PATCH 0
-PRERELEASE 5
+PRERELEASE 6
PRERELEASE_PATCH 0
diff --git a/tools/testing/dart/http_server.dart b/tools/testing/dart/http_server.dart
index 429ddeac..82f45cc 100644
--- a/tools/testing/dart/http_server.dart
+++ b/tools/testing/dart/http_server.dart
@@ -85,6 +85,7 @@
abbr: 'h', negatable: false, help: 'Print this usage information.');
parser.addOption('build-directory', help: 'The build directory to use.');
parser.addOption('package-root', help: 'The package root to use.');
+ parser.addOption('packages', help: 'The package spec file to use.');
parser.addOption('network',
help: 'The network interface to use.', defaultsTo: '0.0.0.0');
parser.addFlag('csp',
@@ -97,7 +98,8 @@
print(parser.getUsage());
} else {
var servers = new TestingServers(new Path(args['build-directory']),
- args['csp'], args['runtime'], null, args['package-root']);
+ args['csp'], args['runtime'], null, args['package-root'],
+ args['packages']);
var port = int.parse(args['port']);
var crossOriginPort = int.parse(args['crossOriginPort']);
servers
@@ -130,6 +132,7 @@
Path _buildDirectory = null;
Path _dartDirectory = null;
Path _packageRoot;
+ Path _packages;
final bool useContentSecurityPolicy;
final String runtime;
DispatchingServer _server;
@@ -137,13 +140,15 @@
TestingServers(Path buildDirectory, this.useContentSecurityPolicy,
[String this.runtime = 'none',
String dartDirectory,
- String packageRoot]) {
+ String packageRoot,
+ String packages]) {
_buildDirectory = TestUtils.absolutePath(buildDirectory);
_dartDirectory =
dartDirectory == null ? TestUtils.dartDir : new Path(dartDirectory);
_packageRoot = packageRoot == null
- ? _buildDirectory.append('packages')
- : new Path(packageRoot);
+ ? (packages == null ? _buildDirectory.append('packages') : null)
+ : new Path(packageRoot);
+ _packages = packages == null ? null : new Path(packages);
}
int get port => _serverList[0].port;
@@ -288,6 +293,10 @@
}
var packagesIndex = pathSegments.indexOf('packages');
if (packagesIndex != -1) {
+ if (_packages != null) {
+ // TODO(27065): Package spec file not supported by http server yet
+ return null;
+ }
var start = packagesIndex + 1;
basePath = _packageRoot;
relativePath = new Path(pathSegments.skip(start).join('/'));
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index c685988..922e386 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -437,6 +437,12 @@
new _TestOptionSpecification('package_root',
'The package root to use for testing.', ['--package-root'], [], null),
new _TestOptionSpecification(
+ 'packages',
+ 'The package spec file to use for testing.',
+ ['--packages'],
+ [],
+ null),
+ new _TestOptionSpecification(
'exclude_suite',
'Exclude suites from default selector, only works when no'
' selector has been specified on the command line',
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index abdde58..fd8270d 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -973,6 +973,10 @@
packageRoot = new Path(configuration['package_root']);
optionsFromFile['packageRoot'] = packageRoot.toNativePath();
}
+ if (configuration['packages'] != null) {
+ Path packages = new Path(configuration['packages']);
+ optionsFromFile['packages'] = packages.toNativePath();
+ }
if (new CompilerConfiguration(configuration).hasCompiler &&
expectCompileError(info)) {
@@ -1471,9 +1475,8 @@
args = [];
}
args.addAll(TestUtils.standardOptions(configuration));
- String packageRoot = packageRootArgument(optionsFromFile['packageRoot']);
- if (packageRoot != null) args.add(packageRoot);
- String packages = packagesArgument(optionsFromFile['packages']);
+ String packages = packagesArgument(optionsFromFile['packageRoot'],
+ optionsFromFile['packages']);
if (packages != null) args.add(packages);
args.add('--out=$outputFile');
args.add(inputFile);
@@ -1493,9 +1496,8 @@
Command _polymerDeployCommand(
String inputFile, String outputDir, optionsFromFile) {
List<String> args = [];
- String packageRoot = packageRootArgument(optionsFromFile['packageRoot']);
- if (packageRoot != null) args.add(packageRoot);
- String packages = packagesArgument(optionsFromFile['packages']);
+ String packages = packagesArgument(optionsFromFile['packageRoot'],
+ optionsFromFile['packages']);
if (packages != null) args.add(packages);
args
..add('package:polymer/deploy.dart')
@@ -1550,11 +1552,8 @@
List<String> commonArgumentsFromFile(Path filePath, Map optionsFromFile) {
List args = TestUtils.standardOptions(configuration);
- String packageRoot = packageRootArgument(optionsFromFile['packageRoot']);
- if (packageRoot != null) {
- args.add(packageRoot);
- }
- String packages = packagesArgument(optionsFromFile['packages']);
+ String packages = packagesArgument(optionsFromFile['packageRoot'],
+ optionsFromFile['packages']);
if (packages != null) {
args.add(packages);
}
@@ -1582,30 +1581,16 @@
return args;
}
- String packageRoot(String packageRootFromFile) {
+ String packagesArgument(String packageRootFromFile,
+ String packagesFromFile) {
+ if (packagesFromFile != null) {
+ return "--packages=$packagesFromFile";
+ }
if (packageRootFromFile == "none") {
return null;
}
- String packageRoot = packageRootFromFile;
- if (packageRootFromFile == null) {
- packageRoot = "$buildDir/packages/";
- }
- return packageRoot;
- }
-
- String packageRootArgument(String packageRootFromFile) {
- var packageRootPath = packageRoot(packageRootFromFile);
- if (packageRootPath == null) {
- return null;
- }
- return "--package-root=$packageRootPath";
- }
-
- String packagesArgument(String packagesFromFile) {
- if (packagesFromFile == null || packagesFromFile == "none") {
- return null;
- }
- return "--packages=$packagesFromFile";
+ packageRootFromFile ??= "$buildDir/packages/";
+ return "--package-root=$packageRootFromFile";
}
/**