Changes to the ownership of Profiles and allows multiple Profiles at a time
authortimothy@apple.com <timothy@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 May 2008 18:16:18 +0000 (18:16 +0000)
committertimothy@apple.com <timothy@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 May 2008 18:16:18 +0000 (18:16 +0000)
JavaScriptCore:

        Change the Profiler to allow multiple profiles to be running at
        the same time. This can happen when you have nested console.profile()
        calls. This required two changes. First, the Profiler needed to keep a
        Vector of current profiles, instead of one. Second, a Profile needs
        to keep track of the global ExecState it started in and the page group
        identifier it is tracking.

        The stopProfiling call now takes the same arguments as startProfiling.
        This makes sure the correct profile is stopped. Passing a null UString
        as the title will stop the last profile for the matching ExecState.

        <rdar://problem/5951559> Multiple pages profiling can interfere with each other

        Reviewed by Kevin McCullough.

        * JavaScriptCore.exp: Added new exports. Removed old symbols.
        * profiler/Profile.cpp:
        (KJS::Profile::Profile): New constructor arguments for the
        originatingGlobalExec and pageGroupIdentifier.
        (KJS::Profile::stopProfiling): Set the m_originatingGlobalExec to null.
        * profiler/Profile.h:
        (KJS::Profile::create): Additional arguments.
        (KJS::Profile::originatingGlobalExec): Return m_originatingGlobalExec.
        (KJS::Profile::pageGroupIdentifier): Return m_pageGroupIdentifier.
        * profiler/Profiler.cpp:
        (KJS::Profiler::findProfile): Added. Finds a Profile that matches
        the ExecState and title.
        (KJS::Profiler::startProfiling): Return early if there is already
        a Profile with the ExecState and title. If not, create a new profile
        and append it to m_currentProfiles.
        (KJS::Profiler::stopProfiling): Loops through m_currentProfiles
        and find the one matching the ExecState and title. If one is found
        call stopProfiling and return the Profile after removing it
        from m_currentProfiles.
        (KJS::dispatchFunctionToProfiles): Helper inline function to loop through
        m_currentProfiles and call a Profile function.
        (KJS::Profiler::willExecute): Call dispatchFunctionToProfiles.
        (KJS::Profiler::didExecute): Ditto.
        * profiler/Profiler.h:

WebCore:

        Changes to work with the new Profiler API. The Profile is now
        stored by the InspectorController when Console.profileEnd is called.
        This solves three issues with the previous design. First, we don't
        keep profiles around unless the Inspector is enabled. Second, we
        only show Profiles initiated by the Page in it's Inspector, not every
        Profile for the whole process. Third, we now show Profiles in the
        Inspector when they are created.

        <rdar://problem/5951562> New profiles aren't added to the Inspector
        as they finish

        Reviewed by Kevin McCullough.

        * bindings/js/JSConsoleCustom.cpp:
        (WebCore::JSConsole::profileEnd): Added. Calls impl()->profileEnd()
        and passes the ExecState and arguments.
        * page/Console.cpp:
        (WebCore::Console::profile):
        (WebCore::Console::profileEnd): Accept the optional title argument
        and pass it to Profilier::stopProfiling along with the ExecState.
        Calls InspectorController::addProfile with the result Profile.
        * page/Console.h:
        * page/Console.idl: Made profileEnd Custom so we can get the ExecState.
        * page/InspectorController.cpp:
        (WebCore::profiles): Renamed from allProfiles. Uses the controller's
        profiles vector.
        (WebCore::InspectorController::addProfile): Appends to m_profiles.
        Calls addScriptProfile if the window is visible.
        (WebCore::InspectorController::windowScriptObjectAvailable): Renamed
        allProfiles to profiles.
        (WebCore::InspectorController::addScriptProfile): Calls addProfile on
        the JavaScript side.
        (WebCore::InspectorController::didCommitLoad): Clears m_profiles.
        * page/InspectorController.h:
        * page/inspector/ProfilesPanel.js: Populates the profiles sidebar the first
        time the panel is shown after a rest.
        * page/inspector/inspector.js: Added addProfile, calls ProfilesPanel's
        addProfile function.

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

