165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// Copyright 2009 the V8 project authors. All rights reserved.
265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// Redistribution and use in source and binary forms, with or without
365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// modification, are permitted provided that the following conditions are
465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// met:
565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//
665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//     * Redistributions of source code must retain the above copyright
765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//       notice, this list of conditions and the following disclaimer.
865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//     * Redistributions in binary form must reproduce the above
965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//       copyright notice, this list of conditions and the following
1065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//       disclaimer in the documentation and/or other materials provided
1165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//       with the distribution.
1265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//     * Neither the name of Google Inc. nor the names of its
1365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//       contributors may be used to endorse or promote products derived
1465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//       from this software without specific prior written permission.
1565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org//
1665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
2865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
2965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
3065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Creates a profile object for processing profiling-related events
3165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * and calculating function execution times.
3265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
3365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @constructor
3465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
35496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgfunction Profile() {
36496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  this.codeMap_ = new CodeMap();
37496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  this.topDownTree_ = new CallTree();
38496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  this.bottomUpTree_ = new CallTree();
3965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
4065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
4165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
4265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
4365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Returns whether a function with the specified name must be skipped.
4465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Should be overriden by subclasses.
4565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
4665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {string} name Function name.
4765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
48496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.skipThisFunction = function(name) {
4965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  return false;
5065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
5165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
5265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
5365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
543a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * Enum for profiler operations that involve looking up existing
553a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * code entries.
563a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *
573a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * @enum {number}
583a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org */
59496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.Operation = {
603a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  MOVE: 0,
613a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  DELETE: 1,
623a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  TICK: 2
633a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org};
643a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org
653a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org
663a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org/**
673a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * Enum for code state regarding its dynamic optimization.
683a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org *
693a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @enum {number}
703a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org */
713a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgProfile.CodeState = {
723a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  COMPILED: 0,
733a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  OPTIMIZABLE: 1,
743a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  OPTIMIZED: 2
753a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org};
763a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
773a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
783a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org/**
7965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Called whenever the specified operation has failed finding a function
8065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * containing the specified address. Should be overriden by subclasses.
81496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * See the Profile.Operation enum for the list of
823a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * possible operations.
8365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
843a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * @param {number} operation Operation.
8565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {number} addr Address of the unknown code.
863a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * @param {number} opt_stackPos If an unknown address is encountered
873a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *     during stack strace processing, specifies a position of the frame
883a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *     containing the address.
8965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
90496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.handleUnknownCode = function(
913a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org    operation, addr, opt_stackPos) {
9265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
9365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
9465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
9565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
96e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org * Registers a library.
97e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org *
98e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org * @param {string} name Code entry name.
99e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org * @param {number} startAddr Starting address.
100e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org * @param {number} endAddr Ending address.
101e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org */
102496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.addLibrary = function(
103e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org    name, startAddr, endAddr) {
104496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  var entry = new CodeMap.CodeEntry(
105e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org      endAddr - startAddr, name);
106e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org  this.codeMap_.addLibrary(startAddr, entry);
107e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org  return entry;
108e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org};
109e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org
110e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org
111e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org/**
112e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org * Registers statically compiled code entry.
11365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
11465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {string} name Code entry name.
11565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {number} startAddr Starting address.
11665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {number} endAddr Ending address.
11765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
118496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.addStaticCode = function(
11965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    name, startAddr, endAddr) {
120496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  var entry = new CodeMap.CodeEntry(
1213a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org      endAddr - startAddr, name);
1223a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  this.codeMap_.addStaticCode(startAddr, entry);
1233a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  return entry;
12465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
12565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
12665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
12765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
12865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Registers dynamic (JIT-compiled) code entry.
12965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
13065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {string} type Code entry type.
13165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {string} name Code entry name.
13265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {number} start Starting address.
13365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {number} size Code entry size.
13465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
135496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.addCode = function(
13665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    type, name, start, size) {
137496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  var entry = new Profile.DynamicCodeEntry(size, type, name);
1383a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  this.codeMap_.addCode(start, entry);
1393a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  return entry;
14065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
14165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
14265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
14365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
1443a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * Registers dynamic (JIT-compiled) code entry.
145b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org *
1463a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {string} type Code entry type.
1473a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {string} name Code entry name.
1483a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {number} start Starting address.
1493a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {number} size Code entry size.
1503a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {number} funcAddr Shared function object address.
1513a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {Profile.CodeState} state Optimization state.
1523a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org */
1533a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgProfile.prototype.addFuncCode = function(
1543a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org    type, name, start, size, funcAddr, state) {
1553a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  // As code and functions are in the same address space,
1563a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  // it is safe to put them in a single code map.
1573a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
1583a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  if (!func) {
1593a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org    func = new Profile.FunctionEntry(name);
1603a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org    this.codeMap_.addCode(funcAddr, func);
1613a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  } else if (func.name !== name) {
1623a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org    // Function object has been overwritten with a new one.
1633a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org    func.name = name;
164b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org  }
165030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  var entry = this.codeMap_.findDynamicEntryByStartAddress(start);
166030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  if (entry) {
167030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    if (entry.size === size && entry.func === func) {
168030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org      // Entry state has changed.
169030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org      entry.state = state;
170030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    }
171030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  } else {
172030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    entry = new Profile.DynamicFuncCodeEntry(size, type, func, state);
173030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    this.codeMap_.addCode(start, entry);
174030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  }
1753a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  return entry;
176b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org};
177b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
178b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
179b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org/**
18065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Reports about moving of a dynamic code entry.
18165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
18265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {number} from Current code entry address.
18365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {number} to New code entry address.
18465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
185496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.moveCode = function(from, to) {
18665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  try {
18765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    this.codeMap_.moveCode(from, to);
18865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  } catch (e) {
189496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org    this.handleUnknownCode(Profile.Operation.MOVE, from);
19065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
19165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
19265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
19365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
19465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
19565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Reports about deletion of a dynamic code entry.
19665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
19765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {number} start Starting address.
19865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
199496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.deleteCode = function(start) {
20065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  try {
20165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    this.codeMap_.deleteCode(start);
20265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  } catch (e) {
203496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org    this.handleUnknownCode(Profile.Operation.DELETE, start);
20465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
20565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
20665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
20765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
20865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
209b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org * Reports about moving of a dynamic code entry.
210b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org *
211b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org * @param {number} from Current code entry address.
212b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org * @param {number} to New code entry address.
213b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org */
2143a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgProfile.prototype.moveFunc = function(from, to) {
215b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org  if (this.codeMap_.findDynamicEntryByStartAddress(from)) {
216b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org    this.codeMap_.moveCode(from, to);
217b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org  }
218b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org};
219b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
220b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
221b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org/**
222b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org * Retrieves a code entry by an address.
223b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org *
224b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org * @param {number} addr Entry address.
225b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org */
226496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.findEntry = function(addr) {
227b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org  return this.codeMap_.findEntry(addr);
228b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org};
229b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
230b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
231b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org/**
23265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Records a tick event. Stack must contain a sequence of
23365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * addresses starting with the program counter value.
23465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
23565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {Array<number>} stack Stack sample.
23665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
237496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.recordTick = function(stack) {
23865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  var processedStack = this.resolveAndFilterFuncs_(stack);
23965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.bottomUpTree_.addPath(processedStack);
24065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  processedStack.reverse();
24165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.topDownTree_.addPath(processedStack);
24265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
24365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
24465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
24565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
24665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Translates addresses into function names and filters unneeded
24765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * functions.
24865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
24965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {Array<number>} stack Stack sample.
25065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
251496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.resolveAndFilterFuncs_ = function(stack) {
25265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  var result = [];
25365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  for (var i = 0; i < stack.length; ++i) {
25465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    var entry = this.codeMap_.findEntry(stack[i]);
25565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    if (entry) {
25665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org      var name = entry.getName();
25765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org      if (!this.skipThisFunction(name)) {
25865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org        result.push(name);
25965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org      }
26065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    } else {
2613a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org      this.handleUnknownCode(
262496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org          Profile.Operation.TICK, stack[i], i);
26365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    }
26465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
26565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  return result;
26665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
26765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
26865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
26965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
2705ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Performs a BF traversal of the top down call graph.
27165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
272496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(CallTree.Node)} f Visitor function.
27365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
274496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.traverseTopDownTree = function(f) {
27565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.topDownTree_.traverse(f);
27665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
27765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
27865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
27965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
2805ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Performs a BF traversal of the bottom up call graph.
28165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
282496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(CallTree.Node)} f Visitor function.
28365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
284496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.traverseBottomUpTree = function(f) {
28565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.bottomUpTree_.traverse(f);
28665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
28765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
28865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
28965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
2905ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Calculates a top down profile for a node with the specified label.
2915ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * If no name specified, returns the whole top down calls tree.
2923a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *
2935ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @param {string} opt_label Node label.
2943a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org */
295496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.getTopDownProfile = function(opt_label) {
2965ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  return this.getTreeProfile_(this.topDownTree_, opt_label);
2975ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org};
2985ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
2995ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
3005ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
3015ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Calculates a bottom up profile for a node with the specified label.
3025ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * If no name specified, returns the whole bottom up calls tree.
3035ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
3045ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @param {string} opt_label Node label.
3055ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
306496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.getBottomUpProfile = function(opt_label) {
3075ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  return this.getTreeProfile_(this.bottomUpTree_, opt_label);
3083a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org};
3093a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org
3103a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org
3113a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org/**
3125ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Helper function for calculating a tree profile.
3133a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *
314496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {Profile.CallTree} tree Call tree.
3155ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @param {string} opt_label Node label.
3163a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org */
317496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.getTreeProfile_ = function(tree, opt_label) {
3185ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  if (!opt_label) {
3195ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    tree.computeTotalWeights();
3205ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    return tree;
3213a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  } else {
3225ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    var subTree = tree.cloneSubtree(opt_label);
3235ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    subTree.computeTotalWeights();
3245ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    return subTree;
3253a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  }
3263a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org};
3273a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org
3283a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org
3293a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org/**
3305ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Calculates a flat profile of callees starting from a node with
3315ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * the specified label. If no name specified, starts from the root.
33265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
3335ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @param {string} opt_label Starting node label.
33465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
335496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.prototype.getFlatProfile = function(opt_label) {
336496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  var counters = new CallTree();
337496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  var rootLabel = opt_label || CallTree.ROOT_NODE_LABEL;
33865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  var precs = {};
3395ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  precs[rootLabel] = 0;
3405ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  var root = counters.findOrAddChild(rootLabel);
3415ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
34265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.topDownTree_.computeTotalWeights();
34365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.topDownTree_.traverseInDepth(
34465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    function onEnter(node) {
34565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org      if (!(node.label in precs)) {
34665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org        precs[node.label] = 0;
34765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org      }
3485ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org      var nodeLabelIsRootLabel = node.label == rootLabel;
3495ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org      if (nodeLabelIsRootLabel || precs[rootLabel] > 0) {
3505ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org        if (precs[rootLabel] == 0) {
3515ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org          root.selfWeight += node.selfWeight;
3525ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org          root.totalWeight += node.totalWeight;
3535ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org        } else {
3545ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org          var rec = root.findOrAddChild(node.label);
3555ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org          rec.selfWeight += node.selfWeight;
3565ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org          if (nodeLabelIsRootLabel || precs[node.label] == 0) {
3575ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org            rec.totalWeight += node.totalWeight;
3585ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org          }
3595ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org        }
3605ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org        precs[node.label]++;
36165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org      }
36265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    },
36365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    function onExit(node) {
3645ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org      if (node.label == rootLabel || precs[rootLabel] > 0) {
3655ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org        precs[node.label]--;
3665ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org      }
36765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    },
3685ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    null);
3695ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
3705ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  if (!opt_label) {
3715ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    // If we have created a flat profile for the whole program, we don't
3725ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    // need an explicit root in it. Thus, replace the counters tree
3735ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    // root with the node corresponding to the whole program.
3745ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    counters.root_ = root;
3755ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  } else {
3765ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    // Propagate weights so percents can be calculated correctly.
3775ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    counters.getRoot().selfWeight = root.selfWeight;
3785ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    counters.getRoot().totalWeight = root.totalWeight;
3795ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  }
3803a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  return counters;
38165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
38265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
38365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
38465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
385030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org * Cleans up function entries that are not referenced by code entries.
386030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org */
387030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.orgProfile.prototype.cleanUpFuncEntries = function() {
388030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  var referencedFuncEntries = [];
389030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  var entries = this.codeMap_.getAllDynamicEntriesWithAddresses();
390030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  for (var i = 0, l = entries.length; i < l; ++i) {
391030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    if (entries[i][1].constructor === Profile.FunctionEntry) {
392030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org      entries[i][1].used = false;
393030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    }
394030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  }
395030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  for (var i = 0, l = entries.length; i < l; ++i) {
396030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    if ("func" in entries[i][1]) {
397030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org      entries[i][1].func.used = true;
398030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    }
399030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  }
400030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  for (var i = 0, l = entries.length; i < l; ++i) {
401030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    if (entries[i][1].constructor === Profile.FunctionEntry &&
402030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org        !entries[i][1].used) {
403030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org      this.codeMap_.deleteCode(entries[i][0]);
404030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    }
405030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  }
406030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org};
407030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org
408030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org
409030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org/**
41065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Creates a dynamic code entry.
41165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
41265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {number} size Code size.
41365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {string} type Code type.
41465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {string} name Function name.
41565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @constructor
41665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
417496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.DynamicCodeEntry = function(size, type, name) {
418496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  CodeMap.CodeEntry.call(this, size, name);
41965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.type = type;
42065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
42165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
42265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
42365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
42465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Returns node name.
42565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
426496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.DynamicCodeEntry.prototype.getName = function() {
4273a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  return this.type + ': ' + this.name;
42865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
42965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
43065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
43165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
432b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org * Returns raw node name (without type decoration).
433b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org */
434496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.DynamicCodeEntry.prototype.getRawName = function() {
435b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org  return this.name;
436b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org};
437b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
438b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
439496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfile.DynamicCodeEntry.prototype.isJSFunction = function() {
4403a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  return false;
4413a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org};
4423a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
4433a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
444030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.orgProfile.DynamicCodeEntry.prototype.toString = function() {
445030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  return this.getName() + ': ' + this.size.toString(16);
446030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org};
447030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org
448030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org
4493a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org/**
4503a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * Creates a dynamic code entry.
4513a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org *
4523a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {number} size Code size.
4533a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {string} type Code type.
4543a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {Profile.FunctionEntry} func Shared function entry.
4553a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {Profile.CodeState} state Code optimization state.
4563a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @constructor
4573a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org */
4583a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgProfile.DynamicFuncCodeEntry = function(size, type, func, state) {
4593a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  CodeMap.CodeEntry.call(this, size);
4603a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  this.type = type;
4613a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  this.func = func;
4623a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  this.state = state;
4633a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org};
4643a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
4653a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgProfile.DynamicFuncCodeEntry.STATE_PREFIX = ["", "~", "*"];
4663a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
4673a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org/**
4683a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * Returns node name.
4693a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org */
4703a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgProfile.DynamicFuncCodeEntry.prototype.getName = function() {
4713a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  var name = this.func.getName();
4723a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  return this.type + ': ' + Profile.DynamicFuncCodeEntry.STATE_PREFIX[this.state] + name;
4733a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org};
4743a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
4753a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
4763a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org/**
4773a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * Returns raw node name (without type decoration).
4783a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org */
4793a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgProfile.DynamicFuncCodeEntry.prototype.getRawName = function() {
4803a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  return this.func.getName();
4813a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org};
4823a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
4833a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
4843a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgProfile.DynamicFuncCodeEntry.prototype.isJSFunction = function() {
4853a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  return true;
4863a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org};
4873a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
4883a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
489030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.orgProfile.DynamicFuncCodeEntry.prototype.toString = function() {
490030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  return this.getName() + ': ' + this.size.toString(16);
491030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org};
492030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org
493030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org
4943a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org/**
4953a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * Creates a shared function object entry.
4963a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org *
4973a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @param {string} name Function name.
4983a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * @constructor
4993a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org */
5003a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgProfile.FunctionEntry = function(name) {
5013a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  CodeMap.CodeEntry.call(this, 0, name);
5023a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org};
5033a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
5043a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
5053a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org/**
5063a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org * Returns node name.
5073a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org */
5083a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgProfile.FunctionEntry.prototype.getName = function() {
5093a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  var name = this.name;
5103a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  if (name.length == 0) {
5113a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org    name = '<anonymous>';
5123a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  } else if (name.charAt(0) == ' ') {
5133a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org    // An anonymous function with location: " aaa.js:10".
5143a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org    name = '<anonymous>' + name;
5153a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  }
5163a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  return name;
517b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org};
518b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
519030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.orgProfile.FunctionEntry.prototype.toString = CodeMap.CodeEntry.prototype.toString;
520b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
521b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org/**
52265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Constructs a call graph.
52365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
52465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @constructor
52565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
526496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgfunction CallTree() {
527496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  this.root_ = new CallTree.Node(
528496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org      CallTree.ROOT_NODE_LABEL);
52965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
53065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
53165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
53265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
5335ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * The label of the root node.
5345ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
535496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.ROOT_NODE_LABEL = '';
5365ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
5375ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
5385ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
53965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @private
54065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
541496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.prototype.totalsComputed_ = false;
54265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
54365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
54465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
5453a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * Returns the tree root.
5463a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org */
547496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.prototype.getRoot = function() {
5483a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org  return this.root_;
5493a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org};
5503a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org
5513a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org
5523a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org/**
55365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Adds the specified call path, constructing nodes as necessary.
55465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
55565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {Array<string>} path Call path.
55665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
557496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.prototype.addPath = function(path) {
55865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  if (path.length == 0) {
55965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    return;
56065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
56165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  var curr = this.root_;
56265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  for (var i = 0; i < path.length; ++i) {
56365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    curr = curr.findOrAddChild(path[i]);
56465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
56565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  curr.selfWeight++;
56665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.totalsComputed_ = false;
56765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
56865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
56965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
57065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
5713a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * Finds an immediate child of the specified parent with the specified
5723a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * label, creates a child node if necessary. If a parent node isn't
5733a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * specified, uses tree root.
5743a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *
5753a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * @param {string} label Child node label.
5763a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org */
577496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.prototype.findOrAddChild = function(label) {
5785ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  return this.root_.findOrAddChild(label);
5795ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org};
5805ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
5815ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
5825ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
5835ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Creates a subtree by cloning and merging all subtrees rooted at nodes
5845ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * with a given label. E.g. cloning the following call tree on label 'A'
5855ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * will give the following result:
5865ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
5875ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *           <A>--<B>                                     <B>
5885ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *          /                                            /
5895ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *     <root>             == clone on 'A' ==>  <root>--<A>
5905ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *          \                                            \
5915ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *           <C>--<A>--<D>                                <D>
5925ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
5935ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * And <A>'s selfWeight will be the sum of selfWeights of <A>'s from the
5945ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * source call tree.
5955ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
5965ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @param {string} label The label of the new root node.
5975ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
598496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.prototype.cloneSubtree = function(label) {
599496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  var subTree = new CallTree();
6005ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.traverse(function(node, parent) {
6015ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    if (!parent && node.label != label) {
6025ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org      return null;
6035ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    }
6045ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    var child = (parent ? parent : subTree).findOrAddChild(node.label);
6055ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    child.selfWeight += node.selfWeight;
6065ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    return child;
6075ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  });
6085ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  return subTree;
6093a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org};
6103a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org
6113a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org
6123a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org/**
61365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Computes total weights in the call graph.
61465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
615496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.prototype.computeTotalWeights = function() {
61665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  if (this.totalsComputed_) {
61765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    return;
61865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
61965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.root_.computeTotalWeight();
62065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.totalsComputed_ = true;
62165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
62265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
62365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
62465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
6253a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * Traverses the call graph in preorder. This function can be used for
6263a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * building optionally modified tree clones. This is the boilerplate code
6273a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * for this scenario:
62865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
6293a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * callTree.traverse(function(node, parentClone) {
6303a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *   var nodeClone = cloneNode(node);
6313a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *   if (parentClone)
6323a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *     parentClone.addChild(nodeClone);
6333a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *   return nodeClone;
6343a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org * });
6353a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *
636496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(CallTree.Node, *)} f Visitor function.
6373a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org *    The second parameter is the result of calling 'f' on the parent node.
63865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
639496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.prototype.traverse = function(f) {
6405ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  var pairsToProcess = new ConsArray();
6415ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  pairsToProcess.concat([{node: this.root_, param: null}]);
6425ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  while (!pairsToProcess.atEnd()) {
6435ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    var pair = pairsToProcess.next();
6443a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org    var node = pair.node;
6453a37e9b96c768f6b5b6b09542e1cb1a1ece7a022ager@chromium.org    var newParam = f(node, pair.param);
6465ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    var morePairsToProcess = [];
6475ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    node.forEachChild(function (child) {
6485ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org        morePairsToProcess.push({node: child, param: newParam}); });
6495ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    pairsToProcess.concat(morePairsToProcess);
65065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
65165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
65265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
65365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
65465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
65565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Performs an indepth call graph traversal.
65665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
657496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(CallTree.Node)} enter A function called
65865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *     prior to visiting node's children.
659496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(CallTree.Node)} exit A function called
66065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *     after visiting node's children.
66165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
662496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.prototype.traverseInDepth = function(enter, exit) {
66365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  function traverse(node) {
66465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    enter(node);
66565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    node.forEachChild(traverse);
66665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    exit(node);
66765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
6685ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  traverse(this.root_);
66965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
67065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
67165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
67265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
67365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Constructs a call graph node.
67465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
67565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {string} label Node label.
676496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {CallTree.Node} opt_parent Node parent.
67765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
678496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node = function(label, opt_parent) {
67965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.label = label;
68065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.parent = opt_parent;
68165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.children = {};
68265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
68365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
68465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
68565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
68665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Node self weight (how many times this node was the last node in
68765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * a call path).
68865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @type {number}
68965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
690496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node.prototype.selfWeight = 0;
69165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
69265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
69365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
69465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Node total weight (includes weights of all children).
69565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @type {number}
69665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
697496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node.prototype.totalWeight = 0;
69865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
69965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
70065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
70165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Adds a child node.
70265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
70365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {string} label Child node label.
70465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
705496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node.prototype.addChild = function(label) {
706496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  var child = new CallTree.Node(label, this);
70765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.children[label] = child;
70865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  return child;
70965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
71065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
71165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
71265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
71365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Computes node's total weight.
71465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
715496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node.prototype.computeTotalWeight =
71665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    function() {
71765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  var totalWeight = this.selfWeight;
71865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.forEachChild(function(child) {
71965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org      totalWeight += child.computeTotalWeight(); });
72065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  return this.totalWeight = totalWeight;
72165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
72265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
72365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
72465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
72565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Returns all node's children as an array.
72665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
727496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node.prototype.exportChildren = function() {
72865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  var result = [];
72965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  this.forEachChild(function (node) { result.push(node); });
73065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  return result;
73165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
73265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
73365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
73465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
73565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Finds an immediate child with the specified label.
73665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
73765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {string} label Child node label.
73865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
739496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node.prototype.findChild = function(label) {
74065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  return this.children[label] || null;
74165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
74265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
74365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
74465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
74565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Finds an immediate child with the specified label, creates a child
74665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * node if necessary.
74765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
74865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {string} label Child node label.
74965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
750496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node.prototype.findOrAddChild = function(label) {
75165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  return this.findChild(label) || this.addChild(label);
75265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
75365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
75465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
75565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
75665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Calls the specified function for every child.
75765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
758496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(CallTree.Node)} f Visitor function.
75965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
760496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node.prototype.forEachChild = function(f) {
76165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  for (var c in this.children) {
76265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    f(this.children[c]);
76365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
76465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
76565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
76665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
76765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
76865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Walks up from the current node up to the call tree root.
76965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
770496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(CallTree.Node)} f Visitor function.
77165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
772496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node.prototype.walkUpToRoot = function(f) {
77365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  for (var curr = this; curr != null; curr = curr.parent) {
77465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    f(curr);
77565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
77665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
77765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
77865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org
77965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org/**
78065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * Tries to find a node with the specified path.
78165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org *
78265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org * @param {Array<string>} labels The path.
783496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(CallTree.Node)} opt_f Visitor function.
78465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org */
785496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgCallTree.Node.prototype.descendToChild = function(
78665dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    labels, opt_f) {
78765dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) {
78865dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    var child = curr.findChild(labels[pos]);
78965dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    if (opt_f) {
79065dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org      opt_f(child, pos);
79165dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    }
79265dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org    curr = child;
79365dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  }
79465dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org  return curr;
79565dad4b091d2925543c6326db635d0f7cf9e1edcager@chromium.org};
796