2  * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. 
   4  * Redistribution and use in source and binary forms, with or without 
   5  * modification, are permitted provided that the following conditions 
   7  * 1. Redistributions of source code must retain the above copyright 
   8  *    notice, this list of conditions and the following disclaimer. 
   9  * 2. Redistributions in binary form must reproduce the above copyright 
  10  *    notice, this list of conditions and the following disclaimer in the 
  11  *    documentation and/or other materials provided with the distribution. 
  13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 
  14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR 
  17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
  19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
  21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
  22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
  23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
  27 #include "ProfilerDatabase.h" 
  29 #include "CodeBlock.h" 
  30 #include "JSONObject.h" 
  31 #include "ObjectConstructor.h" 
  32 #include "JSCInlines.h" 
  34 namespace JSC 
{ namespace Profiler 
{ 
  36 static std::atomic
<int> databaseCounter
; 
  38 static SpinLock registrationLock 
= SPINLOCK_INITIALIZER
; 
  39 static std::atomic
<int> didRegisterAtExit
; 
  40 static Database
* firstDatabase
; 
  42 Database::Database(VM
& vm
) 
  43     : m_databaseID(++databaseCounter
) 
  45     , m_shouldSaveAtExit(false) 
  46     , m_nextRegisteredDatabase(0) 
  52     if (m_shouldSaveAtExit
) { 
  53         removeDatabaseFromAtExit(); 
  58 Bytecodes
* Database::ensureBytecodesFor(CodeBlock
* codeBlock
) 
  60     Locker 
locker(m_lock
); 
  62     codeBlock 
= codeBlock
->baselineVersion(); 
  64     HashMap
<CodeBlock
*, Bytecodes
*>::iterator iter 
= m_bytecodesMap
.find(codeBlock
); 
  65     if (iter 
!= m_bytecodesMap
.end()) 
  68     m_bytecodes
.append(Bytecodes(m_bytecodes
.size(), codeBlock
)); 
  69     Bytecodes
* result 
= &m_bytecodes
.last(); 
  71     m_bytecodesMap
.add(codeBlock
, result
); 
  76 void Database::notifyDestruction(CodeBlock
* codeBlock
) 
  78     Locker 
locker(m_lock
); 
  80     m_bytecodesMap
.remove(codeBlock
); 
  83 void Database::addCompilation(PassRefPtr
<Compilation
> compilation
) 
  85     ASSERT(!isCompilationThread()); 
  87     m_compilations
.append(compilation
); 
  90 JSValue 
Database::toJS(ExecState
* exec
) const 
  92     JSObject
* result 
= constructEmptyObject(exec
); 
  94     JSArray
* bytecodes 
= constructEmptyArray(exec
, 0); 
  95     for (unsigned i 
= 0; i 
< m_bytecodes
.size(); ++i
) 
  96         bytecodes
->putDirectIndex(exec
, i
, m_bytecodes
[i
].toJS(exec
)); 
  97     result
->putDirect(exec
->vm(), exec
->propertyNames().bytecodes
, bytecodes
); 
  99     JSArray
* compilations 
= constructEmptyArray(exec
, 0); 
 100     for (unsigned i 
= 0; i 
< m_compilations
.size(); ++i
) 
 101         compilations
->putDirectIndex(exec
, i
, m_compilations
[i
]->toJS(exec
)); 
 102     result
->putDirect(exec
->vm(), exec
->propertyNames().compilations
, compilations
); 
 107 String 
Database::toJSON() const 
 109     JSGlobalObject
* globalObject 
= JSGlobalObject::create( 
 110         m_vm
, JSGlobalObject::createStructure(m_vm
, jsNull())); 
 112     return JSONStringify(globalObject
->globalExec(), toJS(globalObject
->globalExec()), 0); 
 115 bool Database::save(const char* filename
) const 
 117     auto out 
= FilePrintStream::open(filename
, "w"); 
 121     out
->print(toJSON()); 
 125 void Database::registerToSaveAtExit(const char* filename
) 
 127     m_atExitSaveFilename 
= filename
; 
 129     if (m_shouldSaveAtExit
) 
 132     addDatabaseToAtExit(); 
 133     m_shouldSaveAtExit 
= true; 
 136 void Database::addDatabaseToAtExit() 
 138     if (++didRegisterAtExit 
== 1) 
 139         atexit(atExitCallback
); 
 141     TCMalloc_SpinLockHolder 
holder(®istrationLock
); 
 142     m_nextRegisteredDatabase 
= firstDatabase
; 
 143     firstDatabase 
= this; 
 146 void Database::removeDatabaseFromAtExit() 
 148     TCMalloc_SpinLockHolder 
holder(®istrationLock
); 
 149     for (Database
** current 
= &firstDatabase
; *current
; current 
= &(*current
)->m_nextRegisteredDatabase
) { 
 150         if (*current 
!= this) 
 152         *current 
= m_nextRegisteredDatabase
; 
 153         m_nextRegisteredDatabase 
= 0; 
 154         m_shouldSaveAtExit 
= false; 
 159 void Database::performAtExitSave() const 
 161     save(m_atExitSaveFilename
.data()); 
 164 Database
* Database::removeFirstAtExitDatabase() 
 166     TCMalloc_SpinLockHolder 
holder(®istrationLock
); 
 167     Database
* result 
= firstDatabase
; 
 169         firstDatabase 
= result
->m_nextRegisteredDatabase
; 
 170         result
->m_nextRegisteredDatabase 
= 0; 
 171         result
->m_shouldSaveAtExit 
= false; 
 176 void Database::atExitCallback() 
 178     while (Database
* database 
= removeFirstAtExitDatabase()) 
 179         database
->performAtExitSave(); 
 182 } } // namespace JSC::Profiler