15 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/profiler/Profile.cpp
JavaScriptCore/profiler/Profile.h
JavaScriptCore/profiler/Profiler.cpp
JavaScriptCore/profiler/Profiler.h
WebCore/ChangeLog
WebCore/bindings/js/JSConsoleCustom.cpp
WebCore/page/Console.cpp
WebCore/page/Console.h
WebCore/page/Console.idl
WebCore/page/InspectorController.cpp
WebCore/page/InspectorController.h
WebCore/page/inspector/ProfilesPanel.js
WebCore/page/inspector/inspector.js

index 942c506..f461aa3 100644 (file)
@@ -1,3 +1,45 @@
+2008-05-20  Timothy Hatcher  <timothy@apple.com>
+
+        Change the Profiler to allow multiple profiles to be running at
+        the same time. This can happen when you have nested console.profile()
+        calls. This required two changes. First, the Profiler needed to keep a
+        Vector of current profiles, instead of one. Second, a Profile needs
+        to keep track of the global ExecState it started in and the page group
+        identifier it is tracking.
+
+        The stopProfiling call now takes the same arguments as startProfiling.
+        This makes sure the correct profile is stopped. Passing a null UString
+        as the title will stop the last profile for the matching ExecState.
+
+        <rdar://problem/5951559> Multiple pages profiling can interfere with each other
+
+        Reviewed by Kevin McCullough.
+
+        * JavaScriptCore.exp: Added new exports. Removed old symbols.
+        * profiler/Profile.cpp:
+        (KJS::Profile::Profile): New constructor arguments for the
+        originatingGlobalExec and pageGroupIdentifier.
+        (KJS::Profile::stopProfiling): Set the m_originatingGlobalExec to null.
+        * profiler/Profile.h:
+        (KJS::Profile::create): Additional arguments.
+        (KJS::Profile::originatingGlobalExec): Return m_originatingGlobalExec.
+        (KJS::Profile::pageGroupIdentifier): Return m_pageGroupIdentifier.
+        * profiler/Profiler.cpp:
+        (KJS::Profiler::findProfile): Added. Finds a Profile that matches
+        the ExecState and title.
+        (KJS::Profiler::startProfiling): Return early if there is already
+        a Profile with the ExecState and title. If not, create a new profile
+        and append it to m_currentProfiles.
+        (KJS::Profiler::stopProfiling): Loops through m_currentProfiles
+        and find the one matching the ExecState and title. If one is found
+        call stopProfiling and return the Profile after removing it
+        from m_currentProfiles.
+        (KJS::dispatchFunctionToProfiles): Helper inline function to loop through
+        m_currentProfiles and call a Profile function.
+        (KJS::Profiler::willExecute): Call dispatchFunctionToProfiles.
+        (KJS::Profiler::didExecute): Ditto.
+        * profiler/Profiler.h:
+
 2008-05-21  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Darin.
index 62aeec1..204a704 100644 (file)
@@ -197,8 +197,6 @@ __ZN3KJS8JSObject9constructEPNS_9ExecStateERKNS_4ListE
 __ZN3KJS8JSObject9constructEPNS_9ExecStateERKNS_4ListERKNS_10IdentifierERKNS_7UStringEi
 __ZN3KJS8JSObject9putDirectERKNS_10IdentifierEPNS_7JSValueEi
 __ZN3KJS8JSObject9putDirectERKNS_10IdentifierEii
-__ZN3KJS8Profiler13stopProfilingEv
-__ZN3KJS8Profiler14startProfilingEPNS_9ExecStateEjRKNS_7UStringE
 __ZN3KJS8Profiler8profilerEv
 __ZN3KJS8jsStringEPKc
 __ZN3KJS8jsStringERKNS_7UStringE
