• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3   *
4   * Redistribution and use in source and binary forms, with or without
5   * modification, are permitted provided that the following conditions
6   * are met:
7   * 1. Redistributions of source code must retain the above copyright
8   *    notice, this list of conditions and the following disclaimer.
9   * 2. Redistributions in binary form must reproduce the above copyright
10   *    notice, this list of conditions and the following disclaimer in the
11   *    documentation and/or other materials provided with the distribution.
12   *
13   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24   */
25  
26  #include "config.h"
27  #include "ProfileGenerator.h"
28  
29  #include "CallFrame.h"
30  #include "JSGlobalObject.h"
31  #include "JSStringRef.h"
32  #include "JSFunction.h"
33  #include "Interpreter.h"
34  #include "Profile.h"
35  #include "Profiler.h"
36  #include "Tracing.h"
37  
38  namespace JSC {
39  
40  static const char* NonJSExecution = "(idle)";
41  
create(const UString & title,ExecState * originatingExec,unsigned uid)42  PassRefPtr<ProfileGenerator> ProfileGenerator::create(const UString& title, ExecState* originatingExec, unsigned uid)
43  {
44      return adoptRef(new ProfileGenerator(title, originatingExec, uid));
45  }
46  
ProfileGenerator(const UString & title,ExecState * originatingExec,unsigned uid)47  ProfileGenerator::ProfileGenerator(const UString& title, ExecState* originatingExec, unsigned uid)
48      : m_originatingGlobalExec(originatingExec ? originatingExec->lexicalGlobalObject()->globalExec() : 0)
49      , m_profileGroup(originatingExec ? originatingExec->lexicalGlobalObject()->profileGroup() : 0)
50  {
51      m_profile = Profile::create(title, uid);
52      m_currentNode = m_head = m_profile->head();
53      if (originatingExec)
54          addParentForConsoleStart(originatingExec);
55  }
56  
addParentForConsoleStart(ExecState * exec)57  void ProfileGenerator::addParentForConsoleStart(ExecState* exec)
58  {
59      int lineNumber;
60      intptr_t sourceID;
61      UString sourceURL;
62      JSValuePtr function;
63  
64      exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function);
65      m_currentNode = ProfileNode::create(Profiler::createCallIdentifier(&exec->globalData(), function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
66      m_head->insertNode(m_currentNode.get());
67  }
68  
title() const69  const UString& ProfileGenerator::title() const
70  {
71      return m_profile->title();
72  }
73  
willExecute(const CallIdentifier & callIdentifier)74  void ProfileGenerator::willExecute(const CallIdentifier& callIdentifier)
75  {
76      if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) {
77          CString name = callIdentifier.m_name.UTF8String();
78          CString url = callIdentifier.m_url.UTF8String();
79          JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.c_str()), const_cast<char*>(url.c_str()), callIdentifier.m_lineNumber);
80      }
81  
82      if (!m_originatingGlobalExec)
83          return;
84  
85      ASSERT_ARG(m_currentNode, m_currentNode);
86      m_currentNode = m_currentNode->willExecute(callIdentifier);
87  }
88  
didExecute(const CallIdentifier & callIdentifier)89  void ProfileGenerator::didExecute(const CallIdentifier& callIdentifier)
90  {
91      if (JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED()) {
92          CString name = callIdentifier.m_name.UTF8String();
93          CString url = callIdentifier.m_url.UTF8String();
94          JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.c_str()), const_cast<char*>(url.c_str()), callIdentifier.m_lineNumber);
95      }
96  
97      if (!m_originatingGlobalExec)
98          return;
99  
100      ASSERT_ARG(m_currentNode, m_currentNode);
101      if (m_currentNode->callIdentifier() != callIdentifier) {
102          RefPtr<ProfileNode> returningNode = ProfileNode::create(callIdentifier, m_head.get(), m_currentNode.get());
103          returningNode->setStartTime(m_currentNode->startTime());
104          returningNode->didExecute();
105          m_currentNode->insertNode(returningNode.release());
106          return;
107      }
108  
109      m_currentNode = m_currentNode->didExecute();
110  }
111  
stopProfiling()112  void ProfileGenerator::stopProfiling()
113  {
114      m_profile->forEach(&ProfileNode::stopProfiling);
115  
116      removeProfileStart();
117      removeProfileEnd();
118  
119      ASSERT_ARG(m_currentNode, m_currentNode);
120  
121      // Set the current node to the parent, because we are in a call that
122      // will not get didExecute call.
123      m_currentNode = m_currentNode->parent();
124  
125     if (double headSelfTime = m_head->selfTime()) {
126          RefPtr<ProfileNode> idleNode = ProfileNode::create(CallIdentifier(NonJSExecution, 0, 0), m_head.get(), m_head.get());
127  
128          idleNode->setTotalTime(headSelfTime);
129          idleNode->setSelfTime(headSelfTime);
130          idleNode->setVisible(true);
131  
132          m_head->setSelfTime(0.0);
133          m_head->addChild(idleNode.release());
134      }
135  }
136  
137  // The console.ProfileGenerator that started this ProfileGenerator will be the first child.
removeProfileStart()138  void ProfileGenerator::removeProfileStart()
139  {
140      ProfileNode* currentNode = 0;
141      for (ProfileNode* next = m_head.get(); next; next = next->firstChild())
142          currentNode = next;
143  
144      if (currentNode->callIdentifier().m_name != "profile")
145          return;
146  
147      // Attribute the time of the node aobut to be removed to the self time of its parent
148      currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
149      currentNode->parent()->removeChild(currentNode);
150  }
151  
152  // The console.ProfileGeneratorEnd that stopped this ProfileGenerator will be the last child.
removeProfileEnd()153  void ProfileGenerator::removeProfileEnd()
154  {
155      ProfileNode* currentNode = 0;
156      for (ProfileNode* next = m_head.get(); next; next = next->lastChild())
157          currentNode = next;
158  
159      if (currentNode->callIdentifier().m_name != "profileEnd")
160          return;
161  
162      // Attribute the time of the node aobut to be removed to the self time of its parent
163      currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
164  
165      ASSERT(currentNode->callIdentifier() == (currentNode->parent()->children()[currentNode->parent()->children().size() - 1])->callIdentifier());
166      currentNode->parent()->removeChild(currentNode);
167  }
168  
169  } // namespace JSC
170