1/*
2 * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
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.
13 * 3. Neither the name of Apple 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.
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"
30#include "VM.h"
31
32#include "ArgList.h"
33#include "ArrayBufferNeuteringWatchpointSet.h"
34#include "BuiltinExecutables.h"
35#include "BytecodeIntrinsicRegistry.h"
36#include "CodeBlock.h"
37#include "CodeCache.h"
38#include "CommonIdentifiers.h"
39#include "CommonSlowPaths.h"
40#include "CustomGetterSetter.h"
41#include "DFGWorklist.h"
42#include "DirectEvalExecutable.h"
43#include "Disassembler.h"
44#include "DoublePredictionFuzzerAgent.h"
45#include "Error.h"
46#include "ErrorConstructor.h"
47#include "ErrorInstance.h"
48#include "EvalCodeBlock.h"
49#include "Exception.h"
50#include "ExecutableToCodeBlockEdge.h"
51#include "FTLThunks.h"
52#include "FastMallocAlignedMemoryAllocator.h"
53#include "FunctionCodeBlock.h"
54#include "FunctionConstructor.h"
55#include "FunctionExecutable.h"
56#include "GCActivityCallback.h"
57#include "GetterSetter.h"
58#include "GigacageAlignedMemoryAllocator.h"
59#include "HasOwnPropertyCache.h"
60#include "Heap.h"
61#include "HeapIterationScope.h"
62#include "HeapProfiler.h"
63#include "HostCallReturnValue.h"
64#include "Identifier.h"
65#include "IncrementalSweeper.h"
66#include "IndirectEvalExecutable.h"
67#include "Interpreter.h"
68#include "IntlCollatorConstructor.h"
69#include "IntlDateTimeFormatConstructor.h"
70#include "IntlNumberFormatConstructor.h"
71#include "IntlPluralRulesConstructor.h"
72#include "JITCode.h"
73#include "JITWorklist.h"
74#include "JSAPIValueWrapper.h"
75#include "JSArray.h"
76#include "JSArrayBufferConstructor.h"
77#include "JSAsyncFunction.h"
78#include "JSBigInt.h"
79#include "JSBoundFunction.h"
80#include "JSCInlines.h"
81#include "JSCallbackFunction.h"
82#include "JSCustomGetterSetterFunction.h"
83#include "JSDestructibleObjectHeapCellType.h"
84#include "JSFixedArray.h"
85#include "JSFunction.h"
86#include "JSGlobalObjectFunctions.h"
87#include "JSImmutableButterfly.h"
88#include "JSInternalPromise.h"
89#include "JSLock.h"
90#include "JSMap.h"
91#include "JSMapIterator.h"
92#include "JSPromise.h"
93#include "JSPropertyNameEnumerator.h"
94#include "JSScriptFetchParameters.h"
95#include "JSScriptFetcher.h"
96#include "JSSet.h"
97#include "JSSetIterator.h"
98#include "JSSourceCode.h"
99#include "JSStringHeapCellType.h"
100#include "JSTemplateObjectDescriptor.h"
101#include "JSWeakMap.h"
102#include "JSWeakObjectRef.h"
103#include "JSWeakSet.h"
104#include "JSWebAssembly.h"
105#include "JSWebAssemblyCodeBlock.h"
106#include "JSWebAssemblyCodeBlockHeapCellType.h"
107#include "JSWebAssemblyMemory.h"
108#include "JSWithScope.h"
109#include "LLIntData.h"
110#include "Lexer.h"
111#include "Lookup.h"
112#include "MinimumReservedZoneSize.h"
113#include "ModuleProgramCodeBlock.h"
114#include "ModuleProgramExecutable.h"
115#include "NativeErrorConstructor.h"
116#include "NativeExecutable.h"
117#include "NativeStdFunctionCell.h"
118#include "Nodes.h"
119#include "ObjCCallbackFunction.h"
120#include "Parser.h"
121#include "ProfilerDatabase.h"
122#include "ProgramCodeBlock.h"
123#include "ProgramExecutable.h"
124#include "PromiseTimer.h"
125#include "PropertyMapHashTable.h"
126#include "ProxyRevoke.h"
127#include "RandomizingFuzzerAgent.h"
128#include "RegExpCache.h"
129#include "RegExpObject.h"
130#include "RegisterAtOffsetList.h"
131#include "RuntimeType.h"
132#include "SamplingProfiler.h"
133#include "ScopedArguments.h"
134#include "ShadowChicken.h"
135#include "SimpleTypedArrayController.h"
136#include "SourceProviderCache.h"
137#include "StackVisitor.h"
138#include "StrictEvalActivation.h"
139#include "StrongInlines.h"
140#include "StructureInlines.h"
141#include "TestRunnerUtils.h"
142#include "ThunkGenerators.h"
143#include "TypeProfiler.h"
144#include "TypeProfilerLog.h"
145#include "UnlinkedCodeBlock.h"
146#include "VMEntryScope.h"
147#include "VMInlines.h"
148#include "VMInspector.h"
149#include "VariableEnvironment.h"
150#include "WasmWorklist.h"
151#include "Watchdog.h"
152#include "WeakGCMapInlines.h"
153#include "WebAssemblyFunction.h"
154#include "WebAssemblyFunctionHeapCellType.h"
155#include "WebAssemblyWrapperFunction.h"
156#include <wtf/ProcessID.h>
157#include <wtf/ReadWriteLock.h>
158#include <wtf/SimpleStats.h>
159#include <wtf/StringPrintStream.h>
160#include <wtf/Threading.h>
161#include <wtf/text/AtomStringTable.h>
162#include <wtf/text/SymbolRegistry.h>
163
164#if ENABLE(C_LOOP)
165#include "CLoopStack.h"
166#include "CLoopStackInlines.h"
167#endif
168
169#if ENABLE(DFG_JIT)
170#include "ConservativeRoots.h"
171#endif
172
173#if ENABLE(REGEXP_TRACING)
174#include "RegExp.h"
175#endif
176
177namespace JSC {
178
179#if ENABLE(JIT)
180#if !ASSERT_DISABLED
181bool VM::s_canUseJITIsSet = false;
182#endif
183bool VM::s_canUseJIT = false;
184#endif
185
186Atomic<unsigned> VM::s_numberOfIDs;
187
188// Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either
189// ENABLE(JIT) or ENABLE(YARR_JIT) or both are enabled. The code below
190// just checks for ENABLE(JIT) or ENABLE(YARR_JIT) with this premise in mind.
191
192#if ENABLE(ASSEMBLER)
193static bool enableAssembler()
194{
195 if (!Options::useJIT())
196 return false;
197
198 char* canUseJITString = getenv("JavaScriptCoreUseJIT");
199 if (canUseJITString && !atoi(canUseJITString))
200 return false;
201
202 ExecutableAllocator::initializeUnderlyingAllocator();
203 if (!ExecutableAllocator::singleton().isValid()) {
204 if (Options::crashIfCantAllocateJITMemory())
205 CRASH();
206 return false;
207 }
208
209 return true;
210}
211#endif // ENABLE(!ASSEMBLER)
212
213bool VM::canUseAssembler()
214{
215#if ENABLE(ASSEMBLER)
216 static std::once_flag onceKey;
217 static bool enabled = false;
218 std::call_once(onceKey, [] {
219 enabled = enableAssembler();
220 });
221 return enabled;
222#else
223 return false; // interpreter only
224#endif
225}
226
227void VM::computeCanUseJIT()
228{
229#if ENABLE(JIT)
230#if !ASSERT_DISABLED
231 RELEASE_ASSERT(!s_canUseJITIsSet);
232 s_canUseJITIsSet = true;
233#endif
234 s_canUseJIT = VM::canUseAssembler() && Options::useJIT();
235#endif
236}
237
238inline unsigned VM::nextID()
239{
240 for (;;) {
241 unsigned currentNumberOfIDs = s_numberOfIDs.load();
242 unsigned newID = currentNumberOfIDs + 1;
243 if (s_numberOfIDs.compareExchangeWeak(currentNumberOfIDs, newID))
244 return newID;
245 }
246}
247
248static bool vmCreationShouldCrash = false;
249
250VM::VM(VMType vmType, HeapType heapType)
251 : m_id(nextID())
252 , m_apiLock(adoptRef(new JSLock(this)))
253#if USE(CF)
254 , m_runLoop(CFRunLoopGetCurrent())
255#endif // USE(CF)
256 , m_random(Options::seedOfVMRandomForFuzzer() ? Options::seedOfVMRandomForFuzzer() : cryptographicallyRandomNumber())
257 , m_integrityRandom(*this)
258 , heap(*this, heapType)
259 , fastMallocAllocator(makeUnique<FastMallocAlignedMemoryAllocator>())
260 , primitiveGigacageAllocator(makeUnique<GigacageAlignedMemoryAllocator>(Gigacage::Primitive))
261 , jsValueGigacageAllocator(makeUnique<GigacageAlignedMemoryAllocator>(Gigacage::JSValue))
262 , auxiliaryHeapCellType(makeUnique<HeapCellType>(CellAttributes(DoesNotNeedDestruction, HeapCell::Auxiliary)))
263 , immutableButterflyHeapCellType(makeUnique<HeapCellType>(CellAttributes(DoesNotNeedDestruction, HeapCell::JSCellWithInteriorPointers)))
264 , cellHeapCellType(makeUnique<HeapCellType>(CellAttributes(DoesNotNeedDestruction, HeapCell::JSCell)))
265 , destructibleCellHeapCellType(makeUnique<HeapCellType>(CellAttributes(NeedsDestruction, HeapCell::JSCell)))
266 , stringHeapCellType(makeUnique<JSStringHeapCellType>())
267 , destructibleObjectHeapCellType(makeUnique<JSDestructibleObjectHeapCellType>())
268#if ENABLE(WEBASSEMBLY)
269 , webAssemblyCodeBlockHeapCellType(makeUnique<JSWebAssemblyCodeBlockHeapCellType>())
270 , webAssemblyFunctionHeapCellType(makeUnique<WebAssemblyFunctionHeapCellType>())
271#endif
272 , primitiveGigacageAuxiliarySpace("Primitive Gigacage Auxiliary", heap, auxiliaryHeapCellType.get(), primitiveGigacageAllocator.get()) // Hash:0x3e7cd762
273 , jsValueGigacageAuxiliarySpace("JSValue Gigacage Auxiliary", heap, auxiliaryHeapCellType.get(), jsValueGigacageAllocator.get()) // Hash:0x241e946
274 , immutableButterflyJSValueGigacageAuxiliarySpace("ImmutableButterfly Gigacage JSCellWithInteriorPointers", heap, immutableButterflyHeapCellType.get(), jsValueGigacageAllocator.get()) // Hash:0x7a945300
275 , cellSpace("JSCell", heap, cellHeapCellType.get(), fastMallocAllocator.get()) // Hash:0xadfb5a79
276 , variableSizedCellSpace("Variable Sized JSCell", heap, cellHeapCellType.get(), fastMallocAllocator.get()) // Hash:0xbcd769cc
277 , destructibleCellSpace("Destructible JSCell", heap, destructibleCellHeapCellType.get(), fastMallocAllocator.get()) // Hash:0xbfff3d73
278 , destructibleObjectSpace("JSDestructibleObject", heap, destructibleObjectHeapCellType.get(), fastMallocAllocator.get()) // Hash:0x4f5ed7a9
279 , bigIntSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), JSBigInt)
280 , executableToCodeBlockEdgeSpace ISO_SUBSPACE_INIT(heap, cellHeapCellType.get(), ExecutableToCodeBlockEdge) // Hash:0x7b730b20
281 , functionSpace ISO_SUBSPACE_INIT(heap, cellHeapCellType.get(), JSFunction) // Hash:0x800fca72
282 , getterSetterSpace ISO_SUBSPACE_INIT(heap, cellHeapCellType.get(), GetterSetter)
283 , internalFunctionSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), InternalFunction) // Hash:0xf845c464
284 , nativeExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), NativeExecutable) // Hash:0x67567f95
285 , propertyTableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), PropertyTable) // Hash:0xc6bc9f12
286 , ropeStringSpace ISO_SUBSPACE_INIT(heap, stringHeapCellType.get(), JSRopeString)
287 , scopedArgumentsSpace ISO_SUBSPACE_INIT(heap, cellHeapCellType.get(), ScopedArguments)
288 , sparseArrayValueMapSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), SparseArrayValueMap)
289 , stringSpace ISO_SUBSPACE_INIT(heap, stringHeapCellType.get(), JSString) // Hash:0x90cf758f
290 , structureRareDataSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), StructureRareData) // Hash:0xaca4e62d
291 , structureSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), Structure) // Hash:0x1f1bcdca
292 , symbolTableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), SymbolTable) // Hash:0xc5215afd
293 , executableToCodeBlockEdgesWithConstraints(executableToCodeBlockEdgeSpace)
294 , executableToCodeBlockEdgesWithFinalizers(executableToCodeBlockEdgeSpace)
295 , codeBlockSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), CodeBlock) // Hash:0x77e66ec9
296 , functionExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), FunctionExecutable) // Hash:0x5d158f3
297 , programExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), ProgramExecutable) // Hash:0x527c77e7
298 , unlinkedFunctionExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), UnlinkedFunctionExecutable) // Hash:0xf6b828d9
299 , vmType(vmType)
300 , clientData(0)
301 , topEntryFrame(nullptr)
302 , topCallFrame(CallFrame::noCaller())
303 , promiseTimer(PromiseTimer::create(*this))
304 , m_atomStringTable(vmType == Default ? Thread::current().atomStringTable() : new AtomStringTable)
305 , propertyNames(nullptr)
306 , emptyList(new ArgList)
307 , machineCodeBytesPerBytecodeWordForBaselineJIT(makeUnique<SimpleStats>())
308 , customGetterSetterFunctionMap(*this)
309 , stringCache(*this)
310 , symbolImplToSymbolMap(*this)
311 , structureCache(*this)
312 , interpreter(0)
313 , entryScope(0)
314 , m_regExpCache(new RegExpCache(this))
315 , m_compactVariableMap(adoptRef(*(new CompactVariableMap)))
316#if ENABLE(REGEXP_TRACING)
317 , m_rtTraceList(new RTTraceList())
318#endif
319#if ENABLE(GC_VALIDATION)
320 , m_initializingObjectClass(0)
321#endif
322 , m_stackPointerAtVMEntry(0)
323 , m_codeCache(makeUnique<CodeCache>())
324 , m_builtinExecutables(makeUnique<BuiltinExecutables>(*this))
325 , m_typeProfilerEnabledCount(0)
326 , m_primitiveGigacageEnabled(IsWatched)
327 , m_controlFlowProfilerEnabledCount(0)
328{
329 if (UNLIKELY(vmCreationShouldCrash))
330 CRASH_WITH_INFO(0x4242424220202020, 0xbadbeef0badbeef, 0x1234123412341234, 0x1337133713371337);
331
332 interpreter = new Interpreter(*this);
333 StackBounds stack = Thread::current().stack();
334 updateSoftReservedZoneSize(Options::softReservedZoneSize());
335 setLastStackTop(stack.origin());
336
337 JSRunLoopTimer::Manager::shared().registerVM(*this);
338
339 // Need to be careful to keep everything consistent here
340 JSLockHolder lock(this);
341 AtomStringTable* existingEntryAtomStringTable = Thread::current().setCurrentAtomStringTable(m_atomStringTable);
342 structureStructure.set(*this, Structure::createStructure(*this));
343 structureRareDataStructure.set(*this, StructureRareData::createStructure(*this, 0, jsNull()));
344 stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
345
346 smallStrings.initializeCommonStrings(*this);
347
348 propertyNames = new CommonIdentifiers(*this);
349 terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
350 propertyNameEnumeratorStructure.set(*this, JSPropertyNameEnumerator::createStructure(*this, 0, jsNull()));
351 getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
352 customGetterSetterStructure.set(*this, CustomGetterSetter::createStructure(*this, 0, jsNull()));
353 domAttributeGetterSetterStructure.set(*this, DOMAttributeGetterSetter::createStructure(*this, 0, jsNull()));
354 scopedArgumentsTableStructure.set(*this, ScopedArgumentsTable::createStructure(*this, 0, jsNull()));
355 apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
356 nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, 0, jsNull()));
357 evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, 0, jsNull()));
358 programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
359 functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
360#if ENABLE(WEBASSEMBLY)
361 webAssemblyCodeBlockStructure.set(*this, JSWebAssemblyCodeBlock::createStructure(*this, 0, jsNull()));
362#endif
363 moduleProgramExecutableStructure.set(*this, ModuleProgramExecutable::createStructure(*this, 0, jsNull()));
364 regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
365 symbolStructure.set(*this, Symbol::createStructure(*this, 0, jsNull()));
366 symbolTableStructure.set(*this, SymbolTable::createStructure(*this, 0, jsNull()));
367 fixedArrayStructure.set(*this, JSFixedArray::createStructure(*this, 0, jsNull()));
368
369 immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithInt32) - NumberOfIndexingShapes].set(*this, JSImmutableButterfly::createStructure(*this, 0, jsNull(), CopyOnWriteArrayWithInt32));
370 immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithDouble) - NumberOfIndexingShapes].set(*this, JSImmutableButterfly::createStructure(*this, 0, jsNull(), CopyOnWriteArrayWithDouble));
371 immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].set(*this, JSImmutableButterfly::createStructure(*this, 0, jsNull(), CopyOnWriteArrayWithContiguous));
372
373 sourceCodeStructure.set(*this, JSSourceCode::createStructure(*this, 0, jsNull()));
374 scriptFetcherStructure.set(*this, JSScriptFetcher::createStructure(*this, 0, jsNull()));
375 scriptFetchParametersStructure.set(*this, JSScriptFetchParameters::createStructure(*this, 0, jsNull()));
376 structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
377 sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull()));
378 templateObjectDescriptorStructure.set(*this, JSTemplateObjectDescriptor::createStructure(*this, 0, jsNull()));
379 arrayBufferNeuteringWatchpointStructure.set(*this, ArrayBufferNeuteringWatchpointSet::createStructure(*this));
380 unlinkedFunctionExecutableStructure.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull()));
381 unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull()));
382 unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull()));
383 unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull()));
384 unlinkedModuleProgramCodeBlockStructure.set(*this, UnlinkedModuleProgramCodeBlock::createStructure(*this, 0, jsNull()));
385 propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull()));
386 functionRareDataStructure.set(*this, FunctionRareData::createStructure(*this, 0, jsNull()));
387 exceptionStructure.set(*this, Exception::createStructure(*this, 0, jsNull()));
388 nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull()));
389 programCodeBlockStructure.set(*this, ProgramCodeBlock::createStructure(*this, 0, jsNull()));
390 moduleProgramCodeBlockStructure.set(*this, ModuleProgramCodeBlock::createStructure(*this, 0, jsNull()));
391 evalCodeBlockStructure.set(*this, EvalCodeBlock::createStructure(*this, 0, jsNull()));
392 functionCodeBlockStructure.set(*this, FunctionCodeBlock::createStructure(*this, 0, jsNull()));
393 hashMapBucketSetStructure.set(*this, HashMapBucket<HashMapBucketDataKey>::createStructure(*this, 0, jsNull()));
394 hashMapBucketMapStructure.set(*this, HashMapBucket<HashMapBucketDataKeyValue>::createStructure(*this, 0, jsNull()));
395 bigIntStructure.set(*this, JSBigInt::createStructure(*this, 0, jsNull()));
396 executableToCodeBlockEdgeStructure.set(*this, ExecutableToCodeBlockEdge::createStructure(*this, nullptr, jsNull()));
397
398 // Eagerly initialize constant cells since the concurrent compiler can access them.
399 if (canUseJIT()) {
400 sentinelMapBucket();
401 sentinelSetBucket();
402 }
403 bigIntConstantOne.set(*this, JSBigInt::createFrom(*this, 1));
404
405 Thread::current().setCurrentAtomStringTable(existingEntryAtomStringTable);
406
407#if !ENABLE(C_LOOP)
408 initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
409#endif
410
411 Gigacage::addPrimitiveDisableCallback(primitiveGigacageDisabledCallback, this);
412
413 heap.notifyIsSafeToCollect();
414
415 LLInt::Data::performAssertions(*this);
416
417 if (UNLIKELY(Options::useProfiler())) {
418 m_perBytecodeProfiler = makeUnique<Profiler::Database>(*this);
419
420 StringPrintStream pathOut;
421 const char* profilerPath = getenv("JSC_PROFILER_PATH");
422 if (profilerPath)
423 pathOut.print(profilerPath, "/");
424 pathOut.print("JSCProfile-", getCurrentProcessID(), "-", m_perBytecodeProfiler->databaseID(), ".json");
425 m_perBytecodeProfiler->registerToSaveAtExit(pathOut.toCString().data());
426 }
427
428 callFrameForCatch = nullptr;
429
430 // Initialize this last, as a free way of asserting that VM initialization itself
431 // won't use this.
432 m_typedArrayController = adoptRef(new SimpleTypedArrayController());
433
434 m_bytecodeIntrinsicRegistry = makeUnique<BytecodeIntrinsicRegistry>(*this);
435
436 if (Options::useTypeProfiler())
437 enableTypeProfiler();
438 if (Options::useControlFlowProfiler())
439 enableControlFlowProfiler();
440#if ENABLE(SAMPLING_PROFILER)
441 if (Options::useSamplingProfiler()) {
442 setShouldBuildPCToCodeOriginMapping();
443 Ref<Stopwatch> stopwatch = Stopwatch::create();
444 stopwatch->start();
445 m_samplingProfiler = adoptRef(new SamplingProfiler(*this, WTFMove(stopwatch)));
446 if (Options::samplingProfilerPath())
447 m_samplingProfiler->registerForReportAtExit();
448 m_samplingProfiler->start();
449 }
450#endif // ENABLE(SAMPLING_PROFILER)
451
452 if (Options::useRandomizingFuzzerAgent())
453 setFuzzerAgent(makeUnique<RandomizingFuzzerAgent>(*this));
454 else if (Options::useDoublePredictionFuzzerAgent())
455 setFuzzerAgent(makeUnique<DoublePredictionFuzzerAgent>(*this));
456
457 if (Options::alwaysGeneratePCToCodeOriginMap())
458 setShouldBuildPCToCodeOriginMapping();
459
460 if (Options::watchdog()) {
461 Watchdog& watchdog = ensureWatchdog();
462 watchdog.setTimeLimit(Seconds::fromMilliseconds(Options::watchdog()));
463 }
464
465#if ENABLE(JIT)
466 // Make sure that any stubs that the JIT is going to use are initialized in non-compilation threads.
467 if (canUseJIT()) {
468 jitStubs = makeUnique<JITThunks>();
469#if ENABLE(FTL_JIT)
470 ftlThunks = makeUnique<FTL::Thunks>();
471#endif // ENABLE(FTL_JIT)
472 getCTIInternalFunctionTrampolineFor(CodeForCall);
473 getCTIInternalFunctionTrampolineFor(CodeForConstruct);
474 }
475#endif
476
477 if (Options::forceDebuggerBytecodeGeneration() || Options::alwaysUseShadowChicken())
478 ensureShadowChicken();
479
480 VMInspector::instance().add(this);
481
482 if (!g_jscConfig.disabledFreezingForTesting)
483 Config::permanentlyFreeze();
484}
485
486static ReadWriteLock s_destructionLock;
487
488void waitForVMDestruction()
489{
490 auto locker = holdLock(s_destructionLock.write());
491}
492
493VM::~VM()
494{
495 auto destructionLocker = holdLock(s_destructionLock.read());
496
497 Gigacage::removePrimitiveDisableCallback(primitiveGigacageDisabledCallback, this);
498 promiseTimer->stopRunningTasks();
499#if ENABLE(WEBASSEMBLY)
500 if (Wasm::Worklist* worklist = Wasm::existingWorklistOrNull())
501 worklist->stopAllPlansForContext(wasmContext);
502#endif
503 if (UNLIKELY(m_watchdog))
504 m_watchdog->willDestroyVM(this);
505 m_traps.willDestroyVM();
506 VMInspector::instance().remove(this);
507
508 // Never GC, ever again.
509 heap.incrementDeferralDepth();
510
511#if ENABLE(SAMPLING_PROFILER)
512 if (m_samplingProfiler) {
513 m_samplingProfiler->reportDataToOptionFile();
514 m_samplingProfiler->shutdown();
515 }
516#endif // ENABLE(SAMPLING_PROFILER)
517
518#if ENABLE(JIT)
519 if (JITWorklist* worklist = JITWorklist::existingGlobalWorklistOrNull())
520 worklist->completeAllForVM(*this);
521#endif // ENABLE(JIT)
522
523#if ENABLE(DFG_JIT)
524 // Make sure concurrent compilations are done, but don't install them, since there is
525 // no point to doing so.
526 for (unsigned i = DFG::numberOfWorklists(); i--;) {
527 if (DFG::Worklist* worklist = DFG::existingWorklistForIndexOrNull(i)) {
528 worklist->removeNonCompilingPlansForVM(*this);
529 worklist->waitUntilAllPlansForVMAreReady(*this);
530 worklist->removeAllReadyPlansForVM(*this);
531 }
532 }
533#endif // ENABLE(DFG_JIT)
534
535 waitForAsynchronousDisassembly();
536
537 // Clear this first to ensure that nobody tries to remove themselves from it.
538 m_perBytecodeProfiler = nullptr;
539
540 ASSERT(currentThreadIsHoldingAPILock());
541 m_apiLock->willDestroyVM(this);
542 smallStrings.setIsInitialized(false);
543 heap.lastChanceToFinalize();
544
545 JSRunLoopTimer::Manager::shared().unregisterVM(*this);
546
547 delete interpreter;
548#ifndef NDEBUG
549 interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef);
550#endif
551
552 delete emptyList;
553
554 delete propertyNames;
555 if (vmType != Default)
556 delete m_atomStringTable;
557
558 delete clientData;
559 delete m_regExpCache;
560
561#if ENABLE(REGEXP_TRACING)
562 delete m_rtTraceList;
563#endif
564
565#if ENABLE(DFG_JIT)
566 for (unsigned i = 0; i < m_scratchBuffers.size(); ++i)
567 fastFree(m_scratchBuffers[i]);
568#endif
569}
570
571void VM::primitiveGigacageDisabledCallback(void* argument)
572{
573 static_cast<VM*>(argument)->primitiveGigacageDisabled();
574}
575
576void VM::primitiveGigacageDisabled()
577{
578 if (m_apiLock->currentThreadIsHoldingLock()) {
579 m_primitiveGigacageEnabled.fireAll(*this, "Primitive gigacage disabled");
580 return;
581 }
582
583 // This is totally racy, and that's OK. The point is, it's up to the user to ensure that they pass the
584 // uncaged buffer in a nicely synchronized manner.
585 m_needToFirePrimitiveGigacageEnabled = true;
586}
587
588void VM::setLastStackTop(void* lastStackTop)
589{
590 m_lastStackTop = lastStackTop;
591}
592
593Ref<VM> VM::createContextGroup(HeapType heapType)
594{
595 return adoptRef(*new VM(APIContextGroup, heapType));
596}
597
598Ref<VM> VM::create(HeapType heapType)
599{
600 return adoptRef(*new VM(Default, heapType));
601}
602
603bool VM::sharedInstanceExists()
604{
605 return sharedInstanceInternal();
606}
607
608VM& VM::sharedInstance()
609{
610 GlobalJSLock globalLock;
611 VM*& instance = sharedInstanceInternal();
612 if (!instance)
613 instance = adoptRef(new VM(APIShared, SmallHeap)).leakRef();
614 return *instance;
615}
616
617VM*& VM::sharedInstanceInternal()
618{
619 static VM* sharedInstance;
620 return sharedInstance;
621}
622
623Watchdog& VM::ensureWatchdog()
624{
625 if (!m_watchdog)
626 m_watchdog = adoptRef(new Watchdog(this));
627 return *m_watchdog;
628}
629
630HeapProfiler& VM::ensureHeapProfiler()
631{
632 if (!m_heapProfiler)
633 m_heapProfiler = makeUnique<HeapProfiler>(*this);
634 return *m_heapProfiler;
635}
636
637#if ENABLE(SAMPLING_PROFILER)
638SamplingProfiler& VM::ensureSamplingProfiler(RefPtr<Stopwatch>&& stopwatch)
639{
640 if (!m_samplingProfiler)
641 m_samplingProfiler = adoptRef(new SamplingProfiler(*this, WTFMove(stopwatch)));
642 return *m_samplingProfiler;
643}
644#endif // ENABLE(SAMPLING_PROFILER)
645
646#if ENABLE(JIT)
647static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
648{
649 switch (intrinsic) {
650 case CharCodeAtIntrinsic:
651 return charCodeAtThunkGenerator;
652 case CharAtIntrinsic:
653 return charAtThunkGenerator;
654 case StringPrototypeCodePointAtIntrinsic:
655 return stringPrototypeCodePointAtThunkGenerator;
656 case Clz32Intrinsic:
657 return clz32ThunkGenerator;
658 case FromCharCodeIntrinsic:
659 return fromCharCodeThunkGenerator;
660 case SqrtIntrinsic:
661 return sqrtThunkGenerator;
662 case AbsIntrinsic:
663 return absThunkGenerator;
664 case FloorIntrinsic:
665 return floorThunkGenerator;
666 case CeilIntrinsic:
667 return ceilThunkGenerator;
668 case TruncIntrinsic:
669 return truncThunkGenerator;
670 case RoundIntrinsic:
671 return roundThunkGenerator;
672 case ExpIntrinsic:
673 return expThunkGenerator;
674 case LogIntrinsic:
675 return logThunkGenerator;
676 case IMulIntrinsic:
677 return imulThunkGenerator;
678 case RandomIntrinsic:
679 return randomThunkGenerator;
680 case BoundThisNoArgsFunctionCallIntrinsic:
681 return boundThisNoArgsFunctionCallGenerator;
682 default:
683 return nullptr;
684 }
685}
686
687#endif // ENABLE(JIT)
688
689NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor, const String& name)
690{
691 return getHostFunction(function, NoIntrinsic, constructor, nullptr, name);
692}
693
694static Ref<NativeJITCode> jitCodeForCallTrampoline()
695{
696 static NativeJITCode* result;
697 static std::once_flag onceKey;
698 std::call_once(onceKey, [&] {
699 result = new NativeJITCode(LLInt::getCodeRef<JSEntryPtrTag>(llint_native_call_trampoline), JITType::HostCallThunk, NoIntrinsic);
700 });
701 return makeRef(*result);
702}
703
704static Ref<NativeJITCode> jitCodeForConstructTrampoline()
705{
706 static NativeJITCode* result;
707 static std::once_flag onceKey;
708 std::call_once(onceKey, [&] {
709 result = new NativeJITCode(LLInt::getCodeRef<JSEntryPtrTag>(llint_native_construct_trampoline), JITType::HostCallThunk, NoIntrinsic);
710 });
711 return makeRef(*result);
712}
713
714NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic, NativeFunction constructor, const DOMJIT::Signature* signature, const String& name)
715{
716#if ENABLE(JIT)
717 if (canUseJIT()) {
718 return jitStubs->hostFunctionStub(
719 *this, function, constructor,
720 intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0,
721 intrinsic, signature, name);
722 }
723#endif // ENABLE(JIT)
724 UNUSED_PARAM(intrinsic);
725 UNUSED_PARAM(signature);
726 return NativeExecutable::create(*this, jitCodeForCallTrampoline(), function, jitCodeForConstructTrampoline(), constructor, name);
727}
728
729MacroAssemblerCodePtr<JSEntryPtrTag> VM::getCTIInternalFunctionTrampolineFor(CodeSpecializationKind kind)
730{
731#if ENABLE(JIT)
732 if (canUseJIT()) {
733 if (kind == CodeForCall)
734 return jitStubs->ctiInternalFunctionCall(*this).retagged<JSEntryPtrTag>();
735 return jitStubs->ctiInternalFunctionConstruct(*this).retagged<JSEntryPtrTag>();
736 }
737#endif
738 if (kind == CodeForCall)
739 return LLInt::getCodePtr<JSEntryPtrTag>(llint_internal_function_call_trampoline);
740 return LLInt::getCodePtr<JSEntryPtrTag>(llint_internal_function_construct_trampoline);
741}
742
743VM::ClientData::~ClientData()
744{
745}
746
747void VM::resetDateCache()
748{
749 utcTimeOffsetCache.reset();
750 localTimeOffsetCache.reset();
751 cachedDateString = String();
752 cachedDateStringValue = std::numeric_limits<double>::quiet_NaN();
753 dateInstanceCache.reset();
754}
755
756void VM::whenIdle(Function<void()>&& callback)
757{
758 if (!entryScope) {
759 callback();
760 return;
761 }
762
763 entryScope->addDidPopListener(WTFMove(callback));
764}
765
766void VM::deleteAllLinkedCode(DeleteAllCodeEffort effort)
767{
768 whenIdle([=] () {
769 heap.deleteAllCodeBlocks(effort);
770 });
771}
772
773void VM::deleteAllCode(DeleteAllCodeEffort effort)
774{
775 whenIdle([=] () {
776 m_codeCache->clear();
777 m_regExpCache->deleteAllCode();
778 heap.deleteAllCodeBlocks(effort);
779 heap.deleteAllUnlinkedCodeBlocks(effort);
780 heap.reportAbandonedObjectGraph();
781 });
782}
783
784void VM::shrinkFootprintWhenIdle()
785{
786 whenIdle([=] () {
787 sanitizeStackForVM(*this);
788 deleteAllCode(DeleteAllCodeIfNotCollecting);
789 heap.collectNow(Synchronousness::Sync, CollectionScope::Full);
790 // FIXME: Consider stopping various automatic threads here.
791 // https://bugs.webkit.org/show_bug.cgi?id=185447
792 WTF::releaseFastMallocFreeMemory();
793 });
794}
795
796SourceProviderCache* VM::addSourceProviderCache(SourceProvider* sourceProvider)
797{
798 auto addResult = sourceProviderCacheMap.add(sourceProvider, nullptr);
799 if (addResult.isNewEntry)
800 addResult.iterator->value = adoptRef(new SourceProviderCache);
801 return addResult.iterator->value.get();
802}
803
804void VM::clearSourceProviderCaches()
805{
806 sourceProviderCacheMap.clear();
807}
808
809Exception* VM::throwException(JSGlobalObject* globalObject, Exception* exception)
810{
811 CallFrame* throwOriginFrame = topJSCallFrame();
812 if (!throwOriginFrame)
813 throwOriginFrame = globalObject->deprecatedCallFrameForDebugger();
814
815 if (Options::breakOnThrow()) {
816 CodeBlock* codeBlock = throwOriginFrame ? throwOriginFrame->codeBlock() : nullptr;
817 dataLog("Throwing exception in call frame ", RawPointer(throwOriginFrame), " for code block ", codeBlock, "\n");
818 CRASH();
819 }
820
821 interpreter->notifyDebuggerOfExceptionToBeThrown(*this, globalObject, throwOriginFrame, exception);
822
823 setException(exception);
824
825#if ENABLE(EXCEPTION_SCOPE_VERIFICATION)
826 m_nativeStackTraceOfLastThrow = StackTrace::captureStackTrace(Options::unexpectedExceptionStackTraceLimit());
827 m_throwingThread = &Thread::current();
828#endif
829 return exception;
830}
831
832Exception* VM::throwException(JSGlobalObject* globalObject, JSValue thrownValue)
833{
834 VM& vm = *this;
835 Exception* exception = jsDynamicCast<Exception*>(vm, thrownValue);
836 if (!exception)
837 exception = Exception::create(*this, thrownValue);
838
839 return throwException(globalObject, exception);
840}
841
842Exception* VM::throwException(JSGlobalObject* globalObject, JSObject* error)
843{
844 return throwException(globalObject, JSValue(error));
845}
846
847void VM::setStackPointerAtVMEntry(void* sp)
848{
849 m_stackPointerAtVMEntry = sp;
850 updateStackLimits();
851}
852
853size_t VM::updateSoftReservedZoneSize(size_t softReservedZoneSize)
854{
855 size_t oldSoftReservedZoneSize = m_currentSoftReservedZoneSize;
856 m_currentSoftReservedZoneSize = softReservedZoneSize;
857#if ENABLE(C_LOOP)
858 interpreter->cloopStack().setSoftReservedZoneSize(softReservedZoneSize);
859#endif
860
861 updateStackLimits();
862
863 return oldSoftReservedZoneSize;
864}
865
866#if OS(WINDOWS)
867// On Windows the reserved stack space consists of committed memory, a guard page, and uncommitted memory,
868// where the guard page is a barrier between committed and uncommitted memory.
869// When data from the guard page is read or written, the guard page is moved, and memory is committed.
870// This is how the system grows the stack.
871// When using the C stack on Windows we need to precommit the needed stack space.
872// Otherwise we might crash later if we access uncommitted stack memory.
873// This can happen if we allocate stack space larger than the page guard size (4K).
874// The system does not get the chance to move the guard page, and commit more memory,
875// and we crash if uncommitted memory is accessed.
876// The MSVC compiler fixes this by inserting a call to the _chkstk() function,
877// when needed, see http://support.microsoft.com/kb/100775.
878// By touching every page up to the stack limit with a dummy operation,
879// we force the system to move the guard page, and commit memory.
880
881static void preCommitStackMemory(void* stackLimit)
882{
883 const int pageSize = 4096;
884 for (volatile char* p = reinterpret_cast<char*>(&stackLimit); p > stackLimit; p -= pageSize) {
885 char ch = *p;
886 *p = ch;
887 }
888}
889#endif
890
891void VM::updateStackLimits()
892{
893#if OS(WINDOWS)
894 void* lastSoftStackLimit = m_softStackLimit;
895#endif
896
897 const StackBounds& stack = Thread::current().stack();
898 size_t reservedZoneSize = Options::reservedZoneSize();
899 // We should have already ensured that Options::reservedZoneSize() >= minimumReserveZoneSize at
900 // options initialization time, and the option value should not have been changed thereafter.
901 // We don't have the ability to assert here that it hasn't changed, but we can at least assert
902 // that the value is sane.
903 RELEASE_ASSERT(reservedZoneSize >= minimumReservedZoneSize);
904
905 if (m_stackPointerAtVMEntry) {
906 char* startOfStack = reinterpret_cast<char*>(m_stackPointerAtVMEntry);
907 m_softStackLimit = stack.recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_currentSoftReservedZoneSize);
908 m_stackLimit = stack.recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), reservedZoneSize);
909 } else {
910 m_softStackLimit = stack.recursionLimit(m_currentSoftReservedZoneSize);
911 m_stackLimit = stack.recursionLimit(reservedZoneSize);
912 }
913
914#if OS(WINDOWS)
915 // We only need to precommit stack memory dictated by the VM::m_softStackLimit limit.
916 // This is because VM::m_softStackLimit applies to stack usage by LLINT asm or JIT
917 // generated code which can allocate stack space that the C++ compiler does not know
918 // about. As such, we have to precommit that stack memory manually.
919 //
920 // In contrast, we do not need to worry about VM::m_stackLimit because that limit is
921 // used exclusively by C++ code, and the C++ compiler will automatically commit the
922 // needed stack pages.
923 if (lastSoftStackLimit != m_softStackLimit)
924 preCommitStackMemory(m_softStackLimit);
925#endif
926}
927
928#if ENABLE(DFG_JIT)
929void VM::gatherScratchBufferRoots(ConservativeRoots& conservativeRoots)
930{
931 auto lock = holdLock(m_scratchBufferLock);
932 for (auto* scratchBuffer : m_scratchBuffers) {
933 if (scratchBuffer->activeLength()) {
934 void* bufferStart = scratchBuffer->dataBuffer();
935 conservativeRoots.add(bufferStart, static_cast<void*>(static_cast<char*>(bufferStart) + scratchBuffer->activeLength()));
936 }
937 }
938}
939#endif
940
941void logSanitizeStack(VM& vm)
942{
943 if (Options::verboseSanitizeStack() && vm.topCallFrame) {
944 int dummy;
945 auto& stackBounds = Thread::current().stack();
946 dataLog(
947 "Sanitizing stack for VM = ", RawPointer(&vm), " with top call frame at ", RawPointer(vm.topCallFrame),
948 ", current stack pointer at ", RawPointer(&dummy), ", in ",
949 pointerDump(vm.topCallFrame->codeBlock()), ", last code origin = ",
950 vm.topCallFrame->codeOrigin(), ", last stack top = ", RawPointer(vm.lastStackTop()), ", in stack range [", RawPointer(stackBounds.origin()), ", ", RawPointer(stackBounds.end()), "]\n");
951 }
952}
953
954#if ENABLE(YARR_JIT_ALL_PARENS_EXPRESSIONS)
955char* VM::acquireRegExpPatternContexBuffer()
956{
957 m_regExpPatternContextLock.lock();
958 ASSERT(m_regExpPatternContextLock.isLocked());
959 if (!m_regExpPatternContexBuffer)
960 m_regExpPatternContexBuffer = makeUniqueArray<char>(VM::patternContextBufferSize);
961 return m_regExpPatternContexBuffer.get();
962}
963
964void VM::releaseRegExpPatternContexBuffer()
965{
966 ASSERT(m_regExpPatternContextLock.isLocked());
967
968 m_regExpPatternContextLock.unlock();
969}
970#endif
971
972#if ENABLE(REGEXP_TRACING)
973void VM::addRegExpToTrace(RegExp* regExp)
974{
975 gcProtect(regExp);
976 m_rtTraceList->add(regExp);
977}
978
979void VM::dumpRegExpTrace()
980{
981 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
982 RTTraceList::iterator iter = ++m_rtTraceList->begin();
983
984 if (iter != m_rtTraceList->end()) {
985 dataLogF("\nRegExp Tracing\n");
986 dataLogF("Regular Expression 8 Bit 16 Bit match() Matches Average\n");
987 dataLogF(" <Match only / Match> JIT Addr JIT Address calls found String len\n");
988 dataLogF("----------------------------------------+----------------+----------------+----------+----------+-----------\n");
989
990 unsigned reCount = 0;
991
992 for (; iter != m_rtTraceList->end(); ++iter, ++reCount) {
993 (*iter)->printTraceData();
994 gcUnprotect(*iter);
995 }
996
997 dataLogF("%d Regular Expressions\n", reCount);
998 }
999
1000 m_rtTraceList->clear();
1001}
1002#else
1003void VM::dumpRegExpTrace()
1004{
1005}
1006#endif
1007
1008WatchpointSet* VM::ensureWatchpointSetForImpureProperty(const Identifier& propertyName)
1009{
1010 auto result = m_impurePropertyWatchpointSets.add(propertyName.string(), nullptr);
1011 if (result.isNewEntry)
1012 result.iterator->value = adoptRef(new WatchpointSet(IsWatched));
1013 return result.iterator->value.get();
1014}
1015
1016void VM::registerWatchpointForImpureProperty(const Identifier& propertyName, Watchpoint* watchpoint)
1017{
1018 ensureWatchpointSetForImpureProperty(propertyName)->add(watchpoint);
1019}
1020
1021void VM::addImpureProperty(const String& propertyName)
1022{
1023 if (RefPtr<WatchpointSet> watchpointSet = m_impurePropertyWatchpointSets.take(propertyName))
1024 watchpointSet->fireAll(*this, "Impure property added");
1025}
1026
1027template<typename Func>
1028static bool enableProfilerWithRespectToCount(unsigned& counter, const Func& doEnableWork)
1029{
1030 bool needsToRecompile = false;
1031 if (!counter) {
1032 doEnableWork();
1033 needsToRecompile = true;
1034 }
1035 counter++;
1036
1037 return needsToRecompile;
1038}
1039
1040template<typename Func>
1041static bool disableProfilerWithRespectToCount(unsigned& counter, const Func& doDisableWork)
1042{
1043 RELEASE_ASSERT(counter > 0);
1044 bool needsToRecompile = false;
1045 counter--;
1046 if (!counter) {
1047 doDisableWork();
1048 needsToRecompile = true;
1049 }
1050
1051 return needsToRecompile;
1052}
1053
1054bool VM::enableTypeProfiler()
1055{
1056 auto enableTypeProfiler = [this] () {
1057 this->m_typeProfiler = makeUnique<TypeProfiler>();
1058 this->m_typeProfilerLog = makeUnique<TypeProfilerLog>(*this);
1059 };
1060
1061 return enableProfilerWithRespectToCount(m_typeProfilerEnabledCount, enableTypeProfiler);
1062}
1063
1064bool VM::disableTypeProfiler()
1065{
1066 auto disableTypeProfiler = [this] () {
1067 this->m_typeProfiler.reset(nullptr);
1068 this->m_typeProfilerLog.reset(nullptr);
1069 };
1070
1071 return disableProfilerWithRespectToCount(m_typeProfilerEnabledCount, disableTypeProfiler);
1072}
1073
1074bool VM::enableControlFlowProfiler()
1075{
1076 auto enableControlFlowProfiler = [this] () {
1077 this->m_controlFlowProfiler = makeUnique<ControlFlowProfiler>();
1078 };
1079
1080 return enableProfilerWithRespectToCount(m_controlFlowProfilerEnabledCount, enableControlFlowProfiler);
1081}
1082
1083bool VM::disableControlFlowProfiler()
1084{
1085 auto disableControlFlowProfiler = [this] () {
1086 this->m_controlFlowProfiler.reset(nullptr);
1087 };
1088
1089 return disableProfilerWithRespectToCount(m_controlFlowProfilerEnabledCount, disableControlFlowProfiler);
1090}
1091
1092void VM::dumpTypeProfilerData()
1093{
1094 if (!typeProfiler())
1095 return;
1096
1097 typeProfilerLog()->processLogEntries(*this, "VM Dump Types"_s);
1098 typeProfiler()->dumpTypeProfilerData(*this);
1099}
1100
1101void VM::queueMicrotask(JSGlobalObject& globalObject, Ref<Microtask>&& task)
1102{
1103 m_microtaskQueue.append(makeUnique<QueuedTask>(*this, &globalObject, WTFMove(task)));
1104}
1105
1106void VM::callPromiseRejectionCallback(Strong<JSPromise>& promise)
1107{
1108 JSObject* callback = promise->globalObject()->unhandledRejectionCallback();
1109 if (!callback)
1110 return;
1111
1112 auto scope = DECLARE_CATCH_SCOPE(*this);
1113
1114 CallData callData;
1115 CallType callType = getCallData(*this, callback, callData);
1116 ASSERT(callType != CallType::None);
1117
1118 MarkedArgumentBuffer args;
1119 args.append(promise.get());
1120 args.append(promise->result(*this));
1121 call(promise->globalObject(), callback, callType, callData, jsNull(), args);
1122 scope.clearException();
1123}
1124
1125void VM::didExhaustMicrotaskQueue()
1126{
1127 auto unhandledRejections = WTFMove(m_aboutToBeNotifiedRejectedPromises);
1128 for (auto& promise : unhandledRejections) {
1129 if (promise->isHandled(*this))
1130 continue;
1131
1132 callPromiseRejectionCallback(promise);
1133 }
1134}
1135
1136void VM::promiseRejected(JSPromise* promise)
1137{
1138 m_aboutToBeNotifiedRejectedPromises.constructAndAppend(*this, promise);
1139}
1140
1141void VM::drainMicrotasks()
1142{
1143 do {
1144 while (!m_microtaskQueue.isEmpty()) {
1145 m_microtaskQueue.takeFirst()->run();
1146 if (m_onEachMicrotaskTick)
1147 m_onEachMicrotaskTick(*this);
1148 }
1149 didExhaustMicrotaskQueue();
1150 } while (!m_microtaskQueue.isEmpty());
1151 finalizeSynchronousJSExecution();
1152}
1153
1154void QueuedTask::run()
1155{
1156 m_microtask->run(m_globalObject.get());
1157}
1158
1159void sanitizeStackForVM(VM& vm)
1160{
1161 logSanitizeStack(vm);
1162 if (vm.topCallFrame) {
1163 auto& stackBounds = Thread::current().stack();
1164 ASSERT(vm.currentThreadIsHoldingAPILock());
1165 ASSERT_UNUSED(stackBounds, stackBounds.contains(vm.lastStackTop()));
1166 }
1167#if ENABLE(C_LOOP)
1168 vm.interpreter->cloopStack().sanitizeStack();
1169#else
1170 sanitizeStackForVMImpl(&vm);
1171#endif
1172}
1173
1174size_t VM::committedStackByteCount()
1175{
1176#if !ENABLE(C_LOOP)
1177 // When using the C stack, we don't know how many stack pages are actually
1178 // committed. So, we use the current stack usage as an estimate.
1179 uint8_t* current = bitwise_cast<uint8_t*>(currentStackPointer());
1180 uint8_t* high = bitwise_cast<uint8_t*>(Thread::current().stack().origin());
1181 return high - current;
1182#else
1183 return CLoopStack::committedByteCount();
1184#endif
1185}
1186
1187#if ENABLE(C_LOOP)
1188bool VM::ensureStackCapacityForCLoop(Register* newTopOfStack)
1189{
1190 return interpreter->cloopStack().ensureCapacityFor(newTopOfStack);
1191}
1192
1193bool VM::isSafeToRecurseSoftCLoop() const
1194{
1195 return interpreter->cloopStack().isSafeToRecurse();
1196}
1197
1198void* VM::currentCLoopStackPointer() const
1199{
1200 return interpreter->cloopStack().currentStackPointer();
1201}
1202#endif // ENABLE(C_LOOP)
1203
1204#if ENABLE(EXCEPTION_SCOPE_VERIFICATION)
1205void VM::verifyExceptionCheckNeedIsSatisfied(unsigned recursionDepth, ExceptionEventLocation& location)
1206{
1207 if (!Options::validateExceptionChecks())
1208 return;
1209
1210 if (UNLIKELY(m_needExceptionCheck)) {
1211 auto throwDepth = m_simulatedThrowPointRecursionDepth;
1212 auto& throwLocation = m_simulatedThrowPointLocation;
1213
1214 dataLog(
1215 "ERROR: Unchecked JS exception:\n"
1216 " This scope can throw a JS exception: ", throwLocation, "\n"
1217 " (ExceptionScope::m_recursionDepth was ", throwDepth, ")\n"
1218 " But the exception was unchecked as of this scope: ", location, "\n"
1219 " (ExceptionScope::m_recursionDepth was ", recursionDepth, ")\n"
1220 "\n");
1221
1222 StringPrintStream out;
1223 std::unique_ptr<StackTrace> currentTrace = StackTrace::captureStackTrace(Options::unexpectedExceptionStackTraceLimit());
1224
1225 if (Options::dumpSimulatedThrows()) {
1226 out.println("The simulated exception was thrown at:");
1227 m_nativeStackTraceOfLastSimulatedThrow->dump(out, " ");
1228 out.println();
1229 }
1230 out.println("Unchecked exception detected at:");
1231 currentTrace->dump(out, " ");
1232 out.println();
1233
1234 dataLog(out.toCString());
1235 RELEASE_ASSERT(!m_needExceptionCheck);
1236 }
1237}
1238#endif
1239
1240#if USE(CF)
1241void VM::setRunLoop(CFRunLoopRef runLoop)
1242{
1243 ASSERT(runLoop);
1244 m_runLoop = runLoop;
1245 JSRunLoopTimer::Manager::shared().didChangeRunLoop(*this, runLoop);
1246}
1247#endif // USE(CF)
1248
1249ScratchBuffer* VM::scratchBufferForSize(size_t size)
1250{
1251 if (!size)
1252 return nullptr;
1253
1254 auto locker = holdLock(m_scratchBufferLock);
1255
1256 if (size > m_sizeOfLastScratchBuffer) {
1257 // Protect against a N^2 memory usage pathology by ensuring
1258 // that at worst, we get a geometric series, meaning that the
1259 // total memory usage is somewhere around
1260 // max(scratch buffer size) * 4.
1261 m_sizeOfLastScratchBuffer = size * 2;
1262
1263 ScratchBuffer* newBuffer = ScratchBuffer::create(m_sizeOfLastScratchBuffer);
1264 RELEASE_ASSERT(newBuffer);
1265 m_scratchBuffers.append(newBuffer);
1266 }
1267
1268 ScratchBuffer* result = m_scratchBuffers.last();
1269 return result;
1270}
1271
1272void VM::clearScratchBuffers()
1273{
1274 auto lock = holdLock(m_scratchBufferLock);
1275 for (auto* scratchBuffer : m_scratchBuffers)
1276 scratchBuffer->setActiveLength(0);
1277}
1278
1279void VM::ensureShadowChicken()
1280{
1281 if (m_shadowChicken)
1282 return;
1283 m_shadowChicken = makeUnique<ShadowChicken>();
1284}
1285
1286#define DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(name, heapCellType, type) \
1287 IsoSubspace* VM::name##Slow() \
1288 { \
1289 ASSERT(!m_##name); \
1290 auto space = makeUnique<IsoSubspace> ISO_SUBSPACE_INIT(heap, heapCellType, type); \
1291 WTF::storeStoreFence(); \
1292 m_##name = WTFMove(space); \
1293 return m_##name.get(); \
1294 }
1295
1296
1297DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(boundFunctionSpace, cellHeapCellType.get(), JSBoundFunction) // Hash:0xd7916d41
1298DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(callbackFunctionSpace, destructibleObjectHeapCellType.get(), JSCallbackFunction) // Hash:0xe7648ebc
1299DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(customGetterSetterFunctionSpace, cellHeapCellType.get(), JSCustomGetterSetterFunction) // Hash:0x18091000
1300DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(errorInstanceSpace, destructibleObjectHeapCellType.get(), ErrorInstance) // Hash:0x3f40d4a
1301DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(functionRareDataSpace, destructibleCellHeapCellType.get(), FunctionRareData)
1302DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(nativeStdFunctionSpace, cellHeapCellType.get(), JSNativeStdFunction) // Hash:0x70ed61e4
1303DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(proxyObjectSpace, cellHeapCellType.get(), ProxyObject)
1304DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(proxyRevokeSpace, destructibleObjectHeapCellType.get(), ProxyRevoke) // Hash:0xb506a939
1305DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(symbolSpace, destructibleCellHeapCellType.get(), Symbol)
1306DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(unlinkedEvalCodeBlockSpace, destructibleCellHeapCellType.get(), UnlinkedEvalCodeBlock)
1307DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(unlinkedFunctionCodeBlockSpace, destructibleCellHeapCellType.get(), UnlinkedFunctionCodeBlock)
1308DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(unlinkedModuleProgramCodeBlockSpace, destructibleCellHeapCellType.get(), UnlinkedModuleProgramCodeBlock)
1309DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(unlinkedProgramCodeBlockSpace, destructibleCellHeapCellType.get(), UnlinkedProgramCodeBlock)
1310DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(weakMapSpace, destructibleObjectHeapCellType.get(), JSWeakMap) // Hash:0x662b12a3
1311DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(weakSetSpace, destructibleObjectHeapCellType.get(), JSWeakSet) // Hash:0x4c781b30
1312DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(weakObjectRefSpace, cellHeapCellType.get(), JSWeakObjectRef) // Hash:0x8ec68f1f
1313#if JSC_OBJC_API_ENABLED
1314DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(objCCallbackFunctionSpace, destructibleObjectHeapCellType.get(), ObjCCallbackFunction) // Hash:0x10f610b8
1315#endif
1316#if ENABLE(WEBASSEMBLY)
1317DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(webAssemblyCodeBlockSpace, webAssemblyCodeBlockHeapCellType.get(), JSWebAssemblyCodeBlock) // Hash:0x9ad995cd
1318DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(webAssemblyFunctionSpace, webAssemblyFunctionHeapCellType.get(), WebAssemblyFunction) // Hash:0x8b7c32db
1319DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(webAssemblyMemorySpace, destructibleObjectHeapCellType.get(), JSWebAssemblyMemory)
1320DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(webAssemblyWrapperFunctionSpace, cellHeapCellType.get(), WebAssemblyWrapperFunction) // Hash:0xd4a5ff01
1321#endif
1322
1323#undef DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW
1324
1325#define DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER_SLOW(name, heapCellType, type) \
1326 IsoSubspace* VM::name##Slow() \
1327 { \
1328 ASSERT(!m_##name); \
1329 auto space = makeUnique<SpaceAndSet> ISO_SUBSPACE_INIT(heap, heapCellType, type); \
1330 WTF::storeStoreFence(); \
1331 m_##name = WTFMove(space); \
1332 return &m_##name->space; \
1333 }
1334
1335DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER_SLOW(evalExecutableSpace, destructibleCellHeapCellType.get(), EvalExecutable) // Hash:0x958e3e9d
1336DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER_SLOW(moduleProgramExecutableSpace, destructibleCellHeapCellType.get(), ModuleProgramExecutable) // Hash:0x6506fa3c
1337
1338#undef DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER_SLOW
1339
1340Structure* VM::setIteratorStructureSlow()
1341{
1342 ASSERT(!m_setIteratorStructure);
1343 m_setIteratorStructure.set(*this, JSSetIterator::createStructure(*this, 0, jsNull()));
1344 return m_setIteratorStructure.get();
1345}
1346
1347Structure* VM::mapIteratorStructureSlow()
1348{
1349 ASSERT(!m_mapIteratorStructure);
1350 m_mapIteratorStructure.set(*this, JSMapIterator::createStructure(*this, 0, jsNull()));
1351 return m_mapIteratorStructure.get();
1352}
1353
1354JSCell* VM::sentinelSetBucketSlow()
1355{
1356 ASSERT(!m_sentinelSetBucket);
1357 auto* sentinel = JSSet::BucketType::createSentinel(*this);
1358 m_sentinelSetBucket.set(*this, sentinel);
1359 return sentinel;
1360}
1361
1362JSCell* VM::sentinelMapBucketSlow()
1363{
1364 ASSERT(!m_sentinelMapBucket);
1365 auto* sentinel = JSMap::BucketType::createSentinel(*this);
1366 m_sentinelMapBucket.set(*this, sentinel);
1367 return sentinel;
1368}
1369
1370JSPropertyNameEnumerator* VM::emptyPropertyNameEnumeratorSlow()
1371{
1372 ASSERT(!m_emptyPropertyNameEnumerator);
1373 PropertyNameArray propertyNames(*this, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
1374 auto* enumerator = JSPropertyNameEnumerator::create(*this, nullptr, 0, 0, WTFMove(propertyNames));
1375 m_emptyPropertyNameEnumerator.set(*this, enumerator);
1376 return enumerator;
1377}
1378
1379JSGlobalObject* VM::deprecatedVMEntryGlobalObject(JSGlobalObject* globalObject) const
1380{
1381 if (entryScope)
1382 return entryScope->globalObject();
1383 return globalObject;
1384}
1385
1386void VM::setCrashOnVMCreation(bool shouldCrash)
1387{
1388 vmCreationShouldCrash = shouldCrash;
1389}
1390
1391} // namespace JSC
1392