@@ -207,6 +205,8 @@ __ZN3KJS9Collector17globalObjectCountEv
 __ZN3KJS9Collector20protectedObjectCountEv
 __ZN3KJS9Collector23collectOnMainThreadOnlyEPNS_7JSValueE
 __ZN3KJS9Collector25protectedObjectTypeCountsEv
+__ZN3KJS8Profiler13stopProfilingEPNS_9ExecStateERKNS_7UStringE
+__ZN3KJS8Profiler14startProfilingEPNS_9ExecStateERKNS_7UStringE
 __ZN3KJS9Collector26protectedGlobalObjectCountEv
 __ZN3KJS9Collector4sizeEv
 __ZN3KJS9Collector7collectEv
index 2168b63..e0efd93 100644 (file)
 
 namespace KJS {
 
-Profile::Profile(const UString& title)
+Profile::Profile(const UString& title, ExecState* originatingGlobalExec, unsigned pageGroupIdentifier)
     : m_title(title)
+    , m_originatingGlobalExec(originatingGlobalExec)
+    , m_pageGroupIdentifier(pageGroupIdentifier)
 {
     // FIXME: When multi-threading is supported this will be a vector and calls
     // into the profiler will need to know which thread it is executing on.
     m_callTree = ProfileNode::create(CallIdentifier("Thread_1", 0, 0));
 }
 
+void Profile::stopProfiling()
+{
+    m_originatingGlobalExec = 0;
+    m_callTree->stopProfiling(0, true);
+}
+
 // The callIdentifiers are in order of bottom of the stack to top of the stack so we iterate it backwards.
 void Profile::willExecute(const Vector<CallIdentifier>& callIdentifiers)
 {
index 1ff1033..604d2b8 100644 (file)
 namespace KJS {
 
     class ExecState;
-    class FunctionImp;
-    class JSObject;
 
     class Profile : public RefCounted<Profile> {
     public:
-        static PassRefPtr<Profile> create(const UString& title) { return adoptRef(new Profile(title)); }
+        static PassRefPtr<Profile> create(const UString& title, ExecState* originatingGlobalExec, unsigned pageGroupIdentifier) { return adoptRef(new Profile(title, originatingGlobalExec, pageGroupIdentifier)); }
 
         void willExecute(const Vector<CallIdentifier>& CallIdentifier);
         void didExecute(const Vector<CallIdentifier>& CallIdentifier);
+        void stopProfiling();
 
-        void stopProfiling() { m_callTree->stopProfiling(0, true); };
         const UString& title() const { return m_title; };
         ProfileNode* callTree() const { return m_callTree.get(); };
 
         double totalTime() const { return m_callTree->totalTime(); }
 
+        ExecState* originatingGlobalExec() const { return m_originatingGlobalExec; }
+        unsigned pageGroupIdentifier() const { return m_pageGroupIdentifier; }
+
         void sortTotalTimeDescending() { m_callTree->sortTotalTimeDescending(); }
         void sortTotalTimeAscending() { m_callTree->sortTotalTimeAscending(); }
         void sortSelfTimeDescending() { m_callTree->sortSelfTimeDescending(); }
@@ -65,11 +66,14 @@ namespace KJS {
         void debugPrintDataSampleStyle() const;
 #endif
 
+        typedef void (Profile::*ProfileFunction)(const Vector<CallIdentifier>& callIdentifiers);
+
     private:
-        Profile(const UString& title);
+        Profile(const UString& title, ExecState* originatingGlobalExec, unsigned pageGroupIdentifier);
 
         UString m_title;
-
+        ExecState* m_originatingGlobalExec;
+        unsigned m_pageGroupIdentifier;
         RefPtr<ProfileNode> m_callTree;
     };
 
index 4cbee28..837a2b1 100644 (file)
@@ -55,31 +55,49 @@ Profiler* Profiler::profiler()
     return sharedProfiler;
 }
 
-void Profiler::startProfiling(ExecState* exec, unsigned pageGroupIdentifier, const UString& title)
+Profile* Profiler::findProfile(ExecState* exec, const UString& title) const
 {
-    if (m_profiling)
-        return;
+    ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
+    for (size_t i = 0; i < m_currentProfiles.size(); ++i)
+        if (m_currentProfiles[i]->originatingGlobalExec() == globalExec && (title.isNull() || m_currentProfiles[i]->title() == title))
+            return m_currentProfiles[i].get();
+    return 0;
+}
+
+void Profiler::startProfiling(ExecState* exec, const UString& title)
+{
+    ASSERT_ARG(exec, exec);
 
-    m_pageGroupIdentifier = pageGroupIdentifier;
+    // Check if we currently have a Profile for this global ExecState and title.
+    // If so return early and don't create a new Profile.
+    ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
+    for (size_t i = 0; i < m_currentProfiles.size(); ++i)
+        if (m_currentProfiles[i]->originatingGlobalExec() == globalExec && m_currentProfiles[i]->title() == title)
+            return;
 
-    m_currentProfile = Profile::create(title);
-    m_profiling = true;
-    
+    RefPtr<Profile> profile = Profile::create(title, globalExec, exec->lexicalGlobalObject()->pageGroupIdentifier());
+    m_currentProfiles.append(profile);
+
+    // Update the profile with the current call identifiers that started the profiling.
     Vector<CallIdentifier> callIdentifiers;
     getCallIdentifiers(exec, callIdentifiers);
-    m_currentProfile->willExecute(callIdentifiers);
+    profile->willExecute(callIdentifiers);
 }
 
-void Profiler::stopProfiling()
+PassRefPtr<Profile> Profiler::stopProfiling(ExecState* exec, const UString& title)
 {
-    m_profiling = false;
-
-    if (!m_currentProfile)
-        return;
+    ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
+    for (ssize_t i = m_currentProfiles.size() - 1; i >= 0; --i) {
+        if (m_currentProfiles[i]->originatingGlobalExec() == globalExec && (title.isNull() || m_currentProfiles[i]->title() == title)) {
+            m_currentProfiles[i]->stopProfiling();
+
+            PassRefPtr<Profile> prpProfile = m_currentProfiles[i].release();
+            m_currentProfiles.remove(i);
+            return prpProfile;
+        }
+    }
 
-    m_currentProfile->stopProfiling();
-    m_allProfiles.append(m_currentProfile.release());
-    m_currentProfile = 0;
+    return 0;
 }
 
 static inline bool shouldExcludeFunction(ExecState* exec, JSObject* calledFunction)
@@ -94,9 +112,16 @@ static inline bool shouldExcludeFunction(ExecState* exec, JSObject* calledFuncti
     return false;
 }
 
+static inline void dispatchFunctionToProfiles(const Vector<RefPtr<Profile> >& profiles, Profile::ProfileFunction function, const Vector<CallIdentifier>& callIdentifiers, unsigned currentPageGroupIdentifier)
+{
+    for (size_t i = 0; i < profiles.size(); ++i)
+        if (profiles[i]->pageGroupIdentifier() == currentPageGroupIdentifier)
+            (profiles[i].get()->*function)(callIdentifiers);
+}
+
 void Profiler::willExecute(ExecState* exec, JSObject* calledFunction)
 {
-    if (!m_profiling || exec->lexicalGlobalObject()->pageGroupIdentifier() != m_pageGroupIdentifier)
+    if (m_currentProfiles.isEmpty())
         return;
 
     if (shouldExcludeFunction(exec, calledFunction))
@@ -104,22 +129,24 @@ void Profiler::willExecute(ExecState* exec, JSObject* calledFunction)
 
     Vector<CallIdentifier> callIdentifiers;
     getCallIdentifiers(exec, calledFunction, callIdentifiers);
-    m_currentProfile->willExecute(callIdentifiers);
+
+    dispatchFunctionToProfiles(m_currentProfiles, &Profile::willExecute, callIdentifiers, exec->lexicalGlobalObject()->pageGroupIdentifier());
 }
 
 void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
 {
-    if (!m_profiling || exec->lexicalGlobalObject()->pageGroupIdentifier() != m_pageGroupIdentifier)
+    if (m_currentProfiles.isEmpty())
         return;
 
     Vector<CallIdentifier> callIdentifiers;
     getCallIdentifiers(exec, sourceURL, startingLineNumber, callIdentifiers);
-    m_currentProfile->willExecute(callIdentifiers);
+
+    dispatchFunctionToProfiles(m_currentProfiles, &Profile::willExecute, callIdentifiers, exec->lexicalGlobalObject()->pageGroupIdentifier());
 }
 
 void Profiler::didExecute(ExecState* exec, JSObject* calledFunction)
 {
-    if (!m_profiling || exec->lexicalGlobalObject()->pageGroupIdentifier() != m_pageGroupIdentifier)
+    if (m_currentProfiles.isEmpty())
         return;
 
     if (shouldExcludeFunction(exec, calledFunction))
@@ -127,17 +154,19 @@ void Profiler::didExecute(ExecState* exec, JSObject* calledFunction)
 
     Vector<CallIdentifier> callIdentifiers;
     getCallIdentifiers(exec, calledFunction, callIdentifiers);
-    m_currentProfile->didExecute(callIdentifiers);
+
+    dispatchFunctionToProfiles(m_currentProfiles, &Profile::didExecute, callIdentifiers, exec->lexicalGlobalObject()->pageGroupIdentifier());
 }
 
 void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
 {
-    if (!m_profiling || exec->lexicalGlobalObject()->pageGroupIdentifier() != m_pageGroupIdentifier)
+    if (m_currentProfiles.isEmpty())
         return;
 
     Vector<CallIdentifier> callIdentifiers;
     getCallIdentifiers(exec, sourceURL, startingLineNumber, callIdentifiers);
-    m_currentProfile->didExecute(callIdentifiers);
+
+    dispatchFunctionToProfiles(m_currentProfiles, &Profile::didExecute, callIdentifiers, exec->lexicalGlobalObject()->pageGroupIdentifier());
 }
 
 void getCallIdentifiers(ExecState* exec, Vector<CallIdentifier>& callIdentifiers)
index e84bf9a..4c41ec4 100644 (file)
 namespace KJS {
 
     class ExecState;
-    class FunctionImp;
     class JSObject;
 
     class Profiler {
     public:
         static Profiler* profiler();
 
-        void startProfiling(ExecState*, unsigned pageGroupIdentifier, const UString&);
-        void stopProfiling();
+        void startProfiling(ExecState*, const UString& title);
+        PassRefPtr<Profile> stopProfiling(ExecState*, const UString& title);
+
+        Profile* findProfile(ExecState*, const UString& title) const;
 
         void willExecute(ExecState*, JSObject* calledFunction);
         void willExecute(ExecState*, const UString& sourceURL, int startingLineNumber);
         void didExecute(ExecState*, JSObject* calledFunction);
         void didExecute(ExecState*, const UString& sourceURL, int startingLineNumber);
 
-        const Vector<RefPtr<Profile> >& allProfiles() { return m_allProfiles; };
-        void clearProfiles() { if (!m_profiling) m_allProfiles.clear(); };
-
-        Profile* currentProfile() const { return m_currentProfile.get(); }
+        const Vector<RefPtr<Profile> >& currentProfiles() { return m_currentProfiles; };
 
     private:
-        Profiler()
-            : m_profiling(false)
-            , m_pageGroupIdentifier(0)
-        {
-        }
-
-        bool m_profiling;
-        unsigned m_pageGroupIdentifier;
-
-        RefPtr<Profile> m_currentProfile;
-        Vector<RefPtr<Profile> > m_allProfiles;
+        Vector<RefPtr<Profile> > m_currentProfiles;
     };
 
 } // namespace KJS
index ca54494..fa51d99 100644 (file)
@@ -1,3 +1,44 @@
+2008-05-20  Timothy Hatcher  <timothy@apple.com>
+
+        Changes to work with the new Profiler API. The Profile is now
+        stored by the InspectorController when Console.profileEnd is called.
+        This solves three issues with the previous design. First, we don't
+        keep profiles around unless the Inspector is enabled. Second, we
+        only show Profiles initiated by the Page in it's Inspector, not every
+        Profile for the whole process. Third, we now show Profiles in the
+        Inspector when they are created.
+
+        <rdar://problem/5951562> New profiles aren't added to the Inspector
+        as they finish
+
+        Reviewed by Kevin McCullough.
+
+        * bindings/js/JSConsoleCustom.cpp:
+        (WebCore::JSConsole::profileEnd): Added. Calls impl()->profileEnd()
+        and passes the ExecState and arguments.
+        * page/Console.cpp:
+        (WebCore::Console::profile):
+        (WebCore::Console::profileEnd): Accept the optional title argument
+        and pass it to Profilier::stopProfiling along with the ExecState.
+        Calls InspectorController::addProfile with the result Profile.
+        * page/Console.h:
+        * page/Console.idl: Made profileEnd Custom so we can get the ExecState.
+        * page/InspectorController.cpp:
+        (WebCore::profiles): Renamed from allProfiles. Uses the controller's
+        profiles vector.
+        (WebCore::InspectorController::addProfile): Appends to m_profiles.
+        Calls addScriptProfile if the window is visible.
+        (WebCore::InspectorController::windowScriptObjectAvailable): Renamed
+        allProfiles to profiles.
+        (WebCore::InspectorController::addScriptProfile): Calls addProfile on
+        the JavaScript side.
+        (WebCore::InspectorController::didCommitLoad): Clears m_profiles.
+        * page/InspectorController.h:
+        * page/inspector/ProfilesPanel.js: Populates the profiles sidebar the first
+        time the panel is shown after a rest.
+        * page/inspector/inspector.js: Added addProfile, calls ProfilesPanel's
+        addProfile function.
+
 2008-05-21  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Darin.
index daed126..10b67ce 100644 (file)
@@ -71,4 +71,10 @@ JSValue* JSConsole::profile(ExecState* exec, const List& arguments)
     return jsUndefined();
 }
 
+JSValue* JSConsole::profileEnd(ExecState* exec, const List& arguments)
+{
+    impl()->profileEnd(exec, arguments);
+    return jsUndefined();
+}
+
 } // namespace WebCore
index 57cd8c4..208d509 100644 (file)
@@ -156,12 +156,22 @@ void Console::profile(ExecState* exec, const List& arguments) const
         return;
 
     UString title = arguments[0]->toString(exec);
-    Profiler::profiler()->startProfiling(exec, page->group().identifier(), title);
+    Profiler::profiler()->startProfiling(exec, title);
 }
 
