• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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