]>
Commit | Line | Data |
---|---|---|
9dae56ea | 1 | /* |
81345200 | 2 | * Copyright (C) 2008, 2011, 2013, 2014 Apple Inc. All rights reserved. |
9dae56ea A |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * | |
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. | |
81345200 | 13 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
9dae56ea A |
14 | * its contributors may be used to endorse or promote products derived |
15 | * from this software without specific prior written permission. | |
16 | * | |
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. | |
27 | */ | |
28 | ||
29 | #include "config.h" | |
93a37866 | 30 | #include "VM.h" |
9dae56ea A |
31 | |
32 | #include "ArgList.h" | |
81345200 A |
33 | #include "ArityCheckFailReturnThunks.h" |
34 | #include "ArrayBufferNeuteringWatchpoint.h" | |
35 | #include "BuiltinExecutables.h" | |
36 | #include "CodeBlock.h" | |
93a37866 | 37 | #include "CodeCache.h" |
9dae56ea | 38 | #include "CommonIdentifiers.h" |
81345200 A |
39 | #include "CommonSlowPaths.h" |
40 | #include "CustomGetterSetter.h" | |
93a37866 | 41 | #include "DFGLongLivedState.h" |
81345200 | 42 | #include "DFGWorklist.h" |
14957cd0 | 43 | #include "DebuggerActivation.h" |
81345200 A |
44 | #include "ErrorInstance.h" |
45 | #include "FTLThunks.h" | |
9dae56ea | 46 | #include "FunctionConstructor.h" |
6fe7ccc8 | 47 | #include "GCActivityCallback.h" |
f9bf01c6 | 48 | #include "GetterSetter.h" |
93a37866 | 49 | #include "Heap.h" |
81345200 | 50 | #include "HeapIterationScope.h" |
6fe7ccc8 | 51 | #include "HostCallReturnValue.h" |
81345200 | 52 | #include "Identifier.h" |
93a37866 | 53 | #include "IncrementalSweeper.h" |
9dae56ea | 54 | #include "Interpreter.h" |
81345200 | 55 | #include "JITCode.h" |
f9bf01c6 | 56 | #include "JSAPIValueWrapper.h" |
81345200 | 57 | #include "JSActivation.h" |
ba379fdc | 58 | #include "JSArray.h" |
81345200 | 59 | #include "JSCInlines.h" |
ba379fdc | 60 | #include "JSFunction.h" |
81345200 | 61 | #include "JSGlobalObjectFunctions.h" |
9dae56ea | 62 | #include "JSLock.h" |
93a37866 | 63 | #include "JSNameScope.h" |
9dae56ea | 64 | #include "JSNotAnObject.h" |
81345200 A |
65 | #include "JSPromiseDeferred.h" |
66 | #include "JSPromiseReaction.h" | |
f9bf01c6 | 67 | #include "JSPropertyNameIterator.h" |
93a37866 | 68 | #include "JSWithScope.h" |
9dae56ea A |
69 | #include "Lexer.h" |
70 | #include "Lookup.h" | |
81345200 | 71 | #include "MapData.h" |
9dae56ea | 72 | #include "Nodes.h" |
81345200 | 73 | #include "Parser.h" |
6fe7ccc8 | 74 | #include "ParserArena.h" |
81345200 A |
75 | #include "ProfilerDatabase.h" |
76 | #include "PropertyMapHashTable.h" | |
4e4e5a6f | 77 | #include "RegExpCache.h" |
14957cd0 | 78 | #include "RegExpObject.h" |
81345200 | 79 | #include "SimpleTypedArrayController.h" |
93a37866 | 80 | #include "SourceProviderCache.h" |
14957cd0 | 81 | #include "StrictEvalActivation.h" |
6fe7ccc8 | 82 | #include "StrongInlines.h" |
81345200 | 83 | #include "StructureInlines.h" |
93a37866 | 84 | #include "UnlinkedCodeBlock.h" |
81345200 | 85 | #include "WeakMapData.h" |
93a37866 A |
86 | #include <wtf/ProcessID.h> |
87 | #include <wtf/RetainPtr.h> | |
88 | #include <wtf/StringPrintStream.h> | |
6fe7ccc8 | 89 | #include <wtf/Threading.h> |
4e4e5a6f | 90 | #include <wtf/WTFThreadData.h> |
81345200 | 91 | #include <wtf/text/AtomicStringTable.h> |
14957cd0 | 92 | |
6fe7ccc8 A |
93 | #if ENABLE(DFG_JIT) |
94 | #include "ConservativeRoots.h" | |
95 | #endif | |
9dae56ea | 96 | |
6fe7ccc8 A |
97 | #if ENABLE(REGEXP_TRACING) |
98 | #include "RegExp.h" | |
9dae56ea A |
99 | #endif |
100 | ||
6fe7ccc8 | 101 | #if USE(CF) |
4e4e5a6f | 102 | #include <CoreFoundation/CoreFoundation.h> |
9dae56ea A |
103 | #endif |
104 | ||
105 | using namespace WTF; | |
106 | ||
6fe7ccc8 | 107 | namespace JSC { |
14957cd0 | 108 | |
6fe7ccc8 A |
109 | extern const HashTable arrayConstructorTable; |
110 | extern const HashTable arrayPrototypeTable; | |
111 | extern const HashTable booleanPrototypeTable; | |
112 | extern const HashTable jsonTable; | |
81345200 | 113 | extern const HashTable dataViewTable; |
6fe7ccc8 A |
114 | extern const HashTable dateTable; |
115 | extern const HashTable dateConstructorTable; | |
116 | extern const HashTable errorPrototypeTable; | |
117 | extern const HashTable globalObjectTable; | |
6fe7ccc8 A |
118 | extern const HashTable numberConstructorTable; |
119 | extern const HashTable numberPrototypeTable; | |
120 | JS_EXPORTDATA extern const HashTable objectConstructorTable; | |
93a37866 | 121 | extern const HashTable privateNamePrototypeTable; |
6fe7ccc8 A |
122 | extern const HashTable regExpTable; |
123 | extern const HashTable regExpConstructorTable; | |
124 | extern const HashTable regExpPrototypeTable; | |
6fe7ccc8 | 125 | extern const HashTable stringConstructorTable; |
81345200 A |
126 | #if ENABLE(PROMISES) |
127 | extern const HashTable promisePrototypeTable; | |
128 | extern const HashTable promiseConstructorTable; | |
129 | #endif | |
6fe7ccc8 | 130 | |
93a37866 A |
131 | // Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either |
132 | // ENABLE(JIT) or ENABLE(YARR_JIT) or both are enabled. The code below | |
133 | // just checks for ENABLE(JIT) or ENABLE(YARR_JIT) with this premise in mind. | |
134 | ||
135 | #if ENABLE(ASSEMBLER) | |
6fe7ccc8 | 136 | static bool enableAssembler(ExecutableAllocator& executableAllocator) |
14957cd0 | 137 | { |
93a37866 A |
138 | if (!Options::useJIT() && !Options::useRegExpJIT()) |
139 | return false; | |
140 | ||
141 | if (!executableAllocator.isValid()) { | |
142 | if (Options::crashIfCantAllocateJITMemory()) | |
143 | CRASH(); | |
6fe7ccc8 | 144 | return false; |
6fe7ccc8 | 145 | } |
93a37866 A |
146 | |
147 | #if USE(CF) | |
93a37866 | 148 | CFStringRef canUseJITKey = CFSTR("JavaScriptCoreUseJIT"); |
93a37866 A |
149 | RetainPtr<CFTypeRef> canUseJIT = adoptCF(CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication)); |
150 | if (canUseJIT) | |
151 | return kCFBooleanTrue == canUseJIT.get(); | |
6fe7ccc8 | 152 | #endif |
9dae56ea | 153 | |
6fe7ccc8 A |
154 | #if USE(CF) || OS(UNIX) |
155 | char* canUseJITString = getenv("JavaScriptCoreUseJIT"); | |
156 | return !canUseJITString || atoi(canUseJITString); | |
14957cd0 | 157 | #else |
6fe7ccc8 | 158 | return true; |
14957cd0 | 159 | #endif |
ba379fdc | 160 | } |
93a37866 | 161 | #endif // ENABLE(!ASSEMBLER) |
ba379fdc | 162 | |
93a37866 A |
163 | VM::VM(VMType vmType, HeapType heapType) |
164 | : m_apiLock(adoptRef(new JSLock(this))) | |
165 | #if ENABLE(ASSEMBLER) | |
166 | , executableAllocator(*this) | |
167 | #endif | |
168 | , heap(this, heapType) | |
169 | , vmType(vmType) | |
ba379fdc | 170 | , clientData(0) |
6fe7ccc8 | 171 | , topCallFrame(CallFrame::noCaller()) |
81345200 A |
172 | , arrayConstructorTable(adoptPtr(new HashTable(JSC::arrayConstructorTable))) |
173 | , arrayPrototypeTable(adoptPtr(new HashTable(JSC::arrayPrototypeTable))) | |
174 | , booleanPrototypeTable(adoptPtr(new HashTable(JSC::booleanPrototypeTable))) | |
175 | , dataViewTable(adoptPtr(new HashTable(JSC::dataViewTable))) | |
176 | , dateTable(adoptPtr(new HashTable(JSC::dateTable))) | |
177 | , dateConstructorTable(adoptPtr(new HashTable(JSC::dateConstructorTable))) | |
178 | , errorPrototypeTable(adoptPtr(new HashTable(JSC::errorPrototypeTable))) | |
179 | , globalObjectTable(adoptPtr(new HashTable(JSC::globalObjectTable))) | |
180 | , jsonTable(adoptPtr(new HashTable(JSC::jsonTable))) | |
181 | , numberConstructorTable(adoptPtr(new HashTable(JSC::numberConstructorTable))) | |
182 | , numberPrototypeTable(adoptPtr(new HashTable(JSC::numberPrototypeTable))) | |
183 | , objectConstructorTable(adoptPtr(new HashTable(JSC::objectConstructorTable))) | |
184 | , privateNamePrototypeTable(adoptPtr(new HashTable(JSC::privateNamePrototypeTable))) | |
185 | , regExpTable(adoptPtr(new HashTable(JSC::regExpTable))) | |
186 | , regExpConstructorTable(adoptPtr(new HashTable(JSC::regExpConstructorTable))) | |
187 | , regExpPrototypeTable(adoptPtr(new HashTable(JSC::regExpPrototypeTable))) | |
188 | , stringConstructorTable(adoptPtr(new HashTable(JSC::stringConstructorTable))) | |
189 | #if ENABLE(PROMISES) | |
190 | , promisePrototypeTable(adoptPtr(new HashTable(JSC::promisePrototypeTable))) | |
191 | , promiseConstructorTable(adoptPtr(new HashTable(JSC::promiseConstructorTable))) | |
192 | #endif | |
193 | , m_atomicStringTable(vmType == Default ? wtfThreadData().atomicStringTable() : new AtomicStringTable) | |
194 | , propertyNames(nullptr) | |
ba379fdc | 195 | , emptyList(new MarkedArgumentBuffer) |
6fe7ccc8 | 196 | , parserArena(adoptPtr(new ParserArena)) |
81345200 | 197 | , keywords(adoptPtr(new Keywords(*this))) |
14957cd0 | 198 | , interpreter(0) |
81345200 A |
199 | , jsArrayClassInfo(JSArray::info()) |
200 | , jsFinalObjectClassInfo(JSFinalObject::info()) | |
40a37d08 | 201 | , varargsLength(0) |
6fe7ccc8 | 202 | , sizeOfLastScratchBuffer(0) |
81345200 | 203 | , entryScope(0) |
4e4e5a6f | 204 | , m_regExpCache(new RegExpCache(this)) |
14957cd0 A |
205 | #if ENABLE(REGEXP_TRACING) |
206 | , m_rtTraceList(new RTTraceList()) | |
f9bf01c6 | 207 | #endif |
93a37866 A |
208 | , m_newStringsSinceLastHashCons(0) |
209 | #if ENABLE(ASSEMBLER) | |
6fe7ccc8 A |
210 | , m_canUseAssembler(enableAssembler(executableAllocator)) |
211 | #endif | |
93a37866 A |
212 | #if ENABLE(JIT) |
213 | , m_canUseJIT(m_canUseAssembler && Options::useJIT()) | |
214 | #endif | |
215 | #if ENABLE(YARR_JIT) | |
216 | , m_canUseRegExpJIT(m_canUseAssembler && Options::useRegExpJIT()) | |
217 | #endif | |
6fe7ccc8 A |
218 | #if ENABLE(GC_VALIDATION) |
219 | , m_initializingObjectClass(0) | |
81345200 A |
220 | #endif |
221 | , m_stackPointerAtVMEntry(0) | |
222 | , m_stackLimit(0) | |
223 | #if !ENABLE(JIT) | |
224 | , m_jsStackLimit(0) | |
225 | #endif | |
226 | #if ENABLE(FTL_JIT) | |
227 | , m_ftlStackLimit(0) | |
228 | , m_largestFTLStackSize(0) | |
6fe7ccc8 A |
229 | #endif |
230 | , m_inDefineOwnProperty(false) | |
81345200 A |
231 | , m_codeCache(CodeCache::create()) |
232 | , m_enabledProfiler(nullptr) | |
233 | , m_builtinExecutables(BuiltinExecutables::create(*this)) | |
9dae56ea | 234 | { |
93a37866 | 235 | interpreter = new Interpreter(*this); |
81345200 A |
236 | StackBounds stack = wtfThreadData().stack(); |
237 | updateReservedZoneSize(Options::reservedZoneSize()); | |
238 | #if !ENABLE(JIT) | |
239 | interpreter->stack().setReservedZoneSize(Options::reservedZoneSize()); | |
240 | #endif | |
241 | setLastStackTop(stack.origin()); | |
14957cd0 A |
242 | |
243 | // Need to be careful to keep everything consistent here | |
6fe7ccc8 | 244 | JSLockHolder lock(this); |
81345200 A |
245 | AtomicStringTable* existingEntryAtomicStringTable = wtfThreadData().setCurrentAtomicStringTable(m_atomicStringTable); |
246 | propertyNames = new CommonIdentifiers(this); | |
14957cd0 | 247 | structureStructure.set(*this, Structure::createStructure(*this)); |
93a37866 | 248 | structureRareDataStructure.set(*this, StructureRareData::createStructure(*this, 0, jsNull())); |
6fe7ccc8 | 249 | debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull())); |
6fe7ccc8 | 250 | terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull())); |
6fe7ccc8 A |
251 | stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull())); |
252 | notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull())); | |
253 | propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull())); | |
254 | getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull())); | |
81345200 | 255 | customGetterSetterStructure.set(*this, CustomGetterSetter::createStructure(*this, 0, jsNull())); |
6fe7ccc8 | 256 | apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull())); |
93a37866 | 257 | JSScopeStructure.set(*this, JSScope::createStructure(*this, 0, jsNull())); |
6fe7ccc8 A |
258 | executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull())); |
259 | nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, 0, jsNull())); | |
260 | evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, 0, jsNull())); | |
261 | programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull())); | |
262 | functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull())); | |
263 | regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull())); | |
81345200 | 264 | symbolTableStructure.set(*this, SymbolTable::createStructure(*this, 0, jsNull())); |
6fe7ccc8 | 265 | structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull())); |
93a37866 | 266 | sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull())); |
81345200 | 267 | arrayBufferNeuteringWatchpointStructure.set(*this, ArrayBufferNeuteringWatchpoint::createStructure(*this)); |
93a37866 A |
268 | withScopeStructure.set(*this, JSWithScope::createStructure(*this, 0, jsNull())); |
269 | unlinkedFunctionExecutableStructure.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull())); | |
270 | unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull())); | |
271 | unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull())); | |
272 | unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull())); | |
273 | propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull())); | |
81345200 A |
274 | mapDataStructure.set(*this, MapData::createStructure(*this, 0, jsNull())); |
275 | weakMapDataStructure.set(*this, WeakMapData::createStructure(*this, 0, jsNull())); | |
276 | #if ENABLE(PROMISES) | |
277 | promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull())); | |
278 | promiseReactionStructure.set(*this, JSPromiseReaction::createStructure(*this, 0, jsNull())); | |
279 | #endif | |
280 | iterationTerminator.set(*this, JSFinalObject::create(*this, JSFinalObject::createStructure(*this, 0, jsNull(), 1))); | |
93a37866 | 281 | smallStrings.initializeCommonStrings(*this); |
14957cd0 | 282 | |
81345200 | 283 | wtfThreadData().setCurrentAtomicStringTable(existingEntryAtomicStringTable); |
14957cd0 | 284 | |
4e4e5a6f | 285 | #if ENABLE(JIT) |
93a37866 | 286 | jitStubs = adoptPtr(new JITThunks()); |
81345200 | 287 | arityCheckFailReturnThunks = std::make_unique<ArityCheckFailReturnThunks>(); |
14957cd0 | 288 | #endif |
81345200 A |
289 | arityCheckData = std::make_unique<CommonSlowPaths::ArityCheckData>(); |
290 | ||
291 | #if ENABLE(FTL_JIT) | |
292 | ftlThunks = std::make_unique<FTL::Thunks>(); | |
293 | #endif // ENABLE(FTL_JIT) | |
6fe7ccc8 | 294 | |
93a37866 | 295 | interpreter->initialize(this->canUseJIT()); |
6fe7ccc8 | 296 | |
93a37866 | 297 | #if ENABLE(JIT) |
6fe7ccc8 | 298 | initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support. |
93a37866 | 299 | #endif |
14957cd0 | 300 | |
6fe7ccc8 | 301 | heap.notifyIsSafeToCollect(); |
81345200 | 302 | |
93a37866 | 303 | LLInt::Data::performAssertions(*this); |
6fe7ccc8 | 304 | |
93a37866 A |
305 | if (Options::enableProfiler()) { |
306 | m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*this)); | |
307 | ||
308 | StringPrintStream pathOut; | |
309 | #if !OS(WINCE) | |
310 | const char* profilerPath = getenv("JSC_PROFILER_PATH"); | |
311 | if (profilerPath) | |
312 | pathOut.print(profilerPath, "/"); | |
313 | #endif | |
314 | pathOut.print("JSCProfile-", getCurrentProcessID(), "-", m_perBytecodeProfiler->databaseID(), ".json"); | |
315 | m_perBytecodeProfiler->registerToSaveAtExit(pathOut.toCString().data()); | |
316 | } | |
317 | ||
318 | #if ENABLE(DFG_JIT) | |
319 | if (canUseJIT()) | |
81345200 | 320 | dfgState = adoptPtr(new DFG::LongLivedState()); |
93a37866 | 321 | #endif |
81345200 A |
322 | |
323 | // Initialize this last, as a free way of asserting that VM initialization itself | |
324 | // won't use this. | |
325 | m_typedArrayController = adoptRef(new SimpleTypedArrayController()); | |
9dae56ea A |
326 | } |
327 | ||
93a37866 | 328 | VM::~VM() |
9dae56ea | 329 | { |
81345200 A |
330 | // Never GC, ever again. |
331 | heap.incrementDeferralDepth(); | |
332 | ||
333 | #if ENABLE(DFG_JIT) | |
334 | // Make sure concurrent compilations are done, but don't install them, since there is | |
335 | // no point to doing so. | |
336 | for (unsigned i = DFG::numberOfWorklists(); i--;) { | |
337 | if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) { | |
338 | worklist->waitUntilAllPlansForVMAreReady(*this); | |
339 | worklist->removeAllReadyPlansForVM(*this); | |
340 | } | |
341 | } | |
342 | #endif // ENABLE(DFG_JIT) | |
343 | ||
93a37866 A |
344 | // Clear this first to ensure that nobody tries to remove themselves from it. |
345 | m_perBytecodeProfiler.clear(); | |
346 | ||
347 | ASSERT(m_apiLock->currentThreadIsHoldingLock()); | |
348 | m_apiLock->willDestroyVM(this); | |
6fe7ccc8 | 349 | heap.lastChanceToFinalize(); |
9dae56ea A |
350 | |
351 | delete interpreter; | |
352 | #ifndef NDEBUG | |
6fe7ccc8 | 353 | interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef); |
9dae56ea A |
354 | #endif |
355 | ||
14957cd0 A |
356 | arrayPrototypeTable->deleteTable(); |
357 | arrayConstructorTable->deleteTable(); | |
358 | booleanPrototypeTable->deleteTable(); | |
81345200 | 359 | dataViewTable->deleteTable(); |
9dae56ea | 360 | dateTable->deleteTable(); |
14957cd0 A |
361 | dateConstructorTable->deleteTable(); |
362 | errorPrototypeTable->deleteTable(); | |
363 | globalObjectTable->deleteTable(); | |
ba379fdc | 364 | jsonTable->deleteTable(); |
14957cd0 A |
365 | numberConstructorTable->deleteTable(); |
366 | numberPrototypeTable->deleteTable(); | |
367 | objectConstructorTable->deleteTable(); | |
93a37866 | 368 | privateNamePrototypeTable->deleteTable(); |
9dae56ea A |
369 | regExpTable->deleteTable(); |
370 | regExpConstructorTable->deleteTable(); | |
14957cd0 | 371 | regExpPrototypeTable->deleteTable(); |
14957cd0 | 372 | stringConstructorTable->deleteTable(); |
81345200 A |
373 | #if ENABLE(PROMISES) |
374 | promisePrototypeTable->deleteTable(); | |
375 | promiseConstructorTable->deleteTable(); | |
376 | #endif | |
9dae56ea | 377 | |
9dae56ea A |
378 | delete emptyList; |
379 | ||
380 | delete propertyNames; | |
93a37866 | 381 | if (vmType != Default) |
81345200 | 382 | delete m_atomicStringTable; |
9dae56ea | 383 | |
9dae56ea | 384 | delete clientData; |
4e4e5a6f | 385 | delete m_regExpCache; |
14957cd0 A |
386 | #if ENABLE(REGEXP_TRACING) |
387 | delete m_rtTraceList; | |
388 | #endif | |
6fe7ccc8 A |
389 | |
390 | #if ENABLE(DFG_JIT) | |
391 | for (unsigned i = 0; i < scratchBuffers.size(); ++i) | |
392 | fastFree(scratchBuffers[i]); | |
393 | #endif | |
9dae56ea A |
394 | } |
395 | ||
93a37866 | 396 | PassRefPtr<VM> VM::createContextGroup(HeapType heapType) |
9dae56ea | 397 | { |
93a37866 | 398 | return adoptRef(new VM(APIContextGroup, heapType)); |
f9bf01c6 A |
399 | } |
400 | ||
93a37866 | 401 | PassRefPtr<VM> VM::create(HeapType heapType) |
f9bf01c6 | 402 | { |
93a37866 | 403 | return adoptRef(new VM(Default, heapType)); |
9dae56ea A |
404 | } |
405 | ||
93a37866 | 406 | PassRefPtr<VM> VM::createLeaked(HeapType heapType) |
9dae56ea | 407 | { |
93a37866 | 408 | return create(heapType); |
9dae56ea A |
409 | } |
410 | ||
93a37866 | 411 | bool VM::sharedInstanceExists() |
9dae56ea A |
412 | { |
413 | return sharedInstanceInternal(); | |
414 | } | |
415 | ||
93a37866 | 416 | VM& VM::sharedInstance() |
9dae56ea | 417 | { |
6fe7ccc8 | 418 | GlobalJSLock globalLock; |
93a37866 | 419 | VM*& instance = sharedInstanceInternal(); |
9dae56ea | 420 | if (!instance) { |
93a37866 | 421 | instance = adoptRef(new VM(APIShared, SmallHeap)).leakRef(); |
9dae56ea | 422 | instance->makeUsableFromMultipleThreads(); |
9dae56ea A |
423 | } |
424 | return *instance; | |
425 | } | |
426 | ||
93a37866 | 427 | VM*& VM::sharedInstanceInternal() |
9dae56ea | 428 | { |
93a37866 | 429 | static VM* sharedInstance; |
9dae56ea A |
430 | return sharedInstance; |
431 | } | |
432 | ||
14957cd0 | 433 | #if ENABLE(JIT) |
6fe7ccc8 | 434 | static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) |
9dae56ea | 435 | { |
6fe7ccc8 A |
436 | switch (intrinsic) { |
437 | case CharCodeAtIntrinsic: | |
438 | return charCodeAtThunkGenerator; | |
439 | case CharAtIntrinsic: | |
440 | return charAtThunkGenerator; | |
441 | case FromCharCodeIntrinsic: | |
442 | return fromCharCodeThunkGenerator; | |
443 | case SqrtIntrinsic: | |
444 | return sqrtThunkGenerator; | |
445 | case PowIntrinsic: | |
446 | return powThunkGenerator; | |
447 | case AbsIntrinsic: | |
448 | return absThunkGenerator; | |
449 | case FloorIntrinsic: | |
450 | return floorThunkGenerator; | |
451 | case CeilIntrinsic: | |
452 | return ceilThunkGenerator; | |
453 | case RoundIntrinsic: | |
454 | return roundThunkGenerator; | |
455 | case ExpIntrinsic: | |
456 | return expThunkGenerator; | |
457 | case LogIntrinsic: | |
458 | return logThunkGenerator; | |
93a37866 A |
459 | case IMulIntrinsic: |
460 | return imulThunkGenerator; | |
81345200 A |
461 | case ArrayIteratorNextKeyIntrinsic: |
462 | return arrayIteratorNextKeyThunkGenerator; | |
463 | case ArrayIteratorNextValueIntrinsic: | |
464 | return arrayIteratorNextValueThunkGenerator; | |
6fe7ccc8 A |
465 | default: |
466 | return 0; | |
467 | } | |
468 | } | |
469 | ||
93a37866 | 470 | NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor) |
6fe7ccc8 | 471 | { |
6fe7ccc8 | 472 | return jitStubs->hostFunctionStub(this, function, constructor); |
14957cd0 | 473 | } |
93a37866 | 474 | NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic) |
14957cd0 | 475 | { |
6fe7ccc8 A |
476 | ASSERT(canUseJIT()); |
477 | return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic); | |
9dae56ea | 478 | } |
93a37866 A |
479 | |
480 | #else // !ENABLE(JIT) | |
81345200 | 481 | |
93a37866 | 482 | NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor) |
14957cd0 | 483 | { |
81345200 A |
484 | return NativeExecutable::create(*this, |
485 | adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_call_trampoline), JITCode::HostCallThunk)), function, | |
486 | adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_construct_trampoline), JITCode::HostCallThunk)), constructor, | |
487 | NoIntrinsic); | |
14957cd0 | 488 | } |
81345200 | 489 | |
93a37866 | 490 | #endif // !ENABLE(JIT) |
9dae56ea | 491 | |
93a37866 | 492 | VM::ClientData::~ClientData() |
9dae56ea A |
493 | { |
494 | } | |
495 | ||
93a37866 | 496 | void VM::resetDateCache() |
f9bf01c6 | 497 | { |
93a37866 A |
498 | localTimeOffsetCache.reset(); |
499 | cachedDateString = String(); | |
81345200 | 500 | cachedDateStringValue = std::numeric_limits<double>::quiet_NaN(); |
f9bf01c6 A |
501 | dateInstanceCache.reset(); |
502 | } | |
503 | ||
93a37866 | 504 | void VM::startSampling() |
f9bf01c6 A |
505 | { |
506 | interpreter->startSampling(); | |
507 | } | |
508 | ||
93a37866 | 509 | void VM::stopSampling() |
f9bf01c6 A |
510 | { |
511 | interpreter->stopSampling(); | |
512 | } | |
513 | ||
81345200 A |
514 | void VM::waitForCompilationsToComplete() |
515 | { | |
516 | #if ENABLE(DFG_JIT) | |
517 | for (unsigned i = DFG::numberOfWorklists(); i--;) { | |
518 | if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) | |
519 | worklist->completeAllPlansForVM(*this); | |
520 | } | |
521 | #endif // ENABLE(DFG_JIT) | |
522 | } | |
523 | ||
93a37866 A |
524 | void VM::discardAllCode() |
525 | { | |
81345200 | 526 | waitForCompilationsToComplete(); |
93a37866 | 527 | m_codeCache->clear(); |
81345200 | 528 | m_regExpCache->invalidateCode(); |
93a37866 | 529 | heap.deleteAllCompiledCode(); |
81345200 | 530 | heap.deleteAllUnlinkedFunctionCode(); |
93a37866 A |
531 | heap.reportAbandonedObjectGraph(); |
532 | } | |
533 | ||
534 | void VM::dumpSampleData(ExecState* exec) | |
f9bf01c6 A |
535 | { |
536 | interpreter->dumpSampleData(exec); | |
6fe7ccc8 A |
537 | #if ENABLE(ASSEMBLER) |
538 | ExecutableAllocator::dumpProfile(); | |
539 | #endif | |
f9bf01c6 A |
540 | } |
541 | ||
93a37866 A |
542 | SourceProviderCache* VM::addSourceProviderCache(SourceProvider* sourceProvider) |
543 | { | |
81345200 | 544 | auto addResult = sourceProviderCacheMap.add(sourceProvider, nullptr); |
93a37866 A |
545 | if (addResult.isNewEntry) |
546 | addResult.iterator->value = adoptRef(new SourceProviderCache); | |
547 | return addResult.iterator->value.get(); | |
548 | } | |
549 | ||
550 | void VM::clearSourceProviderCaches() | |
551 | { | |
552 | sourceProviderCacheMap.clear(); | |
553 | } | |
554 | ||
6fe7ccc8 | 555 | struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor { |
14957cd0 A |
556 | HashSet<FunctionExecutable*> currentlyExecutingFunctions; |
557 | void operator()(JSCell* cell) | |
558 | { | |
81345200 | 559 | if (!cell->inherits(FunctionExecutable::info())) |
14957cd0 | 560 | return; |
6fe7ccc8 | 561 | FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); |
14957cd0 A |
562 | if (currentlyExecutingFunctions.contains(executable)) |
563 | return; | |
93a37866 | 564 | executable->clearCodeIfNotCompiling(); |
14957cd0 A |
565 | } |
566 | }; | |
b80e6193 | 567 | |
93a37866 | 568 | void VM::releaseExecutableMemory() |
14957cd0 | 569 | { |
81345200 A |
570 | waitForCompilationsToComplete(); |
571 | ||
572 | if (entryScope) { | |
14957cd0 | 573 | StackPreservingRecompiler recompiler; |
81345200 | 574 | HeapIterationScope iterationScope(heap); |
14957cd0 A |
575 | HashSet<JSCell*> roots; |
576 | heap.getConservativeRegisterRoots(roots); | |
577 | HashSet<JSCell*>::iterator end = roots.end(); | |
578 | for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) { | |
579 | ScriptExecutable* executable = 0; | |
580 | JSCell* cell = *ptr; | |
81345200 | 581 | if (cell->inherits(ScriptExecutable::info())) |
14957cd0 | 582 | executable = static_cast<ScriptExecutable*>(*ptr); |
81345200 | 583 | else if (cell->inherits(JSFunction::info())) { |
6fe7ccc8 | 584 | JSFunction* function = jsCast<JSFunction*>(*ptr); |
14957cd0 A |
585 | if (function->isHostFunction()) |
586 | continue; | |
587 | executable = function->jsExecutable(); | |
588 | } else | |
589 | continue; | |
81345200 | 590 | ASSERT(executable->inherits(ScriptExecutable::info())); |
14957cd0 | 591 | executable->unlinkCalls(); |
81345200 | 592 | if (executable->inherits(FunctionExecutable::info())) |
14957cd0 A |
593 | recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable)); |
594 | ||
b80e6193 | 595 | } |
81345200 | 596 | heap.objectSpace().forEachLiveCell<StackPreservingRecompiler>(iterationScope, recompiler); |
6fe7ccc8 | 597 | } |
14957cd0 A |
598 | m_regExpCache->invalidateCode(); |
599 | heap.collectAllGarbage(); | |
600 | } | |
601 | ||
81345200 | 602 | static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset) |
93a37866 | 603 | { |
81345200 A |
604 | exception->clearAppendSourceToMessage(); |
605 | ||
606 | if (!callFrame->codeBlock()->hasExpressionInfo()) | |
607 | return; | |
608 | ||
609 | int startOffset = 0; | |
610 | int endOffset = 0; | |
611 | int divotPoint = 0; | |
612 | unsigned line = 0; | |
613 | unsigned column = 0; | |
614 | ||
615 | CodeBlock* codeBlock = callFrame->codeBlock(); | |
616 | codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column); | |
617 | ||
618 | int expressionStart = divotPoint - startOffset; | |
619 | int expressionStop = divotPoint + endOffset; | |
620 | ||
621 | const String& sourceString = codeBlock->source()->source(); | |
622 | if (!expressionStop || expressionStart > static_cast<int>(sourceString.length())) | |
623 | return; | |
624 | ||
625 | VM* vm = &callFrame->vm(); | |
626 | JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message); | |
627 | if (!jsMessage || !jsMessage.isString()) | |
628 | return; | |
629 | ||
630 | String message = asString(jsMessage)->value(callFrame); | |
631 | ||
632 | if (expressionStart < expressionStop) | |
633 | message = makeString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')"); | |
634 | else { | |
635 | // No range information, so give a few characters of context. | |
636 | const StringImpl* data = sourceString.impl(); | |
637 | int dataLength = sourceString.length(); | |
638 | int start = expressionStart; | |
639 | int stop = expressionStart; | |
640 | // Get up to 20 characters of context to the left and right of the divot, clamping to the line. | |
641 | // Then strip whitespace. | |
642 | while (start > 0 && (expressionStart - start < 20) && (*data)[start - 1] != '\n') | |
643 | start--; | |
644 | while (start < (expressionStart - 1) && isStrWhiteSpace((*data)[start])) | |
645 | start++; | |
646 | while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n') | |
647 | stop++; | |
648 | while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1])) | |
649 | stop--; | |
650 | message = makeString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')"); | |
651 | } | |
652 | ||
653 | exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message)); | |
93a37866 A |
654 | } |
655 | ||
81345200 A |
656 | JSValue VM::throwException(ExecState* exec, JSValue error) |
657 | { | |
658 | if (Options::breakOnThrow()) { | |
659 | dataLog("In call frame ", RawPointer(exec), " for code block ", *exec->codeBlock(), "\n"); | |
660 | CRASH(); | |
661 | } | |
662 | ||
663 | ASSERT(exec == topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec()); | |
664 | ||
665 | Vector<StackFrame> stackTrace; | |
666 | interpreter->getStackTrace(stackTrace); | |
667 | m_exceptionStack = RefCountedArray<StackFrame>(stackTrace); | |
668 | m_exception = error; | |
669 | ||
670 | if (stackTrace.isEmpty() || !error.isObject()) | |
671 | return error; | |
672 | JSObject* exception = asObject(error); | |
673 | ||
674 | StackFrame stackFrame; | |
675 | for (unsigned i = 0 ; i < stackTrace.size(); ++i) { | |
676 | stackFrame = stackTrace.at(i); | |
677 | if (stackFrame.bytecodeOffset) | |
678 | break; | |
679 | } | |
680 | unsigned bytecodeOffset = stackFrame.bytecodeOffset; | |
681 | if (!hasErrorInfo(exec, exception)) { | |
682 | // FIXME: We should only really be adding these properties to VM generated exceptions, | |
683 | // but the inspector currently requires these for all thrown objects. | |
684 | unsigned line; | |
685 | unsigned column; | |
686 | stackFrame.computeLineAndColumn(line, column); | |
687 | exception->putDirect(*this, Identifier(this, "line"), jsNumber(line), ReadOnly | DontDelete); | |
688 | exception->putDirect(*this, Identifier(this, "column"), jsNumber(column), ReadOnly | DontDelete); | |
689 | if (!stackFrame.sourceURL.isEmpty()) | |
690 | exception->putDirect(*this, Identifier(this, "sourceURL"), jsString(this, stackFrame.sourceURL), ReadOnly | DontDelete); | |
691 | } | |
692 | if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage()) { | |
693 | unsigned stackIndex = 0; | |
694 | CallFrame* callFrame; | |
695 | for (callFrame = exec; callFrame && !callFrame->codeBlock(); ) { | |
696 | stackIndex++; | |
697 | callFrame = callFrame->callerFrameSkippingVMEntrySentinel(); | |
698 | } | |
699 | if (callFrame && callFrame->codeBlock()) { | |
700 | stackFrame = stackTrace.at(stackIndex); | |
701 | bytecodeOffset = stackFrame.bytecodeOffset; | |
702 | appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset); | |
703 | } | |
704 | } | |
705 | ||
706 | if (exception->hasProperty(exec, this->propertyNames->stack)) | |
707 | return error; | |
708 | ||
709 | exception->putDirect(*this, propertyNames->stack, interpreter->stackTraceAsString(topCallFrame, stackTrace), DontEnum); | |
710 | return error; | |
711 | } | |
712 | ||
713 | JSObject* VM::throwException(ExecState* exec, JSObject* error) | |
714 | { | |
715 | return asObject(throwException(exec, JSValue(error))); | |
716 | } | |
717 | void VM::getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack) | |
718 | { | |
719 | exception = m_exception; | |
720 | exceptionStack = m_exceptionStack; | |
721 | } | |
722 | void VM::setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack) | |
723 | { | |
724 | m_exception = exception; | |
725 | m_exceptionStack = exceptionStack; | |
726 | } | |
727 | ||
728 | void VM::clearException() | |
729 | { | |
730 | m_exception = JSValue(); | |
731 | } | |
732 | void VM:: clearExceptionStack() | |
733 | { | |
734 | m_exceptionStack = RefCountedArray<StackFrame>(); | |
735 | } | |
736 | ||
737 | void VM::setStackPointerAtVMEntry(void* sp) | |
738 | { | |
739 | m_stackPointerAtVMEntry = sp; | |
740 | updateStackLimit(); | |
741 | } | |
742 | ||
743 | size_t VM::updateReservedZoneSize(size_t reservedZoneSize) | |
744 | { | |
745 | size_t oldReservedZoneSize = m_reservedZoneSize; | |
746 | m_reservedZoneSize = reservedZoneSize; | |
747 | ||
748 | updateStackLimit(); | |
749 | ||
750 | return oldReservedZoneSize; | |
751 | } | |
752 | ||
753 | #if PLATFORM(WIN) | |
754 | // On Windows the reserved stack space consists of committed memory, a guard page, and uncommitted memory, | |
755 | // where the guard page is a barrier between committed and uncommitted memory. | |
756 | // When data from the guard page is read or written, the guard page is moved, and memory is committed. | |
757 | // This is how the system grows the stack. | |
758 | // When using the C stack on Windows we need to precommit the needed stack space. | |
759 | // Otherwise we might crash later if we access uncommitted stack memory. | |
760 | // This can happen if we allocate stack space larger than the page guard size (4K). | |
761 | // The system does not get the chance to move the guard page, and commit more memory, | |
762 | // and we crash if uncommitted memory is accessed. | |
763 | // The MSVC compiler fixes this by inserting a call to the _chkstk() function, | |
764 | // when needed, see http://support.microsoft.com/kb/100775. | |
765 | // By touching every page up to the stack limit with a dummy operation, | |
766 | // we force the system to move the guard page, and commit memory. | |
767 | ||
768 | static void preCommitStackMemory(void* stackLimit) | |
769 | { | |
770 | const int pageSize = 4096; | |
771 | for (volatile char* p = reinterpret_cast<char*>(&stackLimit); p > stackLimit; p -= pageSize) { | |
772 | char ch = *p; | |
773 | *p = ch; | |
774 | } | |
775 | } | |
776 | #endif | |
777 | ||
778 | inline void VM::updateStackLimit() | |
779 | { | |
780 | #if PLATFORM(WIN) | |
781 | void* lastStackLimit = m_stackLimit; | |
782 | #endif | |
783 | ||
784 | if (m_stackPointerAtVMEntry) { | |
785 | ASSERT(wtfThreadData().stack().isGrowingDownward()); | |
786 | char* startOfStack = reinterpret_cast<char*>(m_stackPointerAtVMEntry); | |
787 | #if ENABLE(FTL_JIT) | |
788 | m_stackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize + m_largestFTLStackSize); | |
789 | m_ftlStackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize + 2 * m_largestFTLStackSize); | |
790 | #else | |
791 | m_stackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize); | |
792 | #endif | |
793 | } else { | |
794 | #if ENABLE(FTL_JIT) | |
795 | m_stackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize + m_largestFTLStackSize); | |
796 | m_ftlStackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize + 2 * m_largestFTLStackSize); | |
797 | #else | |
798 | m_stackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize); | |
799 | #endif | |
800 | } | |
801 | ||
802 | #if PLATFORM(WIN) | |
803 | if (lastStackLimit != m_stackLimit) | |
804 | preCommitStackMemory(m_stackLimit); | |
805 | #endif | |
806 | } | |
807 | ||
808 | #if ENABLE(FTL_JIT) | |
809 | void VM::updateFTLLargestStackSize(size_t stackSize) | |
810 | { | |
811 | if (stackSize > m_largestFTLStackSize) { | |
812 | m_largestFTLStackSize = stackSize; | |
813 | updateStackLimit(); | |
814 | } | |
815 | } | |
816 | #endif | |
817 | ||
93a37866 | 818 | void releaseExecutableMemory(VM& vm) |
14957cd0 | 819 | { |
93a37866 | 820 | vm.releaseExecutableMemory(); |
14957cd0 | 821 | } |
14957cd0 | 822 | |
6fe7ccc8 | 823 | #if ENABLE(DFG_JIT) |
93a37866 | 824 | void VM::gatherConservativeRoots(ConservativeRoots& conservativeRoots) |
6fe7ccc8 A |
825 | { |
826 | for (size_t i = 0; i < scratchBuffers.size(); i++) { | |
827 | ScratchBuffer* scratchBuffer = scratchBuffers[i]; | |
828 | if (scratchBuffer->activeLength()) { | |
829 | void* bufferStart = scratchBuffer->dataBuffer(); | |
830 | conservativeRoots.add(bufferStart, static_cast<void*>(static_cast<char*>(bufferStart) + scratchBuffer->activeLength())); | |
831 | } | |
832 | } | |
833 | } | |
834 | #endif | |
835 | ||
81345200 A |
836 | void logSanitizeStack(VM* vm) |
837 | { | |
838 | if (Options::verboseSanitizeStack() && vm->topCallFrame) { | |
839 | int dummy; | |
840 | dataLog( | |
841 | "Sanitizing stack with top call frame at ", RawPointer(vm->topCallFrame), | |
842 | ", current stack pointer at ", RawPointer(&dummy), ", in ", | |
843 | pointerDump(vm->topCallFrame->codeBlock()), " and last code origin = ", | |
844 | vm->topCallFrame->codeOrigin(), "\n"); | |
845 | } | |
846 | } | |
847 | ||
14957cd0 | 848 | #if ENABLE(REGEXP_TRACING) |
93a37866 | 849 | void VM::addRegExpToTrace(RegExp* regExp) |
14957cd0 | 850 | { |
81345200 | 851 | gcProtect(regExp); |
14957cd0 A |
852 | m_rtTraceList->add(regExp); |
853 | } | |
854 | ||
93a37866 | 855 | void VM::dumpRegExpTrace() |
14957cd0 A |
856 | { |
857 | // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used. | |
858 | RTTraceList::iterator iter = ++m_rtTraceList->begin(); | |
859 | ||
860 | if (iter != m_rtTraceList->end()) { | |
93a37866 | 861 | dataLogF("\nRegExp Tracing\n"); |
81345200 A |
862 | dataLogF("Regular Expression 8 Bit 16 Bit match() Matches Average\n"); |
863 | dataLogF(" <Match only / Match> JIT Addr JIT Address calls found String len\n"); | |
864 | dataLogF("----------------------------------------+----------------+----------------+----------+----------+-----------\n"); | |
14957cd0 A |
865 | |
866 | unsigned reCount = 0; | |
867 | ||
81345200 | 868 | for (; iter != m_rtTraceList->end(); ++iter, ++reCount) { |
14957cd0 | 869 | (*iter)->printTraceData(); |
81345200 A |
870 | gcUnprotect(*iter); |
871 | } | |
14957cd0 | 872 | |
93a37866 | 873 | dataLogF("%d Regular Expressions\n", reCount); |
b80e6193 | 874 | } |
14957cd0 A |
875 | |
876 | m_rtTraceList->clear(); | |
877 | } | |
878 | #else | |
93a37866 | 879 | void VM::dumpRegExpTrace() |
14957cd0 | 880 | { |
b80e6193 | 881 | } |
14957cd0 | 882 | #endif |
b80e6193 | 883 | |
81345200 A |
884 | void VM::registerWatchpointForImpureProperty(const Identifier& propertyName, Watchpoint* watchpoint) |
885 | { | |
886 | auto result = m_impurePropertyWatchpointSets.add(propertyName.string(), nullptr); | |
887 | if (result.isNewEntry) | |
888 | result.iterator->value = adoptRef(new WatchpointSet(IsWatched)); | |
889 | result.iterator->value->add(watchpoint); | |
890 | } | |
891 | ||
892 | void VM::addImpureProperty(const String& propertyName) | |
893 | { | |
894 | if (RefPtr<WatchpointSet> watchpointSet = m_impurePropertyWatchpointSets.take(propertyName)) | |
895 | watchpointSet->fireAll(); | |
896 | } | |
897 | ||
898 | class SetEnabledProfilerFunctor { | |
899 | public: | |
900 | bool operator()(CodeBlock* codeBlock) | |
901 | { | |
902 | if (JITCode::isOptimizingJIT(codeBlock->jitType())) | |
903 | codeBlock->jettison(Profiler::JettisonDueToLegacyProfiler); | |
904 | return false; | |
905 | } | |
906 | }; | |
907 | ||
908 | void VM::setEnabledProfiler(LegacyProfiler* profiler) | |
909 | { | |
910 | m_enabledProfiler = profiler; | |
911 | if (m_enabledProfiler) { | |
912 | waitForCompilationsToComplete(); | |
913 | SetEnabledProfilerFunctor functor; | |
914 | heap.forEachCodeBlock(functor); | |
915 | } | |
916 | } | |
917 | ||
918 | void sanitizeStackForVM(VM* vm) | |
919 | { | |
920 | logSanitizeStack(vm); | |
921 | #if !ENABLE(JIT) | |
922 | vm->interpreter->stack().sanitizeStack(); | |
923 | #else | |
924 | sanitizeStackForVMImpl(vm); | |
925 | #endif | |
926 | } | |
927 | ||
9dae56ea | 928 | } // namespace JSC |