mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-05-28 08:07:25 +08:00
refactor how path and react tree are done in jsc heap capture
Reviewed By: bnham Differential Revision: D3757510 fbshipit-source-id: dff0f85586ef910b28c3fedf06a5178a2c2b28b2
This commit is contained in:
committed by
Facebook Github Bot 5
parent
6efe8e1d81
commit
73d7f36d8f
@@ -114,195 +114,128 @@ callback(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeName(ref){
|
||||
if(ref.type==='Function'&&!!ref.value){
|
||||
return'Function '+ref.value.name;
|
||||
function getInternalInstanceName(visitor){
|
||||
var type=visitor.clone().moveToEdge('_currentElement').moveToEdge('type');
|
||||
if(type.getType()==='string'){// element.type is string
|
||||
return type.getValue();
|
||||
}else if(type.getType()==='Function'){// element.type is function
|
||||
var displayName=type.clone().moveToEdge('displayName');
|
||||
if(displayName.isDefined()){
|
||||
return displayName.getValue();// element.type.displayName
|
||||
}
|
||||
return ref.type;
|
||||
}
|
||||
|
||||
function idGetProp(refs,id,prop){
|
||||
var ref=refs[id];
|
||||
if(ref&&ref.edges){
|
||||
var edges=ref.edges;
|
||||
for(var edgeId in edges){
|
||||
if(edges[edgeId]===prop){
|
||||
return edgeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function idPropForEach(refs,id,callback){
|
||||
var ref=refs[id];
|
||||
if(ref&&ref.edges){
|
||||
var edges=ref.edges;
|
||||
for(var edgeId in edges){
|
||||
callback(edges[edgeId],edgeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getInternalInstanceName(refs,id){
|
||||
var elementId=idGetProp(refs,id,'_currentElement');
|
||||
var typeId=idGetProp(refs,elementId,'type');
|
||||
var typeRef=refs[typeId];
|
||||
if(typeRef){
|
||||
if(typeRef.type==='string'){// element.type is string
|
||||
if(typeRef.value){
|
||||
return typeRef.value;
|
||||
}
|
||||
}else if(typeRef.type==='Function'){// element.type is function
|
||||
var displayNameId=idGetProp(refs,typeId,'displayName');
|
||||
if(displayNameId){
|
||||
var displayNameRef=refs[displayNameId];
|
||||
if(displayNameRef&&displayNameRef.value){
|
||||
return displayNameRef.value;// element.type.displayName
|
||||
}
|
||||
}
|
||||
var nameId=idGetProp(refs,typeId,'name');
|
||||
if(nameId){
|
||||
var nameRef=refs[nameId];
|
||||
if(nameRef&&nameRef.value){
|
||||
return nameRef.value;// element.type.name
|
||||
}
|
||||
}
|
||||
if(typeRef.value&&typeRef.value.name){
|
||||
return typeRef.value.name;// element.type symbolicated function name
|
||||
var name=type.clone().moveToEdge('name');
|
||||
if(name.isDefined()){
|
||||
return name.getValue();// element.type.name
|
||||
}
|
||||
type.moveToEdge('@Executable');
|
||||
if(type.getType()==='FunctionExecutable'){
|
||||
return type.getRef().value.name;// element.type symbolicated name
|
||||
}
|
||||
}
|
||||
return'#unknown';
|
||||
}
|
||||
|
||||
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,getInternalInstanceName(refs,id));
|
||||
function buildReactComponentTree(visitor,registry){
|
||||
var ref=visitor.getRef();
|
||||
if(ref.reactTree||ref.reactParent===undefined){
|
||||
return;// has one or doesn't need one
|
||||
}
|
||||
var parentVisitor=ref.reactParent;
|
||||
if(parentVisitor===null){
|
||||
ref.reactTree=registry.insert(registry.root,getInternalInstanceName(visitor));
|
||||
}else if(parentVisitor){
|
||||
var parentRef=parentVisitor.getRef();
|
||||
buildReactComponentTree(parentVisitor,registry);
|
||||
var relativeName=getInternalInstanceName(visitor);
|
||||
if(ref.reactKey){
|
||||
relativeName=ref.reactKey+': '+relativeName;
|
||||
}
|
||||
ref.reactTree=registry.insert(parentRef.reactTree,relativeName);
|
||||
}else{
|
||||
var parent=parents[id];
|
||||
var inEdgeName=inEdgeNames[id];
|
||||
var parentTree=trees[parent];
|
||||
if(parentTree===undefined){
|
||||
parentTree=registerReactComponentTreeImpl(
|
||||
refs,
|
||||
registry,
|
||||
parents,
|
||||
inEdgeNames,
|
||||
trees,
|
||||
parent);
|
||||
throw'non react instance parent of react instance';
|
||||
}
|
||||
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={};var _loop=function _loop(
|
||||
id){
|
||||
idPropForEach(refs,id,function(name,propId){
|
||||
if(propId!=='0x0'){
|
||||
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;
|
||||
function markReactComponentTree(refs,registry){
|
||||
// annotate all refs that are react internal instances with their parent and name
|
||||
// ref.reactParent = visitor that points to parent instance,
|
||||
// null if we know it's an instance, but don't have a parent yet
|
||||
// ref.reactKey = if a key is used to distinguish siblings
|
||||
forEachRef(refs,function(visitor){
|
||||
var visitorClone=visitor.clone();// visitor will get stomped on next iteration
|
||||
var ref=visitor.getRef();
|
||||
visitor.forEachEdge(function(edgeName,edgeVisitor){
|
||||
var edgeRef=edgeVisitor.getRef();
|
||||
if(edgeRef){
|
||||
if(edgeName==='_renderedChildren'){
|
||||
if(ref.reactParent===undefined){
|
||||
// ref is react component, even if we don't have a parent yet
|
||||
ref.reactParent=null;
|
||||
}
|
||||
idPropForEach(refs,propId,function(childName,childPropId){
|
||||
if(childName.startsWith('.')){
|
||||
parents[childPropId]=id;
|
||||
inEdgeNames[childPropId]=childName+': '+
|
||||
getInternalInstanceName(refs,childPropId);
|
||||
edgeVisitor.forEachEdge(function(childName,childVisitor){
|
||||
var childRef=childVisitor.getRef();
|
||||
if(childRef&&childName.startsWith('.')){
|
||||
childRef.reactParent=visitorClone;
|
||||
childRef.reactKey=childName;
|
||||
}
|
||||
});
|
||||
}else if(name==='_renderedComponent'){
|
||||
if(parents[id]===undefined){
|
||||
parents[id]=null;
|
||||
}else if(edgeName==='_renderedComponent'){
|
||||
if(ref.reactParent===undefined){
|
||||
ref.reactParent=null;
|
||||
}
|
||||
parents[propId]=id;
|
||||
inEdgeNames[propId]=getInternalInstanceName(refs,propId);
|
||||
edgeRef.reactParent=visitorClone;
|
||||
}
|
||||
}
|
||||
});};for(var id in refs){_loop(id);
|
||||
}
|
||||
});
|
||||
});
|
||||
// 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);
|
||||
}
|
||||
// fill in ref.reactTree = path registry node
|
||||
forEachRef(refs,function(visitor){
|
||||
buildReactComponentTree(visitor,registry);
|
||||
});
|
||||
// hook in components by looking at their _reactInternalInstance fields
|
||||
for(var _id2 in refs){
|
||||
var internalInstance=idGetProp(refs,_id2,'_reactInternalInstance');
|
||||
if(internalInstance&&trees[internalInstance]){
|
||||
trees[_id2]=trees[internalInstance];
|
||||
}
|
||||
}
|
||||
return trees;
|
||||
}
|
||||
|
||||
function registerPathToRoot(roots,refs,registry,reactComponentTree){
|
||||
var visited={};
|
||||
var breadth=[];
|
||||
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,getTypeName(ref));
|
||||
breadth.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
while(breadth.length>0){
|
||||
var nextBreadth=[];var _loop2=function _loop2(
|
||||
_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);
|
||||
forEachRef(refs,function(visitor){
|
||||
var ref=visitor.getRef();
|
||||
var instanceRef=visitor.moveToEdge('_reactInternalInstance').getRef();
|
||||
if(instanceRef){
|
||||
ref.reactTree=instanceRef.reactTree;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(var j=0;j<edges.length;j++){
|
||||
var edgeId=edges[j];
|
||||
var edgeName='';
|
||||
if(ref.edges[edgeId]){
|
||||
edgeName=ref.edges[edgeId]+': ';
|
||||
function registerPathToRoot(refs,registry){
|
||||
markReactComponentTree(refs,registry);
|
||||
var breadth=[];
|
||||
forEachRef(refs,function(visitor){
|
||||
var ref=visitor.getRef();
|
||||
if(ref.type==='CallbackGlobalObject'){
|
||||
ref.rootPath=registry.insert(registry.root,ref.type);
|
||||
breadth.push(visitor.clone());
|
||||
}
|
||||
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+getTypeName(edgeRef));
|
||||
nextBreadth.push(edgeId);
|
||||
if(reactComponentTree[edgeId]===undefined){
|
||||
reactComponentTree[edgeId]=reactComponentTree[id];
|
||||
});var _loop=function _loop(){
|
||||
|
||||
var nextBreadth=[];var _loop2=function _loop2(
|
||||
i){
|
||||
var visitor=breadth[i];
|
||||
var ref=visitor.getRef();
|
||||
visitor.forEachEdge(function(edgeName,edgeVisitor){
|
||||
var edgeRef=edgeVisitor.getRef();
|
||||
if(edgeRef&&edgeRef.rootPath===undefined){
|
||||
var pathName=edgeRef.type;
|
||||
if(edgeName){
|
||||
pathName=edgeName+': '+pathName;
|
||||
}
|
||||
edgeRef.rootPath=registry.insert(ref.rootPath,pathName);
|
||||
nextBreadth.push(edgeVisitor.clone());
|
||||
// copy react tree forward
|
||||
if(edgeRef.reactTree===undefined){
|
||||
edgeRef.reactTree=ref.reactTree;
|
||||
}
|
||||
}
|
||||
});};for(var i=0;i<breadth.length;i++){_loop2(i);
|
||||
}
|
||||
}};for(var _i=0;_i<breadth.length;_i++){_loop2(_i);
|
||||
breadth=nextBreadth;};while(breadth.length>0){_loop();
|
||||
}
|
||||
breadth=nextBreadth;
|
||||
}
|
||||
return visited;
|
||||
}
|
||||
|
||||
function captureRegistry(){
|
||||
@@ -330,7 +263,7 @@ var rowCount=0;
|
||||
for(var id in capture.refs){// eslint-disable-line no-unused-vars
|
||||
rowCount++;
|
||||
}
|
||||
for(var _id3 in capture.markedBlocks){// eslint-disable-line no-unused-vars
|
||||
for(var _id in capture.markedBlocks){// eslint-disable-line no-unused-vars
|
||||
rowCount++;
|
||||
}
|
||||
console.log(
|
||||
@@ -342,13 +275,7 @@ newData.set(data);
|
||||
var dataOffset=this.data.length;
|
||||
this.data=null;
|
||||
|
||||
var reactComponentTreeMap=registerReactComponentTree(capture.refs,this.stacks);
|
||||
var rootPathMap=registerPathToRoot(
|
||||
capture.roots,
|
||||
capture.refs,
|
||||
this.stacks,
|
||||
reactComponentTreeMap);
|
||||
|
||||
registerPathToRoot(capture.refs,this.stacks);
|
||||
var internedCaptureId=this.strings.intern(captureId);
|
||||
var noneStack=this.stacks.insert(this.stacks.root,'#none');
|
||||
forEachRef(capture.refs,function(visitor){
|
||||
@@ -358,23 +285,22 @@ newData[dataOffset+idField]=parseInt(id,16);
|
||||
newData[dataOffset+typeField]=_this2.strings.intern(ref.type);
|
||||
newData[dataOffset+sizeField]=ref.size;
|
||||
newData[dataOffset+traceField]=internedCaptureId;
|
||||
var pathNode=rootPathMap[id];
|
||||
if(pathNode===undefined){
|
||||
throw'did not find path for ref!';
|
||||
if(ref.rootPath===undefined){
|
||||
newData[dataOffset+pathField]=noneStack.id;
|
||||
}else{
|
||||
newData[dataOffset+pathField]=ref.rootPath.id;
|
||||
}
|
||||
newData[dataOffset+pathField]=pathNode.id;
|
||||
var reactTree=reactComponentTreeMap[id];
|
||||
if(reactTree===undefined){
|
||||
if(ref.reactTree===undefined){
|
||||
newData[dataOffset+reactField]=noneStack.id;
|
||||
}else{
|
||||
newData[dataOffset+reactField]=reactTree.id;
|
||||
newData[dataOffset+reactField]=ref.reactTree.id;
|
||||
}
|
||||
newData[dataOffset+valueField]=_this2.strings.intern(visitor.getValue());
|
||||
dataOffset+=numFields;
|
||||
});
|
||||
for(var _id4 in capture.markedBlocks){
|
||||
var block=capture.markedBlocks[_id4];
|
||||
newData[dataOffset+idField]=parseInt(_id4,16);
|
||||
for(var _id2 in capture.markedBlocks){
|
||||
var block=capture.markedBlocks[_id2];
|
||||
newData[dataOffset+idField]=parseInt(_id2,16);
|
||||
newData[dataOffset+typeField]=this.strings.intern('Marked Block Overhead');
|
||||
newData[dataOffset+sizeField]=block.capacity-block.size;
|
||||
newData[dataOffset+traceField]=internedCaptureId;
|
||||
|
||||
@@ -114,195 +114,128 @@ function forEachRef(refs, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeName(ref) {
|
||||
if (ref.type === 'Function' && !!ref.value) {
|
||||
return 'Function ' + ref.value.name;
|
||||
}
|
||||
return ref.type;
|
||||
}
|
||||
|
||||
function idGetProp(refs, id, prop) {
|
||||
const ref = refs[id];
|
||||
if (ref && ref.edges) {
|
||||
const edges = ref.edges;
|
||||
for (const edgeId in edges) {
|
||||
if (edges[edgeId] === prop) {
|
||||
return edgeId;
|
||||
}
|
||||
function getInternalInstanceName(visitor) {
|
||||
const type = visitor.clone().moveToEdge('_currentElement').moveToEdge('type');
|
||||
if (type.getType() === 'string') { // element.type is string
|
||||
return type.getValue();
|
||||
} else if (type.getType() === 'Function') { // element.type is function
|
||||
const displayName = type.clone().moveToEdge('displayName');
|
||||
if (displayName.isDefined()) {
|
||||
return displayName.getValue(); // element.type.displayName
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function idPropForEach(refs, id, callback) {
|
||||
const ref = refs[id];
|
||||
if (ref && ref.edges) {
|
||||
const edges = ref.edges;
|
||||
for (const edgeId in edges) {
|
||||
callback(edges[edgeId], edgeId);
|
||||
const name = type.clone().moveToEdge('name');
|
||||
if (name.isDefined()) {
|
||||
return name.getValue(); // element.type.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getInternalInstanceName(refs, id) {
|
||||
const elementId = idGetProp(refs, id, '_currentElement');
|
||||
const typeId = idGetProp(refs, elementId, 'type');
|
||||
const typeRef = refs[typeId];
|
||||
if (typeRef) {
|
||||
if (typeRef.type === 'string') { // element.type is string
|
||||
if (typeRef.value) {
|
||||
return typeRef.value;
|
||||
}
|
||||
} else if (typeRef.type === 'Function') { // element.type is function
|
||||
const displayNameId = idGetProp(refs, typeId, 'displayName');
|
||||
if (displayNameId) {
|
||||
const displayNameRef = refs[displayNameId];
|
||||
if (displayNameRef && displayNameRef.value) {
|
||||
return displayNameRef.value; // element.type.displayName
|
||||
}
|
||||
}
|
||||
const nameId = idGetProp(refs, typeId, 'name');
|
||||
if (nameId) {
|
||||
const nameRef = refs[nameId];
|
||||
if (nameRef && nameRef.value) {
|
||||
return nameRef.value; // element.type.name
|
||||
}
|
||||
}
|
||||
if (typeRef.value && typeRef.value.name) {
|
||||
return typeRef.value.name; // element.type symbolicated function name
|
||||
}
|
||||
type.moveToEdge('@Executable');
|
||||
if (type.getType() === 'FunctionExecutable') {
|
||||
return type.getRef().value.name; // element.type symbolicated name
|
||||
}
|
||||
}
|
||||
return '#unknown';
|
||||
}
|
||||
|
||||
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, getInternalInstanceName(refs, id));
|
||||
} else {
|
||||
const parent = parents[id];
|
||||
const inEdgeName = inEdgeNames[id];
|
||||
let parentTree = trees[parent];
|
||||
if (parentTree === undefined) {
|
||||
parentTree = registerReactComponentTreeImpl(
|
||||
refs,
|
||||
registry,
|
||||
parents,
|
||||
inEdgeNames,
|
||||
trees,
|
||||
parent);
|
||||
}
|
||||
trees[id] = registry.insert(parentTree, inEdgeName);
|
||||
function buildReactComponentTree(visitor, registry) {
|
||||
const ref = visitor.getRef();
|
||||
if (ref.reactTree || ref.reactParent === undefined) {
|
||||
return; // has one or doesn't need one
|
||||
}
|
||||
const parentVisitor = ref.reactParent;
|
||||
if (parentVisitor === null) {
|
||||
ref.reactTree = registry.insert(registry.root, getInternalInstanceName(visitor));
|
||||
} else if (parentVisitor) {
|
||||
const parentRef = parentVisitor.getRef();
|
||||
buildReactComponentTree(parentVisitor, registry);
|
||||
let relativeName = getInternalInstanceName(visitor);
|
||||
if (ref.reactKey) {
|
||||
relativeName = ref.reactKey + ': ' + relativeName;
|
||||
}
|
||||
ref.reactTree = registry.insert(parentRef.reactTree, relativeName);
|
||||
} else {
|
||||
throw 'non react instance parent of react instance';
|
||||
}
|
||||
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
|
||||
const parents = {};
|
||||
const inEdgeNames = {};
|
||||
for (const id in refs) {
|
||||
idPropForEach(refs, id, (name, propId) => {
|
||||
if (propId !== '0x0') {
|
||||
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;
|
||||
function markReactComponentTree(refs, registry) {
|
||||
// annotate all refs that are react internal instances with their parent and name
|
||||
// ref.reactParent = visitor that points to parent instance,
|
||||
// null if we know it's an instance, but don't have a parent yet
|
||||
// ref.reactKey = if a key is used to distinguish siblings
|
||||
forEachRef(refs, (visitor) => {
|
||||
const visitorClone = visitor.clone(); // visitor will get stomped on next iteration
|
||||
const ref = visitor.getRef();
|
||||
visitor.forEachEdge((edgeName, edgeVisitor) => {
|
||||
const edgeRef = edgeVisitor.getRef();
|
||||
if (edgeRef) {
|
||||
if (edgeName === '_renderedChildren') {
|
||||
if (ref.reactParent === undefined) {
|
||||
// ref is react component, even if we don't have a parent yet
|
||||
ref.reactParent = null;
|
||||
}
|
||||
idPropForEach(refs, propId, (childName, childPropId) => {
|
||||
if (childName.startsWith('.')) {
|
||||
parents[childPropId] = id;
|
||||
inEdgeNames[childPropId] = childName + ': '
|
||||
+ getInternalInstanceName(refs, childPropId);
|
||||
edgeVisitor.forEachEdge((childName, childVisitor) => {
|
||||
const childRef = childVisitor.getRef();
|
||||
if (childRef && childName.startsWith('.')) {
|
||||
childRef.reactParent = visitorClone;
|
||||
childRef.reactKey = childName;
|
||||
}
|
||||
});
|
||||
} else if (name === '_renderedComponent') {
|
||||
if (parents[id] === undefined) {
|
||||
parents[id] = null;
|
||||
} else if (edgeName === '_renderedComponent') {
|
||||
if (ref.reactParent === undefined) {
|
||||
ref.reactParent = null;
|
||||
}
|
||||
parents[propId] = id;
|
||||
inEdgeNames[propId] = getInternalInstanceName(refs, propId);
|
||||
edgeRef.reactParent = visitorClone;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// build tree of react internal instances (since that's what has the structure)
|
||||
const trees = {};
|
||||
for (const id in refs) {
|
||||
registerReactComponentTreeImpl(refs, registry, parents, inEdgeNames, trees, id);
|
||||
}
|
||||
// fill in ref.reactTree = path registry node
|
||||
forEachRef(refs, (visitor) => {
|
||||
buildReactComponentTree(visitor, registry);
|
||||
});
|
||||
// hook in components by looking at their _reactInternalInstance fields
|
||||
for (const id in refs) {
|
||||
const internalInstance = idGetProp(refs, id, '_reactInternalInstance');
|
||||
if (internalInstance && trees[internalInstance]) {
|
||||
trees[id] = trees[internalInstance];
|
||||
forEachRef(refs, (visitor) => {
|
||||
const ref = visitor.getRef();
|
||||
const instanceRef = visitor.moveToEdge('_reactInternalInstance').getRef();
|
||||
if (instanceRef) {
|
||||
ref.reactTree = instanceRef.reactTree;
|
||||
}
|
||||
}
|
||||
return trees;
|
||||
});
|
||||
}
|
||||
|
||||
function registerPathToRoot(roots, refs, registry, reactComponentTree) {
|
||||
const visited = {};
|
||||
function registerPathToRoot(refs, registry) {
|
||||
markReactComponentTree(refs, registry);
|
||||
let breadth = [];
|
||||
for (let i = 0; i < roots.length; i++) {
|
||||
const id = roots[i];
|
||||
if (visited[id] === undefined) {
|
||||
const ref = refs[id];
|
||||
visited[id] = registry.insert(registry.root, getTypeName(ref));
|
||||
breadth.push(id);
|
||||
forEachRef(refs, (visitor) => {
|
||||
const ref = visitor.getRef();
|
||||
if (ref.type === 'CallbackGlobalObject') {
|
||||
ref.rootPath = registry.insert(registry.root, ref.type);
|
||||
breadth.push(visitor.clone());
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
while (breadth.length > 0) {
|
||||
const nextBreadth = [];
|
||||
for (let i = 0; i < breadth.length; i++) {
|
||||
const id = breadth[i];
|
||||
const ref = refs[id];
|
||||
const node = visited[id];
|
||||
// TODO: make edges map id -> name, (empty for none) seems that would be better
|
||||
|
||||
const edges = Object.getOwnPropertyNames(ref.edges);
|
||||
edges.sort(function putUnknownLast(a, b) {
|
||||
const aName = ref.edges[a];
|
||||
const 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 (let j = 0; j < edges.length; j++) {
|
||||
const edgeId = edges[j];
|
||||
let edgeName = '';
|
||||
if (ref.edges[edgeId]) {
|
||||
edgeName = ref.edges[edgeId] + ': ';
|
||||
}
|
||||
if (visited[edgeId] === undefined) {
|
||||
const 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 + getTypeName(edgeRef));
|
||||
nextBreadth.push(edgeId);
|
||||
if (reactComponentTree[edgeId] === undefined) {
|
||||
reactComponentTree[edgeId] = reactComponentTree[id];
|
||||
}
|
||||
const visitor = breadth[i];
|
||||
const ref = visitor.getRef();
|
||||
visitor.forEachEdge((edgeName, edgeVisitor) => {
|
||||
const edgeRef = edgeVisitor.getRef();
|
||||
if (edgeRef && edgeRef.rootPath === undefined) {
|
||||
let pathName = edgeRef.type;
|
||||
if (edgeName) {
|
||||
pathName = edgeName + ': ' + pathName;
|
||||
}
|
||||
edgeRef.rootPath = registry.insert(ref.rootPath, pathName);
|
||||
nextBreadth.push(edgeVisitor.clone());
|
||||
// copy react tree forward
|
||||
if (edgeRef.reactTree === undefined) {
|
||||
edgeRef.reactTree = ref.reactTree;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
breadth = nextBreadth;
|
||||
}
|
||||
return visited;
|
||||
}
|
||||
|
||||
function captureRegistry() {
|
||||
@@ -342,13 +275,7 @@ function captureRegistry() {
|
||||
let dataOffset = this.data.length;
|
||||
this.data = null;
|
||||
|
||||
const reactComponentTreeMap = registerReactComponentTree(capture.refs, this.stacks);
|
||||
const rootPathMap = registerPathToRoot(
|
||||
capture.roots,
|
||||
capture.refs,
|
||||
this.stacks,
|
||||
reactComponentTreeMap
|
||||
);
|
||||
registerPathToRoot(capture.refs, this.stacks);
|
||||
const internedCaptureId = this.strings.intern(captureId);
|
||||
const noneStack = this.stacks.insert(this.stacks.root, '#none');
|
||||
forEachRef(capture.refs, (visitor) => {
|
||||
@@ -358,16 +285,15 @@ function captureRegistry() {
|
||||
newData[dataOffset + typeField] = this.strings.intern(ref.type);
|
||||
newData[dataOffset + sizeField] = ref.size;
|
||||
newData[dataOffset + traceField] = internedCaptureId;
|
||||
const pathNode = rootPathMap[id];
|
||||
if (pathNode === undefined) {
|
||||
throw 'did not find path for ref!';
|
||||
if (ref.rootPath === undefined) {
|
||||
newData[dataOffset + pathField] = noneStack.id;
|
||||
} else {
|
||||
newData[dataOffset + pathField] = ref.rootPath.id;
|
||||
}
|
||||
newData[dataOffset + pathField] = pathNode.id;
|
||||
const reactTree = reactComponentTreeMap[id];
|
||||
if (reactTree === undefined) {
|
||||
if (ref.reactTree === undefined) {
|
||||
newData[dataOffset + reactField] = noneStack.id;
|
||||
} else {
|
||||
newData[dataOffset + reactField] = reactTree.id;
|
||||
newData[dataOffset + reactField] = ref.reactTree.id;
|
||||
}
|
||||
newData[dataOffset + valueField] = this.strings.intern(visitor.getValue());
|
||||
dataOffset += numFields;
|
||||
|
||||
Reference in New Issue
Block a user