dcbe3c4bbd50a7b2b2014cf5359db81144779d34
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSGlobalData.cpp
1 /*
2  * Copyright (C) 2008 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "JSGlobalData.h"
31
32 #include "ArgList.h"
33 #include "Heap.h"
34 #include "CommonIdentifiers.h"
35 #include "FunctionConstructor.h"
36 #include "GetterSetter.h"
37 #include "Interpreter.h"
38 #include "JSActivation.h"
39 #include "JSAPIValueWrapper.h"
40 #include "JSArray.h"
41 #include "JSByteArray.h"
42 #include "JSClassRef.h"
43 #include "JSFunction.h"
44 #include "JSLock.h"
45 #include "JSNotAnObject.h"
46 #include "JSPropertyNameIterator.h"
47 #include "JSStaticScopeObject.h"
48 #include "Lexer.h"
49 #include "Lookup.h"
50 #include "Nodes.h"
51 #include "Parser.h"
52 #include "RegExpCache.h"
53 #include "StrictEvalActivation.h"
54 #include <wtf/WTFThreadData.h>
55 #if ENABLE(REGEXP_TRACING)
56 #include "RegExp.h"
57 #endif
58
59
60 #if ENABLE(JSC_MULTIPLE_THREADS)
61 #include <wtf/Threading.h>
62 #endif
63
64 #if PLATFORM(MAC)
65 #include "ProfilerServer.h"
66 #include <CoreFoundation/CoreFoundation.h>
67 #endif
68
69 using namespace WTF;
70
71 namespace JSC {
72
73 extern JSC_CONST_HASHTABLE HashTable arrayTable;
74 extern JSC_CONST_HASHTABLE HashTable jsonTable;
75 extern JSC_CONST_HASHTABLE HashTable dateTable;
76 extern JSC_CONST_HASHTABLE HashTable mathTable;
77 extern JSC_CONST_HASHTABLE HashTable numberTable;
78 extern JSC_CONST_HASHTABLE HashTable regExpTable;
79 extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable;
80 extern JSC_CONST_HASHTABLE HashTable stringTable;
81
82 void* JSGlobalData::jsArrayVPtr;
83 void* JSGlobalData::jsByteArrayVPtr;
84 void* JSGlobalData::jsStringVPtr;
85 void* JSGlobalData::jsFunctionVPtr;
86
87 void JSGlobalData::storeVPtrs()
88 {
89     // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction.
90     // COMPILE_ASSERTS below check that this is true.
91     char storage[64];
92
93     COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage);
94     JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack);
95     JSGlobalData::jsArrayVPtr = jsArray->vptr();
96     jsArray->~JSCell();
97
98     COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage);
99     JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
100     JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr();
101     jsByteArray->~JSCell();
102
103     COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage);
104     JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
105     JSGlobalData::jsStringVPtr = jsString->vptr();
106     jsString->~JSCell();
107
108     COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage);
109     JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull()));
110     JSGlobalData::jsFunctionVPtr = jsFunction->vptr();
111     jsFunction->~JSCell();
112 }
113
114 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType)
115     : globalDataType(globalDataType)
116     , clientData(0)
117     , arrayTable(fastNew<HashTable>(JSC::arrayTable))
118     , dateTable(fastNew<HashTable>(JSC::dateTable))
119     , jsonTable(fastNew<HashTable>(JSC::jsonTable))
120     , mathTable(fastNew<HashTable>(JSC::mathTable))
121     , numberTable(fastNew<HashTable>(JSC::numberTable))
122     , regExpTable(fastNew<HashTable>(JSC::regExpTable))
123     , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
124     , stringTable(fastNew<HashTable>(JSC::stringTable))
125     , activationStructure(JSActivation::createStructure(jsNull()))
126     , interruptedExecutionErrorStructure(createEmptyObjectStructure(jsNull()))
127     , terminatedExecutionErrorStructure(createEmptyObjectStructure(jsNull()))
128     , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull()))
129     , strictEvalActivationStructure(StrictEvalActivation::createStructure(jsNull()))
130     , stringStructure(JSString::createStructure(jsNull()))
131     , notAnObjectStructure(JSNotAnObject::createStructure(jsNull()))
132     , propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull()))
133     , getterSetterStructure(GetterSetter::createStructure(jsNull()))
134     , apiWrapperStructure(JSAPIValueWrapper::createStructure(jsNull()))
135     , dummyMarkableCellStructure(JSCell::createDummyStructure())
136     , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
137     , propertyNames(new CommonIdentifiers(this))
138     , emptyList(new MarkedArgumentBuffer)
139     , lexer(new Lexer(this))
140     , parser(new Parser)
141     , interpreter(0)
142     , heap(this)
143     , dynamicGlobalObject(0)
144     , firstStringifierToMark(0)
145     , cachedUTCOffset(NaN)
146     , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
147     , m_regExpCache(new RegExpCache(this))
148 #if ENABLE(REGEXP_TRACING)
149     , m_rtTraceList(new RTTraceList())
150 #endif
151 #ifndef NDEBUG
152     , exclusiveThread(0)
153 #endif
154 {
155     interpreter = new Interpreter(*this);
156     if (globalDataType == Default)
157         m_stack = wtfThreadData().stack();
158
159 #if PLATFORM(MAC)
160     startProfilerServerIfNeeded();
161 #endif
162 #if ENABLE(JIT) && ENABLE(INTERPRETER)
163 #if PLATFORM(CF)
164     CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
165     CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
166     if (canUseJIT) {
167         m_canUseJIT = kCFBooleanTrue == canUseJIT;
168         CFRelease(canUseJIT);
169     } else {
170       char* canUseJITString = getenv("JavaScriptCoreUseJIT");
171       m_canUseJIT = !canUseJITString || atoi(canUseJITString);
172     }
173     CFRelease(canUseJITKey);
174 #elif OS(UNIX)
175     char* canUseJITString = getenv("JavaScriptCoreUseJIT");
176     m_canUseJIT = !canUseJITString || atoi(canUseJITString);
177 #else
178     m_canUseJIT = true;
179 #endif
180 #endif
181 #if ENABLE(JIT)
182 #if ENABLE(INTERPRETER)
183     if (m_canUseJIT)
184         m_canUseJIT = executableAllocator.isValid();
185 #endif
186     jitStubs = new JITThunks(this);
187 #endif
188 }
189
190 JSGlobalData::~JSGlobalData()
191 {
192     // By the time this is destroyed, heap.destroy() must already have been called.
193
194     delete interpreter;
195 #ifndef NDEBUG
196     // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance.
197     interpreter = 0;
198 #endif
199
200     arrayTable->deleteTable();
201     dateTable->deleteTable();
202     jsonTable->deleteTable();
203     mathTable->deleteTable();
204     numberTable->deleteTable();
205     regExpTable->deleteTable();
206     regExpConstructorTable->deleteTable();
207     stringTable->deleteTable();
208
209     fastDelete(const_cast<HashTable*>(arrayTable));
210     fastDelete(const_cast<HashTable*>(dateTable));
211     fastDelete(const_cast<HashTable*>(jsonTable));
212     fastDelete(const_cast<HashTable*>(mathTable));
213     fastDelete(const_cast<HashTable*>(numberTable));
214     fastDelete(const_cast<HashTable*>(regExpTable));
215     fastDelete(const_cast<HashTable*>(regExpConstructorTable));
216     fastDelete(const_cast<HashTable*>(stringTable));
217
218     delete parser;
219     delete lexer;
220
221     deleteAllValues(opaqueJSClassData);
222
223     delete emptyList;
224
225     delete propertyNames;
226     if (globalDataType != Default)
227         deleteIdentifierTable(identifierTable);
228
229     delete clientData;
230     delete m_regExpCache;
231 #if ENABLE(REGEXP_TRACING)
232     delete m_rtTraceList;
233 #endif
234 }
235
236 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type)
237 {
238     return adoptRef(new JSGlobalData(APIContextGroup, type));
239 }
240
241 PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type)
242 {
243     return adoptRef(new JSGlobalData(Default, type));
244 }
245
246 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type)
247 {
248     Structure::startIgnoringLeaks();
249     RefPtr<JSGlobalData> data = create(type);
250     Structure::stopIgnoringLeaks();
251     return data.release();
252 }
253
254 bool JSGlobalData::sharedInstanceExists()
255 {
256     return sharedInstanceInternal();
257 }
258
259 JSGlobalData& JSGlobalData::sharedInstance()
260 {
261     JSGlobalData*& instance = sharedInstanceInternal();
262     if (!instance) {
263         instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall)).leakRef();
264 #if ENABLE(JSC_MULTIPLE_THREADS)
265         instance->makeUsableFromMultipleThreads();
266 #endif
267     }
268     return *instance;
269 }
270
271 JSGlobalData*& JSGlobalData::sharedInstanceInternal()
272 {
273     ASSERT(JSLock::currentThreadIsHoldingLock());
274     static JSGlobalData* sharedInstance;
275     return sharedInstance;
276 }
277
278 #if ENABLE(JIT)
279 PassRefPtr<NativeExecutable> JSGlobalData::getHostFunction(NativeFunction function)
280 {
281     return jitStubs->hostFunctionStub(this, function);
282 }
283 PassRefPtr<NativeExecutable> JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator)
284 {
285     return jitStubs->hostFunctionStub(this, function, generator);
286 }
287 #else
288 PassRefPtr<NativeExecutable> JSGlobalData::getHostFunction(NativeFunction function)
289 {
290     return NativeExecutable::create(function, callHostFunctionAsConstructor);
291 }
292 #endif
293
294 JSGlobalData::ClientData::~ClientData()
295 {
296 }
297
298 void JSGlobalData::resetDateCache()
299 {
300     cachedUTCOffset = NaN;
301     dstOffsetCache.reset();
302     cachedDateString = UString();
303     cachedDateStringValue = NaN;
304     dateInstanceCache.reset();
305 }
306
307 void JSGlobalData::startSampling()
308 {
309     interpreter->startSampling();
310 }
311
312 void JSGlobalData::stopSampling()
313 {
314     interpreter->stopSampling();
315 }
316
317 void JSGlobalData::dumpSampleData(ExecState* exec)
318 {
319     interpreter->dumpSampleData(exec);
320 }
321
322 class Recompiler {
323 public:
324     void operator()(JSCell*);
325 };
326
327 inline void Recompiler::operator()(JSCell* cell)
328 {
329     if (!cell->inherits(&JSFunction::s_info))
330         return;
331     JSFunction* function = asFunction(cell);
332     if (function->executable()->isHostFunction())
333         return;
334     function->jsExecutable()->discardCode();
335 }
336
337
338 void JSGlobalData::recompileAllJSFunctions()
339 {
340     // If JavaScript is running, it's not safe to recompile, since we'll end
341     // up throwing away code that is live on the stack.
342     ASSERT(!dynamicGlobalObject);
343     
344     Recompiler recompiler;
345     heap.forEach(recompiler);
346 }
347
348 #if ENABLE(REGEXP_TRACING)
349 void JSGlobalData::addRegExpToTrace(PassRefPtr<RegExp> regExp)
350 {
351     m_rtTraceList->add(regExp);
352 }
353
354 void JSGlobalData::dumpRegExpTrace()
355 {
356     // The first RegExp object is ignored.  It is create by the RegExpPrototype ctor and not used.
357     RTTraceList::iterator iter = ++m_rtTraceList->begin();
358     
359     if (iter != m_rtTraceList->end()) {
360         printf("\nRegExp Tracing\n");
361         printf("                                                            match()    matches\n");
362         printf("Regular Expression                          JIT Address      calls      found\n");
363         printf("----------------------------------------+----------------+----------+----------\n");
364     
365         unsigned reCount = 0;
366     
367         for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
368             (*iter)->printTraceData();
369
370         printf("%d Regular Expressions\n", reCount);
371     }
372     
373     m_rtTraceList->clear();
374 }
375 #else
376 void JSGlobalData::dumpRegExpTrace()
377 {
378 }
379 #endif
380
381 } // namespace JSC