18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2008 Apple Inc. All Rights Reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "ProfileGenerator.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
29635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "CallFrame.h"
30231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "CodeBlock.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSGlobalObject.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSStringRef.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSFunction.h"
34635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "Interpreter.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Profile.h"
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Profiler.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Tracing.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace JSC {
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic const char* NonJSExecution = "(idle)";
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
432bde8e466a4451c7319e3a072d118917957d6554Steve BlockPassRefPtr<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const UString& title, unsigned uid)
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
452bde8e466a4451c7319e3a072d118917957d6554Steve Block    return adoptRef(new ProfileGenerator(exec, title, uid));
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
482bde8e466a4451c7319e3a072d118917957d6554Steve BlockProfileGenerator::ProfileGenerator(ExecState* exec, const UString& title, unsigned uid)
492bde8e466a4451c7319e3a072d118917957d6554Steve Block    : m_origin(exec ? exec->lexicalGlobalObject() : 0)
502bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_profileGroup(exec ? exec->lexicalGlobalObject()->profileGroup() : 0)
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_profile = Profile::create(title, uid);
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_currentNode = m_head = m_profile->head();
542bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (exec)
552bde8e466a4451c7319e3a072d118917957d6554Steve Block        addParentForConsoleStart(exec);
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid ProfileGenerator::addParentForConsoleStart(ExecState* exec)
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int lineNumber;
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    intptr_t sourceID;
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UString sourceURL;
635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    JSValue function;
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
65635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function);
664576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    m_currentNode = ProfileNode::create(exec, Profiler::createCallIdentifier(exec, function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_head->insertNode(m_currentNode.get());
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectconst UString& ProfileGenerator::title() const
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_profile->title();
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
754576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangvoid ProfileGenerator::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) {
78f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        CString name = callIdentifier.m_name.utf8();
79f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        CString url = callIdentifier.m_url.utf8();
80dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.m_lineNumber);
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
832bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_origin)
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
864576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    ASSERT(m_currentNode);
874576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    m_currentNode = m_currentNode->willExecute(callerCallFrame, callIdentifier);
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
904576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangvoid ProfileGenerator::didExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED()) {
93f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        CString name = callIdentifier.m_name.utf8();
94f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        CString url = callIdentifier.m_url.utf8();
95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.m_lineNumber);
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
982bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_origin)
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1014576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    ASSERT(m_currentNode);
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_currentNode->callIdentifier() != callIdentifier) {
1034576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        RefPtr<ProfileNode> returningNode = ProfileNode::create(callerCallFrame, callIdentifier, m_head.get(), m_currentNode.get());
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        returningNode->setStartTime(m_currentNode->startTime());
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        returningNode->didExecute();
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_currentNode->insertNode(returningNode.release());
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_currentNode = m_currentNode->didExecute();
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1134576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangvoid ProfileGenerator::exceptionUnwind(ExecState* handlerCallFrame, const CallIdentifier&)
1144576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang{
1154576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    // If the current node was called by the handler (==) or any
1164576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    // more nested function (>) the we have exited early from it.
1174576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    ASSERT(m_currentNode);
1184576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    while (m_currentNode->callerCallFrame() >= handlerCallFrame) {
1194576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        didExecute(m_currentNode->callerCallFrame(), m_currentNode->callIdentifier());
1204576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        ASSERT(m_currentNode);
1214576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    }
1224576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang}
1234576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid ProfileGenerator::stopProfiling()
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_profile->forEach(&ProfileNode::stopProfiling);
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    removeProfileStart();
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    removeProfileEnd();
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1314576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    ASSERT(m_currentNode);
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Set the current node to the parent, because we are in a call that
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // will not get didExecute call.
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_currentNode = m_currentNode->parent();
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project   if (double headSelfTime = m_head->selfTime()) {
1384576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        RefPtr<ProfileNode> idleNode = ProfileNode::create(0, CallIdentifier(NonJSExecution, UString(), 0), m_head.get(), m_head.get());
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        idleNode->setTotalTime(headSelfTime);
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        idleNode->setSelfTime(headSelfTime);
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        idleNode->setVisible(true);
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_head->setSelfTime(0.0);
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_head->addChild(idleNode.release());
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// The console.ProfileGenerator that started this ProfileGenerator will be the first child.
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid ProfileGenerator::removeProfileStart()
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ProfileNode* currentNode = 0;
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (ProfileNode* next = m_head.get(); next; next = next->firstChild())
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        currentNode = next;
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (currentNode->callIdentifier().m_name != "profile")
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Attribute the time of the node aobut to be removed to the self time of its parent
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    currentNode->parent()->removeChild(currentNode);
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// The console.ProfileGeneratorEnd that stopped this ProfileGenerator will be the last child.
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid ProfileGenerator::removeProfileEnd()
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ProfileNode* currentNode = 0;
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (ProfileNode* next = m_head.get(); next; next = next->lastChild())
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        currentNode = next;
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (currentNode->callIdentifier().m_name != "profileEnd")
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Attribute the time of the node aobut to be removed to the self time of its parent
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(currentNode->callIdentifier() == (currentNode->parent()->children()[currentNode->parent()->children().size() - 1])->callIdentifier());
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    currentNode->parent()->removeChild(currentNode);
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace JSC
182