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 562615e72ba..818480ab85b 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/builder.dart'; 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 @@ class DillLibraryBuilder extends LibraryBuilderImpl { /// [../kernel/kernel_library_builder.dart]. Map 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 @@ class DillLibraryBuilder extends LibraryBuilderImpl { exportScopeBuilder.addMember(name, declaration); }); + Map 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); - } - if (declaration == null) { - internalProblem( - templateUnspecified.withArguments( - "Exported element '$name' not found in '$libraryUri'."), - -1, - fileUri); + 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); + } } + 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 3d91dbd086f..0ce2b6638fa 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 '../loader.dart' show Loader; 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_library_builder.dart' show DillLibraryBuilder; import 'dill_target.dart' show DillTarget; class DillLoader extends Loader { + SourceLoader currentSourceLoader; + DillLoader(TargetImplementation target) : super(target); Template 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 859942918dc..b58f3415a5a 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 @@ class IncrementalCompiler implements IncrementalKernelGenerator { List platformBuilders; Map userBuilders; final Uri initializeFromDillUri; - final Component componentToInitializeFrom; + Component componentToInitializeFrom; bool initializedFromDill = false; bool initializedIncrementalSerializer = false; Uri previousPackagesUri; @@ -213,13 +213,14 @@ class IncrementalCompiler implements IncrementalKernelGenerator { KernelTarget userCodeOld = userCode; setupNewUserCode(c, uriTranslator, hierarchy, reusedLibraries, experimentalInvalidation, entryPoints.first); - Map> rebuildBodiesMap = + Map> 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 @@ class IncrementalCompiler implements IncrementalKernelGenerator { 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 @@ class IncrementalCompiler implements IncrementalKernelGenerator { /// 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> convertSourceLibraryBuildersToDill() async { + Future> convertSourceLibraryBuildersToDill( + ExperimentalInvalidation experimentalInvalidation) async { bool changed = false; Set newDillLibraryBuilders = new Set(); userBuilders ??= {}; + Map> convertedLibraries; for (MapEntry entry in userCode.loader.builders.entries) { if (entry.value is SourceLibraryBuilder) { @@ -309,14 +320,53 @@ class IncrementalCompiler implements IncrementalKernelGenerator { 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>(); + 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> replacementMap = {}; + + // Maps from old library builder to map of new content. + Map> 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 @@ class IncrementalCompiler implements IncrementalKernelGenerator { /// Fill in the replacement maps that describe the replacements that need to /// happen because of experimental invalidation. void experimentalInvalidationFillReplacementMaps( - Map> rebuildBodiesMap, + Map> rebuildBodiesMap, Map> replacementMap, Map> replacementSettersMap) { - for (MapEntry> entry + for (MapEntry> entry in rebuildBodiesMap.entries) { Map childReplacementMap = {}; Map childReplacementSettersMap = {}; - List builders = rebuildBodiesMap[entry.key]; + List 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 @@ class IncrementalCompiler implements IncrementalKernelGenerator { /// 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> + Map> 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> rebuildBodiesMap = - new Map>.identity(); + Map> rebuildBodiesMap = + new Map>.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 builders = [newBuilder]; + List 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 @@ class IncrementalCompiler implements IncrementalKernelGenerator { /// didn't do anything special. void experimentalInvalidationPatchUpScopes( ExperimentalInvalidation experimentalInvalidation, - Map> rebuildBodiesMap) { + Map> rebuildBodiesMap) { if (experimentalInvalidation != null) { // Maps from old library builder to map of new content. Map> replacementMap = {}; @@ -557,8 +607,16 @@ class IncrementalCompiler implements IncrementalKernelGenerator { } } } + } 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 @@ class IncrementalCompiler implements IncrementalKernelGenerator { 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 @@ class IncrementalCompiler implements IncrementalKernelGenerator { // 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 iterator = builder.iterator; while (iterator.moveNext()) { Builder childBuilder = iterator.current; @@ -866,6 +929,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator { // 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 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 dc904d839ac..65e40438532 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 @@ import 'package:kernel/ast.dart' Nullability, Procedure, ProcedureKind, + Reference, SetLiteral, StaticInvocation, StringLiteral, Supertype, - Typedef, TypeParameter, TypeParameterType, + Typedef, VariableDeclaration, VoidType; @@ -774,13 +775,18 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { } } - 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 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { // 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 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { members.forEach(setParentAndCheckConflicts); constructors.forEach(setParentAndCheckConflicts); setters.forEach(setParentAndCheckConflicts); - addBuilder(className, classBuilder, nameOffset); + addBuilder(className, classBuilder, nameOffset, + reference: referencesFromClass?.reference); } Map checkTypeVariables( @@ -1668,7 +1678,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { 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 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { // 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 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { 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 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { 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 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { 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 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { 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 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { charEndOffset, referencesFromClass, referencesFromIndexedClass); - addBuilder(name, builder, charOffset); + addBuilder(name, builder, charOffset, + reference: referencesFromClass?.reference); metadataCollector?.setDocumentationComment( builder.cls, documentationComment); } @@ -2379,7 +2396,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { // 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 9a798678b66..9d3b7d3ae94 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 @@ import 'package:kernel/ast.dart' LibraryDependency, Nullability, ProcedureKind, + Reference, Supertype, TreeNode; @@ -152,6 +153,11 @@ class SourceLoader extends Loader { 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 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 a6c7251c329..7cb4916d65c 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 'dart:io' show File; 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 @@ String textualOutline(List rawBytes, {bool makeMoreReadable: false}) { 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 @@ String textualOutline(List rawBytes, {bool makeMoreReadable: false}) { 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 @@ main(List args) { } class EndOffsetListener extends DirectiveListener { - Set endOffsets = new Set(); + Set nonClassEndOffsets = new Set(); + Set classEndOffsets = new Set(); @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 0eb21c7a3b8..b8f8b479ede 100644 --- a/pkg/front_end/test/incremental_dart2js_tester.dart +++ b/pkg/front_end/test/incremental_dart2js_tester.dart @@ -31,58 +31,50 @@ main(List args) async { } } - 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 firstCompileData; Map> 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 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 uris = c.uriToSource.values - .map((s) => s != null ? s.importUri : null) - .where((u) => u != null && u.scheme != "dart") - .toSet() - .toList(); - - c = null; + List uris; List diffs = new List(); Set componentUris = new Set(); - 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(); + componentUris = new Set(); + + 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 @@ main(List args) async { print("-----"); } - print("A total of ${diffs.length} diffs:"); - for (Uri uri in diffs) { - print(" - $uri"); + Future 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 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 a, List 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 a, List 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 79b25aa0f4c..97a33b5b620 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 @@ class RunCompilations extends Step { "forceLateLoweringForTesting", "incrementalSerialization" ]); - await newWorldTest( + await new NewWorldTest().newWorldTest( data, context, map["worlds"], @@ -317,519 +317,542 @@ Future>> createModules( return moduleResult; } -Future 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 sdkSummaryData = - await new File.fromUri(platformUri).readAsBytes(); - - List 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 sourceFiles; - CompilerOptions options; - TestIncrementalCompiler compiler; - IncrementalSerializer incrementalSerializer; - - Map> moduleData; - Map 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 modulesToUse; - if (world["modules"] != null) { - moduleComponents ??= new Map(); + Future 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 sdkSummaryData = + await new File.fromUri(platformUri).readAsBytes(); - sdk.adoptChildren(); - for (Component c in moduleComponents.values) { - c.adoptChildren(); - } + List newestWholeComponentData; + MemoryFileSystem fs; + Map sourceFiles; + CompilerOptions options; + TestIncrementalCompiler compiler; + IncrementalSerializer incrementalSerializer; - modulesToUse = new List(); - for (String moduleName in world["modules"]) { - Component moduleComponent = moduleComponents[moduleName]; - if (moduleComponent != null) { - modulesToUse.add(moduleComponent); + Map> moduleData; + Map 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 modulesToUse; + if (world["modules"] != null) { + moduleComponents ??= new Map(); + + sdk.adoptChildren(); + for (Component c in moduleComponents.values) { + c.adoptChildren(); + } + + modulesToUse = new List(); + 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.from(world["sources"]); - } else { - sourceFiles.addAll( - new Map.from(world["sources"] ?? {})); - } - 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 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 formattedErrors = Set(); - bool gotWarning = false; - final Set formattedWarnings = Set(); - - 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 entries; - if (world["entry"] is String) { - entries = [base.resolve(world["entry"])]; - } else { - entries = new List(); - List 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.from(world["sources"]); } else { - compiler = new TestIncrementalCompiler(options, entries.first, - initializeFrom, outlineOnly, incrementalSerializer); + sourceFiles.addAll(new Map.from( + world["sources"] ?? {})); + } + 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 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 invalidated = new List(); - 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 formattedErrors = Set(); + bool gotWarning = false; + final Set formattedWarnings = Set(); - 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 entries; + if (world["entry"] is String) { + entries = [base.resolve(world["entry"])]; + } else { + entries = new List(); + List 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 invalidated = new List(); + 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 allLibraries = new Set(); + 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 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 allLibraries = new Set(); - 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 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 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 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 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 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 incrementalSerializationBytes = checkIncrementalSerialization( - incrementalSerialization, component, incrementalSerializer, world); - - Set prevFormattedErrors = formattedErrors.toSet(); - Set 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 thisWholeComponent = util.postProcess(component2); - print("*****\n\ncomponent2:\n" - "${componentToStringSdkFiltered(component2)}\n\n\n"); - checkIsEqual(newestWholeComponentData, thisWholeComponent); - checkErrorsAndWarnings(prevFormattedErrors, formattedErrors, - prevFormattedWarnings, formattedWarnings); - - List 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 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 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 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 incrementalSerializationBytes = checkIncrementalSerialization( + incrementalSerialization, component, incrementalSerializer, world); - if (context.breakBetween) { - debugger(); - print("Continuing after debug break"); + Set prevFormattedErrors = formattedErrors.toSet(); + Set 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 thisWholeComponent = util.postProcess(component2); + print("*****\n\ncomponent2:\n" + "${componentToStringSdkFiltered(component2)}\n\n\n"); + checkIsEqual(newestWholeComponentData, thisWholeComponent); + checkErrorsAndWarnings(prevFormattedErrors, formattedErrors, + prevFormattedWarnings, formattedWarnings); + newestWholeComponent = component2; + + List 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 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 @@ Map> buildMapOfContent(Component component) { 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 ef6d66dc3a1..ac51d6152d4 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 @@ deleting depended depfile desc +detector deviation dfast dictionaries @@ -138,6 +139,7 @@ disallowed disconnect discovering dispatcher +dispose dist doctype doesnt @@ -185,6 +187,7 @@ finder fisk five floor +foos forbidden forces foreign @@ -381,6 +384,7 @@ splay 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 7d3c6baf754..040e1d5a25a 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 @@ main(List args) async { ["_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 00000000000..f199b1eca57 --- /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 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 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 b4a80f1b9f2..e23bdbd705c 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 "package:vm_service/vm_service_io.dart" as vmService; import "dijkstras_sssp_algorithm.dart"; -class VMServiceHeapHelper { - Process _process; +class VMServiceHeapHelperBase { vmService.VmService _serviceClient; - bool _started = false; - final Map>> _interests = - new Map>>(); - final Map>> _prettyPrints = - new Map>>(); - final bool throwOnPossibleLeak; - VMServiceHeapHelper(List interests, List prettyPrints, - this.throwOnPossibleLeak) { - if (interests.isEmpty) throw "Empty list of interests given"; - for (Interest interest in interests) { - Map> classToFields = _interests[interest.uri]; - if (classToFields == null) { - classToFields = Map>(); - _interests[interest.uri] = classToFields; - } - List fields = classToFields[interest.className]; - if (fields == null) { - fields = new List(); - classToFields[interest.className] = fields; - } - fields.addAll(interest.fieldNames); - } - for (Interest interest in prettyPrints) { - Map> classToFields = _prettyPrints[interest.uri]; - if (classToFields == null) { - classToFields = Map>(); - _prettyPrints[interest.uri] = classToFields; - } - List fields = classToFields[interest.className]; - if (fields == null) { - fields = new List(); - classToFields[interest.className] = fields; - } - fields.addAll(interest.fieldNames); - } - } + VMServiceHeapHelperBase(); - void start(List 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 seenPrints = {}; - Set duplicatePrints = {}; - Map> groupedByToString = {}; - for (HeapGraphClassActual c in graph.classes) { - Map> interests = _interests[c.libraryUri]; - if (interests != null && interests.isNotEmpty) { - List 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 Function(HeapGraphElement target) - dijkstraTarget = dijkstra(graph.elements.first, graph); - for (HeapGraphElement duplicate - in groupedByToString[duplicateString]) { - print("${duplicate} pointed to from:"); - List 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 Function(HeapGraphElement target) dijkstra( - HeapGraphElement source, HeapGraph heapGraph) { - Map elementNum = {}; - Map> elements = {}; - elements[heapGraph.elementSentinel] = - new GraphNode(heapGraph.elementSentinel); - elementNum[heapGraph.elementSentinel] = elements.length; - for (HeapGraphElementActual element in heapGraph.elements) { - elements[element] = new GraphNode(element); - elementNum[element] = elements.length; - } - - for (HeapGraphElementActual element in heapGraph.elements) { - GraphNode node = elements[element]; - for (HeapGraphElement out in element.references) { - node.addOutgoing(elements[out]); - } - } - - DijkstrasAlgorithm result = - new DijkstrasAlgorithm( - 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 _waitUntilPaused(String isolateId) async { @@ -310,6 +101,329 @@ class VMServiceHeapHelper { } } } + + Future 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 filterAndPrintInstances(String isolateId, String filter, + String fieldName, Set 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 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>> _interests = + new Map>>(); + final Map>> _prettyPrints = + new Map>>(); + final bool throwOnPossibleLeak; + + VMServiceHeapHelper(List interests, List prettyPrints, + this.throwOnPossibleLeak) { + if (interests.isEmpty) throw "Empty list of interests given"; + for (Interest interest in interests) { + Map> classToFields = _interests[interest.uri]; + if (classToFields == null) { + classToFields = Map>(); + _interests[interest.uri] = classToFields; + } + List fields = classToFields[interest.className]; + if (fields == null) { + fields = new List(); + classToFields[interest.className] = fields; + } + fields.addAll(interest.fieldNames); + } + for (Interest interest in prettyPrints) { + Map> classToFields = _prettyPrints[interest.uri]; + if (classToFields == null) { + classToFields = Map>(); + _prettyPrints[interest.uri] = classToFields; + } + List fields = classToFields[interest.className]; + if (fields == null) { + fields = new List(); + classToFields[interest.className] = fields; + } + fields.addAll(interest.fieldNames); + } + } + + void start(List 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 seenPrints = {}; + Set duplicatePrints = {}; + Map> groupedByToString = {}; + for (HeapGraphClassActual c in graph.classes) { + Map> interests = _interests[c.libraryUri]; + if (interests != null && interests.isNotEmpty) { + List 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 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 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 Function(HeapGraphElement target) dijkstra( + HeapGraphElement source, HeapGraph heapGraph) { + Map elementNum = {}; + Map> elements = {}; + elements[heapGraph.elementSentinel] = + new GraphNode(heapGraph.elementSentinel); + elementNum[heapGraph.elementSentinel] = elements.length; + for (HeapGraphElementActual element in heapGraph.elements) { + elements[element] = new GraphNode(element); + elementNum[element] = elements.length; + } + + for (HeapGraphElementActual element in heapGraph.elements) { + GraphNode node = elements[element]; + for (HeapGraphElement out in element.references) { + node.addOutgoing(elements[out]); + } + } + + DijkstrasAlgorithm result = + new DijkstrasAlgorithm( + 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 @@ abstract class HeapGraphElement { 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 5016781a63f..c7db57e205f 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 @@ worlds: 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 6ada515f21e..b561e9d4877 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 @@ worlds: } } 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 5f07ff25f54..9986dfb54f5 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 @@ worlds: 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 1771b2506bd..eaa4d068bed 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 @@ worlds: } 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 52f52b557fc..366f4470b57 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 = ; 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 00000000000..d3b6f537110 --- /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 next; + + factory Coordinate.allocate(double x, double y, Pointer 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 next; + + factory Coordinate.allocate(double x, double y, Pointer 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 00000000000..748c4c00a63 --- /dev/null +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect @@ -0,0 +1,60 @@ +main = ; +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* next) → lib::Coordinate* { + return null; + } + get #_ptr_x() → dart.ffi::Pointer* + return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::cast}(); + 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* + return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C9).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}(); + 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*>* + return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C11).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}*>(); + get next() → dart.ffi::Pointer* + return dart.ffi::_loadPointer*>(this.{lib::Coordinate::#_ptr_next}, #C7); + set next(dart.ffi::Pointer* #v) → void + return dart.ffi::_storePointer*>(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 = [#C4, #C5, #C4] + #C7 = 0 + #C8 = 8 + #C9 = [#C8, #C8, #C8] + #C10 = 16 + #C11 = [#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 00000000000..b1805b0d47f --- /dev/null +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect @@ -0,0 +1,61 @@ +main = ; +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* next) → lib::Coordinate* { + return null; + } + get #_ptr_x() → dart.ffi::Pointer* + return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::cast}(); + 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* + return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C9).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}(); + 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*>* + return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C11).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}*>(); + get next() → dart.ffi::Pointer* + return dart.ffi::_loadPointer*>(this.{lib::Coordinate::#_ptr_next}, #C7); + set next(dart.ffi::Pointer* #v) → void + return dart.ffi::_storePointer*>(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 = [#C4, #C5, #C4] + #C7 = 0 + #C8 = 8 + #C9 = [#C8, #C8, #C8] + #C10 = 16 + #C11 = [#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 00000000000..32cc8544764 --- /dev/null +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect @@ -0,0 +1,62 @@ +main = ; +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* next) → lib::Coordinate* { + dart.core::print("hello"); + return null; + } + get #_ptr_x() → dart.ffi::Pointer* + return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::cast}(); + 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* + return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C9).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}(); + 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*>* + return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C11).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}*>(); + get next() → dart.ffi::Pointer* + return dart.ffi::_loadPointer*>(this.{lib::Coordinate::#_ptr_next}, #C7); + set next(dart.ffi::Pointer* #v) → void + return dart.ffi::_storePointer*>(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 = [#C4, #C5, #C4] + #C7 = 0 + #C8 = 8 + #C9 = [#C8, #C8, #C8] + #C10 = 16 + #C11 = [#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 8aa50fc0c75..96943e2cc60 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 @@ worlds: 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 @@ worlds: 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 4874153e413..3cae5cc3f28 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.