Move V8 to external/v8
Change-Id: If68025d67453785a651c5dfb34fad298c16676a4
diff --git a/test/mjsunit/tools/codemap.js b/test/mjsunit/tools/codemap.js
new file mode 100644
index 0000000..06a91e8
--- /dev/null
+++ b/test/mjsunit/tools/codemap.js
@@ -0,0 +1,180 @@
+// Copyright 2009 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 Splay tree and CodeMap implementations from <project root>/tools.
+// Files: tools/splaytree.js tools/codemap.js
+
+
+function newCodeEntry(size, name) {
+ return new devtools.profiler.CodeMap.CodeEntry(size, name);
+};
+
+
+function assertEntry(codeMap, expected_name, addr) {
+ var entry = codeMap.findEntry(addr);
+ assertNotNull(entry, 'no entry at ' + addr.toString(16));
+ assertEquals(expected_name, entry.name, 'at ' + addr.toString(16));
+};
+
+
+function assertNoEntry(codeMap, addr) {
+ assertNull(codeMap.findEntry(addr), 'at ' + addr.toString(16));
+};
+
+
+(function testLibrariesAndStaticCode() {
+ var codeMap = new devtools.profiler.CodeMap();
+ codeMap.addLibrary(0x1500, newCodeEntry(0x3000, 'lib1'));
+ codeMap.addLibrary(0x15500, newCodeEntry(0x5000, 'lib2'));
+ codeMap.addLibrary(0x155500, newCodeEntry(0x10000, 'lib3'));
+ assertNoEntry(codeMap, 0);
+ assertNoEntry(codeMap, 0x1500 - 1);
+ assertEntry(codeMap, 'lib1', 0x1500);
+ assertEntry(codeMap, 'lib1', 0x1500 + 0x100);
+ assertEntry(codeMap, 'lib1', 0x1500 + 0x1000);
+ assertEntry(codeMap, 'lib1', 0x1500 + 0x3000 - 1);
+ assertNoEntry(codeMap, 0x1500 + 0x3000);
+ assertNoEntry(codeMap, 0x15500 - 1);
+ assertEntry(codeMap, 'lib2', 0x15500);
+ assertEntry(codeMap, 'lib2', 0x15500 + 0x100);
+ assertEntry(codeMap, 'lib2', 0x15500 + 0x1000);
+ assertEntry(codeMap, 'lib2', 0x15500 + 0x5000 - 1);
+ assertNoEntry(codeMap, 0x15500 + 0x5000);
+ assertNoEntry(codeMap, 0x155500 - 1);
+ assertEntry(codeMap, 'lib3', 0x155500);
+ assertEntry(codeMap, 'lib3', 0x155500 + 0x100);
+ assertEntry(codeMap, 'lib3', 0x155500 + 0x1000);
+ assertEntry(codeMap, 'lib3', 0x155500 + 0x10000 - 1);
+ assertNoEntry(codeMap, 0x155500 + 0x10000);
+ assertNoEntry(codeMap, 0xFFFFFFFF);
+
+ codeMap.addStaticCode(0x1510, newCodeEntry(0x30, 'lib1-f1'));
+ codeMap.addStaticCode(0x1600, newCodeEntry(0x50, 'lib1-f2'));
+ codeMap.addStaticCode(0x15520, newCodeEntry(0x100, 'lib2-f1'));
+ assertEntry(codeMap, 'lib1', 0x1500);
+ assertEntry(codeMap, 'lib1', 0x1510 - 1);
+ assertEntry(codeMap, 'lib1-f1', 0x1510);
+ assertEntry(codeMap, 'lib1-f1', 0x1510 + 0x15);
+ assertEntry(codeMap, 'lib1-f1', 0x1510 + 0x30 - 1);
+ assertEntry(codeMap, 'lib1', 0x1510 + 0x30);
+ assertEntry(codeMap, 'lib1', 0x1600 - 1);
+ assertEntry(codeMap, 'lib1-f2', 0x1600);
+ assertEntry(codeMap, 'lib1-f2', 0x1600 + 0x30);
+ assertEntry(codeMap, 'lib1-f2', 0x1600 + 0x50 - 1);
+ assertEntry(codeMap, 'lib1', 0x1600 + 0x50);
+ assertEntry(codeMap, 'lib2', 0x15500);
+ assertEntry(codeMap, 'lib2', 0x15520 - 1);
+ assertEntry(codeMap, 'lib2-f1', 0x15520);
+ assertEntry(codeMap, 'lib2-f1', 0x15520 + 0x80);
+ assertEntry(codeMap, 'lib2-f1', 0x15520 + 0x100 - 1);
+ assertEntry(codeMap, 'lib2', 0x15520 + 0x100);
+
+})();
+
+
+(function testDynamicCode() {
+ var codeMap = new devtools.profiler.CodeMap();
+ codeMap.addCode(0x1500, newCodeEntry(0x200, 'code1'));
+ codeMap.addCode(0x1700, newCodeEntry(0x100, 'code2'));
+ codeMap.addCode(0x1900, newCodeEntry(0x50, 'code3'));
+ codeMap.addCode(0x1950, newCodeEntry(0x10, 'code4'));
+ assertNoEntry(codeMap, 0);
+ assertNoEntry(codeMap, 0x1500 - 1);
+ assertEntry(codeMap, 'code1', 0x1500);
+ assertEntry(codeMap, 'code1', 0x1500 + 0x100);
+ assertEntry(codeMap, 'code1', 0x1500 + 0x200 - 1);
+ assertEntry(codeMap, 'code2', 0x1700);
+ assertEntry(codeMap, 'code2', 0x1700 + 0x50);
+ assertEntry(codeMap, 'code2', 0x1700 + 0x100 - 1);
+ assertNoEntry(codeMap, 0x1700 + 0x100);
+ assertNoEntry(codeMap, 0x1900 - 1);
+ assertEntry(codeMap, 'code3', 0x1900);
+ assertEntry(codeMap, 'code3', 0x1900 + 0x28);
+ assertEntry(codeMap, 'code4', 0x1950);
+ assertEntry(codeMap, 'code4', 0x1950 + 0x7);
+ assertEntry(codeMap, 'code4', 0x1950 + 0x10 - 1);
+ assertNoEntry(codeMap, 0x1950 + 0x10);
+ assertNoEntry(codeMap, 0xFFFFFFFF);
+})();
+
+
+(function testCodeMovesAndDeletions() {
+ var codeMap = new devtools.profiler.CodeMap();
+ codeMap.addCode(0x1500, newCodeEntry(0x200, 'code1'));
+ codeMap.addCode(0x1700, newCodeEntry(0x100, 'code2'));
+ assertEntry(codeMap, 'code1', 0x1500);
+ assertEntry(codeMap, 'code2', 0x1700);
+ codeMap.moveCode(0x1500, 0x1800);
+ assertNoEntry(codeMap, 0x1500);
+ assertEntry(codeMap, 'code2', 0x1700);
+ assertEntry(codeMap, 'code1', 0x1800);
+ codeMap.deleteCode(0x1700);
+ assertNoEntry(codeMap, 0x1700);
+ assertEntry(codeMap, 'code1', 0x1800);
+})();
+
+
+(function testDynamicNamesDuplicates() {
+ var codeMap = new devtools.profiler.CodeMap();
+ // Code entries with same names but different addresses.
+ codeMap.addCode(0x1500, newCodeEntry(0x200, 'code'));
+ codeMap.addCode(0x1700, newCodeEntry(0x100, 'code'));
+ assertEntry(codeMap, 'code', 0x1500);
+ assertEntry(codeMap, 'code {1}', 0x1700);
+ // Test name stability.
+ assertEntry(codeMap, 'code', 0x1500);
+ assertEntry(codeMap, 'code {1}', 0x1700);
+})();
+
+
+(function testStaticEntriesExport() {
+ var codeMap = new devtools.profiler.CodeMap();
+ codeMap.addStaticCode(0x1500, newCodeEntry(0x3000, 'lib1'));
+ codeMap.addStaticCode(0x15500, newCodeEntry(0x5000, 'lib2'));
+ codeMap.addStaticCode(0x155500, newCodeEntry(0x10000, 'lib3'));
+ var allStatics = codeMap.getAllStaticEntries();
+ allStatics.sort();
+ assertEquals(['lib1: 3000', 'lib2: 5000', 'lib3: 10000'], allStatics);
+})();
+
+
+(function testDynamicEntriesExport() {
+ var codeMap = new devtools.profiler.CodeMap();
+ codeMap.addCode(0x1500, newCodeEntry(0x200, 'code1'));
+ codeMap.addCode(0x1700, newCodeEntry(0x100, 'code2'));
+ codeMap.addCode(0x1900, newCodeEntry(0x50, 'code3'));
+ var allDynamics = codeMap.getAllDynamicEntries();
+ allDynamics.sort();
+ assertEquals(['code1: 200', 'code2: 100', 'code3: 50'], allDynamics);
+ codeMap.deleteCode(0x1700);
+ var allDynamics2 = codeMap.getAllDynamicEntries();
+ allDynamics2.sort();
+ assertEquals(['code1: 200', 'code3: 50'], allDynamics2);
+ codeMap.deleteCode(0x1500);
+ var allDynamics3 = codeMap.getAllDynamicEntries();
+ assertEquals(['code3: 50'], allDynamics3);
+})();
diff --git a/test/mjsunit/tools/consarray.js b/test/mjsunit/tools/consarray.js
new file mode 100644
index 0000000..8b2c59b
--- /dev/null
+++ b/test/mjsunit/tools/consarray.js
@@ -0,0 +1,60 @@
+// Copyright 2009 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 ConsArray implementation from <project root>/tools.
+// Files: tools/consarray.js
+
+
+var arr1 = new ConsArray();
+assertTrue(arr1.atEnd());
+
+arr1.concat([]);
+assertTrue(arr1.atEnd());
+
+arr1.concat([1]);
+assertFalse(arr1.atEnd());
+assertEquals(1, arr1.next());
+assertTrue(arr1.atEnd());
+
+arr1.concat([2, 3, 4]);
+arr1.concat([5]);
+arr1.concat([]);
+arr1.concat([6, 7]);
+
+assertFalse(arr1.atEnd());
+assertEquals(2, arr1.next());
+assertFalse(arr1.atEnd());
+assertEquals(3, arr1.next());
+assertFalse(arr1.atEnd());
+assertEquals(4, arr1.next());
+assertFalse(arr1.atEnd());
+assertEquals(5, arr1.next());
+assertFalse(arr1.atEnd());
+assertEquals(6, arr1.next());
+assertFalse(arr1.atEnd());
+assertEquals(7, arr1.next());
+assertTrue(arr1.atEnd());
diff --git a/test/mjsunit/tools/csvparser.js b/test/mjsunit/tools/csvparser.js
new file mode 100644
index 0000000..db3a2eb
--- /dev/null
+++ b/test/mjsunit/tools/csvparser.js
@@ -0,0 +1,79 @@
+// Copyright 2009 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 CSV parser implementation from <project root>/tools.
+// Files: tools/csvparser.js
+
+var parser = new devtools.profiler.CsvParser();
+
+assertEquals(
+ [],
+ parser.parseLine(''));
+
+assertEquals(
+ ['', ''],
+ parser.parseLine(','));
+
+assertEquals(
+ ['1997','Ford','E350'],
+ parser.parseLine('1997,Ford,E350'));
+
+assertEquals(
+ ['1997','Ford','E350'],
+ parser.parseLine('"1997","Ford","E350"'));
+
+assertEquals(
+ ['1997','Ford','E350','Super, luxurious truck'],
+ parser.parseLine('1997,Ford,E350,"Super, luxurious truck"'));
+
+assertEquals(
+ ['1997','Ford','E350','Super "luxurious" truck'],
+ parser.parseLine('1997,Ford,E350,"Super ""luxurious"" truck"'));
+
+assertEquals(
+ ['1997','Ford','E350','Super "luxurious" "truck"'],
+ parser.parseLine('1997,Ford,E350,"Super ""luxurious"" ""truck"""'));
+
+assertEquals(
+ ['1997','Ford','E350','Super "luxurious""truck"'],
+ parser.parseLine('1997,Ford,E350,"Super ""luxurious""""truck"""'));
+
+assertEquals(
+ ['shared-library','/lib/ld-2.3.6.so','0x489a2000','0x489b7000'],
+ parser.parseLine('shared-library,"/lib/ld-2.3.6.so",0x489a2000,0x489b7000'));
+
+assertEquals(
+ ['code-creation','LazyCompile','0xf6fe2d20','1201','APPLY_PREPARE native runtime.js:165'],
+ parser.parseLine('code-creation,LazyCompile,0xf6fe2d20,1201,"APPLY_PREPARE native runtime.js:165"'));
+
+assertEquals(
+ ['code-creation','LazyCompile','0xf6fe4bc0','282',' native v8natives.js:69'],
+ parser.parseLine('code-creation,LazyCompile,0xf6fe4bc0,282," native v8natives.js:69"'));
+
+assertEquals(
+ ['code-creation','RegExp','0xf6c21c00','826','NccyrJroXvg\\/([^,]*)'],
+ parser.parseLine('code-creation,RegExp,0xf6c21c00,826,"NccyrJroXvg\\/([^,]*)"'));
diff --git a/test/mjsunit/tools/logreader.js b/test/mjsunit/tools/logreader.js
new file mode 100644
index 0000000..8ed5ffd
--- /dev/null
+++ b/test/mjsunit/tools/logreader.js
@@ -0,0 +1,98 @@
+// Copyright 2009 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 CSV Parser and Log Reader implementations from <project root>/tools.
+// Files: tools/csvparser.js tools/logreader.js
+
+
+(function testAddressParser() {
+ var reader = new devtools.profiler.LogReader({});
+ var parser = reader.createAddressParser('test');
+
+ // Test that 0x values are parsed, and prevAddresses_ are untouched.
+ assertFalse('test' in reader.prevAddresses_);
+ assertEquals(0, parser('0x0'));
+ assertFalse('test' in reader.prevAddresses_);
+ assertEquals(0x100, parser('0x100'));
+ assertFalse('test' in reader.prevAddresses_);
+ assertEquals(0xffffffff, parser('0xffffffff'));
+ assertFalse('test' in reader.prevAddresses_);
+
+ // Test that values that has no '+' or '-' prefix are parsed
+ // and saved to prevAddresses_.
+ assertEquals(0, parser('0'));
+ assertEquals(0, reader.prevAddresses_.test);
+ assertEquals(0x100, parser('100'));
+ assertEquals(0x100, reader.prevAddresses_.test);
+ assertEquals(0xffffffff, parser('ffffffff'));
+ assertEquals(0xffffffff, reader.prevAddresses_.test);
+
+ // Test that values prefixed with '+' or '-' are treated as deltas,
+ // and prevAddresses_ is updated.
+ // Set base value.
+ assertEquals(0x100, parser('100'));
+ assertEquals(0x100, reader.prevAddresses_.test);
+ assertEquals(0x200, parser('+100'));
+ assertEquals(0x200, reader.prevAddresses_.test);
+ assertEquals(0x100, parser('-100'));
+ assertEquals(0x100, reader.prevAddresses_.test);
+})();
+
+
+(function testAddressParser() {
+ var reader = new devtools.profiler.LogReader({});
+
+ assertEquals([0x10000000, 0x10001000, 0xffff000, 0x10000000],
+ reader.processStack(0x10000000, ['overflow',
+ '+1000', '-2000', '+1000']));
+})();
+
+
+(function testExpandBackRef() {
+ var reader = new devtools.profiler.LogReader({});
+
+ assertEquals('aaaaaaaa', reader.expandBackRef_('aaaaaaaa'));
+ assertEquals('aaaaaaaa', reader.expandBackRef_('#1'));
+ assertEquals('bbbbaaaa', reader.expandBackRef_('bbbb#2:4'));
+ assertEquals('"#1:1"', reader.expandBackRef_('"#1:1"'));
+})();
+
+
+// See http://code.google.com/p/v8/issues/detail?id=420
+(function testReadingTruncatedLog() {
+ // Having an incorrect event in the middle of a log should throw an exception.
+ var reader1 = new devtools.profiler.LogReader({});
+ assertThrows(function() {
+ reader1.processLogChunk('alias,a,b\nxxxx\nalias,c,d\n');
+ });
+
+ // But having it as the last record should not.
+ var reader2 = new devtools.profiler.LogReader({});
+ assertDoesNotThrow(function() {
+ reader2.processLogChunk('alias,a,b\nalias,c,d\nxxxx');
+ });
+})();
diff --git a/test/mjsunit/tools/profile.js b/test/mjsunit/tools/profile.js
new file mode 100644
index 0000000..9ed851b
--- /dev/null
+++ b/test/mjsunit/tools/profile.js
@@ -0,0 +1,348 @@
+// Copyright 2009 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 source code files from <project root>/tools.
+// Files: tools/splaytree.js tools/codemap.js tools/consarray.js tools/profile.js
+
+
+function stackToString(stack) {
+ return stack.join(' -> ');
+};
+
+
+function assertPathExists(root, path, opt_message) {
+ var message = opt_message ? ' (' + opt_message + ')' : '';
+ assertNotNull(root.descendToChild(path, function(node, pos) {
+ assertNotNull(node,
+ stackToString(path.slice(0, pos)) + ' has no child ' +
+ path[pos] + message);
+ }), opt_message);
+};
+
+
+function assertNoPathExists(root, path, opt_message) {
+ var message = opt_message ? ' (' + opt_message + ')' : '';
+ assertNull(root.descendToChild(path), opt_message);
+};
+
+
+function countNodes(profile, traverseFunc) {
+ var count = 0;
+ traverseFunc.call(profile, function () { count++; });
+ return count;
+};
+
+
+function ProfileTestDriver() {
+ this.profile = new devtools.profiler.Profile();
+ this.stack_ = [];
+ this.addFunctions_();
+};
+
+
+// Addresses inside functions.
+ProfileTestDriver.prototype.funcAddrs_ = {
+ 'lib1-f1': 0x11110, 'lib1-f2': 0x11210,
+ 'lib2-f1': 0x21110, 'lib2-f2': 0x21210,
+ 'T: F1': 0x50110, 'T: F2': 0x50210, 'T: F3': 0x50410 };
+
+
+ProfileTestDriver.prototype.addFunctions_ = function() {
+ this.profile.addLibrary('lib1', 0x11000, 0x12000);
+ this.profile.addStaticCode('lib1-f1', 0x11100, 0x11900);
+ this.profile.addStaticCode('lib1-f2', 0x11200, 0x11500);
+ this.profile.addLibrary('lib2', 0x21000, 0x22000);
+ this.profile.addStaticCode('lib2-f1', 0x21100, 0x21900);
+ this.profile.addStaticCode('lib2-f2', 0x21200, 0x21500);
+ this.profile.addCode('T', 'F1', 0x50100, 0x100);
+ this.profile.addCode('T', 'F2', 0x50200, 0x100);
+ this.profile.addCode('T', 'F3', 0x50400, 0x100);
+};
+
+
+ProfileTestDriver.prototype.enter = function(funcName) {
+ // Stack looks like this: [pc, caller, ..., main].
+ // Therefore, we are adding entries at the beginning.
+ this.stack_.unshift(this.funcAddrs_[funcName]);
+ this.profile.recordTick(this.stack_);
+};
+
+
+ProfileTestDriver.prototype.stay = function() {
+ this.profile.recordTick(this.stack_);
+};
+
+
+ProfileTestDriver.prototype.leave = function() {
+ this.stack_.shift();
+};
+
+
+ProfileTestDriver.prototype.execute = function() {
+ this.enter('lib1-f1');
+ this.enter('lib1-f2');
+ this.enter('T: F1');
+ this.enter('T: F2');
+ this.leave();
+ this.stay();
+ this.enter('lib2-f1');
+ this.enter('lib2-f1');
+ this.leave();
+ this.stay();
+ this.leave();
+ this.enter('T: F3');
+ this.enter('T: F3');
+ this.enter('T: F3');
+ this.leave();
+ this.enter('T: F2');
+ this.stay();
+ this.leave();
+ this.leave();
+ this.leave();
+ this.leave();
+ this.enter('lib2-f1');
+ this.enter('lib1-f1');
+ this.leave();
+ this.leave();
+ this.stay();
+ this.leave();
+};
+
+
+function Inherits(childCtor, parentCtor) {
+ function tempCtor() {};
+ tempCtor.prototype = parentCtor.prototype;
+ childCtor.superClass_ = parentCtor.prototype;
+ childCtor.prototype = new tempCtor();
+ childCtor.prototype.constructor = childCtor;
+};
+
+
+(function testCallTreeBuilding() {
+ function Driver() {
+ ProfileTestDriver.call(this);
+ this.namesTopDown = [];
+ this.namesBottomUp = [];
+ };
+ Inherits(Driver, ProfileTestDriver);
+
+ Driver.prototype.enter = function(func) {
+ this.namesTopDown.push(func);
+ this.namesBottomUp.unshift(func);
+ assertNoPathExists(this.profile.getTopDownProfile().getRoot(), this.namesTopDown,
+ 'pre enter/topDown');
+ assertNoPathExists(this.profile.getBottomUpProfile().getRoot(), this.namesBottomUp,
+ 'pre enter/bottomUp');
+ Driver.superClass_.enter.call(this, func);
+ assertPathExists(this.profile.getTopDownProfile().getRoot(), this.namesTopDown,
+ 'post enter/topDown');
+ assertPathExists(this.profile.getBottomUpProfile().getRoot(), this.namesBottomUp,
+ 'post enter/bottomUp');
+ };
+
+ Driver.prototype.stay = function() {
+ var preTopDownNodes = countNodes(this.profile, this.profile.traverseTopDownTree);
+ var preBottomUpNodes = countNodes(this.profile, this.profile.traverseBottomUpTree);
+ Driver.superClass_.stay.call(this);
+ var postTopDownNodes = countNodes(this.profile, this.profile.traverseTopDownTree);
+ var postBottomUpNodes = countNodes(this.profile, this.profile.traverseBottomUpTree);
+ // Must be no changes in tree layout.
+ assertEquals(preTopDownNodes, postTopDownNodes, 'stay/topDown');
+ assertEquals(preBottomUpNodes, postBottomUpNodes, 'stay/bottomUp');
+ };
+
+ Driver.prototype.leave = function() {
+ Driver.superClass_.leave.call(this);
+ this.namesTopDown.pop();
+ this.namesBottomUp.shift();
+ };
+
+ var testDriver = new Driver();
+ testDriver.execute();
+})();
+
+
+function assertNodeWeights(root, path, selfTicks, totalTicks) {
+ var node = root.descendToChild(path);
+ var stack = stackToString(path);
+ assertNotNull(node, 'node not found: ' + stack);
+ assertEquals(selfTicks, node.selfWeight, 'self of ' + stack);
+ assertEquals(totalTicks, node.totalWeight, 'total of ' + stack);
+};
+
+
+(function testTopDownRootProfileTicks() {
+ var testDriver = new ProfileTestDriver();
+ testDriver.execute();
+
+ var pathWeights = [
+ [['lib1-f1'], 1, 16],
+ [['lib1-f1', 'lib1-f2'], 2, 15],
+ [['lib1-f1', 'lib1-f2', 'T: F1'], 2, 11],
+ [['lib1-f1', 'lib1-f2', 'T: F1', 'T: F2'], 1, 1],
+ [['lib1-f1', 'lib1-f2', 'T: F1', 'lib2-f1'], 2, 3],
+ [['lib1-f1', 'lib1-f2', 'T: F1', 'lib2-f1', 'lib2-f1'], 1, 1],
+ [['lib1-f1', 'lib1-f2', 'T: F1', 'T: F3'], 1, 5],
+ [['lib1-f1', 'lib1-f2', 'T: F1', 'T: F3', 'T: F3'], 1, 4],
+ [['lib1-f1', 'lib1-f2', 'T: F1', 'T: F3', 'T: F3', 'T: F3'], 1, 1],
+ [['lib1-f1', 'lib1-f2', 'T: F1', 'T: F3', 'T: F3', 'T: F2'], 2, 2],
+ [['lib1-f1', 'lib1-f2', 'lib2-f1'], 1, 2],
+ [['lib1-f1', 'lib1-f2', 'lib2-f1', 'lib1-f1'], 1, 1]
+ ];
+
+ var root = testDriver.profile.getTopDownProfile().getRoot();
+ for (var i = 0; i < pathWeights.length; ++i) {
+ var data = pathWeights[i];
+ assertNodeWeights(root, data[0], data[1], data[2]);
+ }
+})();
+
+
+(function testRootFlatProfileTicks() {
+ function Driver() {
+ ProfileTestDriver.call(this);
+ this.namesTopDown = [''];
+ this.counters = {};
+ this.root = null;
+ };
+ Inherits(Driver, ProfileTestDriver);
+
+ Driver.prototype.increment = function(func, self, total) {
+ if (!(func in this.counters)) {
+ this.counters[func] = { self: 0, total: 0 };
+ }
+ this.counters[func].self += self;
+ this.counters[func].total += total;
+ };
+
+ Driver.prototype.incrementTotals = function() {
+ // Only count each function in the stack once.
+ var met = {};
+ for (var i = 0; i < this.namesTopDown.length; ++i) {
+ var name = this.namesTopDown[i];
+ if (!(name in met)) {
+ this.increment(name, 0, 1);
+ }
+ met[name] = true;
+ }
+ };
+
+ Driver.prototype.enter = function(func) {
+ Driver.superClass_.enter.call(this, func);
+ this.namesTopDown.push(func);
+ this.increment(func, 1, 0);
+ this.incrementTotals();
+ };
+
+ Driver.prototype.stay = function() {
+ Driver.superClass_.stay.call(this);
+ this.increment(this.namesTopDown[this.namesTopDown.length - 1], 1, 0);
+ this.incrementTotals();
+ };
+
+ Driver.prototype.leave = function() {
+ Driver.superClass_.leave.call(this);
+ this.namesTopDown.pop();
+ };
+
+ Driver.prototype.extractRoot = function() {
+ assertTrue('' in this.counters);
+ this.root = this.counters[''];
+ delete this.counters[''];
+ };
+
+ var testDriver = new Driver();
+ testDriver.execute();
+ testDriver.extractRoot();
+
+ var counted = 0;
+ for (var c in testDriver.counters) {
+ counted++;
+ }
+
+ var flatProfileRoot = testDriver.profile.getFlatProfile().getRoot();
+ assertEquals(testDriver.root.self, flatProfileRoot.selfWeight);
+ assertEquals(testDriver.root.total, flatProfileRoot.totalWeight);
+
+ var flatProfile = flatProfileRoot.exportChildren();
+ assertEquals(counted, flatProfile.length, 'counted vs. flatProfile');
+ for (var i = 0; i < flatProfile.length; ++i) {
+ var rec = flatProfile[i];
+ assertTrue(rec.label in testDriver.counters, 'uncounted: ' + rec.label);
+ var reference = testDriver.counters[rec.label];
+ assertEquals(reference.self, rec.selfWeight, 'self of ' + rec.label);
+ assertEquals(reference.total, rec.totalWeight, 'total of ' + rec.label);
+ }
+
+})();
+
+
+(function testFunctionCalleesProfileTicks() {
+ var testDriver = new ProfileTestDriver();
+ testDriver.execute();
+
+ var pathWeights = [
+ [['lib2-f1'], 3, 5],
+ [['lib2-f1', 'lib2-f1'], 1, 1],
+ [['lib2-f1', 'lib1-f1'], 1, 1]
+ ];
+
+ var profile = testDriver.profile.getTopDownProfile('lib2-f1');
+ var root = profile.getRoot();
+ for (var i = 0; i < pathWeights.length; ++i) {
+ var data = pathWeights[i];
+ assertNodeWeights(root, data[0], data[1], data[2]);
+ }
+})();
+
+
+(function testFunctionFlatProfileTicks() {
+ var testDriver = new ProfileTestDriver();
+ testDriver.execute();
+
+ var flatWeights = {
+ 'lib2-f1': [1, 1],
+ 'lib1-f1': [1, 1]
+ };
+
+ var flatProfileRoot =
+ testDriver.profile.getFlatProfile('lib2-f1').findOrAddChild('lib2-f1');
+ assertEquals(3, flatProfileRoot.selfWeight);
+ assertEquals(5, flatProfileRoot.totalWeight);
+
+ var flatProfile = flatProfileRoot.exportChildren();
+ assertEquals(2, flatProfile.length, 'counted vs. flatProfile');
+ for (var i = 0; i < flatProfile.length; ++i) {
+ var rec = flatProfile[i];
+ assertTrue(rec.label in flatWeights, 'uncounted: ' + rec.label);
+ var reference = flatWeights[rec.label];
+ assertEquals(reference[0], rec.selfWeight, 'self of ' + rec.label);
+ assertEquals(reference[1], rec.totalWeight, 'total of ' + rec.label);
+ }
+
+})();
+
diff --git a/test/mjsunit/tools/profile_view.js b/test/mjsunit/tools/profile_view.js
new file mode 100644
index 0000000..3ed1128
--- /dev/null
+++ b/test/mjsunit/tools/profile_view.js
@@ -0,0 +1,95 @@
+// Copyright 2009 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 source code files from <project root>/tools.
+// Files: tools/consarray.js tools/profile.js tools/profile_view.js
+
+
+function createNode(name, time, opt_parent) {
+ var node = new devtools.profiler.ProfileView.Node(name, time, time, null);
+ if (opt_parent) {
+ opt_parent.addChild(node);
+ }
+ return node;
+}
+
+
+(function testSorting() {
+ //
+ // Build a tree:
+ // root +--c/5
+ // | |
+ // +--a/2 +--b/3--+--d/4
+ // | | |
+ // +--a/1--+--c/1 +--d/2
+ // | |
+ // +--c/1 +--b/2
+ //
+ // So we can sort it using 2 fields: name and time.
+ var root = createNode('root', 0);
+ createNode('a', 2, root);
+ var a1 = createNode('a', 1, root);
+ createNode('c', 1, root);
+ var b3 = createNode('b', 3, a1);
+ createNode('c', 1, a1);
+ createNode('b', 2, a1);
+ createNode('c', 5, b3);
+ createNode('d', 4, b3);
+ createNode('d', 2, b3);
+
+ var view = new devtools.profiler.ProfileView(root);
+ var flatTree = [];
+
+ function fillFlatTree(node) {
+ flatTree.push(node.internalFuncName);
+ flatTree.push(node.selfTime);
+ }
+
+ view.traverse(fillFlatTree);
+ assertEquals(
+ ['root', 0,
+ 'a', 2, 'a', 1, 'c', 1,
+ 'b', 3, 'c', 1, 'b', 2,
+ 'c', 5, 'd', 4, 'd', 2], flatTree);
+
+ function cmpStrs(s1, s2) {
+ return s1 == s2 ? 0 : (s1 < s2 ? -1 : 1);
+ }
+
+ view.sort(function(n1, n2) {
+ return cmpStrs(n1.internalFuncName, n2.internalFuncName) ||
+ (n1.selfTime - n2.selfTime);
+ });
+
+ flatTree = [];
+ view.traverse(fillFlatTree);
+ assertEquals(
+ ['root', 0,
+ 'a', 1, 'a', 2, 'c', 1,
+ 'b', 2, 'b', 3, 'c', 1,
+ 'c', 5, 'd', 2, 'd', 4], flatTree);
+})();
diff --git a/test/mjsunit/tools/splaytree.js b/test/mjsunit/tools/splaytree.js
new file mode 100644
index 0000000..3beba0b
--- /dev/null
+++ b/test/mjsunit/tools/splaytree.js
@@ -0,0 +1,166 @@
+// Copyright 2009 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 the Splay tree implementation from <project root>/tools.
+// Files: tools/splaytree.js
+
+
+(function testIsEmpty() {
+ var tree = new goog.structs.SplayTree();
+ assertTrue(tree.isEmpty());
+ tree.insert(0, 'value');
+ assertFalse(tree.isEmpty());
+})();
+
+
+(function testExportValues() {
+ var tree = new goog.structs.SplayTree();
+ assertArrayEquals([], tree.exportValues());
+ tree.insert(0, 'value');
+ assertArrayEquals(['value'], tree.exportValues());
+ tree.insert(0, 'value');
+ assertArrayEquals(['value'], tree.exportValues());
+})();
+
+
+function createSampleTree() {
+ // Creates the following tree:
+ // 50
+ // / \
+ // 30 60
+ // / \ \
+ // 10 40 90
+ // \ / \
+ // 20 70 100
+ // / \
+ // 15 80
+ //
+ // We can't use the 'insert' method because it also uses 'splay_'.
+ return { key: 50, value: 50,
+ left: { key: 30, value: 30,
+ left: { key: 10, value: 10, left: null,
+ right: { key: 20, value: 20,
+ left: { key: 15, value: 15,
+ left: null, right: null },
+ right: null } },
+ right: { key: 40, value: 40, left: null, right: null } },
+ right: { key: 60, value: 60, left: null,
+ right: { key: 90, value: 90,
+ left: { key: 70, value: 70, left: null,
+ right: { key: 80, value: 80,
+ left: null, right: null } },
+ right: { key: 100, value: 100,
+ left: null, right: null } } } };
+};
+
+
+(function testSplay() {
+ var tree = new goog.structs.SplayTree();
+ tree.root_ = createSampleTree();
+ assertArrayEquals(['50', '30', '60', '10', '40', '90', '20', '70', '100', '15', '80'],
+ tree.exportValues());
+ tree.splay_(50);
+ assertArrayEquals(['50', '30', '60', '10', '40', '90', '20', '70', '100', '15', '80'],
+ tree.exportValues());
+ tree.splay_(80);
+ assertArrayEquals(['80', '60', '90', '50', '70', '100', '30', '10', '40', '20', '15'],
+ tree.exportValues());
+})();
+
+
+(function testInsert() {
+ var tree = new goog.structs.SplayTree();
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ assertArrayEquals(['left', 'root'], tree.exportValues());
+ tree.insert(7, 'right');
+ assertArrayEquals(['right', 'root', 'left'], tree.exportValues());
+})();
+
+
+(function testFind() {
+ var tree = new goog.structs.SplayTree();
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ tree.insert(7, 'right');
+ assertEquals('root', tree.find(5).value);
+ assertEquals('left', tree.find(3).value);
+ assertEquals('right', tree.find(7).value);
+ assertEquals(null, tree.find(0));
+ assertEquals(null, tree.find(100));
+ assertEquals(null, tree.find(-100));
+})();
+
+
+(function testFindMin() {
+ var tree = new goog.structs.SplayTree();
+ assertEquals(null, tree.findMin());
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ tree.insert(7, 'right');
+ assertEquals('left', tree.findMin().value);
+})();
+
+
+(function testFindMax() {
+ var tree = new goog.structs.SplayTree();
+ assertEquals(null, tree.findMax());
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ tree.insert(7, 'right');
+ assertEquals('right', tree.findMax().value);
+})();
+
+
+(function testFindGreatestLessThan() {
+ var tree = new goog.structs.SplayTree();
+ assertEquals(null, tree.findGreatestLessThan(10));
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ tree.insert(7, 'right');
+ assertEquals('right', tree.findGreatestLessThan(10).value);
+ assertEquals('right', tree.findGreatestLessThan(7).value);
+ assertEquals('root', tree.findGreatestLessThan(6).value);
+ assertEquals('left', tree.findGreatestLessThan(4).value);
+ assertEquals(null, tree.findGreatestLessThan(2));
+})();
+
+
+(function testRemove() {
+ var tree = new goog.structs.SplayTree();
+ assertThrows('tree.remove(5)');
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ tree.insert(7, 'right');
+ assertThrows('tree.remove(1)');
+ assertThrows('tree.remove(6)');
+ assertThrows('tree.remove(10)');
+ assertEquals('root', tree.remove(5).value);
+ assertEquals('left', tree.remove(3).value);
+ assertEquals('right', tree.remove(7).value);
+ assertArrayEquals([], tree.exportValues());
+})();
diff --git a/test/mjsunit/tools/tickprocessor-test.default b/test/mjsunit/tools/tickprocessor-test.default
new file mode 100644
index 0000000..702f4bc
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor-test.default
@@ -0,0 +1,55 @@
+Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
+
+ [Unknown]:
+ ticks total nonlib name
+ 2 15.4%
+
+ [Shared libraries]:
+ ticks total nonlib name
+ 3 23.1% 0.0% /lib32/libm-2.7.so
+ 1 7.7% 0.0% ffffe000-fffff000
+
+ [JavaScript]:
+ ticks total nonlib name
+ 1 7.7% 11.1% LazyCompile: exp native math.js:41
+
+ [C++]:
+ ticks total nonlib name
+ 2 15.4% 22.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+ 1 7.7% 11.1% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+ 1 7.7% 11.1% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+ 1 7.7% 11.1% exp
+
+ [GC]:
+ ticks total nonlib name
+ 0 0.0%
+
+ [Bottom up (heavy) profile]:
+ Note: percentage shows a share of a particular caller in the total
+ amount of its parent calls.
+ Callers occupying less than 2.0% are not shown.
+
+ ticks parent name
+ 3 23.1% /lib32/libm-2.7.so
+ 3 100.0% LazyCompile: exp native math.js:41
+ 3 100.0% Script: exp.js
+
+ 2 15.4% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+ 2 100.0% LazyCompile: exp native math.js:41
+ 2 100.0% Script: exp.js
+
+ 1 7.7% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+ 1 100.0% Script: exp.js
+
+ 1 7.7% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+ 1 100.0% Script: exp.js
+
+ 1 7.7% ffffe000-fffff000
+
+ 1 7.7% exp
+ 1 100.0% LazyCompile: exp native math.js:41
+ 1 100.0% Script: exp.js
+
+ 1 7.7% LazyCompile: exp native math.js:41
+ 1 100.0% Script: exp.js
+
diff --git a/test/mjsunit/tools/tickprocessor-test.gc-state b/test/mjsunit/tools/tickprocessor-test.gc-state
new file mode 100644
index 0000000..40f90db
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor-test.gc-state
@@ -0,0 +1,21 @@
+Statistical profiling result from v8.log, (13 ticks, 0 unaccounted, 13 excluded).
+
+ [Shared libraries]:
+ ticks total nonlib name
+
+ [JavaScript]:
+ ticks total nonlib name
+
+ [C++]:
+ ticks total nonlib name
+
+ [GC]:
+ ticks total nonlib name
+ 0 0.0%
+
+ [Bottom up (heavy) profile]:
+ Note: percentage shows a share of a particular caller in the total
+ amount of its parent calls.
+ Callers occupying less than 2.0% are not shown.
+
+ ticks parent name
diff --git a/test/mjsunit/tools/tickprocessor-test.ignore-unknown b/test/mjsunit/tools/tickprocessor-test.ignore-unknown
new file mode 100644
index 0000000..306d646
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor-test.ignore-unknown
@@ -0,0 +1,51 @@
+Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
+
+ [Shared libraries]:
+ ticks total nonlib name
+ 3 27.3% 0.0% /lib32/libm-2.7.so
+ 1 9.1% 0.0% ffffe000-fffff000
+
+ [JavaScript]:
+ ticks total nonlib name
+ 1 9.1% 14.3% LazyCompile: exp native math.js:41
+
+ [C++]:
+ ticks total nonlib name
+ 2 18.2% 28.6% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+ 1 9.1% 14.3% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+ 1 9.1% 14.3% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+ 1 9.1% 14.3% exp
+
+ [GC]:
+ ticks total nonlib name
+ 0 0.0%
+
+ [Bottom up (heavy) profile]:
+ Note: percentage shows a share of a particular caller in the total
+ amount of its parent calls.
+ Callers occupying less than 2.0% are not shown.
+
+ ticks parent name
+ 3 27.3% /lib32/libm-2.7.so
+ 3 100.0% LazyCompile: exp native math.js:41
+ 3 100.0% Script: exp.js
+
+ 2 18.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+ 2 100.0% LazyCompile: exp native math.js:41
+ 2 100.0% Script: exp.js
+
+ 1 9.1% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+ 1 100.0% Script: exp.js
+
+ 1 9.1% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+ 1 100.0% Script: exp.js
+
+ 1 9.1% ffffe000-fffff000
+
+ 1 9.1% exp
+ 1 100.0% LazyCompile: exp native math.js:41
+ 1 100.0% Script: exp.js
+
+ 1 9.1% LazyCompile: exp native math.js:41
+ 1 100.0% Script: exp.js
+
diff --git a/test/mjsunit/tools/tickprocessor-test.log b/test/mjsunit/tools/tickprocessor-test.log
new file mode 100644
index 0000000..75daad6
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor-test.log
@@ -0,0 +1,24 @@
+shared-library,"shell",0x08048000,0x081ee000
+shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000
+shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000
+profiler,"begin",1
+code-creation,Stub,0xf540a100,474,"CEntryStub"
+code-creation,Script,0xf541cd80,736,"exp.js"
+code-creation,Stub,0xf541d0e0,47,"RuntimeStub_Math_exp"
+code-creation,LazyCompile,0xf541d120,145,"exp native math.js:41"
+code-creation,LoadIC,0xf541d280,117,"j"
+code-creation,LoadIC,0xf541d360,63,"i"
+tick,0x80f82d1,0xffdfe880,0,0xf541ce5c
+tick,0x80f89a1,0xffdfecf0,0,0xf541ce5c
+tick,0x8123b5c,0xffdff1a0,0,0xf541d1a1,0xf541ceea
+tick,0x8123b65,0xffdff1a0,0,0xf541d1a1,0xf541ceea
+tick,0xf541d2be,0xffdff1e4,0
+tick,0xf541d320,0xffdff1dc,0
+tick,0xf541d384,0xffdff1d8,0
+tick,0xf7db94da,0xffdff0ec,0,0xf541d1a1,0xf541ceea
+tick,0xf7db951c,0xffdff0f0,0,0xf541d1a1,0xf541ceea
+tick,0xf7dbc508,0xffdff14c,0,0xf541d1a1,0xf541ceea
+tick,0xf7dbff21,0xffdff198,0,0xf541d1a1,0xf541ceea
+tick,0xf7edec90,0xffdff0ec,0,0xf541d1a1,0xf541ceea
+tick,0xffffe402,0xffdff488,0
+profiler,"end"
diff --git a/test/mjsunit/tools/tickprocessor-test.separate-ic b/test/mjsunit/tools/tickprocessor-test.separate-ic
new file mode 100644
index 0000000..3a2041b
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor-test.separate-ic
@@ -0,0 +1,61 @@
+Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
+
+ [Unknown]:
+ ticks total nonlib name
+ 2 15.4%
+
+ [Shared libraries]:
+ ticks total nonlib name
+ 3 23.1% 0.0% /lib32/libm-2.7.so
+ 1 7.7% 0.0% ffffe000-fffff000
+
+ [JavaScript]:
+ ticks total nonlib name
+ 1 7.7% 11.1% LoadIC: j
+ 1 7.7% 11.1% LoadIC: i
+ 1 7.7% 11.1% LazyCompile: exp native math.js:41
+
+ [C++]:
+ ticks total nonlib name
+ 2 15.4% 22.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+ 1 7.7% 11.1% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+ 1 7.7% 11.1% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+ 1 7.7% 11.1% exp
+
+ [GC]:
+ ticks total nonlib name
+ 0 0.0%
+
+ [Bottom up (heavy) profile]:
+ Note: percentage shows a share of a particular caller in the total
+ amount of its parent calls.
+ Callers occupying less than 2.0% are not shown.
+
+ ticks parent name
+ 3 23.1% /lib32/libm-2.7.so
+ 3 100.0% LazyCompile: exp native math.js:41
+ 3 100.0% Script: exp.js
+
+ 2 15.4% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+ 2 100.0% LazyCompile: exp native math.js:41
+ 2 100.0% Script: exp.js
+
+ 1 7.7% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+ 1 100.0% Script: exp.js
+
+ 1 7.7% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+ 1 100.0% Script: exp.js
+
+ 1 7.7% ffffe000-fffff000
+
+ 1 7.7% exp
+ 1 100.0% LazyCompile: exp native math.js:41
+ 1 100.0% Script: exp.js
+
+ 1 7.7% LoadIC: j
+
+ 1 7.7% LoadIC: i
+
+ 1 7.7% LazyCompile: exp native math.js:41
+ 1 100.0% Script: exp.js
+
diff --git a/test/mjsunit/tools/tickprocessor.js b/test/mjsunit/tools/tickprocessor.js
new file mode 100644
index 0000000..83bdac8
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor.js
@@ -0,0 +1,409 @@
+// Copyright 2009 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 tools/tickprocessor.js
+// Env: TEST_FILE_NAME
+
+
+(function testArgumentsProcessor() {
+ var p_default = new ArgumentsProcessor([]);
+ assertTrue(p_default.parse());
+ assertEquals(ArgumentsProcessor.DEFAULTS, p_default.result());
+
+ var p_logFile = new ArgumentsProcessor(['logfile.log']);
+ assertTrue(p_logFile.parse());
+ assertEquals('logfile.log', p_logFile.result().logFileName);
+
+ var p_platformAndLog = new ArgumentsProcessor(['--windows', 'winlog.log']);
+ assertTrue(p_platformAndLog.parse());
+ assertEquals('windows', p_platformAndLog.result().platform);
+ assertEquals('winlog.log', p_platformAndLog.result().logFileName);
+
+ var p_flags = new ArgumentsProcessor(['--gc', '--separate-ic']);
+ assertTrue(p_flags.parse());
+ assertEquals(TickProcessor.VmStates.GC, p_flags.result().stateFilter);
+ assertTrue(p_flags.result().separateIc);
+
+ var p_nmAndLog = new ArgumentsProcessor(['--nm=mn', 'nmlog.log']);
+ assertTrue(p_nmAndLog.parse());
+ assertEquals('mn', p_nmAndLog.result().nm);
+ assertEquals('nmlog.log', p_nmAndLog.result().logFileName);
+
+ var p_bad = new ArgumentsProcessor(['--unknown', 'badlog.log']);
+ assertFalse(p_bad.parse());
+})();
+
+
+(function testUnixCppEntriesProvider() {
+ var oldLoadSymbols = UnixCppEntriesProvider.prototype.loadSymbols;
+
+ // shell executable
+ UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
+ this.symbols = [[
+ ' U operator delete[](void*)@@GLIBCXX_3.4',
+ '08049790 T _init',
+ '08049f50 T _start',
+ '08139150 00000b4b t v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)',
+ '08139ca0 000003f1 T v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)',
+ '0813a0b0 00000855 t v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)',
+ '0818b220 00000036 W v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)',
+ ' w __gmon_start__',
+ '081f08a0 00000004 B stdout\n'
+ ].join('\n'), ''];
+ };
+
+ var shell_prov = new UnixCppEntriesProvider();
+ var shell_syms = [];
+ shell_prov.parseVmSymbols('shell', 0x08048000, 0x081ee000,
+ function (name, start, end) {
+ shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ assertEquals(
+ [['_init', 0x08049790, 0x08049f50],
+ ['_start', 0x08049f50, 0x08139150],
+ ['v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', 0x08139150, 0x08139150 + 0xb4b],
+ ['v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)', 0x08139ca0, 0x08139ca0 + 0x3f1],
+ ['v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', 0x0813a0b0, 0x0813a0b0 + 0x855],
+ ['v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)', 0x0818b220, 0x0818b220 + 0x36]],
+ shell_syms);
+
+ // libc library
+ UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
+ this.symbols = [[
+ '000162a0 00000005 T __libc_init_first',
+ '0002a5f0 0000002d T __isnan',
+ '0002a5f0 0000002d W isnan',
+ '0002aaa0 0000000d W scalblnf',
+ '0002aaa0 0000000d W scalbnf',
+ '0011a340 00000048 T __libc_thread_freeres',
+ '00128860 00000024 R _itoa_lower_digits\n'].join('\n'), ''];
+ };
+ var libc_prov = new UnixCppEntriesProvider();
+ var libc_syms = [];
+ libc_prov.parseVmSymbols('libc', 0xf7c5c000, 0xf7da5000,
+ function (name, start, end) {
+ libc_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ var libc_ref_syms = [['__libc_init_first', 0x000162a0, 0x000162a0 + 0x5],
+ ['__isnan', 0x0002a5f0, 0x0002a5f0 + 0x2d],
+ ['scalblnf', 0x0002aaa0, 0x0002aaa0 + 0xd],
+ ['__libc_thread_freeres', 0x0011a340, 0x0011a340 + 0x48]];
+ for (var i = 0; i < libc_ref_syms.length; ++i) {
+ libc_ref_syms[i][1] += 0xf7c5c000;
+ libc_ref_syms[i][2] += 0xf7c5c000;
+ }
+ assertEquals(libc_ref_syms, libc_syms);
+
+ UnixCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
+})();
+
+
+(function testMacCppEntriesProvider() {
+ var oldLoadSymbols = MacCppEntriesProvider.prototype.loadSymbols;
+
+ // shell executable
+ MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
+ this.symbols = [[
+ ' U operator delete[]',
+ '00001000 A __mh_execute_header',
+ '00001b00 T start',
+ '00001b40 t dyld_stub_binding_helper',
+ '0011b710 T v8::internal::RegExpMacroAssembler::CheckPosition',
+ '00134250 t v8::internal::Runtime_StringReplaceRegExpWithString',
+ '00137220 T v8::internal::Runtime::GetElementOrCharAt',
+ '00137400 t v8::internal::Runtime_DebugGetPropertyDetails',
+ '001c1a80 b _private_mem\n'
+ ].join('\n'), ''];
+ };
+
+ var shell_prov = new MacCppEntriesProvider();
+ var shell_syms = [];
+ shell_prov.parseVmSymbols('shell', 0x00001b00, 0x00163156,
+ function (name, start, end) {
+ shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ assertEquals(
+ [['start', 0x00001b00, 0x00001b40],
+ ['dyld_stub_binding_helper', 0x00001b40, 0x0011b710],
+ ['v8::internal::RegExpMacroAssembler::CheckPosition', 0x0011b710, 0x00134250],
+ ['v8::internal::Runtime_StringReplaceRegExpWithString', 0x00134250, 0x00137220],
+ ['v8::internal::Runtime::GetElementOrCharAt', 0x00137220, 0x00137400],
+ ['v8::internal::Runtime_DebugGetPropertyDetails', 0x00137400, 0x00163156]],
+ shell_syms);
+
+ // stdc++ library
+ MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
+ this.symbols = [[
+ '0000107a T __gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector',
+ '0002c410 T std::basic_streambuf<char, std::char_traits<char> >::pubseekoff',
+ '0002c488 T std::basic_streambuf<char, std::char_traits<char> >::pubseekpos',
+ '000466aa T ___cxa_pure_virtual\n'].join('\n'), ''];
+ };
+ var stdc_prov = new MacCppEntriesProvider();
+ var stdc_syms = [];
+ stdc_prov.parseVmSymbols('stdc++', 0x95728fb4, 0x95770005,
+ function (name, start, end) {
+ stdc_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ var stdc_ref_syms = [['__gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector', 0x0000107a, 0x0002c410],
+ ['std::basic_streambuf<char, std::char_traits<char> >::pubseekoff', 0x0002c410, 0x0002c488],
+ ['std::basic_streambuf<char, std::char_traits<char> >::pubseekpos', 0x0002c488, 0x000466aa],
+ ['___cxa_pure_virtual', 0x000466aa, 0x95770005 - 0x95728fb4]];
+ for (var i = 0; i < stdc_ref_syms.length; ++i) {
+ stdc_ref_syms[i][1] += 0x95728fb4;
+ stdc_ref_syms[i][2] += 0x95728fb4;
+ }
+ assertEquals(stdc_ref_syms, stdc_syms);
+
+ MacCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
+})();
+
+
+(function testWindowsCppEntriesProvider() {
+ var oldLoadSymbols = WindowsCppEntriesProvider.prototype.loadSymbols;
+
+ WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) {
+ this.symbols = [
+ ' Start Length Name Class',
+ ' 0001:00000000 000ac902H .text CODE',
+ ' 0001:000ac910 000005e2H .text$yc CODE',
+ ' Address Publics by Value Rva+Base Lib:Object',
+ ' 0000:00000000 __except_list 00000000 <absolute>',
+ ' 0001:00000000 ?ReadFile@@YA?AV?$Handle@VString@v8@@@v8@@PBD@Z 00401000 f shell.obj',
+ ' 0001:000000a0 ?Print@@YA?AV?$Handle@VValue@v8@@@v8@@ABVArguments@2@@Z 004010a0 f shell.obj',
+ ' 0001:00001230 ??1UTF8Buffer@internal@v8@@QAE@XZ 00402230 f v8_snapshot:scanner.obj',
+ ' 0001:00001230 ??1Utf8Value@String@v8@@QAE@XZ 00402230 f v8_snapshot:api.obj',
+ ' 0001:000954ba __fclose_nolock 004964ba f LIBCMT:fclose.obj',
+ ' 0002:00000000 __imp__SetThreadPriority@8 004af000 kernel32:KERNEL32.dll',
+ ' 0003:00000418 ?in_use_list_@PreallocatedStorage@internal@v8@@0V123@A 00544418 v8_snapshot:allocation.obj',
+ ' Static symbols',
+ ' 0001:00000b70 ?DefaultFatalErrorHandler@v8@@YAXPBD0@Z 00401b70 f v8_snapshot:api.obj',
+ ' 0001:000010b0 ?EnsureInitialized@v8@@YAXPBD@Z 004020b0 f v8_snapshot:api.obj',
+ ' 0001:000ad17b ??__Fnomem@?5???2@YAPAXI@Z@YAXXZ 004ae17b f LIBCMT:new.obj'
+ ].join('\r\n');
+ };
+ var shell_prov = new WindowsCppEntriesProvider();
+ var shell_syms = [];
+ shell_prov.parseVmSymbols('shell.exe', 0x00400000, 0x0057c000,
+ function (name, start, end) {
+ shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ assertEquals(
+ [['ReadFile', 0x00401000, 0x004010a0],
+ ['Print', 0x004010a0, 0x00402230],
+ ['v8::String::?1Utf8Value', 0x00402230, 0x004964ba],
+ ['v8::DefaultFatalErrorHandler', 0x00401b70, 0x004020b0],
+ ['v8::EnsureInitialized', 0x004020b0, 0x0057c000]],
+ shell_syms);
+
+ WindowsCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
+})();
+
+
+// http://code.google.com/p/v8/issues/detail?id=427
+(function testWindowsProcessExeAndDllMapFile() {
+ function exeSymbols(exeName) {
+ return [
+ ' 0000:00000000 ___ImageBase 00400000 <linker-defined>',
+ ' 0001:00000780 ?RunMain@@YAHHQAPAD@Z 00401780 f shell.obj',
+ ' 0001:00000ac0 _main 00401ac0 f shell.obj',
+ ''
+ ].join('\r\n');
+ }
+
+ function dllSymbols(dllName) {
+ return [
+ ' 0000:00000000 ___ImageBase 01c30000 <linker-defined>',
+ ' 0001:00000780 _DllMain@12 01c31780 f libcmt:dllmain.obj',
+ ' 0001:00000ac0 ___DllMainCRTStartup 01c31ac0 f libcmt:dllcrt0.obj',
+ ''
+ ].join('\r\n');
+ }
+
+ var oldRead = read;
+
+ read = exeSymbols;
+ var exe_exe_syms = [];
+ (new WindowsCppEntriesProvider()).parseVmSymbols(
+ 'chrome.exe', 0x00400000, 0x00472000,
+ function (name, start, end) {
+ exe_exe_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ assertEquals(
+ [['RunMain', 0x00401780, 0x00401ac0],
+ ['_main', 0x00401ac0, 0x00472000]],
+ exe_exe_syms, '.exe with .exe symbols');
+
+ read = dllSymbols;
+ var exe_dll_syms = [];
+ (new WindowsCppEntriesProvider()).parseVmSymbols(
+ 'chrome.exe', 0x00400000, 0x00472000,
+ function (name, start, end) {
+ exe_dll_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ assertEquals(
+ [],
+ exe_dll_syms, '.exe with .dll symbols');
+
+ read = dllSymbols;
+ var dll_dll_syms = [];
+ (new WindowsCppEntriesProvider()).parseVmSymbols(
+ 'chrome.dll', 0x01c30000, 0x02b80000,
+ function (name, start, end) {
+ dll_dll_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ assertEquals(
+ [['_DllMain@12', 0x01c31780, 0x01c31ac0],
+ ['___DllMainCRTStartup', 0x01c31ac0, 0x02b80000]],
+ dll_dll_syms, '.dll with .dll symbols');
+
+ read = exeSymbols;
+ var dll_exe_syms = [];
+ (new WindowsCppEntriesProvider()).parseVmSymbols(
+ 'chrome.dll', 0x01c30000, 0x02b80000,
+ function (name, start, end) {
+ dll_exe_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ assertEquals(
+ [],
+ dll_exe_syms, '.dll with .exe symbols');
+
+ read = oldRead;
+})();
+
+
+function CppEntriesProviderMock() {
+};
+
+
+CppEntriesProviderMock.prototype.parseVmSymbols = function(
+ name, startAddr, endAddr, symbolAdder) {
+ var symbols = {
+ 'shell':
+ [['v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)', 0x080f8800, 0x080f8d90],
+ ['v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)', 0x080f8210, 0x080f8800],
+ ['v8::internal::Runtime_Math_exp(v8::internal::Arguments)', 0x08123b20, 0x08123b80]],
+ '/lib32/libm-2.7.so':
+ [['exp', startAddr + 0x00009e80, startAddr + 0x00009e80 + 0xa3],
+ ['fegetexcept', startAddr + 0x000061e0, startAddr + 0x000061e0 + 0x15]],
+ 'ffffe000-fffff000': []};
+ assertTrue(name in symbols);
+ var syms = symbols[name];
+ for (var i = 0; i < syms.length; ++i) {
+ symbolAdder.apply(null, syms[i]);
+ }
+};
+
+
+function PrintMonitor(outputOrFileName) {
+ var expectedOut = typeof outputOrFileName == 'string' ?
+ this.loadExpectedOutput(outputOrFileName) : outputOrFileName;
+ var outputPos = 0;
+ var diffs = this.diffs = [];
+ var realOut = this.realOut = [];
+ var unexpectedOut = this.unexpectedOut = null;
+
+ this.oldPrint = print;
+ print = function(str) {
+ var strSplit = str.split('\n');
+ for (var i = 0; i < strSplit.length; ++i) {
+ s = strSplit[i];
+ realOut.push(s);
+ if (outputPos < expectedOut.length) {
+ if (expectedOut[outputPos] != s) {
+ diffs.push('line ' + outputPos + ': expected <' +
+ expectedOut[outputPos] + '> found <' + s + '>\n');
+ }
+ outputPos++;
+ } else {
+ unexpectedOut = true;
+ }
+ }
+ };
+};
+
+
+PrintMonitor.prototype.loadExpectedOutput = function(fileName) {
+ var output = readFile(fileName);
+ return output.split('\n');
+};
+
+
+PrintMonitor.prototype.finish = function() {
+ print = this.oldPrint;
+ if (this.diffs.length > 0 || this.unexpectedOut != null) {
+ print(this.realOut.join('\n'));
+ assertEquals([], this.diffs);
+ assertNull(this.unexpectedOut);
+ }
+};
+
+
+function driveTickProcessorTest(
+ separateIc, ignoreUnknown, stateFilter, logInput, refOutput) {
+ // TEST_FILE_NAME must be provided by test runner.
+ assertEquals('string', typeof TEST_FILE_NAME);
+ var pathLen = TEST_FILE_NAME.lastIndexOf('/');
+ if (pathLen == -1) {
+ pathLen = TEST_FILE_NAME.lastIndexOf('\\');
+ }
+ assertTrue(pathLen != -1);
+ var testsPath = TEST_FILE_NAME.substr(0, pathLen + 1);
+ var tp = new TickProcessor(
+ new CppEntriesProviderMock(), separateIc, ignoreUnknown, stateFilter);
+ var pm = new PrintMonitor(testsPath + refOutput);
+ tp.processLogFile(testsPath + logInput);
+ // Hack file name to avoid dealing with platform specifics.
+ tp.lastLogFileName_ = 'v8.log';
+ tp.printStatistics();
+ pm.finish();
+};
+
+
+(function testProcessing() {
+ var testData = {
+ 'Default': [
+ false, false, null,
+ 'tickprocessor-test.log', 'tickprocessor-test.default'],
+ 'SeparateIc': [
+ true, false, null,
+ 'tickprocessor-test.log', 'tickprocessor-test.separate-ic'],
+ 'IgnoreUnknown': [
+ false, true, null,
+ 'tickprocessor-test.log', 'tickprocessor-test.ignore-unknown'],
+ 'GcState': [
+ false, false, TickProcessor.VmStates.GC,
+ 'tickprocessor-test.log', 'tickprocessor-test.gc-state']
+ };
+ for (var testName in testData) {
+ print('=== testProcessing-' + testName + ' ===');
+ driveTickProcessorTest.apply(null, testData[testName]);
+ }
+})();