-void Console::profileEnd() const
+void Console::profileEnd(ExecState* exec, const List& arguments) const
 {
-    Profiler::profiler()->stopProfiling();
+    Page* page = m_frame->page();
+    if (!page)
+        return;
+
+    UString title;
+    if (arguments.size() >= 1)
+        title = arguments[0]->toString(exec);
+
+    RefPtr<Profile> profile = Profiler::profiler()->stopProfiling(exec, title);
+    if (profile)
+        page->inspectorController()->addProfile(profile);
 }
 
 void Console::warn(ExecState* exec, const List& arguments)
index 6038cea..5df8fac 100644 (file)
@@ -72,7 +72,7 @@ namespace WebCore {
         void warn(KJS::ExecState*, const KJS::List& arguments);
         void assertCondition(bool condition, KJS::ExecState*, const KJS::List& arguments);
         void profile(KJS::ExecState*, const KJS::List& arguments) const;
-        void profileEnd() const;
+        void profileEnd(KJS::ExecState*, const KJS::List& arguments) const;
 
     private:
         Console(Frame*);
index bfdb7f0..12c6fab 100644 (file)
@@ -36,7 +36,7 @@ module window {
         [Custom, ImplementationFunction=assertCondition] void assert(in boolean condition);
 
         [Custom] void profile(in DOMString title);
-        void profileEnd();
+        [Custom] void profileEnd();
     };
 
 }
