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 "GetterSetter.h"
38 #include "Interpreter.h"
39 #include "JSActivation.h"
40 #include "JSAPIValueWrapper.h"
42 #include "JSByteArray.h"
43 #include "JSClassRef.h"
44 #include "JSFunction.h"
46 #include "JSNotAnObject.h"
47 #include "JSPropertyNameIterator.h"
48 #include "JSStaticScopeObject.h"
53 #include "RegExpCache.h"
54 #include "RegExpObject.h"
55 #include "StrictEvalActivation.h"
56 #include <wtf/WTFThreadData.h>
57 #if ENABLE(REGEXP_TRACING)
62 #if ENABLE(JSC_MULTIPLE_THREADS)
63 #include <wtf/Threading.h>
67 #include "ProfilerServer.h"
68 #include <CoreFoundation/CoreFoundation.h>
77 class Recompiler : public MarkedBlock::VoidFunctor {
79 void operator()(JSCell*);
82 inline void Recompiler::operator()(JSCell* cell)
84 if (!cell->inherits(&JSFunction::s_info))
86 JSFunction* function = asFunction(cell);
87 if (!function->executable() || function->executable()->isHostFunction())
89 function->jsExecutable()->discardCode();
96 extern JSC_CONST_HASHTABLE HashTable arrayConstructorTable;
97 extern JSC_CONST_HASHTABLE HashTable arrayPrototypeTable;
98 extern JSC_CONST_HASHTABLE HashTable booleanPrototypeTable;
99 extern JSC_CONST_HASHTABLE HashTable jsonTable;
100 extern JSC_CONST_HASHTABLE HashTable dateTable;
101 extern JSC_CONST_HASHTABLE HashTable dateConstructorTable;
102 extern JSC_CONST_HASHTABLE HashTable errorPrototypeTable;
103 extern JSC_CONST_HASHTABLE HashTable globalObjectTable;
104 extern JSC_CONST_HASHTABLE HashTable mathTable;
105 extern JSC_CONST_HASHTABLE HashTable numberConstructorTable;
106 extern JSC_CONST_HASHTABLE HashTable numberPrototypeTable;
107 extern JSC_CONST_HASHTABLE HashTable objectConstructorTable;
108 extern JSC_CONST_HASHTABLE HashTable objectPrototypeTable;
109 extern JSC_CONST_HASHTABLE HashTable regExpTable;
110 extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable;
111 extern JSC_CONST_HASHTABLE HashTable regExpPrototypeTable;
112 extern JSC_CONST_HASHTABLE HashTable stringTable;
113 extern JSC_CONST_HASHTABLE HashTable stringConstructorTable;
115 void* JSGlobalData::jsFinalObjectVPtr;
116 void* JSGlobalData::jsArrayVPtr;
117 void* JSGlobalData::jsByteArrayVPtr;
118 void* JSGlobalData::jsStringVPtr;
119 void* JSGlobalData::jsFunctionVPtr;
122 // Work around for gcc trying to coalesce our reads of the various cell vptrs
123 #define CLOBBER_MEMORY() do { \
124 asm volatile ("" : : : "memory"); \
127 #define CLOBBER_MEMORY() do { } while (false)
130 void JSGlobalData::storeVPtrs()
132 // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction.
133 // COMPILE_ASSERTS below check that this is true.
136 COMPILE_ASSERT(sizeof(JSFinalObject) <= sizeof(storage), sizeof_JSFinalObject_must_be_less_than_storage);
137 JSCell* jsFinalObject = new (storage) JSFinalObject(JSFinalObject::VPtrStealingHack);
139 JSGlobalData::jsFinalObjectVPtr = jsFinalObject->vptr();
141 COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage);
142 JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack);
144 JSGlobalData::jsArrayVPtr = jsArray->vptr();
146 COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage);
147 JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
149 JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr();
151 COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage);
152 JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
154 JSGlobalData::jsStringVPtr = jsString->vptr();
156 COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage);
157 JSCell* jsFunction = new (storage) JSFunction(JSCell::VPtrStealingHack);
159 JSGlobalData::jsFunctionVPtr = jsFunction->vptr();
162 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType, HeapSize heapSize)
163 : globalDataType(globalDataType)
165 , topCallFrame(CallFrame::noCaller())
166 , arrayConstructorTable(fastNew<HashTable>(JSC::arrayConstructorTable))
167 , arrayPrototypeTable(fastNew<HashTable>(JSC::arrayPrototypeTable))
168 , booleanPrototypeTable(fastNew<HashTable>(JSC::booleanPrototypeTable))
169 , dateTable(fastNew<HashTable>(JSC::dateTable))
170 , dateConstructorTable(fastNew<HashTable>(JSC::dateConstructorTable))
171 , errorPrototypeTable(fastNew<HashTable>(JSC::errorPrototypeTable))
172 , globalObjectTable(fastNew<HashTable>(JSC::globalObjectTable))
173 , jsonTable(fastNew<HashTable>(JSC::jsonTable))
174 , mathTable(fastNew<HashTable>(JSC::mathTable))
175 , numberConstructorTable(fastNew<HashTable>(JSC::numberConstructorTable))
176 , numberPrototypeTable(fastNew<HashTable>(JSC::numberPrototypeTable))
177 , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable))
178 , objectPrototypeTable(fastNew<HashTable>(JSC::objectPrototypeTable))
179 , regExpTable(fastNew<HashTable>(JSC::regExpTable))
180 , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
181 , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable))
182 , stringTable(fastNew<HashTable>(JSC::stringTable))
183 , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
184 , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
185 , propertyNames(new CommonIdentifiers(this))
186 , emptyList(new MarkedArgumentBuffer)
187 #if ENABLE(ASSEMBLER)
188 , executableAllocator(*this)
190 , lexer(new Lexer(this))
193 , heap(this, heapSize)
194 #if ENABLE(TIERED_COMPILATION)
195 , sizeOfLastOSRScratchBuffer(0)
197 , dynamicGlobalObject(0)
198 , cachedUTCOffset(std::numeric_limits<double>::quiet_NaN())
199 , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
200 , m_regExpCache(new RegExpCache(this))
201 #if ENABLE(REGEXP_TRACING)
202 , m_rtTraceList(new RTTraceList())
207 #if ENABLE(GC_VALIDATION)
208 , m_isInitializingObject(false)
211 interpreter = new Interpreter;
212 if (globalDataType == Default)
213 m_stack = wtfThreadData().stack();
215 // Need to be careful to keep everything consistent here
216 IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable);
217 JSLock lock(SilenceAssertionsOnly);
218 structureStructure.set(*this, Structure::createStructure(*this));
219 debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull()));
220 activationStructure.set(*this, JSActivation::createStructure(*this, 0, jsNull()));
221 interruptedExecutionErrorStructure.set(*this, InterruptedExecutionError::createStructure(*this, 0, jsNull()));
222 terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
223 staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, 0, jsNull()));
224 strictEvalActivationStructure.set(*this, StrictEvalActivation::createStructure(*this, 0, jsNull()));
225 stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
226 notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
227 propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
228 getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
229 apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
230 scopeChainNodeStructure.set(*this, ScopeChainNode::createStructure(*this, 0, jsNull()));
231 executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull()));
232 nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, 0, jsNull()));
233 evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, 0, jsNull()));
234 programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
235 functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
236 regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
237 structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
239 wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
242 startProfilerServerIfNeeded();
244 #if ENABLE(JIT) && ENABLE(INTERPRETER)
246 CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
247 CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
249 m_canUseJIT = kCFBooleanTrue == canUseJIT;
250 CFRelease(canUseJIT);
252 char* canUseJITString = getenv("JavaScriptCoreUseJIT");
253 m_canUseJIT = !canUseJITString || atoi(canUseJITString);
255 CFRelease(canUseJITKey);
257 char* canUseJITString = getenv("JavaScriptCoreUseJIT");
258 m_canUseJIT = !canUseJITString || atoi(canUseJITString);
264 #if ENABLE(INTERPRETER)
266 m_canUseJIT = executableAllocator.isValid();
268 jitStubs = adoptPtr(new JITThunks(this));
271 heap.notifyIsSafeToCollect();
274 void JSGlobalData::clearBuiltinStructures()
276 structureStructure.clear();
277 debuggerActivationStructure.clear();
278 activationStructure.clear();
279 interruptedExecutionErrorStructure.clear();
280 terminatedExecutionErrorStructure.clear();
281 staticScopeStructure.clear();
282 strictEvalActivationStructure.clear();
283 stringStructure.clear();
284 notAnObjectStructure.clear();
285 propertyNameIteratorStructure.clear();
286 getterSetterStructure.clear();
287 apiWrapperStructure.clear();
288 scopeChainNodeStructure.clear();
289 executableStructure.clear();
290 nativeExecutableStructure.clear();
291 evalExecutableStructure.clear();
292 programExecutableStructure.clear();
293 functionExecutableStructure.clear();
294 regExpStructure.clear();
295 structureChainStructure.clear();
298 JSGlobalData::~JSGlobalData()
300 // By the time this is destroyed, heap.destroy() must already have been called.
304 // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance.
308 arrayPrototypeTable->deleteTable();
309 arrayConstructorTable->deleteTable();
310 booleanPrototypeTable->deleteTable();
311 dateTable->deleteTable();
312 dateConstructorTable->deleteTable();
313 errorPrototypeTable->deleteTable();
314 globalObjectTable->deleteTable();
315 jsonTable->deleteTable();
316 mathTable->deleteTable();
317 numberConstructorTable->deleteTable();
318 numberPrototypeTable->deleteTable();
319 objectConstructorTable->deleteTable();
320 objectPrototypeTable->deleteTable();
321 regExpTable->deleteTable();
322 regExpConstructorTable->deleteTable();
323 regExpPrototypeTable->deleteTable();
324 stringTable->deleteTable();
325 stringConstructorTable->deleteTable();
327 fastDelete(const_cast<HashTable*>(arrayConstructorTable));
328 fastDelete(const_cast<HashTable*>(arrayPrototypeTable));
329 fastDelete(const_cast<HashTable*>(booleanPrototypeTable));
330 fastDelete(const_cast<HashTable*>(dateTable));
331 fastDelete(const_cast<HashTable*>(dateConstructorTable));
332 fastDelete(const_cast<HashTable*>(errorPrototypeTable));
333 fastDelete(const_cast<HashTable*>(globalObjectTable));
334 fastDelete(const_cast<HashTable*>(jsonTable));
335 fastDelete(const_cast<HashTable*>(mathTable));
336 fastDelete(const_cast<HashTable*>(numberConstructorTable));
337 fastDelete(const_cast<HashTable*>(numberPrototypeTable));
338 fastDelete(const_cast<HashTable*>(objectConstructorTable));
339 fastDelete(const_cast<HashTable*>(objectPrototypeTable));
340 fastDelete(const_cast<HashTable*>(regExpTable));
341 fastDelete(const_cast<HashTable*>(regExpConstructorTable));
342 fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
343 fastDelete(const_cast<HashTable*>(stringTable));
344 fastDelete(const_cast<HashTable*>(stringConstructorTable));
349 deleteAllValues(opaqueJSClassData);
353 delete propertyNames;
354 if (globalDataType != Default)
355 deleteIdentifierTable(identifierTable);
358 delete m_regExpCache;
359 #if ENABLE(REGEXP_TRACING)
360 delete m_rtTraceList;
363 #if ENABLE(TIERED_COMPILATION)
364 for (unsigned i = 0; i < osrScratchBuffers.size(); ++i)
365 fastFree(osrScratchBuffers[i]);
369 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type, HeapSize heapSize)
371 return adoptRef(new JSGlobalData(APIContextGroup, type, heapSize));
374 PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type, HeapSize heapSize)
376 return adoptRef(new JSGlobalData(Default, type, heapSize));
379 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type, HeapSize heapSize)
381 return create(type, heapSize);
384 bool JSGlobalData::sharedInstanceExists()
386 return sharedInstanceInternal();
389 JSGlobalData& JSGlobalData::sharedInstance()
391 JSGlobalData*& instance = sharedInstanceInternal();
393 instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall, SmallHeap)).leakRef();
394 #if ENABLE(JSC_MULTIPLE_THREADS)
395 instance->makeUsableFromMultipleThreads();
401 JSGlobalData*& JSGlobalData::sharedInstanceInternal()
403 ASSERT(JSLock::currentThreadIsHoldingLock());
404 static JSGlobalData* sharedInstance;
405 return sharedInstance;
409 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
411 return jitStubs->hostFunctionStub(this, function);
413 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator)
415 return jitStubs->hostFunctionStub(this, function, generator);
418 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
420 return NativeExecutable::create(*this, function, callHostFunctionAsConstructor);
424 JSGlobalData::ClientData::~ClientData()
428 void JSGlobalData::resetDateCache()
430 cachedUTCOffset = std::numeric_limits<double>::quiet_NaN();
431 dstOffsetCache.reset();
432 cachedDateString = UString();
433 cachedDateStringValue = std::numeric_limits<double>::quiet_NaN();
434 dateInstanceCache.reset();
437 void JSGlobalData::startSampling()
439 interpreter->startSampling();
442 void JSGlobalData::stopSampling()
444 interpreter->stopSampling();
447 void JSGlobalData::dumpSampleData(ExecState* exec)
449 interpreter->dumpSampleData(exec);
450 #if ENABLE(ASSEMBLER)
451 ExecutableAllocator::dumpProfile();
455 void JSGlobalData::recompileAllJSFunctions()
457 // If JavaScript is running, it's not safe to recompile, since we'll end
458 // up throwing away code that is live on the stack.
459 ASSERT(!dynamicGlobalObject);
461 heap.forEachCell<Recompiler>();
464 struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
465 HashSet<FunctionExecutable*> currentlyExecutingFunctions;
466 void operator()(JSCell* cell)
468 if (!cell->inherits(&FunctionExecutable::s_info))
470 FunctionExecutable* executable = static_cast<FunctionExecutable*>(cell);
471 if (currentlyExecutingFunctions.contains(executable))
473 executable->discardCode();
477 void JSGlobalData::releaseExecutableMemory()
479 if (dynamicGlobalObject) {
480 StackPreservingRecompiler recompiler;
481 HashSet<JSCell*> roots;
482 heap.getConservativeRegisterRoots(roots);
483 HashSet<JSCell*>::iterator end = roots.end();
484 for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) {
485 ScriptExecutable* executable = 0;
487 if (cell->inherits(&ScriptExecutable::s_info))
488 executable = static_cast<ScriptExecutable*>(*ptr);
489 else if (cell->inherits(&JSFunction::s_info)) {
490 JSFunction* function = asFunction(*ptr);
491 if (function->isHostFunction())
493 executable = function->jsExecutable();
496 ASSERT(executable->inherits(&ScriptExecutable::s_info));
497 executable->unlinkCalls();
498 if (executable->inherits(&FunctionExecutable::s_info))
499 recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable));
502 heap.forEachCell<StackPreservingRecompiler>(recompiler);
504 m_regExpCache->invalidateCode();
505 heap.collectAllGarbage();
508 void releaseExecutableMemory(JSGlobalData& globalData)
510 globalData.releaseExecutableMemory();
513 #if ENABLE(REGEXP_TRACING)
514 void JSGlobalData::addRegExpToTrace(RegExp* regExp)
516 m_rtTraceList->add(regExp);
519 void JSGlobalData::dumpRegExpTrace()
521 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
522 RTTraceList::iterator iter = ++m_rtTraceList->begin();
524 if (iter != m_rtTraceList->end()) {
525 printf("\nRegExp Tracing\n");
526 printf(" match() matches\n");
527 printf("Regular Expression JIT Address calls found\n");
528 printf("----------------------------------------+----------------+----------+----------\n");
530 unsigned reCount = 0;
532 for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
533 (*iter)->printTraceData();
535 printf("%d Regular Expressions\n", reCount);
538 m_rtTraceList->clear();
541 void JSGlobalData::dumpRegExpTrace()