anchor.diff:      }
       final outputPath = args['out'];
       final AllInfo allInfo = await infoFromFile(args.rest.first);
  +
  +    /// Mapping between the filename of the outputUnit and the name
  +    /// of the corresponding outputUnit root to store in the treemap.
  +    final Map<String, String> treemapRoots = {};
  +
  +    /// Mapping between the filename and size of the outputUnit.
  +    final Map<String, int> treemapSizes = {};
  +    for (var outputUnit in allInfo.outputUnits) {
  +      treemapRoots[outputUnit.filename] = outputUnit.name;
  +      treemapSizes[outputUnit.filename] = outputUnit.size;
  +    }
       final builder = ProgramInfoBuilder(allInfo);
  -    vm.ProgramInfo programInfo = builder.build(allInfo);
  -    Map<String, dynamic> programInfoTree = programInfo.toJson();
  -    // TODO: convert the programInfo tree to a treemap
  +    final outputUnits = builder.outputUnitMap(allInfo);
  +
  +    /// For deferred apps, VM Devtools expects an artificial root whose children
  +    /// are a single main unit followed by each of the deferred units. For non-
  +    /// deferred apps, VM Devtools expects a root with its children in the main
  +    /// unit.
  +    Map<String, dynamic> output = {};
  +    output['n'] = '';
  +    output['type'] = "web";
  +
  +    if (outputUnits.length == 1) {
  +      vm.ProgramInfo programInfoTree =
  +          builder.build(allInfo, outputUnits.keys.first);
  +      Map<String, dynamic> treeMap = treemapFromInfo(programInfoTree);
  +      output = treeMap;
  +      output['n'] = 'Root';
  +    } else {
  +      output['n'] = "ArtificialRoot";
  +      output['children'] = [];
  +      Map<String, dynamic> mainOutput = {};
  +      List<dynamic> deferredOutputs = [];
  +      for (var outputUnitName in outputUnits.keys) {
  +        vm.ProgramInfo programInfoTree = builder.build(allInfo, outputUnitName);
  +        Map<String, dynamic> treeMap = treemapFromInfo(programInfoTree);
  +        treeMap['n'] = treemapRoots[outputUnitName];
  +        if (treeMap['n'] == 'main') {
  +          mainOutput.addAll(treeMap);
  +          treeMap['isDeferred'] = false;
  +          // recursively visit children
  +          List<dynamic> mainStack = [];
  +          mainStack.add(treeMap);
  +          while (mainStack.isNotEmpty) {
  +            var item = mainStack.removeLast();
  +            item['isDeferred'] = false;
  +            mainStack.addAll(item['children'] ?? []);
  +          }
  +        } else {
  +          Map<String, dynamic> deferredOutput = {};
  +          deferredOutput.addAll(treeMap);
  +          treeMap['isDeferred'] = true;
  +          List<dynamic> deferredStack = [];
  +          deferredStack.add(treeMap);
  +          while (deferredStack.isNotEmpty) {
  +            var item = deferredStack.removeLast();
  +            item['isDeferred'] = true;
  +            deferredStack.addAll(item['children'] ?? []);
  +          }
  +          deferredOutputs.add(deferredOutput);
  +        }
  +        treeMap['value'] = treemapSizes[outputUnitName];
  +      }
  +      output['children'].add(mainOutput);
  +      for (var deferredUnit in deferredOutputs) {
  +        output['children'].add(deferredUnit);
  +      }
  +    }
       if (outputPath == null) {
  -      print(jsonEncode(programInfoTree));
  +      print(jsonEncode(output));
       } else {
  -      await File(outputPath).writeAsString(jsonEncode(programInfoTree));
  +      await io.File(outputPath).writeAsString(jsonEncode(output));
       }
     }
   }
  
positive.code:       newPackage.size = libraryInfo.size;
        packageInfoNodes[compositePackageName] = newPackage;
        outputUnit.root.children[compositePackageName] = newPackage;
        outputInfo.add(newPackage);
        var packageNode = infoNodesByName[compositePackageName];
        assert(packageNode == null,
            "encountered package with duplicated name: $compositePackageName");
  
negative.code:     vm.ProgramInfoNode? typedefNode = infoNodesByName[newTypedef.name];
      assert(typedefNode == null,
          "encountered constant with duplicated name: $newTypedef.name");
    }
  
    void makeClassType(ClassTypeInfo classTypeInfo) {
  