2017-02-20 09:20:42 +00:00
|
|
|
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
function inherits(childCtor, parentCtor) {
|
|
|
|
childCtor.prototype.__proto__ = parentCtor.prototype;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A thin wrapper around shell's 'read' function showing a file name on error.
|
|
|
|
*/
|
|
|
|
function readFile(fileName) {
|
|
|
|
try {
|
|
|
|
return read(fileName);
|
|
|
|
} catch (e) {
|
|
|
|
print(fileName + ': ' + (e.message || e));
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parser for dynamic code optimization state.
|
|
|
|
*/
|
|
|
|
function parseState(s) {
|
|
|
|
switch (s) {
|
|
|
|
case "": return Profile.CodeState.COMPILED;
|
|
|
|
case "~": return Profile.CodeState.OPTIMIZABLE;
|
|
|
|
case "*": return Profile.CodeState.OPTIMIZED;
|
|
|
|
}
|
|
|
|
throw new Error("unknown code state: " + s);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function IcProcessor() {
|
|
|
|
var propertyICParser = [parseInt, parseInt, parseInt, null, null, parseInt,
|
|
|
|
null, null, null];
|
|
|
|
LogReader.call(this, {
|
|
|
|
'code-creation': {
|
2017-04-11 14:39:25 +00:00
|
|
|
parsers: [null, parseInt, parseInt, parseInt, parseInt, null, 'var-args'],
|
2017-02-20 09:20:42 +00:00
|
|
|
processor: this.processCodeCreation },
|
|
|
|
'code-move': { parsers: [parseInt, parseInt],
|
|
|
|
processor: this.processCodeMove },
|
|
|
|
'code-delete': { parsers: [parseInt],
|
|
|
|
processor: this.processCodeDelete },
|
|
|
|
'sfi-move': { parsers: [parseInt, parseInt],
|
|
|
|
processor: this.processFunctionMove },
|
|
|
|
'LoadIC': {
|
|
|
|
parsers : propertyICParser,
|
|
|
|
processor: this.processPropertyIC.bind(this, "LoadIC") },
|
|
|
|
'StoreIC': {
|
|
|
|
parsers : propertyICParser,
|
|
|
|
processor: this.processPropertyIC.bind(this, "StoreIC") },
|
|
|
|
'KeyedLoadIC': {
|
|
|
|
parsers : propertyICParser,
|
|
|
|
processor: this.processPropertyIC.bind(this, "KeyedLoadIC") },
|
|
|
|
'KeyedStoreIC': {
|
|
|
|
parsers : propertyICParser,
|
|
|
|
processor: this.processPropertyIC.bind(this, "KeyedStoreIC") },
|
|
|
|
'CompareIC': {
|
|
|
|
parsers : [parseInt, parseInt, parseInt, parseInt, null, null, null,
|
|
|
|
null, null, null, null],
|
|
|
|
processor: this.processCompareIC },
|
|
|
|
'PatchIC': {
|
|
|
|
parsers : [parseInt, parseInt, parseInt],
|
|
|
|
processor: this.processPatchIC },
|
|
|
|
});
|
|
|
|
this.deserializedEntriesNames_ = [];
|
|
|
|
this.profile_ = new Profile();
|
|
|
|
|
|
|
|
this.LoadIC = 0;
|
|
|
|
this.StoreIC = 0;
|
|
|
|
this.KeyedLoadIC = 0;
|
|
|
|
this.KeyedStoreIC = 0;
|
|
|
|
this.CompareIC = 0;
|
|
|
|
this.PatchIC = 0;
|
|
|
|
}
|
|
|
|
inherits(IcProcessor, LogReader);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @override
|
|
|
|
*/
|
|
|
|
IcProcessor.prototype.printError = function(str) {
|
|
|
|
print(str);
|
|
|
|
};
|
|
|
|
|
2017-04-11 14:39:25 +00:00
|
|
|
IcProcessor.prototype.processString = function(string) {
|
|
|
|
var end = string.length;
|
|
|
|
var current = 0;
|
|
|
|
var next = 0;
|
|
|
|
var line;
|
|
|
|
var i = 0;
|
|
|
|
var entry;
|
|
|
|
while (current < end) {
|
|
|
|
next = string.indexOf("\n", current);
|
|
|
|
if (next === -1) break;
|
|
|
|
i++;
|
|
|
|
line = string.substring(current, next);
|
|
|
|
current = next + 1;
|
|
|
|
this.processLogLine(line);
|
|
|
|
}
|
|
|
|
}
|
2017-02-20 09:20:42 +00:00
|
|
|
|
|
|
|
IcProcessor.prototype.processLogFile = function(fileName) {
|
2017-04-11 14:39:25 +00:00
|
|
|
this.collectEntries = true
|
2017-02-20 09:20:42 +00:00
|
|
|
this.lastLogFileName_ = fileName;
|
|
|
|
var line;
|
|
|
|
while (line = readline()) {
|
|
|
|
this.processLogLine(line);
|
|
|
|
}
|
|
|
|
print();
|
|
|
|
print("=====================");
|
|
|
|
print("Load: " + this.LoadIC);
|
|
|
|
print("Store: " + this.StoreIC);
|
|
|
|
print("KeyedLoad: " + this.KeyedLoadIC);
|
|
|
|
print("KeyedStore: " + this.KeyedStoreIC);
|
|
|
|
print("CompareIC: " + this.CompareIC);
|
|
|
|
print("PatchIC: " + this.PatchIC);
|
|
|
|
};
|
|
|
|
|
2017-04-11 14:39:25 +00:00
|
|
|
IcProcessor.prototype.addEntry = function(entry) {
|
|
|
|
this.entries.push(entry);
|
|
|
|
}
|
2017-02-20 09:20:42 +00:00
|
|
|
|
|
|
|
IcProcessor.prototype.processCodeCreation = function(
|
2017-04-11 14:39:25 +00:00
|
|
|
type, kind, timestamp, start, size, name, maybe_func) {
|
2017-02-20 09:20:42 +00:00
|
|
|
name = this.deserializedEntriesNames_[start] || name;
|
2017-04-11 14:39:25 +00:00
|
|
|
if (name.startsWith("onComplete")) {
|
|
|
|
console.log(name);
|
|
|
|
}
|
2017-02-20 09:20:42 +00:00
|
|
|
if (maybe_func.length) {
|
|
|
|
var funcAddr = parseInt(maybe_func[0]);
|
|
|
|
var state = parseState(maybe_func[1]);
|
2017-04-11 14:39:25 +00:00
|
|
|
this.profile_.addFuncCode(type, name, timestamp, start, size, funcAddr, state);
|
2017-02-20 09:20:42 +00:00
|
|
|
} else {
|
2017-04-11 14:39:25 +00:00
|
|
|
this.profile_.addCode(type, name, timestamp, start, size);
|
2017-02-20 09:20:42 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
IcProcessor.prototype.processCodeMove = function(from, to) {
|
|
|
|
this.profile_.moveCode(from, to);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
IcProcessor.prototype.processCodeDelete = function(start) {
|
|
|
|
this.profile_.deleteCode(start);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
IcProcessor.prototype.processFunctionMove = function(from, to) {
|
|
|
|
this.profile_.moveFunc(from, to);
|
|
|
|
};
|
|
|
|
|
|
|
|
IcProcessor.prototype.formatName = function(entry) {
|
|
|
|
if (!entry) return "<unknown>"
|
|
|
|
var name = entry.func.getName();
|
|
|
|
var re = /(.*):[0-9]+:[0-9]+$/;
|
|
|
|
var array = re.exec(name);
|
|
|
|
if (!array) return name;
|
2017-04-25 12:01:18 +00:00
|
|
|
return entry.getState() + array[1];
|
2017-02-20 09:20:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
IcProcessor.prototype.processPropertyIC = function (
|
|
|
|
type, pc, line, column, old_state, new_state, map, name, modifier,
|
|
|
|
slow_reason) {
|
|
|
|
this[type]++;
|
|
|
|
var entry = this.profile_.findEntry(pc);
|
|
|
|
print(type + " (" + old_state + "->" + new_state + modifier + ") at " +
|
|
|
|
this.formatName(entry) + ":" + line + ":" + column + " " + name +
|
|
|
|
" (map 0x" + map.toString(16) + ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
IcProcessor.prototype.processCompareIC = function (
|
|
|
|
pc, line, column, stub, op, old_left, old_right, old_state, new_left,
|
|
|
|
new_right, new_state) {
|
|
|
|
var entry = this.profile_.findEntry(pc);
|
|
|
|
this.CompareIC++;
|
|
|
|
print("CompareIC[" + op + "] ((" +
|
|
|
|
old_left + "+" + old_right + "=" + old_state + ")->(" +
|
|
|
|
new_left + "+" + new_right + "=" + new_state + ")) at " +
|
|
|
|
this.formatName(entry) + ":" + line + ":" + column);
|
|
|
|
}
|
|
|
|
|
|
|
|
IcProcessor.prototype.processPatchIC = function (pc, test, delta) {
|
|
|
|
var entry = this.profile_.findEntry(pc);
|
|
|
|
this.PatchIC++;
|
|
|
|
print("PatchIC (0x" + test.toString(16) + ", " + delta + ") at " +
|
|
|
|
this.formatName(entry));
|
|
|
|
}
|
|
|
|
|
|
|
|
function padLeft(s, len) {
|
|
|
|
s = s.toString();
|
|
|
|
if (s.length < len) {
|
|
|
|
var padLength = len - s.length;
|
|
|
|
if (!(padLength in padLeft)) {
|
|
|
|
padLeft[padLength] = new Array(padLength + 1).join(' ');
|
|
|
|
}
|
|
|
|
s = padLeft[padLength] + s;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
function ArgumentsProcessor(args) {
|
|
|
|
this.args_ = args;
|
|
|
|
this.result_ = ArgumentsProcessor.DEFAULTS;
|
|
|
|
|
|
|
|
this.argsDispatch_ = {
|
|
|
|
'--range': ['range', 'auto,auto',
|
|
|
|
'Specify the range limit as [start],[end]'],
|
|
|
|
'--source-map': ['sourceMap', null,
|
|
|
|
'Specify the source map that should be used for output']
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
ArgumentsProcessor.DEFAULTS = {
|
|
|
|
logFileName: 'v8.log',
|
|
|
|
range: 'auto,auto',
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
ArgumentsProcessor.prototype.parse = function() {
|
|
|
|
while (this.args_.length) {
|
|
|
|
var arg = this.args_.shift();
|
|
|
|
if (arg.charAt(0) != '-') {
|
|
|
|
this.result_.logFileName = arg;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
var userValue = null;
|
|
|
|
var eqPos = arg.indexOf('=');
|
|
|
|
if (eqPos != -1) {
|
|
|
|
userValue = arg.substr(eqPos + 1);
|
|
|
|
arg = arg.substr(0, eqPos);
|
|
|
|
}
|
|
|
|
if (arg in this.argsDispatch_) {
|
|
|
|
var dispatch = this.argsDispatch_[arg];
|
|
|
|
this.result_[dispatch[0]] = userValue == null ? dispatch[1] : userValue;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
ArgumentsProcessor.prototype.result = function() {
|
|
|
|
return this.result_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
ArgumentsProcessor.prototype.printUsageAndExit = function() {
|
|
|
|
|
|
|
|
function padRight(s, len) {
|
|
|
|
s = s.toString();
|
|
|
|
if (s.length < len) {
|
|
|
|
s = s + (new Array(len - s.length + 1).join(' '));
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
print('Cmdline args: [options] [log-file-name]\n' +
|
|
|
|
'Default log file name is "' +
|
|
|
|
ArgumentsProcessor.DEFAULTS.logFileName + '".\n');
|
|
|
|
print('Options:');
|
|
|
|
for (var arg in this.argsDispatch_) {
|
|
|
|
var synonyms = [arg];
|
|
|
|
var dispatch = this.argsDispatch_[arg];
|
|
|
|
for (var synArg in this.argsDispatch_) {
|
|
|
|
if (arg !== synArg && dispatch === this.argsDispatch_[synArg]) {
|
|
|
|
synonyms.push(synArg);
|
|
|
|
delete this.argsDispatch_[synArg];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
print(' ' + padRight(synonyms.join(', '), 20) + " " + dispatch[2]);
|
|
|
|
}
|
|
|
|
quit(2);
|
|
|
|
};
|