[CFE] Allow experimental invalidation to work on DillLibraryBuilders
This CL makes experimental invalidation work on DillLibraryBuilders, and solves all found issues (e.g. old references (aka leaks)) with it. Note: This CL introduces a few writes that seems weird (e.g. setting variables that's about to be out-of-scope to null). This is done to prevent "leaks", or probably more likely, prevent a "false positive" leak detection and it currently gives a "clean bill of health" from the leak detector. Change-Id: I5b01df6e9ede710a5b624a8a4c21015214140318 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/134288 Commit-Queue: Jens Johansen <jensj@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
be38459b98
commit
ddd6e31dee
@@ -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<String, String> unserializableExports;
|
||||
|
||||
// TODO(jensj): These 4 booleans could potentially be merged into a single
|
||||
// TODO(jensj): These 5 booleans could potentially be merged into a single
|
||||
// state field.
|
||||
bool isReadyToBuild = false;
|
||||
bool isReadyToFinalizeExports = false;
|
||||
@@ -294,53 +295,75 @@ class DillLibraryBuilder extends LibraryBuilderImpl {
|
||||
exportScopeBuilder.addMember(name, declaration);
|
||||
});
|
||||
|
||||
Map<Reference, Builder> sourceBuildersMap =
|
||||
loader.currentSourceLoader?.buildersCreatedWithReferences;
|
||||
for (Reference reference in library.additionalExports) {
|
||||
NamedNode node = reference.node;
|
||||
Uri libraryUri;
|
||||
String name;
|
||||
bool isSetter = false;
|
||||
if (node is Class) {
|
||||
libraryUri = node.enclosingLibrary.importUri;
|
||||
name = node.name;
|
||||
} else if (node is Procedure) {
|
||||
libraryUri = node.enclosingLibrary.importUri;
|
||||
name = node.name.name;
|
||||
isSetter = node.isSetter;
|
||||
} else if (node is Member) {
|
||||
libraryUri = node.enclosingLibrary.importUri;
|
||||
name = node.name.name;
|
||||
} else if (node is Typedef) {
|
||||
libraryUri = node.enclosingLibrary.importUri;
|
||||
name = node.name;
|
||||
} else if (node is Extension) {
|
||||
libraryUri = node.enclosingLibrary.importUri;
|
||||
name = node.name;
|
||||
} else {
|
||||
unhandled("${node.runtimeType}", "finalizeExports", -1, fileUri);
|
||||
}
|
||||
DillLibraryBuilder library = loader.builders[libraryUri];
|
||||
if (library == null) {
|
||||
internalProblem(
|
||||
templateUnspecified.withArguments("No builder for '$libraryUri'."),
|
||||
-1,
|
||||
fileUri);
|
||||
}
|
||||
Builder declaration;
|
||||
if (isSetter) {
|
||||
declaration = library.exportScope.lookupLocalMember(name, setter: true);
|
||||
exportScopeBuilder.addSetter(name, declaration);
|
||||
String name;
|
||||
if (sourceBuildersMap?.containsKey(reference) == true) {
|
||||
declaration = sourceBuildersMap[reference];
|
||||
assert(declaration != null);
|
||||
if (declaration is ModifierBuilder) {
|
||||
name = declaration.name;
|
||||
} else {
|
||||
throw new StateError(
|
||||
"Unexpected: $declaration (${declaration.runtimeType}");
|
||||
}
|
||||
|
||||
if (declaration.isSetter) {
|
||||
exportScopeBuilder.addSetter(name, declaration);
|
||||
} else {
|
||||
exportScopeBuilder.addMember(name, declaration);
|
||||
}
|
||||
} else {
|
||||
declaration =
|
||||
library.exportScope.lookupLocalMember(name, setter: false);
|
||||
exportScopeBuilder.addMember(name, declaration);
|
||||
}
|
||||
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 &&
|
||||
|
||||
@@ -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<SummaryTemplate> get outlineSummaryTemplate =>
|
||||
|
||||
@@ -129,7 +129,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
|
||||
List<LibraryBuilder> platformBuilders;
|
||||
Map<Uri, LibraryBuilder> userBuilders;
|
||||
final Uri initializeFromDillUri;
|
||||
final Component componentToInitializeFrom;
|
||||
Component componentToInitializeFrom;
|
||||
bool initializedFromDill = false;
|
||||
bool initializedIncrementalSerializer = false;
|
||||
Uri previousPackagesUri;
|
||||
@@ -213,13 +213,14 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
|
||||
KernelTarget userCodeOld = userCode;
|
||||
setupNewUserCode(c, uriTranslator, hierarchy, reusedLibraries,
|
||||
experimentalInvalidation, entryPoints.first);
|
||||
Map<LibraryBuilder, List<SourceLibraryBuilder>> rebuildBodiesMap =
|
||||
Map<LibraryBuilder, List<LibraryBuilder>> rebuildBodiesMap =
|
||||
experimentalInvalidationCreateRebuildBodiesBuilders(
|
||||
experimentalInvalidation, uriTranslator);
|
||||
entryPoints = userCode.setEntryPoints(entryPoints);
|
||||
await userCode.loader.buildOutlines();
|
||||
experimentalInvalidationPatchUpScopes(
|
||||
experimentalInvalidation, rebuildBodiesMap);
|
||||
rebuildBodiesMap = null;
|
||||
|
||||
// Checkpoint: Build the actual outline.
|
||||
// Note that the [Component] is not the "full" component.
|
||||
@@ -277,10 +278,14 @@ 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<Set<Library>> convertSourceLibraryBuildersToDill() async {
|
||||
Future<Set<Library>> convertSourceLibraryBuildersToDill(
|
||||
ExperimentalInvalidation experimentalInvalidation) async {
|
||||
bool changed = false;
|
||||
Set<Library> newDillLibraryBuilders = new Set<Library>();
|
||||
userBuilders ??= <Uri, LibraryBuilder>{};
|
||||
Map<LibraryBuilder, List<LibraryBuilder>> convertedLibraries;
|
||||
for (MapEntry<Uri, LibraryBuilder> entry
|
||||
in userCode.loader.builders.entries) {
|
||||
if (entry.value is SourceLibraryBuilder) {
|
||||
@@ -309,14 +320,53 @@ 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<LibraryBuilder, List<LibraryBuilder>>();
|
||||
convertedLibraries[builder] = [dillBuilder];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
// We suppress finalization errors because they have already been
|
||||
// reported.
|
||||
await dillLoadedData.buildOutlines(suppressFinalizationErrors: true);
|
||||
|
||||
if (experimentalInvalidation != null) {
|
||||
/// If doing experimental invalidation that means that some of the old
|
||||
/// dill library builders might have links (via export scopes) to the
|
||||
/// source builders. Patch that up.
|
||||
|
||||
// Maps from old library builder to map of new content.
|
||||
Map<LibraryBuilder, Map<String, Builder>> replacementMap = {};
|
||||
|
||||
// Maps from old library builder to map of new content.
|
||||
Map<LibraryBuilder, Map<String, Builder>> replacementSettersMap = {};
|
||||
|
||||
experimentalInvalidationFillReplacementMaps(
|
||||
convertedLibraries, replacementMap, replacementSettersMap);
|
||||
|
||||
for (LibraryBuilder builder
|
||||
in experimentalInvalidation.originalNotReusedLibraries) {
|
||||
DillLibraryBuilder dillBuilder = builder;
|
||||
if (dillBuilder.isBuilt) {
|
||||
dillBuilder.exportScope
|
||||
.patchUpScope(replacementMap, replacementSettersMap);
|
||||
}
|
||||
}
|
||||
replacementMap = null;
|
||||
replacementSettersMap = null;
|
||||
}
|
||||
}
|
||||
userCode.loader.buildersCreatedWithReferences.clear();
|
||||
userCode.loader.builderHierarchy.nodes.clear();
|
||||
userCode.loader.referenceFromIndex = null;
|
||||
convertedLibraries = null;
|
||||
experimentalInvalidation = null;
|
||||
if (userBuilders.isEmpty) userBuilders = null;
|
||||
return newDillLibraryBuilders;
|
||||
}
|
||||
@@ -415,17 +465,17 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
|
||||
/// Fill in the replacement maps that describe the replacements that need to
|
||||
/// happen because of experimental invalidation.
|
||||
void experimentalInvalidationFillReplacementMaps(
|
||||
Map<LibraryBuilder, List<SourceLibraryBuilder>> rebuildBodiesMap,
|
||||
Map<LibraryBuilder, List<LibraryBuilder>> rebuildBodiesMap,
|
||||
Map<LibraryBuilder, Map<String, Builder>> replacementMap,
|
||||
Map<LibraryBuilder, Map<String, Builder>> replacementSettersMap) {
|
||||
for (MapEntry<LibraryBuilder, List<SourceLibraryBuilder>> entry
|
||||
for (MapEntry<LibraryBuilder, List<LibraryBuilder>> entry
|
||||
in rebuildBodiesMap.entries) {
|
||||
Map<String, Builder> childReplacementMap = {};
|
||||
Map<String, Builder> childReplacementSettersMap = {};
|
||||
List<SourceLibraryBuilder> builders = rebuildBodiesMap[entry.key];
|
||||
List<LibraryBuilder> builders = rebuildBodiesMap[entry.key];
|
||||
replacementMap[entry.key] = childReplacementMap;
|
||||
replacementSettersMap[entry.key] = childReplacementSettersMap;
|
||||
for (SourceLibraryBuilder builder in builders) {
|
||||
for (LibraryBuilder builder in builders) {
|
||||
NameIterator iterator = builder.nameIterator;
|
||||
while (iterator.moveNext()) {
|
||||
Builder childBuilder = iterator.current;
|
||||
@@ -450,22 +500,22 @@ 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<LibraryBuilder, List<SourceLibraryBuilder>>
|
||||
Map<LibraryBuilder, List<LibraryBuilder>>
|
||||
experimentalInvalidationCreateRebuildBodiesBuilders(
|
||||
ExperimentalInvalidation experimentalInvalidation,
|
||||
UriTranslator uriTranslator) {
|
||||
// Any builder(s) in [rebuildBodies] should be semi-reused: Create source
|
||||
// builders based on the underlying libraries.
|
||||
// Maps from old library builder to list of new library builder(s).
|
||||
Map<LibraryBuilder, List<SourceLibraryBuilder>> rebuildBodiesMap =
|
||||
new Map<LibraryBuilder, List<SourceLibraryBuilder>>.identity();
|
||||
Map<LibraryBuilder, List<LibraryBuilder>> rebuildBodiesMap =
|
||||
new Map<LibraryBuilder, List<LibraryBuilder>>.identity();
|
||||
if (experimentalInvalidation != null) {
|
||||
for (LibraryBuilder library in experimentalInvalidation.rebuildBodies) {
|
||||
LibraryBuilder newBuilder = userCode.loader.read(library.importUri, -1,
|
||||
accessor: userCode.loader.first,
|
||||
fileUri: library.fileUri,
|
||||
referencesFrom: library.library);
|
||||
List<SourceLibraryBuilder> builders = [newBuilder];
|
||||
List<LibraryBuilder> builders = [newBuilder];
|
||||
rebuildBodiesMap[library] = builders;
|
||||
for (LibraryPart part in library.library.parts) {
|
||||
// We need to pass the reference to make any class, procedure etc
|
||||
@@ -492,7 +542,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
|
||||
/// didn't do anything special.
|
||||
void experimentalInvalidationPatchUpScopes(
|
||||
ExperimentalInvalidation experimentalInvalidation,
|
||||
Map<LibraryBuilder, List<SourceLibraryBuilder>> rebuildBodiesMap) {
|
||||
Map<LibraryBuilder, List<LibraryBuilder>> rebuildBodiesMap) {
|
||||
if (experimentalInvalidation != null) {
|
||||
// Maps from old library builder to map of new content.
|
||||
Map<LibraryBuilder, Map<String, Builder>> replacementMap = {};
|
||||
@@ -557,8 +607,16 @@ 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<Builder> 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<int> summaryBytes = await c.options.loadSdkSummaryBytes();
|
||||
bytesLength = prepareSummary(summaryBytes, uriTranslator, c, data);
|
||||
|
||||
@@ -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<String, TypeVariableBuilder> 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(
|
||||
|
||||
@@ -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<Reference, Builder> buildersCreatedWithReferences = {};
|
||||
|
||||
/// Used when checking whether a return type of an async function is valid.
|
||||
///
|
||||
/// The said return type is valid if it's a subtype of [futureOfBottom].
|
||||
|
||||
@@ -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<int> 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<int> 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<String> args) {
|
||||
}
|
||||
|
||||
class EndOffsetListener extends DirectiveListener {
|
||||
Set<int> endOffsets = new Set<int>();
|
||||
Set<int> nonClassEndOffsets = new Set<int>();
|
||||
Set<int> classEndOffsets = new Set<int>();
|
||||
|
||||
@override
|
||||
void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
|
||||
Token beginInitializers, Token endToken) {
|
||||
endOffsets.add(endToken.offset);
|
||||
nonClassEndOffsets.add(endToken.offset);
|
||||
}
|
||||
|
||||
@override
|
||||
void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
|
||||
endOffsets.add(endToken.offset);
|
||||
nonClassEndOffsets.add(endToken.offset);
|
||||
}
|
||||
|
||||
@override
|
||||
void endClassFactoryMethod(
|
||||
Token beginToken, Token factoryKeyword, Token endToken) {
|
||||
nonClassEndOffsets.add(endToken.offset);
|
||||
}
|
||||
|
||||
@override
|
||||
void endClassOrMixinBody(
|
||||
DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
|
||||
classEndOffsets.add(endToken.offset);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -31,58 +31,50 @@ main(List<String> 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<int> firstCompileData;
|
||||
Map<Uri, List<int>> libToData;
|
||||
if (fast) {
|
||||
libToData = {};
|
||||
c.libraries.sort((l1, l2) {
|
||||
return "${l1.fileUri}".compareTo("${l2.fileUri}");
|
||||
});
|
||||
|
||||
c.problemsAsJson?.sort();
|
||||
|
||||
c.computeCanonicalNames();
|
||||
|
||||
for (Library library in c.libraries) {
|
||||
library.additionalExports.sort((Reference r1, Reference r2) {
|
||||
return "${r1.canonicalName}".compareTo("${r2.canonicalName}");
|
||||
});
|
||||
library.problemsAsJson?.sort();
|
||||
|
||||
List<int> libSerialized =
|
||||
serializeComponent(c, filter: (l) => l == library);
|
||||
libToData[library.importUri] = libSerialized;
|
||||
}
|
||||
} else {
|
||||
firstCompileData = util.postProcess(c);
|
||||
}
|
||||
print("Serialized in ${stopwatch.elapsedMilliseconds} ms");
|
||||
stopwatch.reset();
|
||||
|
||||
List<Uri> uris = c.uriToSource.values
|
||||
.map((s) => s != null ? s.importUri : null)
|
||||
.where((u) => u != null && u.scheme != "dart")
|
||||
.toSet()
|
||||
.toList();
|
||||
|
||||
c = null;
|
||||
List<Uri> uris;
|
||||
|
||||
List<Uri> diffs = new List<Uri>();
|
||||
Set<Uri> componentUris = new Set<Uri>();
|
||||
|
||||
Stopwatch localStopwatch = new Stopwatch()..start();
|
||||
for (int i = 0; i < uris.length; i++) {
|
||||
Uri uri = uris[i];
|
||||
Dart2jsTester(
|
||||
this.useExperimentalInvalidation, this.fast, this.addDebugBreaks);
|
||||
|
||||
void test() async {
|
||||
helper.TestIncrementalCompiler compiler = await setup();
|
||||
|
||||
diffs = new List<Uri>();
|
||||
componentUris = new Set<Uri>();
|
||||
|
||||
Stopwatch localStopwatch = new Stopwatch()..start();
|
||||
for (int i = 0; i < uris.length; i++) {
|
||||
Uri uri = uris[i];
|
||||
await step(uri, i, compiler, localStopwatch);
|
||||
}
|
||||
|
||||
print("A total of ${diffs.length} diffs:");
|
||||
for (Uri uri in diffs) {
|
||||
print(" - $uri");
|
||||
}
|
||||
|
||||
print("Done after ${uris.length} recompiles in "
|
||||
"${stopwatch.elapsedMilliseconds} ms");
|
||||
}
|
||||
|
||||
Future step(Uri uri, int i, helper.TestIncrementalCompiler compiler,
|
||||
Stopwatch localStopwatch) async {
|
||||
print("Invalidating $uri ($i)");
|
||||
compiler.invalidate(uri);
|
||||
localStopwatch.reset();
|
||||
@@ -168,24 +160,65 @@ main(List<String> args) async {
|
||||
print("-----");
|
||||
}
|
||||
|
||||
print("A total of ${diffs.length} diffs:");
|
||||
for (Uri uri in diffs) {
|
||||
print(" - $uri");
|
||||
Future<helper.TestIncrementalCompiler> setup() async {
|
||||
stopwatch.reset();
|
||||
stopwatch.start();
|
||||
Uri input = Platform.script.resolve("../../compiler/bin/dart2js.dart");
|
||||
CompilerOptions options = helper.getOptions(targetName: "VM");
|
||||
helper.TestIncrementalCompiler compiler =
|
||||
new helper.TestIncrementalCompiler(options, input);
|
||||
compiler.useExperimentalInvalidation = useExperimentalInvalidation;
|
||||
Component c = await compiler.computeDelta();
|
||||
print("Compiled dart2js to Component with ${c.libraries.length} libraries "
|
||||
"in ${stopwatch.elapsedMilliseconds} ms.");
|
||||
stopwatch.reset();
|
||||
if (fast) {
|
||||
libToData = {};
|
||||
c.libraries.sort((l1, l2) {
|
||||
return "${l1.fileUri}".compareTo("${l2.fileUri}");
|
||||
});
|
||||
|
||||
c.problemsAsJson?.sort();
|
||||
|
||||
c.computeCanonicalNames();
|
||||
|
||||
for (Library library in c.libraries) {
|
||||
library.additionalExports.sort((Reference r1, Reference r2) {
|
||||
return "${r1.canonicalName}".compareTo("${r2.canonicalName}");
|
||||
});
|
||||
library.problemsAsJson?.sort();
|
||||
|
||||
List<int> libSerialized =
|
||||
serializeComponent(c, filter: (l) => l == library);
|
||||
libToData[library.importUri] = libSerialized;
|
||||
}
|
||||
} else {
|
||||
firstCompileData = util.postProcess(c);
|
||||
}
|
||||
print("Serialized in ${stopwatch.elapsedMilliseconds} ms");
|
||||
stopwatch.reset();
|
||||
|
||||
uris = c.uriToSource.values
|
||||
.map((s) => s != null ? s.importUri : null)
|
||||
.where((u) => u != null && u.scheme != "dart")
|
||||
.toSet()
|
||||
.toList();
|
||||
|
||||
c = null;
|
||||
|
||||
return compiler;
|
||||
}
|
||||
|
||||
print("Done after ${uris.length} recompiles in "
|
||||
"${stopwatch.elapsedMilliseconds} ms");
|
||||
}
|
||||
|
||||
bool isEqual(List<int> a, List<int> b) {
|
||||
int length = a.length;
|
||||
if (b.length != length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < length; ++i) {
|
||||
if (a[i] != b[i]) {
|
||||
bool isEqual(List<int> a, List<int> b) {
|
||||
int length = a.length;
|
||||
if (b.length != length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < length; ++i) {
|
||||
if (a[i] != b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -26,11 +26,23 @@ main(List<String> 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_...",
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import "dart:io";
|
||||
import "vm_service_heap_helper.dart";
|
||||
|
||||
class Foo {
|
||||
final String x;
|
||||
final int y;
|
||||
|
||||
Foo(this.x, this.y);
|
||||
}
|
||||
|
||||
main() async {
|
||||
List<Foo> foos = [];
|
||||
foos.add(new Foo("hello", 42));
|
||||
foos.add(new Foo("world", 43));
|
||||
foos.add(new Foo("!", 44));
|
||||
String connectTo = ask("Connect to");
|
||||
VMServiceHeapHelperBase vm = VMServiceHeapHelperBase();
|
||||
await vm.connect(Uri.parse(connectTo));
|
||||
String isolateId = await vm.getIsolateId();
|
||||
String classToFind = ask("Find what class");
|
||||
await vm.printAllocationProfile(isolateId, filter: classToFind);
|
||||
String fieldToFilter = ask("Filter on what field");
|
||||
Set<String> fieldValues = {};
|
||||
while (true) {
|
||||
String fieldValue = ask("Look for value in field (empty to stop)");
|
||||
if (fieldValue == "") break;
|
||||
fieldValues.add(fieldValue);
|
||||
}
|
||||
|
||||
await vm.filterAndPrintInstances(
|
||||
isolateId, classToFind, fieldToFilter, fieldValues);
|
||||
|
||||
await vm.disconnect();
|
||||
print("Disconnect done!");
|
||||
}
|
||||
|
||||
String ask(String question) {
|
||||
stdout.write("$question: ");
|
||||
return stdin.readLineSync();
|
||||
}
|
||||
@@ -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<Uri, Map<String, List<String>>> _interests =
|
||||
new Map<Uri, Map<String, List<String>>>();
|
||||
final Map<Uri, Map<String, List<String>>> _prettyPrints =
|
||||
new Map<Uri, Map<String, List<String>>>();
|
||||
final bool throwOnPossibleLeak;
|
||||
|
||||
VMServiceHeapHelper(List<Interest> interests, List<Interest> prettyPrints,
|
||||
this.throwOnPossibleLeak) {
|
||||
if (interests.isEmpty) throw "Empty list of interests given";
|
||||
for (Interest interest in interests) {
|
||||
Map<String, List<String>> classToFields = _interests[interest.uri];
|
||||
if (classToFields == null) {
|
||||
classToFields = Map<String, List<String>>();
|
||||
_interests[interest.uri] = classToFields;
|
||||
}
|
||||
List<String> fields = classToFields[interest.className];
|
||||
if (fields == null) {
|
||||
fields = new List<String>();
|
||||
classToFields[interest.className] = fields;
|
||||
}
|
||||
fields.addAll(interest.fieldNames);
|
||||
}
|
||||
for (Interest interest in prettyPrints) {
|
||||
Map<String, List<String>> classToFields = _prettyPrints[interest.uri];
|
||||
if (classToFields == null) {
|
||||
classToFields = Map<String, List<String>>();
|
||||
_prettyPrints[interest.uri] = classToFields;
|
||||
}
|
||||
List<String> fields = classToFields[interest.className];
|
||||
if (fields == null) {
|
||||
fields = new List<String>();
|
||||
classToFields[interest.className] = fields;
|
||||
}
|
||||
fields.addAll(interest.fieldNames);
|
||||
}
|
||||
}
|
||||
VMServiceHeapHelperBase();
|
||||
|
||||
void start(List<String> scriptAndArgs) async {
|
||||
if (_started) throw "Already started";
|
||||
_started = true;
|
||||
_process = await Process.start(
|
||||
Platform.resolvedExecutable,
|
||||
["--pause_isolates_on_start", "--enable-vm-service=0"]
|
||||
..addAll(scriptAndArgs));
|
||||
_process.stdout
|
||||
.transform(utf8.decoder)
|
||||
.transform(new LineSplitter())
|
||||
.listen((line) {
|
||||
const kObservatoryListening = 'Observatory listening on ';
|
||||
if (line.startsWith(kObservatoryListening)) {
|
||||
Uri observatoryUri =
|
||||
Uri.parse(line.substring(kObservatoryListening.length));
|
||||
_gotObservatoryUri(observatoryUri);
|
||||
}
|
||||
stdout.writeln("> $line");
|
||||
});
|
||||
_process.stderr
|
||||
.transform(utf8.decoder)
|
||||
.transform(new LineSplitter())
|
||||
.listen((line) {
|
||||
stderr.writeln("> $line");
|
||||
});
|
||||
}
|
||||
|
||||
void _gotObservatoryUri(Uri observatoryUri) async {
|
||||
Future connect(Uri observatoryUri) async {
|
||||
String wsUriString =
|
||||
'ws://${observatoryUri.authority}${observatoryUri.path}ws';
|
||||
_serviceClient = await vmService.vmServiceConnectUri(wsUriString,
|
||||
log: const StdOutLog());
|
||||
await _run();
|
||||
}
|
||||
|
||||
void _run() async {
|
||||
vmService.VM vm = await _serviceClient.getVM();
|
||||
if (vm.isolates.length != 1) {
|
||||
throw "Expected 1 isolate, got ${vm.isolates.length}";
|
||||
}
|
||||
vmService.IsolateRef isolateRef = vm.isolates.single;
|
||||
await _forceGC(isolateRef.id);
|
||||
|
||||
assert(await _isPausedAtStart(isolateRef.id));
|
||||
await _serviceClient.resume(isolateRef.id);
|
||||
|
||||
int iterationNumber = 1;
|
||||
while (true) {
|
||||
await _waitUntilPaused(isolateRef.id);
|
||||
print("Iteration: #$iterationNumber");
|
||||
iterationNumber++;
|
||||
await _forceGC(isolateRef.id);
|
||||
|
||||
vmService.HeapSnapshotGraph heapSnapshotGraph =
|
||||
await vmService.HeapSnapshotGraph.getSnapshot(
|
||||
_serviceClient, isolateRef);
|
||||
HeapGraph graph = convertHeapGraph(heapSnapshotGraph);
|
||||
|
||||
Set<String> seenPrints = {};
|
||||
Set<String> duplicatePrints = {};
|
||||
Map<String, List<HeapGraphElement>> groupedByToString = {};
|
||||
for (HeapGraphClassActual c in graph.classes) {
|
||||
Map<String, List<String>> interests = _interests[c.libraryUri];
|
||||
if (interests != null && interests.isNotEmpty) {
|
||||
List<String> fieldsToUse = interests[c.name];
|
||||
if (fieldsToUse != null && fieldsToUse.isNotEmpty) {
|
||||
for (HeapGraphElement instance in c.instances) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.writeln("Instance: ${instance}");
|
||||
if (instance is HeapGraphElementActual) {
|
||||
for (String fieldName in fieldsToUse) {
|
||||
String prettyPrinted = instance
|
||||
.getField(fieldName)
|
||||
.getPrettyPrint(_prettyPrints);
|
||||
sb.writeln(" $fieldName: "
|
||||
"${prettyPrinted}");
|
||||
}
|
||||
}
|
||||
String sbToString = sb.toString();
|
||||
if (!seenPrints.add(sbToString)) {
|
||||
duplicatePrints.add(sbToString);
|
||||
}
|
||||
groupedByToString[sbToString] ??= [];
|
||||
groupedByToString[sbToString].add(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (duplicatePrints.isNotEmpty) {
|
||||
print("======================================");
|
||||
print("WARNING: Duplicated pretty prints of objects.");
|
||||
print("This might be a memory leak!");
|
||||
print("");
|
||||
for (String s in duplicatePrints) {
|
||||
int count = groupedByToString[s].length;
|
||||
print("$s ($count)");
|
||||
print("");
|
||||
}
|
||||
print("======================================");
|
||||
for (String duplicateString in duplicatePrints) {
|
||||
print("$duplicateString:");
|
||||
List<HeapGraphElement> Function(HeapGraphElement target)
|
||||
dijkstraTarget = dijkstra(graph.elements.first, graph);
|
||||
for (HeapGraphElement duplicate
|
||||
in groupedByToString[duplicateString]) {
|
||||
print("${duplicate} pointed to from:");
|
||||
List<HeapGraphElement> shortestPath = dijkstraTarget(duplicate);
|
||||
for (int i = 0; i < shortestPath.length - 1; i++) {
|
||||
HeapGraphElement thisOne = shortestPath[i];
|
||||
HeapGraphElement nextOne = shortestPath[i + 1];
|
||||
String indexFieldName;
|
||||
if (thisOne is HeapGraphElementActual) {
|
||||
HeapGraphClass c = thisOne.class_;
|
||||
if (c is HeapGraphClassActual) {
|
||||
for (vmService.HeapSnapshotField field in c.origin.fields) {
|
||||
if (thisOne.references[field.index] == nextOne) {
|
||||
indexFieldName = field.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (indexFieldName == null) {
|
||||
indexFieldName = "no field found; index "
|
||||
"${thisOne.references.indexOf(nextOne)}";
|
||||
}
|
||||
print(" $thisOne -> $nextOne ($indexFieldName)");
|
||||
}
|
||||
print("---------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
if (throwOnPossibleLeak) throw "Possible leak detected.";
|
||||
}
|
||||
await _serviceClient.resume(isolateRef.id);
|
||||
}
|
||||
}
|
||||
|
||||
List<HeapGraphElement> Function(HeapGraphElement target) dijkstra(
|
||||
HeapGraphElement source, HeapGraph heapGraph) {
|
||||
Map<HeapGraphElement, int> elementNum = {};
|
||||
Map<HeapGraphElement, GraphNode<HeapGraphElement>> elements = {};
|
||||
elements[heapGraph.elementSentinel] =
|
||||
new GraphNode<HeapGraphElement>(heapGraph.elementSentinel);
|
||||
elementNum[heapGraph.elementSentinel] = elements.length;
|
||||
for (HeapGraphElementActual element in heapGraph.elements) {
|
||||
elements[element] = new GraphNode<HeapGraphElement>(element);
|
||||
elementNum[element] = elements.length;
|
||||
}
|
||||
|
||||
for (HeapGraphElementActual element in heapGraph.elements) {
|
||||
GraphNode<HeapGraphElement> node = elements[element];
|
||||
for (HeapGraphElement out in element.references) {
|
||||
node.addOutgoing(elements[out]);
|
||||
}
|
||||
}
|
||||
|
||||
DijkstrasAlgorithm<HeapGraphElement> result =
|
||||
new DijkstrasAlgorithm<HeapGraphElement>(
|
||||
elements.values,
|
||||
elements[source],
|
||||
(HeapGraphElement a, HeapGraphElement b) {
|
||||
if (identical(a, b)) {
|
||||
throw "Comparing two identical ones was unexpected";
|
||||
}
|
||||
return elementNum[a] - elementNum[b];
|
||||
},
|
||||
(HeapGraphElement a, HeapGraphElement b) {
|
||||
if (identical(a, b)) return 0;
|
||||
// Prefer not to go via sentinel and via "Context".
|
||||
if (b is HeapGraphElementSentinel) return 100;
|
||||
HeapGraphElementActual bb = b;
|
||||
if (bb.class_ is HeapGraphClassSentinel) return 100;
|
||||
HeapGraphClassActual c = bb.class_;
|
||||
if (c.name == "Context") {
|
||||
if (c.libraryUri.toString().isEmpty) return 100;
|
||||
}
|
||||
return 1;
|
||||
},
|
||||
);
|
||||
|
||||
return (HeapGraphElement target) {
|
||||
return result.getPathFromTarget(elements[source], elements[target]);
|
||||
};
|
||||
Future disconnect() async {
|
||||
await _serviceClient.dispose();
|
||||
}
|
||||
|
||||
Future<void> _waitUntilPaused(String isolateId) async {
|
||||
@@ -310,6 +101,329 @@ class VMServiceHeapHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> printAllocationProfile(String isolateId, {String filter}) async {
|
||||
await _waitUntilIsolateIsRunnable(isolateId);
|
||||
vmService.AllocationProfile allocationProfile =
|
||||
await _serviceClient.getAllocationProfile(isolateId);
|
||||
for (vmService.ClassHeapStats member in allocationProfile.members) {
|
||||
if (filter != null) {
|
||||
if (member.classRef.name != filter) continue;
|
||||
} else {
|
||||
if (member.classRef.name == "") continue;
|
||||
if (member.instancesCurrent == 0) continue;
|
||||
}
|
||||
vmService.Class c =
|
||||
await _serviceClient.getObject(isolateId, member.classRef.id);
|
||||
if (c.location?.script?.uri == null) continue;
|
||||
print("${member.classRef.name}: ${member.instancesCurrent}");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> filterAndPrintInstances(String isolateId, String filter,
|
||||
String fieldName, Set<String> fieldValues) async {
|
||||
await _waitUntilIsolateIsRunnable(isolateId);
|
||||
vmService.AllocationProfile allocationProfile =
|
||||
await _serviceClient.getAllocationProfile(isolateId);
|
||||
for (vmService.ClassHeapStats member in allocationProfile.members) {
|
||||
if (member.classRef.name != filter) continue;
|
||||
vmService.Class c =
|
||||
await _serviceClient.getObject(isolateId, member.classRef.id);
|
||||
if (c.location?.script?.uri == null) continue;
|
||||
print("${member.classRef.name}: ${member.instancesCurrent}");
|
||||
print(c.location.script.uri);
|
||||
|
||||
vmService.InstanceSet instances = await _serviceClient.getInstances(
|
||||
isolateId, member.classRef.id, 10000);
|
||||
int instanceNum = 0;
|
||||
for (vmService.ObjRef instance in instances.instances) {
|
||||
instanceNum++;
|
||||
var receivedObject =
|
||||
await _serviceClient.getObject(isolateId, instance.id);
|
||||
if (receivedObject is! vmService.Instance) continue;
|
||||
vmService.Instance object = receivedObject;
|
||||
for (vmService.BoundField field in object.fields) {
|
||||
if (field.decl.name == fieldName) {
|
||||
if (field.value is vmService.Sentinel) continue;
|
||||
var receivedValue =
|
||||
await _serviceClient.getObject(isolateId, field.value.id);
|
||||
if (receivedValue is! vmService.Instance) continue;
|
||||
String value = (receivedValue as vmService.Instance).valueAsString;
|
||||
if (!fieldValues.contains(value)) continue;
|
||||
print("${instanceNum}: ${field.decl.name}: "
|
||||
"${value} --- ${instance.id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
print("Done!");
|
||||
}
|
||||
|
||||
Future<String> getIsolateId() async {
|
||||
vmService.VM vm = await _serviceClient.getVM();
|
||||
if (vm.isolates.length != 1) {
|
||||
throw "Expected 1 isolate, got ${vm.isolates.length}";
|
||||
}
|
||||
vmService.IsolateRef isolateRef = vm.isolates.single;
|
||||
return isolateRef.id;
|
||||
}
|
||||
}
|
||||
|
||||
class VMServiceHeapHelper extends VMServiceHeapHelperBase {
|
||||
Process _process;
|
||||
|
||||
bool _started = false;
|
||||
final Map<Uri, Map<String, List<String>>> _interests =
|
||||
new Map<Uri, Map<String, List<String>>>();
|
||||
final Map<Uri, Map<String, List<String>>> _prettyPrints =
|
||||
new Map<Uri, Map<String, List<String>>>();
|
||||
final bool throwOnPossibleLeak;
|
||||
|
||||
VMServiceHeapHelper(List<Interest> interests, List<Interest> prettyPrints,
|
||||
this.throwOnPossibleLeak) {
|
||||
if (interests.isEmpty) throw "Empty list of interests given";
|
||||
for (Interest interest in interests) {
|
||||
Map<String, List<String>> classToFields = _interests[interest.uri];
|
||||
if (classToFields == null) {
|
||||
classToFields = Map<String, List<String>>();
|
||||
_interests[interest.uri] = classToFields;
|
||||
}
|
||||
List<String> fields = classToFields[interest.className];
|
||||
if (fields == null) {
|
||||
fields = new List<String>();
|
||||
classToFields[interest.className] = fields;
|
||||
}
|
||||
fields.addAll(interest.fieldNames);
|
||||
}
|
||||
for (Interest interest in prettyPrints) {
|
||||
Map<String, List<String>> classToFields = _prettyPrints[interest.uri];
|
||||
if (classToFields == null) {
|
||||
classToFields = Map<String, List<String>>();
|
||||
_prettyPrints[interest.uri] = classToFields;
|
||||
}
|
||||
List<String> fields = classToFields[interest.className];
|
||||
if (fields == null) {
|
||||
fields = new List<String>();
|
||||
classToFields[interest.className] = fields;
|
||||
}
|
||||
fields.addAll(interest.fieldNames);
|
||||
}
|
||||
}
|
||||
|
||||
void start(List<String> scriptAndArgs) async {
|
||||
if (_started) throw "Already started";
|
||||
_started = true;
|
||||
_process = await Process.start(
|
||||
Platform.resolvedExecutable,
|
||||
["--pause_isolates_on_start", "--enable-vm-service=0"]
|
||||
..addAll(scriptAndArgs));
|
||||
_process.stdout
|
||||
.transform(utf8.decoder)
|
||||
.transform(new LineSplitter())
|
||||
.listen((line) {
|
||||
const kObservatoryListening = 'Observatory listening on ';
|
||||
if (line.startsWith(kObservatoryListening)) {
|
||||
Uri observatoryUri =
|
||||
Uri.parse(line.substring(kObservatoryListening.length));
|
||||
_setupAndRun(observatoryUri);
|
||||
}
|
||||
stdout.writeln("> $line");
|
||||
});
|
||||
_process.stderr
|
||||
.transform(utf8.decoder)
|
||||
.transform(new LineSplitter())
|
||||
.listen((line) {
|
||||
stderr.writeln("> $line");
|
||||
});
|
||||
}
|
||||
|
||||
void _setupAndRun(Uri observatoryUri) async {
|
||||
await connect(observatoryUri);
|
||||
await _run();
|
||||
}
|
||||
|
||||
void _run() async {
|
||||
vmService.VM vm = await _serviceClient.getVM();
|
||||
if (vm.isolates.length != 1) {
|
||||
throw "Expected 1 isolate, got ${vm.isolates.length}";
|
||||
}
|
||||
vmService.IsolateRef isolateRef = vm.isolates.single;
|
||||
await _forceGC(isolateRef.id);
|
||||
|
||||
assert(await _isPausedAtStart(isolateRef.id));
|
||||
await _serviceClient.resume(isolateRef.id);
|
||||
|
||||
int iterationNumber = 1;
|
||||
while (true) {
|
||||
await _waitUntilPaused(isolateRef.id);
|
||||
print("Iteration: #$iterationNumber");
|
||||
iterationNumber++;
|
||||
await _forceGC(isolateRef.id);
|
||||
|
||||
vmService.HeapSnapshotGraph heapSnapshotGraph =
|
||||
await vmService.HeapSnapshotGraph.getSnapshot(
|
||||
_serviceClient, isolateRef);
|
||||
HeapGraph graph = convertHeapGraph(heapSnapshotGraph);
|
||||
|
||||
Set<String> seenPrints = {};
|
||||
Set<String> duplicatePrints = {};
|
||||
Map<String, List<HeapGraphElement>> groupedByToString = {};
|
||||
for (HeapGraphClassActual c in graph.classes) {
|
||||
Map<String, List<String>> interests = _interests[c.libraryUri];
|
||||
if (interests != null && interests.isNotEmpty) {
|
||||
List<String> fieldsToUse = interests[c.name];
|
||||
if (fieldsToUse != null && fieldsToUse.isNotEmpty) {
|
||||
for (HeapGraphElement instance in c.instances) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.writeln("Instance: ${instance}");
|
||||
if (instance is HeapGraphElementActual) {
|
||||
for (String fieldName in fieldsToUse) {
|
||||
String prettyPrinted = instance
|
||||
.getField(fieldName)
|
||||
.getPrettyPrint(_prettyPrints);
|
||||
sb.writeln(" $fieldName: "
|
||||
"${prettyPrinted}");
|
||||
}
|
||||
}
|
||||
String sbToString = sb.toString();
|
||||
if (!seenPrints.add(sbToString)) {
|
||||
duplicatePrints.add(sbToString);
|
||||
}
|
||||
groupedByToString[sbToString] ??= [];
|
||||
groupedByToString[sbToString].add(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (duplicatePrints.isNotEmpty) {
|
||||
print("======================================");
|
||||
print("WARNING: Duplicated pretty prints of objects.");
|
||||
print("This might be a memory leak!");
|
||||
print("");
|
||||
for (String s in duplicatePrints) {
|
||||
int count = groupedByToString[s].length;
|
||||
print("$s ($count)");
|
||||
print("");
|
||||
}
|
||||
print("======================================");
|
||||
for (String duplicateString in duplicatePrints) {
|
||||
print("$duplicateString:");
|
||||
List<HeapGraphElement> Function(HeapGraphElement target)
|
||||
dijkstraTarget = dijkstra(graph.elements.first, graph);
|
||||
for (HeapGraphElement duplicate
|
||||
in groupedByToString[duplicateString]) {
|
||||
print("${duplicate} pointed to from:");
|
||||
print(duplicate.getPrettyPrint(_prettyPrints));
|
||||
List<HeapGraphElement> shortestPath = dijkstraTarget(duplicate);
|
||||
for (int i = 0; i < shortestPath.length - 1; i++) {
|
||||
HeapGraphElement thisOne = shortestPath[i];
|
||||
HeapGraphElement nextOne = shortestPath[i + 1];
|
||||
String indexFieldName;
|
||||
if (thisOne is HeapGraphElementActual) {
|
||||
HeapGraphClass c = thisOne.class_;
|
||||
if (c is HeapGraphClassActual) {
|
||||
for (vmService.HeapSnapshotField field in c.origin.fields) {
|
||||
if (thisOne.references[field.index] == nextOne) {
|
||||
indexFieldName = field.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (indexFieldName == null) {
|
||||
indexFieldName = "no field found; index "
|
||||
"${thisOne.references.indexOf(nextOne)}";
|
||||
}
|
||||
print(" $thisOne -> $nextOne ($indexFieldName)");
|
||||
}
|
||||
print("---------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
if (throwOnPossibleLeak) {
|
||||
debugger();
|
||||
throw "Possible leak detected.";
|
||||
}
|
||||
}
|
||||
await _serviceClient.resume(isolateRef.id);
|
||||
}
|
||||
}
|
||||
|
||||
List<HeapGraphElement> Function(HeapGraphElement target) dijkstra(
|
||||
HeapGraphElement source, HeapGraph heapGraph) {
|
||||
Map<HeapGraphElement, int> elementNum = {};
|
||||
Map<HeapGraphElement, GraphNode<HeapGraphElement>> elements = {};
|
||||
elements[heapGraph.elementSentinel] =
|
||||
new GraphNode<HeapGraphElement>(heapGraph.elementSentinel);
|
||||
elementNum[heapGraph.elementSentinel] = elements.length;
|
||||
for (HeapGraphElementActual element in heapGraph.elements) {
|
||||
elements[element] = new GraphNode<HeapGraphElement>(element);
|
||||
elementNum[element] = elements.length;
|
||||
}
|
||||
|
||||
for (HeapGraphElementActual element in heapGraph.elements) {
|
||||
GraphNode<HeapGraphElement> node = elements[element];
|
||||
for (HeapGraphElement out in element.references) {
|
||||
node.addOutgoing(elements[out]);
|
||||
}
|
||||
}
|
||||
|
||||
DijkstrasAlgorithm<HeapGraphElement> result =
|
||||
new DijkstrasAlgorithm<HeapGraphElement>(
|
||||
elements.values,
|
||||
elements[source],
|
||||
(HeapGraphElement a, HeapGraphElement b) {
|
||||
if (identical(a, b)) {
|
||||
throw "Comparing two identical ones was unexpected";
|
||||
}
|
||||
return elementNum[a] - elementNum[b];
|
||||
},
|
||||
(HeapGraphElement a, HeapGraphElement b) {
|
||||
if (identical(a, b)) return 0;
|
||||
|
||||
// Prefer going via actual field.
|
||||
if (a is HeapGraphElementActual) {
|
||||
HeapGraphClass c = a.class_;
|
||||
if (c is HeapGraphClassActual) {
|
||||
for (vmService.HeapSnapshotField field in c.origin.fields) {
|
||||
if (a.references[field.index] == b) {
|
||||
// Via actual field!
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer not to go directly from HeapGraphClassSentinel to Procedure.
|
||||
if (a is HeapGraphElementActual && b is HeapGraphElementActual) {
|
||||
HeapGraphElementActual aa = a;
|
||||
HeapGraphElementActual bb = b;
|
||||
if (aa.class_ is HeapGraphClassSentinel &&
|
||||
bb.class_ is HeapGraphClassActual) {
|
||||
HeapGraphClassActual c = bb.class_;
|
||||
if (c.name == "Procedure") {
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer not to go via sentinel and via "Context".
|
||||
if (b is HeapGraphElementSentinel) return 100;
|
||||
HeapGraphElementActual bb = b;
|
||||
if (bb.class_ is HeapGraphClassSentinel) return 100;
|
||||
HeapGraphClassActual c = bb.class_;
|
||||
if (c.name == "Context") {
|
||||
if (c.libraryUri.toString().isEmpty) return 100;
|
||||
}
|
||||
|
||||
// Not via actual field.
|
||||
return 10;
|
||||
},
|
||||
);
|
||||
|
||||
return (HeapGraphElement target) {
|
||||
return result.getPathFromTarget(elements[source], elements[target]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Interest {
|
||||
@@ -412,7 +526,8 @@ 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(", ") +
|
||||
"]";
|
||||
}
|
||||
|
||||
@@ -41,4 +41,4 @@ worlds:
|
||||
print("exports!")
|
||||
}
|
||||
expectedLibraryCount: 3
|
||||
expectsRebuildBodiesOnly: true
|
||||
expectsRebuildBodiesOnly: false # For now, libraries with errors cannot have bodies rebuild.
|
||||
|
||||
@@ -48,4 +48,4 @@ worlds:
|
||||
}
|
||||
}
|
||||
expectedLibraryCount: 1
|
||||
expectsRebuildBodiesOnly: true
|
||||
expectsRebuildBodiesOnly: false # For now, libraries with errors cannot have bodies rebuild.
|
||||
|
||||
@@ -40,4 +40,4 @@ worlds:
|
||||
new A1.foo();
|
||||
}
|
||||
expectedLibraryCount: 1
|
||||
expectsRebuildBodiesOnly: true
|
||||
expectsRebuildBodiesOnly: false # For now, libraries with errors cannot have bodies rebuild.
|
||||
|
||||
@@ -95,7 +95,6 @@ worlds:
|
||||
}
|
||||
expectedLibraryCount: 3
|
||||
expectsRebuildBodiesOnly: true
|
||||
|
||||
- entry: main.dart
|
||||
useExperimentalInvalidation: true
|
||||
worldType: updated
|
||||
|
||||
+3
-1
@@ -1,6 +1,8 @@
|
||||
main = <No Member>;
|
||||
library from "org-dartlang-test:///lib1.dart" as lib1 {
|
||||
additionalExports = (main::main,
|
||||
additionalExports = (main::Extension|get#method,
|
||||
main::Extension|method,
|
||||
main::main,
|
||||
main::Class,
|
||||
main::Extension)
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
||||
# for details. All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE.md file.
|
||||
|
||||
# Compile an application, change a file, but don't change the outline.
|
||||
# Test FFI compilation.
|
||||
|
||||
type: newworld
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
useExperimentalInvalidation: true
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'lib.dart';
|
||||
|
||||
main() {
|
||||
Coordinate coordinate = new Coordinate.allocate(42.0, 42.0, null);
|
||||
print(coordinate.x);
|
||||
print(coordinate.y);
|
||||
print(coordinate.next);
|
||||
}
|
||||
lib.dart: |
|
||||
import 'dart:ffi';
|
||||
class Coordinate extends Struct {
|
||||
@Double()
|
||||
double x;
|
||||
|
||||
@Double()
|
||||
double y;
|
||||
|
||||
Pointer<Coordinate> next;
|
||||
|
||||
factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
expectedLibraryCount: 2
|
||||
- entry: main.dart
|
||||
useExperimentalInvalidation: true
|
||||
worldType: updated
|
||||
expectInitializeFromDill: false
|
||||
invalidate:
|
||||
- main.dart
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'lib.dart';
|
||||
|
||||
main() {
|
||||
Coordinate coordinate = new Coordinate.allocate(42.0, 42.0, null);
|
||||
print(coordinate.x);
|
||||
print(coordinate.y);
|
||||
print(coordinate.next);
|
||||
print("Done!");
|
||||
}
|
||||
expectedLibraryCount: 2
|
||||
expectsRebuildBodiesOnly: true
|
||||
- entry: main.dart
|
||||
useExperimentalInvalidation: true
|
||||
worldType: updated
|
||||
expectInitializeFromDill: false
|
||||
invalidate:
|
||||
- lib.dart
|
||||
sources:
|
||||
lib.dart: |
|
||||
import 'dart:ffi';
|
||||
class Coordinate extends Struct {
|
||||
@Double()
|
||||
double x;
|
||||
|
||||
@Double()
|
||||
double y;
|
||||
|
||||
Pointer<Coordinate> next;
|
||||
|
||||
factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
|
||||
print("hello");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
expectedLibraryCount: 2
|
||||
expectsRebuildBodiesOnly: true
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
main = <No Member>;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
|
||||
import "dart:ffi";
|
||||
|
||||
@#C3
|
||||
class Coordinate extends dart.ffi::Struct {
|
||||
@#C3
|
||||
static final field dart.core::int* #sizeOf = (#C6).{dart.core::List::[]}(dart.ffi::_abi());
|
||||
@#C3
|
||||
constructor #fromPointer(dynamic #pointer) → dynamic
|
||||
: super dart.ffi::Struct::_fromPointer(#pointer)
|
||||
;
|
||||
static factory allocate(dart.core::double* x, dart.core::double* y, dart.ffi::Pointer<lib::Coordinate*>* next) → lib::Coordinate* {
|
||||
return null;
|
||||
}
|
||||
get #_ptr_x() → dart.ffi::Pointer<dart.ffi::Double*>*
|
||||
return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
|
||||
get x() → dart.core::double*
|
||||
return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_x}, #C7);
|
||||
set x(dart.core::double* #v) → void
|
||||
return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_x}, #C7, #v);
|
||||
get #_ptr_y() → dart.ffi::Pointer<dart.ffi::Double*>*
|
||||
return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C9).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
|
||||
get y() → dart.core::double*
|
||||
return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_y}, #C7);
|
||||
set y(dart.core::double* #v) → void
|
||||
return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_y}, #C7, #v);
|
||||
get #_ptr_next() → dart.ffi::Pointer<dart.ffi::Pointer<lib::Coordinate*>*>*
|
||||
return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C11).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Pointer<lib::Coordinate*>*>();
|
||||
get next() → dart.ffi::Pointer<lib::Coordinate*>*
|
||||
return dart.ffi::_loadPointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7);
|
||||
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
|
||||
return dart.ffi::_storePointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7, #v);
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart";
|
||||
|
||||
static method main() → dynamic {
|
||||
lib::Coordinate* coordinate = lib::Coordinate::allocate(42.0, 42.0, null);
|
||||
dart.core::print(coordinate.{lib::Coordinate::x});
|
||||
dart.core::print(coordinate.{lib::Coordinate::y});
|
||||
dart.core::print(coordinate.{lib::Coordinate::next});
|
||||
}
|
||||
}
|
||||
constants {
|
||||
#C1 = "vm:entry-point"
|
||||
#C2 = null
|
||||
#C3 = dart.core::pragma {name:#C1, options:#C2}
|
||||
#C4 = 24
|
||||
#C5 = 20
|
||||
#C6 = <dart.core::int*>[#C4, #C5, #C4]
|
||||
#C7 = 0
|
||||
#C8 = 8
|
||||
#C9 = <dart.core::int*>[#C8, #C8, #C8]
|
||||
#C10 = 16
|
||||
#C11 = <dart.core::int*>[#C10, #C10, #C10]
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
main = <No Member>;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
|
||||
import "dart:ffi";
|
||||
|
||||
@#C3
|
||||
class Coordinate extends dart.ffi::Struct {
|
||||
@#C3
|
||||
static final field dart.core::int* #sizeOf = (#C6).{dart.core::List::[]}(dart.ffi::_abi());
|
||||
@#C3
|
||||
constructor #fromPointer(dynamic #pointer) → dynamic
|
||||
: super dart.ffi::Struct::_fromPointer(#pointer)
|
||||
;
|
||||
static factory allocate(dart.core::double* x, dart.core::double* y, dart.ffi::Pointer<lib::Coordinate*>* next) → lib::Coordinate* {
|
||||
return null;
|
||||
}
|
||||
get #_ptr_x() → dart.ffi::Pointer<dart.ffi::Double*>*
|
||||
return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
|
||||
get x() → dart.core::double*
|
||||
return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_x}, #C7);
|
||||
set x(dart.core::double* #v) → void
|
||||
return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_x}, #C7, #v);
|
||||
get #_ptr_y() → dart.ffi::Pointer<dart.ffi::Double*>*
|
||||
return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C9).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
|
||||
get y() → dart.core::double*
|
||||
return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_y}, #C7);
|
||||
set y(dart.core::double* #v) → void
|
||||
return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_y}, #C7, #v);
|
||||
get #_ptr_next() → dart.ffi::Pointer<dart.ffi::Pointer<lib::Coordinate*>*>*
|
||||
return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C11).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Pointer<lib::Coordinate*>*>();
|
||||
get next() → dart.ffi::Pointer<lib::Coordinate*>*
|
||||
return dart.ffi::_loadPointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7);
|
||||
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
|
||||
return dart.ffi::_storePointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7, #v);
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart";
|
||||
|
||||
static method main() → dynamic {
|
||||
lib::Coordinate* coordinate = lib::Coordinate::allocate(42.0, 42.0, null);
|
||||
dart.core::print(coordinate.{lib::Coordinate::x});
|
||||
dart.core::print(coordinate.{lib::Coordinate::y});
|
||||
dart.core::print(coordinate.{lib::Coordinate::next});
|
||||
dart.core::print("Done!");
|
||||
}
|
||||
}
|
||||
constants {
|
||||
#C1 = "vm:entry-point"
|
||||
#C2 = null
|
||||
#C3 = dart.core::pragma {name:#C1, options:#C2}
|
||||
#C4 = 24
|
||||
#C5 = 20
|
||||
#C6 = <dart.core::int*>[#C4, #C5, #C4]
|
||||
#C7 = 0
|
||||
#C8 = 8
|
||||
#C9 = <dart.core::int*>[#C8, #C8, #C8]
|
||||
#C10 = 16
|
||||
#C11 = <dart.core::int*>[#C10, #C10, #C10]
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
main = <No Member>;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
|
||||
import "dart:ffi";
|
||||
|
||||
@#C3
|
||||
class Coordinate extends dart.ffi::Struct {
|
||||
@#C3
|
||||
static final field dart.core::int* #sizeOf = (#C6).{dart.core::List::[]}(dart.ffi::_abi());
|
||||
@#C3
|
||||
constructor #fromPointer(dynamic #pointer) → dynamic
|
||||
: super dart.ffi::Struct::_fromPointer(#pointer)
|
||||
;
|
||||
static factory allocate(dart.core::double* x, dart.core::double* y, dart.ffi::Pointer<lib::Coordinate*>* next) → lib::Coordinate* {
|
||||
dart.core::print("hello");
|
||||
return null;
|
||||
}
|
||||
get #_ptr_x() → dart.ffi::Pointer<dart.ffi::Double*>*
|
||||
return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
|
||||
get x() → dart.core::double*
|
||||
return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_x}, #C7);
|
||||
set x(dart.core::double* #v) → void
|
||||
return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_x}, #C7, #v);
|
||||
get #_ptr_y() → dart.ffi::Pointer<dart.ffi::Double*>*
|
||||
return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C9).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Double*>();
|
||||
get y() → dart.core::double*
|
||||
return dart.ffi::_loadDouble(this.{lib::Coordinate::#_ptr_y}, #C7);
|
||||
set y(dart.core::double* #v) → void
|
||||
return dart.ffi::_storeDouble(this.{lib::Coordinate::#_ptr_y}, #C7, #v);
|
||||
get #_ptr_next() → dart.ffi::Pointer<dart.ffi::Pointer<lib::Coordinate*>*>*
|
||||
return this.{dart.ffi::Struct::_addressOf}.{dart.ffi::Pointer::_offsetBy}((#C11).{dart.core::List::[]}(dart.ffi::_abi())).{dart.ffi::Pointer::cast}<dart.ffi::Pointer<lib::Coordinate*>*>();
|
||||
get next() → dart.ffi::Pointer<lib::Coordinate*>*
|
||||
return dart.ffi::_loadPointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7);
|
||||
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
|
||||
return dart.ffi::_storePointer<dart.ffi::Pointer<lib::Coordinate*>*>(this.{lib::Coordinate::#_ptr_next}, #C7, #v);
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart";
|
||||
|
||||
static method main() → dynamic {
|
||||
lib::Coordinate* coordinate = lib::Coordinate::allocate(42.0, 42.0, null);
|
||||
dart.core::print(coordinate.{lib::Coordinate::x});
|
||||
dart.core::print(coordinate.{lib::Coordinate::y});
|
||||
dart.core::print(coordinate.{lib::Coordinate::next});
|
||||
dart.core::print("Done!");
|
||||
}
|
||||
}
|
||||
constants {
|
||||
#C1 = "vm:entry-point"
|
||||
#C2 = null
|
||||
#C3 = dart.core::pragma {name:#C1, options:#C2}
|
||||
#C4 = 24
|
||||
#C5 = 20
|
||||
#C6 = <dart.core::int*>[#C4, #C5, #C4]
|
||||
#C7 = 0
|
||||
#C8 = 8
|
||||
#C9 = <dart.core::int*>[#C8, #C8, #C8]
|
||||
#C10 = 16
|
||||
#C11 = <dart.core::int*>[#C10, #C10, #C10]
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user