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 5function 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 */ 12function 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 */ 24function 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 34function 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} 86inherits(IcProcessor, LogReader); 87 88/** 89 * @override 90 */ 91IcProcessor.prototype.printError = function(str) { 92 print(str); 93}; 94 95 96IcProcessor.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 115IcProcessor.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 128IcProcessor.prototype.processCodeMove = function(from, to) { 129 this.profile_.moveCode(from, to); 130}; 131 132 133IcProcessor.prototype.processCodeDelete = function(start) { 134 this.profile_.deleteCode(start); 135}; 136 137 138IcProcessor.prototype.processFunctionMove = function(from, to) { 139 this.profile_.moveFunc(from, to); 140}; 141 142IcProcessor.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 151IcProcessor.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 161IcProcessor.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 172IcProcessor.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 180IcProcessor.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 188IcProcessor.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 195function 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 208function 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 221ArgumentsProcessor.DEFAULTS = { 222 logFileName: 'v8.log', 223 range: 'auto,auto', 224}; 225 226 227ArgumentsProcessor.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 251ArgumentsProcessor.prototype.result = function() { 252 return this.result_; 253}; 254 255 256ArgumentsProcessor.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