docs: function(dump) {
        // Completely skip dumps with undefined size. As a result, each dump will
        // have defined effective size if and only if it has defined size.
        if (!hasSize(dump)) {
          // The rest of the pipeline relies on effective size being either a
          // valid ScalarAttribute, or undefined.
          dump.attributes[EFFECTIVE_SIZE_ATTRIBUTE_NAME] = undefined;
          return;
        }
  
        var effectiveSize;
        if (dump.children === undefined || dump.children.length === 0) {
          // Leaf dump.
          effectiveSize = getSize(dump) * dump.cumulativeOwningCoefficient_ *
              dump.cumulativeOwnedCoefficient_;
        } else {
          // Non-leaf dump.
          effectiveSize = 0;
          dump.children.forEach(function(childDump) {
            if (!hasSize(childDump))
              return;
            effectiveSize +=
                childDump.attributes[EFFECTIVE_SIZE_ATTRIBUTE_NAME].value;
          });
        }
        var attribute = new tr.model.ScalarAttribute('bytes', effectiveSize);
        dump.attributes[EFFECTIVE_SIZE_ATTRIBUTE_NAME] = attribute;
  
        // Add attribute infos regarding ownership (if applicable).
        // TODO(petrcermak): This belongs to the corresponding analysis UI code.
        if (dump.ownedBy.length > 0) {
          var message = 'shared by:' +
              dump.ownedBy.map(function(ownershipLink) {
                return '\n  - ' + ownershipToUserFriendlyString(
                    ownershipLink.source, ownershipLink.importance);
              }).join();
          attribute.infos.push(new tr.model.AttributeInfo(
              tr.model.AttributeInfoType.MEMORY_OWNED, message));
        }
        if (dump.owns !== undefined) {
          var target = dump.owns.target;
          var message = 'shares ' +
              ownershipToUserFriendlyString(target, dump.owns.importance) +
              ' with';
  
          var otherOwnershipLinks = target.ownedBy.filter(
              function(ownershipLink) {
            return ownershipLink.source !== dump;
          });
          if (otherOwnershipLinks.length > 0) {
            message += ':';
            message += otherOwnershipLinks.map(function(ownershipLink) {
              return '\n  - ' + ownershipToUserFriendlyString(
                  ownershipLink.source, ownershipLink.importance);
            }).join();
          } else {
            message += ' no other dumps';
          }
  
          attribute.infos.push(new tr.model.AttributeInfo(
              tr.model.AttributeInfoType.MEMORY_OWNER, message));
        }
      }