d78305a190ac88eb7902d0280a817349a7347ea2
[WebKit-https.git] / Source / JavaScriptCore / 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 StaticLock 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     LockHolder holder(registrationLock);
142     m_nextRegisteredDatabase = firstDatabase;
143     firstDatabase = this;
144 }
145
146 void Database::removeDatabaseFromAtExit()
147 {
148     LockHolder 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     LockHolder 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