1<!DOCTYPE html> 2<!-- 3Copyright (c) 2012 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found in the LICENSE file. 6--> 7<link rel="import" href="/tracing/base/base.html"> 8<script> 9'use strict'; 10 11/** 12 * @fileoverview Log Reader is used to process log file produced by V8. 13 */ 14tr.exportTo('tr.e.importer.v8', function() { 15 /** 16 * Creates a CSV lines parser. 17 */ 18 function CsvParser() { }; 19 20 /** 21 * A regex for matching a CSV field. 22 * @private 23 */ 24 CsvParser.CSV_FIELD_RE_ = /^"((?:[^"]|"")*)"|([^,]*)/; 25 26 /** 27 * A regex for matching a double quote. 28 * @private 29 */ 30 CsvParser.DOUBLE_QUOTE_RE_ = /""/g; 31 32 /** 33 * Parses a line of CSV-encoded values. Returns an array of fields. 34 * 35 * @param {string} line Input line. 36 */ 37 CsvParser.prototype.parseLine = function(line) { 38 var fieldRe = CsvParser.CSV_FIELD_RE_; 39 var doubleQuoteRe = CsvParser.DOUBLE_QUOTE_RE_; 40 var pos = 0; 41 var endPos = line.length; 42 var fields = []; 43 if (endPos > 0) { 44 do { 45 var fieldMatch = fieldRe.exec(line.substr(pos)); 46 if (typeof fieldMatch[1] === 'string') { 47 var field = fieldMatch[1]; 48 pos += field.length + 3; // Skip comma and quotes. 49 fields.push(field.replace(doubleQuoteRe, '"')); 50 } else { 51 // The second field pattern will match anything, thus 52 // in the worst case the match will be an empty string. 53 var field = fieldMatch[2]; 54 pos += field.length + 1; // Skip comma. 55 fields.push(field); 56 } 57 } while (pos <= endPos); 58 } 59 return fields; 60 }; 61 62 /** 63 * Base class for processing log files. 64 * 65 * @param {Array.<Object>} dispatchTable A table used for parsing and 66 * processing log records. 67 * 68 * @constructor 69 */ 70 function LogReader(dispatchTable) { 71 /** 72 * @type {Array.<Object>} 73 */ 74 this.dispatchTable_ = dispatchTable; 75 76 /** 77 * Current line. 78 * @type {number} 79 */ 80 this.lineNum_ = 0; 81 82 /** 83 * CSV lines parser. 84 * @type {CsvParser} 85 */ 86 this.csvParser_ = new CsvParser(); 87 }; 88 89 /** 90 * Used for printing error messages. 91 * 92 * @param {string} str Error message. 93 */ 94 LogReader.prototype.printError = function(str) { 95 // Do nothing. 96 }; 97 98 /** 99 * Processes a portion of V8 profiler event log. 100 * 101 * @param {string} chunk A portion of log. 102 */ 103 LogReader.prototype.processLogChunk = function(chunk) { 104 this.processLog_(chunk.split('\n')); 105 }; 106 107 /** 108 * Processes a line of V8 profiler event log. 109 * 110 * @param {string} line A line of log. 111 */ 112 LogReader.prototype.processLogLine = function(line) { 113 this.processLog_([line]); 114 }; 115 116 /** 117 * Processes stack record. 118 * 119 * @param {number} pc Program counter. 120 * @param {number} func JS Function. 121 * @param {Array.<string>} stack String representation of a stack. 122 * @return {Array.<number>} Processed stack. 123 */ 124 LogReader.prototype.processStack = function(pc, func, stack) { 125 var fullStack = func ? [pc, func] : [pc]; 126 var prevFrame = pc; 127 for (var i = 0, n = stack.length; i < n; ++i) { 128 var frame = stack[i]; 129 var firstChar = frame.charAt(0); 130 if (firstChar == '+' || firstChar == '-') { 131 // An offset from the previous frame. 132 prevFrame += parseInt(frame, 16); 133 fullStack.push(prevFrame); 134 // Filter out possible 'overflow' string. 135 } else if (firstChar != 'o') { 136 fullStack.push(parseInt(frame, 16)); 137 } 138 } 139 return fullStack; 140 }; 141 142 /** 143 * Returns whether a particular dispatch must be skipped. 144 * 145 * @param {!Object} dispatch Dispatch record. 146 * @return {boolean} True if dispatch must be skipped. 147 */ 148 LogReader.prototype.skipDispatch = function(dispatch) { 149 return false; 150 }; 151 152 /** 153 * Does a dispatch of a log record. 154 * 155 * @param {Array.<string>} fields Log record. 156 * @private 157 */ 158 LogReader.prototype.dispatchLogRow_ = function(fields) { 159 // Obtain the dispatch. 160 var command = fields[0]; 161 if (!(command in this.dispatchTable_)) return; 162 163 var dispatch = this.dispatchTable_[command]; 164 165 if (dispatch === null || this.skipDispatch(dispatch)) { 166 return; 167 } 168 169 // Parse fields. 170 var parsedFields = []; 171 for (var i = 0; i < dispatch.parsers.length; ++i) { 172 var parser = dispatch.parsers[i]; 173 if (parser === null) { 174 parsedFields.push(fields[1 + i]); 175 } else if (typeof parser == 'function') { 176 parsedFields.push(parser(fields[1 + i])); 177 } else { 178 // var-args 179 parsedFields.push(fields.slice(1 + i)); 180 break; 181 } 182 } 183 184 // Run the processor. 185 dispatch.processor.apply(this, parsedFields); 186 }; 187 188 /** 189 * Processes log lines. 190 * 191 * @param {Array.<string>} lines Log lines. 192 * @private 193 */ 194 LogReader.prototype.processLog_ = function(lines) { 195 for (var i = 0, n = lines.length; i < n; ++i, ++this.lineNum_) { 196 var line = lines[i]; 197 if (!line) { 198 continue; 199 } 200 try { 201 var fields = this.csvParser_.parseLine(line); 202 this.dispatchLogRow_(fields); 203 } catch (e) { 204 this.printError('line ' + (this.lineNum_ + 1) + ': ' + 205 (e.message || e)); 206 } 207 } 208 }; 209 return { 210 LogReader: LogReader 211 }; 212}); 213</script> 214