Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 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 var Sodium = (function() { | |
| 29 "use strict"; | |
| 30 | |
| 31 var kinds = ["FUNCTION", "OPTIMIZED_FUNCTION", "STUB", "BUILTIN", | |
| 32 "LOAD_IC", "KEYED_LOAD_IC", "CALL_IC", "KEYED_CALL_IC", | |
| 33 "STORE_IC", "KEYED_STORE_IC", "BINARY_OP_IC", "COMPARE_IC", | |
| 34 "COMPARE_NIL_IC", "TO_BOOLEAN_IC"]; | |
| 35 var kindsWithSource = { | |
| 36 'FUNCTION': true, | |
| 37 'OPTIMIZED_FUNCTION': true | |
| 38 }; | |
| 39 | |
| 40 var addressRegEx = "0x[0-9a-f]{8,16}"; | |
| 41 var nameFinder = new RegExp("^name = (.+)$"); | |
| 42 var kindFinder = new RegExp("^kind = (.+)$"); | |
| 43 var firstPositionFinder = new RegExp("^source_position = (\\d+)$"); | |
| 44 var separatorFilter = new RegExp("^--- (.)+ ---$"); | |
| 45 var rawSourceFilter = new RegExp("^--- Raw source ---$"); | |
| 46 var codeEndFinder = new RegExp("^--- End code ---$"); | |
| 47 var whiteSpaceLineFinder = new RegExp("^\\W*$"); | |
| 48 var instructionBeginFinder = | |
| 49 new RegExp("^Instructions\\W+\\(size = \\d+\\)"); | |
| 50 var instructionFinder = | |
| 51 new RegExp("^\(" + addressRegEx + "\)\(\\W+\\d+\\W+.+\)"); | |
| 52 var positionFinder = | |
| 53 new RegExp("^(" + addressRegEx + ")\\W+position\\W+\\((\\d+)\\)"); | |
| 54 var addressFinder = new RegExp("\(" + addressRegEx + "\)"); | |
| 55 var addressReplacer = new RegExp("\(" + addressRegEx + "\)", "gi"); | |
| 56 | |
| 57 var fileContent = ""; | |
| 58 var selectedFunctionKind = ""; | |
| 59 var currentFunctionKind = ""; | |
| 60 | |
| 61 var currentFunctionName = ""; | |
| 62 var firstSourcePosition = 0; | |
| 63 var startAddress = ""; | |
| 64 var readingSource = false; | |
| 65 var readingAsm = false; | |
| 66 var sourceBegin = -1; | |
| 67 var sourceEnd = -1; | |
| 68 var asmBegin = -1; | |
| 69 var asmEnd = -1; | |
| 70 var codeObjects = []; | |
| 71 var selectedAsm = null; | |
| 72 var selectedSource = null; | |
| 73 var selectedSourceClass = ""; | |
| 74 | |
| 75 function Code(name, kind, sourceBegin, sourceEnd, asmBegin, asmEnd, | |
| 76 firstSourcePosition, startAddress) { | |
| 77 this.name = name; | |
| 78 this.kind = kind; | |
| 79 this.sourceBegin = sourceBegin; | |
| 80 this.sourceEnd = sourceEnd; | |
| 81 this.asmBegin = asmBegin; | |
| 82 this.asmEnd = asmEnd; | |
| 83 this.firstSourcePosition = firstSourcePosition; | |
| 84 this.startAddress = startAddress; | |
| 85 } | |
| 86 | |
| 87 function getCurrentCodeObject() { | |
| 88 var functionSelect = document.getElementById('function-selector-id'); | |
| 89 return functionSelect.options[functionSelect.selectedIndex].codeObject; | |
| 90 } | |
| 91 | |
| 92 function getCurrentSourceText() { | |
| 93 var code = getCurrentCodeObject(); | |
| 94 if (code.sourceBegin == -1 || code.sourceEnd == -1) return ""; | |
| 95 return fileContent.substring(code.sourceBegin, code.sourceEnd); | |
| 96 } | |
| 97 | |
| 98 function getCurrentAsmText() { | |
| 99 var code = getCurrentCodeObject(); | |
| 100 if (code.asmBegin == -1 || code.asmEnd == -1) return ""; | |
| 101 return fileContent.substring(code.asmBegin, code.asmEnd); | |
| 102 } | |
| 103 | |
| 104 function setKindByIndex(index) { | |
| 105 selectedFunctionKind = kinds[index]; | |
| 106 } | |
| 107 | |
| 108 function processLine(text, begin, end) { | |
| 109 var line = text.substring(begin, end); | |
| 110 if (readingSource) { | |
| 111 if (separatorFilter.exec(line) != null) { | |
| 112 readingSource = false; | |
| 113 } else { | |
| 114 if (sourceBegin == -1) { | |
| 115 sourceBegin = begin; | |
| 116 } | |
| 117 sourceEnd = end; | |
| 118 } | |
| 119 } else { | |
| 120 if (readingAsm) { | |
| 121 if (codeEndFinder.exec(line) != null) { | |
| 122 readingAsm = false; | |
| 123 asmEnd = begin; | |
| 124 var newCode = | |
| 125 new Code(currentFunctionName, currentFunctionKind, | |
| 126 sourceBegin, sourceEnd, asmBegin, asmEnd, | |
| 127 firstSourcePosition, startAddress); | |
| 128 codeObjects.push(newCode); | |
| 129 currentFunctionKind = null; | |
| 130 } else { | |
| 131 if (asmBegin == -1) { | |
| 132 matches = instructionBeginFinder.exec(line); | |
| 133 if (matches != null) { | |
| 134 asmBegin = begin; | |
| 135 } | |
| 136 } | |
| 137 if (startAddress == "") { | |
| 138 matches = instructionFinder.exec(line); | |
| 139 if (matches != null) { | |
| 140 startAddress = matches[1]; | |
| 141 } | |
| 142 } | |
| 143 } | |
| 144 } else { | |
| 145 var matches = kindFinder.exec(line); | |
| 146 if (matches != null) { | |
| 147 currentFunctionKind = matches[1]; | |
| 148 if (!kindsWithSource[currentFunctionKind]) { | |
| 149 sourceBegin = -1; | |
| 150 sourceEnd = -1; | |
| 151 } | |
| 152 } else if (currentFunctionKind != null) { | |
| 153 matches = nameFinder.exec(line); | |
| 154 if (matches != null) { | |
| 155 readingAsm = true; | |
| 156 asmBegin = -1; | |
| 157 currentFunctionName = matches[1]; | |
| 158 } | |
| 159 } else if (rawSourceFilter.exec(line) != null) { | |
| 160 readingSource = true; | |
| 161 sourceBegin = -1; | |
| 162 } else { | |
| 163 var matches = firstPositionFinder.exec(line); | |
| 164 if (matches != null) { | |
| 165 firstSourcePosition = parseInt(matches[1]); | |
| 166 } | |
| 167 } | |
| 168 } | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 function processLines(source, size, processLine) { | |
| 173 var firstChar = 0; | |
| 174 for (var x = 0; x < size; x++) { | |
| 175 var curChar = source[x]; | |
| 176 if (curChar == '\n' || curChar == '\r') { | |
| 177 processLine(source, firstChar, x); | |
| 178 firstChar = x + 1; | |
| 179 } | |
| 180 } | |
| 181 if (firstChar != size - 1) { | |
| 182 processLine(source, firstChar, size - 1); | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 function processFileContent() { | |
| 187 var sourceDivElement = document.getElementById('source-text'); | |
| 188 sourceDivElement.innerHTML = "<pre/>"; | |
| 189 sourceBegin = -1; | |
| 190 codeObjects = []; | |
| 191 processLines(fileContent, fileContent.length, processLine); | |
| 192 var functionSelectElement = document.getElementById('function-selector-id'); | |
| 193 functionSelectElement.innerHTML = | |
| 194 "<select id=\"function-selector-id\"></select>"; | |
| 195 var length = codeObjects.length; | |
| 196 for (var i = 0; i < codeObjects.length; ++i) { | |
| 197 var code = codeObjects[i]; | |
| 198 if (code.kind == selectedFunctionKind) { | |
| 199 var optionElement = document.createElement("option"); | |
| 200 optionElement.codeObject = code; | |
| 201 optionElement.text = code.name; | |
| 202 functionSelectElement.add(optionElement, null); | |
| 203 } | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 function asmClick(element) { | |
| 208 if (element == selectedAsm) return; | |
| 209 if (selectedAsm != null) { | |
| 210 selectedAsm.classList.remove('highlight-yellow'); | |
| 211 } | |
| 212 selectedAsm = element; | |
| 213 selectedAsm.classList.add('highlight-yellow'); | |
| 214 | |
| 215 var pc = element.firstChild.innerText; | |
| 216 var sourceLine = null; | |
| 217 if (addressFinder.exec(pc) != null) { | |
| 218 var position = findSourcePosition(pc); | |
| 219 var line = findSourceLine(position); | |
| 220 sourceLine = document.getElementById('source-line-' + line); | |
| 221 var sourceLineTop = sourceLine.offsetTop; | |
| 222 makeSourcePosVisible(sourceLineTop); | |
| 223 } | |
| 224 if (selectedSource == sourceLine) return; | |
| 225 if (selectedSource != null) { | |
| 226 selectedSource.classList.remove('highlight-yellow'); | |
| 227 selectedSource.classList.add(selectedSourceClass); | |
| 228 } | |
| 229 if (sourceLine != null) { | |
| 230 selectedSourceClass = sourceLine.classList[0]; | |
| 231 sourceLine.classList.remove(selectedSourceClass); | |
| 232 sourceLine.classList.add('highlight-yellow'); | |
| 233 } | |
| 234 selectedSource = sourceLine; | |
| 235 } | |
| 236 | |
| 237 function makeContainerPosVisible(container, newTop) { | |
| 238 var height = container.offsetHeight; | |
| 239 var margin = Math.floor(height / 4); | |
| 240 if (newTop < container.scrollTop + margin) { | |
| 241 newTop -= margin; | |
| 242 if (newTop < 0) newTop = 0; | |
| 243 container.scrollTop = newTop; | |
| 244 return; | |
| 245 } | |
| 246 if (newTop > (container.scrollTop + 3 * margin)) { | |
| 247 newTop = newTop - 3 * margin; | |
| 248 container.scrollTop = newTop; | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 function makeAsmPosVisible(newTop) { | |
| 253 var asmContainer = document.getElementById('asm-container'); | |
| 254 makeContainerPosVisible(asmContainer, newTop); | |
| 255 } | |
| 256 | |
| 257 function makeSourcePosVisible(newTop) { | |
| 258 var sourceContainer = document.getElementById('source-container'); | |
| 259 makeContainerPosVisible(sourceContainer, newTop); | |
| 260 } | |
| 261 | |
| 262 function addressClick(element, event) { | |
| 263 event.stopPropagation(); | |
| 264 var asmLineId = 'address-' + element.innerText; | |
| 265 var asmLineElement = document.getElementById(asmLineId); | |
| 266 if (asmLineElement != null) { | |
| 267 var asmLineTop = asmLineElement.parentNode.offsetTop; | |
| 268 makeAsmPosVisible(asmLineTop); | |
| 269 asmLineElement.classList.add('highlight-flash-blue'); | |
| 270 window.setTimeout(function() { | |
| 271 asmLineElement.classList.remove('highlight-flash-blue'); | |
| 272 }, 1500); | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 function prepareAsm(originalSource) { | |
| 277 var newSource = ""; | |
| 278 var lineNumber = 1; | |
| 279 var functionProcessLine = function(text, begin, end) { | |
| 280 var currentLine = text.substring(begin, end); | |
| 281 var matches = instructionFinder.exec(currentLine); | |
| 282 var clickHandler = ""; | |
| 283 if (matches != null) { | |
| 284 var restOfLine = matches[2]; | |
| 285 restOfLine = restOfLine.replace( | |
| 286 addressReplacer, | |
| 287 '<span class="hover-underline" ' + | |
| 288 'onclick="Sodium.addressClick(this, event);">\$1</span>'); | |
| 289 currentLine = '<span id="address-' + matches[1] + '" >' + | |
| 290 matches[1] + '</span>' + restOfLine; | |
| 291 clickHandler = 'onclick=\'Sodium.asmClick(this)\' '; | |
| 292 } else if (whiteSpaceLineFinder.exec(currentLine)) { | |
| 293 currentLine = "<br>"; | |
| 294 } | |
| 295 newSource += '<pre style=\'margin-bottom: -12px;\' ' + clickHandler + '>' + | |
| 296 currentLine + '</pre>'; | |
| 297 lineNumber++; | |
| 298 } | |
| 299 processLines(originalSource, originalSource.length, functionProcessLine); | |
| 300 return newSource; | |
| 301 } | |
| 302 | |
| 303 function findSourcePosition(pcToSearch) { | |
| 304 var position = 0; | |
| 305 var distance = 0x7FFFFFFF; | |
| 306 var pcToSearchOffset = parseInt(pcToSearch); | |
| 307 var processOneLine = function(text, begin, end) { | |
| 308 var currentLine = text.substring(begin, end); | |
| 309 var matches = positionFinder.exec(currentLine); | |
| 310 if (matches != null) { | |
| 311 var pcOffset = parseInt(matches[1]); | |
| 312 if (pcOffset <= pcToSearchOffset) { | |
| 313 var dist = pcToSearchOffset - pcOffset; | |
| 314 var pos = parseInt(matches[2]); | |
| 315 if ((dist < distance) || (dist == distance && pos > position)) { | |
| 316 position = pos; | |
| 317 distance = dist; | |
| 318 } | |
| 319 } | |
| 320 } | |
| 321 } | |
| 322 var asmText = getCurrentAsmText(); | |
| 323 processLines(asmText, asmText.length, processOneLine); | |
| 324 var code = getCurrentCodeObject(); | |
| 325 if (position == 0) return 0; | |
| 326 return position - code.firstSourcePosition; | |
| 327 } | |
| 328 | |
| 329 function findSourceLine(position) { | |
| 330 if (position == 0) return 1; | |
| 331 var line = 0; | |
| 332 var processOneLine = function(text, begin, end) { | |
| 333 if (begin < position) { | |
| 334 line++; | |
| 335 } | |
| 336 } | |
| 337 var sourceText = getCurrentSourceText(); | |
| 338 processLines(sourceText, sourceText.length, processOneLine); | |
| 339 return line; | |
| 340 } | |
| 341 | |
| 342 function functionChangedHandler() { | |
| 343 var functionSelect = document.getElementById('function-selector-id'); | |
| 344 var source = getCurrentSourceText(); | |
| 345 var sourceDivElement = document.getElementById('source-text'); | |
| 346 var code = getCurrentCodeObject(); | |
| 347 var newHtml = "<pre class=\"prettyprint linenums\" id=\"source-text\">" + | |
| 348 + 'function ' + code.name + source + "</pre>"; | |
| 349 sourceDivElement.innerHTML = newHtml; | |
| 350 try { | |
| 351 // Wrap in try to work when offline. | |
| 352 PR.prettyPrint(); | |
| 353 } catch (e) { | |
| 354 } | |
| 355 var sourceLineContainer = sourceDivElement.firstChild.firstChild; | |
| 356 var lineCount = sourceLineContainer.childElementCount; | |
| 357 var current = sourceLineContainer.firstChild; | |
| 358 for (var i = 1; i < lineCount; ++i) { | |
| 359 current.id = "source-line-" + i; | |
| 360 current = current.nextElementSibling; | |
| 361 } | |
| 362 | |
| 363 var asmDivElement = document.getElementById('asm-container'); | |
| 364 var asm = getCurrentAsmText(); | |
| 365 newHtml = prepareAsm(asm); | |
| 366 asmDivElement.innerHTML = '<div id=\"asm-text\">' + newHtml + '</div>'; | |
|
Dmitry Lomov (no reviews)
2013/10/18 16:07:53
Use createElement here
danno
2013/10/19 17:11:40
Done.
| |
| 367 } | |
| 368 | |
| 369 function kindChangedHandler(element) { | |
| 370 setKindByIndex(element.selectedIndex); | |
| 371 processFileContent(); | |
| 372 functionChangedHandler(); | |
| 373 } | |
| 374 | |
| 375 function readLog(evt) { | |
| 376 //Retrieve the first (and only!) File from the FileList object | |
| 377 var f = evt.target.files[0]; | |
| 378 if (f) { | |
| 379 var r = new FileReader(); | |
| 380 r.onload = function(e) { | |
| 381 var file = evt.target.files[0]; | |
| 382 currentFunctionKind = ""; | |
| 383 fileContent = e.target.result; | |
| 384 processFileContent(); | |
| 385 functionChangedHandler(); | |
| 386 } | |
| 387 r.readAsText(f); | |
| 388 } else { | |
| 389 alert("Failed to load file"); | |
| 390 } | |
| 391 } | |
| 392 | |
| 393 function buildFunctionKindSelector() { | |
| 394 document.getElementById('log-file-id').addEventListener('change', | |
|
Dmitry Lomov (no reviews)
2013/10/18 16:07:53
Consider replacing getElementById with parameters
danno
2013/10/19 17:11:40
Done.
| |
| 395 readLog, false); | |
| 396 var kindSelectElement = document.getElementById('kind-selector-id'); | |
| 397 for (var x = 0; x < kinds.length; ++x) { | |
| 398 var optionElement = document.createElement("option"); | |
| 399 optionElement.value = x; | |
| 400 optionElement.text = kinds[x]; | |
| 401 kindSelectElement.add(optionElement, null); | |
| 402 } | |
| 403 kindSelectElement.selectedIndex = 1; | |
| 404 setKindByIndex(1); | |
| 405 } | |
| 406 | |
| 407 return { | |
| 408 buildFunctionKindSelector: buildFunctionKindSelector, | |
| 409 kindChangedHandler: kindChangedHandler, | |
| 410 functionChangedHandler: functionChangedHandler, | |
| 411 asmClick: asmClick, | |
| 412 addressClick: addressClick | |
| 413 }; | |
| 414 | |
| 415 })(); | |
| OLD | NEW |