mirror of
				https://github.com/tc39/test262.git
				synced 2025-11-04 05:33:50 +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);
 | 
						|
  }
 | 
						|
 | 
						|
})();
 |