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