blob: f83652dda48fe1dbce1fbcec0e6e823e400c0394 [file] [log] [blame]
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +00001/*
fpizlo@apple.com71834602013-03-26 21:43:27 +00002 * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +00003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26#include "config.h"
27#include "ProfilerDatabase.h"
28
29#include "CodeBlock.h"
30#include "JSONObject.h"
ggaren@apple.comc862eac2013-01-29 05:48:01 +000031#include "ObjectConstructor.h"
fpizlo@apple.coma4b4cbe2013-01-12 04:47:03 +000032#include "Operations.h"
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +000033
34namespace JSC { namespace Profiler {
35
andersca@apple.com99491a22014-01-25 21:16:42 +000036static std::atomic<int> databaseCounter;
37
fpizlo@apple.coma6734fc2013-03-26 21:46:00 +000038static SpinLock registrationLock = SPINLOCK_INITIALIZER;
andersca@apple.com99491a22014-01-25 21:16:42 +000039static std::atomic<int> didRegisterAtExit;
fpizlo@apple.com71834602013-03-26 21:43:27 +000040static Database* firstDatabase;
41
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000042Database::Database(VM& vm)
andersca@apple.com99491a22014-01-25 21:16:42 +000043 : m_databaseID(++databaseCounter)
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000044 , m_vm(vm)
fpizlo@apple.com71834602013-03-26 21:43:27 +000045 , m_shouldSaveAtExit(false)
46 , m_nextRegisteredDatabase(0)
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +000047{
48}
49
50Database::~Database()
51{
fpizlo@apple.com71834602013-03-26 21:43:27 +000052 if (m_shouldSaveAtExit) {
53 removeDatabaseFromAtExit();
54 performAtExitSave();
55 }
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +000056}
57
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +000058Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock)
59{
oliver@apple.com4bba8c02013-07-25 03:59:31 +000060 Locker locker(m_lock);
61
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +000062 codeBlock = codeBlock->baselineVersion();
63
64 HashMap<CodeBlock*, Bytecodes*>::iterator iter = m_bytecodesMap.find(codeBlock);
65 if (iter != m_bytecodesMap.end())
66 return iter->value;
67
fpizlo@apple.com77ef0e32012-12-12 00:21:43 +000068 m_bytecodes.append(Bytecodes(m_bytecodes.size(), codeBlock));
69 Bytecodes* result = &m_bytecodes.last();
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +000070
71 m_bytecodesMap.add(codeBlock, result);
72
73 return result;
74}
75
76void Database::notifyDestruction(CodeBlock* codeBlock)
77{
oliver@apple.com4bba8c02013-07-25 03:59:31 +000078 Locker locker(m_lock);
79
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +000080 m_bytecodesMap.remove(codeBlock);
81}
82
oliver@apple.com4bba8c02013-07-25 03:59:31 +000083void Database::addCompilation(PassRefPtr<Compilation> compilation)
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +000084{
oliver@apple.com4bba8c02013-07-25 03:59:31 +000085 ASSERT(!isCompilationThread());
86
fpizlo@apple.comd2deec82012-12-10 18:17:46 +000087 m_compilations.append(compilation);
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +000088}
89
90JSValue Database::toJS(ExecState* exec) const
91{
92 JSObject* result = constructEmptyObject(exec);
93
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));
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000097 result->putDirect(exec->vm(), exec->propertyNames().bytecodes, bytecodes);
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +000098
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));
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +0000102 result->putDirect(exec->vm(), exec->propertyNames().compilations, compilations);
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +0000103
104 return result;
105}
106
107String Database::toJSON() const
108{
109 JSGlobalObject* globalObject = JSGlobalObject::create(
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +0000110 m_vm, JSGlobalObject::createStructure(m_vm, jsNull()));
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +0000111
112 return JSONStringify(globalObject->globalExec(), toJS(globalObject->globalExec()), 0);
113}
114
115bool Database::save(const char* filename) const
116{
andersca@apple.com8359a7b2013-10-05 18:59:00 +0000117 auto out = FilePrintStream::open(filename, "w");
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +0000118 if (!out)
119 return false;
120
121 out->print(toJSON());
122 return true;
123}
124
fpizlo@apple.com71834602013-03-26 21:43:27 +0000125void Database::registerToSaveAtExit(const char* filename)
126{
127 m_atExitSaveFilename = filename;
128
129 if (m_shouldSaveAtExit)
130 return;
131
132 addDatabaseToAtExit();
133 m_shouldSaveAtExit = true;
134}
135
136void Database::addDatabaseToAtExit()
137{
andersca@apple.com99491a22014-01-25 21:16:42 +0000138 if (++didRegisterAtExit == 1)
fpizlo@apple.com71834602013-03-26 21:43:27 +0000139 atexit(atExitCallback);
140
141 TCMalloc_SpinLockHolder holder(&registrationLock);
142 m_nextRegisteredDatabase = firstDatabase;
143 firstDatabase = this;
144}
145
146void Database::removeDatabaseFromAtExit()
147{
148 TCMalloc_SpinLockHolder holder(&registrationLock);
149 for (Database** current = &firstDatabase; *current; current = &(*current)->m_nextRegisteredDatabase) {
150 if (*current != this)
151 continue;
152 *current = m_nextRegisteredDatabase;
153 m_nextRegisteredDatabase = 0;
154 m_shouldSaveAtExit = false;
155 break;
156 }
157}
158
159void Database::performAtExitSave() const
160{
161 save(m_atExitSaveFilename.data());
162}
163
164Database* Database::removeFirstAtExitDatabase()
165{
166 TCMalloc_SpinLockHolder holder(&registrationLock);
167 Database* result = firstDatabase;
168 if (result) {
169 firstDatabase = result->m_nextRegisteredDatabase;
170 result->m_nextRegisteredDatabase = 0;
171 result->m_shouldSaveAtExit = false;
172 }
173 return result;
174}
175
176void Database::atExitCallback()
177{
178 while (Database* database = removeFirstAtExitDatabase())
179 database->performAtExitSave();
180}
181
fpizlo@apple.com4a81fa42012-12-05 01:26:13 +0000182} } // namespace JSC::Profiler
183