6ef7542dc42722c46ea730229e219ff501cc1d4b
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSGlobalData.cpp
1 /*
2  * Copyright (C) 2008, 2011 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 "DebuggerActivation.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 "JSZombie.h"
50 #include "Lexer.h"
51 #include "Lookup.h"
52 #include "Nodes.h"
53 #include "Parser.h"
54 #include "RegExpCache.h"
55 #include "RegExpObject.h"
56 #include "StrictEvalActivation.h"
57 #include <wtf/WTFThreadData.h>
58 #if ENABLE(REGEXP_TRACING)
59 #include "RegExp.h"
60 #endif
61
62
63 #if ENABLE(JSC_MULTIPLE_THREADS)
64 #include <wtf/Threading.h>
65 #endif
66
67 #if PLATFORM(MAC)
68 #include "ProfilerServer.h"
69 #include <CoreFoundation/CoreFoundation.h>
70 #endif
71
72 using namespace WTF;
73
74 namespace {
75
76 using namespace JSC;
77
78 class Recompiler : public MarkedBlock::VoidFunctor {
79 public:
80     void operator()(JSCell*);
81 };
82
83 inline void Recompiler::operator()(JSCell* cell)
84 {
85     if (!cell->inherits(&JSFunction::s_info))
86         return;
87     JSFunction* function = asFunction(cell);
88     if (function->executable()->isHostFunction())
89         return;
90     function->jsExecutable()->discardCode();
91 }
92
93 } // namespace
94
95 namespace JSC {
96
97 extern JSC_CONST_HASHTABLE HashTable arrayConstructorTable;
98 extern JSC_CONST_HASHTABLE HashTable arrayPrototypeTable;
99 extern JSC_CONST_HASHTABLE HashTable booleanPrototypeTable;
100 extern JSC_CONST_HASHTABLE HashTable jsonTable;
101 extern JSC_CONST_HASHTABLE HashTable dateTable;
102 extern JSC_CONST_HASHTABLE HashTable dateConstructorTable;
103 extern JSC_CONST_HASHTABLE HashTable errorPrototypeTable;
104 extern JSC_CONST_HASHTABLE HashTable globalObjectTable;
105 extern JSC_CONST_HASHTABLE HashTable mathTable;
106 extern JSC_CONST_HASHTABLE HashTable numberConstructorTable;
107 extern JSC_CONST_HASHTABLE HashTable numberPrototypeTable;
108 extern JSC_CONST_HASHTABLE HashTable objectConstructorTable;
109 extern JSC_CONST_HASHTABLE HashTable objectPrototypeTable;
110 extern JSC_CONST_HASHTABLE HashTable regExpTable;
111 extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable;
112 extern JSC_CONST_HASHTABLE HashTable regExpPrototypeTable;
113 extern JSC_CONST_HASHTABLE HashTable stringTable;
114 extern JSC_CONST_HASHTABLE HashTable stringConstructorTable;
115
116 void* JSGlobalData::jsArrayVPtr;
117 void* JSGlobalData::jsByteArrayVPtr;
118 void* JSGlobalData::jsStringVPtr;
119 void* JSGlobalData::jsFunctionVPtr;
120
121 #if COMPILER(GCC)
122 // Work around for gcc trying to coalesce our reads of the various cell vptrs
123 #define CLOBBER_MEMORY() do { \
124     asm volatile ("" : : : "memory"); \
125 } while (false)
126 #else
127 #define CLOBBER_MEMORY() do { } while (false)
128 #endif
129
130 void JSGlobalData::storeVPtrs()
131 {
132     // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction.
133     // COMPILE_ASSERTS below check that this is true.
134     char storage[64];
135
136     COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage);
137     JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack);
138     CLOBBER_MEMORY();
139     JSGlobalData::jsArrayVPtr = jsArray->vptr();
140
141     COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage);
142     JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
143     CLOBBER_MEMORY();
144     JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr();
145
146     COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage);
147     JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
148     CLOBBER_MEMORY();
149     JSGlobalData::jsStringVPtr = jsString->vptr();
150
151     COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage);
152     JSCell* jsFunction = new (storage) JSFunction(JSCell::VPtrStealingHack);
153     CLOBBER_MEMORY();
154     JSGlobalData::jsFunctionVPtr = jsFunction->vptr();
155 }
156
157 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType)
158     : globalDataType(globalDataType)
159     , clientData(0)
160     , arrayConstructorTable(fastNew<HashTable>(JSC::arrayConstructorTable))
161     , arrayPrototypeTable(fastNew<HashTable>(JSC::arrayPrototypeTable))
162     , booleanPrototypeTable(fastNew<HashTable>(JSC::booleanPrototypeTable))
163     , dateTable(fastNew<HashTable>(JSC::dateTable))
164     , dateConstructorTable(fastNew<HashTable>(JSC::dateConstructorTable))
165     , errorPrototypeTable(fastNew<HashTable>(JSC::errorPrototypeTable))
166     , globalObjectTable(fastNew<HashTable>(JSC::globalObjectTable))
167     , jsonTable(fastNew<HashTable>(JSC::jsonTable))
168     , mathTable(fastNew<HashTable>(JSC::mathTable))
169     , numberConstructorTable(fastNew<HashTable>(JSC::numberConstructorTable))
170     , numberPrototypeTable(fastNew<HashTable>(JSC::numberPrototypeTable))
171     , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable))
172     , objectPrototypeTable(fastNew<HashTable>(JSC::objectPrototypeTable))
173     , regExpTable(fastNew<HashTable>(JSC::regExpTable))
174     , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
175     , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable))
176     , stringTable(fastNew<HashTable>(JSC::stringTable))
177     , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
178     , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
179     , propertyNames(new CommonIdentifiers(this))
180     , emptyList(new MarkedArgumentBuffer)
181 #if ENABLE(ASSEMBLER)
182     , executableAllocator(*this)
183     , regexAllocator(*this)
184 #endif
185     , lexer(new Lexer(this))
186     , parser(new Parser)
187     , interpreter(0)
188     , heap(this)
189     , dynamicGlobalObject(0)
190     , cachedUTCOffset(NaN)
191     , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
192     , m_regExpCache(new RegExpCache(this))
193 #if ENABLE(REGEXP_TRACING)
194     , m_rtTraceList(new RTTraceList())
195 #endif
196 #ifndef NDEBUG
197     , exclusiveThread(0)
198 #endif
199 {
200     interpreter = new Interpreter(*this);
201     if (globalDataType == Default)
202         m_stack = wtfThreadData().stack();
203
204     // Need to be careful to keep everything consistent here
205     IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable);
206     JSLock lock(SilenceAssertionsOnly);
207     structureStructure.set(*this, Structure::createStructure(*this));
208     debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, jsNull()));
209     activationStructure.set(*this, JSActivation::createStructure(*this, jsNull()));
210     interruptedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull()));
211     terminatedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull()));
212     staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, jsNull()));
213     strictEvalActivationStructure.set(*this, StrictEvalActivation::createStructure(*this, jsNull()));
214     stringStructure.set(*this, JSString::createStructure(*this, jsNull()));
215     notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, jsNull()));
216     propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, jsNull()));
217     getterSetterStructure.set(*this, GetterSetter::createStructure(*this, jsNull()));
218     apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, jsNull()));
219     scopeChainNodeStructure.set(*this, ScopeChainNode::createStructure(*this, jsNull()));
220     executableStructure.set(*this, ExecutableBase::createStructure(*this, jsNull()));
221     nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, jsNull()));
222     evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, jsNull()));
223     programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, jsNull()));
224     functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, jsNull()));
225     dummyMarkableCellStructure.set(*this, JSCell::createDummyStructure(*this));
226     regExpStructure.set(*this, RegExp::createStructure(*this, jsNull()));
227     structureChainStructure.set(*this, StructureChain::createStructure(*this, jsNull()));
228
229 #if ENABLE(JSC_ZOMBIES)
230     zombieStructure.set(*this, JSZombie::createStructure(*this, jsNull()));
231 #endif
232
233     wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
234
235 #if PLATFORM(MAC)
236     startProfilerServerIfNeeded();
237 #endif
238 #if ENABLE(JIT) && ENABLE(INTERPRETER)
239 #if USE(CF)
240     CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
241     CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
242     if (canUseJIT) {
243         m_canUseJIT = kCFBooleanTrue == canUseJIT;
244         CFRelease(canUseJIT);
245     } else {
246       char* canUseJITString = getenv("JavaScriptCoreUseJIT");
247       m_canUseJIT = !canUseJITString || atoi(canUseJITString);
248     }
249     CFRelease(canUseJITKey);
250 #elif OS(UNIX)
251     char* canUseJITString = getenv("JavaScriptCoreUseJIT");
252     m_canUseJIT = !canUseJITString || atoi(canUseJITString);
253 #else
254     m_canUseJIT = true;
255 #endif
256 #endif
257 #if ENABLE(JIT)
258 #if ENABLE(INTERPRETER)
259     if (m_canUseJIT)
260         m_canUseJIT = executableAllocator.isValid();
261 #endif
262     jitStubs = adoptPtr(new JITThunks(this));
263 #endif
264 }
265
266 void JSGlobalData::clearBuiltinStructures()
267 {
268     structureStructure.clear();
269     debuggerActivationStructure.clear();
270     activationStructure.clear();
271     interruptedExecutionErrorStructure.clear();
272     terminatedExecutionErrorStructure.clear();
273     staticScopeStructure.clear();
274     strictEvalActivationStructure.clear();
275     stringStructure.clear();
276     notAnObjectStructure.clear();
277     propertyNameIteratorStructure.clear();
278     getterSetterStructure.clear();
279     apiWrapperStructure.clear();
280     scopeChainNodeStructure.clear();
281     executableStructure.clear();
282     nativeExecutableStructure.clear();
283     evalExecutableStructure.clear();
284     programExecutableStructure.clear();
285     functionExecutableStructure.clear();
286     dummyMarkableCellStructure.clear();
287     regExpStructure.clear();
288     structureChainStructure.clear();
289
290 #if ENABLE(JSC_ZOMBIES)
291     zombieStructure.clear();
292 #endif
293 }
294
295 JSGlobalData::~JSGlobalData()
296 {
297     // By the time this is destroyed, heap.destroy() must already have been called.
298
299     delete interpreter;
300 #ifndef NDEBUG
301     // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance.
302     interpreter = 0;
303 #endif
304
305     arrayPrototypeTable->deleteTable();
306     arrayConstructorTable->deleteTable();
307     booleanPrototypeTable->deleteTable();
308     dateTable->deleteTable();
309     dateConstructorTable->deleteTable();
310     errorPrototypeTable->deleteTable();
311     globalObjectTable->deleteTable();
312     jsonTable->deleteTable();
313     mathTable->deleteTable();
314     numberConstructorTable->deleteTable();
315     numberPrototypeTable->deleteTable();
316     objectConstructorTable->deleteTable();
317     objectPrototypeTable->deleteTable();
318     regExpTable->deleteTable();
319     regExpConstructorTable->deleteTable();
320     regExpPrototypeTable->deleteTable();
321     stringTable->deleteTable();
322     stringConstructorTable->deleteTable();
323
324     fastDelete(const_cast<HashTable*>(arrayConstructorTable));
325     fastDelete(const_cast<HashTable*>(arrayPrototypeTable));
326     fastDelete(const_cast<HashTable*>(booleanPrototypeTable));
327     fastDelete(const_cast<HashTable*>(dateTable));
328     fastDelete(const_cast<HashTable*>(dateConstructorTable));
329     fastDelete(const_cast<HashTable*>(errorPrototypeTable));
330     fastDelete(const_cast<HashTable*>(globalObjectTable));
331     fastDelete(const_cast<HashTable*>(jsonTable));
332     fastDelete(const_cast<HashTable*>(mathTable));
333     fastDelete(const_cast<HashTable*>(numberConstructorTable));
334     fastDelete(const_cast<HashTable*>(numberPrototypeTable));
335     fastDelete(const_cast<HashTable*>(objectConstructorTable));
336     fastDelete(const_cast<HashTable*>(objectPrototypeTable));
337     fastDelete(const_cast<HashTable*>(regExpTable));
338     fastDelete(const_cast<HashTable*>(regExpConstructorTable));
339     fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
340     fastDelete(const_cast<HashTable*>(stringTable));
341     fastDelete(const_cast<HashTable*>(stringConstructorTable));
342
343     delete parser;
344     delete lexer;
345
346     deleteAllValues(opaqueJSClassData);
347
348     delete emptyList;
349
350     delete propertyNames;
351     if (globalDataType != Default)
352         deleteIdentifierTable(identifierTable);
353
354     delete clientData;
355     delete m_regExpCache;
356 #if ENABLE(REGEXP_TRACING)
357     delete m_rtTraceList;
358 #endif
359 }
360
361 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type)
362 {
363     return adoptRef(new JSGlobalData(APIContextGroup, type));
364 }
365
366 PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type)
367 {
368     return adoptRef(new JSGlobalData(Default, type));
369 }
370
371 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type)
372 {
373     return create(type);
374 }
375
376 bool JSGlobalData::sharedInstanceExists()
377 {
378     return sharedInstanceInternal();
379 }
380
381 JSGlobalData& JSGlobalData::sharedInstance()
382 {
383     JSGlobalData*& instance = sharedInstanceInternal();
384     if (!instance) {
385         instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall)).leakRef();
386 #if ENABLE(JSC_MULTIPLE_THREADS)
387         instance->makeUsableFromMultipleThreads();
388 #endif
389     }
390     return *instance;
391 }
392
393 JSGlobalData*& JSGlobalData::sharedInstanceInternal()
394 {
395     ASSERT(JSLock::currentThreadIsHoldingLock());
396     static JSGlobalData* sharedInstance;
397     return sharedInstance;
398 }
399
400 #if ENABLE(JIT)
401 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
402 {
403     return jitStubs->hostFunctionStub(this, function);
404 }
405 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator)
406 {
407     return jitStubs->hostFunctionStub(this, function, generator);
408 }
409 #else
410 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
411 {
412     return NativeExecutable::create(*this, function, callHostFunctionAsConstructor);
413 }
414 #endif
415
416 JSGlobalData::ClientData::~ClientData()
417 {
418 }
419
420 void JSGlobalData::resetDateCache()
421 {
422     cachedUTCOffset = NaN;
423     dstOffsetCache.reset();
424     cachedDateString = UString();
425     cachedDateStringValue = NaN;
426     dateInstanceCache.reset();
427 }
428
429 void JSGlobalData::startSampling()
430 {
431     interpreter->startSampling();
432 }
433
434 void JSGlobalData::stopSampling()
435 {
436     interpreter->stopSampling();
437 }
438
439 void JSGlobalData::dumpSampleData(ExecState* exec)
440 {
441     interpreter->dumpSampleData(exec);
442 }
443
444 void JSGlobalData::recompileAllJSFunctions()
445 {
446     // If JavaScript is running, it's not safe to recompile, since we'll end
447     // up throwing away code that is live on the stack.
448     ASSERT(!dynamicGlobalObject);
449     
450     heap.forEachCell<Recompiler>();
451 }
452
453 void JSGlobalData::releaseExecutableMemory()
454 {
455     if (!dynamicGlobalObject)
456         recompileAllJSFunctions();
457     m_regExpCache->invalidateCode();
458 }
459     
460 void releaseExecutableMemory(JSGlobalData& globalData)
461 {
462     globalData.releaseExecutableMemory();
463 }
464
465 #if ENABLE(REGEXP_TRACING)
466 void JSGlobalData::addRegExpToTrace(RegExp* regExp)
467 {
468     m_rtTraceList->add(regExp);
469 }
470
471 void JSGlobalData::dumpRegExpTrace()
472 {
473     // The first RegExp object is ignored.  It is create by the RegExpPrototype ctor and not used.
474     RTTraceList::iterator iter = ++m_rtTraceList->begin();
475     
476     if (iter != m_rtTraceList->end()) {
477         printf("\nRegExp Tracing\n");
478         printf("                                                            match()    matches\n");
479         printf("Regular Expression                          JIT Address      calls      found\n");
480         printf("----------------------------------------+----------------+----------+----------\n");
481     
482         unsigned reCount = 0;
483     
484         for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
485             (*iter)->printTraceData();
486
487         printf("%d Regular Expressions\n", reCount);
488     }
489     
490     m_rtTraceList->clear();
491 }
492 #else
493 void JSGlobalData::dumpRegExpTrace()
494 {
495 }
496 #endif
497
498 } // namespace JSC