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