[dart2js] Removing most non-kernel operations from kernel dump info
Note: Function parameter logic is incomplete, and some JElement tables need to be updated.
Change-Id: I429ff40160b0c4e96c6e6916ba371a01c7bb087c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240945
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Mark Zhou <markzipan@google.com>
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index fb3eb0b..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,46 +481,23 @@
}
});
- if (info.isEmpty && !shouldKeep(libEntity)) return null;
result.libraries.add(info);
return info;
}
- 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;
- // If a field has an empty inferred type it is never used.
- if (inferredType == null ||
- closedWorld.abstractValueDomain
- .isEmpty(inferredType)
- .isDefinitelyTrue) {
- return null;
- }
-
- int size = dumpInfoTask.sizeOf(fieldEntity);
- List<CodeSpan> code = dumpInfoTask.codeOf(fieldEntity);
-
- // 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);
+ inferredType: null,
+ code: null,
+ outputUnit: null,
+ isConst: field.isConst,
+ size: null);
_entityToInfo[fieldEntity] = info;
- FieldAnalysisData fieldData =
- closedWorld.fieldAnalysis.getFieldData(fieldEntity);
- if (fieldData.initialValue != null) {
- info.initializer = _constantToInfo[fieldData.initialValue];
- }
if (compiler.options.experimentCallInstrumentation) {
// We use field.hashCode because it is globally unique and it is
@@ -548,27 +505,12 @@
info.coverageId = '${field.hashCode}';
}
- int closureSize = _addClosureInfo(info, fieldEntity);
- info.size = size + closureSize;
-
result.fields.add(info);
return info;
}
- ClassTypeInfo visitClassType(ClassEntity clazz) {
- // Omit class type if it is not needed.
- ClassTypeInfo classTypeInfo = ClassTypeInfo(
- name: clazz.name, outputUnit: _unitInfoForClassType(clazz));
-
- // TODO(joshualitt): Get accurate size information for class types.
- classTypeInfo.size = 0;
-
- bool isNeeded =
- compiler.backendStrategy.emitterTask.neededClassTypes.contains(clazz);
- if (!isNeeded) {
- return null;
- }
-
+ ClassTypeInfo visitClassType(ir.Class clazz) {
+ ClassTypeInfo classTypeInfo = ClassTypeInfo(name: clazz.name);
result.classTypes.add(classTypeInfo);
return classTypeInfo;
}
@@ -576,165 +518,125 @@
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));
+ name: clazz.name, isAbstract: clazz.isAbstract, outputUnit: null);
_entityToInfo[classEntity] = classInfo;
- int size = dumpInfoTask.sizeOf(classEntity);
clazz.members.forEach((ir.Member member) {
+ // clazz.members includes constructors
MemberEntity memberEntity =
- environment.lookupClassMember(classEntity, member.name.text);
+ environment.lookupLocalClassMember(classEntity, member.name.text) ??
+ environment.lookupConstructor(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)) {
+ // 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(memberEntity);
+ FunctionInfo functionInfo =
+ visitFunction(member.function, functionEntity: memberEntity);
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);
if (fieldInfo != null) {
classInfo.fields.add(fieldInfo);
fieldInfo.parent = classInfo;
- for (var closureInfo in fieldInfo.closures) {
- size += closureInfo.size;
- }
}
}
});
- clazz.constructors.forEach((ir.Constructor constructor) {
- final constructorEntity =
- environment.lookupConstructor(classEntity, constructor.name.text);
- if (constructorEntity == null) return;
- FunctionInfo functionInfo = visitFunction(constructorEntity);
- if (functionInfo != null) {
- classInfo.functions.add(functionInfo);
- functionInfo.parent = classInfo;
- for (var closureInfo in functionInfo.closures) {
- size += closureInfo.size;
- }
- }
- });
-
- classInfo.size = size;
-
- if (!compiler.backendStrategy.emitterTask.neededClasses
- .contains(classEntity) &&
- classInfo.fields.isEmpty &&
- classInfo.functions.isEmpty) {
- return null;
- }
-
result.classes.add(classInfo);
return classInfo;
}
- ClosureInfo visitClosureClass(ClassEntity element) {
- ClosureInfo closureInfo = ClosureInfo(
- name: element.name,
- outputUnit: _unitInfoForClass(element),
- size: dumpInfoTask.sizeOf(element));
- _entityToInfo[element] = closureInfo;
-
- FunctionEntity callMethod = closedWorld.elementEnvironment
- .lookupClassMember(element, Identifiers.call);
-
- FunctionInfo functionInfo = visitFunction(callMethod);
- if (functionInfo == null) return null;
- closureInfo.function = functionInfo;
- functionInfo.parent = closureInfo;
-
- result.closures.add(closureInfo);
- return closureInfo;
- }
-
- FunctionInfo visitFunction(FunctionEntity function) {
- 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;
+ 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 (function.isStatic || function.isTopLevel) {
+ if (isTopLevel) {
kind = FunctionInfo.TOP_LEVEL_FUNCTION_KIND;
- } else if (function.enclosingClass != null) {
+ } else if (isMethod) {
kind = FunctionInfo.METHOD_FUNCTION_KIND;
}
-
- if (function.isConstructor) {
- name = name == ""
- ? "${function.enclosingClass.name}"
- : "${function.enclosingClass.name}.${function.name}";
+ 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];
+ }
}
-
- assert(kind != null);
+ if (name.endsWith('.')) name = name.substring(0, name.length - 1);
FunctionModifiers modifiers = FunctionModifiers(
- isStatic: function.isStatic,
- isConst: function.isConst,
- isFactory: function.isConstructor
- ? (function as ConstructorEntity).isFactoryConstructor
- : false,
- isExternal: function.isExternal,
+ isStatic: isStaticMember,
+ isConst: isConst,
+ isFactory: isFactory,
+ isExternal: isExternal,
+ isGetter: isGetter,
+ isSetter: isSetter,
);
- List<CodeSpan> code = dumpInfoTask.codeOf(function);
List<ParameterInfo> parameters = <ParameterInfo>[];
List<String> inferredParameterTypes = <String>[];
closedWorld.elementEnvironment.forEachParameterAsLocal(
- _globalInferenceResults.globalLocalsMap, function, (parameter) {
+ _globalInferenceResults.globalLocalsMap, functionEntity, (parameter) {
inferredParameterTypes.add('${_resultOfParameter(parameter)}');
});
+
int parameterIndex = 0;
- closedWorld.elementEnvironment.forEachParameter(function, (type, name, _) {
+ 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'));
});
- 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];
- if (inlinedCount == null) inlinedCount = 0;
+ // 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: returnType,
- inferredReturnType: inferredReturnType,
+ returnType: function.returnType.toStringInternal(),
+ inferredReturnType: null,
parameters: parameters,
- sideEffects: sideEffects,
- inlinedCount: inlinedCount,
- code: code,
- type: functionType.toString(),
- outputUnit: _unitInfoForMember(function));
- _entityToInfo[function] = info;
-
- int closureSize = _addClosureInfo(info, function);
- size += closureSize;
+ 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
@@ -742,75 +644,9 @@
info.coverageId = '${function.hashCode}';
}
- info.size = size;
-
result.functions.add(info);
return info;
}
-
- /// 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) {
- assert(info is FunctionInfo || info is FieldInfo);
- int size = 0;
- List<ClosureInfo> nestedClosures = <ClosureInfo>[];
- environment.forEachNestedClosure(member, (closure) {
- ClosureInfo closureInfo = visitClosureClass(closure.enclosingClass);
- if (closureInfo != null) {
- closureInfo.parent = info;
- nestedClosures.add(closureInfo);
- size += closureInfo.size;
- }
- });
- if (info is FunctionInfo) info.closures = nestedClosures;
- if (info is FieldInfo) info.closures = nestedClosures;
-
- return size;
- }
-
- OutputUnitInfo _infoFromOutputUnit(OutputUnit outputUnit) {
- return _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;
- assert(outputUnit.name != null || outputUnit.isMainOutput);
- var filename = outputUnit.isMainOutput
- ? compiler.options.outputUri.pathSegments.last
- : deferredPartFileName(compiler.options, outputUnit.name);
- OutputUnitInfo info = OutputUnitInfo(filename, outputUnit.name,
- backendStrategy.emitterTask.emitter.generatedSize(outputUnit));
- info.imports
- .addAll(closedWorld.outputUnitData.getImportNames(outputUnit));
- result.outputUnits.add(info);
- return info;
- });
- }
-
- OutputUnitInfo _unitInfoForMember(MemberEntity entity) {
- return _infoFromOutputUnit(
- closedWorld.outputUnitData.outputUnitForMember(entity));
- }
-
- OutputUnitInfo _unitInfoForClass(ClassEntity entity) {
- return _infoFromOutputUnit(
- closedWorld.outputUnitData.outputUnitForClass(entity, allowNull: true));
- }
-
- OutputUnitInfo _unitInfoForClassType(ClassEntity entity) {
- return _infoFromOutputUnit(closedWorld.outputUnitData
- .outputUnitForClassType(entity, allowNull: true));
- }
-
- OutputUnitInfo _unitInfoForConstant(ConstantValue constant) {
- OutputUnit outputUnit =
- closedWorld.outputUnitData.outputUnitForConstant(constant);
- if (outputUnit == null) {
- assert(constant is InterceptorConstantValue);
- return null;
- }
- return _infoFromOutputUnit(outputUnit);
- }
}
/// Annotates [KernelInfoCollector] with info extracted from closed-world
@@ -1364,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);
}