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