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 "JSFunction.h" 36 #include "JSGlobalObject.h" 37 #include "Nodes.h" 38 #include "Profile.h" 39 #include "ProfileGenerator.h" 40 #include "ProfileNode.h" 41 #include <stdio.h> 42 43 namespace JSC { 44 45 static const char* GlobalCodeExecution = "(program)"; 46 static const char* AnonymousFunction = "(anonymous function)"; 47 static unsigned ProfilesUID = 0; 48 49 static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSFunction*); 50 51 Profiler* Profiler::s_sharedProfiler = 0; 52 Profiler* Profiler::s_sharedEnabledProfilerReference = 0; 53 54 Profiler* Profiler::profiler() 55 { 56 if (!s_sharedProfiler) 57 s_sharedProfiler = new Profiler(); 58 return s_sharedProfiler; 59 } 60 61 void Profiler::startProfiling(ExecState* exec, const UString& title) 62 { 63 ASSERT_ARG(title, !title.isNull()); 64 65 // Check if we currently have a Profile for this global ExecState and title. 66 // If so return early and don't create a new Profile. 67 ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0; 68 69 for (size_t i = 0; i < m_currentProfiles.size(); ++i) { 70 ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); 71 if (profileGenerator->originatingGlobalExec() == globalExec && profileGenerator->title() == title) 72 return; 73 } 74 75 s_sharedEnabledProfilerReference = this; 76 RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(title, exec, ++ProfilesUID); 77 m_currentProfiles.append(profileGenerator); 78 } 79 80 PassRefPtr<Profile> Profiler::stopProfiling(ExecState* exec, const UString& title) 81 { 82 ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0; 83 for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) { 84 ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); 85 if (profileGenerator->originatingGlobalExec() == globalExec && (title.isNull() || profileGenerator->title() == title)) { 86 profileGenerator->stopProfiling(); 87 RefPtr<Profile> returnProfile = profileGenerator->profile(); 88 89 m_currentProfiles.remove(i); 90 if (!m_currentProfiles.size()) 91 s_sharedEnabledProfilerReference = 0; 92 93 return returnProfile; 94 } 95 } 96 97 return 0; 98 } 99 100 static inline void dispatchFunctionToProfiles(const Vector<RefPtr<ProfileGenerator> >& profiles, ProfileGenerator::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentProfileTargetGroup) 101 { 102 for (size_t i = 0; i < profiles.size(); ++i) { 103 if (profiles[i]->profileGroup() == currentProfileTargetGroup || !profiles[i]->originatingGlobalExec()) 104 (profiles[i].get()->*function)(callIdentifier); 105 } 106 } 107 108 void Profiler::willExecute(ExecState* exec, JSValue function) 109 { 110 ASSERT(!m_currentProfiles.isEmpty()); 111 112 dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(exec, function, "", 0), exec->lexicalGlobalObject()->profileGroup()); 113 } 114 115 void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber) 116 { 117 ASSERT(!m_currentProfiles.isEmpty()); 118 119 CallIdentifier callIdentifier = createCallIdentifier(exec, JSValue(), sourceURL, startingLineNumber); 120 121 dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, exec->lexicalGlobalObject()->profileGroup()); 122 } 123 124 void Profiler::didExecute(ExecState* exec, JSValue function) 125 { 126 ASSERT(!m_currentProfiles.isEmpty()); 127 128 dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(exec, function, "", 0), exec->lexicalGlobalObject()->profileGroup()); 129 } 130 131 void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber) 132 { 133 ASSERT(!m_currentProfiles.isEmpty()); 134 135 dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(exec, JSValue(), sourceURL, startingLineNumber), exec->lexicalGlobalObject()->profileGroup()); 136 } 137 138 CallIdentifier Profiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const UString& defaultSourceURL, int defaultLineNumber) 139 { 140 if (!functionValue) 141 return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber); 142 if (!functionValue.isObject()) 143 return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber); 144 if (asObject(functionValue)->inherits(&JSFunction::info)) { 145 JSFunction* function = asFunction(functionValue); 146 if (!function->executable()->isHostFunction()) 147 return createCallIdentifierFromFunctionImp(exec, function); 148 } 149 if (asObject(functionValue)->inherits(&InternalFunction::info)) 150 return CallIdentifier(static_cast<InternalFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber); 151 return CallIdentifier(makeString("(", asObject(functionValue)->className(), " object)"), defaultSourceURL, defaultLineNumber); 152 } 153 154 CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSFunction* function) 155 { 156 ASSERT(!function->isHostFunction()); 157 const UString& name = function->calculatedDisplayName(exec); 158 return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, function->jsExecutable()->sourceURL(), function->jsExecutable()->lineNo()); 159 } 160 161 } // namespace JSC 162