2011-02-10 Geoffrey Garen <ggaren@apple.com>
[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 "CollectorHeapIterator.h"
35 #include "CommonIdentifiers.h"
36 #include "FunctionConstructor.h"
37 #include "GetterSetter.h"
38 #include "Interpreter.h"
39 #include "JSActivation.h"
40 #include "JSAPIValueWrapper.h"
41 #include "JSArray.h"
42 #include "JSByteArray.h"
43 #include "JSClassRef.h"
44 #include "JSFunction.h"
45 #include "JSLock.h"
46 #include "JSNotAnObject.h"
47 #include "JSPropertyNameIterator.h"
48 #include "JSStaticScopeObject.h"
49 #include "Lexer.h"
50 #include "Lookup.h"
51 #include "Nodes.h"
52 #include "Parser.h"
53 #include "RegExpCache.h"
54 #include "StrictEvalActivation.h"
55 #include <wtf/WTFThreadData.h>
56 #if ENABLE(REGEXP_TRACING)
57 #include "RegExp.h"
58 #endif
59
60
61 #if ENABLE(JSC_MULTIPLE_THREADS)
62 #include <wtf/Threading.h>
63 #endif
64
65 #if PLATFORM(MAC)
66 #include "ProfilerServer.h"
67 #include <CoreFoundation/CoreFoundation.h>
68 #endif
69
70 using namespace WTF;
71
72 namespace JSC {
73
74 extern JSC_CONST_HASHTABLE HashTable arrayTable;
75 extern JSC_CONST_HASHTABLE HashTable jsonTable;
76 extern JSC_CONST_HASHTABLE HashTable dateTable;
77 extern JSC_CONST_HASHTABLE HashTable mathTable;
78 extern JSC_CONST_HASHTABLE HashTable numberTable;
79 extern JSC_CONST_HASHTABLE HashTable regExpTable;
80 extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable;
81 extern JSC_CONST_HASHTABLE HashTable stringTable;
82
83 void* JSGlobalData::jsArrayVPtr;
84 void* JSGlobalData::jsByteArrayVPtr;
85 void* JSGlobalData::jsStringVPtr;
86 void* JSGlobalData::jsFunctionVPtr;
87
88 void JSGlobalData::storeVPtrs()
89 {
90     // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction.
91     // COMPILE_ASSERTS below check that this is true.
92     char storage[64];
93
94     COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage);
95     JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack);
96     JSGlobalData::jsArrayVPtr = jsArray->vptr();
97     jsArray->~JSCell();
98
99     COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage);
100     JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
101     JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr();
102     jsByteArray->~JSCell();
103
104     COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage);
105     JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
106     JSGlobalData::jsStringVPtr = jsString->vptr();
107     jsString->~JSCell();
108
109     COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage);
110     JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull()));
111     JSGlobalData::jsFunctionVPtr = jsFunction->vptr();
112     jsFunction->~JSCell();
113 }
114
115 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType)
116     : globalDataType(globalDataType)
117     , clientData(0)
118     , arrayTable(fastNew<HashTable>(JSC::arrayTable))
119     , dateTable(fastNew<HashTable>(JSC::dateTable))
120     , jsonTable(fastNew<HashTable>(JSC::jsonTable))
121     , mathTable(fastNew<HashTable>(JSC::mathTable))
122     , numberTable(fastNew<HashTable>(JSC::numberTable))
123     , regExpTable(fastNew<HashTable>(JSC::regExpTable))
124     , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
125     , stringTable(fastNew<HashTable>(JSC::stringTable))
126     , activationStructure(JSActivation::createStructure(jsNull()))
127     , interruptedExecutionErrorStructure(JSObject::createStructure(jsNull()))
128     , terminatedExecutionErrorStructure(JSObject::createStructure(jsNull()))
129     , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull()))
130     , strictEvalActivationStructure(StrictEvalActivation::createStructure(jsNull()))
131     , stringStructure(JSString::createStructure(jsNull()))
132     , notAnObjectStructure(JSNotAnObject::createStructure(jsNull()))
133     , propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull()))
134     , getterSetterStructure(GetterSetter::createStructure(jsNull()))
135     , apiWrapperStructure(JSAPIValueWrapper::createStructure(jsNull()))
136     , dummyMarkableCellStructure(JSCell::createDummyStructure())
137     , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
138     , propertyNames(new CommonIdentifiers(this))
139     , emptyList(new MarkedArgumentBuffer)
140     , lexer(new Lexer(this))
141     , parser(new Parser)
142     , interpreter(new Interpreter)
143     , heap(this)
144     , dynamicGlobalObject(0)
145     , firstStringifierToMark(0)
146     , cachedUTCOffset(NaN)
147     , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
148     , m_regExpCache(new RegExpCache(this))
149 #if ENABLE(REGEXP_TRACING)
150     , m_rtTraceList(new RTTraceList())
151 #endif
152 #ifndef NDEBUG
153     , exclusiveThread(0)
154 #endif
155 {
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 #endif
288
289 JSGlobalData::ClientData::~ClientData()
290 {
291 }
292
293 void JSGlobalData::resetDateCache()
294 {
295     cachedUTCOffset = NaN;
296     dstOffsetCache.reset();
297     cachedDateString = UString();
298     cachedDateStringValue = NaN;
299     dateInstanceCache.reset();
300 }
301
302 void JSGlobalData::startSampling()
303 {
304     interpreter->startSampling();
305 }
306
307 void JSGlobalData::stopSampling()
308 {
309     interpreter->stopSampling();
310 }
311
312 void JSGlobalData::dumpSampleData(ExecState* exec)
313 {
314     interpreter->dumpSampleData(exec);
315 }
316
317 void JSGlobalData::recompileAllJSFunctions()
318 {
319     // If JavaScript is running, it's not safe to recompile, since we'll end
320     // up throwing away code that is live on the stack.
321     ASSERT(!dynamicGlobalObject);
322
323     LiveObjectIterator it = heap.primaryHeapBegin();
324     LiveObjectIterator heapEnd = heap.primaryHeapEnd();
325     for ( ; it != heapEnd; ++it) {
326         if ((*it)->inherits(&JSFunction::info)) {
327             JSFunction* function = asFunction(*it);
328             if (!function->executable()->isHostFunction())
329                 function->jsExecutable()->discardCode();
330         }
331     }
332 }
333
334 #if ENABLE(REGEXP_TRACING)
335 void JSGlobalData::addRegExpToTrace(PassRefPtr<RegExp> regExp)
336 {
337     m_rtTraceList->add(regExp);
338 }
339
340 void JSGlobalData::dumpRegExpTrace()
341 {
342     // The first RegExp object is ignored.  It is create by the RegExpPrototype ctor and not used.
343     RTTraceList::iterator iter = ++m_rtTraceList->begin();
344     
345     if (iter != m_rtTraceList->end()) {
346         printf("\nRegExp Tracing\n");
347         printf("                                                            match()    matches\n");
348         printf("Regular Expression                          JIT Address      calls      found\n");
349         printf("----------------------------------------+----------------+----------+----------\n");
350     
351         unsigned reCount = 0;
352     
353         for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
354             (*iter)->printTraceData();
355
356         printf("%d Regular Expressions\n", reCount);
357     }
358     
359     m_rtTraceList->clear();
360 }
361 #else
362 void JSGlobalData::dumpRegExpTrace()
363 {
364 }
365 #endif
366
367 } // namespace JSC