<rdar://problem/5951561> Turn on JavaScript Profiler
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 May 2008 08:56:21 +0000 (08:56 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 May 2008 08:56:21 +0000 (08:56 +0000)
Reviewed by Kevin McCullough

Flipped the switch on the profiler, rearranged how we
signal the the profiler is active so that calls aren't
needed in the general case.

Also fixed the entry point for Machine::execute(FunctionBodyNode..)
to correctly indicate function exit.

Results in a 0.7-1.0% regression in SunSpider :-(

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@34065 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/kjs/config.h
JavaScriptCore/profiler/Profiler.cpp
JavaScriptCore/profiler/Profiler.h

index 815f50b..b30948e 100644 (file)
@@ -1,3 +1,31 @@
+2008-05-23  Oliver Hunt  <oliver@apple.com>
+
+       <rdar://problem/5951561> Turn on JavaScript Profiler
+
+        Reviewed by Kevin McCullough.
+
+        Flipped the switch on the profiler, rearranged how we
+        signal the the profiler is active so that calls aren't
+        needed in the general case.
+        
+        Also fixed the entry point for Machine::execute(FunctionBodyNode..)
+        to correctly indicate function exit.
+
+        Results in a 0.7-1.0% regression in SunSpider :-(
+
+        * VM/Machine.cpp:
+        (KJS::callEval):
+        (KJS::Machine::unwindCallFrame):
+        (KJS::Machine::execute):
+        (KJS::Machine::privateExecute):
+        * kjs/config.h:
+        * profiler/Profiler.cpp:
+        (KJS::Profiler::profiler):
+        (KJS::Profiler::startProfiling):
+        (KJS::Profiler::stopProfiling):
+        * profiler/Profiler.h:
+        (KJS::Profiler::enabledProfilerReference):
+
 2008-05-23  Simon Hausmann  <hausmann@webkit.org>
 
         Fix the Qt build by adding profiler/ to the include search path.
index 0865a98..75360df 100644 (file)
@@ -437,13 +437,13 @@ static NEVER_INLINE bool isNotObject(ExecState* exec, const Instruction*, CodeBl
     return true;
 }
 
-#if JAVASCRIPT_PROFILING
-static NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* evalFunction, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
-{
-    Profiler::profiler()->willExecute(exec, evalFunction);
-#else
 static NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
 {
+#if JAVASCRIPT_PROFILING
+    Profiler** profiler = Profiler::enabledProfilerReference();
+    JSObject* evalFunction = scopeChain->globalObject()->evalFunction();
+    if (*profiler)
+        (*profiler)->willExecute(exec, evalFunction);
 #endif
 
     JSValue* x = argc >= 2 ? r[argv + 1].u.jsValue : jsUndefined();
@@ -471,7 +471,8 @@ static NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeC
 #if JAVASCRIPT_PROFILING
     JSValue* result = machine().execute(evalNode.get(), exec, thisObj, registerFile, r - (*registerFile->basePointer()) + argv + argc, scopeChain, &exceptionValue);
 
-    Profiler::profiler()->didExecute(exec, evalFunction);
+    if ((*profiler))
+        (*profiler)->didExecute(exec, evalFunction);
 
     return result;
 #else
@@ -607,7 +608,8 @@ NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionVa
     vPC = callFrame[ReturnVPC].u.vPC;
 
 #if JAVASCRIPT_PROFILING
-    Profiler::profiler()->didExecute(exec, callFrame[Callee].u.jsObject);
+    if (Profiler* profiler = *Profiler::enabledProfilerReference())
+        profiler->didExecute(exec, callFrame[Callee].u.jsObject);
 #endif
     return true;
 }
@@ -657,10 +659,6 @@ JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainN
         return 0;
     }
 
-#if JAVASCRIPT_PROFILING
-    Profiler::profiler()->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
-#endif
-
     RegisterFile* registerFile = registerFileStack->pushGlobalRegisterFile();
     ASSERT(registerFile->numGlobalSlots());
     CodeBlock* codeBlock = &programNode->code(scopeChain, !registerFileStack->inImplicitCall());
@@ -673,7 +671,13 @@ JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainN
     
     if (codeBlock->needsFullScopeChain)
         scopeChain = scopeChain->copy();
-    
+
+#if JAVASCRIPT_PROFILING
+    Profiler** profiler = Profiler::enabledProfilerReference();
+    if (*profiler)
+        (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
+#endif
+
     ExecState newExec(exec, this, registerFile, scopeChain, -1);
 
     m_reentryDepth++;
@@ -683,7 +687,8 @@ JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainN
     registerFileStack->popGlobalRegisterFile();
 
 #if JAVASCRIPT_PROFILING
-    Profiler::profiler()->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
+    if (*profiler)
+        (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
 #endif
 
     return result;
@@ -696,10 +701,6 @@ JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, F
         return 0;
     }
 
-#if JAVASCRIPT_PROFILING
-    Profiler::profiler()->willExecute(exec, function);
-#endif
-
     RegisterFile* registerFile = registerFileStack->current();
 
     int argv = CallFrameHeaderSize;
@@ -737,11 +738,21 @@ JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, F
     scopeChain = scopeChainForCall(functionBodyNode, newCodeBlock, scopeChain, registerBase, r);            
 
     ExecState newExec(exec, this, registerFile, scopeChain, callFrameOffset);
+    
+#if JAVASCRIPT_PROFILING
+    Profiler** profiler = Profiler::enabledProfilerReference();
+    if (*profiler)
+        (*profiler)->willExecute(exec, function);
+#endif
 
     m_reentryDepth++;
     JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, newCodeBlock, exception);
     m_reentryDepth--;
 
+#if JAVASCRIPT_PROFILING
+    if (*profiler)
+        (*profiler)->didExecute(exec, function);
+#endif
     registerFile->shrink(oldSize);
     return result;
 }
@@ -753,10 +764,6 @@ JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj
         return 0;
     }
 
-#if JAVASCRIPT_PROFILING
-    Profiler::profiler()->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
-#endif
-
     EvalCodeBlock* codeBlock = &evalNode->code(scopeChain);
     
     JSVariableObject* variableObject;
@@ -797,6 +804,12 @@ JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj
     if (codeBlock->needsFullScopeChain)
         scopeChain = scopeChain->copy();
 
+#if JAVASCRIPT_PROFILING
+    Profiler** profiler = Profiler::enabledProfilerReference();
+    if (*profiler)
+        (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
+#endif
+
     ExecState newExec(exec, this, registerFile, scopeChain, -1);
 
     m_reentryDepth++;
@@ -806,7 +819,8 @@ JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj
     registerFile->shrink(oldSize);
 
 #if JAVASCRIPT_PROFILING
-    Profiler::profiler()->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
+    if (*profiler)
+        (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
 #endif
 
     return result;
@@ -879,10 +893,22 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
     JSValue* exceptionValue = 0;
     Instruction* handlerVPC = 0;
-    
+
     Register** registerBase = registerFile->basePointer();
     Instruction* vPC = codeBlock->instructions.begin();
     JSValue** k = codeBlock->jsValues.data();
+#if JAVASCRIPT_PROFILING
+    Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
+    
+#if HAVE(COMPUTED_GOTO)
+    // Yet another hack around GCC's various foibles, in this case fetching the
+    // profiler reference results in a regression.  Removing this indirection
+    // results in a 0.8% regression.
+    goto *(&&profilerFetchHack);
+    profilerFetchHack:
+#endif
+    
+#endif
     
     registerFile->setSafeForReentry(false);
 #define VM_CHECK_EXCEPTION() \
@@ -1855,11 +1881,9 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             JSObject* thisObject = r[codeBlock->thisRegister].u.jsObject;
 
             registerFile->setSafeForReentry(true);
-#if JAVASCRIPT_PROFILING
-            JSValue* result = callEval(exec, static_cast<JSObject*>(funcVal), thisObject, scopeChain, registerFile, r, argv, argc, exceptionValue);
-#else
+
             JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, argv, argc, exceptionValue);
-#endif
+
             registerFile->setSafeForReentry(false);
             r = (*registerBase) + registerOffset;
 
@@ -1900,7 +1924,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         
         if (callType == CallTypeJS) {
 #if JAVASCRIPT_PROFILING
-            Profiler::profiler()->willExecute(exec, static_cast<JSObject*>(v));
+            if (*enabledProfilerReference)
+                (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
 #endif
             int registerOffset = r - (*registerBase);
             Register* callFrame = r + argv - CallFrameHeaderSize;
@@ -1928,7 +1953,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
         if (callType == CallTypeNative) {
 #if JAVASCRIPT_PROFILING
-            Profiler::profiler()->willExecute(exec, static_cast<JSObject*>(v));
+            if (*enabledProfilerReference)
+                (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
 #endif
             int registerOffset = r - (*registerBase);
 
@@ -1945,7 +1971,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             r[dst].u.jsValue = returnValue;
 
 #if JAVASCRIPT_PROFILING
-            Profiler::profiler()->didExecute(exec, static_cast<JSObject*>(v));
+            if (*enabledProfilerReference)
+                (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
 #endif
             VM_CHECK_EXCEPTION();
 
@@ -1994,7 +2021,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         r[r0].u.jsValue = returnValue;
         
 #if JAVASCRIPT_PROFILING
-        Profiler::profiler()->didExecute(exec, callFrame[Callee].u.jsObject);
+        if (*enabledProfilerReference)
+            (*enabledProfilerReference)->didExecute(exec, callFrame[Callee].u.jsObject);
 #endif
         NEXT_OPCODE;
     }
@@ -2014,7 +2042,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
         if (constructType == ConstructTypeJS) {
 #if JAVASCRIPT_PROFILING
-            Profiler::profiler()->willExecute(exec, constructor);
+            if (*enabledProfilerReference)
+                (*enabledProfilerReference)->willExecute(exec, constructor);
 #endif
             int registerOffset = r - (*registerBase);
             Register* callFrame = r + argv - CallFrameHeaderSize;
@@ -2050,7 +2079,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
         if (constructType == ConstructTypeNative) {
 #if JAVASCRIPT_PROFILING
-            Profiler::profiler()->willExecute(exec, constructor);
+            if (*enabledProfilerReference)
+                (*enabledProfilerReference)->willExecute(exec, constructor);
 #endif
             int registerOffset = r - (*registerBase);
 
@@ -2064,7 +2094,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             r[dst].u.jsValue = returnValue;
 
 #if JAVASCRIPT_PROFILING
-            Profiler::profiler()->didExecute(exec, constructor);
+            if (*enabledProfilerReference)
+                (*enabledProfilerReference)->didExecute(exec, constructor);
 #endif
             ++vPC;
             NEXT_OPCODE;
index f1f9c18..1ee73b5 100644 (file)
@@ -86,4 +86,4 @@
 #include <wtf/DisallowCType.h>
 #endif
 
-#define JAVASCRIPT_PROFILING 0
+#define JAVASCRIPT_PROFILING 1
index e24310a..57ec0ef 100644 (file)
@@ -39,7 +39,6 @@
 
 namespace KJS {
 
-static Profiler* sharedProfiler = 0;
 static const char* GlobalCodeExecution = "(program)";
 static const char* AnonymousFunction = "(anonymous function)";
 
@@ -47,13 +46,16 @@ static CallIdentifier createCallIdentifier(JSObject*);
 static CallIdentifier createCallIdentifier(const UString& sourceURL, int startingLineNumber);
 static CallIdentifier createCallIdentifierFromFunctionImp(FunctionImp*);
 
+Profiler* Profiler::s_sharedProfiler = 0;
+Profiler* Profiler::s_sharedEnabledProfilerReference = 0;
+
 Profiler* Profiler::profiler()
 {
-    if (!sharedProfiler)
-        sharedProfiler = new Profiler;
-    return sharedProfiler;
-}
-
+    if (!s_sharedProfiler)
+        s_sharedProfiler = new Profiler();
+    return s_sharedProfiler;
+}   
+    
 Profile* Profiler::findProfile(ExecState* exec, const UString& title) const
 {
     ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
@@ -73,7 +75,7 @@ void Profiler::startProfiling(ExecState* exec, const UString& title)
     for (size_t i = 0; i < m_currentProfiles.size(); ++i)
         if (m_currentProfiles[i]->originatingGlobalExec() == globalExec && m_currentProfiles[i]->title() == title)
             return;
-
+    s_sharedEnabledProfilerReference = this;
     RefPtr<Profile> profile = Profile::create(title, globalExec, exec->lexicalGlobalObject()->pageGroupIdentifier());
     m_currentProfiles.append(profile);
 }
@@ -87,6 +89,8 @@ PassRefPtr<Profile> Profiler::stopProfiling(ExecState* exec, const UString& titl
 
             PassRefPtr<Profile> prpProfile = m_currentProfiles[i].release();
             m_currentProfiles.remove(i);
+            if (!m_currentProfiles.size())
+                s_sharedEnabledProfilerReference = 0;
             return prpProfile;
         }
     }
index fe0fc62..bde7ca2 100644 (file)
@@ -39,7 +39,12 @@ namespace KJS {
 
     class Profiler {
     public:
-        static Profiler* profiler();
+        static Profiler** enabledProfilerReference()
+        {
+            return &s_sharedEnabledProfilerReference;
+        }
+
+        static Profiler* profiler(); 
 
         void startProfiling(ExecState*, const UString& title);
         PassRefPtr<Profile> stopProfiling(ExecState*, const UString& title);
@@ -55,6 +60,8 @@ namespace KJS {
 
     private:
         Vector<RefPtr<Profile> > m_currentProfiles;
+        static Profiler* s_sharedProfiler;
+        static Profiler* s_sharedEnabledProfilerReference;
     };
 
 } // namespace KJS