]> git.saurik.com Git - apple/javascriptcore.git/blob - profiler/ProfilerDatabase.cpp
JavaScriptCore-1218.33.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 "Operations.h"
33
34 namespace JSC { namespace Profiler {
35
36 #if COMPILER(MINGW) || COMPILER(MSVC7_OR_LOWER) || OS(WINCE)
37 static int databaseCounter;
38 #else
39 static volatile int databaseCounter;
40 #endif
41 static SpinLock registrationLock = SPINLOCK_INITIALIZER;
42 static int didRegisterAtExit;
43 static Database* firstDatabase;
44
45 Database::Database(VM& vm)
46 : m_databaseID(atomicIncrement(&databaseCounter))
47 , m_vm(vm)
48 , m_shouldSaveAtExit(false)
49 , m_nextRegisteredDatabase(0)
50 {
51 }
52
53 Database::~Database()
54 {
55 if (m_shouldSaveAtExit) {
56 removeDatabaseFromAtExit();
57 performAtExitSave();
58 }
59 }
60
61 Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock)
62 {
63 codeBlock = codeBlock->baselineVersion();
64
65 HashMap<CodeBlock*, Bytecodes*>::iterator iter = m_bytecodesMap.find(codeBlock);
66 if (iter != m_bytecodesMap.end())
67 return iter->value;
68
69 m_bytecodes.append(Bytecodes(m_bytecodes.size(), codeBlock));
70 Bytecodes* result = &m_bytecodes.last();
71
72 m_bytecodesMap.add(codeBlock, result);
73
74 return result;
75 }
76
77 void Database::notifyDestruction(CodeBlock* codeBlock)
78 {
79 m_bytecodesMap.remove(codeBlock);
80 }
81
82 PassRefPtr<Compilation> Database::newCompilation(Bytecodes* bytecodes, CompilationKind kind)
83 {
84 RefPtr<Compilation> compilation = adoptRef(new Compilation(bytecodes, kind));
85 m_compilations.append(compilation);
86 return compilation.release();
87 }
88
89 PassRefPtr<Compilation> Database::newCompilation(CodeBlock* codeBlock, CompilationKind kind)
90 {
91 return newCompilation(ensureBytecodesFor(codeBlock), kind);
92 }
93
94 JSValue Database::toJS(ExecState* exec) const
95 {
96 JSObject* result = constructEmptyObject(exec);
97
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);
102
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);
107
108 return result;
109 }
110
111 String Database::toJSON() const
112 {
113 JSGlobalObject* globalObject = JSGlobalObject::create(
114 m_vm, JSGlobalObject::createStructure(m_vm, jsNull()));
115
116 return JSONStringify(globalObject->globalExec(), toJS(globalObject->globalExec()), 0);
117 }
118
119 bool Database::save(const char* filename) const
120 {
121 OwnPtr<FilePrintStream> out = FilePrintStream::open(filename, "w");
122 if (!out)
123 return false;
124
125 out->print(toJSON());
126 return true;
127 }
128
129 void Database::registerToSaveAtExit(const char* filename)
130 {
131 m_atExitSaveFilename = filename;
132
133 if (m_shouldSaveAtExit)
134 return;
135
136 addDatabaseToAtExit();
137 m_shouldSaveAtExit = true;
138 }
139
140 void Database::addDatabaseToAtExit()
141 {
142 if (atomicIncrement(&didRegisterAtExit) == 1)
143 atexit(atExitCallback);
144
145 TCMalloc_SpinLockHolder holder(&registrationLock);
146 m_nextRegisteredDatabase = firstDatabase;
147 firstDatabase = this;
148 }
149
150 void Database::removeDatabaseFromAtExit()
151 {
152 TCMalloc_SpinLockHolder holder(&registrationLock);
153 for (Database** current = &firstDatabase; *current; current = &(*current)->m_nextRegisteredDatabase) {
154 if (*current != this)
155 continue;
156 *current = m_nextRegisteredDatabase;
157 m_nextRegisteredDatabase = 0;
158 m_shouldSaveAtExit = false;
159 break;
160 }
161 }
162
163 void Database::performAtExitSave() const
164 {
165 save(m_atExitSaveFilename.data());
166 }
167
168 Database* Database::removeFirstAtExitDatabase()
169 {
170 TCMalloc_SpinLockHolder holder(&registrationLock);
171 Database* result = firstDatabase;
172 if (result) {
173 firstDatabase = result->m_nextRegisteredDatabase;
174 result->m_nextRegisteredDatabase = 0;
175 result->m_shouldSaveAtExit = false;
176 }
177 return result;
178 }
179
180 void Database::atExitCallback()
181 {
182 while (Database* database = removeFirstAtExitDatabase())
183 database->performAtExitSave();
184 }
185
186 } } // namespace JSC::Profiler
187