1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28/** 29 * @fileoverview Log Reader is used to process log file produced by V8. 30 */ 31 32 33/** 34 * Base class for processing log files. 35 * 36 * @param {Array.<Object>} dispatchTable A table used for parsing and processing 37 * log records. 38 * @constructor 39 */ 40function LogReader(dispatchTable) { 41 /** 42 * @type {Array.<Object>} 43 */ 44 this.dispatchTable_ = dispatchTable; 45 46 /** 47 * Current line. 48 * @type {number} 49 */ 50 this.lineNum_ = 0; 51 52 /** 53 * CSV lines parser. 54 * @type {CsvParser} 55 */ 56 this.csvParser_ = new CsvParser(); 57}; 58 59 60/** 61 * Used for printing error messages. 62 * 63 * @param {string} str Error message. 64 */ 65LogReader.prototype.printError = function(str) { 66 // Do nothing. 67}; 68 69 70/** 71 * Processes a portion of V8 profiler event log. 72 * 73 * @param {string} chunk A portion of log. 74 */ 75LogReader.prototype.processLogChunk = function(chunk) { 76 this.processLog_(chunk.split('\n')); 77}; 78 79 80/** 81 * Processes a line of V8 profiler event log. 82 * 83 * @param {string} line A line of log. 84 */ 85LogReader.prototype.processLogLine = function(line) { 86 this.processLog_([line]); 87}; 88 89 90/** 91 * Processes stack record. 92 * 93 * @param {number} pc Program counter. 94 * @param {number} func JS Function. 95 * @param {Array.<string>} stack String representation of a stack. 96 * @return {Array.<number>} Processed stack. 97 */ 98LogReader.prototype.processStack = function(pc, func, stack) { 99 var fullStack = func ? [pc, func] : [pc]; 100 var prevFrame = pc; 101 for (var i = 0, n = stack.length; i < n; ++i) { 102 var frame = stack[i]; 103 var firstChar = frame.charAt(0); 104 if (firstChar == '+' || firstChar == '-') { 105 // An offset from the previous frame. 106 prevFrame += parseInt(frame, 16); 107 fullStack.push(prevFrame); 108 // Filter out possible 'overflow' string. 109 } else if (firstChar != 'o') { 110 fullStack.push(parseInt(frame, 16)); 111 } 112 } 113 return fullStack; 114}; 115 116 117/** 118 * Returns whether a particular dispatch must be skipped. 119 * 120 * @param {!Object} dispatch Dispatch record. 121 * @return {boolean} True if dispatch must be skipped. 122 */ 123LogReader.prototype.skipDispatch = function(dispatch) { 124 return false; 125}; 126 127 128/** 129 * Does a dispatch of a log record. 130 * 131 * @param {Array.<string>} fields Log record. 132 * @private 133 */ 134LogReader.prototype.dispatchLogRow_ = function(fields) { 135 // Obtain the dispatch. 136 var command = fields[0]; 137 if (!(command in this.dispatchTable_)) return; 138 139 var dispatch = this.dispatchTable_[command]; 140 141 if (dispatch === null || this.skipDispatch(dispatch)) { 142 return; 143 } 144 145 // Parse fields. 146 var parsedFields = []; 147 for (var i = 0; i < dispatch.parsers.length; ++i) { 148 var parser = dispatch.parsers[i]; 149 if (parser === null) { 150 parsedFields.push(fields[1 + i]); 151 } else if (typeof parser == 'function') { 152 parsedFields.push(parser(fields[1 + i])); 153 } else { 154 // var-args 155 parsedFields.push(fields.slice(1 + i)); 156 break; 157 } 158 } 159 160 // Run the processor. 161 dispatch.processor.apply(this, parsedFields); 162}; 163 164 165/** 166 * Processes log lines. 167 * 168 * @param {Array.<string>} lines Log lines. 169 * @private 170 */ 171LogReader.prototype.processLog_ = function(lines) { 172 for (var i = 0, n = lines.length; i < n; ++i, ++this.lineNum_) { 173 var line = lines[i]; 174 if (!line) { 175 continue; 176 } 177 try { 178 var fields = this.csvParser_.parseLine(line); 179 this.dispatchLogRow_(fields); 180 } catch (e) { 181 this.printError('line ' + (this.lineNum_ + 1) + ': ' + (e.message || e)); 182 } 183 } 184}; 185