mirror of
				https://github.com/tc39/test262.git
				synced 2025-10-27 01:33:59 +01:00 
			
		
		
		
	sourceRevisionAtLastExport: 33f2fb0e53d135f0ee17cfccd9d993eb2a6f47de targetRevisionAtLastExport: 31340cbd9add103f586d501b0c3354b7b182abc0
		
			
				
	
	
		
			348 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			348 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // 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 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', 1, 0x50100, 0x100);
 | |
|   this.profile.addCode('T', 'F2', 2, 0x50200, 0x100);
 | |
|   this.profile.addCode('T', 'F3', 3, 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(0, 0, this.stack_);
 | |
| };
 | |
| 
 | |
| 
 | |
| ProfileTestDriver.prototype.stay = function() {
 | |
|   this.profile.recordTick(0, 0, 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);
 | |
|   }
 | |
| 
 | |
| })();
 |