diff options
Diffstat (limited to 'chromium/v8/tools/SourceMap.js')
-rw-r--r-- | chromium/v8/tools/SourceMap.js | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/chromium/v8/tools/SourceMap.js b/chromium/v8/tools/SourceMap.js new file mode 100644 index 00000000000..9cbd37a7355 --- /dev/null +++ b/chromium/v8/tools/SourceMap.js @@ -0,0 +1,371 @@ +// 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. + +// This is a copy from blink dev tools, see: +// http://src.chromium.org/viewvc/blink/trunk/Source/devtools/front_end/SourceMap.js +// revision: 153407 + +// Added to make the file work without dev tools +WebInspector = {}; +WebInspector.ParsedURL = {}; +WebInspector.ParsedURL.completeURL = function(){}; +// start of original file content + +/* + * Copyright (C) 2012 Google Inc. 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. + */ + +/** + * Implements Source Map V3 model. See http://code.google.com/p/closure-compiler/wiki/SourceMaps + * for format description. + * @constructor + * @param {string} sourceMappingURL + * @param {SourceMapV3} payload + */ +WebInspector.SourceMap = function(sourceMappingURL, payload) +{ + if (!WebInspector.SourceMap.prototype._base64Map) { + const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + WebInspector.SourceMap.prototype._base64Map = {}; + for (var i = 0; i < base64Digits.length; ++i) + WebInspector.SourceMap.prototype._base64Map[base64Digits.charAt(i)] = i; + } + + this._sourceMappingURL = sourceMappingURL; + this._reverseMappingsBySourceURL = {}; + this._mappings = []; + this._sources = {}; + this._sourceContentByURL = {}; + this._parseMappingPayload(payload); +} + +/** + * @param {string} sourceMapURL + * @param {string} compiledURL + * @param {function(WebInspector.SourceMap)} callback + */ +WebInspector.SourceMap.load = function(sourceMapURL, compiledURL, callback) +{ + NetworkAgent.loadResourceForFrontend(WebInspector.resourceTreeModel.mainFrame.id, sourceMapURL, undefined, contentLoaded.bind(this)); + + /** + * @param {?Protocol.Error} error + * @param {number} statusCode + * @param {NetworkAgent.Headers} headers + * @param {string} content + */ + function contentLoaded(error, statusCode, headers, content) + { + if (error || !content || statusCode >= 400) { + console.error("Could not load content for " + sourceMapURL + " : " + (error || ("HTTP status code: " + statusCode))); + callback(null); + return; + } + + if (content.slice(0, 3) === ")]}") + content = content.substring(content.indexOf('\n')); + try { + var payload = /** @type {SourceMapV3} */ (JSON.parse(content)); + var baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourceMapURL; + callback(new WebInspector.SourceMap(baseURL, payload)); + } catch(e) { + console.error(e.message); + callback(null); + } + } +} + +WebInspector.SourceMap.prototype = { + /** + * @return {Array.<string>} + */ + sources: function() + { + return Object.keys(this._sources); + }, + + /** + * @param {string} sourceURL + * @return {string|undefined} + */ + sourceContent: function(sourceURL) + { + return this._sourceContentByURL[sourceURL]; + }, + + /** + * @param {string} sourceURL + * @param {WebInspector.ResourceType} contentType + * @return {WebInspector.ContentProvider} + */ + sourceContentProvider: function(sourceURL, contentType) + { + var lastIndexOfDot = sourceURL.lastIndexOf("."); + var extension = lastIndexOfDot !== -1 ? sourceURL.substr(lastIndexOfDot + 1) : ""; + var mimeType = WebInspector.ResourceType.mimeTypesForExtensions[extension.toLowerCase()]; + var sourceContent = this.sourceContent(sourceURL); + if (sourceContent) + return new WebInspector.StaticContentProvider(contentType, sourceContent, mimeType); + return new WebInspector.CompilerSourceMappingContentProvider(sourceURL, contentType, mimeType); + }, + + /** + * @param {SourceMapV3} mappingPayload + */ + _parseMappingPayload: function(mappingPayload) + { + if (mappingPayload.sections) + this._parseSections(mappingPayload.sections); + else + this._parseMap(mappingPayload, 0, 0); + }, + + /** + * @param {Array.<SourceMapV3.Section>} sections + */ + _parseSections: function(sections) + { + for (var i = 0; i < sections.length; ++i) { + var section = sections[i]; + this._parseMap(section.map, section.offset.line, section.offset.column); + } + }, + + /** + * @param {number} lineNumber in compiled resource + * @param {number} columnNumber in compiled resource + * @return {?Array} + */ + findEntry: function(lineNumber, columnNumber) + { + var first = 0; + var count = this._mappings.length; + while (count > 1) { + var step = count >> 1; + var middle = first + step; + var mapping = this._mappings[middle]; + if (lineNumber < mapping[0] || (lineNumber === mapping[0] && columnNumber < mapping[1])) + count = step; + else { + first = middle; + count -= step; + } + } + var entry = this._mappings[first]; + if (!first && entry && (lineNumber < entry[0] || (lineNumber === entry[0] && columnNumber < entry[1]))) + return null; + return entry; + }, + + /** + * @param {string} sourceURL of the originating resource + * @param {number} lineNumber in the originating resource + * @return {Array} + */ + findEntryReversed: function(sourceURL, lineNumber) + { + var mappings = this._reverseMappingsBySourceURL[sourceURL]; + for ( ; lineNumber < mappings.length; ++lineNumber) { + var mapping = mappings[lineNumber]; + if (mapping) + return mapping; + } + return this._mappings[0]; + }, + + /** + * @override + */ + _parseMap: function(map, lineNumber, columnNumber) + { + var sourceIndex = 0; + var sourceLineNumber = 0; + var sourceColumnNumber = 0; + var nameIndex = 0; + + var sources = []; + var originalToCanonicalURLMap = {}; + for (var i = 0; i < map.sources.length; ++i) { + var originalSourceURL = map.sources[i]; + var sourceRoot = map.sourceRoot || ""; + if (sourceRoot && !sourceRoot.endsWith("/")) + sourceRoot += "/"; + var href = sourceRoot + originalSourceURL; + var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href; + originalToCanonicalURLMap[originalSourceURL] = url; + sources.push(url); + this._sources[url] = true; + + if (map.sourcesContent && map.sourcesContent[i]) + this._sourceContentByURL[url] = map.sourcesContent[i]; + } + + var stringCharIterator = new WebInspector.SourceMap.StringCharIterator(map.mappings); + var sourceURL = sources[sourceIndex]; + + while (true) { + if (stringCharIterator.peek() === ",") + stringCharIterator.next(); + else { + while (stringCharIterator.peek() === ";") { + lineNumber += 1; + columnNumber = 0; + stringCharIterator.next(); + } + if (!stringCharIterator.hasNext()) + break; + } + + columnNumber += this._decodeVLQ(stringCharIterator); + if (this._isSeparator(stringCharIterator.peek())) { + this._mappings.push([lineNumber, columnNumber]); + continue; + } + + var sourceIndexDelta = this._decodeVLQ(stringCharIterator); + if (sourceIndexDelta) { + sourceIndex += sourceIndexDelta; + sourceURL = sources[sourceIndex]; + } + sourceLineNumber += this._decodeVLQ(stringCharIterator); + sourceColumnNumber += this._decodeVLQ(stringCharIterator); + if (!this._isSeparator(stringCharIterator.peek())) + nameIndex += this._decodeVLQ(stringCharIterator); + + this._mappings.push([lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber]); + } + + for (var i = 0; i < this._mappings.length; ++i) { + var mapping = this._mappings[i]; + var url = mapping[2]; + if (!url) + continue; + if (!this._reverseMappingsBySourceURL[url]) + this._reverseMappingsBySourceURL[url] = []; + var reverseMappings = this._reverseMappingsBySourceURL[url]; + var sourceLine = mapping[3]; + if (!reverseMappings[sourceLine]) + reverseMappings[sourceLine] = [mapping[0], mapping[1]]; + } + }, + + /** + * @param {string} char + * @return {boolean} + */ + _isSeparator: function(char) + { + return char === "," || char === ";"; + }, + + /** + * @param {WebInspector.SourceMap.StringCharIterator} stringCharIterator + * @return {number} + */ + _decodeVLQ: function(stringCharIterator) + { + // Read unsigned value. + var result = 0; + var shift = 0; + do { + var digit = this._base64Map[stringCharIterator.next()]; + result += (digit & this._VLQ_BASE_MASK) << shift; + shift += this._VLQ_BASE_SHIFT; + } while (digit & this._VLQ_CONTINUATION_MASK); + + // Fix the sign. + var negative = result & 1; + result >>= 1; + return negative ? -result : result; + }, + + _VLQ_BASE_SHIFT: 5, + _VLQ_BASE_MASK: (1 << 5) - 1, + _VLQ_CONTINUATION_MASK: 1 << 5 +} + +/** + * @constructor + * @param {string} string + */ +WebInspector.SourceMap.StringCharIterator = function(string) +{ + this._string = string; + this._position = 0; +} + +WebInspector.SourceMap.StringCharIterator.prototype = { + /** + * @return {string} + */ + next: function() + { + return this._string.charAt(this._position++); + }, + + /** + * @return {string} + */ + peek: function() + { + return this._string.charAt(this._position); + }, + + /** + * @return {boolean} + */ + hasNext: function() + { + return this._position < this._string.length; + } +} |