• 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