c78cf5a992f814849e36e1909a0f018d15ea4113
[framework/web/webkit-efl.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 "GCActivityCallback.h"
38 #include "GetterSetter.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 "JSNotAnObject.h"
49 #include "JSPropertyNameIterator.h"
50 #include "JSStaticScopeObject.h"
51 #include "Lexer.h"
52 #include "Lookup.h"
53 #include "Nodes.h"
54 #include "ParserArena.h"
55 #include "RegExpCache.h"
56 #include "RegExpObject.h"
57 #include "StrictEvalActivation.h"
58 #include "StrongInlines.h"
59 #include <wtf/RetainPtr.h>
60 #include <wtf/Threading.h>
61 #include <wtf/WTFThreadData.h>
62
63 #if ENABLE(DFG_JIT)
64 #include "ConservativeRoots.h"
65 #endif
66
67 #if ENABLE(REGEXP_TRACING)
68 #include "RegExp.h"
69 #endif
70
71 #if USE(CF)
72 #include <CoreFoundation/CoreFoundation.h>
73 #endif
74
75 using namespace WTF;
76
77 namespace JSC {
78
79 extern const HashTable arrayConstructorTable;
80 extern const HashTable arrayPrototypeTable;
81 extern const HashTable booleanPrototypeTable;
82 extern const HashTable jsonTable;
83 extern const HashTable dateTable;
84 extern const HashTable dateConstructorTable;
85 extern const HashTable errorPrototypeTable;
86 extern const HashTable globalObjectTable;
87 extern const HashTable mathTable;
88 extern const HashTable numberConstructorTable;
89 extern const HashTable numberPrototypeTable;
90 JS_EXPORTDATA extern const HashTable objectConstructorTable;
91 extern const HashTable objectPrototypeTable;
92 extern const HashTable privateNamePrototypeTable;
93 extern const HashTable regExpTable;
94 extern const HashTable regExpConstructorTable;
95 extern const HashTable regExpPrototypeTable;
96 extern const HashTable stringTable;
97 extern const HashTable stringConstructorTable;
98
99 #if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
100 static bool enableAssembler(ExecutableAllocator& executableAllocator)
101 {
102     if (!executableAllocator.isValid() || !Options::useJIT())
103         return false;
104
105 #if USE(CF)
106     RetainPtr<CFStringRef> canUseJITKey(AdoptCF, CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman));
107     RetainPtr<CFBooleanRef> canUseJIT(AdoptCF, (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey.get(), kCFPreferencesCurrentApplication));
108     if (canUseJIT)
109         return kCFBooleanTrue == canUseJIT.get();
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_enabledProfiler(0)
163     , m_regExpCache(new RegExpCache(this))
164 #if ENABLE(REGEXP_TRACING)
165     , m_rtTraceList(new RTTraceList())
166 #endif
167 #ifndef NDEBUG
168     , exclusiveThread(0)
169 #endif
170 #if CPU(X86) && ENABLE(JIT)
171     , m_timeoutCount(512)
172 #endif
173     , m_newStringsSinceLastHashConst(0)
174 #if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
175     , m_canUseAssembler(enableAssembler(executableAllocator))
176 #endif
177 #if ENABLE(GC_VALIDATION)
178     , m_initializingObjectClass(0)
179 #endif
180     , m_inDefineOwnProperty(false)
181 {
182     interpreter = new Interpreter;
183
184     // Need to be careful to keep everything consistent here
185     JSLockHolder lock(this);
186     IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable);
187     structureStructure.set(*this, Structure::createStructure(*this));
188     debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull()));
189     activationStructure.set(*this, JSActivation::createStructure(*this, 0, jsNull()));
190     interruptedExecutionErrorStructure.set(*this, InterruptedExecutionError::createStructure(*this, 0, jsNull()));
191     terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
192     staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, 0, jsNull()));
193     strictEvalActivationStructure.set(*this, StrictEvalActivation::createStructure(*this, 0, jsNull()));
194     stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
195     notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
196     propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
197     getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
198     apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
199     scopeChainNodeStructure.set(*this, ScopeChainNode::createStructure(*this, 0, jsNull()));
200     executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull()));
201     nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, 0, jsNull()));
202     evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, 0, jsNull()));
203     programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
204     functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
205     regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
206     structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
207
208     wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
209
210 #if ENABLE(JIT)
211     jitStubs = adoptPtr(new JITThunks(this));
212 #endif
213     
214     interpreter->initialize(this->canUseJIT());
215     
216     initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
217
218     heap.notifyIsSafeToCollect();
219     
220     LLInt::Data::performAssertions(*this);
221 }
222
223 JSGlobalData::~JSGlobalData()
224 {
225     ASSERT(!m_apiLock.currentThreadIsHoldingLock());
226     heap.didStartVMShutdown();
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     GlobalJSLock globalLock;
316     JSGlobalData*& instance = sharedInstanceInternal();
317     if (!instance) {
318         instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall, SmallHeap)).leakRef();
319         instance->makeUsableFromMultipleThreads();
320     }
321     return *instance;
322 }
323
324 JSGlobalData*& JSGlobalData::sharedInstanceInternal()
325 {
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
375 #else // !ENABLE(JIT)
376 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
377 {
378     return NativeExecutable::create(*this, function, constructor);
379 }
380 #endif // !ENABLE(JIT)
381
382 JSGlobalData::ClientData::~ClientData()
383 {
384 }
385
386 void JSGlobalData::resetDateCache()
387 {
388     cachedUTCOffset = std::numeric_limits<double>::quiet_NaN();
389     dstOffsetCache.reset();
390     cachedDateString = UString();
391     cachedDateStringValue = std::numeric_limits<double>::quiet_NaN();
392     dateInstanceCache.reset();
393 }
394
395 void JSGlobalData::startSampling()
396 {
397     interpreter->startSampling();
398 }
399
400 void JSGlobalData::stopSampling()
401 {
402     interpreter->stopSampling();
403 }
404
405 void JSGlobalData::dumpSampleData(ExecState* exec)
406 {
407     interpreter->dumpSampleData(exec);
408 #if ENABLE(ASSEMBLER)
409     ExecutableAllocator::dumpProfile();
410 #endif
411 }
412
413 struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
414     HashSet<FunctionExecutable*> currentlyExecutingFunctions;
415     void operator()(JSCell* cell)
416     {
417         if (!cell->inherits(&FunctionExecutable::s_info))
418             return;
419         FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
420         if (currentlyExecutingFunctions.contains(executable))
421             return;
422         executable->clearCodeIfNotCompiling();
423     }
424 };
425
426 void JSGlobalData::releaseExecutableMemory()
427 {
428     if (dynamicGlobalObject) {
429         StackPreservingRecompiler recompiler;
430         HashSet<JSCell*> roots;
431         heap.getConservativeRegisterRoots(roots);
432         HashSet<JSCell*>::iterator end = roots.end();
433         for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) {
434             ScriptExecutable* executable = 0;
435             JSCell* cell = *ptr;
436             if (cell->inherits(&ScriptExecutable::s_info))
437                 executable = static_cast<ScriptExecutable*>(*ptr);
438             else if (cell->inherits(&JSFunction::s_info)) {
439                 JSFunction* function = jsCast<JSFunction*>(*ptr);
440                 if (function->isHostFunction())
441                     continue;
442                 executable = function->jsExecutable();
443             } else
444                 continue;
445             ASSERT(executable->inherits(&ScriptExecutable::s_info));
446             executable->unlinkCalls();
447             if (executable->inherits(&FunctionExecutable::s_info))
448                 recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable));
449                 
450         }
451         heap.objectSpace().forEachCell<StackPreservingRecompiler>(recompiler);
452     }
453     m_regExpCache->invalidateCode();
454     heap.collectAllGarbage();
455 }
456     
457 void releaseExecutableMemory(JSGlobalData& globalData)
458 {
459     globalData.releaseExecutableMemory();
460 }
461
462 #if ENABLE(DFG_JIT)
463 void JSGlobalData::gatherConservativeRoots(ConservativeRoots& conservativeRoots)
464 {
465     for (size_t i = 0; i < scratchBuffers.size(); i++) {
466         ScratchBuffer* scratchBuffer = scratchBuffers[i];
467         if (scratchBuffer->activeLength()) {
468             void* bufferStart = scratchBuffer->dataBuffer();
469             conservativeRoots.add(bufferStart, static_cast<void*>(static_cast<char*>(bufferStart) + scratchBuffer->activeLength()));
470         }
471     }
472 }
473 #endif
474
475 #if ENABLE(REGEXP_TRACING)
476 void JSGlobalData::addRegExpToTrace(RegExp* regExp)
477 {
478     m_rtTraceList->add(regExp);
479 }
480
481 void JSGlobalData::dumpRegExpTrace()
482 {
483     // The first RegExp object is ignored.  It is create by the RegExpPrototype ctor and not used.
484     RTTraceList::iterator iter = ++m_rtTraceList->begin();
485     
486     if (iter != m_rtTraceList->end()) {
487         dataLog("\nRegExp Tracing\n");
488         dataLog("                                                            match()    matches\n");
489         dataLog("Regular Expression                          JIT Address      calls      found\n");
490         dataLog("----------------------------------------+----------------+----------+----------\n");
491     
492         unsigned reCount = 0;
493     
494         for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
495             (*iter)->printTraceData();
496
497         dataLog("%d Regular Expressions\n", reCount);
498     }
499     
500     m_rtTraceList->clear();
501 }
502 #else
503 void JSGlobalData::dumpRegExpTrace()
504 {
505 }
506 #endif
507
508 } // namespace JSC