2 * Copyright (C) 2008, 2011, 2013 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.
33 #include "CodeCache.h"
34 #include "CommonIdentifiers.h"
35 #include "DFGLongLivedState.h"
36 #include "DebuggerActivation.h"
37 #include "FunctionConstructor.h"
38 #include "GCActivityCallback.h"
39 #include "GetterSetter.h"
41 #include "HostCallReturnValue.h"
42 #include "IncrementalSweeper.h"
43 #include "Interpreter.h"
44 #include "JSActivation.h"
45 #include "JSAPIValueWrapper.h"
47 #include "JSFunction.h"
49 #include "JSNameScope.h"
50 #include "JSNotAnObject.h"
51 #include "JSPropertyNameIterator.h"
52 #include "JSWithScope.h"
56 #include "ParserArena.h"
57 #include "RegExpCache.h"
58 #include "RegExpObject.h"
59 #include "SourceProviderCache.h"
60 #include "StrictEvalActivation.h"
61 #include "StrongInlines.h"
62 #include "UnlinkedCodeBlock.h"
63 #include <wtf/ProcessID.h>
64 #include <wtf/RetainPtr.h>
65 #include <wtf/StringPrintStream.h>
66 #include <wtf/Threading.h>
67 #include <wtf/WTFThreadData.h>
70 #include "ConservativeRoots.h"
73 #if ENABLE(REGEXP_TRACING)
78 #include <CoreFoundation/CoreFoundation.h>
85 extern const HashTable arrayConstructorTable
;
86 extern const HashTable arrayPrototypeTable
;
87 extern const HashTable booleanPrototypeTable
;
88 extern const HashTable jsonTable
;
89 extern const HashTable dateTable
;
90 extern const HashTable dateConstructorTable
;
91 extern const HashTable errorPrototypeTable
;
92 extern const HashTable globalObjectTable
;
93 extern const HashTable mathTable
;
94 extern const HashTable numberConstructorTable
;
95 extern const HashTable numberPrototypeTable
;
96 JS_EXPORTDATA
extern const HashTable objectConstructorTable
;
97 extern const HashTable privateNamePrototypeTable
;
98 extern const HashTable regExpTable
;
99 extern const HashTable regExpConstructorTable
;
100 extern const HashTable regExpPrototypeTable
;
101 extern const HashTable stringConstructorTable
;
103 // Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either
104 // ENABLE(JIT) or ENABLE(YARR_JIT) or both are enabled. The code below
105 // just checks for ENABLE(JIT) or ENABLE(YARR_JIT) with this premise in mind.
107 #if ENABLE(ASSEMBLER)
108 static bool enableAssembler(ExecutableAllocator
& executableAllocator
)
110 if (!Options::useJIT() && !Options::useRegExpJIT())
113 if (!executableAllocator
.isValid()) {
114 if (Options::crashIfCantAllocateJITMemory())
120 #if COMPILER(GCC) && !COMPILER(CLANG)
121 // FIXME: remove this once the EWS have been upgraded to LLVM.
122 // Work around a bug of GCC with strict-aliasing.
123 RetainPtr
<CFStringRef
> canUseJITKeyRetain
= adoptCF(CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman
));
124 CFStringRef canUseJITKey
= canUseJITKeyRetain
.get();
126 CFStringRef canUseJITKey
= CFSTR("JavaScriptCoreUseJIT");
127 #endif // COMPILER(GCC) && !COMPILER(CLANG)
128 RetainPtr
<CFTypeRef
> canUseJIT
= adoptCF(CFPreferencesCopyAppValue(canUseJITKey
, kCFPreferencesCurrentApplication
));
130 return kCFBooleanTrue
== canUseJIT
.get();
133 #if USE(CF) || OS(UNIX)
134 char* canUseJITString
= getenv("JavaScriptCoreUseJIT");
135 return !canUseJITString
|| atoi(canUseJITString
);
140 #endif // ENABLE(!ASSEMBLER)
142 VM::VM(VMType vmType
, HeapType heapType
)
143 : m_apiLock(adoptRef(new JSLock(this)))
144 #if ENABLE(ASSEMBLER)
145 , executableAllocator(*this)
147 , heap(this, heapType
)
150 , topCallFrame(CallFrame::noCaller())
151 , arrayConstructorTable(fastNew
<HashTable
>(JSC::arrayConstructorTable
))
152 , arrayPrototypeTable(fastNew
<HashTable
>(JSC::arrayPrototypeTable
))
153 , booleanPrototypeTable(fastNew
<HashTable
>(JSC::booleanPrototypeTable
))
154 , dateTable(fastNew
<HashTable
>(JSC::dateTable
))
155 , dateConstructorTable(fastNew
<HashTable
>(JSC::dateConstructorTable
))
156 , errorPrototypeTable(fastNew
<HashTable
>(JSC::errorPrototypeTable
))
157 , globalObjectTable(fastNew
<HashTable
>(JSC::globalObjectTable
))
158 , jsonTable(fastNew
<HashTable
>(JSC::jsonTable
))
159 , mathTable(fastNew
<HashTable
>(JSC::mathTable
))
160 , numberConstructorTable(fastNew
<HashTable
>(JSC::numberConstructorTable
))
161 , numberPrototypeTable(fastNew
<HashTable
>(JSC::numberPrototypeTable
))
162 , objectConstructorTable(fastNew
<HashTable
>(JSC::objectConstructorTable
))
163 , privateNamePrototypeTable(fastNew
<HashTable
>(JSC::privateNamePrototypeTable
))
164 , regExpTable(fastNew
<HashTable
>(JSC::regExpTable
))
165 , regExpConstructorTable(fastNew
<HashTable
>(JSC::regExpConstructorTable
))
166 , regExpPrototypeTable(fastNew
<HashTable
>(JSC::regExpPrototypeTable
))
167 , stringConstructorTable(fastNew
<HashTable
>(JSC::stringConstructorTable
))
168 , identifierTable(vmType
== Default
? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
169 , propertyNames(new CommonIdentifiers(this))
170 , emptyList(new MarkedArgumentBuffer
)
171 , parserArena(adoptPtr(new ParserArena
))
172 , keywords(adoptPtr(new Keywords(this)))
174 , jsArrayClassInfo(&JSArray::s_info
)
175 , jsFinalObjectClassInfo(&JSFinalObject::s_info
)
177 , sizeOfLastScratchBuffer(0)
179 , dynamicGlobalObject(0)
180 , m_enabledProfiler(0)
181 , m_regExpCache(new RegExpCache(this))
182 #if ENABLE(REGEXP_TRACING)
183 , m_rtTraceList(new RTTraceList())
188 , m_newStringsSinceLastHashCons(0)
189 #if ENABLE(ASSEMBLER)
190 , m_canUseAssembler(enableAssembler(executableAllocator
))
193 , m_canUseJIT(m_canUseAssembler
&& Options::useJIT())
196 , m_canUseRegExpJIT(m_canUseAssembler
&& Options::useRegExpJIT())
198 #if ENABLE(GC_VALIDATION)
199 , m_initializingObjectClass(0)
201 , m_inDefineOwnProperty(false)
202 , m_codeCache(CodeCache::create(CodeCache::GlobalCodeCache
))
204 interpreter
= new Interpreter(*this);
206 // Need to be careful to keep everything consistent here
207 JSLockHolder
lock(this);
208 IdentifierTable
* existingEntryIdentifierTable
= wtfThreadData().setCurrentIdentifierTable(identifierTable
);
209 structureStructure
.set(*this, Structure::createStructure(*this));
210 structureRareDataStructure
.set(*this, StructureRareData::createStructure(*this, 0, jsNull()));
211 debuggerActivationStructure
.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull()));
212 terminatedExecutionErrorStructure
.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
213 stringStructure
.set(*this, JSString::createStructure(*this, 0, jsNull()));
214 notAnObjectStructure
.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
215 propertyNameIteratorStructure
.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
216 getterSetterStructure
.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
217 apiWrapperStructure
.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
218 JSScopeStructure
.set(*this, JSScope::createStructure(*this, 0, jsNull()));
219 executableStructure
.set(*this, ExecutableBase::createStructure(*this, 0, jsNull()));
220 nativeExecutableStructure
.set(*this, NativeExecutable::createStructure(*this, 0, jsNull()));
221 evalExecutableStructure
.set(*this, EvalExecutable::createStructure(*this, 0, jsNull()));
222 programExecutableStructure
.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
223 functionExecutableStructure
.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
224 regExpStructure
.set(*this, RegExp::createStructure(*this, 0, jsNull()));
225 sharedSymbolTableStructure
.set(*this, SharedSymbolTable::createStructure(*this, 0, jsNull()));
226 structureChainStructure
.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
227 sparseArrayValueMapStructure
.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull()));
228 withScopeStructure
.set(*this, JSWithScope::createStructure(*this, 0, jsNull()));
229 unlinkedFunctionExecutableStructure
.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull()));
230 unlinkedProgramCodeBlockStructure
.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull()));
231 unlinkedEvalCodeBlockStructure
.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull()));
232 unlinkedFunctionCodeBlockStructure
.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull()));
233 propertyTableStructure
.set(*this, PropertyTable::createStructure(*this, 0, jsNull()));
234 smallStrings
.initializeCommonStrings(*this);
236 wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable
);
239 jitStubs
= adoptPtr(new JITThunks());
240 performPlatformSpecificJITAssertions(this);
243 interpreter
->initialize(this->canUseJIT());
246 initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
249 heap
.notifyIsSafeToCollect();
251 LLInt::Data::performAssertions(*this);
253 if (Options::enableProfiler()) {
254 m_perBytecodeProfiler
= adoptPtr(new Profiler::Database(*this));
256 StringPrintStream pathOut
;
258 const char* profilerPath
= getenv("JSC_PROFILER_PATH");
260 pathOut
.print(profilerPath
, "/");
262 pathOut
.print("JSCProfile-", getCurrentProcessID(), "-", m_perBytecodeProfiler
->databaseID(), ".json");
263 m_perBytecodeProfiler
->registerToSaveAtExit(pathOut
.toCString().data());
268 m_dfgState
= adoptPtr(new DFG::LongLivedState());
274 // Clear this first to ensure that nobody tries to remove themselves from it.
275 m_perBytecodeProfiler
.clear();
277 ASSERT(m_apiLock
->currentThreadIsHoldingLock());
278 m_apiLock
->willDestroyVM(this);
279 heap
.lastChanceToFinalize();
283 interpreter
= reinterpret_cast<Interpreter
*>(0xbbadbeef);
286 arrayPrototypeTable
->deleteTable();
287 arrayConstructorTable
->deleteTable();
288 booleanPrototypeTable
->deleteTable();
289 dateTable
->deleteTable();
290 dateConstructorTable
->deleteTable();
291 errorPrototypeTable
->deleteTable();
292 globalObjectTable
->deleteTable();
293 jsonTable
->deleteTable();
294 mathTable
->deleteTable();
295 numberConstructorTable
->deleteTable();
296 numberPrototypeTable
->deleteTable();
297 objectConstructorTable
->deleteTable();
298 privateNamePrototypeTable
->deleteTable();
299 regExpTable
->deleteTable();
300 regExpConstructorTable
->deleteTable();
301 regExpPrototypeTable
->deleteTable();
302 stringConstructorTable
->deleteTable();
304 fastDelete(const_cast<HashTable
*>(arrayConstructorTable
));
305 fastDelete(const_cast<HashTable
*>(arrayPrototypeTable
));
306 fastDelete(const_cast<HashTable
*>(booleanPrototypeTable
));
307 fastDelete(const_cast<HashTable
*>(dateTable
));
308 fastDelete(const_cast<HashTable
*>(dateConstructorTable
));
309 fastDelete(const_cast<HashTable
*>(errorPrototypeTable
));
310 fastDelete(const_cast<HashTable
*>(globalObjectTable
));
311 fastDelete(const_cast<HashTable
*>(jsonTable
));
312 fastDelete(const_cast<HashTable
*>(mathTable
));
313 fastDelete(const_cast<HashTable
*>(numberConstructorTable
));
314 fastDelete(const_cast<HashTable
*>(numberPrototypeTable
));
315 fastDelete(const_cast<HashTable
*>(objectConstructorTable
));
316 fastDelete(const_cast<HashTable
*>(privateNamePrototypeTable
));
317 fastDelete(const_cast<HashTable
*>(regExpTable
));
318 fastDelete(const_cast<HashTable
*>(regExpConstructorTable
));
319 fastDelete(const_cast<HashTable
*>(regExpPrototypeTable
));
320 fastDelete(const_cast<HashTable
*>(stringConstructorTable
));
324 delete propertyNames
;
325 if (vmType
!= Default
)
326 deleteIdentifierTable(identifierTable
);
329 delete m_regExpCache
;
330 #if ENABLE(REGEXP_TRACING)
331 delete m_rtTraceList
;
335 for (unsigned i
= 0; i
< scratchBuffers
.size(); ++i
)
336 fastFree(scratchBuffers
[i
]);
340 PassRefPtr
<VM
> VM::createContextGroup(HeapType heapType
)
342 return adoptRef(new VM(APIContextGroup
, heapType
));
345 PassRefPtr
<VM
> VM::create(HeapType heapType
)
347 return adoptRef(new VM(Default
, heapType
));
350 PassRefPtr
<VM
> VM::createLeaked(HeapType heapType
)
352 return create(heapType
);
355 bool VM::sharedInstanceExists()
357 return sharedInstanceInternal();
360 VM
& VM::sharedInstance()
362 GlobalJSLock globalLock
;
363 VM
*& instance
= sharedInstanceInternal();
365 instance
= adoptRef(new VM(APIShared
, SmallHeap
)).leakRef();
366 instance
->makeUsableFromMultipleThreads();
371 VM
*& VM::sharedInstanceInternal()
373 static VM
* sharedInstance
;
374 return sharedInstance
;
378 static ThunkGenerator
thunkGeneratorForIntrinsic(Intrinsic intrinsic
)
381 case CharCodeAtIntrinsic
:
382 return charCodeAtThunkGenerator
;
383 case CharAtIntrinsic
:
384 return charAtThunkGenerator
;
385 case FromCharCodeIntrinsic
:
386 return fromCharCodeThunkGenerator
;
388 return sqrtThunkGenerator
;
390 return powThunkGenerator
;
392 return absThunkGenerator
;
394 return floorThunkGenerator
;
396 return ceilThunkGenerator
;
398 return roundThunkGenerator
;
400 return expThunkGenerator
;
402 return logThunkGenerator
;
404 return imulThunkGenerator
;
410 NativeExecutable
* VM::getHostFunction(NativeFunction function
, NativeFunction constructor
)
412 return jitStubs
->hostFunctionStub(this, function
, constructor
);
414 NativeExecutable
* VM::getHostFunction(NativeFunction function
, Intrinsic intrinsic
)
417 return jitStubs
->hostFunctionStub(this, function
, intrinsic
!= NoIntrinsic
? thunkGeneratorForIntrinsic(intrinsic
) : 0, intrinsic
);
420 #else // !ENABLE(JIT)
421 NativeExecutable
* VM::getHostFunction(NativeFunction function
, NativeFunction constructor
)
423 return NativeExecutable::create(*this, function
, constructor
);
425 #endif // !ENABLE(JIT)
427 VM::ClientData::~ClientData()
431 void VM::resetDateCache()
433 localTimeOffsetCache
.reset();
434 cachedDateString
= String();
435 cachedDateStringValue
= QNaN
;
436 dateInstanceCache
.reset();
439 void VM::startSampling()
441 interpreter
->startSampling();
444 void VM::stopSampling()
446 interpreter
->stopSampling();
449 void VM::discardAllCode()
451 m_codeCache
->clear();
452 heap
.deleteAllCompiledCode();
453 heap
.reportAbandonedObjectGraph();
456 void VM::dumpSampleData(ExecState
* exec
)
458 interpreter
->dumpSampleData(exec
);
459 #if ENABLE(ASSEMBLER)
460 ExecutableAllocator::dumpProfile();
464 SourceProviderCache
* VM::addSourceProviderCache(SourceProvider
* sourceProvider
)
466 SourceProviderCacheMap::AddResult addResult
= sourceProviderCacheMap
.add(sourceProvider
, 0);
467 if (addResult
.isNewEntry
)
468 addResult
.iterator
->value
= adoptRef(new SourceProviderCache
);
469 return addResult
.iterator
->value
.get();
472 void VM::clearSourceProviderCaches()
474 sourceProviderCacheMap
.clear();
477 struct StackPreservingRecompiler
: public MarkedBlock::VoidFunctor
{
478 HashSet
<FunctionExecutable
*> currentlyExecutingFunctions
;
479 void operator()(JSCell
* cell
)
481 if (!cell
->inherits(&FunctionExecutable::s_info
))
483 FunctionExecutable
* executable
= jsCast
<FunctionExecutable
*>(cell
);
484 if (currentlyExecutingFunctions
.contains(executable
))
486 executable
->clearCodeIfNotCompiling();
490 void VM::releaseExecutableMemory()
492 if (dynamicGlobalObject
) {
493 StackPreservingRecompiler recompiler
;
494 HashSet
<JSCell
*> roots
;
495 heap
.canonicalizeCellLivenessData();
496 heap
.getConservativeRegisterRoots(roots
);
497 HashSet
<JSCell
*>::iterator end
= roots
.end();
498 for (HashSet
<JSCell
*>::iterator ptr
= roots
.begin(); ptr
!= end
; ++ptr
) {
499 ScriptExecutable
* executable
= 0;
501 if (cell
->inherits(&ScriptExecutable::s_info
))
502 executable
= static_cast<ScriptExecutable
*>(*ptr
);
503 else if (cell
->inherits(&JSFunction::s_info
)) {
504 JSFunction
* function
= jsCast
<JSFunction
*>(*ptr
);
505 if (function
->isHostFunction())
507 executable
= function
->jsExecutable();
510 ASSERT(executable
->inherits(&ScriptExecutable::s_info
));
511 executable
->unlinkCalls();
512 if (executable
->inherits(&FunctionExecutable::s_info
))
513 recompiler
.currentlyExecutingFunctions
.add(static_cast<FunctionExecutable
*>(executable
));
516 heap
.objectSpace().forEachLiveCell
<StackPreservingRecompiler
>(recompiler
);
518 m_regExpCache
->invalidateCode();
519 heap
.collectAllGarbage();
522 void VM::clearExceptionStack()
524 m_exceptionStack
= RefCountedArray
<StackFrame
>();
527 #if ENABLE(ASSEMBLER)
528 void releaseExecutableMemory(VM
& vm
)
530 vm
.releaseExecutableMemory();
535 void VM::gatherConservativeRoots(ConservativeRoots
& conservativeRoots
)
537 for (size_t i
= 0; i
< scratchBuffers
.size(); i
++) {
538 ScratchBuffer
* scratchBuffer
= scratchBuffers
[i
];
539 if (scratchBuffer
->activeLength()) {
540 void* bufferStart
= scratchBuffer
->dataBuffer();
541 conservativeRoots
.add(bufferStart
, static_cast<void*>(static_cast<char*>(bufferStart
) + scratchBuffer
->activeLength()));
547 #if ENABLE(REGEXP_TRACING)
548 void VM::addRegExpToTrace(RegExp
* regExp
)
550 m_rtTraceList
->add(regExp
);
553 void VM::dumpRegExpTrace()
555 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
556 RTTraceList::iterator iter
= ++m_rtTraceList
->begin();
558 if (iter
!= m_rtTraceList
->end()) {
559 dataLogF("\nRegExp Tracing\n");
560 dataLogF(" match() matches\n");
561 dataLogF("Regular Expression JIT Address calls found\n");
562 dataLogF("----------------------------------------+----------------+----------+----------\n");
564 unsigned reCount
= 0;
566 for (; iter
!= m_rtTraceList
->end(); ++iter
, ++reCount
)
567 (*iter
)->printTraceData();
569 dataLogF("%d Regular Expressions\n", reCount
);
572 m_rtTraceList
->clear();
575 void VM::dumpRegExpTrace()