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 "Interpreter.h"
41 #include "JSActivation.h"
42 #include "JSAPIValueWrapper.h"
44 #include "JSClassRef.h"
45 #include "JSFunction.h"
47 #include "JSNotAnObject.h"
48 #include "JSPropertyNameIterator.h"
49 #include "JSStaticScopeObject.h"
53 #include "ParserArena.h"
54 #include "RegExpCache.h"
55 #include "RegExpObject.h"
56 #include "StrictEvalActivation.h"
57 #include "StrongInlines.h"
58 #include <wtf/Threading.h>
59 #include <wtf/WTFThreadData.h>
62 #include "ConservativeRoots.h"
65 #if ENABLE(REGEXP_TRACING)
70 #include <CoreFoundation/CoreFoundation.h>
77 extern const HashTable arrayConstructorTable
;
78 extern const HashTable arrayPrototypeTable
;
79 extern const HashTable booleanPrototypeTable
;
80 extern const HashTable jsonTable
;
81 extern const HashTable dateTable
;
82 extern const HashTable dateConstructorTable
;
83 extern const HashTable errorPrototypeTable
;
84 extern const HashTable globalObjectTable
;
85 extern const HashTable mathTable
;
86 extern const HashTable numberConstructorTable
;
87 extern const HashTable numberPrototypeTable
;
88 JS_EXPORTDATA
extern const HashTable objectConstructorTable
;
89 extern const HashTable objectPrototypeTable
;
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
;
96 #if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
97 static bool enableAssembler(ExecutableAllocator
& executableAllocator
)
99 if (!executableAllocator
.isValid() || !Options::useJIT
)
102 CFStringRef canUseJITKey
= CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman
);
103 CFBooleanRef canUseJIT
= (CFBooleanRef
)CFPreferencesCopyAppValue(canUseJITKey
, kCFPreferencesCurrentApplication
);
105 return kCFBooleanTrue
== canUseJIT
;
106 CFRelease(canUseJIT
);
108 CFRelease(canUseJITKey
);
111 #if USE(CF) || OS(UNIX)
112 char* canUseJITString
= getenv("JavaScriptCoreUseJIT");
113 return !canUseJITString
|| atoi(canUseJITString
);
120 JSGlobalData::JSGlobalData(GlobalDataType globalDataType
, ThreadStackType threadStackType
, HeapSize heapSize
)
121 : heap(this, heapSize
)
122 , globalDataType(globalDataType
)
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)
149 , parserArena(adoptPtr(new ParserArena
))
150 , keywords(adoptPtr(new Keywords(this)))
152 , jsArrayClassInfo(&JSArray::s_info
)
153 , jsFinalObjectClassInfo(&JSFinalObject::s_info
)
155 , sizeOfLastScratchBuffer(0)
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())
167 #if CPU(X86) && ENABLE(JIT)
168 , m_timeoutCount(512)
170 #if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
171 , m_canUseAssembler(enableAssembler(executableAllocator
))
173 #if ENABLE(GC_VALIDATION)
174 , m_initializingObjectClass(0)
176 , m_inDefineOwnProperty(false)
178 interpreter
= new Interpreter
;
180 // Need to be careful to keep everything consistent here
181 JSLockHolder
lock(this);
182 IdentifierTable
* existingEntryIdentifierTable
= wtfThreadData().setCurrentIdentifierTable(identifierTable
);
183 structureStructure
.set(*this, Structure::createStructure(*this));
184 debuggerActivationStructure
.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull()));
185 activationStructure
.set(*this, JSActivation::createStructure(*this, 0, jsNull()));
186 interruptedExecutionErrorStructure
.set(*this, InterruptedExecutionError::createStructure(*this, 0, jsNull()));
187 terminatedExecutionErrorStructure
.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
188 staticScopeStructure
.set(*this, JSStaticScopeObject::createStructure(*this, 0, jsNull()));
189 strictEvalActivationStructure
.set(*this, StrictEvalActivation::createStructure(*this, 0, jsNull()));
190 stringStructure
.set(*this, JSString::createStructure(*this, 0, jsNull()));
191 notAnObjectStructure
.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
192 propertyNameIteratorStructure
.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
193 getterSetterStructure
.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
194 apiWrapperStructure
.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
195 scopeChainNodeStructure
.set(*this, ScopeChainNode::createStructure(*this, 0, jsNull()));
196 executableStructure
.set(*this, ExecutableBase::createStructure(*this, 0, jsNull()));
197 nativeExecutableStructure
.set(*this, NativeExecutable::createStructure(*this, 0, jsNull()));
198 evalExecutableStructure
.set(*this, EvalExecutable::createStructure(*this, 0, jsNull()));
199 programExecutableStructure
.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
200 functionExecutableStructure
.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
201 regExpStructure
.set(*this, RegExp::createStructure(*this, 0, jsNull()));
202 structureChainStructure
.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
204 wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable
);
207 jitStubs
= adoptPtr(new JITThunks(this));
210 interpreter
->initialize(&llintData
, this->canUseJIT());
212 initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
214 heap
.notifyIsSafeToCollect();
216 llintData
.performAssertions(*this);
219 JSGlobalData::~JSGlobalData()
221 ASSERT(!m_apiLock
.currentThreadIsHoldingLock());
222 if (heap
.activityCallback())
223 heap
.activityCallback()->didStartVMShutdown();
224 heap
.lastChanceToFinalize();
228 interpreter
= reinterpret_cast<Interpreter
*>(0xbbadbeef);
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();
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
));
269 opaqueJSClassData
.clear();
273 delete propertyNames
;
274 if (globalDataType
!= Default
)
275 deleteIdentifierTable(identifierTable
);
278 delete m_regExpCache
;
279 #if ENABLE(REGEXP_TRACING)
280 delete m_rtTraceList
;
284 for (unsigned i
= 0; i
< scratchBuffers
.size(); ++i
)
285 fastFree(scratchBuffers
[i
]);
289 PassRefPtr
<JSGlobalData
> JSGlobalData::createContextGroup(ThreadStackType type
, HeapSize heapSize
)
291 return adoptRef(new JSGlobalData(APIContextGroup
, type
, heapSize
));
294 PassRefPtr
<JSGlobalData
> JSGlobalData::create(ThreadStackType type
, HeapSize heapSize
)
296 return adoptRef(new JSGlobalData(Default
, type
, heapSize
));
299 PassRefPtr
<JSGlobalData
> JSGlobalData::createLeaked(ThreadStackType type
, HeapSize heapSize
)
301 return create(type
, heapSize
);
304 bool JSGlobalData::sharedInstanceExists()
306 return sharedInstanceInternal();
309 JSGlobalData
& JSGlobalData::sharedInstance()
311 GlobalJSLock globalLock
;
312 JSGlobalData
*& instance
= sharedInstanceInternal();
314 instance
= adoptRef(new JSGlobalData(APIShared
, ThreadStackTypeSmall
, SmallHeap
)).leakRef();
315 instance
->makeUsableFromMultipleThreads();
320 JSGlobalData
*& JSGlobalData::sharedInstanceInternal()
322 static JSGlobalData
* sharedInstance
;
323 return sharedInstance
;
327 static ThunkGenerator
thunkGeneratorForIntrinsic(Intrinsic intrinsic
)
330 case CharCodeAtIntrinsic
:
331 return charCodeAtThunkGenerator
;
332 case CharAtIntrinsic
:
333 return charAtThunkGenerator
;
334 case FromCharCodeIntrinsic
:
335 return fromCharCodeThunkGenerator
;
337 return sqrtThunkGenerator
;
339 return powThunkGenerator
;
341 return absThunkGenerator
;
343 return floorThunkGenerator
;
345 return ceilThunkGenerator
;
347 return roundThunkGenerator
;
349 return expThunkGenerator
;
351 return logThunkGenerator
;
357 NativeExecutable
* JSGlobalData::getHostFunction(NativeFunction function
, NativeFunction constructor
)
359 #if ENABLE(CLASSIC_INTERPRETER)
361 return NativeExecutable::create(*this, function
, constructor
);
363 return jitStubs
->hostFunctionStub(this, function
, constructor
);
365 NativeExecutable
* JSGlobalData::getHostFunction(NativeFunction function
, Intrinsic intrinsic
)
368 return jitStubs
->hostFunctionStub(this, function
, intrinsic
!= NoIntrinsic
? thunkGeneratorForIntrinsic(intrinsic
) : 0, intrinsic
);
371 NativeExecutable
* JSGlobalData::getHostFunction(NativeFunction function
, NativeFunction constructor
)
373 return NativeExecutable::create(*this, function
, constructor
);
377 JSGlobalData::ClientData::~ClientData()
381 void JSGlobalData::resetDateCache()
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();
390 void JSGlobalData::startSampling()
392 interpreter
->startSampling();
395 void JSGlobalData::stopSampling()
397 interpreter
->stopSampling();
400 void JSGlobalData::dumpSampleData(ExecState
* exec
)
402 interpreter
->dumpSampleData(exec
);
403 #if ENABLE(ASSEMBLER)
404 ExecutableAllocator::dumpProfile();
408 struct StackPreservingRecompiler
: public MarkedBlock::VoidFunctor
{
409 HashSet
<FunctionExecutable
*> currentlyExecutingFunctions
;
410 void operator()(JSCell
* cell
)
412 if (!cell
->inherits(&FunctionExecutable::s_info
))
414 FunctionExecutable
* executable
= jsCast
<FunctionExecutable
*>(cell
);
415 if (currentlyExecutingFunctions
.contains(executable
))
417 executable
->discardCode();
421 void JSGlobalData::releaseExecutableMemory()
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;
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())
437 executable
= function
->jsExecutable();
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
));
446 heap
.objectSpace().forEachCell
<StackPreservingRecompiler
>(recompiler
);
448 m_regExpCache
->invalidateCode();
449 heap
.collectAllGarbage();
452 #if ENABLE(ASSEMBLER)
453 void releaseExecutableMemory(JSGlobalData
& globalData
)
455 globalData
.releaseExecutableMemory();
460 void JSGlobalData::gatherConservativeRoots(ConservativeRoots
& conservativeRoots
)
462 for (size_t i
= 0; i
< scratchBuffers
.size(); i
++) {
463 ScratchBuffer
* scratchBuffer
= scratchBuffers
[i
];
464 if (scratchBuffer
->activeLength()) {
465 void* bufferStart
= scratchBuffer
->dataBuffer();
466 conservativeRoots
.add(bufferStart
, static_cast<void*>(static_cast<char*>(bufferStart
) + scratchBuffer
->activeLength()));
472 #if ENABLE(REGEXP_TRACING)
473 void JSGlobalData::addRegExpToTrace(RegExp
* regExp
)
475 m_rtTraceList
->add(regExp
);
478 void JSGlobalData::dumpRegExpTrace()
480 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
481 RTTraceList::iterator iter
= ++m_rtTraceList
->begin();
483 if (iter
!= m_rtTraceList
->end()) {
484 dataLog("\nRegExp Tracing\n");
485 dataLog(" match() matches\n");
486 dataLog("Regular Expression JIT Address calls found\n");
487 dataLog("----------------------------------------+----------------+----------+----------\n");
489 unsigned reCount
= 0;
491 for (; iter
!= m_rtTraceList
->end(); ++iter
, ++reCount
)
492 (*iter
)->printTraceData();
494 dataLog("%d Regular Expressions\n", reCount
);
497 m_rtTraceList
->clear();
500 void JSGlobalData::dumpRegExpTrace()