JSC_enableProfiler=true should also cause JSGlobalData to save the profiler output somewhere
https://bugs.webkit.org/show_bug.cgi?id=113144

Source/JavaScriptCore: 

Reviewed by Geoffrey Garen.
        
Added the ability to save profiler output with JSC_enableProfiler=true. It will save it
to the current directory, or JSC_PROFILER_PATH if the latter was specified.
        
This works by saving the Profiler::Database either when it is destroyed or atexit(),
whichever happens first.
        
This allows use of the profiler from any WebKit client.

* jsc.cpp:
(jscmain):
* profiler/ProfilerDatabase.cpp:
(Profiler):
(JSC::Profiler::Database::Database):
(JSC::Profiler::Database::~Database):
(JSC::Profiler::Database::registerToSaveAtExit):
(JSC::Profiler::Database::addDatabaseToAtExit):
(JSC::Profiler::Database::removeDatabaseFromAtExit):
(JSC::Profiler::Database::performAtExitSave):
(JSC::Profiler::Database::removeFirstAtExitDatabase):
(JSC::Profiler::Database::atExitCallback):
* profiler/ProfilerDatabase.h:
(JSC::Profiler::Database::databaseID):
(Database):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):

Source/WTF: 

Reviewed by Geoffrey Garen.
        
I got tired of the fact that getpid(2) is not a syscall on Windows (unless you do
_getpid() I believe), so I wrote a header that abstracts it. I also changed existing
code that uses getpid() to use WTF::getCurrentProcessID().

* GNUmakefile.list.am:
* WTF.gypi:
* WTF.pro:
* WTF.vcproj/WTF.vcproj:
* WTF.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/MetaAllocator.cpp:
(WTF::MetaAllocator::dumpProfile):
* wtf/ProcessID.h: Added.
(WTF):
(WTF::getCurrentProcessID):
* wtf/text/StringImpl.cpp:
(WTF::StringStats::printStats):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@146932 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
index 3a0a752..acc9531 100644
--- a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,13 +33,25 @@
 
 namespace JSC { namespace Profiler {
 
+static volatile int databaseCounter;
+static SpinLock registrationLock;
+static int didRegisterAtExit;
+static Database* firstDatabase;
+
 Database::Database(JSGlobalData& globalData)
-    : m_globalData(globalData)
+    : m_databaseID(atomicIncrement(&databaseCounter))
+    , m_globalData(globalData)
+    , m_shouldSaveAtExit(false)
+    , m_nextRegisteredDatabase(0)
 {
 }
 
 Database::~Database()
 {
+    if (m_shouldSaveAtExit) {
+        removeDatabaseFromAtExit();
+        performAtExitSave();
+    }
 }
 
 Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock)
@@ -110,5 +122,62 @@
     return true;
 }
 
+void Database::registerToSaveAtExit(const char* filename)
+{
+    m_atExitSaveFilename = filename;
+    
+    if (m_shouldSaveAtExit)
+        return;
+    
+    addDatabaseToAtExit();
+    m_shouldSaveAtExit = true;
+}
+
+void Database::addDatabaseToAtExit()
+{
+    if (atomicIncrement(&didRegisterAtExit) == 1)
+        atexit(atExitCallback);
+    
+    TCMalloc_SpinLockHolder holder(&registrationLock);
+    m_nextRegisteredDatabase = firstDatabase;
+    firstDatabase = this;
+}
+
+void Database::removeDatabaseFromAtExit()
+{
+    TCMalloc_SpinLockHolder holder(&registrationLock);
+    for (Database** current = &firstDatabase; *current; current = &(*current)->m_nextRegisteredDatabase) {
+        if (*current != this)
+            continue;
+        *current = m_nextRegisteredDatabase;
+        m_nextRegisteredDatabase = 0;
+        m_shouldSaveAtExit = false;
+        break;
+    }
+}
+
+void Database::performAtExitSave() const
+{
+    save(m_atExitSaveFilename.data());
+}
+
+Database* Database::removeFirstAtExitDatabase()
+{
+    TCMalloc_SpinLockHolder holder(&registrationLock);
+    Database* result = firstDatabase;
+    if (result) {
+        firstDatabase = result->m_nextRegisteredDatabase;
+        result->m_nextRegisteredDatabase = 0;
+        result->m_shouldSaveAtExit = false;
+    }
+    return result;
+}
+
+void Database::atExitCallback()
+{
+    while (Database* database = removeFirstAtExitDatabase())
+        database->performAtExitSave();
+}
+
 } } // namespace JSC::Profiler