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"
54 #include "RegExpCache.h"
55 #include "RegExpObject.h"
56 #include "StrictEvalActivation.h"
57 #include <wtf/WTFThreadData.h>
58 #if ENABLE(REGEXP_TRACING)
63 #if ENABLE(JSC_MULTIPLE_THREADS)
64 #include <wtf/Threading.h>
68 #include "ProfilerServer.h"
69 #include <CoreFoundation/CoreFoundation.h>
80 void operator()(JSCell
*);
83 inline void Recompiler::operator()(JSCell
* cell
)
85 if (!cell
->inherits(&JSFunction::s_info
))
87 JSFunction
* function
= asFunction(cell
);
88 if (function
->executable()->isHostFunction())
90 function
->jsExecutable()->discardCode();
97 extern JSC_CONST_HASHTABLE HashTable arrayConstructorTable
;
98 extern JSC_CONST_HASHTABLE HashTable arrayPrototypeTable
;
99 extern JSC_CONST_HASHTABLE HashTable booleanPrototypeTable
;
100 extern JSC_CONST_HASHTABLE HashTable jsonTable
;
101 extern JSC_CONST_HASHTABLE HashTable dateTable
;
102 extern JSC_CONST_HASHTABLE HashTable dateConstructorTable
;
103 extern JSC_CONST_HASHTABLE HashTable errorPrototypeTable
;
104 extern JSC_CONST_HASHTABLE HashTable globalObjectTable
;
105 extern JSC_CONST_HASHTABLE HashTable mathTable
;
106 extern JSC_CONST_HASHTABLE HashTable numberConstructorTable
;
107 extern JSC_CONST_HASHTABLE HashTable numberPrototypeTable
;
108 extern JSC_CONST_HASHTABLE HashTable objectConstructorTable
;
109 extern JSC_CONST_HASHTABLE HashTable objectPrototypeTable
;
110 extern JSC_CONST_HASHTABLE HashTable regExpTable
;
111 extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable
;
112 extern JSC_CONST_HASHTABLE HashTable regExpPrototypeTable
;
113 extern JSC_CONST_HASHTABLE HashTable stringTable
;
114 extern JSC_CONST_HASHTABLE HashTable stringConstructorTable
;
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(JSArray
) <= sizeof(storage
), sizeof_JSArray_must_be_less_than_storage
);
137 JSCell
* jsArray
= new (storage
) JSArray(JSArray::VPtrStealingHack
);
139 JSGlobalData::jsArrayVPtr
= jsArray
->vptr();
141 COMPILE_ASSERT(sizeof(JSByteArray
) <= sizeof(storage
), sizeof_JSByteArray_must_be_less_than_storage
);
142 JSCell
* jsByteArray
= new (storage
) JSByteArray(JSByteArray::VPtrStealingHack
);
144 JSGlobalData::jsByteArrayVPtr
= jsByteArray
->vptr();
146 COMPILE_ASSERT(sizeof(JSString
) <= sizeof(storage
), sizeof_JSString_must_be_less_than_storage
);
147 JSCell
* jsString
= new (storage
) JSString(JSString::VPtrStealingHack
);
149 JSGlobalData::jsStringVPtr
= jsString
->vptr();
151 COMPILE_ASSERT(sizeof(JSFunction
) <= sizeof(storage
), sizeof_JSFunction_must_be_less_than_storage
);
152 JSCell
* jsFunction
= new (storage
) JSFunction(JSCell::VPtrStealingHack
);
154 JSGlobalData::jsFunctionVPtr
= jsFunction
->vptr();
157 JSGlobalData::JSGlobalData(GlobalDataType globalDataType
, ThreadStackType threadStackType
)
158 : globalDataType(globalDataType
)
160 , arrayConstructorTable(fastNew
<HashTable
>(JSC::arrayConstructorTable
))
161 , arrayPrototypeTable(fastNew
<HashTable
>(JSC::arrayPrototypeTable
))
162 , booleanPrototypeTable(fastNew
<HashTable
>(JSC::booleanPrototypeTable
))
163 , dateTable(fastNew
<HashTable
>(JSC::dateTable
))
164 , dateConstructorTable(fastNew
<HashTable
>(JSC::dateConstructorTable
))
165 , errorPrototypeTable(fastNew
<HashTable
>(JSC::errorPrototypeTable
))
166 , globalObjectTable(fastNew
<HashTable
>(JSC::globalObjectTable
))
167 , jsonTable(fastNew
<HashTable
>(JSC::jsonTable
))
168 , mathTable(fastNew
<HashTable
>(JSC::mathTable
))
169 , numberConstructorTable(fastNew
<HashTable
>(JSC::numberConstructorTable
))
170 , numberPrototypeTable(fastNew
<HashTable
>(JSC::numberPrototypeTable
))
171 , objectConstructorTable(fastNew
<HashTable
>(JSC::objectConstructorTable
))
172 , objectPrototypeTable(fastNew
<HashTable
>(JSC::objectPrototypeTable
))
173 , regExpTable(fastNew
<HashTable
>(JSC::regExpTable
))
174 , regExpConstructorTable(fastNew
<HashTable
>(JSC::regExpConstructorTable
))
175 , regExpPrototypeTable(fastNew
<HashTable
>(JSC::regExpPrototypeTable
))
176 , stringTable(fastNew
<HashTable
>(JSC::stringTable
))
177 , stringConstructorTable(fastNew
<HashTable
>(JSC::stringConstructorTable
))
178 , identifierTable(globalDataType
== Default
? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
179 , propertyNames(new CommonIdentifiers(this))
180 , emptyList(new MarkedArgumentBuffer
)
181 #if ENABLE(ASSEMBLER)
182 , executableAllocator(*this)
183 , regexAllocator(*this)
185 , lexer(new Lexer(this))
189 , globalObjectCount(0)
190 , dynamicGlobalObject(0)
191 , cachedUTCOffset(NaN
)
192 , maxReentryDepth(threadStackType
== ThreadStackTypeSmall
? MaxSmallThreadReentryDepth
: MaxLargeThreadReentryDepth
)
193 , m_regExpCache(new RegExpCache(this))
194 #if ENABLE(REGEXP_TRACING)
195 , m_rtTraceList(new RTTraceList())
201 interpreter
= new Interpreter(*this);
202 if (globalDataType
== Default
)
203 m_stack
= wtfThreadData().stack();
205 // Need to be careful to keep everything consistent here
206 IdentifierTable
* existingEntryIdentifierTable
= wtfThreadData().setCurrentIdentifierTable(identifierTable
);
207 JSLock
lock(SilenceAssertionsOnly
);
208 structureStructure
.set(*this, Structure::createStructure(*this));
209 debuggerActivationStructure
.set(*this, DebuggerActivation::createStructure(*this, jsNull()));
210 activationStructure
.set(*this, JSActivation::createStructure(*this, jsNull()));
211 interruptedExecutionErrorStructure
.set(*this, JSNonFinalObject::createStructure(*this, jsNull()));
212 terminatedExecutionErrorStructure
.set(*this, JSNonFinalObject::createStructure(*this, jsNull()));
213 staticScopeStructure
.set(*this, JSStaticScopeObject::createStructure(*this, jsNull()));
214 strictEvalActivationStructure
.set(*this, StrictEvalActivation::createStructure(*this, jsNull()));
215 stringStructure
.set(*this, JSString::createStructure(*this, jsNull()));
216 notAnObjectStructure
.set(*this, JSNotAnObject::createStructure(*this, jsNull()));
217 propertyNameIteratorStructure
.set(*this, JSPropertyNameIterator::createStructure(*this, jsNull()));
218 getterSetterStructure
.set(*this, GetterSetter::createStructure(*this, jsNull()));
219 apiWrapperStructure
.set(*this, JSAPIValueWrapper::createStructure(*this, jsNull()));
220 scopeChainNodeStructure
.set(*this, ScopeChainNode::createStructure(*this, jsNull()));
221 executableStructure
.set(*this, ExecutableBase::createStructure(*this, jsNull()));
222 nativeExecutableStructure
.set(*this, NativeExecutable::createStructure(*this, jsNull()));
223 evalExecutableStructure
.set(*this, EvalExecutable::createStructure(*this, jsNull()));
224 programExecutableStructure
.set(*this, ProgramExecutable::createStructure(*this, jsNull()));
225 functionExecutableStructure
.set(*this, FunctionExecutable::createStructure(*this, jsNull()));
226 dummyMarkableCellStructure
.set(*this, JSCell::createDummyStructure(*this));
227 regExpStructure
.set(*this, RegExp::createStructure(*this, jsNull()));
228 structureChainStructure
.set(*this, StructureChain::createStructure(*this, jsNull()));
230 #if ENABLE(JSC_ZOMBIES)
231 zombieStructure
.set(*this, JSZombie::createStructure(*this, jsNull()));
234 wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable
);
237 startProfilerServerIfNeeded();
239 #if ENABLE(JIT) && ENABLE(INTERPRETER)
241 CFStringRef canUseJITKey
= CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman
);
242 CFBooleanRef canUseJIT
= (CFBooleanRef
)CFPreferencesCopyAppValue(canUseJITKey
, kCFPreferencesCurrentApplication
);
244 m_canUseJIT
= kCFBooleanTrue
== canUseJIT
;
245 CFRelease(canUseJIT
);
247 char* canUseJITString
= getenv("JavaScriptCoreUseJIT");
248 m_canUseJIT
= !canUseJITString
|| atoi(canUseJITString
);
250 CFRelease(canUseJITKey
);
252 char* canUseJITString
= getenv("JavaScriptCoreUseJIT");
253 m_canUseJIT
= !canUseJITString
|| atoi(canUseJITString
);
259 #if ENABLE(INTERPRETER)
261 m_canUseJIT
= executableAllocator
.isValid();
263 jitStubs
= adoptPtr(new JITThunks(this));
267 void JSGlobalData::clearBuiltinStructures()
269 structureStructure
.clear();
270 debuggerActivationStructure
.clear();
271 activationStructure
.clear();
272 interruptedExecutionErrorStructure
.clear();
273 terminatedExecutionErrorStructure
.clear();
274 staticScopeStructure
.clear();
275 strictEvalActivationStructure
.clear();
276 stringStructure
.clear();
277 notAnObjectStructure
.clear();
278 propertyNameIteratorStructure
.clear();
279 getterSetterStructure
.clear();
280 apiWrapperStructure
.clear();
281 scopeChainNodeStructure
.clear();
282 executableStructure
.clear();
283 nativeExecutableStructure
.clear();
284 evalExecutableStructure
.clear();
285 programExecutableStructure
.clear();
286 functionExecutableStructure
.clear();
287 dummyMarkableCellStructure
.clear();
288 regExpStructure
.clear();
289 structureChainStructure
.clear();
291 #if ENABLE(JSC_ZOMBIES)
292 zombieStructure
.clear();
296 JSGlobalData::~JSGlobalData()
298 // By the time this is destroyed, heap.destroy() must already have been called.
302 // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance.
306 arrayPrototypeTable
->deleteTable();
307 arrayConstructorTable
->deleteTable();
308 booleanPrototypeTable
->deleteTable();
309 dateTable
->deleteTable();
310 dateConstructorTable
->deleteTable();
311 errorPrototypeTable
->deleteTable();
312 globalObjectTable
->deleteTable();
313 jsonTable
->deleteTable();
314 mathTable
->deleteTable();
315 numberConstructorTable
->deleteTable();
316 numberPrototypeTable
->deleteTable();
317 objectConstructorTable
->deleteTable();
318 objectPrototypeTable
->deleteTable();
319 regExpTable
->deleteTable();
320 regExpConstructorTable
->deleteTable();
321 regExpPrototypeTable
->deleteTable();
322 stringTable
->deleteTable();
323 stringConstructorTable
->deleteTable();
325 fastDelete(const_cast<HashTable
*>(arrayConstructorTable
));
326 fastDelete(const_cast<HashTable
*>(arrayPrototypeTable
));
327 fastDelete(const_cast<HashTable
*>(booleanPrototypeTable
));
328 fastDelete(const_cast<HashTable
*>(dateTable
));
329 fastDelete(const_cast<HashTable
*>(dateConstructorTable
));
330 fastDelete(const_cast<HashTable
*>(errorPrototypeTable
));
331 fastDelete(const_cast<HashTable
*>(globalObjectTable
));
332 fastDelete(const_cast<HashTable
*>(jsonTable
));
333 fastDelete(const_cast<HashTable
*>(mathTable
));
334 fastDelete(const_cast<HashTable
*>(numberConstructorTable
));
335 fastDelete(const_cast<HashTable
*>(numberPrototypeTable
));
336 fastDelete(const_cast<HashTable
*>(objectConstructorTable
));
337 fastDelete(const_cast<HashTable
*>(objectPrototypeTable
));
338 fastDelete(const_cast<HashTable
*>(regExpTable
));
339 fastDelete(const_cast<HashTable
*>(regExpConstructorTable
));
340 fastDelete(const_cast<HashTable
*>(regExpPrototypeTable
));
341 fastDelete(const_cast<HashTable
*>(stringTable
));
342 fastDelete(const_cast<HashTable
*>(stringConstructorTable
));
347 deleteAllValues(opaqueJSClassData
);
351 delete propertyNames
;
352 if (globalDataType
!= Default
)
353 deleteIdentifierTable(identifierTable
);
356 delete m_regExpCache
;
357 #if ENABLE(REGEXP_TRACING)
358 delete m_rtTraceList
;
362 PassRefPtr
<JSGlobalData
> JSGlobalData::createContextGroup(ThreadStackType type
)
364 return adoptRef(new JSGlobalData(APIContextGroup
, type
));
367 PassRefPtr
<JSGlobalData
> JSGlobalData::create(ThreadStackType type
)
369 return adoptRef(new JSGlobalData(Default
, type
));
372 PassRefPtr
<JSGlobalData
> JSGlobalData::createLeaked(ThreadStackType type
)
377 bool JSGlobalData::sharedInstanceExists()
379 return sharedInstanceInternal();
382 JSGlobalData
& JSGlobalData::sharedInstance()
384 JSGlobalData
*& instance
= sharedInstanceInternal();
386 instance
= adoptRef(new JSGlobalData(APIShared
, ThreadStackTypeSmall
)).leakRef();
387 #if ENABLE(JSC_MULTIPLE_THREADS)
388 instance
->makeUsableFromMultipleThreads();
394 JSGlobalData
*& JSGlobalData::sharedInstanceInternal()
396 ASSERT(JSLock::currentThreadIsHoldingLock());
397 static JSGlobalData
* sharedInstance
;
398 return sharedInstance
;
402 NativeExecutable
* JSGlobalData::getHostFunction(NativeFunction function
)
404 return jitStubs
->hostFunctionStub(this, function
);
406 NativeExecutable
* JSGlobalData::getHostFunction(NativeFunction function
, ThunkGenerator generator
)
408 return jitStubs
->hostFunctionStub(this, function
, generator
);
411 NativeExecutable
* JSGlobalData::getHostFunction(NativeFunction function
)
413 return NativeExecutable::create(*this, function
, callHostFunctionAsConstructor
);
417 JSGlobalData::ClientData::~ClientData()
421 void JSGlobalData::resetDateCache()
423 cachedUTCOffset
= NaN
;
424 dstOffsetCache
.reset();
425 cachedDateString
= UString();
426 cachedDateStringValue
= NaN
;
427 dateInstanceCache
.reset();
430 void JSGlobalData::startSampling()
432 interpreter
->startSampling();
435 void JSGlobalData::stopSampling()
437 interpreter
->stopSampling();
440 void JSGlobalData::dumpSampleData(ExecState
* exec
)
442 interpreter
->dumpSampleData(exec
);
445 void JSGlobalData::recompileAllJSFunctions()
447 // If JavaScript is running, it's not safe to recompile, since we'll end
448 // up throwing away code that is live on the stack.
449 ASSERT(!dynamicGlobalObject
);
451 Recompiler recompiler
;
452 heap
.forEach(recompiler
);
455 struct StackPreservingRecompiler
{
456 HashSet
<FunctionExecutable
*> currentlyExecutingFunctions
;
457 void operator()(JSCell
* cell
)
459 if (!cell
->inherits(&FunctionExecutable::s_info
))
461 FunctionExecutable
* executable
= static_cast<FunctionExecutable
*>(cell
);
462 if (currentlyExecutingFunctions
.contains(executable
))
464 executable
->discardCode();
468 void JSGlobalData::releaseExecutableMemory()
470 if (dynamicGlobalObject
) {
471 StackPreservingRecompiler recompiler
;
472 HashSet
<JSCell
*> roots
;
473 heap
.getConservativeRegisterRoots(roots
);
474 HashSet
<JSCell
*>::iterator end
= roots
.end();
475 for (HashSet
<JSCell
*>::iterator ptr
= roots
.begin(); ptr
!= end
; ++ptr
) {
476 ScriptExecutable
* executable
= 0;
478 if (cell
->inherits(&ScriptExecutable::s_info
))
479 executable
= static_cast<ScriptExecutable
*>(*ptr
);
480 else if (cell
->inherits(&JSFunction::s_info
)) {
481 JSFunction
* function
= asFunction(*ptr
);
482 if (function
->isHostFunction())
484 executable
= function
->jsExecutable();
487 ASSERT(executable
->inherits(&ScriptExecutable::s_info
));
488 executable
->unlinkCalls();
489 if (executable
->inherits(&FunctionExecutable::s_info
))
490 recompiler
.currentlyExecutingFunctions
.add(static_cast<FunctionExecutable
*>(executable
));
493 heap
.forEach(recompiler
);
495 recompileAllJSFunctions();
497 m_regExpCache
->invalidateCode();
498 heap
.collectAllGarbage();
501 #if ENABLE(ASSEMBLER)
502 void releaseExecutableMemory(JSGlobalData
& globalData
)
504 globalData
.releaseExecutableMemory();
508 #if ENABLE(REGEXP_TRACING)
509 void JSGlobalData::addRegExpToTrace(RegExp
* regExp
)
511 m_rtTraceList
->add(regExp
);
514 void JSGlobalData::dumpRegExpTrace()
516 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
517 RTTraceList::iterator iter
= ++m_rtTraceList
->begin();
519 if (iter
!= m_rtTraceList
->end()) {
520 printf("\nRegExp Tracing\n");
521 printf(" match() matches\n");
522 printf("Regular Expression JIT Address calls found\n");
523 printf("----------------------------------------+----------------+----------+----------\n");
525 unsigned reCount
= 0;
527 for (; iter
!= m_rtTraceList
->end(); ++iter
, ++reCount
)
528 (*iter
)->printTraceData();
530 printf("%d Regular Expressions\n", reCount
);
533 m_rtTraceList
->clear();
536 void JSGlobalData::dumpRegExpTrace()