Reduce the verbosity of referring to QNaN in JavaScriptCore
[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 "CommonIdentifiers.h"
34 #include "DebuggerActivation.h"
35 #include "FunctionConstructor.h"
36 #include "GCActivityCallback.h"
37 #include "GetterSetter.h"
38 #include "Heap.h"
39 #include "HostCallReturnValue.h"
40 #include "IncrementalSweeper.h"
41 #include "Interpreter.h"
42 #include "JSActivation.h"
43 #include "JSAPIValueWrapper.h"
44 #include "JSArray.h"
45 #include "JSClassRef.h"
46 #include "JSFunction.h"
47 #include "JSLock.h"
48 #include "JSNameScope.h"
49 #include "JSNotAnObject.h"
50 #include "JSPropertyNameIterator.h"
51 #include "JSWithScope.h"
52 #include "Lexer.h"
53 #include "Lookup.h"
54 #include "Nodes.h"
55 #include "ParserArena.h"
56 #include "RegExpCache.h"
57 #include "RegExpObject.h"
58 #include "StrictEvalActivation.h"
59 #include "StrongInlines.h"
60 #include <wtf/RetainPtr.h>
61 #include <wtf/Threading.h>
62 #include <wtf/WTFThreadData.h>
63
64 #if ENABLE(DFG_JIT)
65 #include "ConservativeRoots.h"
66 #endif
67
68 #if ENABLE(REGEXP_TRACING)
69 #include "RegExp.h"
70 #endif
71
72 #if USE(CF)
73 #include <CoreFoundation/CoreFoundation.h>
74 #endif
75
76 using namespace WTF;
77
78 namespace JSC {
79
80 extern const HashTable arrayConstructorTable;
81 extern const HashTable arrayPrototypeTable;
82 extern const HashTable booleanPrototypeTable;
83 extern const HashTable jsonTable;
84 extern const HashTable dateTable;
85 extern const HashTable dateConstructorTable;
86 extern const HashTable errorPrototypeTable;
87 extern const HashTable globalObjectTable;
88 extern const HashTable mathTable;
89 extern const HashTable numberConstructorTable;
90 extern const HashTable numberPrototypeTable;
91 JS_EXPORTDATA extern const HashTable objectConstructorTable;
92 extern const HashTable objectPrototypeTable;
93 extern const HashTable privateNamePrototypeTable;
94 extern const HashTable regExpTable;
95 extern const HashTable regExpConstructorTable;
96 extern const HashTable regExpPrototypeTable;
97 extern const HashTable stringTable;
98 extern const HashTable stringConstructorTable;
99
100 // Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either
101 // ENABLE(JIT) or ENABLE(YARR_JIT) or both are enabled. The code below
102 // just checks for ENABLE(JIT) or ENABLE(YARR_JIT) with this premise in mind.
103
104 #if ENABLE(ASSEMBLER)
105 static bool enableAssembler(ExecutableAllocator& executableAllocator)
106 {
107     if (!executableAllocator.isValid() || (!Options::useJIT() && !Options::useRegExpJIT()))
108         return false;
109
110 #if USE(CF)
111 #if COMPILER(GCC) && !COMPILER(CLANG)
112     // FIXME: remove this once the EWS have been upgraded to LLVM.
113     // Work around a bug of GCC with strict-aliasing.
114     RetainPtr<CFStringRef> canUseJITKeyRetain(AdoptCF, CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman));
115     CFStringRef canUseJITKey = canUseJITKeyRetain.get();
116 #else
117     CFStringRef canUseJITKey = CFSTR("JavaScriptCoreUseJIT");
118 #endif // COMPILER(GCC) && !COMPILER(CLANG)
119     RetainPtr<CFBooleanRef> canUseJIT(AdoptCF, (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication));
120     if (canUseJIT)
121         return kCFBooleanTrue == canUseJIT.get();
122 #endif
123
124 #if USE(CF) || OS(UNIX)
125     char* canUseJITString = getenv("JavaScriptCoreUseJIT");
126     return !canUseJITString || atoi(canUseJITString);
127 #else
128     return true;
129 #endif
130 }
131 #endif // ENABLE(!ASSEMBLER)
132
133 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType)
134     :
135 #if ENABLE(ASSEMBLER)
136       executableAllocator(*this),
137 #endif
138       heap(this, heapType)
139     , globalDataType(globalDataType)
140     , clientData(0)
141     , topCallFrame(CallFrame::noCaller())
142     , arrayConstructorTable(fastNew<HashTable>(JSC::arrayConstructorTable))
143     , arrayPrototypeTable(fastNew<HashTable>(JSC::arrayPrototypeTable))
144     , booleanPrototypeTable(fastNew<HashTable>(JSC::booleanPrototypeTable))
145     , dateTable(fastNew<HashTable>(JSC::dateTable))
146     , dateConstructorTable(fastNew<HashTable>(JSC::dateConstructorTable))
147     , errorPrototypeTable(fastNew<HashTable>(JSC::errorPrototypeTable))
148     , globalObjectTable(fastNew<HashTable>(JSC::globalObjectTable))
149     , jsonTable(fastNew<HashTable>(JSC::jsonTable))
150     , mathTable(fastNew<HashTable>(JSC::mathTable))
151     , numberConstructorTable(fastNew<HashTable>(JSC::numberConstructorTable))
152     , numberPrototypeTable(fastNew<HashTable>(JSC::numberPrototypeTable))
153     , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable))
154     , objectPrototypeTable(fastNew<HashTable>(JSC::objectPrototypeTable))
155     , privateNamePrototypeTable(fastNew<HashTable>(JSC::privateNamePrototypeTable))
156     , regExpTable(fastNew<HashTable>(JSC::regExpTable))
157     , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
158     , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable))
159     , stringTable(fastNew<HashTable>(JSC::stringTable))
160     , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
161     , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
162     , propertyNames(new CommonIdentifiers(this))
163     , emptyList(new MarkedArgumentBuffer)
164     , parserArena(adoptPtr(new ParserArena))
165     , keywords(adoptPtr(new Keywords(this)))
166     , interpreter(0)
167     , jsArrayClassInfo(&JSArray::s_info)
168     , jsFinalObjectClassInfo(&JSFinalObject::s_info)
169 #if ENABLE(DFG_JIT)
170     , sizeOfLastScratchBuffer(0)
171 #endif
172     , dynamicGlobalObject(0)
173     , cachedUTCOffset(QNaN)
174     , m_enabledProfiler(0)
175     , m_regExpCache(new RegExpCache(this))
176 #if ENABLE(REGEXP_TRACING)
177     , m_rtTraceList(new RTTraceList())
178 #endif
179 #ifndef NDEBUG
180     , exclusiveThread(0)
181 #endif
182 #if CPU(X86) && ENABLE(JIT)
183     , m_timeoutCount(512)
184 #endif
185     , m_newStringsSinceLastHashConst(0)
186 #if ENABLE(ASSEMBLER)
187     , m_canUseAssembler(enableAssembler(executableAllocator))
188 #endif
189 #if ENABLE(JIT)
190     , m_canUseJIT(m_canUseAssembler && Options::useJIT())
191 #endif
192 #if ENABLE(YARR_JIT)
193     , m_canUseRegExpJIT(m_canUseAssembler && Options::useRegExpJIT())
194 #endif
195 #if ENABLE(GC_VALIDATION)
196     , m_initializingObjectClass(0)
197 #endif
198     , m_inDefineOwnProperty(false)
199 {
200     interpreter = new Interpreter(*this);
201
202     // Need to be careful to keep everything consistent here
203     JSLockHolder lock(this);
204     IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable);
205     structureStructure.set(*this, Structure::createStructure(*this));
206     debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull()));
207     interruptedExecutionErrorStructure.set(*this, InterruptedExecutionError::createStructure(*this, 0, jsNull()));
208     terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
209     stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
210     notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
211     propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
212     getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
213     apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
214     JSScopeStructure.set(*this, JSScope::createStructure(*this, 0, jsNull()));
215     executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull()));
216     nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, 0, jsNull()));
217     evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, 0, jsNull()));
218     programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
219     functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
220     regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
221     sharedSymbolTableStructure.set(*this, SharedSymbolTable::createStructure(*this, 0, jsNull()));
222     structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
223     sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull()));
224
225     wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
226
227 #if ENABLE(JIT)
228     jitStubs = adoptPtr(new JITThunks(this));
229 #endif
230     
231     interpreter->initialize(this->canUseJIT());
232     
233 #if ENABLE(JIT)
234     initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
235 #endif
236
237     heap.notifyIsSafeToCollect();
238     
239     LLInt::Data::performAssertions(*this);
240 }
241
242 JSGlobalData::~JSGlobalData()
243 {
244     ASSERT(!m_apiLock.currentThreadIsHoldingLock());
245     heap.didStartVMShutdown();
246
247     delete interpreter;
248 #ifndef NDEBUG
249     interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef);
250 #endif
251
252     arrayPrototypeTable->deleteTable();
253     arrayConstructorTable->deleteTable();
254     booleanPrototypeTable->deleteTable();
255     dateTable->deleteTable();
256     dateConstructorTable->deleteTable();
257     errorPrototypeTable->deleteTable();
258     globalObjectTable->deleteTable();
259     jsonTable->deleteTable();
260     mathTable->deleteTable();
261     numberConstructorTable->deleteTable();
262     numberPrototypeTable->deleteTable();
263     objectConstructorTable->deleteTable();
264     objectPrototypeTable->deleteTable();
265     privateNamePrototypeTable->deleteTable();
266     regExpTable->deleteTable();
267     regExpConstructorTable->deleteTable();
268     regExpPrototypeTable->deleteTable();
269     stringTable->deleteTable();
270     stringConstructorTable->deleteTable();
271
272     fastDelete(const_cast<HashTable*>(arrayConstructorTable));
273     fastDelete(const_cast<HashTable*>(arrayPrototypeTable));
274     fastDelete(const_cast<HashTable*>(booleanPrototypeTable));
275     fastDelete(const_cast<HashTable*>(dateTable));
276     fastDelete(const_cast<HashTable*>(dateConstructorTable));
277     fastDelete(const_cast<HashTable*>(errorPrototypeTable));
278     fastDelete(const_cast<HashTable*>(globalObjectTable));
279     fastDelete(const_cast<HashTable*>(jsonTable));
280     fastDelete(const_cast<HashTable*>(mathTable));
281     fastDelete(const_cast<HashTable*>(numberConstructorTable));
282     fastDelete(const_cast<HashTable*>(numberPrototypeTable));
283     fastDelete(const_cast<HashTable*>(objectConstructorTable));
284     fastDelete(const_cast<HashTable*>(objectPrototypeTable));
285     fastDelete(const_cast<HashTable*>(privateNamePrototypeTable));
286     fastDelete(const_cast<HashTable*>(regExpTable));
287     fastDelete(const_cast<HashTable*>(regExpConstructorTable));
288     fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
289     fastDelete(const_cast<HashTable*>(stringTable));
290     fastDelete(const_cast<HashTable*>(stringConstructorTable));
291
292     opaqueJSClassData.clear();
293
294     delete emptyList;
295
296     delete propertyNames;
297     if (globalDataType != Default)
298         deleteIdentifierTable(identifierTable);
299
300     delete clientData;
301     delete m_regExpCache;
302 #if ENABLE(REGEXP_TRACING)
303     delete m_rtTraceList;
304 #endif
305
306 #if ENABLE(DFG_JIT)
307     for (unsigned i = 0; i < scratchBuffers.size(); ++i)
308         fastFree(scratchBuffers[i]);
309 #endif
310 }
311
312 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(HeapType heapType)
313 {
314     return adoptRef(new JSGlobalData(APIContextGroup, heapType));
315 }
316
317 PassRefPtr<JSGlobalData> JSGlobalData::create(HeapType heapType)
318 {
319     return adoptRef(new JSGlobalData(Default, heapType));
320 }
321
322 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(HeapType heapType)
323 {
324     return create(heapType);
325 }
326
327 bool JSGlobalData::sharedInstanceExists()
328 {
329     return sharedInstanceInternal();
330 }
331
332 JSGlobalData& JSGlobalData::sharedInstance()
333 {
334     GlobalJSLock globalLock;
335     JSGlobalData*& instance = sharedInstanceInternal();
336     if (!instance) {
337         instance = adoptRef(new JSGlobalData(APIShared, SmallHeap)).leakRef();
338         instance->makeUsableFromMultipleThreads();
339     }
340     return *instance;
341 }
342
343 JSGlobalData*& JSGlobalData::sharedInstanceInternal()
344 {
345     static JSGlobalData* sharedInstance;
346     return sharedInstance;
347 }
348
349 #if ENABLE(JIT)
350 static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
351 {
352     switch (intrinsic) {
353     case CharCodeAtIntrinsic:
354         return charCodeAtThunkGenerator;
355     case CharAtIntrinsic:
356         return charAtThunkGenerator;
357     case FromCharCodeIntrinsic:
358         return fromCharCodeThunkGenerator;
359     case SqrtIntrinsic:
360         return sqrtThunkGenerator;
361     case PowIntrinsic:
362         return powThunkGenerator;
363     case AbsIntrinsic:
364         return absThunkGenerator;
365     case FloorIntrinsic:
366         return floorThunkGenerator;
367     case CeilIntrinsic:
368         return ceilThunkGenerator;
369     case RoundIntrinsic:
370         return roundThunkGenerator;
371     case ExpIntrinsic:
372         return expThunkGenerator;
373     case LogIntrinsic:
374         return logThunkGenerator;
375     default:
376         return 0;
377     }
378 }
379
380 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
381 {
382     return jitStubs->hostFunctionStub(this, function, constructor);
383 }
384 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, Intrinsic intrinsic)
385 {
386     ASSERT(canUseJIT());
387     return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic);
388 }
389
390 #else // !ENABLE(JIT)
391 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
392 {
393     return NativeExecutable::create(*this, function, constructor);
394 }
395 #endif // !ENABLE(JIT)
396
397 JSGlobalData::ClientData::~ClientData()
398 {
399 }
400
401 void JSGlobalData::resetDateCache()
402 {
403     cachedUTCOffset = QNaN;
404     dstOffsetCache.reset();
405     cachedDateString = String();
406     cachedDateStringValue = QNaN;
407     dateInstanceCache.reset();
408 }
409
410 void JSGlobalData::startSampling()
411 {
412     interpreter->startSampling();
413 }
414
415 void JSGlobalData::stopSampling()
416 {
417     interpreter->stopSampling();
418 }
419
420 void JSGlobalData::dumpSampleData(ExecState* exec)
421 {
422     interpreter->dumpSampleData(exec);
423 #if ENABLE(ASSEMBLER)
424     ExecutableAllocator::dumpProfile();
425 #endif
426 }
427
428 struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
429     HashSet<FunctionExecutable*> currentlyExecutingFunctions;
430     void operator()(JSCell* cell)
431     {
432         if (!cell->inherits(&FunctionExecutable::s_info))
433             return;
434         FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
435         if (currentlyExecutingFunctions.contains(executable))
436             return;
437         executable->clearCodeIfNotCompiling();
438     }
439 };
440
441 void JSGlobalData::releaseExecutableMemory()
442 {
443     if (dynamicGlobalObject) {
444         StackPreservingRecompiler recompiler;
445         HashSet<JSCell*> roots;
446         heap.getConservativeRegisterRoots(roots);
447         HashSet<JSCell*>::iterator end = roots.end();
448         for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) {
449             ScriptExecutable* executable = 0;
450             JSCell* cell = *ptr;
451             if (cell->inherits(&ScriptExecutable::s_info))
452                 executable = static_cast<ScriptExecutable*>(*ptr);
453             else if (cell->inherits(&JSFunction::s_info)) {
454                 JSFunction* function = jsCast<JSFunction*>(*ptr);
455                 if (function->isHostFunction())
456                     continue;
457                 executable = function->jsExecutable();
458             } else
459                 continue;
460             ASSERT(executable->inherits(&ScriptExecutable::s_info));
461             executable->unlinkCalls();
462             if (executable->inherits(&FunctionExecutable::s_info))
463                 recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable));
464                 
465         }
466         heap.objectSpace().forEachLiveCell<StackPreservingRecompiler>(recompiler);
467     }
468     m_regExpCache->invalidateCode();
469     heap.collectAllGarbage();
470 }
471     
472 void releaseExecutableMemory(JSGlobalData& globalData)
473 {
474     globalData.releaseExecutableMemory();
475 }
476
477 #if ENABLE(DFG_JIT)
478 void JSGlobalData::gatherConservativeRoots(ConservativeRoots& conservativeRoots)
479 {
480     for (size_t i = 0; i < scratchBuffers.size(); i++) {
481         ScratchBuffer* scratchBuffer = scratchBuffers[i];
482         if (scratchBuffer->activeLength()) {
483             void* bufferStart = scratchBuffer->dataBuffer();
484             conservativeRoots.add(bufferStart, static_cast<void*>(static_cast<char*>(bufferStart) + scratchBuffer->activeLength()));
485         }
486     }
487 }
488 #endif
489
490 #if ENABLE(REGEXP_TRACING)
491 void JSGlobalData::addRegExpToTrace(RegExp* regExp)
492 {
493     m_rtTraceList->add(regExp);
494 }
495
496 void JSGlobalData::dumpRegExpTrace()
497 {
498     // The first RegExp object is ignored.  It is create by the RegExpPrototype ctor and not used.
499     RTTraceList::iterator iter = ++m_rtTraceList->begin();
500     
501     if (iter != m_rtTraceList->end()) {
502         dataLog("\nRegExp Tracing\n");
503         dataLog("                                                            match()    matches\n");
504         dataLog("Regular Expression                          JIT Address      calls      found\n");
505         dataLog("----------------------------------------+----------------+----------+----------\n");
506     
507         unsigned reCount = 0;
508     
509         for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
510             (*iter)->printTraceData();
511
512         dataLog("%d Regular Expressions\n", reCount);
513     }
514     
515     m_rtTraceList->clear();
516 }
517 #else
518 void JSGlobalData::dumpRegExpTrace()
519 {
520 }
521 #endif
522
523 } // namespace JSC