@@ -37,6 +37,7 @@ function Profile() {
3737 this . topDownTree_ = new CallTree ( ) ;
3838 this . bottomUpTree_ = new CallTree ( ) ;
3939 this . c_entries_ = { } ;
40+ this . ticks_ = [ ] ;
4041} ;
4142
4243
@@ -235,7 +236,7 @@ Profile.prototype.findEntry = function(addr) {
235236 *
236237 * @param {Array<number> } stack Stack sample.
237238 */
238- Profile . prototype . recordTick = function ( stack ) {
239+ Profile . prototype . recordTick = function ( time_ns , vmState , stack ) {
239240 var processedStack = this . resolveAndFilterFuncs_ ( stack ) ;
240241 this . bottomUpTree_ . addPath ( processedStack ) ;
241242 processedStack . reverse ( ) ;
@@ -832,3 +833,146 @@ CallTree.Node.prototype.descendToChild = function(
832833 }
833834 return curr ;
834835} ;
836+
837+ function JsonProfile ( ) {
838+ this . codeMap_ = new CodeMap ( ) ;
839+ this . codeEntries_ = [ ] ;
840+ this . functionEntries_ = [ ] ;
841+ this . ticks_ = [ ] ;
842+ }
843+
844+ JsonProfile . prototype . addLibrary = function (
845+ name , startAddr , endAddr ) {
846+ var entry = new CodeMap . CodeEntry (
847+ endAddr - startAddr , name , 'SHARED_LIB' ) ;
848+ this . codeMap_ . addLibrary ( startAddr , entry ) ;
849+
850+ entry . codeId = this . codeEntries_ . length ;
851+ this . codeEntries_ . push ( { name : entry . name , type : entry . type } ) ;
852+ return entry ;
853+ } ;
854+
855+ JsonProfile . prototype . addStaticCode = function (
856+ name , startAddr , endAddr ) {
857+ var entry = new CodeMap . CodeEntry (
858+ endAddr - startAddr , name , 'CPP' ) ;
859+ this . codeMap_ . addStaticCode ( startAddr , entry ) ;
860+
861+ entry . codeId = this . codeEntries_ . length ;
862+ this . codeEntries_ . push ( { name : entry . name , type : entry . type } ) ;
863+ return entry ;
864+ } ;
865+
866+ JsonProfile . prototype . addCode = function (
867+ kind , name , start , size ) {
868+ var entry = new CodeMap . CodeEntry ( size , name , 'CODE' ) ;
869+ this . codeMap_ . addCode ( start , entry ) ;
870+
871+ entry . codeId = this . codeEntries_ . length ;
872+ this . codeEntries_ . push ( { name : entry . name , type : entry . type , kind : kind } ) ;
873+
874+ return entry ;
875+ } ;
876+
877+ JsonProfile . prototype . addFuncCode = function (
878+ kind , name , start , size , funcAddr , state ) {
879+ // As code and functions are in the same address space,
880+ // it is safe to put them in a single code map.
881+ var func = this . codeMap_ . findDynamicEntryByStartAddress ( funcAddr ) ;
882+ if ( ! func ) {
883+ var func = new CodeMap . CodeEntry ( 0 , name , 'SFI' ) ;
884+ this . codeMap_ . addCode ( funcAddr , func ) ;
885+
886+ func . funcId = this . functionEntries_ . length ;
887+ this . functionEntries_ . push ( { name : name , codes : [ ] } ) ;
888+ } else if ( func . name !== name ) {
889+ // Function object has been overwritten with a new one.
890+ func . name = name ;
891+
892+ func . funcId = this . functionEntries_ . length ;
893+ this . functionEntries_ . push ( { name : name , codes : [ ] } ) ;
894+ }
895+ // TODO(jarin): Insert the code object into the SFI's code list.
896+ var entry = this . codeMap_ . findDynamicEntryByStartAddress ( start ) ;
897+ if ( entry ) {
898+ // TODO(jarin) This does not look correct, we should really
899+ // update the code object (remove the old one and insert this one).
900+ if ( entry . size === size && entry . func === func ) {
901+ // Entry state has changed.
902+ entry . state = state ;
903+ }
904+ } else {
905+ var entry = new CodeMap . CodeEntry ( size , name , 'JS' ) ;
906+ this . codeMap_ . addCode ( start , entry ) ;
907+
908+ entry . codeId = this . codeEntries_ . length ;
909+
910+ this . functionEntries_ [ func . funcId ] . codes . push ( entry . codeId ) ;
911+
912+ if ( state === 0 ) {
913+ kind = "Builtin" ;
914+ } else if ( state === 1 ) {
915+ kind = "Unopt" ;
916+ } else if ( state === 2 ) {
917+ kind = "Opt" ;
918+ }
919+
920+ this . codeEntries_ . push ( {
921+ name : entry . name ,
922+ type : entry . type ,
923+ kind : kind ,
924+ func : func . funcId
925+ } ) ;
926+ }
927+ return entry ;
928+ } ;
929+
930+ JsonProfile . prototype . moveCode = function ( from , to ) {
931+ try {
932+ this . codeMap_ . moveCode ( from , to ) ;
933+ } catch ( e ) {
934+ printErr ( "Move: unknown source " + from ) ;
935+ }
936+ } ;
937+
938+ JsonProfile . prototype . deleteCode = function ( start ) {
939+ try {
940+ this . codeMap_ . deleteCode ( start ) ;
941+ } catch ( e ) {
942+ printErr ( "Delete: unknown address " + start ) ;
943+ }
944+ } ;
945+
946+ JsonProfile . prototype . moveFunc = function ( from , to ) {
947+ if ( this . codeMap_ . findDynamicEntryByStartAddress ( from ) ) {
948+ this . codeMap_ . moveCode ( from , to ) ;
949+ }
950+ } ;
951+
952+ JsonProfile . prototype . findEntry = function ( addr ) {
953+ return this . codeMap_ . findEntry ( addr ) ;
954+ } ;
955+
956+ JsonProfile . prototype . recordTick = function ( time_ns , vmState , stack ) {
957+ // TODO(jarin) Resolve the frame-less case (when top of stack is
958+ // known code).
959+ var processedStack = [ ] ;
960+ for ( var i = 0 ; i < stack . length ; i ++ ) {
961+ var resolved = this . codeMap_ . findAddress ( stack [ i ] ) ;
962+ if ( resolved ) {
963+ processedStack . push ( resolved . entry . codeId , resolved . offset ) ;
964+ } else {
965+ processedStack . push ( - 1 , stack [ i ] ) ;
966+ }
967+ }
968+ this . ticks_ . push ( { tm : time_ns , vm : vmState , s : processedStack } ) ;
969+ } ;
970+
971+ JsonProfile . prototype . writeJson = function ( ) {
972+ var toplevel = {
973+ code : this . codeEntries_ ,
974+ functions : this . functionEntries_ ,
975+ ticks : this . ticks_
976+ } ;
977+ write ( JSON . stringify ( toplevel ) ) ;
978+ } ;
0 commit comments