2 * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "JSGlobalData.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"
45 #include "JSClassRef.h"
46 #include "JSFunction.h"
48 #include "JSNotAnObject.h"
49 #include "JSPropertyNameIterator.h"
50 #include "JSStaticScopeObject.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>
64 #include "ConservativeRoots.h"
67 #if ENABLE(REGEXP_TRACING)
72 #include <CoreFoundation/CoreFoundation.h>
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;
99 #if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
100 static bool enableAssembler(ExecutableAllocator& executableAllocator)
102 if (!executableAllocator.isValid() || !Options::useJIT())
106 RetainPtr<CFStringRef> canUseJITKey(AdoptCF, CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman));
107 RetainPtr<CFBooleanRef> canUseJIT(AdoptCF, (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey.get(), kCFPreferencesCurrentApplication));
109 return kCFBooleanTrue == canUseJIT.get();
112 #if USE(CF) || OS(UNIX)
113 char* canUseJITString = getenv("JavaScriptCoreUseJIT");
114 return !canUseJITString || atoi(canUseJITString);
121 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType, HeapType heapType)
122 : heap(this, heapType)
123 , globalDataType(globalDataType)
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)
151 , parserArena(adoptPtr(new ParserArena))
152 , keywords(adoptPtr(new Keywords(this)))
154 , jsArrayClassInfo(&JSArray::s_info)
155 , jsFinalObjectClassInfo(&JSFinalObject::s_info)
157 , sizeOfLastScratchBuffer(0)
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())
170 #if CPU(X86) && ENABLE(JIT)
171 , m_timeoutCount(512)
173 , m_newStringsSinceLastHashConst(0)
174 #if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
175 , m_canUseAssembler(enableAssembler(executableAllocator))
177 #if ENABLE(GC_VALIDATION)
178 , m_initializingObjectClass(0)
180 , m_inDefineOwnProperty(false)
182 interpreter = new Interpreter;
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()));
208 wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
211 jitStubs = adoptPtr(new JITThunks(this));
214 interpreter->initialize(this->canUseJIT());
216 initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
218 heap.notifyIsSafeToCollect();
220 LLInt::Data::performAssertions(*this);
223 JSGlobalData::~JSGlobalData()
225 ASSERT(!m_apiLock.currentThreadIsHoldingLock());
226 heap.didStartVMShutdown();
230 interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef);
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();
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));
273 opaqueJSClassData.clear();
277 delete propertyNames;
278 if (globalDataType != Default)
279 deleteIdentifierTable(identifierTable);
282 delete m_regExpCache;
283 #if ENABLE(REGEXP_TRACING)
284 delete m_rtTraceList;
288 for (unsigned i = 0; i < scratchBuffers.size(); ++i)
289 fastFree(scratchBuffers[i]);
293 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type, HeapType heapType)
295 return adoptRef(new JSGlobalData(APIContextGroup, type, heapType));
298 PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type, HeapType heapType)
300 return adoptRef(new JSGlobalData(Default, type, heapType));
303 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type, HeapType heapType)
305 return create(type, heapType);
308 bool JSGlobalData::sharedInstanceExists()
310 return sharedInstanceInternal();
313 JSGlobalData& JSGlobalData::sharedInstance()
315 GlobalJSLock globalLock;
316 JSGlobalData*& instance = sharedInstanceInternal();
318 instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall, SmallHeap)).leakRef();
319 instance->makeUsableFromMultipleThreads();
324 JSGlobalData*& JSGlobalData::sharedInstanceInternal()
326 static JSGlobalData* sharedInstance;
327 return sharedInstance;
331 static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
334 case CharCodeAtIntrinsic:
335 return charCodeAtThunkGenerator;
336 case CharAtIntrinsic:
337 return charAtThunkGenerator;
338 case FromCharCodeIntrinsic:
339 return fromCharCodeThunkGenerator;
341 return sqrtThunkGenerator;
343 return powThunkGenerator;
345 return absThunkGenerator;
347 return floorThunkGenerator;
349 return ceilThunkGenerator;
351 return roundThunkGenerator;
353 return expThunkGenerator;
355 return logThunkGenerator;
361 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
363 #if ENABLE(CLASSIC_INTERPRETER)
365 return NativeExecutable::create(*this, function, constructor);
367 return jitStubs->hostFunctionStub(this, function, constructor);
369 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, Intrinsic intrinsic)
372 return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic);
375 #else // !ENABLE(JIT)
376 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
378 return NativeExecutable::create(*this, function, constructor);
380 #endif // !ENABLE(JIT)
382 JSGlobalData::ClientData::~ClientData()
386 void JSGlobalData::resetDateCache()
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();
395 void JSGlobalData::startSampling()
397 interpreter->startSampling();
400 void JSGlobalData::stopSampling()
402 interpreter->stopSampling();
405 void JSGlobalData::dumpSampleData(ExecState* exec)
407 interpreter->dumpSampleData(exec);
408 #if ENABLE(ASSEMBLER)
409 ExecutableAllocator::dumpProfile();
413 struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
414 HashSet<FunctionExecutable*> currentlyExecutingFunctions;
415 void operator()(JSCell* cell)
417 if (!cell->inherits(&FunctionExecutable::s_info))
419 FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
420 if (currentlyExecutingFunctions.contains(executable))
422 executable->clearCodeIfNotCompiling();
426 void JSGlobalData::releaseExecutableMemory()
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;
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())
442 executable = function->jsExecutable();
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));
451 heap.objectSpace().forEachCell<StackPreservingRecompiler>(recompiler);
453 m_regExpCache->invalidateCode();
454 heap.collectAllGarbage();
457 void releaseExecutableMemory(JSGlobalData& globalData)
459 globalData.releaseExecutableMemory();
463 void JSGlobalData::gatherConservativeRoots(ConservativeRoots& conservativeRoots)
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()));
475 #if ENABLE(REGEXP_TRACING)
476 void JSGlobalData::addRegExpToTrace(RegExp* regExp)
478 m_rtTraceList->add(regExp);
481 void JSGlobalData::dumpRegExpTrace()
483 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
484 RTTraceList::iterator iter = ++m_rtTraceList->begin();
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");
492 unsigned reCount = 0;
494 for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
495 (*iter)->printTraceData();
497 dataLog("%d Regular Expressions\n", reCount);
500 m_rtTraceList->clear();
503 void JSGlobalData::dumpRegExpTrace()