[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);
       }