/** * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ 'use strict'; /*eslint no-console-disallow: "off"*/ /*global React ReactDOM Table stringInterner stackRegistry aggrow preLoadedCapture:true*/var _jsxFileName='src/heapCapture.js'; function registerReactComponentTreeImpl(refs,registry,parents,inEdgeNames,trees,id){ if(parents[id]===undefined){ // not a component }else if(parents[id]===null){ trees[id]=registry.insert(registry.root,'');}else { var parent=parents[id]; var inEdgeName=inEdgeNames[id]; var parentTree=trees[parent]; if(parentTree===undefined){ parentTree=registerReactComponentTreeImpl( refs, registry, parents, inEdgeNames, trees, parent);} trees[id]=registry.insert(parentTree,inEdgeName);} return trees[id];} // TODO: make it easier to query the heap graph, it's super annoying to deal with edges directly function registerReactComponentTree(refs,registry){ // build list of parents for react interal instances, so we can connect a tree var parents={}; var inEdgeNames={}; for(var id in refs){ var ref=refs[id]; for(var linkId in ref.edges){ if(linkId!=='0x0'){ var name=ref.edges[linkId]; if(name==='_renderedChildren'){ if(parents[id]===undefined){ // mark that we are a react component, even if we don't have a parent parents[id]=null;} var childrenRef=refs[linkId]; for(var childId in childrenRef.edges){ var linkName=childrenRef.edges[childId]; if(linkName.startsWith('.')){ parents[childId]=id; inEdgeNames[childId]=linkName;}}}else if(name==='_renderedComponent'){ if(parents[id]===undefined){ parents[id]=null;} parents[linkId]=id; inEdgeNames[linkId]='_renderedComponent';}}}} // build tree of react internal instances (since that's what has the structure) var trees={}; for(var _id in refs){ registerReactComponentTreeImpl(refs,registry,parents,inEdgeNames,trees,_id);} // hook in components by looking at their _reactInternalInstance fields for(var _id2 in refs){ var _ref=refs[_id2]; for(var _linkId in _ref.edges){ var _name=_ref.edges[_linkId]; if(_name==='_reactInternalInstance'){ if(trees[_linkId]!==undefined){ trees[_id2]=registry.insert(trees[_linkId],'');}}}} return trees;} function registerPathToRoot(roots,refs,registry,reactComponentTree){ var visited={}; var breadth=[]; for(var i=0;i0){ var nextBreadth=[];var _loop=function _loop( _i){ var id=breadth[_i]; var ref=refs[id]; var node=visited[id]; // TODO: make edges map id -> name, (empty for none) seems that would be better var edges=Object.getOwnPropertyNames(ref.edges); edges.sort(function putUnknownLast(a,b){ var aName=ref.edges[a]; var bName=ref.edges[b]; if(aName===null&&bName!==null){ return 1;}else if(aName!==null&&bName===null){ return -1;}else if(aName===null&&bName===null){ return 0;}else { return a.localeCompare(b);}}); for(var j=0;j').id;}else { newData[dataOffset+reactField]=reactTree.id;} dataOffset+=numFields;} this.data=newData;}, getAggrow:function getAggrow(){ var agStrings=this.strings; var agStacks=this.stacks.flatten(); var agData=this.data; var agNumRows=agData.length/numFields; var ag=new aggrow(agStrings,agStacks,agNumRows); var idExpander=ag.addFieldExpander('Id', function getId(row){ var id=agData[row*numFields+idField]; if(id<0){ id+=0x100000000; // data is int32, id is uint32 } return '0x'+id.toString(16);}, function compareAddress(rowA,rowB){ return agData[rowA*numFields+idField]-agData[rowB*numFields+idField];}); var typeExpander=ag.addFieldExpander('Type', function getSize(row){return agStrings.get(agData[row*numFields+typeField]);}, function compareSize(rowA,rowB){ return agData[rowA*numFields+typeField]-agData[rowB*numFields+typeField];}); ag.addFieldExpander('Size', function getSize(row){return agData[row*numFields+sizeField].toString();}, function compareSize(rowA,rowB){ return agData[rowA*numFields+sizeField]-agData[rowB*numFields+sizeField];}); var traceExpander=ag.addFieldExpander('Trace', function getSize(row){return agStrings.get(agData[row*numFields+traceField]);}, function compareSize(rowA,rowB){ return agData[rowA*numFields+traceField]-agData[rowB*numFields+traceField];}); var pathExpander=ag.addCalleeStackExpander('Path', function getStack(row){return agStacks.get(agData[row*numFields+pathField]);}); var reactExpander=ag.addCalleeStackExpander('React Tree', function getStack(row){return agStacks.get(agData[row*numFields+reactField]);}); var sizeAggregator=ag.addAggregator('Size', function aggregateSize(indices){ var size=0; for(var i=0;i