Add function name, url, line, column to heap capture
Reviewed By: bnham Differential Revision: D3703012 fbshipit-source-id: 8e15deeeabe15da2a87a71c2baf0fa72d5bc6568
This commit is contained in:
parent
30847b2b35
commit
1199c5ade9
|
@ -1,5 +1,8 @@
|
|||
SHELL := /bin/bash
|
||||
|
||||
all:
|
||||
NODE_PATH="../../../../node_modules/" babel --presets babel-preset-react-native -d out src
|
||||
for f in out/*.js; do echo "// @generated" >> $$f; done
|
||||
|
||||
watch:
|
||||
NODE_PATH="../../../../node_modules/" babel --watch --presets babel-preset-react-native -d out src
|
||||
|
|
|
@ -16,38 +16,38 @@
|
|||
// pivot around frames in the middle of a stack by callers / callees
|
||||
// graphing?
|
||||
|
||||
function stringInterner(){ // eslint-disable-line no-unused-vars
|
||||
function stringInterner(){// eslint-disable-line no-unused-vars
|
||||
var strings=[];
|
||||
var ids={};
|
||||
return {
|
||||
return{
|
||||
intern:function internString(s){
|
||||
var find=ids[s];
|
||||
if(find===undefined){
|
||||
var id=strings.length;
|
||||
ids[s]=id;
|
||||
strings.push(s);
|
||||
return id;}else
|
||||
{
|
||||
return find;}},
|
||||
|
||||
|
||||
return id;
|
||||
}else{
|
||||
return find;
|
||||
}
|
||||
},
|
||||
get:function getString(id){
|
||||
return strings[id];}};}
|
||||
return strings[id];
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function stackData(stackIdMap,maxDepth){ // eslint-disable-line no-unused-vars
|
||||
return {
|
||||
function stackData(stackIdMap,maxDepth){// eslint-disable-line no-unused-vars
|
||||
return{
|
||||
maxDepth:maxDepth,
|
||||
get:function getStack(id){
|
||||
return stackIdMap[id];}};}
|
||||
return stackIdMap[id];
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function stackRegistry(interner){ // eslint-disable-line no-unused-vars
|
||||
return {
|
||||
function stackRegistry(interner){// eslint-disable-line no-unused-vars
|
||||
return{
|
||||
root:{id:0},
|
||||
nodeCount:1,
|
||||
insert:function insertNode(parent,label){
|
||||
|
@ -56,24 +56,24 @@ var node=parent[labelId];
|
|||
if(node===undefined){
|
||||
node={id:this.nodeCount};
|
||||
this.nodeCount++;
|
||||
parent[labelId]=node;}
|
||||
|
||||
return node;},
|
||||
|
||||
parent[labelId]=node;
|
||||
}
|
||||
return node;
|
||||
},
|
||||
flatten:function flattenStacks(){
|
||||
var stackFrameCount=0;
|
||||
function countStacks(tree,depth){
|
||||
var leaf=true;
|
||||
for(var frameId in tree){
|
||||
if(frameId!=='id'){
|
||||
leaf=countStacks(tree[frameId],depth+1);}}
|
||||
|
||||
|
||||
leaf=countStacks(tree[frameId],depth+1);
|
||||
}
|
||||
}
|
||||
if(leaf){
|
||||
stackFrameCount+=depth;}
|
||||
|
||||
return false;}
|
||||
|
||||
stackFrameCount+=depth;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
countStacks(this.root,0);
|
||||
console.log('size needed to store stacks: '+(stackFrameCount*4).toString()+'B');
|
||||
var stackIdMap=new Array(this.nodeCount);
|
||||
|
@ -87,36 +87,36 @@ for(var frameId in tree){
|
|||
if(frameId!=='id'){
|
||||
stack.push(Number(frameId));
|
||||
childStack=flattenStacksImpl(tree[frameId],stack);
|
||||
stack.pop();}}
|
||||
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
var id=tree.id;
|
||||
if(id<0||id>=stackIdMap.length||stackIdMap[id]!==undefined){
|
||||
throw 'invalid stack id!';}
|
||||
|
||||
throw'invalid stack id!';
|
||||
}
|
||||
|
||||
if(childStack!==undefined){
|
||||
// each child must have our stack as a prefix, so just use that
|
||||
stackIdMap[id]=childStack.subarray(0,stack.length);}else
|
||||
{
|
||||
stackIdMap[id]=childStack.subarray(0,stack.length);
|
||||
}else{
|
||||
var newStack=stackArray.subarray(stackFrameCount,stackFrameCount+stack.length);
|
||||
stackFrameCount+=stack.length;
|
||||
for(var i=0;i<stack.length;i++){
|
||||
newStack[i]=stack[i];}
|
||||
|
||||
stackIdMap[id]=newStack;}
|
||||
|
||||
return stackIdMap[id];}
|
||||
|
||||
newStack[i]=stack[i];
|
||||
}
|
||||
stackIdMap[id]=newStack;
|
||||
}
|
||||
return stackIdMap[id];
|
||||
}
|
||||
flattenStacksImpl(this.root,[]);
|
||||
|
||||
return new stackData(stackIdMap,maxStackDepth);}};}
|
||||
return new stackData(stackIdMap,maxStackDepth);
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function aggrow(strings,stacks,numRows){ // eslint-disable-line no-unused-vars
|
||||
function aggrow(strings,stacks,numRows){// eslint-disable-line no-unused-vars
|
||||
// expander ID definitions
|
||||
var FIELD_EXPANDER_ID_MIN=0x0000;
|
||||
var FIELD_EXPANDER_ID_MAX=0x7fff;
|
||||
|
@ -136,41 +136,41 @@ var ACTIVE_AGGREGATOR_MASK=0xffff;
|
|||
var ACTIVE_AGGREGATOR_ASC_BIT=0x10000;
|
||||
|
||||
// tree node state definitions
|
||||
var NODE_EXPANDED_BIT=0x0001; // this row is expanded
|
||||
var NODE_REAGGREGATE_BIT=0x0002; // children need aggregates
|
||||
var NODE_REORDER_BIT=0x0004; // children need to be sorted
|
||||
var NODE_REPOSITION_BIT=0x0008; // children need position
|
||||
var NODE_EXPANDED_BIT=0x0001;// this row is expanded
|
||||
var NODE_REAGGREGATE_BIT=0x0002;// children need aggregates
|
||||
var NODE_REORDER_BIT=0x0004;// children need to be sorted
|
||||
var NODE_REPOSITION_BIT=0x0008;// children need position
|
||||
var NODE_INDENT_SHIFT=16;
|
||||
|
||||
function calleeFrameGetter(stack,depth){
|
||||
return stack[depth];}
|
||||
|
||||
return stack[depth];
|
||||
}
|
||||
|
||||
function callerFrameGetter(stack,depth){
|
||||
return stack[stack.length-depth-1];}
|
||||
|
||||
return stack[stack.length-depth-1];
|
||||
}
|
||||
|
||||
function createStackComparers(stackGetter,frameGetter){
|
||||
var comparers=new Array(stacks.maxDepth);var _loop=function _loop(
|
||||
depth){
|
||||
var captureDepth=depth; // NB: to capture depth per loop iteration
|
||||
var captureDepth=depth;// NB: to capture depth per loop iteration
|
||||
comparers[depth]=function calleeStackComparer(rowA,rowB){
|
||||
var a=stackGetter(rowA);
|
||||
var b=stackGetter(rowB);
|
||||
// NB: we put the stacks that are too short at the top,
|
||||
// so they can be grouped into the '<exclusive>' bucket
|
||||
if(a.length<=captureDepth&&b.length<=captureDepth){
|
||||
return 0;}else
|
||||
if(a.length<=captureDepth){
|
||||
return -1;}else
|
||||
if(b.length<=captureDepth){
|
||||
return 1;}
|
||||
|
||||
return frameGetter(a,captureDepth)-frameGetter(b,captureDepth);};};for(var depth=0;depth<stacks.maxDepth;depth++){_loop(depth);}
|
||||
|
||||
|
||||
return comparers;}
|
||||
|
||||
return 0;
|
||||
}else if(a.length<=captureDepth){
|
||||
return-1;
|
||||
}else if(b.length<=captureDepth){
|
||||
return 1;
|
||||
}
|
||||
return frameGetter(a,captureDepth)-frameGetter(b,captureDepth);
|
||||
};};for(var depth=0;depth<stacks.maxDepth;depth++){_loop(depth);
|
||||
}
|
||||
return comparers;
|
||||
}
|
||||
|
||||
function createTreeNode(parent,label,indices,expander){
|
||||
var indent=parent===null?0:(parent.state>>>NODE_INDENT_SHIFT)+1;
|
||||
|
@ -178,35 +178,35 @@ var state=NODE_REPOSITION_BIT|
|
|||
NODE_REAGGREGATE_BIT|
|
||||
NODE_REORDER_BIT|
|
||||
indent<<NODE_INDENT_SHIFT;
|
||||
return {
|
||||
parent:parent, // null if root
|
||||
children:null, // array of children nodes
|
||||
label:label, // string to show in UI
|
||||
indices:indices, // row indices under this node
|
||||
aggregates:null, // result of aggregate on indices
|
||||
expander:expander, // index into state.activeExpanders
|
||||
top:0, // y position of top row (in rows)
|
||||
height:1, // number of rows including children
|
||||
state:state};} // see NODE_* definitions above
|
||||
|
||||
return{
|
||||
parent:parent,// null if root
|
||||
children:null,// array of children nodes
|
||||
label:label,// string to show in UI
|
||||
indices:indices,// row indices under this node
|
||||
aggregates:null,// result of aggregate on indices
|
||||
expander:expander,// index into state.activeExpanders
|
||||
top:0,// y position of top row (in rows)
|
||||
height:1,// number of rows including children
|
||||
state:state};
|
||||
|
||||
}
|
||||
|
||||
function noSortOrder(a,b){
|
||||
return 0;}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
var indices=new Int32Array(numRows);
|
||||
for(var i=0;i<numRows;i++){
|
||||
indices[i]=i;}
|
||||
|
||||
indices[i]=i;
|
||||
}
|
||||
|
||||
var state={
|
||||
fieldExpanders:[], // tree expanders that expand on simple values
|
||||
stackExpanders:[], // tree expanders that expand stacks
|
||||
activeExpanders:[], // index into field or stack expanders, hierarchy of tree
|
||||
aggregators:[], // all available aggregators, might not be used
|
||||
activeAggregators:[], // index into aggregators, to actually compute
|
||||
sorter:noSortOrder, // compare function that uses sortOrder to sort row.children
|
||||
fieldExpanders:[],// tree expanders that expand on simple values
|
||||
stackExpanders:[],// tree expanders that expand stacks
|
||||
activeExpanders:[],// index into field or stack expanders, hierarchy of tree
|
||||
aggregators:[],// all available aggregators, might not be used
|
||||
activeAggregators:[],// index into aggregators, to actually compute
|
||||
sorter:noSortOrder,// compare function that uses sortOrder to sort row.children
|
||||
root:createTreeNode(null,'<root>',indices,INVALID_ACTIVE_EXPANDER)};
|
||||
|
||||
|
||||
|
@ -215,35 +215,35 @@ var activeAggregators=state.activeAggregators;
|
|||
var aggregates=new Array(activeAggregators.length);
|
||||
for(var j=0;j<activeAggregators.length;j++){
|
||||
var aggregator=state.aggregators[activeAggregators[j]];
|
||||
aggregates[j]=aggregator.aggregator(row.indices);}
|
||||
|
||||
aggregates[j]=aggregator.aggregator(row.indices);
|
||||
}
|
||||
row.aggregates=aggregates;
|
||||
row.state|=NODE_REAGGREGATE_BIT;}
|
||||
|
||||
row.state|=NODE_REAGGREGATE_BIT;
|
||||
}
|
||||
|
||||
function evaluateAggregates(row){
|
||||
if((row.state&NODE_EXPANDED_BIT)!==0){
|
||||
var children=row.children;
|
||||
for(var _i=0;_i<children.length;_i++){
|
||||
evaluateAggregate(children[_i]);}
|
||||
|
||||
row.state|=NODE_REORDER_BIT;}
|
||||
|
||||
row.state^=NODE_REAGGREGATE_BIT;}
|
||||
|
||||
evaluateAggregate(children[_i]);
|
||||
}
|
||||
row.state|=NODE_REORDER_BIT;
|
||||
}
|
||||
row.state^=NODE_REAGGREGATE_BIT;
|
||||
}
|
||||
|
||||
function evaluateOrder(row){
|
||||
if((row.state&NODE_EXPANDED_BIT)!==0){
|
||||
var children=row.children;
|
||||
for(var _i2=0;_i2<children.length;_i2++){
|
||||
var child=children[_i2];
|
||||
child.state|=NODE_REORDER_BIT;}
|
||||
|
||||
child.state|=NODE_REORDER_BIT;
|
||||
}
|
||||
children.sort(state.sorter);
|
||||
row.state|=NODE_REPOSITION_BIT;}
|
||||
|
||||
row.state^=NODE_REORDER_BIT;}
|
||||
|
||||
row.state|=NODE_REPOSITION_BIT;
|
||||
}
|
||||
row.state^=NODE_REORDER_BIT;
|
||||
}
|
||||
|
||||
function evaluatePosition(row){
|
||||
if((row.state&NODE_EXPANDED_BIT)!==0){
|
||||
|
@ -253,49 +253,49 @@ for(var _i3=0;_i3<children.length;_i3++){
|
|||
var child=children[_i3];
|
||||
if(child.top!==childTop){
|
||||
child.top=childTop;
|
||||
child.state|=NODE_REPOSITION_BIT;}
|
||||
|
||||
childTop+=child.height;}}
|
||||
|
||||
|
||||
row.state^=NODE_REPOSITION_BIT;}
|
||||
|
||||
child.state|=NODE_REPOSITION_BIT;
|
||||
}
|
||||
childTop+=child.height;
|
||||
}
|
||||
}
|
||||
row.state^=NODE_REPOSITION_BIT;
|
||||
}
|
||||
|
||||
function getRowsImpl(row,top,height,result){
|
||||
if((row.state&NODE_REAGGREGATE_BIT)!==0){
|
||||
evaluateAggregates(row);}
|
||||
|
||||
evaluateAggregates(row);
|
||||
}
|
||||
if((row.state&NODE_REORDER_BIT)!==0){
|
||||
evaluateOrder(row);}
|
||||
|
||||
evaluateOrder(row);
|
||||
}
|
||||
if((row.state&NODE_REPOSITION_BIT)!==0){
|
||||
evaluatePosition(row);}
|
||||
|
||||
evaluatePosition(row);
|
||||
}
|
||||
|
||||
if(row.top>=top&&row.top<top+height){
|
||||
if(result[row.top-top]!=null){
|
||||
throw 'getRows put more than one row at position '+row.top+' into result';}
|
||||
|
||||
result[row.top-top]=row;}
|
||||
|
||||
throw'getRows put more than one row at position '+row.top+' into result';
|
||||
}
|
||||
result[row.top-top]=row;
|
||||
}
|
||||
if((row.state&NODE_EXPANDED_BIT)!==0){
|
||||
var children=row.children;
|
||||
for(var _i4=0;_i4<children.length;_i4++){
|
||||
var child=children[_i4];
|
||||
if(child.top<top+height&&top<child.top+child.height){
|
||||
getRowsImpl(child,top,height,result);}}}}
|
||||
|
||||
|
||||
|
||||
|
||||
getRowsImpl(child,top,height,result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateHeight(row,heightChange){
|
||||
while(row!==null){
|
||||
row.height+=heightChange;
|
||||
row.state|=NODE_REPOSITION_BIT;
|
||||
row=row.parent;}}
|
||||
|
||||
|
||||
row=row.parent;
|
||||
}
|
||||
}
|
||||
|
||||
function addChildrenWithFieldExpander(row,expander,nextActiveIndex){
|
||||
var rowIndices=row.indices;
|
||||
|
@ -311,16 +311,16 @@ row,
|
|||
expander.name+': '+expander.formatter(rowIndices[begin]),
|
||||
rowIndices.subarray(begin,end),
|
||||
nextActiveIndex));
|
||||
begin=end;}
|
||||
|
||||
end++;}
|
||||
|
||||
begin=end;
|
||||
}
|
||||
end++;
|
||||
}
|
||||
row.children.push(createTreeNode(
|
||||
row,
|
||||
expander.name+': '+expander.formatter(rowIndices[begin]),
|
||||
rowIndices.subarray(begin,end),
|
||||
nextActiveIndex));}
|
||||
|
||||
nextActiveIndex));
|
||||
}
|
||||
|
||||
function addChildrenWithStackExpander(row,expander,activeIndex,depth,nextActiveIndex){
|
||||
var rowIndices=row.indices;
|
||||
|
@ -331,8 +331,8 @@ var expandNextFrame=activeIndex|depth+1<<ACTIVE_EXPANDER_FRAME_SHIFT;
|
|||
rowIndices.sort(comparer);
|
||||
var columnName='';
|
||||
if(depth===0){
|
||||
columnName=expander.name+': ';}
|
||||
|
||||
columnName=expander.name+': ';
|
||||
}
|
||||
|
||||
// put all the too-short stacks under <exclusive>
|
||||
var begin=0;
|
||||
|
@ -341,17 +341,17 @@ row.children=[];
|
|||
while(begin<rowIndices.length){
|
||||
beginStack=stackGetter(rowIndices[begin]);
|
||||
if(beginStack.length>depth){
|
||||
break;}
|
||||
|
||||
begin++;}
|
||||
|
||||
break;
|
||||
}
|
||||
begin++;
|
||||
}
|
||||
if(begin>0){
|
||||
row.children.push(createTreeNode(
|
||||
row,
|
||||
columnName+'<exclusive>',
|
||||
rowIndices.subarray(0,begin),
|
||||
nextActiveIndex));}
|
||||
|
||||
nextActiveIndex));
|
||||
}
|
||||
// aggregate the rest under frames
|
||||
if(begin<rowIndices.length){
|
||||
var end=begin+1;
|
||||
|
@ -364,159 +364,159 @@ columnName+strings.get(frameGetter(beginStack,depth)),
|
|||
rowIndices.subarray(begin,end),
|
||||
expandNextFrame));
|
||||
begin=end;
|
||||
beginStack=endStack;}
|
||||
|
||||
end++;}
|
||||
|
||||
beginStack=endStack;
|
||||
}
|
||||
end++;
|
||||
}
|
||||
row.children.push(createTreeNode(
|
||||
row,
|
||||
columnName+strings.get(frameGetter(beginStack,depth)),
|
||||
rowIndices.subarray(begin,end),
|
||||
expandNextFrame));}}
|
||||
|
||||
|
||||
expandNextFrame));
|
||||
}
|
||||
}
|
||||
|
||||
function contractRow(row){
|
||||
if((row.state&NODE_EXPANDED_BIT)===0){
|
||||
throw 'can not contract row, already contracted';}
|
||||
|
||||
throw'can not contract row, already contracted';
|
||||
}
|
||||
row.state^=NODE_EXPANDED_BIT;
|
||||
var heightChange=1-row.height;
|
||||
updateHeight(row,heightChange);}
|
||||
|
||||
updateHeight(row,heightChange);
|
||||
}
|
||||
|
||||
function pruneExpanders(row,oldExpander,newExpander){
|
||||
row.state|=NODE_REPOSITION_BIT;
|
||||
if(row.expander===oldExpander){
|
||||
row.state|=NODE_REAGGREGATE_BIT|NODE_REORDER_BIT|NODE_REPOSITION_BIT;
|
||||
if((row.state&NODE_EXPANDED_BIT)!==0){
|
||||
contractRow(row);}
|
||||
|
||||
contractRow(row);
|
||||
}
|
||||
row.children=null;
|
||||
row.expander=newExpander;}else
|
||||
{
|
||||
row.expander=newExpander;
|
||||
}else{
|
||||
row.state|=NODE_REPOSITION_BIT;
|
||||
var children=row.children;
|
||||
if(children!=null){
|
||||
for(var _i5=0;_i5<children.length;_i5++){
|
||||
var child=children[_i5];
|
||||
pruneExpanders(child,oldExpander,newExpander);}}}}
|
||||
pruneExpanders(child,oldExpander,newExpander);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return {
|
||||
return{
|
||||
addFieldExpander:function addFieldExpander(name,formatter,comparer){
|
||||
if(FIELD_EXPANDER_ID_MIN+state.fieldExpanders.length>=FIELD_EXPANDER_ID_MAX){
|
||||
throw 'too many field expanders!';}
|
||||
|
||||
throw'too many field expanders!';
|
||||
}
|
||||
state.fieldExpanders.push({
|
||||
name:name, // name for column
|
||||
formatter:formatter, // row index -> display string
|
||||
comparer:comparer}); // compares by two row indices
|
||||
|
||||
return FIELD_EXPANDER_ID_MIN+state.fieldExpanders.length-1;},
|
||||
name:name,// name for column
|
||||
formatter:formatter,// row index -> display string
|
||||
comparer:comparer});
|
||||
|
||||
return FIELD_EXPANDER_ID_MIN+state.fieldExpanders.length-1;
|
||||
},
|
||||
addCalleeStackExpander:function addCalleeStackExpander(name,stackGetter){
|
||||
if(STACK_EXPANDER_ID_MIN+state.fieldExpanders.length>=STACK_EXPANDER_ID_MAX){
|
||||
throw 'too many stack expanders!';}
|
||||
|
||||
throw'too many stack expanders!';
|
||||
}
|
||||
state.stackExpanders.push({
|
||||
name:name, // name for column
|
||||
stackGetter:stackGetter, // row index -> stack array
|
||||
comparers:createStackComparers(stackGetter,calleeFrameGetter), // depth -> comparer
|
||||
frameGetter:calleeFrameGetter}); // (stack, depth) -> string id
|
||||
|
||||
return STACK_EXPANDER_ID_MIN+state.stackExpanders.length-1;},
|
||||
name:name,// name for column
|
||||
stackGetter:stackGetter,// row index -> stack array
|
||||
comparers:createStackComparers(stackGetter,calleeFrameGetter),// depth -> comparer
|
||||
frameGetter:calleeFrameGetter});
|
||||
|
||||
return STACK_EXPANDER_ID_MIN+state.stackExpanders.length-1;
|
||||
},
|
||||
addCallerStackExpander:function addCallerStackExpander(name,stackGetter){
|
||||
if(STACK_EXPANDER_ID_MIN+state.fieldExpanders.length>=STACK_EXPANDER_ID_MAX){
|
||||
throw 'too many stack expanders!';}
|
||||
|
||||
throw'too many stack expanders!';
|
||||
}
|
||||
state.stackExpanders.push({
|
||||
name:name,
|
||||
stackGetter:stackGetter,
|
||||
comparers:createStackComparers(stackGetter,callerFrameGetter),
|
||||
frameGetter:callerFrameGetter});
|
||||
|
||||
return STACK_EXPANDER_ID_MIN+state.stackExpanders.length-1;},
|
||||
|
||||
return STACK_EXPANDER_ID_MIN+state.stackExpanders.length-1;
|
||||
},
|
||||
getExpanders:function getExpanders(){
|
||||
var expanders=[];
|
||||
for(var _i6=0;_i6<state.fieldExpanders.length;_i6++){
|
||||
expanders.push(FIELD_EXPANDER_ID_MIN+_i6);}
|
||||
|
||||
expanders.push(FIELD_EXPANDER_ID_MIN+_i6);
|
||||
}
|
||||
for(var _i7=0;_i7<state.stackExpanders.length;_i7++){
|
||||
expanders.push(STACK_EXPANDER_ID_MIN+_i7);}
|
||||
|
||||
return expanders;},
|
||||
|
||||
expanders.push(STACK_EXPANDER_ID_MIN+_i7);
|
||||
}
|
||||
return expanders;
|
||||
},
|
||||
getExpanderName:function getExpanderName(id){
|
||||
if(id>=FIELD_EXPANDER_ID_MIN&&id<=FIELD_EXPANDER_ID_MAX){
|
||||
return state.fieldExpanders[id-FIELD_EXPANDER_ID_MIN].name;}else
|
||||
if(id>=STACK_EXPANDER_ID_MIN&&id<=STACK_EXPANDER_ID_MAX){
|
||||
return state.stackExpanders[id-STACK_EXPANDER_ID_MIN].name;}
|
||||
|
||||
throw 'Unknown expander ID '+id.toString();},
|
||||
|
||||
return state.fieldExpanders[id-FIELD_EXPANDER_ID_MIN].name;
|
||||
}else if(id>=STACK_EXPANDER_ID_MIN&&id<=STACK_EXPANDER_ID_MAX){
|
||||
return state.stackExpanders[id-STACK_EXPANDER_ID_MIN].name;
|
||||
}
|
||||
throw'Unknown expander ID '+id.toString();
|
||||
},
|
||||
setActiveExpanders:function setActiveExpanders(ids){
|
||||
for(var _i8=0;_i8<ids.length;_i8++){
|
||||
var id=ids[_i8];
|
||||
if(id>=FIELD_EXPANDER_ID_MIN&&id<=FIELD_EXPANDER_ID_MAX){
|
||||
if(id-FIELD_EXPANDER_ID_MIN>=state.fieldExpanders.length){
|
||||
throw 'field expander for id '+id.toString()+' does not exist!';}}else
|
||||
|
||||
if(id>=STACK_EXPANDER_ID_MIN&&id<=STACK_EXPANDER_ID_MAX){
|
||||
throw'field expander for id '+id.toString()+' does not exist!';
|
||||
}
|
||||
}else if(id>=STACK_EXPANDER_ID_MIN&&id<=STACK_EXPANDER_ID_MAX){
|
||||
if(id-STACK_EXPANDER_ID_MIN>=state.stackExpanders.length){
|
||||
throw 'stack expander for id '+id.toString()+' does not exist!';}}}
|
||||
|
||||
|
||||
|
||||
throw'stack expander for id '+id.toString()+' does not exist!';
|
||||
}
|
||||
}
|
||||
}
|
||||
for(var _i9=0;_i9<ids.length;_i9++){
|
||||
if(state.activeExpanders.length<=_i9){
|
||||
pruneExpanders(state.root,INVALID_ACTIVE_EXPANDER,_i9);
|
||||
break;}else
|
||||
if(ids[_i9]!==state.activeExpanders[_i9]){
|
||||
break;
|
||||
}else if(ids[_i9]!==state.activeExpanders[_i9]){
|
||||
pruneExpanders(state.root,_i9,_i9);
|
||||
break;}}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: if ids is prefix of activeExpanders, we need to make an expander invalid
|
||||
state.activeExpanders=ids.slice();},
|
||||
|
||||
state.activeExpanders=ids.slice();
|
||||
},
|
||||
getActiveExpanders:function getActiveExpanders(){
|
||||
return state.activeExpanders.slice();},
|
||||
|
||||
return state.activeExpanders.slice();
|
||||
},
|
||||
addAggregator:function addAggregator(name,aggregator,formatter,sorter){
|
||||
if(state.aggregators.length>=AGGREGATOR_ID_MAX){
|
||||
throw 'too many aggregators!';}
|
||||
|
||||
throw'too many aggregators!';
|
||||
}
|
||||
state.aggregators.push({
|
||||
name:name, // name for column
|
||||
aggregator:aggregator, // index array -> aggregate value
|
||||
formatter:formatter, // aggregate value -> display string
|
||||
sorter:sorter}); // compare two aggregate values
|
||||
|
||||
return state.aggregators.length-1;},
|
||||
name:name,// name for column
|
||||
aggregator:aggregator,// index array -> aggregate value
|
||||
formatter:formatter,// aggregate value -> display string
|
||||
sorter:sorter});
|
||||
|
||||
return state.aggregators.length-1;
|
||||
},
|
||||
getAggregators:function getAggregators(){
|
||||
var aggregators=[];
|
||||
for(var _i10=0;_i10<state.aggregators.length;_i10++){
|
||||
aggregators.push(_i10);}
|
||||
|
||||
return aggregators;},
|
||||
|
||||
aggregators.push(_i10);
|
||||
}
|
||||
return aggregators;
|
||||
},
|
||||
getAggregatorName:function getAggregatorName(id){
|
||||
return state.aggregators[id&ACTIVE_AGGREGATOR_MASK].name;},
|
||||
|
||||
return state.aggregators[id&ACTIVE_AGGREGATOR_MASK].name;
|
||||
},
|
||||
setActiveAggregators:function setActiveAggregators(ids){
|
||||
for(var _i11=0;_i11<ids.length;_i11++){
|
||||
var id=ids[_i11]&ACTIVE_AGGREGATOR_MASK;
|
||||
if(id<0||id>state.aggregators.length){
|
||||
throw 'aggregator id '+id.toString()+' not valid';}}
|
||||
|
||||
|
||||
throw'aggregator id '+id.toString()+' not valid';
|
||||
}
|
||||
}
|
||||
state.activeAggregators=ids.slice();
|
||||
// NB: evaluate root here because dirty bit is for children
|
||||
// so someone has to start with root, and it might as well be right away
|
||||
|
@ -531,86 +531,89 @@ var captureIndex=_i12;
|
|||
sorter=function sorter(a,b){
|
||||
var c=comparer(a.aggregates[captureIndex],b.aggregates[captureIndex]);
|
||||
if(c===0){
|
||||
return captureSorter(a,b);}
|
||||
|
||||
return ascending?-c:c;};};for(var _i12=ids.length-1;_i12>=0;_i12--){_loop2(_i12);}
|
||||
|
||||
|
||||
return captureSorter(a,b);
|
||||
}
|
||||
return ascending?-c:c;
|
||||
};};for(var _i12=ids.length-1;_i12>=0;_i12--){_loop2(_i12);
|
||||
}
|
||||
state.sorter=sorter;
|
||||
state.root.state|=NODE_REORDER_BIT;},
|
||||
|
||||
state.root.state|=NODE_REORDER_BIT;
|
||||
},
|
||||
getActiveAggregators:function getActiveAggregators(){
|
||||
return state.activeAggregators.slice();},
|
||||
|
||||
return state.activeAggregators.slice();
|
||||
},
|
||||
getRows:function getRows(top,height){
|
||||
var result=new Array(height);
|
||||
for(var _i13=0;_i13<height;_i13++){
|
||||
result[_i13]=null;}
|
||||
|
||||
result[_i13]=null;
|
||||
}
|
||||
getRowsImpl(state.root,top,height,result);
|
||||
return result;},
|
||||
|
||||
return result;
|
||||
},
|
||||
getRowLabel:function getRowLabel(row){
|
||||
return row.label;},
|
||||
|
||||
return row.label;
|
||||
},
|
||||
getRowIndent:function getRowIndent(row){
|
||||
return row.state>>>NODE_INDENT_SHIFT;},
|
||||
|
||||
return row.state>>>NODE_INDENT_SHIFT;
|
||||
},
|
||||
getRowAggregate:function getRowAggregate(row,index){
|
||||
var aggregator=state.aggregators[state.activeAggregators[index]];
|
||||
return aggregator.formatter(row.aggregates[index]);},
|
||||
|
||||
return aggregator.formatter(row.aggregates[index]);
|
||||
},
|
||||
getHeight:function getHeight(){
|
||||
return state.root.height;},
|
||||
|
||||
return state.root.height;
|
||||
},
|
||||
canExpand:function canExpand(row){
|
||||
return (row.state&NODE_EXPANDED_BIT)===0&&row.expander!==INVALID_ACTIVE_EXPANDER;},
|
||||
|
||||
return(row.state&NODE_EXPANDED_BIT)===0&&row.expander!==INVALID_ACTIVE_EXPANDER;
|
||||
},
|
||||
canContract:function canContract(row){
|
||||
return (row.state&NODE_EXPANDED_BIT)!==0;},
|
||||
|
||||
return(row.state&NODE_EXPANDED_BIT)!==0;
|
||||
},
|
||||
expand:function expand(row){
|
||||
if((row.state&NODE_EXPANDED_BIT)!==0){
|
||||
throw 'can not expand row, already expanded';}
|
||||
|
||||
throw'can not expand row, already expanded';
|
||||
}
|
||||
if(row.height!==1){
|
||||
throw 'unexpanded row has height '+row.height.toString()+' != 1';}
|
||||
|
||||
if(row.children===null){ // first expand, generate children
|
||||
throw'unexpanded row has height '+row.height.toString()+' != 1';
|
||||
}
|
||||
if(row.children===null){// first expand, generate children
|
||||
var activeIndex=row.expander&ACTIVE_EXPANDER_MASK;
|
||||
var nextActiveIndex=activeIndex+1; // NB: if next is stack, frame is 0
|
||||
var nextActiveIndex=activeIndex+1;// NB: if next is stack, frame is 0
|
||||
if(nextActiveIndex>=state.activeExpanders.length){
|
||||
nextActiveIndex=INVALID_ACTIVE_EXPANDER;}
|
||||
|
||||
nextActiveIndex=INVALID_ACTIVE_EXPANDER;
|
||||
}
|
||||
if(activeIndex>=state.activeExpanders.length){
|
||||
throw 'invalid active expander index '+activeIndex.toString();}
|
||||
|
||||
throw'invalid active expander index '+activeIndex.toString();
|
||||
}
|
||||
var exId=state.activeExpanders[activeIndex];
|
||||
if(exId>=FIELD_EXPANDER_ID_MIN&&
|
||||
exId<FIELD_EXPANDER_ID_MIN+state.fieldExpanders.length){
|
||||
var expander=state.fieldExpanders[exId-FIELD_EXPANDER_ID_MIN];
|
||||
addChildrenWithFieldExpander(row,expander,nextActiveIndex);}else
|
||||
if(exId>=STACK_EXPANDER_ID_MIN&&
|
||||
addChildrenWithFieldExpander(row,expander,nextActiveIndex);
|
||||
}else if(exId>=STACK_EXPANDER_ID_MIN&&
|
||||
exId<STACK_EXPANDER_ID_MIN+state.stackExpanders.length){
|
||||
var depth=row.expander>>>ACTIVE_EXPANDER_FRAME_SHIFT;
|
||||
var _expander=state.stackExpanders[exId-STACK_EXPANDER_ID_MIN];
|
||||
addChildrenWithStackExpander(row,_expander,activeIndex,depth,nextActiveIndex);}else
|
||||
{
|
||||
throw 'state.activeIndex '+activeIndex.toString()+
|
||||
' has invalid expander'+exId.toString();}}
|
||||
|
||||
|
||||
addChildrenWithStackExpander(row,_expander,activeIndex,depth,nextActiveIndex);
|
||||
}else{
|
||||
throw'state.activeIndex '+activeIndex.toString()+
|
||||
' has invalid expander'+exId.toString();
|
||||
}
|
||||
}
|
||||
row.state|=NODE_EXPANDED_BIT|
|
||||
NODE_REAGGREGATE_BIT|NODE_REORDER_BIT|NODE_REPOSITION_BIT;
|
||||
var heightChange=0;
|
||||
for(var _i14=0;_i14<row.children.length;_i14++){
|
||||
heightChange+=row.children[_i14].height;}
|
||||
|
||||
heightChange+=row.children[_i14].height;
|
||||
}
|
||||
updateHeight(row,heightChange);
|
||||
// if children only contains one node, then expand it as well
|
||||
if(row.children.length===1&&this.canExpand(row.children[0])){
|
||||
this.expand(row.children[0]);}},
|
||||
|
||||
|
||||
this.expand(row.children[0]);
|
||||
}
|
||||
},
|
||||
contract:function contract(row){
|
||||
contractRow(row);}};}
|
||||
contractRow(row);
|
||||
}};
|
||||
|
||||
}// @generated
|
||||
|
|
|
@ -8,14 +8,21 @@
|
|||
*/
|
||||
'use strict';
|
||||
/*eslint no-console-disallow: "off"*/
|
||||
/*global React ReactDOM Table stringInterner stackRegistry aggrow preLoadedCapture:true*/var _jsxFileName='src/heapCapture.js';
|
||||
/*global React ReactDOM Table stringInterner stackRegistry aggrow preLoadedCapture:true*/
|
||||
|
||||
function getTypeName(ref){
|
||||
if(ref.type==='Function'&&!!ref.value){
|
||||
return'Function '+ref.value.name;
|
||||
}
|
||||
return ref.type;
|
||||
}
|
||||
|
||||
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,'<internalInstance>');}else
|
||||
{
|
||||
trees[id]=registry.insert(registry.root,'<internalInstance>');
|
||||
}else{
|
||||
var parent=parents[id];
|
||||
var inEdgeName=inEdgeNames[id];
|
||||
var parentTree=trees[parent];
|
||||
|
@ -26,12 +33,12 @@ registry,
|
|||
parents,
|
||||
inEdgeNames,
|
||||
trees,
|
||||
parent);}
|
||||
|
||||
trees[id]=registry.insert(parentTree,inEdgeName);}
|
||||
|
||||
return trees[id];}
|
||||
|
||||
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){
|
||||
|
@ -46,31 +53,31 @@ 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;}
|
||||
|
||||
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'){
|
||||
inEdgeNames[childId]=linkName;
|
||||
}
|
||||
}
|
||||
}else if(name==='_renderedComponent'){
|
||||
if(parents[id]===undefined){
|
||||
parents[id]=null;}
|
||||
|
||||
parents[id]=null;
|
||||
}
|
||||
parents[linkId]=id;
|
||||
inEdgeNames[linkId]='_renderedComponent';}}}}
|
||||
|
||||
|
||||
|
||||
|
||||
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);}
|
||||
|
||||
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];
|
||||
|
@ -78,13 +85,13 @@ for(var _linkId in _ref.edges){
|
|||
var _name=_ref.edges[_linkId];
|
||||
if(_name==='_reactInternalInstance'){
|
||||
if(trees[_linkId]!==undefined){
|
||||
trees[_id2]=registry.insert(trees[_linkId],'<component>');}}}}
|
||||
|
||||
|
||||
|
||||
|
||||
return trees;}
|
||||
|
||||
trees[_id2]=registry.insert(trees[_linkId],'<component>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return trees;
|
||||
}
|
||||
|
||||
function registerPathToRoot(roots,refs,registry,reactComponentTree){
|
||||
var visited={};
|
||||
|
@ -93,10 +100,10 @@ for(var i=0;i<roots.length;i++){
|
|||
var id=roots[i];
|
||||
if(visited[id]===undefined){
|
||||
var ref=refs[id];
|
||||
visited[id]=registry.insert(registry.root,ref.type);
|
||||
breadth.push(id);}}
|
||||
|
||||
|
||||
visited[id]=registry.insert(registry.root,getTypeName(ref));
|
||||
breadth.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
while(breadth.length>0){
|
||||
var nextBreadth=[];var _loop=function _loop(
|
||||
|
@ -111,41 +118,41 @@ 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);}});
|
||||
|
||||
|
||||
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<edges.length;j++){
|
||||
var edgeId=edges[j];
|
||||
var edgeName='';
|
||||
if(ref.edges[edgeId]){
|
||||
edgeName=ref.edges[edgeId]+': ';}
|
||||
|
||||
edgeName=ref.edges[edgeId]+': ';
|
||||
}
|
||||
if(visited[edgeId]===undefined){
|
||||
var edgeRef=refs[edgeId];
|
||||
if(edgeRef===undefined){
|
||||
// TODO: figure out why we have edges that point to things not JSCell
|
||||
//console.log('registerPathToRoot unable to follow edge from ' + id + ' to ' + edgeId);
|
||||
}else {
|
||||
visited[edgeId]=registry.insert(node,edgeName+edgeRef.type);
|
||||
}else{
|
||||
visited[edgeId]=registry.insert(node,edgeName+getTypeName(edgeRef));
|
||||
nextBreadth.push(edgeId);
|
||||
if(reactComponentTree[edgeId]===undefined){
|
||||
reactComponentTree[edgeId]=reactComponentTree[id];}}}}};for(var _i=0;_i<breadth.length;_i++){_loop(_i);}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
breadth=nextBreadth;}
|
||||
|
||||
return visited;}
|
||||
|
||||
reactComponentTree[edgeId]=reactComponentTree[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}};for(var _i=0;_i<breadth.length;_i++){_loop(_i);
|
||||
}
|
||||
breadth=nextBreadth;
|
||||
}
|
||||
return visited;
|
||||
}
|
||||
|
||||
function captureRegistry(){
|
||||
var strings=stringInterner();
|
||||
|
@ -160,15 +167,17 @@ var pathField=4;
|
|||
var reactField=5;
|
||||
var numFields=6;
|
||||
|
||||
return {
|
||||
return{
|
||||
strings:strings,
|
||||
stacks:stacks,
|
||||
data:data,
|
||||
register:function registerCapture(captureId,capture){
|
||||
// NB: capture.refs is potentially VERY large, so we try to avoid making
|
||||
// copies, even of iteration is a bit more annoying.
|
||||
var rowCount=0;
|
||||
for(var id in capture.refs){
|
||||
rowCount++;}
|
||||
|
||||
for(var id in capture.refs){// eslint-disable-line no-unused-vars
|
||||
rowCount++;
|
||||
}
|
||||
console.log(
|
||||
'increasing row data from '+(this.data.length*4).toString()+'B to '+
|
||||
(this.data.length*4+rowCount*numFields*4).toString()+'B');
|
||||
|
@ -189,25 +198,25 @@ var internedCaptureId=this.strings.intern(captureId);
|
|||
for(var _id3 in capture.refs){
|
||||
var ref=capture.refs[_id3];
|
||||
newData[dataOffset+idField]=parseInt(_id3,16);
|
||||
newData[dataOffset+typeField]=this.strings.intern(ref.type);
|
||||
newData[dataOffset+typeField]=this.strings.intern(getTypeName(ref));
|
||||
newData[dataOffset+sizeField]=ref.size;
|
||||
newData[dataOffset+traceField]=internedCaptureId;
|
||||
var pathNode=rootPathMap[_id3];
|
||||
if(pathNode===undefined){
|
||||
throw 'did not find path for ref!';}
|
||||
|
||||
throw'did not find path for ref!';
|
||||
}
|
||||
newData[dataOffset+pathField]=pathNode.id;
|
||||
var reactTree=reactComponentTreeMap[_id3];
|
||||
if(reactTree===undefined){
|
||||
newData[dataOffset+reactField]=
|
||||
this.stacks.insert(this.stacks.root,'<not-under-tree>').id;}else
|
||||
{
|
||||
newData[dataOffset+reactField]=reactTree.id;}
|
||||
|
||||
dataOffset+=numFields;}
|
||||
|
||||
this.data=newData;},
|
||||
|
||||
this.stacks.insert(this.stacks.root,'<not-under-tree>').id;
|
||||
}else{
|
||||
newData[dataOffset+reactField]=reactTree.id;
|
||||
}
|
||||
dataOffset+=numFields;
|
||||
}
|
||||
this.data=newData;
|
||||
},
|
||||
getAggrow:function getAggrow(){
|
||||
var agStrings=this.strings;
|
||||
var agStacks=this.stacks.flatten();
|
||||
|
@ -219,31 +228,31 @@ 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
|
||||
id+=0x100000000;// data is int32, id is uint32
|
||||
}
|
||||
return '0x'+id.toString(16);},
|
||||
|
||||
return'0x'+id.toString(16);
|
||||
},
|
||||
function compareAddress(rowA,rowB){
|
||||
return agData[rowA*numFields+idField]-agData[rowB*numFields+idField];});
|
||||
|
||||
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];});
|
||||
|
||||
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];});
|
||||
|
||||
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];});
|
||||
|
||||
return agData[rowA*numFields+traceField]-agData[rowB*numFields+traceField];
|
||||
});
|
||||
|
||||
var pathExpander=ag.addCalleeStackExpander('Path',
|
||||
function getStack(row){return agStacks.get(agData[row*numFields+pathField]);});
|
||||
|
@ -256,29 +265,30 @@ function aggregateSize(indices){
|
|||
var size=0;
|
||||
for(var i=0;i<indices.length;i++){
|
||||
var row=indices[i];
|
||||
size+=agData[row*numFields+sizeField];}
|
||||
|
||||
return size;},
|
||||
|
||||
size+=agData[row*numFields+sizeField];
|
||||
}
|
||||
return size;
|
||||
},
|
||||
function formatSize(value){return value.toString();},
|
||||
function sortSize(a,b){return b-a;});
|
||||
|
||||
var countAggregator=ag.addAggregator('Count',
|
||||
function aggregateCount(indices){
|
||||
return indices.length;},
|
||||
|
||||
return indices.length;
|
||||
},
|
||||
function formatCount(value){return value.toString();},
|
||||
function sortCount(a,b){return b-a;});
|
||||
|
||||
ag.setActiveExpanders([pathExpander,reactExpander,typeExpander,idExpander,traceExpander]);
|
||||
ag.setActiveAggregators([sizeAggregator,countAggregator]);
|
||||
return ag;}};}
|
||||
|
||||
|
||||
return ag;
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
if(preLoadedCapture){
|
||||
var r=new captureRegistry();
|
||||
r.register('trace',preLoadedCapture);
|
||||
preLoadedCapture=undefined; // let GG clean up the capture
|
||||
ReactDOM.render(React.createElement(Table,{aggrow:r.getAggrow(),__source:{fileName:_jsxFileName,lineNumber:284}}),document.body);}
|
||||
preLoadedCapture=undefined;// let GG clean up the capture
|
||||
ReactDOM.render(React.createElement(Table,{aggrow:r.getAggrow()}),document.body);
|
||||
}// @generated
|
||||
|
|
|
@ -13,35 +13,35 @@
|
|||
|
||||
// TODO:
|
||||
// selection and arrow keys for navigating
|
||||
var _jsxFileName='src/table.js';var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value" in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor;};}();function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}function _possibleConstructorReturn(self,call){if(!self){throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return call&&(typeof call==="object"||typeof call==="function")?call:self;}function _inherits(subClass,superClass){if(typeof superClass!=="function"&&superClass!==null){throw new TypeError("Super expression must either be null or a function, not "+typeof superClass);}subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,enumerable:false,writable:true,configurable:true}});if(superClass)Object.setPrototypeOf?Object.setPrototypeOf(subClass,superClass):subClass.__proto__=superClass;}
|
||||
var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor;};}();function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}function _possibleConstructorReturn(self,call){if(!self){throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return call&&(typeof call==="object"||typeof call==="function")?call:self;}function _inherits(subClass,superClass){if(typeof superClass!=="function"&&superClass!==null){throw new TypeError("Super expression must either be null or a function, not "+typeof superClass);}subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,enumerable:false,writable:true,configurable:true}});if(superClass)Object.setPrototypeOf?Object.setPrototypeOf(subClass,superClass):subClass.__proto__=superClass;}
|
||||
var rowHeight=20;
|
||||
var treeIndent=16;var
|
||||
var treeIndent=16;var
|
||||
|
||||
Draggable=function(_React$Component){_inherits(Draggable,_React$Component); // eslint-disable-line no-unused-vars
|
||||
Draggable=function(_React$Component){_inherits(Draggable,_React$Component);// eslint-disable-line no-unused-vars
|
||||
function Draggable(props){_classCallCheck(this,Draggable);return _possibleConstructorReturn(this,Object.getPrototypeOf(Draggable).call(this,
|
||||
props));}_createClass(Draggable,[{key:'render',value:function render()
|
||||
|
||||
props));
|
||||
}_createClass(Draggable,[{key:'render',value:function render()
|
||||
|
||||
{
|
||||
var id=this.props.id;
|
||||
function dragStart(e){
|
||||
e.dataTransfer.setData('text/plain',id);}
|
||||
|
||||
e.dataTransfer.setData('text/plain',id);
|
||||
}
|
||||
return React.cloneElement(
|
||||
this.props.children,
|
||||
{draggable:'true',onDragStart:dragStart});}}]);return Draggable;}(React.Component);
|
||||
|
||||
{draggable:'true',onDragStart:dragStart});
|
||||
|
||||
}}]);return Draggable;}(React.Component);
|
||||
|
||||
Draggable.propTypes={
|
||||
children:React.PropTypes.element.isRequired,
|
||||
id:React.PropTypes.string.isRequired};var
|
||||
id:React.PropTypes.string.isRequired};var
|
||||
|
||||
|
||||
DropTarget=function(_React$Component2){_inherits(DropTarget,_React$Component2); // eslint-disable-line no-unused-vars
|
||||
DropTarget=function(_React$Component2){_inherits(DropTarget,_React$Component2);// eslint-disable-line no-unused-vars
|
||||
function DropTarget(props){_classCallCheck(this,DropTarget);return _possibleConstructorReturn(this,Object.getPrototypeOf(DropTarget).call(this,
|
||||
props));}_createClass(DropTarget,[{key:'render',value:function render()
|
||||
|
||||
props));
|
||||
}_createClass(DropTarget,[{key:'render',value:function render()
|
||||
|
||||
{
|
||||
var thisId=this.props.id;
|
||||
|
@ -53,36 +53,36 @@ this.props.children,
|
|||
onDragOver:function onDragOver(e){
|
||||
var sourceId=e.dataTransfer.getData('text/plain');
|
||||
if(dropFilter(sourceId)){
|
||||
e.preventDefault();}},
|
||||
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
onDrop:function onDrop(e){
|
||||
var sourceId=e.dataTransfer.getData('text/plain');
|
||||
if(dropFilter(sourceId)){
|
||||
e.preventDefault();
|
||||
dropAction(sourceId,thisId);}}});}}]);return DropTarget;}(React.Component);
|
||||
|
||||
|
||||
|
||||
dropAction(sourceId,thisId);
|
||||
}
|
||||
}});
|
||||
|
||||
|
||||
}}]);return DropTarget;}(React.Component);
|
||||
|
||||
|
||||
DropTarget.propTypes={
|
||||
children:React.PropTypes.element.isRequired,
|
||||
id:React.PropTypes.string.isRequired,
|
||||
dropFilter:React.PropTypes.func.isRequired,
|
||||
dropAction:React.PropTypes.func.isRequired};var
|
||||
dropAction:React.PropTypes.func.isRequired};var
|
||||
|
||||
|
||||
Table=function(_React$Component3){_inherits(Table,_React$Component3); // eslint-disable-line no-unused-vars
|
||||
Table=function(_React$Component3){_inherits(Table,_React$Component3);// eslint-disable-line no-unused-vars
|
||||
function Table(props){_classCallCheck(this,Table);var _this3=_possibleConstructorReturn(this,Object.getPrototypeOf(Table).call(this,
|
||||
props));
|
||||
_this3.state={
|
||||
aggrow:props.aggrow,
|
||||
viewport:{top:0,height:100}};return _this3;}_createClass(Table,[{key:'scroll',value:function scroll(
|
||||
|
||||
viewport:{top:0,height:100}};return _this3;
|
||||
|
||||
}_createClass(Table,[{key:'scroll',value:function scroll(
|
||||
|
||||
e){
|
||||
var viewport=e.target;
|
||||
|
@ -90,8 +90,8 @@ var top=Math.floor((viewport.scrollTop-viewport.clientHeight*1.0)/rowHeight);
|
|||
var height=Math.ceil(viewport.clientHeight*3.0/rowHeight);
|
||||
this.state.viewport.top=top;
|
||||
this.state.viewport.height=height;
|
||||
this.forceUpdate();}},{key:'dropAggregator',value:function dropAggregator(
|
||||
|
||||
this.forceUpdate();
|
||||
}},{key:'dropAggregator',value:function dropAggregator(
|
||||
|
||||
s,d){
|
||||
var aggrow=this.state.aggrow;
|
||||
|
@ -102,40 +102,40 @@ var dIndex=-1;
|
|||
var active=aggrow.getActiveAggregators();
|
||||
var dragged=active[sIndex];
|
||||
if(d.startsWith('aggregate:insert:')){
|
||||
dIndex=parseInt(d.substr(17),10);}else
|
||||
if(d==='divider:insert'){
|
||||
dIndex=active.length;}else
|
||||
{
|
||||
throw 'not allowed to drag '+s+' to '+d;}
|
||||
|
||||
dIndex=parseInt(d.substr(17),10);
|
||||
}else if(d==='divider:insert'){
|
||||
dIndex=active.length;
|
||||
}else{
|
||||
throw'not allowed to drag '+s+' to '+d;
|
||||
}
|
||||
if(dIndex>sIndex){
|
||||
dIndex--;}
|
||||
|
||||
dIndex--;
|
||||
}
|
||||
active.splice(sIndex,1);
|
||||
active.splice(dIndex,0,dragged);
|
||||
aggrow.setActiveAggregators(active);
|
||||
this.forceUpdate();}else
|
||||
if(s.startsWith('expander:active:')){
|
||||
this.forceUpdate();
|
||||
}else if(s.startsWith('expander:active:')){
|
||||
var _sIndex=parseInt(s.substr(16),10);
|
||||
var _dIndex=-1;
|
||||
var _active=aggrow.getActiveExpanders();
|
||||
var _dragged=_active[_sIndex];
|
||||
if(d.startsWith('expander:insert:')){
|
||||
_dIndex=parseInt(d.substr(16),10);}else
|
||||
if(d==='divider:insert'){
|
||||
_dIndex=0;}else
|
||||
{
|
||||
throw 'not allowed to drag '+s+' to '+d;}
|
||||
|
||||
_dIndex=parseInt(d.substr(16),10);
|
||||
}else if(d==='divider:insert'){
|
||||
_dIndex=0;
|
||||
}else{
|
||||
throw'not allowed to drag '+s+' to '+d;
|
||||
}
|
||||
if(_dIndex>_sIndex){
|
||||
_dIndex--;}
|
||||
|
||||
_dIndex--;
|
||||
}
|
||||
_active.splice(_sIndex,1);
|
||||
_active.splice(_dIndex,0,_dragged);
|
||||
aggrow.setActiveExpanders(_active);
|
||||
this.forceUpdate();}}},{key:'render',value:function render()
|
||||
|
||||
|
||||
this.forceUpdate();
|
||||
}
|
||||
}},{key:'render',value:function render()
|
||||
|
||||
{var _this4=this;
|
||||
var headers=[];
|
||||
|
@ -149,41 +149,41 @@ headers.push(
|
|||
React.createElement(DropTarget,{
|
||||
id:'aggregate:insert:'+i.toString(),
|
||||
dropFilter:function dropFilter(){return true;},
|
||||
dropAction:function dropAction(s,d){_this4.dropAggregator(s,d);},__source:{fileName:_jsxFileName,lineNumber:149}},
|
||||
dropAction:function dropAction(s,d){_this4.dropAggregator(s,d);}},
|
||||
|
||||
React.createElement('div',{style:{
|
||||
width:'16px',
|
||||
height:'inherit',
|
||||
backgroundColor:'darkGray',
|
||||
flexShrink:'0'},__source:{fileName:_jsxFileName,lineNumber:154}})));
|
||||
flexShrink:'0'}})));
|
||||
|
||||
|
||||
headers.push(React.createElement(Draggable,{id:'aggregate:active:'+i.toString(),__source:{fileName:_jsxFileName,lineNumber:161}},
|
||||
React.createElement('div',{style:{width:'128px',textAlign:'center',flexShrink:'0'},__source:{fileName:_jsxFileName,lineNumber:162}},name)));}
|
||||
|
||||
headers.push(React.createElement(Draggable,{id:'aggregate:active:'+i.toString()},
|
||||
React.createElement('div',{style:{width:'128px',textAlign:'center',flexShrink:'0'}},name)));
|
||||
|
||||
}
|
||||
headers.push(
|
||||
React.createElement(DropTarget,{
|
||||
id:'divider:insert',
|
||||
dropFilter:function dropFilter(){return true;},
|
||||
dropAction:function dropAction(s,d){_this4.dropAggregator(s,d);},__source:{fileName:_jsxFileName,lineNumber:166}},
|
||||
dropAction:function dropAction(s,d){_this4.dropAggregator(s,d);}},
|
||||
|
||||
React.createElement('div',{style:{
|
||||
width:'16px',
|
||||
height:'inherit',
|
||||
backgroundColor:'gold',
|
||||
flexShrink:'0'},__source:{fileName:_jsxFileName,lineNumber:171}})));
|
||||
flexShrink:'0'}})));
|
||||
|
||||
|
||||
for(var _i=0;_i<expanders.length;_i++){
|
||||
var _name=aggrow.getExpanderName(expanders[_i]);
|
||||
var bg=_i%2===0?'white':'lightGray';
|
||||
headers.push(React.createElement(Draggable,{id:'expander:active:'+_i.toString(),__source:{fileName:_jsxFileName,lineNumber:181}},
|
||||
headers.push(React.createElement(Draggable,{id:'expander:active:'+_i.toString()},
|
||||
React.createElement('div',{style:{
|
||||
width:'128px',
|
||||
textAlign:'center',
|
||||
backgroundColor:bg,
|
||||
flexShrink:'0'},__source:{fileName:_jsxFileName,lineNumber:182}},
|
||||
flexShrink:'0'}},
|
||||
|
||||
_name)));
|
||||
|
||||
|
@ -193,28 +193,28 @@ headers.push(
|
|||
React.createElement(DropTarget,{
|
||||
id:'expander:insert:'+(_i+1).toString(),
|
||||
dropFilter:function dropFilter(){return true;},
|
||||
dropAction:function dropAction(s,d){_this4.dropAggregator(s,d);},__source:{fileName:_jsxFileName,lineNumber:193}},
|
||||
dropAction:function dropAction(s,d){_this4.dropAggregator(s,d);}},
|
||||
|
||||
React.createElement('div',{style:{
|
||||
height:'inherit',
|
||||
backgroundColor:'darkGray',
|
||||
flexShrink:'0'},__source:{fileName:_jsxFileName,lineNumber:198}},
|
||||
flexShrink:'0'}},
|
||||
|
||||
sep)));}
|
||||
sep)));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
React.createElement('div',{style:{width:'100%',height:'100%',display:'flex',flexDirection:'column'},__source:{fileName:_jsxFileName,lineNumber:210}},
|
||||
return(
|
||||
React.createElement('div',{style:{width:'100%',height:'100%',display:'flex',flexDirection:'column'}},
|
||||
React.createElement('div',{style:{
|
||||
width:'100%',
|
||||
height:'26px',
|
||||
display:'flex',
|
||||
flexDirection:'row',
|
||||
alignItems:'center',
|
||||
borderBottom:'2px solid black'},__source:{fileName:_jsxFileName,lineNumber:211}},
|
||||
borderBottom:'2px solid black'}},
|
||||
|
||||
headers),
|
||||
|
||||
|
@ -222,34 +222,34 @@ React.createElement('div',{style:{
|
|||
width:'100%',
|
||||
flexGrow:'1',
|
||||
overflow:'scroll'},
|
||||
onScroll:function onScroll(e){return _this4.scroll(e);},__source:{fileName:_jsxFileName,lineNumber:221}},
|
||||
React.createElement('div',{style:{position:'relative'},__source:{fileName:_jsxFileName,lineNumber:226}},
|
||||
this.renderVirtualizedRows()))));}},{key:'renderVirtualizedRows',value:function renderVirtualizedRows()
|
||||
|
||||
onScroll:function onScroll(e){return _this4.scroll(e);}},
|
||||
React.createElement('div',{style:{position:'relative'}},
|
||||
this.renderVirtualizedRows()))));
|
||||
|
||||
|
||||
|
||||
|
||||
}},{key:'renderVirtualizedRows',value:function renderVirtualizedRows()
|
||||
|
||||
{var _this5=this;
|
||||
var aggrow=this.state.aggrow;
|
||||
var viewport=this.state.viewport;
|
||||
var rows=aggrow.getRows(viewport.top,viewport.height);
|
||||
return (
|
||||
return(
|
||||
React.createElement('div',{style:{
|
||||
position:'absolute',
|
||||
width:'100%',
|
||||
height:(rowHeight*(aggrow.getHeight()+20)).toString()+'px'},__source:{fileName:_jsxFileName,lineNumber:239}},
|
||||
|
||||
rows.map(function(child){return _this5.renderRow(child);})));}},{key:'renderRow',value:function renderRow(
|
||||
height:(rowHeight*(aggrow.getHeight()+20)).toString()+'px'}},
|
||||
|
||||
rows.map(function(child){return _this5.renderRow(child);})));
|
||||
|
||||
|
||||
}},{key:'renderRow',value:function renderRow(
|
||||
|
||||
row){var _this6=this;
|
||||
if(row===null){
|
||||
return null;}
|
||||
|
||||
return null;
|
||||
}
|
||||
var bg='lightGray';
|
||||
var aggrow=this.state.aggrow;
|
||||
var columns=[];
|
||||
|
@ -257,8 +257,8 @@ var rowText='';
|
|||
var indent=4+aggrow.getRowIndent(row)*treeIndent;
|
||||
var aggregates=aggrow.getActiveAggregators();
|
||||
if(row.parent!==null&&row.parent.expander%2===0){
|
||||
bg='white';}
|
||||
|
||||
bg='white';
|
||||
}
|
||||
for(var i=0;i<aggregates.length;i++){
|
||||
var aggregate=aggrow.getRowAggregate(row,i);
|
||||
columns.push(
|
||||
|
@ -266,45 +266,45 @@ React.createElement('div',{style:{
|
|||
width:'16px',
|
||||
height:'inherit',
|
||||
backgroundColor:'darkGray',
|
||||
flexShrink:'0'},__source:{fileName:_jsxFileName,lineNumber:265}}));
|
||||
flexShrink:'0'}}));
|
||||
|
||||
|
||||
columns.push(
|
||||
React.createElement('div',{style:{
|
||||
width:'128px',
|
||||
textAlign:'right',
|
||||
flexShrink:'0'},__source:{fileName:_jsxFileName,lineNumber:273}},
|
||||
|
||||
aggregate));}
|
||||
flexShrink:'0'}},
|
||||
|
||||
aggregate));
|
||||
|
||||
|
||||
}
|
||||
columns.push(
|
||||
React.createElement('div',{style:{
|
||||
width:'16px',
|
||||
height:'inherit',
|
||||
backgroundColor:'gold',
|
||||
flexShrink:'0'},__source:{fileName:_jsxFileName,lineNumber:283}}));
|
||||
flexShrink:'0'}}));
|
||||
|
||||
|
||||
if(aggrow.canExpand(row)){
|
||||
rowText+='+';}else
|
||||
if(aggrow.canContract(row)){
|
||||
rowText+='-';}else
|
||||
{
|
||||
rowText+=' ';}
|
||||
|
||||
rowText+='+';
|
||||
}else if(aggrow.canContract(row)){
|
||||
rowText+='-';
|
||||
}else{
|
||||
rowText+=' ';
|
||||
}
|
||||
rowText+=aggrow.getRowLabel(row);
|
||||
columns.push(
|
||||
React.createElement('div',{style:{
|
||||
marginLeft:indent.toString()+'px',
|
||||
flexShrink:'0',
|
||||
whiteSpace:'nowrap'},__source:{fileName:_jsxFileName,lineNumber:299}},
|
||||
whiteSpace:'nowrap'}},
|
||||
|
||||
rowText));
|
||||
|
||||
|
||||
return (
|
||||
return(
|
||||
React.createElement('div',{style:{
|
||||
position:'absolute',
|
||||
height:(rowHeight-1).toString()+'px',
|
||||
|
@ -317,10 +317,13 @@ borderBottom:'1px solid gray'},
|
|||
onClick:function onClick(){
|
||||
if(aggrow.canExpand(row)){
|
||||
aggrow.expand(row);
|
||||
_this6.forceUpdate();}else
|
||||
if(aggrow.canContract(row)){
|
||||
_this6.forceUpdate();
|
||||
}else if(aggrow.canContract(row)){
|
||||
aggrow.contract(row);
|
||||
_this6.forceUpdate();}},__source:{fileName:_jsxFileName,lineNumber:308}},
|
||||
_this6.forceUpdate();
|
||||
}
|
||||
}},
|
||||
columns));
|
||||
|
||||
|
||||
columns));}}]);return Table;}(React.Component);
|
||||
}}]);return Table;}(React.Component);// @generated
|
||||
|
|
|
@ -10,6 +10,13 @@
|
|||
/*eslint no-console-disallow: "off"*/
|
||||
/*global React ReactDOM Table stringInterner stackRegistry aggrow preLoadedCapture:true*/
|
||||
|
||||
function getTypeName(ref) {
|
||||
if (ref.type === 'Function' && !!ref.value) {
|
||||
return 'Function ' + ref.value.name;
|
||||
}
|
||||
return ref.type;
|
||||
}
|
||||
|
||||
function registerReactComponentTreeImpl(refs, registry, parents, inEdgeNames, trees, id) {
|
||||
if (parents[id] === undefined) {
|
||||
// not a component
|
||||
|
@ -93,7 +100,7 @@ function registerPathToRoot(roots, refs, registry, reactComponentTree) {
|
|||
const id = roots[i];
|
||||
if (visited[id] === undefined) {
|
||||
const ref = refs[id];
|
||||
visited[id] = registry.insert(registry.root, ref.type);
|
||||
visited[id] = registry.insert(registry.root, getTypeName(ref));
|
||||
breadth.push(id);
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +140,7 @@ function registerPathToRoot(roots, refs, registry, reactComponentTree) {
|
|||
// TODO: figure out why we have edges that point to things not JSCell
|
||||
//console.log('registerPathToRoot unable to follow edge from ' + id + ' to ' + edgeId);
|
||||
} else {
|
||||
visited[edgeId] = registry.insert(node, edgeName + edgeRef.type);
|
||||
visited[edgeId] = registry.insert(node, edgeName + getTypeName(edgeRef));
|
||||
nextBreadth.push(edgeId);
|
||||
if (reactComponentTree[edgeId] === undefined) {
|
||||
reactComponentTree[edgeId] = reactComponentTree[id];
|
||||
|
@ -191,7 +198,7 @@ function captureRegistry() {
|
|||
for (const id in capture.refs) {
|
||||
const ref = capture.refs[id];
|
||||
newData[dataOffset + idField] = parseInt(id, 16);
|
||||
newData[dataOffset + typeField] = this.strings.intern(ref.type);
|
||||
newData[dataOffset + typeField] = this.strings.intern(getTypeName(ref));
|
||||
newData[dataOffset + sizeField] = ref.size;
|
||||
newData[dataOffset + traceField] = internedCaptureId;
|
||||
const pathNode = rootPathMap[id];
|
||||
|
|
|
@ -12,6 +12,100 @@
|
|||
const spawn = require('child_process').spawn;
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const http = require('http');
|
||||
const urlLib = require('url');
|
||||
const SourceMapConsumer = require('source-map').SourceMapConsumer;
|
||||
|
||||
|
||||
// url: string
|
||||
// onSuccess: function (SourceMapConsumer)
|
||||
// onFailure: function (string)
|
||||
function getSourceMapForUrl(url, onFailure, onSuccess) {
|
||||
if (!url) {
|
||||
onFailure('must provide a URL');
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedUrl = urlLib.parse(url);
|
||||
const options = {
|
||||
host: 'localhost',
|
||||
port: parsedUrl.port,
|
||||
path: parsedUrl.pathname.replace(/\.bundle$/, '.map') + parsedUrl.search,
|
||||
};
|
||||
|
||||
http.get(options, (res) => {
|
||||
res.setEncoding('utf8');
|
||||
let sawEnd = false;
|
||||
let resBody = '';
|
||||
res.on('data', (chunk) => {
|
||||
resBody += chunk;
|
||||
}).on('end', () => {
|
||||
sawEnd = true;
|
||||
onSuccess(new SourceMapConsumer(resBody));
|
||||
}).on('close', (err) => {
|
||||
if (!sawEnd) {
|
||||
onFailure('Connection terminated prematurely because of: '
|
||||
+ err.code + ' for url: ' + url);
|
||||
}
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
onFailure('Could not get response from: ' + url + ', error: ' + err.message);
|
||||
});
|
||||
}
|
||||
|
||||
// capture: capture object
|
||||
// onSuccess: function (Map of url -> SourceMapConsumer)
|
||||
// onFailure: function (string)
|
||||
function getSourceMapsForCapture(capture, onFailure, onSuccess) {
|
||||
const urls = new Set();
|
||||
const sourcemaps = new Map();
|
||||
for (const id in capture.refs) {
|
||||
const ref = capture.refs[id];
|
||||
if (ref.type === 'Function' && ref.value && !!ref.value.url) {
|
||||
urls.add(ref.value.url);
|
||||
}
|
||||
}
|
||||
urls.forEach((url) => {
|
||||
getSourceMapForUrl(url, onFailure, (sourcemap) => {
|
||||
sourcemaps.set(url, sourcemap);
|
||||
urls.delete(url);
|
||||
if (urls.size === 0) {
|
||||
onSuccess(sourcemaps);
|
||||
}
|
||||
});
|
||||
});
|
||||
if (urls.size === 0) {
|
||||
console.warn('No source information found in capture');
|
||||
onSuccess(sourcemaps);
|
||||
}
|
||||
}
|
||||
|
||||
// capture: capture object
|
||||
// onSuccess: function (capture object)
|
||||
// onFailure: function (string)
|
||||
function symbolocateHeapCaptureFunctions(capture, onFailure, onSuccess) {
|
||||
getSourceMapsForCapture(capture, onFailure, (sourcemaps) => {
|
||||
for (const id in capture.refs) {
|
||||
const ref = capture.refs[id];
|
||||
if (ref.type === 'Function' && ref.value && !!ref.value.url) {
|
||||
const sourcemap = sourcemaps.get(ref.value.url);
|
||||
const original = sourcemap.originalPositionFor({
|
||||
line: ref.value.line,
|
||||
column: ref.value.col,
|
||||
});
|
||||
if (original.name) {
|
||||
ref.value.name = original.name;
|
||||
} else if (!ref.value.name) {
|
||||
ref.value.name = path.posix.basename(original.source) + ':' + original.line;
|
||||
}
|
||||
ref.value.url = 'file://' + original.source;
|
||||
ref.value.line = original.line;
|
||||
ref.value.col = original.column;
|
||||
}
|
||||
}
|
||||
onSuccess(capture);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function(req, res, next) {
|
||||
if (req.url !== '/jscheapcaptureupload') {
|
||||
|
@ -19,35 +113,41 @@ module.exports = function(req, res, next) {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log('Downloading Heap Capture');
|
||||
var preload = path.join(__dirname, 'heapCapture/preLoadedCapture.js');
|
||||
fs.writeFileSync(preload, 'var preLoadedCapture = ');
|
||||
fs.appendFileSync(preload, req.rawBody);
|
||||
fs.appendFileSync(preload, ';');
|
||||
res.end();
|
||||
const captureDir = path.join(__dirname, 'heapCapture/captures');
|
||||
if (!fs.existsSync(captureDir)) {
|
||||
fs.mkdirSync(captureDir);
|
||||
}
|
||||
console.log('Packaging Trace');
|
||||
var captureHtml = captureDir + '/capture_' + Date.now() + '.html';
|
||||
var capture = fs.createWriteStream(captureHtml);
|
||||
var inliner = spawn(
|
||||
'inliner',
|
||||
['--nocompress', 'heapCapture.html'],
|
||||
{ cwd: path.join(__dirname, '/heapCapture/'),
|
||||
stdio: [ process.stdin, 'pipe', process.stderr ],
|
||||
});
|
||||
inliner.stdout.pipe(capture);
|
||||
inliner.on('error', (err) => {
|
||||
console.error('Error processing heap capture: ' + err.message);
|
||||
console.error('make sure you have installed inliner with \'npm install inliner -g\'');
|
||||
});
|
||||
inliner.on('exit', (code, signal) => {
|
||||
if (code === 0) {
|
||||
console.log('Heap capture written to: ' + captureHtml);
|
||||
} else {
|
||||
console.error('Error processing heap capture, inliner returned code: ' + code);
|
||||
console.log('Symbolocating Heap Capture');
|
||||
symbolocateHeapCaptureFunctions(JSON.parse(req.rawBody), (err) => {
|
||||
console.error('Error when symbolicating: ' + err);
|
||||
},
|
||||
(capture) => {
|
||||
res.end();
|
||||
const preload = path.join(__dirname, 'heapCapture/preLoadedCapture.js');
|
||||
fs.writeFileSync(preload, 'var preLoadedCapture = ');
|
||||
fs.appendFileSync(preload, JSON.stringify(capture));
|
||||
fs.appendFileSync(preload, ';');
|
||||
const captureDir = path.join(__dirname, 'heapCapture/captures');
|
||||
if (!fs.existsSync(captureDir)) {
|
||||
fs.mkdirSync(captureDir);
|
||||
}
|
||||
console.log('Packaging Trace');
|
||||
var captureHtml = captureDir + '/capture_' + Date.now() + '.html';
|
||||
var capture = fs.createWriteStream(captureHtml);
|
||||
var inliner = spawn(
|
||||
'inliner',
|
||||
['--nocompress', 'heapCapture.html'],
|
||||
{ cwd: path.join(__dirname, '/heapCapture/'),
|
||||
stdio: [ process.stdin, 'pipe', process.stderr ],
|
||||
});
|
||||
inliner.stdout.pipe(capture);
|
||||
inliner.on('error', (err) => {
|
||||
console.error('Error processing heap capture: ' + err.message);
|
||||
console.error('make sure you have installed inliner with \'npm install inliner -g\'');
|
||||
});
|
||||
inliner.on('exit', (code, signal) => {
|
||||
if (code === 0) {
|
||||
console.log('Heap capture written to: ' + captureHtml);
|
||||
} else {
|
||||
console.error('Error processing heap capture, inliner returned code: ' + code);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue