[CFE] Allow experimental invalidation to work on DillLibraryBuilders
This CL makes experimental invalidation work on DillLibraryBuilders,
and solves all found issues (e.g. old references (aka leaks)) with it.
Note: This CL introduces a few writes that seems weird (e.g. setting
variables that's about to be out-of-scope to null). This is done to
prevent "leaks", or probably more likely, prevent a "false positive"
leak detection and it currently gives a "clean bill of health" from
the leak detector.
Change-Id: I5b01df6e9ede710a5b624a8a4c21015214140318
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/134288
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
index 562615e..818480a 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
@@ -32,6 +32,7 @@
import '../builder/class_builder.dart';
import '../builder/dynamic_type_builder.dart';
import '../builder/extension_builder.dart';
+import '../builder/modifier_builder.dart';
import '../builder/never_type_builder.dart';
import '../builder/invalid_type_declaration_builder.dart';
import '../builder/library_builder.dart';
@@ -89,7 +90,7 @@
/// [../kernel/kernel_library_builder.dart].
Map<String, String> unserializableExports;
- // TODO(jensj): These 4 booleans could potentially be merged into a single
+ // TODO(jensj): These 5 booleans could potentially be merged into a single
// state field.
bool isReadyToBuild = false;
bool isReadyToFinalizeExports = false;
@@ -294,53 +295,75 @@
exportScopeBuilder.addMember(name, declaration);
});
+ Map<Reference, Builder> sourceBuildersMap =
+ loader.currentSourceLoader?.buildersCreatedWithReferences;
for (Reference reference in library.additionalExports) {
NamedNode node = reference.node;
- Uri libraryUri;
- String name;
- bool isSetter = false;
- if (node is Class) {
- libraryUri = node.enclosingLibrary.importUri;
- name = node.name;
- } else if (node is Procedure) {
- libraryUri = node.enclosingLibrary.importUri;
- name = node.name.name;
- isSetter = node.isSetter;
- } else if (node is Member) {
- libraryUri = node.enclosingLibrary.importUri;
- name = node.name.name;
- } else if (node is Typedef) {
- libraryUri = node.enclosingLibrary.importUri;
- name = node.name;
- } else if (node is Extension) {
- libraryUri = node.enclosingLibrary.importUri;
- name = node.name;
- } else {
- unhandled("${node.runtimeType}", "finalizeExports", -1, fileUri);
- }
- DillLibraryBuilder library = loader.builders[libraryUri];
- if (library == null) {
- internalProblem(
- templateUnspecified.withArguments("No builder for '$libraryUri'."),
- -1,
- fileUri);
- }
Builder declaration;
- if (isSetter) {
- declaration = library.exportScope.lookupLocalMember(name, setter: true);
- exportScopeBuilder.addSetter(name, declaration);
+ String name;
+ if (sourceBuildersMap?.containsKey(reference) == true) {
+ declaration = sourceBuildersMap[reference];
+ assert(declaration != null);
+ if (declaration is ModifierBuilder) {
+ name = declaration.name;
+ } else {
+ throw new StateError(
+ "Unexpected: $declaration (${declaration.runtimeType}");
+ }
+
+ if (declaration.isSetter) {
+ exportScopeBuilder.addSetter(name, declaration);
+ } else {
+ exportScopeBuilder.addMember(name, declaration);
+ }
} else {
- declaration =
- library.exportScope.lookupLocalMember(name, setter: false);
- exportScopeBuilder.addMember(name, declaration);
+ Uri libraryUri;
+ bool isSetter = false;
+ if (node is Class) {
+ libraryUri = node.enclosingLibrary.importUri;
+ name = node.name;
+ } else if (node is Procedure) {
+ libraryUri = node.enclosingLibrary.importUri;
+ name = node.name.name;
+ isSetter = node.isSetter;
+ } else if (node is Member) {
+ libraryUri = node.enclosingLibrary.importUri;
+ name = node.name.name;
+ } else if (node is Typedef) {
+ libraryUri = node.enclosingLibrary.importUri;
+ name = node.name;
+ } else if (node is Extension) {
+ libraryUri = node.enclosingLibrary.importUri;
+ name = node.name;
+ } else {
+ unhandled("${node.runtimeType}", "finalizeExports", -1, fileUri);
+ }
+ LibraryBuilder library = loader.builders[libraryUri];
+ if (library == null) {
+ internalProblem(
+ templateUnspecified
+ .withArguments("No builder for '$libraryUri'."),
+ -1,
+ fileUri);
+ }
+ if (isSetter) {
+ declaration =
+ library.exportScope.lookupLocalMember(name, setter: true);
+ exportScopeBuilder.addSetter(name, declaration);
+ } else {
+ declaration =
+ library.exportScope.lookupLocalMember(name, setter: false);
+ exportScopeBuilder.addMember(name, declaration);
+ }
+ if (declaration == null) {
+ internalProblem(
+ templateUnspecified.withArguments(
+ "Exported element '$name' not found in '$libraryUri'."),
+ -1,
+ fileUri);
+ }
}
- if (declaration == null) {
- internalProblem(
- templateUnspecified.withArguments(
- "Exported element '$name' not found in '$libraryUri'."),
- -1,
- fileUri);
- }
+
assert(
(declaration is ClassBuilder && node == declaration.cls) ||
(declaration is TypeAliasBuilder &&
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
index 3d91dbd..0ce2b66 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
@@ -21,6 +21,8 @@
import '../problems.dart' show unhandled;
+import '../source/source_loader.dart' show SourceLoader;
+
import '../target_implementation.dart' show TargetImplementation;
import 'dill_library_builder.dart' show DillLibraryBuilder;
@@ -28,6 +30,8 @@
import 'dill_target.dart' show DillTarget;
class DillLoader extends Loader {
+ SourceLoader currentSourceLoader;
+
DillLoader(TargetImplementation target) : super(target);
Template<SummaryTemplate> get outlineSummaryTemplate =>
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 8599429..b58f341 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -129,7 +129,7 @@
List<LibraryBuilder> platformBuilders;
Map<Uri, LibraryBuilder> userBuilders;
final Uri initializeFromDillUri;
- final Component componentToInitializeFrom;
+ Component componentToInitializeFrom;
bool initializedFromDill = false;
bool initializedIncrementalSerializer = false;
Uri previousPackagesUri;
@@ -213,13 +213,14 @@
KernelTarget userCodeOld = userCode;
setupNewUserCode(c, uriTranslator, hierarchy, reusedLibraries,
experimentalInvalidation, entryPoints.first);
- Map<LibraryBuilder, List<SourceLibraryBuilder>> rebuildBodiesMap =
+ Map<LibraryBuilder, List<LibraryBuilder>> rebuildBodiesMap =
experimentalInvalidationCreateRebuildBodiesBuilders(
experimentalInvalidation, uriTranslator);
entryPoints = userCode.setEntryPoints(entryPoints);
await userCode.loader.buildOutlines();
experimentalInvalidationPatchUpScopes(
experimentalInvalidation, rebuildBodiesMap);
+ rebuildBodiesMap = null;
// Checkpoint: Build the actual outline.
// Note that the [Component] is not the "full" component.
@@ -277,10 +278,14 @@
if (componentWithDill == null) {
userCode.loader.builders.clear();
userCode = userCodeOld;
+ dillLoadedData.loader.currentSourceLoader = userCode.loader;
} else {
- previousSourceBuilders = await convertSourceLibraryBuildersToDill();
+ previousSourceBuilders =
+ await convertSourceLibraryBuildersToDill(experimentalInvalidation);
}
+ experimentalInvalidation = null;
+
// Output result.
Procedure mainMethod = componentWithDill == null
? data.userLoadedUriMain
@@ -295,11 +300,17 @@
/// Convert every SourceLibraryBuilder to a DillLibraryBuilder.
/// As we always do this, this will only be the new ones.
///
+ /// If doing experimental invalidation that means that some of the old dill
+ /// library builders might have links (via export scopes) to the
+ /// source builders and they will thus be patched up here too.
+ ///
/// Returns the set of Libraries that now has new (dill) builders.
- Future<Set<Library>> convertSourceLibraryBuildersToDill() async {
+ Future<Set<Library>> convertSourceLibraryBuildersToDill(
+ ExperimentalInvalidation experimentalInvalidation) async {
bool changed = false;
Set<Library> newDillLibraryBuilders = new Set<Library>();
userBuilders ??= <Uri, LibraryBuilder>{};
+ Map<LibraryBuilder, List<LibraryBuilder>> convertedLibraries;
for (MapEntry<Uri, LibraryBuilder> entry
in userCode.loader.builders.entries) {
if (entry.value is SourceLibraryBuilder) {
@@ -309,14 +320,53 @@
userCode.loader.builders[entry.key] = dillBuilder;
userBuilders[entry.key] = dillBuilder;
newDillLibraryBuilders.add(builder.library);
+ if (userCode.loader.first == builder) {
+ userCode.loader.first = dillBuilder;
+ }
changed = true;
+ if (experimentalInvalidation != null) {
+ convertedLibraries ??=
+ new Map<LibraryBuilder, List<LibraryBuilder>>();
+ convertedLibraries[builder] = [dillBuilder];
+ }
}
}
if (changed) {
// We suppress finalization errors because they have already been
// reported.
await dillLoadedData.buildOutlines(suppressFinalizationErrors: true);
+
+ if (experimentalInvalidation != null) {
+ /// If doing experimental invalidation that means that some of the old
+ /// dill library builders might have links (via export scopes) to the
+ /// source builders. Patch that up.
+
+ // Maps from old library builder to map of new content.
+ Map<LibraryBuilder, Map<String, Builder>> replacementMap = {};
+
+ // Maps from old library builder to map of new content.
+ Map<LibraryBuilder, Map<String, Builder>> replacementSettersMap = {};
+
+ experimentalInvalidationFillReplacementMaps(
+ convertedLibraries, replacementMap, replacementSettersMap);
+
+ for (LibraryBuilder builder
+ in experimentalInvalidation.originalNotReusedLibraries) {
+ DillLibraryBuilder dillBuilder = builder;
+ if (dillBuilder.isBuilt) {
+ dillBuilder.exportScope
+ .patchUpScope(replacementMap, replacementSettersMap);
+ }
+ }
+ replacementMap = null;
+ replacementSettersMap = null;
+ }
}
+ userCode.loader.buildersCreatedWithReferences.clear();
+ userCode.loader.builderHierarchy.nodes.clear();
+ userCode.loader.referenceFromIndex = null;
+ convertedLibraries = null;
+ experimentalInvalidation = null;
if (userBuilders.isEmpty) userBuilders = null;
return newDillLibraryBuilders;
}
@@ -415,17 +465,17 @@
/// Fill in the replacement maps that describe the replacements that need to
/// happen because of experimental invalidation.
void experimentalInvalidationFillReplacementMaps(
- Map<LibraryBuilder, List<SourceLibraryBuilder>> rebuildBodiesMap,
+ Map<LibraryBuilder, List<LibraryBuilder>> rebuildBodiesMap,
Map<LibraryBuilder, Map<String, Builder>> replacementMap,
Map<LibraryBuilder, Map<String, Builder>> replacementSettersMap) {
- for (MapEntry<LibraryBuilder, List<SourceLibraryBuilder>> entry
+ for (MapEntry<LibraryBuilder, List<LibraryBuilder>> entry
in rebuildBodiesMap.entries) {
Map<String, Builder> childReplacementMap = {};
Map<String, Builder> childReplacementSettersMap = {};
- List<SourceLibraryBuilder> builders = rebuildBodiesMap[entry.key];
+ List<LibraryBuilder> builders = rebuildBodiesMap[entry.key];
replacementMap[entry.key] = childReplacementMap;
replacementSettersMap[entry.key] = childReplacementSettersMap;
- for (SourceLibraryBuilder builder in builders) {
+ for (LibraryBuilder builder in builders) {
NameIterator iterator = builder.nameIterator;
while (iterator.moveNext()) {
Builder childBuilder = iterator.current;
@@ -450,22 +500,22 @@
/// When doing experimental invalidation, we have some builders that needs to
/// be rebuild special, namely they have to be [userCode.loader.read] with
/// references from the original [Library] for things to work.
- Map<LibraryBuilder, List<SourceLibraryBuilder>>
+ Map<LibraryBuilder, List<LibraryBuilder>>
experimentalInvalidationCreateRebuildBodiesBuilders(
ExperimentalInvalidation experimentalInvalidation,
UriTranslator uriTranslator) {
// Any builder(s) in [rebuildBodies] should be semi-reused: Create source
// builders based on the underlying libraries.
// Maps from old library builder to list of new library builder(s).
- Map<LibraryBuilder, List<SourceLibraryBuilder>> rebuildBodiesMap =
- new Map<LibraryBuilder, List<SourceLibraryBuilder>>.identity();
+ Map<LibraryBuilder, List<LibraryBuilder>> rebuildBodiesMap =
+ new Map<LibraryBuilder, List<LibraryBuilder>>.identity();
if (experimentalInvalidation != null) {
for (LibraryBuilder library in experimentalInvalidation.rebuildBodies) {
LibraryBuilder newBuilder = userCode.loader.read(library.importUri, -1,
accessor: userCode.loader.first,
fileUri: library.fileUri,
referencesFrom: library.library);
- List<SourceLibraryBuilder> builders = [newBuilder];
+ List<LibraryBuilder> builders = [newBuilder];
rebuildBodiesMap[library] = builders;
for (LibraryPart part in library.library.parts) {
// We need to pass the reference to make any class, procedure etc
@@ -492,7 +542,7 @@
/// didn't do anything special.
void experimentalInvalidationPatchUpScopes(
ExperimentalInvalidation experimentalInvalidation,
- Map<LibraryBuilder, List<SourceLibraryBuilder>> rebuildBodiesMap) {
+ Map<LibraryBuilder, List<LibraryBuilder>> rebuildBodiesMap) {
if (experimentalInvalidation != null) {
// Maps from old library builder to map of new content.
Map<LibraryBuilder, Map<String, Builder>> replacementMap = {};
@@ -557,8 +607,16 @@
}
}
}
+ } else if (builder is DillLibraryBuilder) {
+ DillLibraryBuilder dillBuilder = builder;
+ // There's only something to patch up if it was build already.
+ if (dillBuilder.isBuilt) {
+ dillBuilder.exportScope
+ .patchUpScope(replacementMap, replacementSettersMap);
+ }
} else {
- throw "Currently unsupported";
+ throw new StateError(
+ "Unexpected builder: $builder (${builder.runtimeType})");
}
}
}
@@ -581,6 +639,7 @@
dillLoadedData,
uriTranslator);
userCode.loader.hierarchy = hierarchy;
+ dillLoadedData.loader.currentSourceLoader = userCode.loader;
// Re-use the libraries we've deemed re-usable.
for (LibraryBuilder library in reusedLibraries) {
@@ -754,6 +813,10 @@
// rebuild the bodies.
for (int i = 0; i < reusedResult.directlyInvalidated.length; i++) {
LibraryBuilder builder = reusedResult.directlyInvalidated[i];
+ if (builder.library.problemsAsJson != null) {
+ assert(builder.library.problemsAsJson.isNotEmpty);
+ return null;
+ }
Iterator<Builder> iterator = builder.iterator;
while (iterator.moveNext()) {
Builder childBuilder = iterator.current;
@@ -866,6 +929,7 @@
// If initializing from a component it has to include the sdk,
// so we explicitly don't load it here.
initializeFromComponent(uriTranslator, c, data);
+ componentToInitializeFrom = null;
} else {
List<int> summaryBytes = await c.options.loadSdkSummaryBytes();
bytesLength = prepareSummary(summaryBytes, uriTranslator, c, data);
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index dc904d8..65e4043 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -39,13 +39,14 @@
Nullability,
Procedure,
ProcedureKind,
+ Reference,
SetLiteral,
StaticInvocation,
StringLiteral,
Supertype,
- Typedef,
TypeParameter,
TypeParameterType,
+ Typedef,
VariableDeclaration,
VoidType;
@@ -774,13 +775,18 @@
}
}
- Builder addBuilder(String name, Builder declaration, int charOffset) {
+ @override
+ Builder addBuilder(String name, Builder declaration, int charOffset,
+ {Reference reference}) {
// TODO(ahe): Set the parent correctly here. Could then change the
// implementation of MemberBuilder.isTopLevel to test explicitly for a
// LibraryBuilder.
if (name == null) {
unhandled("null", "name", charOffset, fileUri);
}
+ if (reference != null) {
+ loader.buildersCreatedWithReferences[reference] = declaration;
+ }
if (currentTypeParameterScopeBuilder == libraryDeclaration) {
if (declaration is MemberBuilder) {
declaration.parent = this;
@@ -1134,9 +1140,12 @@
// DietListener can find them.
for (int i = duplicated.length; i > 0; i--) {
Builder declaration = duplicated[i - 1];
+ // No reference: There should be no duplicates when using references.
addBuilder(name, declaration, declaration.charOffset);
}
} else {
+ // No reference: The part is in the same loader so the reference
+ // - if needed - was already added.
addBuilder(name, declaration, declaration.charOffset);
}
}
@@ -1553,7 +1562,8 @@
members.forEach(setParentAndCheckConflicts);
constructors.forEach(setParentAndCheckConflicts);
setters.forEach(setParentAndCheckConflicts);
- addBuilder(className, classBuilder, nameOffset);
+ addBuilder(className, classBuilder, nameOffset,
+ reference: referencesFromClass?.reference);
}
Map<String, TypeVariableBuilder> checkTypeVariables(
@@ -1668,7 +1678,8 @@
members.forEach(setParentAndCheckConflicts);
constructors.forEach(setParentAndCheckConflicts);
setters.forEach(setParentAndCheckConflicts);
- addBuilder(extensionName, extensionBuilder, nameOffset);
+ addBuilder(extensionName, extensionBuilder, nameOffset,
+ reference: referenceFrom?.reference);
}
TypeBuilder applyMixins(TypeBuilder type, int startCharOffset, int charOffset,
@@ -1906,7 +1917,8 @@
// pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart can't
// handle that :(
application.cls.isAnonymousMixin = !isNamedMixinApplication;
- addBuilder(fullname, application, charOffset);
+ addBuilder(fullname, application, charOffset,
+ reference: referencesFromClass?.reference);
supertype = addNamedType(fullname, const NullabilityBuilder.omitted(),
applicationTypeArguments, charOffset);
}
@@ -2062,7 +2074,8 @@
getterReferenceFrom,
setterReferenceFrom);
fieldBuilder.constInitializerToken = constInitializerToken;
- addBuilder(name, fieldBuilder, charOffset);
+ addBuilder(name, fieldBuilder, charOffset,
+ reference: referenceFrom?.reference);
if (type == null && initializerToken != null && fieldBuilder.next == null) {
// Only the first one (the last one in the linked list of next pointers)
// are added to the tree, had parent pointers and can infer correctly.
@@ -2114,7 +2127,8 @@
metadataCollector?.setConstructorNameOffset(
constructorBuilder.constructor, name);
checkTypeVariables(typeVariables, constructorBuilder);
- addBuilder(constructorName, constructorBuilder, charOffset);
+ addBuilder(constructorName, constructorBuilder, charOffset,
+ reference: referenceFrom?.reference);
if (nativeMethodName != null) {
addNativeMethod(constructorBuilder);
}
@@ -2219,7 +2233,8 @@
metadataCollector?.setDocumentationComment(
procedureBuilder.procedure, documentationComment);
checkTypeVariables(typeVariables, procedureBuilder);
- addBuilder(name, procedureBuilder, charOffset);
+ addBuilder(name, procedureBuilder, charOffset,
+ reference: referenceFrom?.reference);
if (nativeMethodName != null) {
addNativeMethod(procedureBuilder);
}
@@ -2319,7 +2334,8 @@
currentTypeParameterScopeBuilder = savedDeclaration;
factoryDeclaration.resolveTypes(procedureBuilder.typeVariables, this);
- addBuilder(procedureName, procedureBuilder, charOffset);
+ addBuilder(procedureName, procedureBuilder, charOffset,
+ reference: referenceFrom?.reference);
if (nativeMethodName != null) {
addNativeMethod(procedureBuilder);
}
@@ -2352,7 +2368,8 @@
charEndOffset,
referencesFromClass,
referencesFromIndexedClass);
- addBuilder(name, builder, charOffset);
+ addBuilder(name, builder, charOffset,
+ reference: referencesFromClass?.reference);
metadataCollector?.setDocumentationComment(
builder.cls, documentationComment);
}
@@ -2379,7 +2396,8 @@
// Nested declaration began in `OutlineBuilder.beginFunctionTypeAlias`.
endNestedDeclaration(TypeParameterScopeKind.typedef, "#typedef")
.resolveTypes(typeVariables, this);
- addBuilder(name, typedefBuilder, charOffset);
+ addBuilder(name, typedefBuilder, charOffset,
+ reference: referenceFrom?.reference);
}
FunctionTypeBuilder addFunctionType(
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 9a79867..9d3b7d3 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -40,6 +40,7 @@
LibraryDependency,
Nullability,
ProcedureKind,
+ Reference,
Supertype,
TreeNode;
@@ -152,6 +153,11 @@
ClassHierarchy hierarchy;
CoreTypes _coreTypes;
+ /// For builders created with a reference, this maps from that reference to
+ /// that builder. This is used for looking up source builders when finalizing
+ /// exports in dill builders.
+ Map<Reference, Builder> buildersCreatedWithReferences = {};
+
/// Used when checking whether a return type of an async function is valid.
///
/// The said return type is valid if it's a subtype of [futureOfBottom].
diff --git a/pkg/front_end/lib/src/fasta/util/textual_outline.dart b/pkg/front_end/lib/src/fasta/util/textual_outline.dart
index a6c7251..7cb4916 100644
--- a/pkg/front_end/lib/src/fasta/util/textual_outline.dart
+++ b/pkg/front_end/lib/src/fasta/util/textual_outline.dart
@@ -9,6 +9,9 @@
import 'package:_fe_analyzer_shared/src/parser/class_member_parser.dart'
show ClassMemberParser;
+import 'package:_fe_analyzer_shared/src/parser/declaration_kind.dart'
+ show DeclarationKind;
+
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
show ErrorToken, LanguageVersionToken, Scanner;
@@ -47,9 +50,12 @@
if (token is ErrorToken) {
return null;
}
- if (printed && token.offset > endOfLast) {
+ if (addLinebreak) {
+ sb.write("\n");
+ } else if (printed && token.offset > endOfLast) {
sb.write(" ");
}
+ addLinebreak = false;
sb.write(token.lexeme);
printed = true;
@@ -58,19 +64,19 @@
if (token.lexeme == ";") {
addLinebreak = true;
} else if (token.endGroup != null &&
- listener.endOffsets.contains(token.endGroup.offset)) {
+ (listener.nonClassEndOffsets.contains(token.endGroup.offset) ||
+ listener.classEndOffsets.contains(token.endGroup.offset))) {
addLinebreak = true;
- } else if (listener.endOffsets.contains(token.offset)) {
+ } else if (listener.nonClassEndOffsets.contains(token.offset) ||
+ listener.classEndOffsets.contains(token.offset)) {
addLinebreak = true;
}
}
- if (addLinebreak) sb.write("\n");
- addLinebreak = false;
if (token.isEof) break;
if (token.endGroup != null &&
- listener.endOffsets.contains(token.endGroup.offset)) {
+ listener.nonClassEndOffsets.contains(token.endGroup.offset)) {
token = token.endGroup;
} else {
token = token.next;
@@ -86,17 +92,30 @@
}
class EndOffsetListener extends DirectiveListener {
- Set<int> endOffsets = new Set<int>();
+ Set<int> nonClassEndOffsets = new Set<int>();
+ Set<int> classEndOffsets = new Set<int>();
@override
void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
Token beginInitializers, Token endToken) {
- endOffsets.add(endToken.offset);
+ nonClassEndOffsets.add(endToken.offset);
}
@override
void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
- endOffsets.add(endToken.offset);
+ nonClassEndOffsets.add(endToken.offset);
+ }
+
+ @override
+ void endClassFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ nonClassEndOffsets.add(endToken.offset);
+ }
+
+ @override
+ void endClassOrMixinBody(
+ DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
+ classEndOffsets.add(endToken.offset);
}
@override
diff --git a/pkg/front_end/test/incremental_dart2js_tester.dart b/pkg/front_end/test/incremental_dart2js_tester.dart
index 0eb21c7..b8f8b47 100644
--- a/pkg/front_end/test/incremental_dart2js_tester.dart
+++ b/pkg/front_end/test/incremental_dart2js_tester.dart
@@ -31,58 +31,50 @@
}
}
- Stopwatch stopwatch = new Stopwatch()..start();
- Uri input = Platform.script.resolve("../../compiler/bin/dart2js.dart");
- CompilerOptions options = helper.getOptions(targetName: "VM");
- helper.TestIncrementalCompiler compiler =
- new helper.TestIncrementalCompiler(options, input);
- compiler.useExperimentalInvalidation = useExperimentalInvalidation;
- Component c = await compiler.computeDelta();
- print("Compiled dart2js to Component with ${c.libraries.length} libraries "
- "in ${stopwatch.elapsedMilliseconds} ms.");
- stopwatch.reset();
+ Dart2jsTester dart2jsTester =
+ new Dart2jsTester(useExperimentalInvalidation, fast, addDebugBreaks);
+ await dart2jsTester.test();
+}
+
+class Dart2jsTester {
+ final bool useExperimentalInvalidation;
+ final bool fast;
+ final bool addDebugBreaks;
+
+ Stopwatch stopwatch = new Stopwatch();
List<int> firstCompileData;
Map<Uri, List<int>> libToData;
- if (fast) {
- libToData = {};
- c.libraries.sort((l1, l2) {
- return "${l1.fileUri}".compareTo("${l2.fileUri}");
- });
-
- c.problemsAsJson?.sort();
-
- c.computeCanonicalNames();
-
- for (Library library in c.libraries) {
- library.additionalExports.sort((Reference r1, Reference r2) {
- return "${r1.canonicalName}".compareTo("${r2.canonicalName}");
- });
- library.problemsAsJson?.sort();
-
- List<int> libSerialized =
- serializeComponent(c, filter: (l) => l == library);
- libToData[library.importUri] = libSerialized;
- }
- } else {
- firstCompileData = util.postProcess(c);
- }
- print("Serialized in ${stopwatch.elapsedMilliseconds} ms");
- stopwatch.reset();
-
- List<Uri> uris = c.uriToSource.values
- .map((s) => s != null ? s.importUri : null)
- .where((u) => u != null && u.scheme != "dart")
- .toSet()
- .toList();
-
- c = null;
+ List<Uri> uris;
List<Uri> diffs = new List<Uri>();
Set<Uri> componentUris = new Set<Uri>();
- Stopwatch localStopwatch = new Stopwatch()..start();
- for (int i = 0; i < uris.length; i++) {
- Uri uri = uris[i];
+ Dart2jsTester(
+ this.useExperimentalInvalidation, this.fast, this.addDebugBreaks);
+
+ void test() async {
+ helper.TestIncrementalCompiler compiler = await setup();
+
+ diffs = new List<Uri>();
+ componentUris = new Set<Uri>();
+
+ Stopwatch localStopwatch = new Stopwatch()..start();
+ for (int i = 0; i < uris.length; i++) {
+ Uri uri = uris[i];
+ await step(uri, i, compiler, localStopwatch);
+ }
+
+ print("A total of ${diffs.length} diffs:");
+ for (Uri uri in diffs) {
+ print(" - $uri");
+ }
+
+ print("Done after ${uris.length} recompiles in "
+ "${stopwatch.elapsedMilliseconds} ms");
+ }
+
+ Future step(Uri uri, int i, helper.TestIncrementalCompiler compiler,
+ Stopwatch localStopwatch) async {
print("Invalidating $uri ($i)");
compiler.invalidate(uri);
localStopwatch.reset();
@@ -168,24 +160,65 @@
print("-----");
}
- print("A total of ${diffs.length} diffs:");
- for (Uri uri in diffs) {
- print(" - $uri");
+ Future<helper.TestIncrementalCompiler> setup() async {
+ stopwatch.reset();
+ stopwatch.start();
+ Uri input = Platform.script.resolve("../../compiler/bin/dart2js.dart");
+ CompilerOptions options = helper.getOptions(targetName: "VM");
+ helper.TestIncrementalCompiler compiler =
+ new helper.TestIncrementalCompiler(options, input);
+ compiler.useExperimentalInvalidation = useExperimentalInvalidation;
+ Component c = await compiler.computeDelta();
+ print("Compiled dart2js to Component with ${c.libraries.length} libraries "
+ "in ${stopwatch.elapsedMilliseconds} ms.");
+ stopwatch.reset();
+ if (fast) {
+ libToData = {};
+ c.libraries.sort((l1, l2) {
+ return "${l1.fileUri}".compareTo("${l2.fileUri}");
+ });
+
+ c.problemsAsJson?.sort();
+
+ c.computeCanonicalNames();
+
+ for (Library library in c.libraries) {
+ library.additionalExports.sort((Reference r1, Reference r2) {
+ return "${r1.canonicalName}".compareTo("${r2.canonicalName}");
+ });
+ library.problemsAsJson?.sort();
+
+ List<int> libSerialized =
+ serializeComponent(c, filter: (l) => l == library);
+ libToData[library.importUri] = libSerialized;
+ }
+ } else {
+ firstCompileData = util.postProcess(c);
+ }
+ print("Serialized in ${stopwatch.elapsedMilliseconds} ms");
+ stopwatch.reset();
+
+ uris = c.uriToSource.values
+ .map((s) => s != null ? s.importUri : null)
+ .where((u) => u != null && u.scheme != "dart")
+ .toSet()
+ .toList();
+
+ c = null;
+
+ return compiler;
}
- print("Done after ${uris.length} recompiles in "
- "${stopwatch.elapsedMilliseconds} ms");
-}
-
-bool isEqual(List<int> a, List<int> b) {
- int length = a.length;
- if (b.length != length) {
- return false;
- }
- for (int i = 0; i < length; ++i) {
- if (a[i] != b[i]) {
+ bool isEqual(List<int> a, List<int> b) {
+ int length = a.length;
+ if (b.length != length) {
return false;
}
+ for (int i = 0; i < length; ++i) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
}
- return true;
}
diff --git a/pkg/front_end/test/incremental_load_from_dill_suite.dart b/pkg/front_end/test/incremental_load_from_dill_suite.dart
index 79b25aa..97a33b5 100644
--- a/pkg/front_end/test/incremental_load_from_dill_suite.dart
+++ b/pkg/front_end/test/incremental_load_from_dill_suite.dart
@@ -166,7 +166,7 @@
"forceLateLoweringForTesting",
"incrementalSerialization"
]);
- await newWorldTest(
+ await new NewWorldTest().newWorldTest(
data,
context,
map["worlds"],
@@ -317,519 +317,542 @@
return moduleResult;
}
-Future<Null> newWorldTest(
- TestData data,
- Context context,
- List worlds,
- Map modules,
- bool omitPlatform,
- String targetName,
- bool forceLateLoweringForTesting,
- bool incrementalSerialization) async {
- final Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
- final Uri base = Uri.parse("org-dartlang-test:///");
- final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
- final Uri initializeFrom = base.resolve("initializeFrom.dill");
- Uri platformUri = sdkRoot.resolve("vm_platform_strong.dill");
- final List<int> sdkSummaryData =
- await new File.fromUri(platformUri).readAsBytes();
-
- List<int> newestWholeComponentData;
+class NewWorldTest {
+ // These are fields in a class to make it easier to track down memory leaks
+ // via the leak detector test.
Component newestWholeComponent;
- MemoryFileSystem fs;
- Map<String, String> sourceFiles;
- CompilerOptions options;
- TestIncrementalCompiler compiler;
- IncrementalSerializer incrementalSerializer;
-
- Map<String, List<int>> moduleData;
- Map<String, Component> moduleComponents;
Component sdk;
- if (modules != null) {
- moduleData = await createModules(
- modules, sdkSummaryData, targetName, forceLateLoweringForTesting);
- sdk = newestWholeComponent = new Component();
- new BinaryBuilder(sdkSummaryData, filename: null, disableLazyReading: false)
- .readComponent(newestWholeComponent);
- }
+ Component component;
+ Component component2;
+ Component component3;
- int worldNum = 0;
- for (YamlMap world in worlds) {
- worldNum++;
- print("----------------");
- print("World #$worldNum");
- print("----------------");
- List<Component> modulesToUse;
- if (world["modules"] != null) {
- moduleComponents ??= new Map<String, Component>();
+ Future<Null> newWorldTest(
+ TestData data,
+ Context context,
+ List worlds,
+ Map modules,
+ bool omitPlatform,
+ String targetName,
+ bool forceLateLoweringForTesting,
+ bool incrementalSerialization) async {
+ final Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
+ final Uri base = Uri.parse("org-dartlang-test:///");
+ final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
+ final Uri initializeFrom = base.resolve("initializeFrom.dill");
+ Uri platformUri = sdkRoot.resolve("vm_platform_strong.dill");
+ final List<int> sdkSummaryData =
+ await new File.fromUri(platformUri).readAsBytes();
- sdk.adoptChildren();
- for (Component c in moduleComponents.values) {
- c.adoptChildren();
- }
+ List<int> newestWholeComponentData;
+ MemoryFileSystem fs;
+ Map<String, String> sourceFiles;
+ CompilerOptions options;
+ TestIncrementalCompiler compiler;
+ IncrementalSerializer incrementalSerializer;
- modulesToUse = new List<Component>();
- for (String moduleName in world["modules"]) {
- Component moduleComponent = moduleComponents[moduleName];
- if (moduleComponent != null) {
- modulesToUse.add(moduleComponent);
+ Map<String, List<int>> moduleData;
+ Map<String, Component> moduleComponents;
+
+ if (modules != null) {
+ moduleData = await createModules(
+ modules, sdkSummaryData, targetName, forceLateLoweringForTesting);
+ sdk = newestWholeComponent = new Component();
+ new BinaryBuilder(sdkSummaryData,
+ filename: null, disableLazyReading: false)
+ .readComponent(newestWholeComponent);
+ }
+
+ int worldNum = 0;
+ for (YamlMap world in worlds) {
+ worldNum++;
+ print("----------------");
+ print("World #$worldNum");
+ print("----------------");
+ List<Component> modulesToUse;
+ if (world["modules"] != null) {
+ moduleComponents ??= new Map<String, Component>();
+
+ sdk.adoptChildren();
+ for (Component c in moduleComponents.values) {
+ c.adoptChildren();
+ }
+
+ modulesToUse = new List<Component>();
+ for (String moduleName in world["modules"]) {
+ Component moduleComponent = moduleComponents[moduleName];
+ if (moduleComponent != null) {
+ modulesToUse.add(moduleComponent);
+ }
+ }
+ for (String moduleName in world["modules"]) {
+ Component moduleComponent = moduleComponents[moduleName];
+ if (moduleComponent == null) {
+ moduleComponent = new Component(nameRoot: sdk.root);
+ new BinaryBuilder(moduleData[moduleName],
+ filename: null,
+ disableLazyReading: false,
+ alwaysCreateNewNamedNodes: true)
+ .readComponent(moduleComponent);
+ moduleComponents[moduleName] = moduleComponent;
+ modulesToUse.add(moduleComponent);
+ }
}
}
- for (String moduleName in world["modules"]) {
- Component moduleComponent = moduleComponents[moduleName];
- if (moduleComponent == null) {
- moduleComponent = new Component(nameRoot: sdk.root);
- new BinaryBuilder(moduleData[moduleName],
- filename: null,
- disableLazyReading: false,
- alwaysCreateNewNamedNodes: true)
- .readComponent(moduleComponent);
- moduleComponents[moduleName] = moduleComponent;
- modulesToUse.add(moduleComponent);
- }
- }
- }
- bool brandNewWorld = true;
- if (world["worldType"] == "updated") {
- brandNewWorld = false;
- }
- bool noFullComponent = false;
- if (world["noFullComponent"] == true) {
- noFullComponent = true;
- }
+ bool brandNewWorld = true;
+ if (world["worldType"] == "updated") {
+ brandNewWorld = false;
+ }
+ bool noFullComponent = false;
+ if (world["noFullComponent"] == true) {
+ noFullComponent = true;
+ }
- if (brandNewWorld) {
- fs = new MemoryFileSystem(base);
- }
- fs.entityForUri(sdkSummary).writeAsBytesSync(sdkSummaryData);
- bool expectInitializeFromDill = false;
- if (newestWholeComponentData != null &&
- newestWholeComponentData.isNotEmpty) {
- fs
- .entityForUri(initializeFrom)
- .writeAsBytesSync(newestWholeComponentData);
- expectInitializeFromDill = true;
- }
- if (world["expectInitializeFromDill"] != null) {
- expectInitializeFromDill = world["expectInitializeFromDill"];
- }
- if (brandNewWorld) {
- sourceFiles = new Map<String, String>.from(world["sources"]);
- } else {
- sourceFiles.addAll(
- new Map<String, String>.from(world["sources"] ?? <String, String>{}));
- }
- Uri packagesUri;
- for (String filename in sourceFiles.keys) {
- String data = sourceFiles[filename] ?? "";
- Uri uri = base.resolve(filename);
- if (filename == ".packages") {
- packagesUri = uri;
+ if (brandNewWorld) {
+ fs = new MemoryFileSystem(base);
}
- fs.entityForUri(uri).writeAsStringSync(data);
- }
- if (world["dotPackagesFile"] != null) {
- packagesUri = base.resolve(world["dotPackagesFile"]);
- }
-
- if (brandNewWorld) {
- options = getOptions(
- targetName: targetName,
- forceLateLoweringForTesting: forceLateLoweringForTesting);
- options.fileSystem = fs;
- options.sdkRoot = null;
- options.sdkSummary = sdkSummary;
- options.omitPlatform = omitPlatform != false;
- if (world["experiments"] != null) {
- Map<ExperimentalFlag, bool> experimentalFlags = parseExperimentalFlags(
- parseExperimentalArguments([world["experiments"]]),
- onError: (e) => throw "Error on parsing experiments flags: $e");
- options.experimentalFlags = experimentalFlags;
+ fs.entityForUri(sdkSummary).writeAsBytesSync(sdkSummaryData);
+ bool expectInitializeFromDill = false;
+ if (newestWholeComponentData != null &&
+ newestWholeComponentData.isNotEmpty) {
+ fs
+ .entityForUri(initializeFrom)
+ .writeAsBytesSync(newestWholeComponentData);
+ expectInitializeFromDill = true;
}
- }
- if (packagesUri != null) {
- options.packagesFileUri = packagesUri;
- }
- bool gotError = false;
- final Set<String> formattedErrors = Set<String>();
- bool gotWarning = false;
- final Set<String> formattedWarnings = Set<String>();
-
- options.onDiagnostic = (DiagnosticMessage message) {
- String stringId = message.ansiFormatted.join("\n");
- if (message is FormattedMessage) {
- stringId = message.toJsonString();
- } else if (message is DiagnosticMessageFromJson) {
- stringId = message.toJsonString();
+ if (world["expectInitializeFromDill"] != null) {
+ expectInitializeFromDill = world["expectInitializeFromDill"];
}
- if (message.severity == Severity.error) {
- gotError = true;
- if (!formattedErrors.add(stringId)) {
- Expect.fail("Got the same message twice: ${stringId}");
- }
- } else if (message.severity == Severity.warning) {
- gotWarning = true;
- if (!formattedWarnings.add(stringId)) {
- Expect.fail("Got the same message twice: ${stringId}");
- }
- }
- };
-
- List<Uri> entries;
- if (world["entry"] is String) {
- entries = [base.resolve(world["entry"])];
- } else {
- entries = new List<Uri>();
- List<dynamic> entryList = world["entry"];
- for (String entry in entryList) {
- entries.add(base.resolve(entry));
- }
- }
- bool outlineOnly = world["outlineOnly"] == true;
- bool skipOutlineBodyCheck = world["skipOutlineBodyCheck"] == true;
- if (brandNewWorld) {
- if (incrementalSerialization == true) {
- incrementalSerializer = new IncrementalSerializer();
- }
- if (world["fromComponent"] == true) {
- compiler = new TestIncrementalCompiler.fromComponent(
- options,
- entries.first,
- (modulesToUse != null) ? sdk : newestWholeComponent,
- outlineOnly,
- incrementalSerializer);
+ if (brandNewWorld) {
+ sourceFiles = new Map<String, String>.from(world["sources"]);
} else {
- compiler = new TestIncrementalCompiler(options, entries.first,
- initializeFrom, outlineOnly, incrementalSerializer);
+ sourceFiles.addAll(new Map<String, String>.from(
+ world["sources"] ?? <String, String>{}));
+ }
+ Uri packagesUri;
+ for (String filename in sourceFiles.keys) {
+ String data = sourceFiles[filename] ?? "";
+ Uri uri = base.resolve(filename);
+ if (filename == ".packages") {
+ packagesUri = uri;
+ }
+ fs.entityForUri(uri).writeAsStringSync(data);
+ }
+ if (world["dotPackagesFile"] != null) {
+ packagesUri = base.resolve(world["dotPackagesFile"]);
+ }
- if (modulesToUse != null) {
- throw "You probably shouldn't do this! "
- "Any modules will have another sdk loaded!";
+ if (brandNewWorld) {
+ options = getOptions(
+ targetName: targetName,
+ forceLateLoweringForTesting: forceLateLoweringForTesting);
+ options.fileSystem = fs;
+ options.sdkRoot = null;
+ options.sdkSummary = sdkSummary;
+ options.omitPlatform = omitPlatform != false;
+ if (world["experiments"] != null) {
+ Map<ExperimentalFlag, bool> experimentalFlags =
+ parseExperimentalFlags(
+ parseExperimentalArguments([world["experiments"]]),
+ onError: (e) =>
+ throw "Error on parsing experiments flags: $e");
+ options.experimentalFlags = experimentalFlags;
}
}
- }
-
- compiler.useExperimentalInvalidation = false;
- if (world["useExperimentalInvalidation"] == true) {
- compiler.useExperimentalInvalidation = true;
- }
-
- List<Uri> invalidated = new List<Uri>();
- if (world["invalidate"] != null) {
- for (String filename in world["invalidate"]) {
- Uri uri = base.resolve(filename);
- invalidated.add(uri);
- compiler.invalidate(uri);
+ if (packagesUri != null) {
+ options.packagesFileUri = packagesUri;
}
- }
+ bool gotError = false;
+ final Set<String> formattedErrors = Set<String>();
+ bool gotWarning = false;
+ final Set<String> formattedWarnings = Set<String>();
- if (modulesToUse != null) {
- compiler.setModulesToLoadOnNextComputeDelta(modulesToUse);
- compiler.invalidateAllSources();
- compiler.trackNeededDillLibraries = true;
- }
+ options.onDiagnostic = (DiagnosticMessage message) {
+ String stringId = message.ansiFormatted.join("\n");
+ if (message is FormattedMessage) {
+ stringId = message.toJsonString();
+ } else if (message is DiagnosticMessageFromJson) {
+ stringId = message.toJsonString();
+ }
+ if (message.severity == Severity.error) {
+ gotError = true;
+ if (!formattedErrors.add(stringId)) {
+ Expect.fail("Got the same message twice: ${stringId}");
+ }
+ } else if (message.severity == Severity.warning) {
+ gotWarning = true;
+ if (!formattedWarnings.add(stringId)) {
+ Expect.fail("Got the same message twice: ${stringId}");
+ }
+ }
+ };
- Stopwatch stopwatch = new Stopwatch()..start();
- Component component = await compiler.computeDelta(
- entryPoints: entries,
- fullComponent: brandNewWorld ? false : (noFullComponent ? false : true),
- simulateTransformer: world["simulateTransformer"]);
- if (outlineOnly && !skipOutlineBodyCheck) {
- for (Library lib in component.libraries) {
- for (Class c in lib.classes) {
- for (Procedure p in c.procedures) {
+ List<Uri> entries;
+ if (world["entry"] is String) {
+ entries = [base.resolve(world["entry"])];
+ } else {
+ entries = new List<Uri>();
+ List<dynamic> entryList = world["entry"];
+ for (String entry in entryList) {
+ entries.add(base.resolve(entry));
+ }
+ }
+ bool outlineOnly = world["outlineOnly"] == true;
+ bool skipOutlineBodyCheck = world["skipOutlineBodyCheck"] == true;
+ if (brandNewWorld) {
+ if (incrementalSerialization == true) {
+ incrementalSerializer = new IncrementalSerializer();
+ }
+ if (world["fromComponent"] == true) {
+ compiler = new TestIncrementalCompiler.fromComponent(
+ options,
+ entries.first,
+ (modulesToUse != null) ? sdk : newestWholeComponent,
+ outlineOnly,
+ incrementalSerializer);
+ } else {
+ compiler = new TestIncrementalCompiler(options, entries.first,
+ initializeFrom, outlineOnly, incrementalSerializer);
+
+ if (modulesToUse != null) {
+ throw "You probably shouldn't do this! "
+ "Any modules will have another sdk loaded!";
+ }
+ }
+ }
+
+ compiler.useExperimentalInvalidation = false;
+ if (world["useExperimentalInvalidation"] == true) {
+ compiler.useExperimentalInvalidation = true;
+ }
+
+ List<Uri> invalidated = new List<Uri>();
+ if (world["invalidate"] != null) {
+ for (String filename in world["invalidate"]) {
+ Uri uri = base.resolve(filename);
+ invalidated.add(uri);
+ compiler.invalidate(uri);
+ }
+ }
+
+ if (modulesToUse != null) {
+ compiler.setModulesToLoadOnNextComputeDelta(modulesToUse);
+ compiler.invalidateAllSources();
+ compiler.trackNeededDillLibraries = true;
+ }
+
+ Stopwatch stopwatch = new Stopwatch()..start();
+ component = await compiler.computeDelta(
+ entryPoints: entries,
+ fullComponent:
+ brandNewWorld ? false : (noFullComponent ? false : true),
+ simulateTransformer: world["simulateTransformer"]);
+ if (outlineOnly && !skipOutlineBodyCheck) {
+ for (Library lib in component.libraries) {
+ for (Class c in lib.classes) {
+ for (Procedure p in c.procedures) {
+ if (p.function.body != null &&
+ p.function.body is! EmptyStatement) {
+ throw "Got body (${p.function.body.runtimeType})";
+ }
+ }
+ }
+ for (Procedure p in lib.procedures) {
if (p.function.body != null && p.function.body is! EmptyStatement) {
throw "Got body (${p.function.body.runtimeType})";
}
}
}
- for (Procedure p in lib.procedures) {
- if (p.function.body != null && p.function.body is! EmptyStatement) {
- throw "Got body (${p.function.body.runtimeType})";
+ }
+ performErrorAndWarningCheck(
+ world, gotError, formattedErrors, gotWarning, formattedWarnings);
+ util.throwOnEmptyMixinBodies(component);
+ await util.throwOnInsufficientUriToSource(component,
+ fileSystem: gotError ? null : fs);
+ print("Compile took ${stopwatch.elapsedMilliseconds} ms");
+
+ checkExpectedContent(world, component);
+ checkNeededDillLibraries(world, compiler.neededDillLibraries, base);
+
+ if (!noFullComponent) {
+ Set<Library> allLibraries = new Set<Library>();
+ for (Library lib in component.libraries) {
+ computeAllReachableLibrariesFor(lib, allLibraries);
+ }
+ if (allLibraries.length != component.libraries.length) {
+ Expect.fail("Expected for the reachable stuff to be equal to "
+ "${component.libraries} but it was $allLibraries");
+ }
+ Set<Library> tooMany = allLibraries.toSet()
+ ..removeAll(component.libraries);
+ if (tooMany.isNotEmpty) {
+ Expect.fail("Expected for the reachable stuff to be equal to "
+ "${component.libraries} but these were there too: $tooMany "
+ "(and others were missing)");
+ }
+ }
+
+ newestWholeComponentData = util.postProcess(component);
+ newestWholeComponent = component;
+ String actualSerialized = componentToStringSdkFiltered(component);
+ print("*****\n\ncomponent:\n"
+ "${actualSerialized}\n\n\n");
+
+ if (world["uriToSourcesDoesntInclude"] != null) {
+ for (String filename in world["uriToSourcesDoesntInclude"]) {
+ Uri uri = base.resolve(filename);
+ if (component.uriToSource[uri] != null) {
+ throw "Expected no uriToSource for $uri but found "
+ "${component.uriToSource[uri]}";
}
}
}
- }
- performErrorAndWarningCheck(
- world, gotError, formattedErrors, gotWarning, formattedWarnings);
- util.throwOnEmptyMixinBodies(component);
- await util.throwOnInsufficientUriToSource(component,
- fileSystem: gotError ? null : fs);
- print("Compile took ${stopwatch.elapsedMilliseconds} ms");
-
- checkExpectedContent(world, component);
- checkNeededDillLibraries(world, compiler.neededDillLibraries, base);
-
- if (!noFullComponent) {
- Set<Library> allLibraries = new Set<Library>();
- for (Library lib in component.libraries) {
- computeAllReachableLibrariesFor(lib, allLibraries);
- }
- if (allLibraries.length != component.libraries.length) {
- Expect.fail("Expected for the reachable stuff to be equal to "
- "${component.libraries} but it was $allLibraries");
- }
- Set<Library> tooMany = allLibraries.toSet()
- ..removeAll(component.libraries);
- if (tooMany.isNotEmpty) {
- Expect.fail("Expected for the reachable stuff to be equal to "
- "${component.libraries} but these were there too: $tooMany "
- "(and others were missing)");
- }
- }
-
- newestWholeComponentData = util.postProcess(component);
- newestWholeComponent = component;
- String actualSerialized = componentToStringSdkFiltered(component);
- print("*****\n\ncomponent:\n"
- "${actualSerialized}\n\n\n");
-
- if (world["uriToSourcesDoesntInclude"] != null) {
- for (String filename in world["uriToSourcesDoesntInclude"]) {
- Uri uri = base.resolve(filename);
- if (component.uriToSource[uri] != null) {
- throw "Expected no uriToSource for $uri but found "
- "${component.uriToSource[uri]}";
+ if (world["uriToSourcesOnlyIncludes"] != null) {
+ Set<Uri> allowed = {};
+ for (String filename in world["uriToSourcesOnlyIncludes"]) {
+ Uri uri = base.resolve(filename);
+ allowed.add(uri);
+ }
+ for (Uri uri in component.uriToSource.keys) {
+ // null is always there, so allow it implicitly.
+ // Dart scheme uris too.
+ if (uri == null || uri.scheme == "org-dartlang-sdk") continue;
+ if (!allowed.contains(uri)) {
+ throw "Expected no uriToSource for $uri but found "
+ "${component.uriToSource[uri]}";
+ }
}
}
- }
- if (world["uriToSourcesOnlyIncludes"] != null) {
- Set<Uri> allowed = {};
- for (String filename in world["uriToSourcesOnlyIncludes"]) {
- Uri uri = base.resolve(filename);
- allowed.add(uri);
- }
- for (Uri uri in component.uriToSource.keys) {
- // null is always there, so allow it implicitly.
- // Dart scheme uris too.
- if (uri == null || uri.scheme == "org-dartlang-sdk") continue;
- if (!allowed.contains(uri)) {
- throw "Expected no uriToSource for $uri but found "
- "${component.uriToSource[uri]}";
- }
- }
- }
- checkExpectFile(data, worldNum, context, actualSerialized);
- checkClassHierarchy(compiler, component, data, worldNum, context);
+ checkExpectFile(data, worldNum, context, actualSerialized);
+ checkClassHierarchy(compiler, component, data, worldNum, context);
- int nonSyntheticLibraries = countNonSyntheticLibraries(component);
- int nonSyntheticPlatformLibraries =
- countNonSyntheticPlatformLibraries(component);
- int syntheticLibraries = countSyntheticLibraries(component);
- if (world["expectsPlatform"] == true) {
- if (nonSyntheticPlatformLibraries < 5) {
- throw "Expected to have at least 5 platform libraries "
- "(actually, the entire sdk), "
- "but got $nonSyntheticPlatformLibraries.";
- }
- } else {
- if (nonSyntheticPlatformLibraries != 0) {
- throw "Expected to have 0 platform libraries "
- "but got $nonSyntheticPlatformLibraries.";
- }
- }
- if (world["expectedLibraryCount"] != null) {
- if (nonSyntheticLibraries - nonSyntheticPlatformLibraries !=
- world["expectedLibraryCount"]) {
- throw "Expected ${world["expectedLibraryCount"]} non-synthetic "
- "libraries, got "
- "${nonSyntheticLibraries - nonSyntheticPlatformLibraries} "
- "(not counting platform libraries)";
- }
- }
- if (world["expectedSyntheticLibraryCount"] != null) {
- if (syntheticLibraries != world["expectedSyntheticLibraryCount"]) {
- throw "Expected ${world["expectedSyntheticLibraryCount"]} synthetic "
- "libraries, got ${syntheticLibraries}";
- }
- }
-
- if (world["expectsRebuildBodiesOnly"] != null) {
- bool didRebuildBodiesOnly = compiler.rebuildBodiesCount > 0;
- Expect.equals(world["expectsRebuildBodiesOnly"], didRebuildBodiesOnly,
- "Whether we expected to rebuild bodies only.");
- }
-
- if (!noFullComponent) {
- List<Library> entryLib = component.libraries
- .where((Library lib) =>
- entries.contains(lib.importUri) || entries.contains(lib.fileUri))
- .toList();
- if (entryLib.length != entries.length) {
- throw "Expected the entries to become libraries. "
- "Got ${entryLib.length} libraries for the expected "
- "${entries.length} entries.";
- }
- }
- if (compiler.initializedFromDill != expectInitializeFromDill) {
- throw "Expected that initializedFromDill would be "
- "$expectInitializeFromDill but was ${compiler.initializedFromDill}";
- }
-
- if (incrementalSerialization == true && compiler.initializedFromDill) {
- Expect.isTrue(compiler.initializedIncrementalSerializer);
- } else {
- Expect.isFalse(compiler.initializedIncrementalSerializer);
- }
-
- if (world["checkInvalidatedFiles"] != false) {
- Set<Uri> filteredInvalidated =
- compiler.getFilteredInvalidatedImportUrisForTesting(invalidated);
- if (world["invalidate"] != null) {
- Expect.equals(
- world["invalidate"].length, filteredInvalidated?.length ?? 0);
- List expectedInvalidatedUri = world["expectedInvalidatedUri"];
- if (expectedInvalidatedUri != null) {
- Expect.setEquals(expectedInvalidatedUri.map((s) => base.resolve(s)),
- filteredInvalidated);
+ int nonSyntheticLibraries = countNonSyntheticLibraries(component);
+ int nonSyntheticPlatformLibraries =
+ countNonSyntheticPlatformLibraries(component);
+ int syntheticLibraries = countSyntheticLibraries(component);
+ if (world["expectsPlatform"] == true) {
+ if (nonSyntheticPlatformLibraries < 5) {
+ throw "Expected to have at least 5 platform libraries "
+ "(actually, the entire sdk), "
+ "but got $nonSyntheticPlatformLibraries.";
}
} else {
- Expect.isNull(filteredInvalidated);
- Expect.isNull(world["expectedInvalidatedUri"]);
- }
- }
- List<int> incrementalSerializationBytes = checkIncrementalSerialization(
- incrementalSerialization, component, incrementalSerializer, world);
-
- Set<String> prevFormattedErrors = formattedErrors.toSet();
- Set<String> prevFormattedWarnings = formattedWarnings.toSet();
-
- clearPrevErrorsEtc() {
- gotError = false;
- formattedErrors.clear();
- gotWarning = false;
- formattedWarnings.clear();
- }
-
- if (!noFullComponent) {
- clearPrevErrorsEtc();
- Component component2 = await compiler.computeDelta(
- entryPoints: entries,
- fullComponent: true,
- simulateTransformer: world["simulateTransformer"]);
- performErrorAndWarningCheck(
- world, gotError, formattedErrors, gotWarning, formattedWarnings);
- List<int> thisWholeComponent = util.postProcess(component2);
- print("*****\n\ncomponent2:\n"
- "${componentToStringSdkFiltered(component2)}\n\n\n");
- checkIsEqual(newestWholeComponentData, thisWholeComponent);
- checkErrorsAndWarnings(prevFormattedErrors, formattedErrors,
- prevFormattedWarnings, formattedWarnings);
-
- List<int> incrementalSerializationBytes2 = checkIncrementalSerialization(
- incrementalSerialization, component2, incrementalSerializer, world);
-
- if ((incrementalSerializationBytes == null &&
- incrementalSerializationBytes2 != null) ||
- (incrementalSerializationBytes != null &&
- incrementalSerializationBytes2 == null)) {
- throw "Incremental serialization gave results in one instance, "
- "but not another.";
- }
-
- if (incrementalSerializationBytes != null) {
- checkIsEqual(
- incrementalSerializationBytes, incrementalSerializationBytes2);
- }
- }
-
- if (world["expressionCompilation"] != null) {
- List compilations;
- if (world["expressionCompilation"] is List) {
- compilations = world["expressionCompilation"];
- } else {
- compilations = [world["expressionCompilation"]];
- }
- for (Map compilation in compilations) {
- clearPrevErrorsEtc();
- bool expectErrors = compilation["errors"] ?? false;
- bool expectWarnings = compilation["warnings"] ?? false;
- Uri uri = base.resolve(compilation["uri"]);
- String expression = compilation["expression"];
- await compiler.compileExpression(expression, {}, [], "debugExpr", uri);
- if (gotError && !expectErrors) {
- throw "Got error(s) on expression compilation: ${formattedErrors}.";
- } else if (!gotError && expectErrors) {
- throw "Didn't get any errors.";
- }
- if (gotWarning && !expectWarnings) {
- throw "Got warning(s) on expression compilation: "
- "${formattedWarnings}.";
- } else if (!gotWarning && expectWarnings) {
- throw "Didn't get any warnings.";
+ if (nonSyntheticPlatformLibraries != 0) {
+ throw "Expected to have 0 platform libraries "
+ "but got $nonSyntheticPlatformLibraries.";
}
}
- }
-
- if (!noFullComponent && incrementalSerialization == true) {
- // Do compile from scratch and compare.
- clearPrevErrorsEtc();
- TestIncrementalCompiler compilerFromScratch;
-
- IncrementalSerializer incrementalSerializer2;
- if (incrementalSerialization == true) {
- incrementalSerializer2 = new IncrementalSerializer();
+ if (world["expectedLibraryCount"] != null) {
+ if (nonSyntheticLibraries - nonSyntheticPlatformLibraries !=
+ world["expectedLibraryCount"]) {
+ throw "Expected ${world["expectedLibraryCount"]} non-synthetic "
+ "libraries, got "
+ "${nonSyntheticLibraries - nonSyntheticPlatformLibraries} "
+ "(not counting platform libraries)";
+ }
+ }
+ if (world["expectedSyntheticLibraryCount"] != null) {
+ if (syntheticLibraries != world["expectedSyntheticLibraryCount"]) {
+ throw "Expected ${world["expectedSyntheticLibraryCount"]} synthetic "
+ "libraries, got ${syntheticLibraries}";
+ }
}
- if (world["fromComponent"] == true || modulesToUse != null) {
- compilerFromScratch = new TestIncrementalCompiler.fromComponent(
- options, entries.first, sdk, outlineOnly, incrementalSerializer2);
+ if (world["expectsRebuildBodiesOnly"] != null) {
+ bool didRebuildBodiesOnly = compiler.rebuildBodiesCount > 0;
+ Expect.equals(world["expectsRebuildBodiesOnly"], didRebuildBodiesOnly,
+ "Whether we expected to rebuild bodies only.");
+ }
+
+ if (!noFullComponent) {
+ List<Library> entryLib = component.libraries
+ .where((Library lib) =>
+ entries.contains(lib.importUri) ||
+ entries.contains(lib.fileUri))
+ .toList();
+ if (entryLib.length != entries.length) {
+ throw "Expected the entries to become libraries. "
+ "Got ${entryLib.length} libraries for the expected "
+ "${entries.length} entries.";
+ }
+ }
+ if (compiler.initializedFromDill != expectInitializeFromDill) {
+ throw "Expected that initializedFromDill would be "
+ "$expectInitializeFromDill but was ${compiler.initializedFromDill}";
+ }
+
+ if (incrementalSerialization == true && compiler.initializedFromDill) {
+ Expect.isTrue(compiler.initializedIncrementalSerializer);
} else {
- compilerFromScratch = new TestIncrementalCompiler(
- options, entries.first, null, outlineOnly, incrementalSerializer2);
+ Expect.isFalse(compiler.initializedIncrementalSerializer);
}
- if (modulesToUse != null) {
- compilerFromScratch.setModulesToLoadOnNextComputeDelta(modulesToUse);
- compilerFromScratch.invalidateAllSources();
- compilerFromScratch.trackNeededDillLibraries = true;
- }
-
- Stopwatch stopwatch = new Stopwatch()..start();
- Component component3 = await compilerFromScratch.computeDelta(
- entryPoints: entries,
- simulateTransformer: world["simulateTransformer"]);
- compilerFromScratch = null;
- performErrorAndWarningCheck(
- world, gotError, formattedErrors, gotWarning, formattedWarnings);
- util.throwOnEmptyMixinBodies(component3);
- await util.throwOnInsufficientUriToSource(component3);
- print("Compile took ${stopwatch.elapsedMilliseconds} ms");
-
- util.postProcess(component3);
- print("*****\n\ncomponent3:\n"
- "${componentToStringSdkFiltered(component3)}\n\n\n");
- checkErrorsAndWarnings(prevFormattedErrors, formattedErrors,
- prevFormattedWarnings, formattedWarnings);
-
- List<int> incrementalSerializationBytes3 = checkIncrementalSerialization(
- incrementalSerialization, component3, incrementalSerializer2, world);
-
- if ((incrementalSerializationBytes == null &&
- incrementalSerializationBytes3 != null) ||
- (incrementalSerializationBytes != null &&
- incrementalSerializationBytes3 == null)) {
- throw "Incremental serialization gave results in one instance, "
- "but not another.";
- }
-
- if (incrementalSerializationBytes != null) {
- if (world["brandNewIncrementalSerializationAllowDifferent"] == true) {
- // Don't check for equality when we allow it to be different
- // (e.g. when the old one contains more, and the new one doesn't).
+ if (world["checkInvalidatedFiles"] != false) {
+ Set<Uri> filteredInvalidated =
+ compiler.getFilteredInvalidatedImportUrisForTesting(invalidated);
+ if (world["invalidate"] != null) {
+ Expect.equals(
+ world["invalidate"].length, filteredInvalidated?.length ?? 0);
+ List expectedInvalidatedUri = world["expectedInvalidatedUri"];
+ if (expectedInvalidatedUri != null) {
+ Expect.setEquals(expectedInvalidatedUri.map((s) => base.resolve(s)),
+ filteredInvalidated);
+ }
} else {
- checkIsEqual(
- incrementalSerializationBytes, incrementalSerializationBytes3);
+ Expect.isNull(filteredInvalidated);
+ Expect.isNull(world["expectedInvalidatedUri"]);
}
- newestWholeComponentData = incrementalSerializationBytes;
}
- }
+ List<int> incrementalSerializationBytes = checkIncrementalSerialization(
+ incrementalSerialization, component, incrementalSerializer, world);
- if (context.breakBetween) {
- debugger();
- print("Continuing after debug break");
+ Set<String> prevFormattedErrors = formattedErrors.toSet();
+ Set<String> prevFormattedWarnings = formattedWarnings.toSet();
+
+ clearPrevErrorsEtc() {
+ gotError = false;
+ formattedErrors.clear();
+ gotWarning = false;
+ formattedWarnings.clear();
+ }
+
+ if (!noFullComponent) {
+ clearPrevErrorsEtc();
+ component2 = await compiler.computeDelta(
+ entryPoints: entries,
+ fullComponent: true,
+ simulateTransformer: world["simulateTransformer"]);
+ performErrorAndWarningCheck(
+ world, gotError, formattedErrors, gotWarning, formattedWarnings);
+ List<int> thisWholeComponent = util.postProcess(component2);
+ print("*****\n\ncomponent2:\n"
+ "${componentToStringSdkFiltered(component2)}\n\n\n");
+ checkIsEqual(newestWholeComponentData, thisWholeComponent);
+ checkErrorsAndWarnings(prevFormattedErrors, formattedErrors,
+ prevFormattedWarnings, formattedWarnings);
+ newestWholeComponent = component2;
+
+ List<int> incrementalSerializationBytes2 =
+ checkIncrementalSerialization(incrementalSerialization, component2,
+ incrementalSerializer, world);
+
+ if ((incrementalSerializationBytes == null &&
+ incrementalSerializationBytes2 != null) ||
+ (incrementalSerializationBytes != null &&
+ incrementalSerializationBytes2 == null)) {
+ throw "Incremental serialization gave results in one instance, "
+ "but not another.";
+ }
+
+ if (incrementalSerializationBytes != null) {
+ checkIsEqual(
+ incrementalSerializationBytes, incrementalSerializationBytes2);
+ }
+ }
+
+ if (world["expressionCompilation"] != null) {
+ List compilations;
+ if (world["expressionCompilation"] is List) {
+ compilations = world["expressionCompilation"];
+ } else {
+ compilations = [world["expressionCompilation"]];
+ }
+ for (Map compilation in compilations) {
+ clearPrevErrorsEtc();
+ bool expectErrors = compilation["errors"] ?? false;
+ bool expectWarnings = compilation["warnings"] ?? false;
+ Uri uri = base.resolve(compilation["uri"]);
+ String expression = compilation["expression"];
+ await compiler.compileExpression(
+ expression, {}, [], "debugExpr", uri);
+ if (gotError && !expectErrors) {
+ throw "Got error(s) on expression compilation: ${formattedErrors}.";
+ } else if (!gotError && expectErrors) {
+ throw "Didn't get any errors.";
+ }
+ if (gotWarning && !expectWarnings) {
+ throw "Got warning(s) on expression compilation: "
+ "${formattedWarnings}.";
+ } else if (!gotWarning && expectWarnings) {
+ throw "Didn't get any warnings.";
+ }
+ }
+ }
+
+ if (!noFullComponent && incrementalSerialization == true) {
+ // Do compile from scratch and compare.
+ clearPrevErrorsEtc();
+ TestIncrementalCompiler compilerFromScratch;
+
+ IncrementalSerializer incrementalSerializer2;
+ if (incrementalSerialization == true) {
+ incrementalSerializer2 = new IncrementalSerializer();
+ }
+
+ if (world["fromComponent"] == true || modulesToUse != null) {
+ compilerFromScratch = new TestIncrementalCompiler.fromComponent(
+ options, entries.first, sdk, outlineOnly, incrementalSerializer2);
+ } else {
+ compilerFromScratch = new TestIncrementalCompiler(options,
+ entries.first, null, outlineOnly, incrementalSerializer2);
+ }
+
+ if (modulesToUse != null) {
+ compilerFromScratch.setModulesToLoadOnNextComputeDelta(modulesToUse);
+ compilerFromScratch.invalidateAllSources();
+ compilerFromScratch.trackNeededDillLibraries = true;
+ }
+
+ Stopwatch stopwatch = new Stopwatch()..start();
+ component3 = await compilerFromScratch.computeDelta(
+ entryPoints: entries,
+ simulateTransformer: world["simulateTransformer"]);
+ compilerFromScratch = null;
+ performErrorAndWarningCheck(
+ world, gotError, formattedErrors, gotWarning, formattedWarnings);
+ util.throwOnEmptyMixinBodies(component3);
+ await util.throwOnInsufficientUriToSource(component3);
+ print("Compile took ${stopwatch.elapsedMilliseconds} ms");
+
+ util.postProcess(component3);
+ print("*****\n\ncomponent3:\n"
+ "${componentToStringSdkFiltered(component3)}\n\n\n");
+ checkErrorsAndWarnings(prevFormattedErrors, formattedErrors,
+ prevFormattedWarnings, formattedWarnings);
+
+ List<int> incrementalSerializationBytes3 =
+ checkIncrementalSerialization(incrementalSerialization, component3,
+ incrementalSerializer2, world);
+
+ if ((incrementalSerializationBytes == null &&
+ incrementalSerializationBytes3 != null) ||
+ (incrementalSerializationBytes != null &&
+ incrementalSerializationBytes3 == null)) {
+ throw "Incremental serialization gave results in one instance, "
+ "but not another.";
+ }
+
+ if (incrementalSerializationBytes != null) {
+ if (world["brandNewIncrementalSerializationAllowDifferent"] == true) {
+ // Don't check for equality when we allow it to be different
+ // (e.g. when the old one contains more, and the new one doesn't).
+ } else {
+ checkIsEqual(
+ incrementalSerializationBytes, incrementalSerializationBytes3);
+ }
+ newestWholeComponentData = incrementalSerializationBytes;
+ }
+ }
+
+ component = null;
+ component2 = null;
+ component3 = null;
+
+ if (context.breakBetween) {
+ debugger();
+ print("Continuing after debug break");
+ }
}
}
}
@@ -1171,10 +1194,10 @@
libContent.add("Class ${c.name}");
}
for (Procedure p in lib.procedures) {
- libContent.add("Procedure ${p.name}");
+ libContent.add("Procedure ${p.name.name}");
}
for (Field f in lib.fields) {
- libContent.add("Field ${f.name}");
+ libContent.add("Field ${f.name.name}");
}
}
return actualContent;
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index ef6d66d..ac51d61 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -122,6 +122,7 @@
depended
depfile
desc
+detector
deviation
dfast
dictionaries
@@ -138,6 +139,7 @@
disconnect
discovering
dispatcher
+dispose
dist
doctype
doesnt
@@ -185,6 +187,7 @@
fisk
five
floor
+foos
forbidden
forces
foreign
@@ -381,6 +384,7 @@
splitting
sqrt
sssp
+stats
std
stdio
strip
diff --git a/pkg/front_end/test/vm_service_for_leak_detection.dart b/pkg/front_end/test/vm_service_for_leak_detection.dart
index 7d3c6ba..040e1d5 100644
--- a/pkg/front_end/test/vm_service_for_leak_detection.dart
+++ b/pkg/front_end/test/vm_service_for_leak_detection.dart
@@ -26,11 +26,23 @@
["_extension"]),
new helper.Interest(Uri.parse("package:kernel/ast.dart"), "Extension",
["name", "fileUri"]),
+ new helper.Interest(Uri.parse("package:kernel/ast.dart"), "Library",
+ ["fileUri", "_libraryIdString"]),
],
true);
+
+ // heapHelper.start([
+ // "--enable-asserts",
+ // Platform.script.resolve("incremental_dart2js_tester.dart").toString(),
+ // "--addDebugBreaks",
+ // "--fast",
+ // "--experimental",
+ // ]);
heapHelper.start([
- Platform.script.resolve("incremental_dart2js_tester.dart").toString(),
- "--fast",
- "--addDebugBreaks",
+ "--enable-asserts",
+ Platform.script.resolve("incremental_load_from_dill_suite.dart").toString(),
+ "-DaddDebugBreaks=true",
+ // "--",
+ // "incremental_load_from_dill/no_outline_change_...",
]);
}
diff --git a/pkg/front_end/test/vm_service_heap_finder.dart b/pkg/front_end/test/vm_service_heap_finder.dart
new file mode 100644
index 0000000..f199b1e
--- /dev/null
+++ b/pkg/front_end/test/vm_service_heap_finder.dart
@@ -0,0 +1,40 @@
+import "dart:io";
+import "vm_service_heap_helper.dart";
+
+class Foo {
+ final String x;
+ final int y;
+
+ Foo(this.x, this.y);
+}
+
+main() async {
+ List<Foo> foos = [];
+ foos.add(new Foo("hello", 42));
+ foos.add(new Foo("world", 43));
+ foos.add(new Foo("!", 44));
+ String connectTo = ask("Connect to");
+ VMServiceHeapHelperBase vm = VMServiceHeapHelperBase();
+ await vm.connect(Uri.parse(connectTo));
+ String isolateId = await vm.getIsolateId();
+ String classToFind = ask("Find what class");
+ await vm.printAllocationProfile(isolateId, filter: classToFind);
+ String fieldToFilter = ask("Filter on what field");
+ Set<String> fieldValues = {};
+ while (true) {
+ String fieldValue = ask("Look for value in field (empty to stop)");
+ if (fieldValue == "") break;
+ fieldValues.add(fieldValue);
+ }
+
+ await vm.filterAndPrintInstances(
+ isolateId, classToFind, fieldToFilter, fieldValues);
+
+ await vm.disconnect();
+ print("Disconnect done!");
+}
+
+String ask(String question) {
+ stdout.write("$question: ");
+ return stdin.readLineSync();
+}
diff --git a/pkg/front_end/test/vm_service_heap_helper.dart b/pkg/front_end/test/vm_service_heap_helper.dart
index b4a80f1..e23bdbd 100644
--- a/pkg/front_end/test/vm_service_heap_helper.dart
+++ b/pkg/front_end/test/vm_service_heap_helper.dart
@@ -1,4 +1,5 @@
import "dart:convert";
+import "dart:developer";
import "dart:io";
import "package:vm_service/vm_service.dart" as vmService;
@@ -6,230 +7,20 @@
import "dijkstras_sssp_algorithm.dart";
-class VMServiceHeapHelper {
- Process _process;
+class VMServiceHeapHelperBase {
vmService.VmService _serviceClient;
- bool _started = false;
- final Map<Uri, Map<String, List<String>>> _interests =
- new Map<Uri, Map<String, List<String>>>();
- final Map<Uri, Map<String, List<String>>> _prettyPrints =
- new Map<Uri, Map<String, List<String>>>();
- final bool throwOnPossibleLeak;
- VMServiceHeapHelper(List<Interest> interests, List<Interest> prettyPrints,
- this.throwOnPossibleLeak) {
- if (interests.isEmpty) throw "Empty list of interests given";
- for (Interest interest in interests) {
- Map<String, List<String>> classToFields = _interests[interest.uri];
- if (classToFields == null) {
- classToFields = Map<String, List<String>>();
- _interests[interest.uri] = classToFields;
- }
- List<String> fields = classToFields[interest.className];
- if (fields == null) {
- fields = new List<String>();
- classToFields[interest.className] = fields;
- }
- fields.addAll(interest.fieldNames);
- }
- for (Interest interest in prettyPrints) {
- Map<String, List<String>> classToFields = _prettyPrints[interest.uri];
- if (classToFields == null) {
- classToFields = Map<String, List<String>>();
- _prettyPrints[interest.uri] = classToFields;
- }
- List<String> fields = classToFields[interest.className];
- if (fields == null) {
- fields = new List<String>();
- classToFields[interest.className] = fields;
- }
- fields.addAll(interest.fieldNames);
- }
- }
+ VMServiceHeapHelperBase();
- void start(List<String> scriptAndArgs) async {
- if (_started) throw "Already started";
- _started = true;
- _process = await Process.start(
- Platform.resolvedExecutable,
- ["--pause_isolates_on_start", "--enable-vm-service=0"]
- ..addAll(scriptAndArgs));
- _process.stdout
- .transform(utf8.decoder)
- .transform(new LineSplitter())
- .listen((line) {
- const kObservatoryListening = 'Observatory listening on ';
- if (line.startsWith(kObservatoryListening)) {
- Uri observatoryUri =
- Uri.parse(line.substring(kObservatoryListening.length));
- _gotObservatoryUri(observatoryUri);
- }
- stdout.writeln("> $line");
- });
- _process.stderr
- .transform(utf8.decoder)
- .transform(new LineSplitter())
- .listen((line) {
- stderr.writeln("> $line");
- });
- }
-
- void _gotObservatoryUri(Uri observatoryUri) async {
+ Future connect(Uri observatoryUri) async {
String wsUriString =
'ws://${observatoryUri.authority}${observatoryUri.path}ws';
_serviceClient = await vmService.vmServiceConnectUri(wsUriString,
log: const StdOutLog());
- await _run();
}
- void _run() async {
- vmService.VM vm = await _serviceClient.getVM();
- if (vm.isolates.length != 1) {
- throw "Expected 1 isolate, got ${vm.isolates.length}";
- }
- vmService.IsolateRef isolateRef = vm.isolates.single;
- await _forceGC(isolateRef.id);
-
- assert(await _isPausedAtStart(isolateRef.id));
- await _serviceClient.resume(isolateRef.id);
-
- int iterationNumber = 1;
- while (true) {
- await _waitUntilPaused(isolateRef.id);
- print("Iteration: #$iterationNumber");
- iterationNumber++;
- await _forceGC(isolateRef.id);
-
- vmService.HeapSnapshotGraph heapSnapshotGraph =
- await vmService.HeapSnapshotGraph.getSnapshot(
- _serviceClient, isolateRef);
- HeapGraph graph = convertHeapGraph(heapSnapshotGraph);
-
- Set<String> seenPrints = {};
- Set<String> duplicatePrints = {};
- Map<String, List<HeapGraphElement>> groupedByToString = {};
- for (HeapGraphClassActual c in graph.classes) {
- Map<String, List<String>> interests = _interests[c.libraryUri];
- if (interests != null && interests.isNotEmpty) {
- List<String> fieldsToUse = interests[c.name];
- if (fieldsToUse != null && fieldsToUse.isNotEmpty) {
- for (HeapGraphElement instance in c.instances) {
- StringBuffer sb = new StringBuffer();
- sb.writeln("Instance: ${instance}");
- if (instance is HeapGraphElementActual) {
- for (String fieldName in fieldsToUse) {
- String prettyPrinted = instance
- .getField(fieldName)
- .getPrettyPrint(_prettyPrints);
- sb.writeln(" $fieldName: "
- "${prettyPrinted}");
- }
- }
- String sbToString = sb.toString();
- if (!seenPrints.add(sbToString)) {
- duplicatePrints.add(sbToString);
- }
- groupedByToString[sbToString] ??= [];
- groupedByToString[sbToString].add(instance);
- }
- }
- }
- }
- if (duplicatePrints.isNotEmpty) {
- print("======================================");
- print("WARNING: Duplicated pretty prints of objects.");
- print("This might be a memory leak!");
- print("");
- for (String s in duplicatePrints) {
- int count = groupedByToString[s].length;
- print("$s ($count)");
- print("");
- }
- print("======================================");
- for (String duplicateString in duplicatePrints) {
- print("$duplicateString:");
- List<HeapGraphElement> Function(HeapGraphElement target)
- dijkstraTarget = dijkstra(graph.elements.first, graph);
- for (HeapGraphElement duplicate
- in groupedByToString[duplicateString]) {
- print("${duplicate} pointed to from:");
- List<HeapGraphElement> shortestPath = dijkstraTarget(duplicate);
- for (int i = 0; i < shortestPath.length - 1; i++) {
- HeapGraphElement thisOne = shortestPath[i];
- HeapGraphElement nextOne = shortestPath[i + 1];
- String indexFieldName;
- if (thisOne is HeapGraphElementActual) {
- HeapGraphClass c = thisOne.class_;
- if (c is HeapGraphClassActual) {
- for (vmService.HeapSnapshotField field in c.origin.fields) {
- if (thisOne.references[field.index] == nextOne) {
- indexFieldName = field.name;
- }
- }
- }
- }
- if (indexFieldName == null) {
- indexFieldName = "no field found; index "
- "${thisOne.references.indexOf(nextOne)}";
- }
- print(" $thisOne -> $nextOne ($indexFieldName)");
- }
- print("---------------------------");
- }
- }
-
- if (throwOnPossibleLeak) throw "Possible leak detected.";
- }
- await _serviceClient.resume(isolateRef.id);
- }
- }
-
- List<HeapGraphElement> Function(HeapGraphElement target) dijkstra(
- HeapGraphElement source, HeapGraph heapGraph) {
- Map<HeapGraphElement, int> elementNum = {};
- Map<HeapGraphElement, GraphNode<HeapGraphElement>> elements = {};
- elements[heapGraph.elementSentinel] =
- new GraphNode<HeapGraphElement>(heapGraph.elementSentinel);
- elementNum[heapGraph.elementSentinel] = elements.length;
- for (HeapGraphElementActual element in heapGraph.elements) {
- elements[element] = new GraphNode<HeapGraphElement>(element);
- elementNum[element] = elements.length;
- }
-
- for (HeapGraphElementActual element in heapGraph.elements) {
- GraphNode<HeapGraphElement> node = elements[element];
- for (HeapGraphElement out in element.references) {
- node.addOutgoing(elements[out]);
- }
- }
-
- DijkstrasAlgorithm<HeapGraphElement> result =
- new DijkstrasAlgorithm<HeapGraphElement>(
- elements.values,
- elements[source],
- (HeapGraphElement a, HeapGraphElement b) {
- if (identical(a, b)) {
- throw "Comparing two identical ones was unexpected";
- }
- return elementNum[a] - elementNum[b];
- },
- (HeapGraphElement a, HeapGraphElement b) {
- if (identical(a, b)) return 0;
- // Prefer not to go via sentinel and via "Context".
- if (b is HeapGraphElementSentinel) return 100;
- HeapGraphElementActual bb = b;
- if (bb.class_ is HeapGraphClassSentinel) return 100;
- HeapGraphClassActual c = bb.class_;
- if (c.name == "Context") {
- if (c.libraryUri.toString().isEmpty) return 100;
- }
- return 1;
- },
- );
-
- return (HeapGraphElement target) {
- return result.getPathFromTarget(elements[source], elements[target]);
- };
+ Future disconnect() async {
+ await _serviceClient.dispose();
}
Future<void> _waitUntilPaused(String isolateId) async {
@@ -310,6 +101,329 @@
}
}
}
+
+ Future<void> printAllocationProfile(String isolateId, {String filter}) async {
+ await _waitUntilIsolateIsRunnable(isolateId);
+ vmService.AllocationProfile allocationProfile =
+ await _serviceClient.getAllocationProfile(isolateId);
+ for (vmService.ClassHeapStats member in allocationProfile.members) {
+ if (filter != null) {
+ if (member.classRef.name != filter) continue;
+ } else {
+ if (member.classRef.name == "") continue;
+ if (member.instancesCurrent == 0) continue;
+ }
+ vmService.Class c =
+ await _serviceClient.getObject(isolateId, member.classRef.id);
+ if (c.location?.script?.uri == null) continue;
+ print("${member.classRef.name}: ${member.instancesCurrent}");
+ }
+ }
+
+ Future<void> filterAndPrintInstances(String isolateId, String filter,
+ String fieldName, Set<String> fieldValues) async {
+ await _waitUntilIsolateIsRunnable(isolateId);
+ vmService.AllocationProfile allocationProfile =
+ await _serviceClient.getAllocationProfile(isolateId);
+ for (vmService.ClassHeapStats member in allocationProfile.members) {
+ if (member.classRef.name != filter) continue;
+ vmService.Class c =
+ await _serviceClient.getObject(isolateId, member.classRef.id);
+ if (c.location?.script?.uri == null) continue;
+ print("${member.classRef.name}: ${member.instancesCurrent}");
+ print(c.location.script.uri);
+
+ vmService.InstanceSet instances = await _serviceClient.getInstances(
+ isolateId, member.classRef.id, 10000);
+ int instanceNum = 0;
+ for (vmService.ObjRef instance in instances.instances) {
+ instanceNum++;
+ var receivedObject =
+ await _serviceClient.getObject(isolateId, instance.id);
+ if (receivedObject is! vmService.Instance) continue;
+ vmService.Instance object = receivedObject;
+ for (vmService.BoundField field in object.fields) {
+ if (field.decl.name == fieldName) {
+ if (field.value is vmService.Sentinel) continue;
+ var receivedValue =
+ await _serviceClient.getObject(isolateId, field.value.id);
+ if (receivedValue is! vmService.Instance) continue;
+ String value = (receivedValue as vmService.Instance).valueAsString;
+ if (!fieldValues.contains(value)) continue;
+ print("${instanceNum}: ${field.decl.name}: "
+ "${value} --- ${instance.id}");
+ }
+ }
+ }
+ }
+ print("Done!");
+ }
+
+ Future<String> getIsolateId() async {
+ vmService.VM vm = await _serviceClient.getVM();
+ if (vm.isolates.length != 1) {
+ throw "Expected 1 isolate, got ${vm.isolates.length}";
+ }
+ vmService.IsolateRef isolateRef = vm.isolates.single;
+ return isolateRef.id;
+ }
+}
+
+class VMServiceHeapHelper extends VMServiceHeapHelperBase {
+ Process _process;
+
+ bool _started = false;
+ final Map<Uri, Map<String, List<String>>> _interests =
+ new Map<Uri, Map<String, List<String>>>();
+ final Map<Uri, Map<String, List<String>>> _prettyPrints =
+ new Map<Uri, Map<String, List<String>>>();
+ final bool throwOnPossibleLeak;
+
+ VMServiceHeapHelper(List<Interest> interests, List<Interest> prettyPrints,
+ this.throwOnPossibleLeak) {
+ if (interests.isEmpty) throw "Empty list of interests given";
+ for (Interest interest in interests) {
+ Map<String, List<String>> classToFields = _interests[interest.uri];
+ if (classToFields == null) {
+ classToFields = Map<String, List<String>>();
+ _interests[interest.uri] = classToFields;
+ }
+ List<String> fields = classToFields[interest.className];
+ if (fields == null) {
+ fields = new List<String>();
+ classToFields[interest.className] = fields;
+ }
+ fields.addAll(interest.fieldNames);
+ }
+ for (Interest interest in prettyPrints) {
+ Map<String, List<String>> classToFields = _prettyPrints[interest.uri];
+ if (classToFields == null) {
+ classToFields = Map<String, List<String>>();
+ _prettyPrints[interest.uri] = classToFields;
+ }
+ List<String> fields = classToFields[interest.className];
+ if (fields == null) {
+ fields = new List<String>();
+ classToFields[interest.className] = fields;
+ }
+ fields.addAll(interest.fieldNames);
+ }
+ }
+
+ void start(List<String> scriptAndArgs) async {
+ if (_started) throw "Already started";
+ _started = true;
+ _process = await Process.start(
+ Platform.resolvedExecutable,
+ ["--pause_isolates_on_start", "--enable-vm-service=0"]
+ ..addAll(scriptAndArgs));
+ _process.stdout
+ .transform(utf8.decoder)
+ .transform(new LineSplitter())
+ .listen((line) {
+ const kObservatoryListening = 'Observatory listening on ';
+ if (line.startsWith(kObservatoryListening)) {
+ Uri observatoryUri =
+ Uri.parse(line.substring(kObservatoryListening.length));
+ _setupAndRun(observatoryUri);
+ }
+ stdout.writeln("> $line");
+ });
+ _process.stderr
+ .transform(utf8.decoder)
+ .transform(new LineSplitter())
+ .listen((line) {
+ stderr.writeln("> $line");
+ });
+ }
+
+ void _setupAndRun(Uri observatoryUri) async {
+ await connect(observatoryUri);
+ await _run();
+ }
+
+ void _run() async {
+ vmService.VM vm = await _serviceClient.getVM();
+ if (vm.isolates.length != 1) {
+ throw "Expected 1 isolate, got ${vm.isolates.length}";
+ }
+ vmService.IsolateRef isolateRef = vm.isolates.single;
+ await _forceGC(isolateRef.id);
+
+ assert(await _isPausedAtStart(isolateRef.id));
+ await _serviceClient.resume(isolateRef.id);
+
+ int iterationNumber = 1;
+ while (true) {
+ await _waitUntilPaused(isolateRef.id);
+ print("Iteration: #$iterationNumber");
+ iterationNumber++;
+ await _forceGC(isolateRef.id);
+
+ vmService.HeapSnapshotGraph heapSnapshotGraph =
+ await vmService.HeapSnapshotGraph.getSnapshot(
+ _serviceClient, isolateRef);
+ HeapGraph graph = convertHeapGraph(heapSnapshotGraph);
+
+ Set<String> seenPrints = {};
+ Set<String> duplicatePrints = {};
+ Map<String, List<HeapGraphElement>> groupedByToString = {};
+ for (HeapGraphClassActual c in graph.classes) {
+ Map<String, List<String>> interests = _interests[c.libraryUri];
+ if (interests != null && interests.isNotEmpty) {
+ List<String> fieldsToUse = interests[c.name];
+ if (fieldsToUse != null && fieldsToUse.isNotEmpty) {
+ for (HeapGraphElement instance in c.instances) {
+ StringBuffer sb = new StringBuffer();
+ sb.writeln("Instance: ${instance}");
+ if (instance is HeapGraphElementActual) {
+ for (String fieldName in fieldsToUse) {
+ String prettyPrinted = instance
+ .getField(fieldName)
+ .getPrettyPrint(_prettyPrints);
+ sb.writeln(" $fieldName: "
+ "${prettyPrinted}");
+ }
+ }
+ String sbToString = sb.toString();
+ if (!seenPrints.add(sbToString)) {
+ duplicatePrints.add(sbToString);
+ }
+ groupedByToString[sbToString] ??= [];
+ groupedByToString[sbToString].add(instance);
+ }
+ }
+ }
+ }
+ if (duplicatePrints.isNotEmpty) {
+ print("======================================");
+ print("WARNING: Duplicated pretty prints of objects.");
+ print("This might be a memory leak!");
+ print("");
+ for (String s in duplicatePrints) {
+ int count = groupedByToString[s].length;
+ print("$s ($count)");
+ print("");
+ }
+ print("======================================");
+ for (String duplicateString in duplicatePrints) {
+ print("$duplicateString:");
+ List<HeapGraphElement> Function(HeapGraphElement target)
+ dijkstraTarget = dijkstra(graph.elements.first, graph);
+ for (HeapGraphElement duplicate
+ in groupedByToString[duplicateString]) {
+ print("${duplicate} pointed to from:");
+ print(duplicate.getPrettyPrint(_prettyPrints));
+ List<HeapGraphElement> shortestPath = dijkstraTarget(duplicate);
+ for (int i = 0; i < shortestPath.length - 1; i++) {
+ HeapGraphElement thisOne = shortestPath[i];
+ HeapGraphElement nextOne = shortestPath[i + 1];
+ String indexFieldName;
+ if (thisOne is HeapGraphElementActual) {
+ HeapGraphClass c = thisOne.class_;
+ if (c is HeapGraphClassActual) {
+ for (vmService.HeapSnapshotField field in c.origin.fields) {
+ if (thisOne.references[field.index] == nextOne) {
+ indexFieldName = field.name;
+ }
+ }
+ }
+ }
+ if (indexFieldName == null) {
+ indexFieldName = "no field found; index "
+ "${thisOne.references.indexOf(nextOne)}";
+ }
+ print(" $thisOne -> $nextOne ($indexFieldName)");
+ }
+ print("---------------------------");
+ }
+ }
+
+ if (throwOnPossibleLeak) {
+ debugger();
+ throw "Possible leak detected.";
+ }
+ }
+ await _serviceClient.resume(isolateRef.id);
+ }
+ }
+
+ List<HeapGraphElement> Function(HeapGraphElement target) dijkstra(
+ HeapGraphElement source, HeapGraph heapGraph) {
+ Map<HeapGraphElement, int> elementNum = {};
+ Map<HeapGraphElement, GraphNode<HeapGraphElement>> elements = {};
+ elements[heapGraph.elementSentinel] =
+ new GraphNode<HeapGraphElement>(heapGraph.elementSentinel);
+ elementNum[heapGraph.elementSentinel] = elements.length;
+ for (HeapGraphElementActual element in heapGraph.elements) {
+ elements[element] = new GraphNode<HeapGraphElement>(element);
+ elementNum[element] = elements.length;
+ }
+
+ for (HeapGraphElementActual element in heapGraph.elements) {
+ GraphNode<HeapGraphElement> node = elements[element];
+ for (HeapGraphElement out in element.references) {
+ node.addOutgoing(elements[out]);
+ }
+ }
+
+ DijkstrasAlgorithm<HeapGraphElement> result =
+ new DijkstrasAlgorithm<HeapGraphElement>(
+ elements.values,
+ elements[source],
+ (HeapGraphElement a, HeapGraphElement b) {
+ if (identical(a, b)) {
+ throw "Comparing two identical ones was unexpected";
+ }
+ return elementNum[a] - elementNum[b];
+ },
+ (HeapGraphElement a, HeapGraphElement b) {
+ if (identical(a, b)) return 0;
+
+ // Prefer going via actual field.
+ if (a is HeapGraphElementActual) {
+ HeapGraphClass c = a.class_;
+ if (c is HeapGraphClassActual) {
+ for (vmService.HeapSnapshotField field in c.origin.fields) {
+ if (a.references[field.index] == b) {
+ // Via actual field!
+ return 1;
+ }
+ }
+ }
+ }
+
+ // Prefer not to go directly from HeapGraphClassSentinel to Procedure.
+ if (a is HeapGraphElementActual && b is HeapGraphElementActual) {
+ HeapGraphElementActual aa = a;
+ HeapGraphElementActual bb = b;
+ if (aa.class_ is HeapGraphClassSentinel &&
+ bb.class_ is HeapGraphClassActual) {
+ HeapGraphClassActual c = bb.class_;
+ if (c.name == "Procedure") {
+ return 1000;
+ }
+ }
+ }
+
+ // Prefer not to go via sentinel and via "Context".
+ if (b is HeapGraphElementSentinel) return 100;
+ HeapGraphElementActual bb = b;
+ if (bb.class_ is HeapGraphClassSentinel) return 100;
+ HeapGraphClassActual c = bb.class_;
+ if (c.name == "Context") {
+ if (c.libraryUri.toString().isEmpty) return 100;
+ }
+
+ // Not via actual field.
+ return 10;
+ },
+ );
+
+ return (HeapGraphElement target) {
+ return result.getPathFromTarget(elements[source], elements[target]);
+ };
+ }
}
class Interest {
@@ -412,7 +526,8 @@
if (fields != null) {
return "${c.name}[" +
fields.map((field) {
- return "$field: ${me.getField(field).getPrettyPrint(prettyPrints)}";
+ return "$field: "
+ "${me.getField(field).getPrettyPrint(prettyPrints)}";
}).join(", ") +
"]";
}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_18.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_18.yaml
index 5016781..c7db57e 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_18.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_18.yaml
@@ -41,4 +41,4 @@
print("exports!")
}
expectedLibraryCount: 3
- expectsRebuildBodiesOnly: true
+ expectsRebuildBodiesOnly: false # For now, libraries with errors cannot have bodies rebuild.
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_25.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_25.yaml
index 6ada515..b561e9d 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_25.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_25.yaml
@@ -48,4 +48,4 @@
}
}
expectedLibraryCount: 1
- expectsRebuildBodiesOnly: true
+ expectsRebuildBodiesOnly: false # For now, libraries with errors cannot have bodies rebuild.
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_26.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_26.yaml
index 5f07ff2..9986dfb 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_26.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_26.yaml
@@ -40,4 +40,4 @@
new A1.foo();
}
expectedLibraryCount: 1
- expectsRebuildBodiesOnly: true
+ expectsRebuildBodiesOnly: false # For now, libraries with errors cannot have bodies rebuild.
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_34.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_34.yaml
index 1771b25..eaa4d06 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_34.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_34.yaml
@@ -95,7 +95,6 @@
}
expectedLibraryCount: 3
expectsRebuildBodiesOnly: true
-
- entry: main.dart
useExperimentalInvalidation: true
worldType: updated
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_34.yaml.world.4.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_34.yaml.world.4.expect
index 52f52b5..366f447 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_34.yaml.world.4.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_34.yaml.world.4.expect
@@ -1,6 +1,8 @@
main = <No Member>;
library from "org-dartlang-test:///lib1.dart" as lib1 {
-additionalExports = (main::main,
+additionalExports = (main::Extension|get#method,
+ main::Extension|method,
+ main::main,
main::Class,
main::Extension)
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml
new file mode 100644
index 0000000..d3b6f53
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml
@@ -0,0 +1,81 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Compile an application, change a file, but don't change the outline.
+# Test FFI compilation.
+
+type: newworld
+worlds:
+ - entry: main.dart
+ useExperimentalInvalidation: true
+ sources:
+ main.dart: |
+ import 'lib.dart';
+
+ main() {
+ Coordinate coordinate = new Coordinate.allocate(42.0, 42.0, null);
+ print(coordinate.x);
+ print(coordinate.y);
+ print(coordinate.next);
+ }
+ lib.dart: |
+ import 'dart:ffi';
+ class Coordinate extends Struct {
+ @Double()
+ double x;
+
+ @Double()
+ double y;
+
+ Pointer<Coordinate> next;
+
+ factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
+ return null;
+ }
+ }
+ expectedLibraryCount: 2
+ - entry: main.dart
+ useExperimentalInvalidation: true
+ worldType: updated
+ expectInitializeFromDill: false
+ invalidate:
+ - main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+
+ main() {
+ Coordinate coordinate = new Coordinate.allocate(42.0, 42.0, null);
+ print(coordinate.x);
+ print(coordinate.y);
+ print(coordinate.next);
+ print("Done!");
+ }
+ expectedLibraryCount: 2
+ expectsRebuildBodiesOnly: true
+ - entry: main.dart
+ useExperimentalInvalidation: true
+ worldType: updated
+ expectInitializeFromDill: false
+ invalidate:
+ - lib.dart
+ sources:
+ lib.dart: |
+ import 'dart:ffi';
+ class Coordinate extends Struct {
+ @Double()
+ double x;
+
+ @Double()
+ double y;
+
+ Pointer<Coordinate> next;
+
+ factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
+ print("hello");
+ return null;
+ }
+ }
+ expectedLibraryCount: 2
+ expectsRebuildBodiesOnly: true
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect
new file mode 100644
index 0000000..748c4c0
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect
@@ -0,0 +1,60 @@
+main = <No Member>;
+library from "org-dartlang-test:///lib.dart" as lib {
+
+ import "dart:ffi";
+
+ @#C3
+ class Coordinate extends dart.ffi::Struct {
+ @#C3
+ static final field dart.core::int* #sizeOf = (#C6).{dart.core::List::[]}(dart.ffi::_abi());
+ @#C3
+ constructor #fromPointer(dynamic #pointer) → dynamic
+ : super dart.ffi::Struct::_fromPointer(#pointer)
+ ;
+ static factory allocate(dart.core::double* x, dart.core::double* y, dart.ffi::Pointer<lib::Coordinate*>* next) → lib::Coordinate* {
+ return null;
+ }
+ get #_ptr_x() → dart.ffi::Pointer<dart.ffi::Double*>*
+ return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
+ get x() → dart.core::double*
+ return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_x}, #C7);
+ set x(dart.core::double* #v) → void
+ return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_x}, #C7, #v);
+ get #_ptr_y() → dart.ffi::Pointer<dart.ffi::Double*>*
+ return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C9).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
+ get y() → dart.core::double*
+ return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_y}, #C7);
+ set y(dart.core::double* #v) → void
+ return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_y}, #C7, #v);
+ get #_ptr_next() → dart.ffi::Pointer<dart.ffi::Pointer<lib::Coordinate*>*>*
+ return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C11).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Pointer<lib::Coordinate*>*>();
+ get next() → dart.ffi::Pointer<lib::Coordinate*>*
+ return dart.ffi::_loadPointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7);
+ set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
+ return dart.ffi::_storePointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7, #v);
+ }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+ import "org-dartlang-test:///lib.dart";
+
+ static method main() → dynamic {
+ lib::Coordinate* coordinate = lib::Coordinate::allocate(42.0, 42.0, null);
+ dart.core::print(coordinate.{lib::Coordinate::x});
+ dart.core::print(coordinate.{lib::Coordinate::y});
+ dart.core::print(coordinate.{lib::Coordinate::next});
+ }
+}
+constants {
+ #C1 = "vm:entry-point"
+ #C2 = null
+ #C3 = dart.core::pragma {name:#C1, options:#C2}
+ #C4 = 24
+ #C5 = 20
+ #C6 = <dart.core::int*>[#C4, #C5, #C4]
+ #C7 = 0
+ #C8 = 8
+ #C9 = <dart.core::int*>[#C8, #C8, #C8]
+ #C10 = 16
+ #C11 = <dart.core::int*>[#C10, #C10, #C10]
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect
new file mode 100644
index 0000000..b1805b0
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect
@@ -0,0 +1,61 @@
+main = <No Member>;
+library from "org-dartlang-test:///lib.dart" as lib {
+
+ import "dart:ffi";
+
+ @#C3
+ class Coordinate extends dart.ffi::Struct {
+ @#C3
+ static final field dart.core::int* #sizeOf = (#C6).{dart.core::List::[]}(dart.ffi::_abi());
+ @#C3
+ constructor #fromPointer(dynamic #pointer) → dynamic
+ : super dart.ffi::Struct::_fromPointer(#pointer)
+ ;
+ static factory allocate(dart.core::double* x, dart.core::double* y, dart.ffi::Pointer<lib::Coordinate*>* next) → lib::Coordinate* {
+ return null;
+ }
+ get #_ptr_x() → dart.ffi::Pointer<dart.ffi::Double*>*
+ return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
+ get x() → dart.core::double*
+ return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_x}, #C7);
+ set x(dart.core::double* #v) → void
+ return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_x}, #C7, #v);
+ get #_ptr_y() → dart.ffi::Pointer<dart.ffi::Double*>*
+ return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C9).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
+ get y() → dart.core::double*
+ return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_y}, #C7);
+ set y(dart.core::double* #v) → void
+ return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_y}, #C7, #v);
+ get #_ptr_next() → dart.ffi::Pointer<dart.ffi::Pointer<lib::Coordinate*>*>*
+ return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C11).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Pointer<lib::Coordinate*>*>();
+ get next() → dart.ffi::Pointer<lib::Coordinate*>*
+ return dart.ffi::_loadPointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7);
+ set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
+ return dart.ffi::_storePointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7, #v);
+ }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+ import "org-dartlang-test:///lib.dart";
+
+ static method main() → dynamic {
+ lib::Coordinate* coordinate = lib::Coordinate::allocate(42.0, 42.0, null);
+ dart.core::print(coordinate.{lib::Coordinate::x});
+ dart.core::print(coordinate.{lib::Coordinate::y});
+ dart.core::print(coordinate.{lib::Coordinate::next});
+ dart.core::print("Done!");
+ }
+}
+constants {
+ #C1 = "vm:entry-point"
+ #C2 = null
+ #C3 = dart.core::pragma {name:#C1, options:#C2}
+ #C4 = 24
+ #C5 = 20
+ #C6 = <dart.core::int*>[#C4, #C5, #C4]
+ #C7 = 0
+ #C8 = 8
+ #C9 = <dart.core::int*>[#C8, #C8, #C8]
+ #C10 = 16
+ #C11 = <dart.core::int*>[#C10, #C10, #C10]
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect
new file mode 100644
index 0000000..32cc854
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect
@@ -0,0 +1,62 @@
+main = <No Member>;
+library from "org-dartlang-test:///lib.dart" as lib {
+
+ import "dart:ffi";
+
+ @#C3
+ class Coordinate extends dart.ffi::Struct {
+ @#C3
+ static final field dart.core::int* #sizeOf = (#C6).{dart.core::List::[]}(dart.ffi::_abi());
+ @#C3
+ constructor #fromPointer(dynamic #pointer) → dynamic
+ : super dart.ffi::Struct::_fromPointer(#pointer)
+ ;
+ static factory allocate(dart.core::double* x, dart.core::double* y, dart.ffi::Pointer<lib::Coordinate*>* next) → lib::Coordinate* {
+ dart.core::print("hello");
+ return null;
+ }
+ get #_ptr_x() → dart.ffi::Pointer<dart.ffi::Double*>*
+ return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
+ get x() → dart.core::double*
+ return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_x}, #C7);
+ set x(dart.core::double* #v) → void
+ return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_x}, #C7, #v);
+ get #_ptr_y() → dart.ffi::Pointer<dart.ffi::Double*>*
+ return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C9).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
+ get y() → dart.core::double*
+ return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_y}, #C7);
+ set y(dart.core::double* #v) → void
+ return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_y}, #C7, #v);
+ get #_ptr_next() → dart.ffi::Pointer<dart.ffi::Pointer<lib::Coordinate*>*>*
+ return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C11).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Pointer<lib::Coordinate*>*>();
+ get next() → dart.ffi::Pointer<lib::Coordinate*>*
+ return dart.ffi::_loadPointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7);
+ set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
+ return dart.ffi::_storePointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7, #v);
+ }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+ import "org-dartlang-test:///lib.dart";
+
+ static method main() → dynamic {
+ lib::Coordinate* coordinate = lib::Coordinate::allocate(42.0, 42.0, null);
+ dart.core::print(coordinate.{lib::Coordinate::x});
+ dart.core::print(coordinate.{lib::Coordinate::y});
+ dart.core::print(coordinate.{lib::Coordinate::next});
+ dart.core::print("Done!");
+ }
+}
+constants {
+ #C1 = "vm:entry-point"
+ #C2 = null
+ #C3 = dart.core::pragma {name:#C1, options:#C2}
+ #C4 = 24
+ #C5 = 20
+ #C6 = <dart.core::int*>[#C4, #C5, #C4]
+ #C7 = 0
+ #C8 = 8
+ #C9 = <dart.core::int*>[#C8, #C8, #C8]
+ #C10 = 16
+ #C11 = <dart.core::int*>[#C10, #C10, #C10]
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml
index 8aa50fc..96943e2 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml
@@ -61,7 +61,7 @@
enum CompilationStrategy { direct, toKernel, toData, fromData }
expectedLibraryCount: 2
- expectsRebuildBodiesOnly: true
+ expectsRebuildBodiesOnly: false # For now, libraries with errors cannot have bodies rebuild.
- entry: main.dart
useExperimentalInvalidation: true
worldType: updated
@@ -88,4 +88,4 @@
enum CompilationStrategy { direct, toKernel, toData, fromData }
expectedLibraryCount: 2
- expectsRebuildBodiesOnly: true
+ expectsRebuildBodiesOnly: false # For now, libraries with errors cannot have bodies rebuild.
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/status.status b/pkg/front_end/testcases/incremental_initialize_from_dill/status.status
index 4874153..3cae5cc 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/status.status
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/status.status
@@ -3,19 +3,3 @@
# BSD-style license that can be found in the LICENSE.md file.
# Status file for the test suite ../test/incremental_load_from_dill_test.dart.
-
-no_outline_change_1: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_2: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_6: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_7: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_9: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_10: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_11: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_12: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_13: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_14: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_21: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_24: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_27: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_33: Crash # Doesn't work on DillLibraryBuilders.
-no_outline_change_34: Crash # Doesn't work on DillLibraryBuilders.