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 StaticSpinLock registrationLock
;
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 SpinLockHolder
holder(registrationLock
);
142 m_nextRegisteredDatabase
= firstDatabase
;
143 firstDatabase
= this;
146 void Database::removeDatabaseFromAtExit()
148 SpinLockHolder
holder(registrationLock
);
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 SpinLockHolder
holder(registrationLock
);
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