Index: tools/sodium/sodium.js |
diff --git a/tools/sodium/sodium.js b/tools/sodium/sodium.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..44475a177f77151e6fddf78438ce03d899e71cc4 |
--- /dev/null |
+++ b/tools/sodium/sodium.js |
@@ -0,0 +1,409 @@ |
+// Copyright 2013 the V8 project authors. All rights reserved. |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions are |
+// met: |
+// |
+// * Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// * Redistributions in binary form must reproduce the above |
+// copyright notice, this list of conditions and the following |
+// disclaimer in the documentation and/or other materials provided |
+// with the distribution. |
+// * Neither the name of Google Inc. nor the names of its |
+// contributors may be used to endorse or promote products derived |
+// from this software without specific prior written permission. |
+// |
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+var Sodium = (function() { |
+ "use strict"; |
+ |
+ var kinds = ["FUNCTION", "OPTIMIZED_FUNCTION", "STUB", "BUILTIN", |
+ "LOAD_IC", "KEYED_LOAD_IC", "CALL_IC", "KEYED_CALL_IC", |
+ "STORE_IC", "KEYED_STORE_IC", "BINARY_OP_IC", "COMPARE_IC", |
+ "COMPARE_NIL_IC", "TO_BOOLEAN_IC"]; |
+ var kindsWithSource = { |
+ 'FUNCTION': true, |
+ 'OPTIMIZED_FUNCTION': true |
+ }; |
+ |
+ var addressRegEx = "0x[0-9a-f]{8,16}"; |
+ var nameFinder = new RegExp("^name = (.+)$"); |
+ var kindFinder = new RegExp("^kind = (.+)$"); |
+ var firstPositionFinder = new RegExp("^source_position = (\\d+)$"); |
+ var separatorFilter = new RegExp("^--- (.)+ ---$"); |
+ var rawSourceFilter = new RegExp("^--- Raw source ---$"); |
+ var codeEndFinder = new RegExp("^--- End code ---$"); |
+ var whiteSpaceLineFinder = new RegExp("^\\W*$"); |
+ var instructionBeginFinder = |
+ new RegExp("^Instructions\\W+\\(size = \\d+\\)"); |
+ var instructionFinder = |
+ new RegExp("^\(" + addressRegEx + "\)\(\\W+\\d+\\W+.+\)"); |
+ var positionFinder = |
+ new RegExp("^(" + addressRegEx + ")\\W+position\\W+\\((\\d+)\\)"); |
+ var addressFinder = new RegExp("\(" + addressRegEx + "\)"); |
+ var addressReplacer = new RegExp("\(" + addressRegEx + "\)", "gi"); |
+ |
+ var fileContent = ""; |
+ var selectedFunctionKind = ""; |
+ var currentFunctionKind = ""; |
+ |
+ var currentFunctionName = ""; |
+ var firstSourcePosition = 0; |
+ var startAddress = ""; |
+ var readingSource = false; |
+ var readingAsm = false; |
+ var sourceBegin = -1; |
+ var sourceEnd = -1; |
+ var asmBegin = -1; |
+ var asmEnd = -1; |
+ var codeObjects = []; |
+ var selectedAsm = null; |
+ var selectedSource = null; |
+ var selectedSourceClass = ""; |
+ |
+ function Code(name, kind, sourceBegin, sourceEnd, asmBegin, asmEnd, |
+ firstSourcePosition, startAddress) { |
+ this.name = name; |
+ this.kind = kind; |
+ this.sourceBegin = sourceBegin; |
+ this.sourceEnd = sourceEnd; |
+ this.asmBegin = asmBegin; |
+ this.asmEnd = asmEnd; |
+ this.firstSourcePosition = firstSourcePosition; |
+ this.startAddress = startAddress; |
+ } |
+ |
+ function getCurrentCodeObject() { |
+ var functionSelect = document.getElementById('function-selector-id'); |
+ return functionSelect.options[functionSelect.selectedIndex].codeObject; |
+ } |
+ |
+ function getCurrentSourceText() { |
+ var code = getCurrentCodeObject(); |
+ if (code.sourceBegin == -1 || code.sourceEnd == -1) return ""; |
+ return fileContent.substring(code.sourceBegin, code.sourceEnd); |
+ } |
+ |
+ function getCurrentAsmText() { |
+ var code = getCurrentCodeObject(); |
+ if (code.asmBegin == -1 || code.asmEnd == -1) return ""; |
+ return fileContent.substring(code.asmBegin, code.asmEnd); |
+ } |
+ |
+ function setKindByIndex(index) { |
+ selectedFunctionKind = kinds[index]; |
+ } |
+ |
+ function processLine(text, begin, end) { |
+ var line = text.substring(begin, end); |
+ if (readingSource) { |
+ if (separatorFilter.exec(line) != null) { |
+ readingSource = false; |
+ } else { |
+ if (sourceBegin == -1) { |
+ sourceBegin = begin; |
+ } |
+ sourceEnd = end; |
+ } |
+ } else { |
+ if (readingAsm) { |
+ if (codeEndFinder.exec(line) != null) { |
+ readingAsm = false; |
+ asmEnd = begin; |
+ var newCode = |
+ new Code(currentFunctionName, currentFunctionKind, |
+ sourceBegin, sourceEnd, asmBegin, asmEnd, |
+ firstSourcePosition, startAddress); |
+ codeObjects.push(newCode); |
+ currentFunctionKind = null; |
+ } else { |
+ if (asmBegin == -1) { |
+ matches = instructionBeginFinder.exec(line); |
+ if (matches != null) { |
+ asmBegin = begin; |
+ } |
+ } |
+ if (startAddress == "") { |
+ matches = instructionFinder.exec(line); |
+ if (matches != null) { |
+ startAddress = matches[1]; |
+ } |
+ } |
+ } |
+ } else { |
+ var matches = kindFinder.exec(line); |
+ if (matches != null) { |
+ currentFunctionKind = matches[1]; |
+ if (!kindsWithSource[currentFunctionKind]) { |
+ sourceBegin = -1; |
+ sourceEnd = -1; |
+ } |
+ } else if (currentFunctionKind != null) { |
+ matches = nameFinder.exec(line); |
+ if (matches != null) { |
+ readingAsm = true; |
+ asmBegin = -1; |
+ currentFunctionName = matches[1]; |
+ } |
+ } else if (rawSourceFilter.exec(line) != null) { |
+ readingSource = true; |
+ sourceBegin = -1; |
+ } else { |
+ var matches = firstPositionFinder.exec(line); |
+ if (matches != null) { |
+ firstSourcePosition = parseInt(matches[1]); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ function processLines(source, size, processLine) { |
+ var firstChar = 0; |
+ for (var x = 0; x < size; x++) { |
+ var curChar = source[x]; |
+ if (curChar == '\n' || curChar == '\r') { |
+ processLine(source, firstChar, x); |
+ firstChar = x + 1; |
+ } |
+ } |
+ if (firstChar != size - 1) { |
+ processLine(source, firstChar, size - 1); |
+ } |
+ } |
+ |
+ function processFileContent() { |
+ document.getElementById('source-text-pre').innerHTML = ''; |
+ sourceBegin = -1; |
+ codeObjects = []; |
+ processLines(fileContent, fileContent.length, processLine); |
+ var functionSelectElement = document.getElementById('function-selector-id'); |
+ functionSelectElement.innerHTML = ''; |
+ var length = codeObjects.length; |
+ for (var i = 0; i < codeObjects.length; ++i) { |
+ var code = codeObjects[i]; |
+ if (code.kind == selectedFunctionKind) { |
+ var optionElement = document.createElement("option"); |
+ optionElement.codeObject = code; |
+ optionElement.text = code.name; |
+ functionSelectElement.add(optionElement, null); |
+ } |
+ } |
+ } |
+ |
+ function asmClick(element) { |
+ if (element == selectedAsm) return; |
+ if (selectedAsm != null) { |
+ selectedAsm.classList.remove('highlight-yellow'); |
+ } |
+ selectedAsm = element; |
+ selectedAsm.classList.add('highlight-yellow'); |
+ |
+ var pc = element.firstChild.innerText; |
+ var sourceLine = null; |
+ if (addressFinder.exec(pc) != null) { |
+ var position = findSourcePosition(pc); |
+ var line = findSourceLine(position); |
+ sourceLine = document.getElementById('source-line-' + line); |
+ var sourceLineTop = sourceLine.offsetTop; |
+ makeSourcePosVisible(sourceLineTop); |
+ } |
+ if (selectedSource == sourceLine) return; |
+ if (selectedSource != null) { |
+ selectedSource.classList.remove('highlight-yellow'); |
+ selectedSource.classList.add(selectedSourceClass); |
+ } |
+ if (sourceLine != null) { |
+ selectedSourceClass = sourceLine.classList[0]; |
+ sourceLine.classList.remove(selectedSourceClass); |
+ sourceLine.classList.add('highlight-yellow'); |
+ } |
+ selectedSource = sourceLine; |
+ } |
+ |
+ function makeContainerPosVisible(container, newTop) { |
+ var height = container.offsetHeight; |
+ var margin = Math.floor(height / 4); |
+ if (newTop < container.scrollTop + margin) { |
+ newTop -= margin; |
+ if (newTop < 0) newTop = 0; |
+ container.scrollTop = newTop; |
+ return; |
+ } |
+ if (newTop > (container.scrollTop + 3 * margin)) { |
+ newTop = newTop - 3 * margin; |
+ container.scrollTop = newTop; |
+ } |
+ } |
+ |
+ function makeAsmPosVisible(newTop) { |
+ var asmContainer = document.getElementById('asm-container'); |
+ makeContainerPosVisible(asmContainer, newTop); |
+ } |
+ |
+ function makeSourcePosVisible(newTop) { |
+ var sourceContainer = document.getElementById('source-container'); |
+ makeContainerPosVisible(sourceContainer, newTop); |
+ } |
+ |
+ function addressClick(element, event) { |
+ event.stopPropagation(); |
+ var asmLineId = 'address-' + element.innerText; |
+ var asmLineElement = document.getElementById(asmLineId); |
+ if (asmLineElement != null) { |
+ var asmLineTop = asmLineElement.parentNode.offsetTop; |
+ makeAsmPosVisible(asmLineTop); |
+ asmLineElement.classList.add('highlight-flash-blue'); |
+ window.setTimeout(function() { |
+ asmLineElement.classList.remove('highlight-flash-blue'); |
+ }, 1500); |
+ } |
+ } |
+ |
+ function prepareAsm(originalSource) { |
+ var newSource = ""; |
+ var lineNumber = 1; |
+ var functionProcessLine = function(text, begin, end) { |
+ var currentLine = text.substring(begin, end); |
+ var matches = instructionFinder.exec(currentLine); |
+ var clickHandler = ""; |
+ if (matches != null) { |
+ var restOfLine = matches[2]; |
+ restOfLine = restOfLine.replace( |
+ addressReplacer, |
+ '<span class="hover-underline" ' + |
+ 'onclick="Sodium.addressClick(this, event);">\$1</span>'); |
+ currentLine = '<span id="address-' + matches[1] + '" >' + |
+ matches[1] + '</span>' + restOfLine; |
+ clickHandler = 'onclick=\'Sodium.asmClick(this)\' '; |
+ } else if (whiteSpaceLineFinder.exec(currentLine)) { |
+ currentLine = "<br>"; |
+ } |
+ newSource += '<pre style=\'margin-bottom: -12px;\' ' + clickHandler + '>' + |
+ currentLine + '</pre>'; |
+ lineNumber++; |
+ } |
+ processLines(originalSource, originalSource.length, functionProcessLine); |
+ return newSource; |
+ } |
+ |
+ function findSourcePosition(pcToSearch) { |
+ var position = 0; |
+ var distance = 0x7FFFFFFF; |
+ var pcToSearchOffset = parseInt(pcToSearch); |
+ var processOneLine = function(text, begin, end) { |
+ var currentLine = text.substring(begin, end); |
+ var matches = positionFinder.exec(currentLine); |
+ if (matches != null) { |
+ var pcOffset = parseInt(matches[1]); |
+ if (pcOffset <= pcToSearchOffset) { |
+ var dist = pcToSearchOffset - pcOffset; |
+ var pos = parseInt(matches[2]); |
+ if ((dist < distance) || (dist == distance && pos > position)) { |
+ position = pos; |
+ distance = dist; |
+ } |
+ } |
+ } |
+ } |
+ var asmText = getCurrentAsmText(); |
+ processLines(asmText, asmText.length, processOneLine); |
+ var code = getCurrentCodeObject(); |
+ if (position == 0) return 0; |
+ return position - code.firstSourcePosition; |
+ } |
+ |
+ function findSourceLine(position) { |
+ if (position == 0) return 1; |
+ var line = 0; |
+ var processOneLine = function(text, begin, end) { |
+ if (begin < position) { |
+ line++; |
+ } |
+ } |
+ var sourceText = getCurrentSourceText(); |
+ processLines(sourceText, sourceText.length, processOneLine); |
+ return line; |
+ } |
+ |
+ function functionChangedHandler() { |
+ var functionSelect = document.getElementById('function-selector-id'); |
+ var source = getCurrentSourceText(); |
+ var sourceDivElement = document.getElementById('source-text'); |
+ var code = getCurrentCodeObject(); |
+ var newHtml = "<pre class=\"prettyprint linenums\" id=\"source-text\">" |
+ + 'function ' + code.name + source + "</pre>"; |
+ sourceDivElement.innerHTML = newHtml; |
+ try { |
+ // Wrap in try to work when offline. |
+ PR.prettyPrint(); |
+ } catch (e) { |
+ } |
+ var sourceLineContainer = sourceDivElement.firstChild.firstChild; |
+ var lineCount = sourceLineContainer.childElementCount; |
+ var current = sourceLineContainer.firstChild; |
+ for (var i = 1; i < lineCount; ++i) { |
+ current.id = "source-line-" + i; |
+ current = current.nextElementSibling; |
+ } |
+ |
+ var asm = getCurrentAsmText(); |
+ document.getElementById('asm-text').innerHTML = prepareAsm(asm); |
+ } |
+ |
+ function kindChangedHandler(element) { |
+ setKindByIndex(element.selectedIndex); |
+ processFileContent(); |
+ functionChangedHandler(); |
+ } |
+ |
+ function readLog(evt) { |
+ //Retrieve the first (and only!) File from the FileList object |
+ var f = evt.target.files[0]; |
+ if (f) { |
+ var r = new FileReader(); |
+ r.onload = function(e) { |
+ var file = evt.target.files[0]; |
+ currentFunctionKind = ""; |
+ fileContent = e.target.result; |
+ processFileContent(); |
+ functionChangedHandler(); |
+ } |
+ r.readAsText(f); |
+ } else { |
+ alert("Failed to load file"); |
+ } |
+ } |
+ |
+ function buildFunctionKindSelector(kindSelectElement) { |
+ for (var x = 0; x < kinds.length; ++x) { |
+ var optionElement = document.createElement("option"); |
+ optionElement.value = x; |
+ optionElement.text = kinds[x]; |
+ kindSelectElement.add(optionElement, null); |
+ } |
+ kindSelectElement.selectedIndex = 1; |
+ setKindByIndex(1); |
+ } |
+ |
+ return { |
+ buildFunctionKindSelector: buildFunctionKindSelector, |
+ kindChangedHandler: kindChangedHandler, |
+ functionChangedHandler: functionChangedHandler, |
+ asmClick: asmClick, |
+ addressClick: addressClick, |
+ readLog: readLog |
+ }; |
+ |
+})(); |