JavaScriptCore/profiler/Profiler.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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  *
       
     8  * 1.  Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer.
       
    10  * 2.  Redistributions in binary form must reproduce the above copyright
       
    11  *     notice, this list of conditions and the following disclaimer in the
       
    12  *     documentation and/or other materials provided with the distribution.
       
    13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission.
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #include "config.h"
       
    30 #include "Profiler.h"
       
    31 
       
    32 #include "CommonIdentifiers.h"
       
    33 #include "CallFrame.h"
       
    34 #include "CodeBlock.h"
       
    35 #include "InternalFunction.h"
       
    36 #include "JSFunction.h"
       
    37 #include "JSGlobalObject.h"
       
    38 #include "Nodes.h"
       
    39 #include "Profile.h"
       
    40 #include "ProfileGenerator.h"
       
    41 #include "ProfileNode.h"
       
    42 #include <stdio.h>
       
    43 
       
    44 namespace JSC {
       
    45 
       
    46 static const char* GlobalCodeExecution = "(program)";
       
    47 static const char* AnonymousFunction = "(anonymous function)";
       
    48 static unsigned ProfilesUID = 0;
       
    49 
       
    50 static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSFunction*);
       
    51 
       
    52 Profiler* Profiler::s_sharedProfiler = 0;
       
    53 Profiler* Profiler::s_sharedEnabledProfilerReference = 0;
       
    54 
       
    55 Profiler* Profiler::profiler()
       
    56 {
       
    57     if (!s_sharedProfiler)
       
    58         s_sharedProfiler = new Profiler();
       
    59     return s_sharedProfiler;
       
    60 }   
       
    61 
       
    62 void Profiler::startProfiling(ExecState* exec, const UString& title)
       
    63 {
       
    64     ASSERT_ARG(title, !title.isNull());
       
    65 
       
    66     // Check if we currently have a Profile for this global ExecState and title.
       
    67     // If so return early and don't create a new Profile.
       
    68     ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0;
       
    69 
       
    70     for (size_t i = 0; i < m_currentProfiles.size(); ++i) {
       
    71         ProfileGenerator* profileGenerator = m_currentProfiles[i].get();
       
    72         if (profileGenerator->originatingGlobalExec() == globalExec && profileGenerator->title() == title)
       
    73             return;
       
    74     }
       
    75 
       
    76     s_sharedEnabledProfilerReference = this;
       
    77     RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(title, exec, ++ProfilesUID);
       
    78     m_currentProfiles.append(profileGenerator);
       
    79 }
       
    80 
       
    81 PassRefPtr<Profile> Profiler::stopProfiling(ExecState* exec, const UString& title)
       
    82 {
       
    83     ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0;
       
    84     for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) {
       
    85         ProfileGenerator* profileGenerator = m_currentProfiles[i].get();
       
    86         if (profileGenerator->originatingGlobalExec() == globalExec && (title.isNull() || profileGenerator->title() == title)) {
       
    87             profileGenerator->stopProfiling();
       
    88             RefPtr<Profile> returnProfile = profileGenerator->profile();
       
    89 
       
    90             m_currentProfiles.remove(i);
       
    91             if (!m_currentProfiles.size())
       
    92                 s_sharedEnabledProfilerReference = 0;
       
    93             
       
    94             return returnProfile;
       
    95         }
       
    96     }
       
    97 
       
    98     return 0;
       
    99 }
       
   100 
       
   101 static inline void dispatchFunctionToProfiles(const Vector<RefPtr<ProfileGenerator> >& profiles, ProfileGenerator::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentProfileTargetGroup)
       
   102 {
       
   103     for (size_t i = 0; i < profiles.size(); ++i) {
       
   104         if (profiles[i]->profileGroup() == currentProfileTargetGroup || !profiles[i]->originatingGlobalExec())
       
   105             (profiles[i].get()->*function)(callIdentifier);
       
   106     }
       
   107 }
       
   108 
       
   109 void Profiler::willExecute(ExecState* exec, JSValue function)
       
   110 {
       
   111     ASSERT(!m_currentProfiles.isEmpty());
       
   112 
       
   113     dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(exec, function, "", 0), exec->lexicalGlobalObject()->profileGroup());
       
   114 }
       
   115 
       
   116 void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
       
   117 {
       
   118     ASSERT(!m_currentProfiles.isEmpty());
       
   119 
       
   120     CallIdentifier callIdentifier = createCallIdentifier(exec, JSValue(), sourceURL, startingLineNumber);
       
   121 
       
   122     dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, exec->lexicalGlobalObject()->profileGroup());
       
   123 }
       
   124 
       
   125 void Profiler::didExecute(ExecState* exec, JSValue function)
       
   126 {
       
   127     ASSERT(!m_currentProfiles.isEmpty());
       
   128 
       
   129     dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(exec, function, "", 0), exec->lexicalGlobalObject()->profileGroup());
       
   130 }
       
   131 
       
   132 void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
       
   133 {
       
   134     ASSERT(!m_currentProfiles.isEmpty());
       
   135 
       
   136     dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(exec, JSValue(), sourceURL, startingLineNumber), exec->lexicalGlobalObject()->profileGroup());
       
   137 }
       
   138 
       
   139 CallIdentifier Profiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const UString& defaultSourceURL, int defaultLineNumber)
       
   140 {
       
   141     if (!functionValue)
       
   142         return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber);
       
   143     if (!functionValue.isObject())
       
   144         return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber);
       
   145     if (asObject(functionValue)->inherits(&JSFunction::info)) {
       
   146         JSFunction* function = asFunction(functionValue);
       
   147         if (!function->executable()->isHostFunction())
       
   148             return createCallIdentifierFromFunctionImp(exec, function);
       
   149     }
       
   150     if (asObject(functionValue)->inherits(&JSFunction::info))
       
   151         return CallIdentifier(static_cast<JSFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber);
       
   152     if (asObject(functionValue)->inherits(&InternalFunction::info))
       
   153         return CallIdentifier(static_cast<InternalFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber);
       
   154     return CallIdentifier(makeString("(", asObject(functionValue)->className(), " object)"), defaultSourceURL, defaultLineNumber);
       
   155 }
       
   156 
       
   157 CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSFunction* function)
       
   158 {
       
   159     ASSERT(!function->isHostFunction());
       
   160     const UString& name = function->calculatedDisplayName(exec);
       
   161     return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, function->jsExecutable()->sourceURL(), function->jsExecutable()->lineNo());
       
   162 }
       
   163 
       
   164 } // namespace JSC