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 */ 40 function 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 */ 65 LogReader.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 */ 75 LogReader.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 */ 85 LogReader.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 */ 98 LogReader.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 */ 123 LogReader.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 */ 134 LogReader.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 */ 171 LogReader.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