index f301607..9fb14b1 100644 (file)
@@ -964,11 +964,15 @@ static JSValueRef removeBreakpoint(JSContextRef ctx, JSObjectRef /*function*/, J
 #pragma mark -
 #pragma mark Profiles
 
-static JSValueRef allProfiles(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef /*thisObject*/, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* exception)
+static JSValueRef profiles(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* exception)
 {
-    KJS::JSLock lock;
+    InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
+    if (!controller)
+        return JSValueMakeUndefined(ctx);
+
+    JSLock lock;
 
-    const Vector<RefPtr<Profile> >& allProfiles = Profiler::profiler()->allProfiles();
+    const Vector<RefPtr<Profile> >& profiles = controller->profiles();
 
     JSObjectRef global = JSContextGetGlobalObject(ctx);
 
@@ -992,8 +996,8 @@ static JSValueRef allProfiles(JSContextRef ctx, JSObjectRef /*function*/, JSObje
     if (exception && *exception)
         return JSValueMakeUndefined(ctx);
 
-    for (size_t i = 0; i < allProfiles.size(); ++i) {
-        JSValueRef arg0 = toRef(toJS(toJS(ctx), allProfiles[i].get()));
+    for (size_t i = 0; i < profiles.size(); ++i) {
+        JSValueRef arg0 = toRef(toJS(toJS(ctx), profiles[i].get()));
         JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception);
         if (exception && *exception)
             return JSValueMakeUndefined(ctx);
@@ -1201,6 +1205,18 @@ void InspectorController::addConsoleMessage(ConsoleMessage* consoleMessage)
         addScriptConsoleMessage(consoleMessage);
 }
 
+void InspectorController::addProfile(PassRefPtr<Profile> prpProfile)
+{
+    if (!enabled())
+        return;
+
+    RefPtr<Profile> profile = prpProfile;
+    m_profiles.append(profile);
+
+    if (windowVisible())
+        addScriptProfile(profile.get());
+}
+
 void InspectorController::attachWindow()
 {
     if (!enabled())
@@ -1247,7 +1263,7 @@ void InspectorController::windowScriptObjectAvailable()
         { "startDebuggingAndReloadInspectedPage", WebCore::startDebuggingAndReloadInspectedPage, kJSPropertyAttributeNone },
         { "stopDebugging", WebCore::stopDebugging, kJSPropertyAttributeNone },
         { "debuggerAttached", WebCore::debuggerAttached, kJSPropertyAttributeNone },
-        { "allProfiles", allProfiles, kJSPropertyAttributeNone },
+        { "profiles", WebCore::profiles, kJSPropertyAttributeNone },
         { "currentCallFrame", WebCore::currentCallFrame, kJSPropertyAttributeNone },
         { "pauseOnExceptions", WebCore::pauseOnExceptions, kJSPropertyAttributeNone },
         { "setPauseOnExceptions", WebCore::setPauseOnExceptions, kJSPropertyAttributeNone },
@@ -1807,6 +1823,14 @@ void InspectorController::addScriptConsoleMessage(const ConsoleMessage* message)
     callFunction(m_scriptContext, m_scriptObject, "addMessageToConsole", 1, &messageObject, exception);
 }
 
+void InspectorController::addScriptProfile(Profile* profile)
+{
+    JSLock lock;
+    JSValueRef exception = 0;
+    JSValueRef profileObject = toRef(toJS(toJS(m_scriptContext), profile));
+    callFunction(m_scriptContext, m_scriptObject, "addProfile", 1, &profileObject, exception);
+}
+
 void InspectorController::resetScriptObjects()
 {
     if (!m_scriptContext || !m_scriptObject)
@@ -1861,6 +1885,8 @@ void InspectorController::didCommitLoad(DocumentLoader* loader)
         deleteAllValues(m_consoleMessages);
         m_consoleMessages.clear();
 
+        m_profiles.clear();
+
 #if ENABLE(DATABASE)
         m_databaseResources.clear();
 #endif
index 5687ee2..244598b 100644 (file)
@@ -38,6 +38,7 @@
 #include <wtf/Vector.h>
 
 namespace KJS {
+    class Profile;
     class UString;
 }
 
@@ -98,6 +99,10 @@ public:
     void addMessageToConsole(MessageSource, MessageLevel, KJS::ExecState*, const KJS::List& arguments, unsigned lineNumber, const String& sourceID);
     void addMessageToConsole(MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceID);
 
+    void addProfile(PassRefPtr<KJS::Profile>);
+    void addScriptProfile(KJS::Profile* profile);
+    const Vector<RefPtr<KJS::Profile> >& profiles() const { return m_profiles; }
+
     void attachWindow();
     void detachWindow();
 
@@ -200,6 +205,7 @@ private:
     ResourcesMap m_resources;
     FrameResourcesMap m_frameResources;
     Vector<ConsoleMessage*> m_consoleMessages;
+    Vector<RefPtr<KJS::Profile> > m_profiles;
 #if ENABLE(DATABASE)
     DatabaseResourcesSet m_databaseResources;
 #endif
index 7cad6f5..6252a4f 100644 (file)
@@ -65,21 +65,19 @@ WebInspector.ProfilesPanel.prototype = {
         WebInspector.Panel.prototype.show.call(this);
         this._updateSidebarWidth();
 
-        // FIXME: the only way to get profiles right now is to ask for the array of all profiles
-        // from the InspectorController. We need to add callback to the profiler that will notify
-        // the Inspector when a new profile is made. That way we can keep the UI updated.
+        if (this._populateProfiles) {
+            var profiles = InspectorController.profiles();
+            var profilesLength = profiles.length;
+            for (var i = 0; i < profilesLength; ++i) {
+                var profile = profiles[i];
+                this.addProfile(profile);
+            }
 
-        this.sidebarTree.removeChildren();
+            if (this.sidebarTree.children[0])
+                this.sidebarTree.children[0].select();
 
-        var profiles = InspectorController.allProfiles();
-        var profilesLength = profiles.length;
-        for (var i = 0; i < profilesLength; ++i) {
-            var profile = profiles[i];
-            this.addProfile(profile);
+            delete this._populateProfiles;
         }
-
-        if (profiles[0])
-            profiles[0]._profilesTreeElement.select();
     },
 
     reset: function()
@@ -96,6 +94,8 @@ WebInspector.ProfilesPanel.prototype = {
 
         this.sidebarTree.removeChildren();
         this.profileViews.removeChildren();
+
+        this._populateProfiles = true;
     },
 
     handleKeyEvent: function(event)
index d4c3cfc..668e51b 100644 (file)
@@ -776,6 +776,11 @@ WebInspector.addMessageToConsole = function(msg)
     this.console.addMessage(msg);
 }
 
+WebInspector.addProfile = function(profile)
+{
+    this.panels.profiles.addProfile(profile);
+}
+
 WebInspector.drawLoadingPieChart = function(canvas, percent) {
     var g = canvas.getContext("2d");
     var darkColor = "rgb(122, 168, 218)";