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 "Operations.h"
34 namespace JSC
{ namespace Profiler
{
36 #if COMPILER(MINGW) || COMPILER(MSVC7_OR_LOWER) || OS(WINCE)
37 static int databaseCounter
;
39 static volatile int databaseCounter
;
41 static SpinLock registrationLock
= SPINLOCK_INITIALIZER
;
42 static int didRegisterAtExit
;
43 static Database
* firstDatabase
;
45 Database::Database(VM
& vm
)
46 : m_databaseID(atomicIncrement(&databaseCounter
))
48 , m_shouldSaveAtExit(false)
49 , m_nextRegisteredDatabase(0)
55 if (m_shouldSaveAtExit
) {
56 removeDatabaseFromAtExit();
61 Bytecodes
* Database::ensureBytecodesFor(CodeBlock
* codeBlock
)
63 codeBlock
= codeBlock
->baselineVersion();
65 HashMap
<CodeBlock
*, Bytecodes
*>::iterator iter
= m_bytecodesMap
.find(codeBlock
);
66 if (iter
!= m_bytecodesMap
.end())
69 m_bytecodes
.append(Bytecodes(m_bytecodes
.size(), codeBlock
));
70 Bytecodes
* result
= &m_bytecodes
.last();
72 m_bytecodesMap
.add(codeBlock
, result
);
77 void Database::notifyDestruction(CodeBlock
* codeBlock
)
79 m_bytecodesMap
.remove(codeBlock
);
82 PassRefPtr
<Compilation
> Database::newCompilation(Bytecodes
* bytecodes
, CompilationKind kind
)
84 RefPtr
<Compilation
> compilation
= adoptRef(new Compilation(bytecodes
, kind
));
85 m_compilations
.append(compilation
);
86 return compilation
.release();
89 PassRefPtr
<Compilation
> Database::newCompilation(CodeBlock
* codeBlock
, CompilationKind kind
)
91 return newCompilation(ensureBytecodesFor(codeBlock
), kind
);
94 JSValue
Database::toJS(ExecState
* exec
) const
96 JSObject
* result
= constructEmptyObject(exec
);
98 JSArray
* bytecodes
= constructEmptyArray(exec
, 0);
99 for (unsigned i
= 0; i
< m_bytecodes
.size(); ++i
)
100 bytecodes
->putDirectIndex(exec
, i
, m_bytecodes
[i
].toJS(exec
));
101 result
->putDirect(exec
->vm(), exec
->propertyNames().bytecodes
, bytecodes
);
103 JSArray
* compilations
= constructEmptyArray(exec
, 0);
104 for (unsigned i
= 0; i
< m_compilations
.size(); ++i
)
105 compilations
->putDirectIndex(exec
, i
, m_compilations
[i
]->toJS(exec
));
106 result
->putDirect(exec
->vm(), exec
->propertyNames().compilations
, compilations
);
111 String
Database::toJSON() const
113 JSGlobalObject
* globalObject
= JSGlobalObject::create(
114 m_vm
, JSGlobalObject::createStructure(m_vm
, jsNull()));
116 return JSONStringify(globalObject
->globalExec(), toJS(globalObject
->globalExec()), 0);
119 bool Database::save(const char* filename
) const
121 OwnPtr
<FilePrintStream
> out
= FilePrintStream::open(filename
, "w");
125 out
->print(toJSON());
129 void Database::registerToSaveAtExit(const char* filename
)
131 m_atExitSaveFilename
= filename
;
133 if (m_shouldSaveAtExit
)
136 addDatabaseToAtExit();
137 m_shouldSaveAtExit
= true;
140 void Database::addDatabaseToAtExit()
142 if (atomicIncrement(&didRegisterAtExit
) == 1)
143 atexit(atExitCallback
);
145 TCMalloc_SpinLockHolder
holder(®istrationLock
);
146 m_nextRegisteredDatabase
= firstDatabase
;
147 firstDatabase
= this;
150 void Database::removeDatabaseFromAtExit()
152 TCMalloc_SpinLockHolder
holder(®istrationLock
);
153 for (Database
** current
= &firstDatabase
; *current
; current
= &(*current
)->m_nextRegisteredDatabase
) {
154 if (*current
!= this)
156 *current
= m_nextRegisteredDatabase
;
157 m_nextRegisteredDatabase
= 0;
158 m_shouldSaveAtExit
= false;
163 void Database::performAtExitSave() const
165 save(m_atExitSaveFilename
.data());
168 Database
* Database::removeFirstAtExitDatabase()
170 TCMalloc_SpinLockHolder
holder(®istrationLock
);
171 Database
* result
= firstDatabase
;
173 firstDatabase
= result
->m_nextRegisteredDatabase
;
174 result
->m_nextRegisteredDatabase
= 0;
175 result
->m_shouldSaveAtExit
= false;
180 void Database::atExitCallback()
182 while (Database
* database
= removeFirstAtExitDatabase())
183 database
->performAtExitSave();
186 } } // namespace JSC::Profiler