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