Chromium Code Reviews| Index: test/mjsunit/log-eq-of-logging-and-traversal.js |
| diff --git a/test/mjsunit/log-eq-of-logging-and-traversal.js b/test/mjsunit/log-eq-of-logging-and-traversal.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..778b6276284ddd46ac70d3a1e6cc2582980cd26a |
| --- /dev/null |
| +++ b/test/mjsunit/log-eq-of-logging-and-traversal.js |
| @@ -0,0 +1,183 @@ |
| +// Copyright 2011 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. |
| + |
| +// Load implementations from <project root>/tools. |
| +// Files: tools/splaytree.js tools/codemap.js tools/csvparser.js |
| +// Files: tools/consarray.js tools/profile.js tools/profile_view.js |
| +// Files: tools/logreader.js |
| +// Files: test/mjsunit/log-utils.js |
| +// Flags: --allow_natives_syntax --log-runtime --prof |
| +// Env: LOG_FILE_NAME |
| + |
|
Søren Thygesen Gjesse
2011/07/07 11:59:53
Please add a comment here to explain that first th
mnaganov (inactive)
2011/07/07 20:19:57
Done.
|
| +%Log("test-start", []); |
| +(function f(obj) { |
| + obj.test = |
| + (function a(j) { return function b() { return j; } })(100); |
| +})(this); |
| +%ProfilerPause(); |
| +%CollectGarbage2(); |
| +%Log("test-logging-done", []); |
| +%LogCompiledFunctions(); |
| +%Log("test-traversal-done", []); |
| +%Log("test-stop", []); |
| + |
| +function parseState(s) { |
| + switch (s) { |
| + case "": return Profile.CodeState.COMPILED; |
| + case "~": return Profile.CodeState.OPTIMIZABLE; |
| + case "*": return Profile.CodeState.OPTIMIZED; |
| + } |
| + throw new Error("unknown code state: " + s); |
| +} |
| + |
| +function LogProcessor() { |
| + LogReader.call(this, { |
| + 'code-creation': { |
| + parsers: [null, parseInt, parseInt, null, 'var-args'], |
| + processor: this.processCodeCreation }, |
| + 'code-move': { parsers: [parseInt, parseInt], |
| + processor: this.processCodeMove }, |
| + 'code-delete': { parsers: [parseInt], |
| + processor: this.processCodeDelete }, |
| + 'sfi-move': { parsers: [parseInt, parseInt], |
| + processor: this.processFunctionMove }, |
| + 'shared-library': null, |
| + 'profiler': null, |
| + 'tick': null }); |
| + this.profile = new Profile(); |
| + |
| +} |
| +LogProcessor.prototype.__proto__ = LogReader.prototype; |
| + |
| +LogProcessor.prototype.processCodeCreation = function( |
| + type, start, size, name, maybe_func) { |
| + if (type != "LazyCompile" && type != "Script" && type != "Function") return; |
| + // Discard types to avoid discrepancies in "LazyCompile" vs. "Function". |
| + type = ""; |
| + if (maybe_func.length) { |
| + var funcAddr = parseInt(maybe_func[0]); |
| + var state = parseState(maybe_func[1]); |
| + this.profile.addFuncCode(type, name, start, size, funcAddr, state); |
| + } else { |
| + this.profile.addCode(type, name, start, size); |
| + } |
| +}; |
| + |
| +LogProcessor.prototype.processCodeMove = function(from, to) { |
| + this.profile.moveCode(from, to); |
| +}; |
| + |
| +LogProcessor.prototype.processCodeDelete = function(start) { |
| + this.profile.deleteCode(start); |
| +}; |
| + |
| +LogProcessor.prototype.processFunctionMove = function(from, to) { |
| + this.profile.moveFunc(from, to); |
| +}; |
| + |
| +var log_reader = new SimpleLogReader(); |
| +var line; |
| +var logging_processor = new LogProcessor(); |
| +while ((line = log_reader.nextLine()) !== "test-logging-done") { |
| + logging_processor.processLogLine(line); |
| +} |
| +var traversal_processor = new LogProcessor(); |
| +while ((line = log_reader.nextLine()) !== "test-traversal-done") { |
| + traversal_processor.processLogLine(line); |
| +} |
| + |
| +var logging_entries = |
| + logging_processor.profile.codeMap_.getAllDynamicEntriesWithAddresses(); |
| +assertTrue(!!logging_entries.length); |
| +var traversal_entries = |
| + traversal_processor.profile.codeMap_.getAllDynamicEntriesWithAddresses(); |
| +assertTrue(!!traversal_entries.length); |
| + |
| +function addressComparator(entryA, entryB) { |
| + return entryA[0] < entryB[0] ? -1 : (entryA[0] > entryB[0] ? 1 : 0); |
| +} |
| + |
| +logging_entries.sort(addressComparator); |
| +traversal_entries.sort(addressComparator); |
| + |
| +function entityNamesEqual(entityA, entityB) { |
| + if ("getRawName" in entityB && |
| + entityNamesEqual.builtins.indexOf(entityB.getRawName()) !== -1) { |
| + return true; |
| + } |
| + if (entityNamesEqual.builtins.indexOf(entityB.getName()) !== -1) return true; |
| + return entityA.getName() === entityB.getName(); |
| +} |
| +entityNamesEqual.builtins = |
| + ["Boolean", "Function", "Number", "Object", |
| + "Script", "String", "RegExp", "Date", "Error"]; |
| + |
| +function entitiesEqual(entityA, entityB) { |
| + if (!entityA && entityB) return true; |
|
Søren Thygesen Gjesse
2011/07/07 11:59:53
!entityA -> entityA == null?
mnaganov (inactive)
2011/07/07 20:19:57
Done.
|
| + if (entityA && !entityB) return false; |
|
Søren Thygesen Gjesse
2011/07/07 11:59:53
Ditto.
mnaganov (inactive)
2011/07/07 20:19:57
Done.
|
| + return entityA.size === entityB.size && entityNamesEqual(entityA, entityB); |
| +} |
| + |
| +var i = 0, j = 0, k = logging_entries.length, l = traversal_entries.length; |
| +var comparison = []; |
| +var equal = true; |
|
Søren Thygesen Gjesse
2011/07/07 11:59:53
Please explain how this comparison works, and why
mnaganov (inactive)
2011/07/07 20:19:57
Done.
|
| +while (i < k && j < l) { |
| + var entryA = logging_entries[i], entryB = traversal_entries[j]; |
| + var cmp = addressComparator(entryA, entryB); |
| + var entityA = entryA[1], entityB = entryB[1]; |
| + var address = entryA[0]; |
| + if (cmp < 0) { |
| + ++i; |
| + entityB = null; |
| + } else if (cmp > 0) { |
| + ++j; |
| + entityA = null; |
| + address = entryB[0]; |
| + } else { |
| + ++i; |
| + ++j; |
| + } |
| + var entities_equal = entitiesEqual(entityA, entityB); |
| + if (!entities_equal) equal = false; |
| + comparison.push([entities_equal, address, entityA, entityB]); |
| +} |
| +if (i < k) equal = false; |
| +while (i < k) { |
| + var entryA = logging_entries[i++]; |
| + comparison.push([false, entryA[0], entryA[1], null]); |
| +} |
| + |
| +if (!equal) { |
| + for (var i = 0, l = comparison.length; i < l; ++i) { |
| + var c = comparison[i]; |
| + print((c[0] ? " " : "* ") + |
| + c[1].toString(16) + " " + |
| + (c[2] ? c[2] : "---") + " " + |
| + (c[3] ? c[3] : "---")); |
| + } |
| +} |
| +assertTrue(equal); |