Version 2.18.0-21.0.dev
Merge commit '61a4d7ef68f98186d924fb8499b34c4b93e1b07e' into 'dev'
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index e66e57d..10b0b88 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -306,7 +306,7 @@
inferredParameterTypes[parameterIndex++], '$type'));
});
- var functionType = environment.getFunctionType(function);
+ final functionType = environment.getFunctionType(function);
String returnType = '${functionType.returnType}';
String inferredReturnType = '${_resultOfMember(function).returnType}';
@@ -428,29 +428,10 @@
this.closedWorld, this._globalInferenceResults);
void run() {
- dumpInfoTask._constantToNode.forEach((constant, node) {
- // TODO(sigmund): add dependencies on other constants
- var span = dumpInfoTask._nodeData[node];
- var info = ConstantInfo(
- size: span.end - span.start,
- code: [span],
- outputUnit: _unitInfoForConstant(constant));
- _constantToInfo[constant] = info;
- result.constants.add(info);
- });
+ // TODO(markzipan): Add CFE constants to `result.constants`.
component.libraries.forEach(visitLibrary);
}
- /// Whether to emit information about [entity].
- ///
- /// By default we emit information for any entity that contributes to the
- /// output size. Either because it is a function being emitted or inlined,
- /// or because it is an entity that holds dependencies to other entities.
- bool shouldKeep(Entity entity) {
- return dumpInfoTask.impacts.containsKey(entity) ||
- dumpInfoTask.inlineCount.containsKey(entity);
- }
-
LibraryInfo visitLibrary(ir.Library lib) {
final libEntity = environment.lookupLibrary(lib.importUri);
if (libEntity == null) return null;
@@ -460,17 +441,16 @@
libname = '<unnamed>';
}
- int size = dumpInfoTask.sizeOf(libEntity);
- LibraryInfo info = LibraryInfo(libname, lib.importUri, null, size);
+ LibraryInfo info = LibraryInfo(libname, lib.importUri, null, null);
_entityToInfo[libEntity] = info;
lib.members.forEach((ir.Member member) {
final memberEntity =
environment.lookupLibraryMember(libEntity, member.name.text);
if (memberEntity == null) return;
-
if (member.function != null) {
- FunctionInfo functionInfo = visitFunction(memberEntity);
+ FunctionInfo functionInfo =
+ visitFunction(member.function, functionEntity: memberEntity);
if (functionInfo != null) {
info.topLevelFunctions.add(functionInfo);
functionInfo.parent = info;
@@ -488,7 +468,7 @@
final classEntity = environment.lookupClass(libEntity, clazz.name);
if (classEntity == null) return;
- ClassTypeInfo classTypeInfo = visitClassType(classEntity);
+ ClassTypeInfo classTypeInfo = visitClassType(clazz);
if (classTypeInfo != null) {
info.classTypes.add(classTypeInfo);
classTypeInfo.parent = info;
@@ -501,19 +481,265 @@
}
});
- if (info.isEmpty && !shouldKeep(libEntity)) return null;
result.libraries.add(info);
return info;
}
+ AbstractValue _resultOfParameter(Local e) =>
+ _globalInferenceResults.resultOfParameter(e);
+
+ FieldInfo visitField(ir.Field field, {FieldEntity fieldEntity}) {
+ FieldInfo info = FieldInfo(
+ name: field.name.text,
+ type: field.type.toStringInternal(),
+ inferredType: null,
+ code: null,
+ outputUnit: null,
+ isConst: field.isConst,
+ size: null);
+ _entityToInfo[fieldEntity] = info;
+
+ if (compiler.options.experimentCallInstrumentation) {
+ // We use field.hashCode because it is globally unique and it is
+ // available while we are doing codegen.
+ info.coverageId = '${field.hashCode}';
+ }
+
+ result.fields.add(info);
+ return info;
+ }
+
+ ClassTypeInfo visitClassType(ir.Class clazz) {
+ ClassTypeInfo classTypeInfo = ClassTypeInfo(name: clazz.name);
+ result.classTypes.add(classTypeInfo);
+ return classTypeInfo;
+ }
+
+ ClassInfo visitClass(ir.Class clazz, {ClassEntity classEntity}) {
+ // Omit class if it is not needed.
+ ClassInfo classInfo = ClassInfo(
+ name: clazz.name, isAbstract: clazz.isAbstract, outputUnit: null);
+ _entityToInfo[classEntity] = classInfo;
+
+ clazz.members.forEach((ir.Member member) {
+ // clazz.members includes constructors
+ MemberEntity memberEntity =
+ environment.lookupLocalClassMember(classEntity, member.name.text) ??
+ environment.lookupConstructor(classEntity, member.name.text);
+ if (memberEntity == null) return;
+ // Multiple kernel members can map to single JWorld member
+ // (e.g., when one of a getter/field pair are tree-shaken),
+ // so avoid duplicating the downstream info object.
+ if (_entityToInfo.containsKey(memberEntity)) {
+ return;
+ }
+
+ if (member.function != null) {
+ FunctionInfo functionInfo =
+ visitFunction(member.function, functionEntity: memberEntity);
+ if (functionInfo != null) {
+ classInfo.functions.add(functionInfo);
+ functionInfo.parent = classInfo;
+ }
+ } else {
+ FieldInfo fieldInfo = visitField(member, fieldEntity: memberEntity);
+ if (fieldInfo != null) {
+ classInfo.fields.add(fieldInfo);
+ fieldInfo.parent = classInfo;
+ }
+ }
+ });
+
+ result.classes.add(classInfo);
+ return classInfo;
+ }
+
+ FunctionInfo visitFunction(ir.FunctionNode function,
+ {FunctionEntity functionEntity}) {
+ var parent = function.parent;
+ String name = parent.toStringInternal();
+ bool isConstructor = parent is ir.Constructor;
+ bool isFactory = parent is ir.Procedure && parent.isFactory;
+ // Kernel `isStatic` refers to static members, constructors, and top-level
+ // members.
+ bool isTopLevel = ((parent is ir.Field && parent.isStatic) ||
+ (parent is ir.Procedure && parent.isStatic)) &&
+ (parent is ir.Member && parent.enclosingClass == null);
+ bool isStaticMember = ((parent is ir.Field && parent.isStatic) ||
+ (parent is ir.Procedure && parent.isStatic)) &&
+ (parent is ir.Member && parent.enclosingClass != null) &&
+ !isConstructor &&
+ !isFactory;
+ bool isConst = parent is ir.Member && parent.isConst;
+ bool isExternal = parent is ir.Member && parent.isExternal;
+ bool isMethod = parent is ir.Member && parent.enclosingClass != null;
+ bool isGetter = parent is ir.Procedure && parent.isGetter;
+ bool isSetter = parent is ir.Procedure && parent.isSetter;
+ int kind;
+ if (isTopLevel) {
+ kind = FunctionInfo.TOP_LEVEL_FUNCTION_KIND;
+ } else if (isMethod) {
+ kind = FunctionInfo.METHOD_FUNCTION_KIND;
+ }
+ if (isConstructor || isFactory) {
+ kind = FunctionInfo.CONSTRUCTOR_FUNCTION_KIND;
+ String functionName = function.toStringInternal();
+ name = functionName.isEmpty ? '$name' : '$name$functionName';
+ } else {
+ if (parent.parent is ir.Class && name.contains('.')) {
+ name = name.split('.')[1];
+ }
+ }
+ if (name.endsWith('.')) name = name.substring(0, name.length - 1);
+
+ FunctionModifiers modifiers = FunctionModifiers(
+ isStatic: isStaticMember,
+ isConst: isConst,
+ isFactory: isFactory,
+ isExternal: isExternal,
+ isGetter: isGetter,
+ isSetter: isSetter,
+ );
+
+ List<ParameterInfo> parameters = <ParameterInfo>[];
+ List<String> inferredParameterTypes = <String>[];
+
+ closedWorld.elementEnvironment.forEachParameterAsLocal(
+ _globalInferenceResults.globalLocalsMap, functionEntity, (parameter) {
+ inferredParameterTypes.add('${_resultOfParameter(parameter)}');
+ });
+
+ int parameterIndex = 0;
+ closedWorld.elementEnvironment.forEachParameter(functionEntity,
+ (type, name, _) {
+ // Synthesized parameters have no name. This can happen on parameters of
+ // setters derived from lowering late fields.
+ parameters.add(ParameterInfo(name ?? '#t${parameterIndex}',
+ inferredParameterTypes[parameterIndex++], '$type'));
+ });
+
+ // TODO(markzipan): Determine if it's safe to default to nonNullable here.
+ final nullability = parent is ir.Member
+ ? parent.enclosingLibrary.nonNullable
+ : ir.Nullability.nonNullable;
+ final functionType = function.computeFunctionType(nullability);
+
+ FunctionInfo info = FunctionInfo(
+ name: name,
+ functionKind: kind,
+ modifiers: modifiers,
+ returnType: function.returnType.toStringInternal(),
+ inferredReturnType: null,
+ parameters: parameters,
+ sideEffects: null,
+ inlinedCount: null,
+ code: null,
+ type: functionType.toStringInternal(),
+ outputUnit: null);
+ _entityToInfo[functionEntity] = info;
+
+ if (compiler.options.experimentCallInstrumentation) {
+ // We use function.hashCode because it is globally unique and it is
+ // available while we are doing codegen.
+ info.coverageId = '${function.hashCode}';
+ }
+
+ result.functions.add(info);
+ return info;
+ }
+}
+
+/// Annotates [KernelInfoCollector] with info extracted from closed-world
+/// analysis.
+class DumpInfoAnnotator {
+ final KernelInfoCollector kernelInfo;
+ final Compiler compiler;
+ final JClosedWorld closedWorld;
+ final GlobalTypeInferenceResults _globalInferenceResults;
+ final DumpInfoTask dumpInfoTask;
+
+ JElementEnvironment get environment => closedWorld.elementEnvironment;
+
+ DumpInfoAnnotator(this.kernelInfo, this.compiler, this.dumpInfoTask,
+ this.closedWorld, this._globalInferenceResults);
+
+ void run() {
+ dumpInfoTask._constantToNode.forEach((constant, node) {
+ // TODO(sigmund): add dependencies on other constants
+ var span = dumpInfoTask._nodeData[node];
+ var info = ConstantInfo(
+ size: span.end - span.start,
+ code: [span],
+ outputUnit: _unitInfoForConstant(constant));
+ kernelInfo._constantToInfo[constant] = info;
+ info.treeShakenStatus = TreeShakenStatus.Live;
+ kernelInfo.result.constants.add(info);
+ });
+ environment.libraries.forEach(visitLibrary);
+ }
+
+ /// Whether to emit information about [entity].
+ ///
+ /// By default we emit information for any entity that contributes to the
+ /// output size. Either because it is a function being emitted or inlined,
+ /// or because it is an entity that holds dependencies to other entities.
+ bool shouldKeep(Entity entity) {
+ return dumpInfoTask.impacts.containsKey(entity) ||
+ dumpInfoTask.inlineCount.containsKey(entity);
+ }
+
+ LibraryInfo visitLibrary(LibraryEntity lib) {
+ var kLibraryInfos = kernelInfo.result.libraries
+ .where((i) => '${i.uri}' == '${lib.canonicalUri}');
+ assert(
+ kLibraryInfos.length == 1,
+ 'Ambiguous library resolution. '
+ 'Expected singleton, found $kLibraryInfos');
+ var kLibraryInfo = kLibraryInfos.first;
+
+ String libname = environment.getLibraryName(lib);
+ if (libname.isEmpty) {
+ libname = '<unnamed>';
+ }
+ assert(kLibraryInfo.name == libname);
+ kLibraryInfo.size = dumpInfoTask.sizeOf(lib);
+
+ environment.forEachLibraryMember(lib, (MemberEntity member) {
+ if (member.isFunction || member.isGetter || member.isSetter) {
+ visitFunction(member, libname);
+ } else if (member.isField) {
+ visitField(member, libname);
+ } else {
+ throw StateError('Class member not a function or field');
+ }
+ });
+
+ environment.forEachClass(lib, (ClassEntity clazz) {
+ visitClassType(clazz, libname);
+ visitClass(clazz, libname);
+ });
+
+ bool hasLiveFields = [
+ ...kLibraryInfo.topLevelFunctions,
+ ...kLibraryInfo.topLevelVariables,
+ ...kLibraryInfo.classes,
+ ...kLibraryInfo.classTypes
+ ].any((i) => i.treeShakenStatus == TreeShakenStatus.Live);
+ if (!hasLiveFields && !shouldKeep(lib)) return null;
+ kLibraryInfo.treeShakenStatus = TreeShakenStatus.Live;
+ return kLibraryInfo;
+ }
+
GlobalTypeInferenceMemberResult _resultOfMember(MemberEntity e) =>
_globalInferenceResults.resultOfMember(e);
AbstractValue _resultOfParameter(Local e) =>
_globalInferenceResults.resultOfParameter(e);
- FieldInfo visitField(ir.Field field, {FieldEntity fieldEntity}) {
- AbstractValue inferredType = _resultOfMember(fieldEntity).type;
+ // TODO(markzipan): [parentName] is used for disambiguation, but this might
+ // not always be valid. Check and validate later.
+ FieldInfo visitField(FieldEntity field, String parentName) {
+ AbstractValue inferredType = _resultOfMember(field).type;
// If a field has an empty inferred type it is never used.
if (inferredType == null ||
closedWorld.abstractValueDomain
@@ -522,123 +748,114 @@
return null;
}
- int size = dumpInfoTask.sizeOf(fieldEntity);
- List<CodeSpan> code = dumpInfoTask.codeOf(fieldEntity);
+ final kFieldInfos = kernelInfo.result.fields
+ .where((f) => f.name == field.name && f.parent.name == parentName)
+ .toList();
+ assert(
+ kFieldInfos.length == 1,
+ 'Ambiguous field resolution. '
+ 'Expected singleton, found $kFieldInfos');
+ final kFieldInfo = kFieldInfos.first;
+
+ int size = dumpInfoTask.sizeOf(field);
+ List<CodeSpan> code = dumpInfoTask.codeOf(field);
// TODO(het): Why doesn't `size` account for the code size already?
if (code != null) size += code.length;
- FieldInfo info = FieldInfo(
- name: field.name.text,
- type: field.type.toStringInternal(),
- inferredType: '$inferredType',
- code: code,
- outputUnit: _unitInfoForMember(fieldEntity),
- isConst: field.isConst);
- _entityToInfo[fieldEntity] = info;
- FieldAnalysisData fieldData =
- closedWorld.fieldAnalysis.getFieldData(fieldEntity);
+ kFieldInfo.outputUnit = _unitInfoForMember(field);
+ kFieldInfo.inferredType = '$inferredType';
+ kFieldInfo.code = code;
+ kFieldInfo.treeShakenStatus = TreeShakenStatus.Live;
+
+ FieldAnalysisData fieldData = closedWorld.fieldAnalysis.getFieldData(field);
if (fieldData.initialValue != null) {
- info.initializer = _constantToInfo[fieldData.initialValue];
+ kFieldInfo.initializer =
+ kernelInfo._constantToInfo[fieldData.initialValue];
}
- if (compiler.options.experimentCallInstrumentation) {
- // We use field.hashCode because it is globally unique and it is
- // available while we are doing codegen.
- info.coverageId = '${field.hashCode}';
- }
-
- int closureSize = _addClosureInfo(info, fieldEntity);
- info.size = size + closureSize;
-
- result.fields.add(info);
- return info;
+ int closureSize = _addClosureInfo(kFieldInfo, field);
+ kFieldInfo.size = size + closureSize;
+ return kFieldInfo;
}
- ClassTypeInfo visitClassType(ClassEntity clazz) {
- // Omit class type if it is not needed.
- ClassTypeInfo classTypeInfo = ClassTypeInfo(
- name: clazz.name, outputUnit: _unitInfoForClassType(clazz));
+ // TODO(markzipan): [parentName] is used for disambiguation, but this might
+ // not always be valid. Check and validate later.
+ ClassTypeInfo visitClassType(ClassEntity clazz, String parentName) {
+ var kClassTypeInfos = kernelInfo.result.classTypes
+ .where((i) => i.name == clazz.name && i.parent.name == parentName);
+ assert(
+ kClassTypeInfos.length == 1,
+ 'Ambiguous class type resolution. '
+ 'Expected singleton, found $kClassTypeInfos');
+ var kClassTypeInfo = kClassTypeInfos.first;
// TODO(joshualitt): Get accurate size information for class types.
- classTypeInfo.size = 0;
+ kClassTypeInfo.size = 0;
+ // Omit class type if it is not needed.
bool isNeeded =
compiler.backendStrategy.emitterTask.neededClassTypes.contains(clazz);
- if (!isNeeded) {
- return null;
- }
+ if (!isNeeded) return null;
- result.classTypes.add(classTypeInfo);
- return classTypeInfo;
+ assert(kClassTypeInfo.name == clazz.name);
+ kClassTypeInfo.outputUnit = _unitInfoForClassType(clazz);
+ kClassTypeInfo.treeShakenStatus = TreeShakenStatus.Live;
+ return kClassTypeInfo;
}
- ClassInfo visitClass(ir.Class clazz, {ClassEntity classEntity}) {
- // Omit class if it is not needed.
- ClassInfo classInfo = ClassInfo(
- name: clazz.name,
- isAbstract: clazz.isAbstract,
- outputUnit: _unitInfoForClass(classEntity));
- _entityToInfo[classEntity] = classInfo;
+ // TODO(markzipan): [parentName] is used for disambiguation, but this might
+ // not always be valid. Check and validate later.
+ ClassInfo visitClass(ClassEntity clazz, String parentName) {
+ final kClassInfos = kernelInfo.result.classes
+ .where((i) => i.name == clazz.name && i.parent.name == parentName)
+ .toList();
+ assert(
+ kClassInfos.length == 1,
+ 'Ambiguous class resolution. '
+ 'Expected singleton, found $kClassInfos');
+ final kClassInfo = kClassInfos.first;
- int size = dumpInfoTask.sizeOf(classEntity);
- clazz.members.forEach((ir.Member member) {
- MemberEntity memberEntity =
- environment.lookupClassMember(classEntity, member.name.text);
- if (memberEntity == null) return;
- // Note: JWorld representations of a kernel member may omit the field or
- // getter. Filter those cases here.
- if ((member is ir.Field && memberEntity is! FieldEntity) ||
- (member is ir.Procedure && memberEntity is! FunctionEntity)) {
- return;
- }
-
- if (member.function != null) {
- FunctionInfo functionInfo = visitFunction(memberEntity);
+ int size = dumpInfoTask.sizeOf(clazz);
+ environment.forEachLocalClassMember(clazz, (member) {
+ if (member.isFunction || member.isGetter || member.isSetter) {
+ FunctionInfo functionInfo = visitFunction(member, clazz.name);
if (functionInfo != null) {
- classInfo.functions.add(functionInfo);
- functionInfo.parent = classInfo;
for (var closureInfo in functionInfo.closures) {
size += closureInfo.size;
}
}
- } else {
- FieldInfo fieldInfo = visitField(member, fieldEntity: memberEntity);
+ } else if (member.isField) {
+ FieldInfo fieldInfo = visitField(member, clazz.name);
if (fieldInfo != null) {
- classInfo.fields.add(fieldInfo);
- fieldInfo.parent = classInfo;
for (var closureInfo in fieldInfo.closures) {
size += closureInfo.size;
}
}
+ } else {
+ throw StateError('Class member not a function or field');
}
});
-
- clazz.constructors.forEach((ir.Constructor constructor) {
- final constructorEntity =
- environment.lookupConstructor(classEntity, constructor.name.text);
- if (constructorEntity == null) return;
- FunctionInfo functionInfo = visitFunction(constructorEntity);
+ environment.forEachConstructor(clazz, (constructor) {
+ FunctionInfo functionInfo = visitFunction(constructor, clazz.name);
if (functionInfo != null) {
- classInfo.functions.add(functionInfo);
- functionInfo.parent = classInfo;
for (var closureInfo in functionInfo.closures) {
size += closureInfo.size;
}
}
});
+ kClassInfo.size = size;
- classInfo.size = size;
-
- if (!compiler.backendStrategy.emitterTask.neededClasses
- .contains(classEntity) &&
- classInfo.fields.isEmpty &&
- classInfo.functions.isEmpty) {
+ bool hasLiveFields = [...kClassInfo.fields, ...kClassInfo.functions]
+ .any((i) => i.treeShakenStatus == TreeShakenStatus.Live);
+ if (!compiler.backendStrategy.emitterTask.neededClasses.contains(clazz) &&
+ !hasLiveFields) {
return null;
}
- result.classes.add(classInfo);
- return classInfo;
+ kClassInfo.outputUnit = _unitInfoForClass(clazz);
+ kClassInfo.treeShakenStatus = TreeShakenStatus.Live;
+ return kClassInfo;
}
ClosureInfo visitClosureClass(ClassEntity element) {
@@ -646,54 +863,53 @@
name: element.name,
outputUnit: _unitInfoForClass(element),
size: dumpInfoTask.sizeOf(element));
- _entityToInfo[element] = closureInfo;
+ kernelInfo._entityToInfo[element] = closureInfo;
FunctionEntity callMethod = closedWorld.elementEnvironment
.lookupClassMember(element, Identifiers.call);
- FunctionInfo functionInfo = visitFunction(callMethod);
+ FunctionInfo functionInfo = visitFunction(callMethod, element.name);
if (functionInfo == null) return null;
+
closureInfo.function = functionInfo;
functionInfo.parent = closureInfo;
+ closureInfo.treeShakenStatus = TreeShakenStatus.Live;
- result.closures.add(closureInfo);
+ kernelInfo.result.closures.add(closureInfo);
return closureInfo;
}
- FunctionInfo visitFunction(FunctionEntity function) {
+ // TODO(markzipan): [parentName] is used for disambiguation, but this might
+ // not always be valid. Check and validate later.
+ FunctionInfo visitFunction(FunctionEntity function, String parentName) {
int size = dumpInfoTask.sizeOf(function);
// TODO(sigmund): consider adding a small info to represent unreachable
// code here.
if (size == 0 && !shouldKeep(function)) return null;
- // TODO(het): use 'toString' instead of 'text'? It will add '=' for setters
- String name = function.memberName.text;
- int kind;
- if (function.isStatic || function.isTopLevel) {
- kind = FunctionInfo.TOP_LEVEL_FUNCTION_KIND;
- } else if (function.enclosingClass != null) {
- kind = FunctionInfo.METHOD_FUNCTION_KIND;
- }
-
+ var compareName = function.name;
if (function.isConstructor) {
- name = name == ""
+ compareName = compareName == ""
? "${function.enclosingClass.name}"
: "${function.enclosingClass.name}.${function.name}";
- kind = FunctionInfo.CONSTRUCTOR_FUNCTION_KIND;
}
- assert(kind != null);
+ // Multiple kernel members members can sometimes map to a single JElement.
+ // [isSetter] and [isGetter] are required for disambiguating these cases.
+ final kFunctionInfos = kernelInfo.result.functions
+ .where((i) =>
+ i.name == compareName &&
+ i.parent.name == parentName &&
+ !(function.isGetter ^ i.modifiers.isGetter) &&
+ !(function.isSetter ^ i.modifiers.isSetter))
+ .toList();
+ assert(
+ kFunctionInfos.length == 1,
+ 'Ambiguous function resolution. '
+ 'Expected singleton, found $kFunctionInfos');
+ final kFunctionInfo = kFunctionInfos.first;
- FunctionModifiers modifiers = FunctionModifiers(
- isStatic: function.isStatic,
- isConst: function.isConst,
- isFactory: function.isConstructor
- ? (function as ConstructorEntity).isFactoryConstructor
- : false,
- isExternal: function.isExternal,
- );
List<CodeSpan> code = dumpInfoTask.codeOf(function);
-
List<ParameterInfo> parameters = <ParameterInfo>[];
List<String> inferredParameterTypes = <String>[];
@@ -709,49 +925,28 @@
inferredParameterTypes[parameterIndex++], '$type'));
});
- var functionType = environment.getFunctionType(function);
- String returnType = '${functionType.returnType}';
-
String inferredReturnType = '${_resultOfMember(function).returnType}';
String sideEffects =
'${_globalInferenceResults.inferredData.getSideEffectsOfElement(function)}';
+ int inlinedCount = dumpInfoTask.inlineCount[function] ?? 0;
- int inlinedCount = dumpInfoTask.inlineCount[function];
- if (inlinedCount == null) inlinedCount = 0;
+ kFunctionInfo.inferredReturnType = inferredReturnType;
+ kFunctionInfo.sideEffects = sideEffects;
+ kFunctionInfo.inlinedCount = inlinedCount;
+ kFunctionInfo.code = code;
+ kFunctionInfo.outputUnit = _unitInfoForMember(function);
- FunctionInfo info = FunctionInfo(
- name: name,
- functionKind: kind,
- modifiers: modifiers,
- returnType: returnType,
- inferredReturnType: inferredReturnType,
- parameters: parameters,
- sideEffects: sideEffects,
- inlinedCount: inlinedCount,
- code: code,
- type: functionType.toString(),
- outputUnit: _unitInfoForMember(function));
- _entityToInfo[function] = info;
+ int closureSize = _addClosureInfo(kFunctionInfo, function);
+ kFunctionInfo.size = size + closureSize;
- int closureSize = _addClosureInfo(info, function);
- size += closureSize;
-
- if (compiler.options.experimentCallInstrumentation) {
- // We use function.hashCode because it is globally unique and it is
- // available while we are doing codegen.
- info.coverageId = '${function.hashCode}';
- }
-
- info.size = size;
-
- result.functions.add(info);
- return info;
+ kFunctionInfo.treeShakenStatus = TreeShakenStatus.Live;
+ return kFunctionInfo;
}
/// Adds closure information to [info], using all nested closures in [member].
///
/// Returns the total size of the nested closures, to add to the info size.
- int _addClosureInfo(Info info, MemberEntity member) {
+ int _addClosureInfo(BasicInfo info, MemberEntity member) {
assert(info is FunctionInfo || info is FieldInfo);
int size = 0;
List<ClosureInfo> nestedClosures = <ClosureInfo>[];
@@ -759,6 +954,7 @@
ClosureInfo closureInfo = visitClosureClass(closure.enclosingClass);
if (closureInfo != null) {
closureInfo.parent = info;
+ closureInfo.treeShakenStatus = info.treeShakenStatus;
nestedClosures.add(closureInfo);
size += closureInfo.size;
}
@@ -770,7 +966,7 @@
}
OutputUnitInfo _infoFromOutputUnit(OutputUnit outputUnit) {
- return _outputToInfo.putIfAbsent(outputUnit, () {
+ return kernelInfo._outputToInfo.putIfAbsent(outputUnit, () {
// Dump-info currently only works with the full emitter. If another
// emitter is used it will fail here.
JsBackendStrategy backendStrategy = compiler.backendStrategy;
@@ -780,9 +976,10 @@
: deferredPartFileName(compiler.options, outputUnit.name);
OutputUnitInfo info = OutputUnitInfo(filename, outputUnit.name,
backendStrategy.emitterTask.emitter.generatedSize(outputUnit));
+ info.treeShakenStatus = TreeShakenStatus.Live;
info.imports
.addAll(closedWorld.outputUnitData.getImportNames(outputUnit));
- result.outputUnits.add(info);
+ kernelInfo.result.outputUnits.add(info);
return info;
});
}
@@ -1003,11 +1200,15 @@
component, compiler, this, closedWorld, globalInferenceResults)
..run();
+ DumpInfoAnnotator(kernelInfoCollector, compiler, this, closedWorld,
+ globalInferenceResults)
+ ..run();
+
var allInfo = buildDumpInfoDataNew(closedWorld, kernelInfoCollector);
// TODO(markzipan): Filter DumpInfo here instead of passing a filter
// filter flag through the serializers.
if (useBinaryFormat) {
- dumpInfoBinary(allInfo, filterTreeshaken: true);
+ dumpInfoBinary(allInfo);
} else {
dumpInfoJson(allInfo, filterTreeshaken: true);
}
diff --git a/pkg/dart2js_info/lib/info.dart b/pkg/dart2js_info/lib/info.dart
index d5d64bf..ad45c6f 100644
--- a/pkg/dart2js_info/lib/info.dart
+++ b/pkg/dart2js_info/lib/info.dart
@@ -467,12 +467,17 @@
final bool isConst;
final bool isFactory;
final bool isExternal;
+ final bool isGetter;
+ final bool isSetter;
- FunctionModifiers(
- {this.isStatic = false,
- this.isConst = false,
- this.isFactory = false,
- this.isExternal = false});
+ FunctionModifiers({
+ this.isStatic = false,
+ this.isConst = false,
+ this.isFactory = false,
+ this.isExternal = false,
+ this.isGetter,
+ this.isSetter,
+ });
}
/// Possible values of the `kind` field in the serialized infos.
diff --git a/tools/VERSION b/tools/VERSION
index c45d641..3e0b84e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 20
+PRERELEASE 21
PRERELEASE_PATCH 0
\ No newline at end of file