]> git.saurik.com Git - apple/javascriptcore.git/blob - profiler/ProfilerDatabase.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / profiler / ProfilerDatabase.cpp
1 /*
2 * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
3 *
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"
31 #include "ObjectConstructor.h"
32 #include "JSCInlines.h"
33
34 namespace JSC { namespace Profiler {
35
36 static std::atomic<int> databaseCounter;
37
38 static StaticSpinLock registrationLock;
39 static std::atomic<int> didRegisterAtExit;
40 static Database* firstDatabase;
41
42 Database::Database(VM& vm)
43 : m_databaseID(++databaseCounter)
44 , m_vm(vm)
45 , m_shouldSaveAtExit(false)
46 , m_nextRegisteredDatabase(0)
47 {
48 }
49
50 Database::~Database()
51 {
52 if (m_shouldSaveAtExit) {
53 removeDatabaseFromAtExit();
54 performAtExitSave();
55 }
56 }
57
58 Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock)
59 {
60 Locker locker(m_lock);
61
62 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
68 m_bytecodes.append(Bytecodes(m_bytecodes.size(), codeBlock));
69 Bytecodes* result = &m_bytecodes.last();
70
71 m_bytecodesMap.add(codeBlock, result);
72
73 return result;
74 }
75
76 void Database::notifyDestruction(CodeBlock* codeBlock)
77 {
78 Locker locker(m_lock);
79
80 m_bytecodesMap.remove(codeBlock);
81 }
82
83 void Database::addCompilation(PassRefPtr<Compilation> compilation)
84 {
85 ASSERT(!isCompilationThread());
86
87 m_compilations.append(compilation);
88 }
89
90 JSValue 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));
97 result->putDirect(exec->vm(), exec->propertyNames().bytecodes, bytecodes);
98
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);
103
104 return result;
105 }
106
107 String Database::toJSON() const
108 {
109 JSGlobalObject* globalObject = JSGlobalObject::create(
110 m_vm, JSGlobalObject::createStructure(m_vm, jsNull()));
111
112 return JSONStringify(globalObject->globalExec(), toJS(globalObject->globalExec()), 0);
113 }
114
115 bool Database::save(const char* filename) const
116 {
117 auto out = FilePrintStream::open(filename, "w");
118 if (!out)
119 return false;
120
121 out->print(toJSON());
122 return true;
123 }
124
125 void 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
136 void Database::addDatabaseToAtExit()
137 {
138 if (++didRegisterAtExit == 1)
139 atexit(atExitCallback);
140
141 SpinLockHolder holder(registrationLock);
142 m_nextRegisteredDatabase = firstDatabase;
143 firstDatabase = this;
144 }
145
146 void Database::removeDatabaseFromAtExit()
147 {
148 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
159 void Database::performAtExitSave() const
160 {
161 save(m_atExitSaveFilename.data());
162 }
163
164 Database* Database::removeFirstAtExitDatabase()
165 {
166 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
176 void Database::atExitCallback()
177 {
178 while (Database* database = removeFirstAtExitDatabase())
179 database->performAtExitSave();
180 }
181
182 } } // namespace JSC::Profiler
183