Home | History | Annotate | Download | only in tools
      1 // Copyright 2017 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 function inherits(childCtor, parentCtor) {
      6   childCtor.prototype.__proto__ = parentCtor.prototype;
      7 };
      8 
      9 /**
     10  * A thin wrapper around shell's 'read' function showing a file name on error.
     11  */
     12 function readFile(fileName) {
     13   try {
     14     return read(fileName);
     15   } catch (e) {
     16     print(fileName + ': ' + (e.message || e));
     17     throw e;
     18   }
     19 }
     20 
     21 /**
     22  * Parser for dynamic code optimization state.
     23  */
     24 function parseState(s) {
     25   switch (s) {
     26   case "": return Profile.CodeState.COMPILED;
     27   case "~": return Profile.CodeState.OPTIMIZABLE;
     28   case "*": return Profile.CodeState.OPTIMIZED;
     29   }
     30   throw new Error("unknown code state: " + s);
     31 }
     32 
     33 
     34 function IcProcessor() {
     35   var propertyICParser = [parseInt, parseInt, parseInt, null, null, parseInt,
     36                           null, null, null];
     37   LogReader.call(this, {
     38       'code-creation': {
     39           parsers: [null, parseInt, parseInt, parseInt, null, 'var-args'],
     40           processor: this.processCodeCreation },
     41       'code-move': { parsers: [parseInt, parseInt],
     42           processor: this.processCodeMove },
     43       'code-delete': { parsers: [parseInt],
     44           processor: this.processCodeDelete },
     45       'sfi-move': { parsers: [parseInt, parseInt],
     46           processor: this.processFunctionMove },
     47       'LoadIC': {
     48         parsers : propertyICParser,
     49         processor: this.processPropertyIC.bind(this, "LoadIC") },
     50       'StoreIC': {
     51         parsers : propertyICParser,
     52         processor: this.processPropertyIC.bind(this, "StoreIC") },
     53       'KeyedLoadIC': {
     54         parsers : propertyICParser,
     55         processor: this.processPropertyIC.bind(this, "KeyedLoadIC") },
     56       'KeyedStoreIC': {
     57         parsers : propertyICParser,
     58         processor: this.processPropertyIC.bind(this, "KeyedStoreIC") },
     59       'CompareIC': {
     60         parsers : [parseInt, parseInt, parseInt, parseInt, null, null, null,
     61                    null, null, null, null],
     62         processor: this.processCompareIC },
     63       'BinaryOpIC': {
     64         parsers : [parseInt, parseInt, parseInt, parseInt, null, null,
     65                    parseInt],
     66         processor: this.processBinaryOpIC },
     67       'ToBooleanIC': {
     68         parsers : [parseInt, parseInt, parseInt, parseInt, null, null],
     69         processor: this.processToBooleanIC },
     70       'PatchIC': {
     71         parsers : [parseInt, parseInt, parseInt],
     72         processor: this.processPatchIC },
     73       });
     74   this.deserializedEntriesNames_ = [];
     75   this.profile_ = new Profile();
     76 
     77   this.LoadIC = 0;
     78   this.StoreIC = 0;
     79   this.KeyedLoadIC = 0;
     80   this.KeyedStoreIC = 0;
     81   this.CompareIC = 0;
     82   this.BinaryOpIC = 0;
     83   this.ToBooleanIC = 0;
     84   this.PatchIC = 0;
     85 }
     86 inherits(IcProcessor, LogReader);
     87 
     88 /**
     89  * @override
     90  */
     91 IcProcessor.prototype.printError = function(str) {
     92   print(str);
     93 };
     94 
     95 
     96 IcProcessor.prototype.processLogFile = function(fileName) {
     97   this.lastLogFileName_ = fileName;
     98   var line;
     99   while (line = readline()) {
    100     this.processLogLine(line);
    101   }
    102   print();
    103   print("=====================");
    104   print("Load: " + this.LoadIC);
    105   print("Store: " + this.StoreIC);
    106   print("KeyedLoad: " + this.KeyedLoadIC);
    107   print("KeyedStore: " + this.KeyedStoreIC);
    108   print("CompareIC: " + this.CompareIC);
    109   print("BinaryOpIC: " + this.BinaryOpIC);
    110   print("ToBooleanIC: " + this.ToBooleanIC);
    111   print("PatchIC: " + this.PatchIC);
    112 };
    113 
    114 
    115 IcProcessor.prototype.processCodeCreation = function(
    116     type, kind, start, size, name, maybe_func) {
    117   name = this.deserializedEntriesNames_[start] || name;
    118   if (maybe_func.length) {
    119     var funcAddr = parseInt(maybe_func[0]);
    120     var state = parseState(maybe_func[1]);
    121     this.profile_.addFuncCode(type, name, start, size, funcAddr, state);
    122   } else {
    123     this.profile_.addCode(type, name, start, size);
    124   }
    125 };
    126 
    127 
    128 IcProcessor.prototype.processCodeMove = function(from, to) {
    129   this.profile_.moveCode(from, to);
    130 };
    131 
    132 
    133 IcProcessor.prototype.processCodeDelete = function(start) {
    134   this.profile_.deleteCode(start);
    135 };
    136 
    137 
    138 IcProcessor.prototype.processFunctionMove = function(from, to) {
    139   this.profile_.moveFunc(from, to);
    140 };
    141 
    142 IcProcessor.prototype.formatName = function(entry) {
    143   if (!entry) return "<unknown>"
    144   var name = entry.func.getName();
    145   var re = /(.*):[0-9]+:[0-9]+$/;
    146   var array = re.exec(name);
    147   if (!array) return name;
    148   return array[1];
    149 }
    150 
    151 IcProcessor.prototype.processPropertyIC = function (
    152     type, pc, line, column, old_state, new_state, map, name, modifier,
    153     slow_reason) {
    154   this[type]++;
    155   var entry = this.profile_.findEntry(pc);
    156   print(type + " (" + old_state + "->" + new_state + modifier + ") at " +
    157         this.formatName(entry) + ":" + line + ":" + column + " " + name +
    158         " (map 0x" + map.toString(16) + ")");
    159 }
    160 
    161 IcProcessor.prototype.processCompareIC = function (
    162     pc, line, column, stub, op, old_left, old_right, old_state, new_left,
    163     new_right, new_state) {
    164   var entry = this.profile_.findEntry(pc);
    165   this.CompareIC++;
    166   print("CompareIC[" + op + "] ((" +
    167         old_left + "+" + old_right + "=" + old_state + ")->(" +
    168         new_left + "+" + new_right + "=" + new_state + ")) at " +
    169         this.formatName(entry) + ":" + line + ":" + column);
    170 }
    171 
    172 IcProcessor.prototype.processBinaryOpIC = function (
    173     pc, line, column, stub, old_state, new_state, allocation_site) {
    174   var entry = this.profile_.findEntry(pc);
    175   this.BinaryOpIC++;
    176   print("BinaryOpIC (" + old_state + "->" + new_state + ") at " +
    177         this.formatName(entry) + ":" + line + ":" + column);
    178 }
    179 
    180 IcProcessor.prototype.processToBooleanIC = function (
    181     pc, line, column, stub, old_state, new_state) {
    182   var entry = this.profile_.findEntry(pc);
    183   this.ToBooleanIC++;
    184   print("ToBooleanIC (" + old_state + "->" + new_state + ") at " +
    185         this.formatName(entry) + ":" + line + ":" + column);
    186 }
    187 
    188 IcProcessor.prototype.processPatchIC = function (pc, test, delta) {
    189   var entry = this.profile_.findEntry(pc);
    190   this.PatchIC++;
    191   print("PatchIC (0x" + test.toString(16) + ", " + delta + ") at " +
    192         this.formatName(entry));
    193 }
    194 
    195 function padLeft(s, len) {
    196   s = s.toString();
    197   if (s.length < len) {
    198     var padLength = len - s.length;
    199     if (!(padLength in padLeft)) {
    200       padLeft[padLength] = new Array(padLength + 1).join(' ');
    201     }
    202     s = padLeft[padLength] + s;
    203   }
    204   return s;
    205 };
    206 
    207 
    208 function ArgumentsProcessor(args) {
    209   this.args_ = args;
    210   this.result_ = ArgumentsProcessor.DEFAULTS;
    211 
    212   this.argsDispatch_ = {
    213     '--range': ['range', 'auto,auto',
    214         'Specify the range limit as [start],[end]'],
    215     '--source-map': ['sourceMap', null,
    216         'Specify the source map that should be used for output']
    217   };
    218 };
    219 
    220 
    221 ArgumentsProcessor.DEFAULTS = {
    222   logFileName: 'v8.log',
    223   range: 'auto,auto',
    224 };
    225 
    226 
    227 ArgumentsProcessor.prototype.parse = function() {
    228   while (this.args_.length) {
    229     var arg = this.args_.shift();
    230     if (arg.charAt(0) != '-') {
    231       this.result_.logFileName = arg;
    232       continue;
    233     }
    234     var userValue = null;
    235     var eqPos = arg.indexOf('=');
    236     if (eqPos != -1) {
    237       userValue = arg.substr(eqPos + 1);
    238       arg = arg.substr(0, eqPos);
    239     }
    240     if (arg in this.argsDispatch_) {
    241       var dispatch = this.argsDispatch_[arg];
    242       this.result_[dispatch[0]] = userValue == null ? dispatch[1] : userValue;
    243     } else {
    244       return false;
    245     }
    246   }
    247   return true;
    248 };
    249 
    250 
    251 ArgumentsProcessor.prototype.result = function() {
    252   return this.result_;
    253 };
    254 
    255 
    256 ArgumentsProcessor.prototype.printUsageAndExit = function() {
    257 
    258   function padRight(s, len) {
    259     s = s.toString();
    260     if (s.length < len) {
    261       s = s + (new Array(len - s.length + 1).join(' '));
    262     }
    263     return s;
    264   }
    265 
    266   print('Cmdline args: [options] [log-file-name]\n' +
    267         'Default log file name is "' +
    268         ArgumentsProcessor.DEFAULTS.logFileName + '".\n');
    269   print('Options:');
    270   for (var arg in this.argsDispatch_) {
    271     var synonyms = [arg];
    272     var dispatch = this.argsDispatch_[arg];
    273     for (var synArg in this.argsDispatch_) {
    274       if (arg !== synArg && dispatch === this.argsDispatch_[synArg]) {
    275         synonyms.push(synArg);
    276         delete this.argsDispatch_[synArg];
    277       }
    278     }
    279     print('  ' + padRight(synonyms.join(', '), 20) + " " + dispatch[2]);
    280   }
    281   quit(2);
    282 };
    283