]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/VM.cpp
JavaScriptCore-7600.1.4.17.5.tar.gz
[apple/javascriptcore.git] / runtime / VM.cpp
CommitLineData
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
105using namespace WTF;
106
6fe7ccc8 107namespace JSC {
14957cd0 108
6fe7ccc8
A
109extern const HashTable arrayConstructorTable;
110extern const HashTable arrayPrototypeTable;
111extern const HashTable booleanPrototypeTable;
112extern const HashTable jsonTable;
81345200 113extern const HashTable dataViewTable;
6fe7ccc8
A
114extern const HashTable dateTable;
115extern const HashTable dateConstructorTable;
116extern const HashTable errorPrototypeTable;
117extern const HashTable globalObjectTable;
6fe7ccc8
A
118extern const HashTable numberConstructorTable;
119extern const HashTable numberPrototypeTable;
120JS_EXPORTDATA extern const HashTable objectConstructorTable;
93a37866 121extern const HashTable privateNamePrototypeTable;
6fe7ccc8
A
122extern const HashTable regExpTable;
123extern const HashTable regExpConstructorTable;
124extern const HashTable regExpPrototypeTable;
6fe7ccc8 125extern const HashTable stringConstructorTable;
81345200
A
126#if ENABLE(PROMISES)
127extern const HashTable promisePrototypeTable;
128extern 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 136static 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
163VM::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 328VM::~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 396PassRefPtr<VM> VM::createContextGroup(HeapType heapType)
9dae56ea 397{
93a37866 398 return adoptRef(new VM(APIContextGroup, heapType));
f9bf01c6
A
399}
400
93a37866 401PassRefPtr<VM> VM::create(HeapType heapType)
f9bf01c6 402{
93a37866 403 return adoptRef(new VM(Default, heapType));
9dae56ea
A
404}
405
93a37866 406PassRefPtr<VM> VM::createLeaked(HeapType heapType)
9dae56ea 407{
93a37866 408 return create(heapType);
9dae56ea
A
409}
410
93a37866 411bool VM::sharedInstanceExists()
9dae56ea
A
412{
413 return sharedInstanceInternal();
414}
415
93a37866 416VM& 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 427VM*& VM::sharedInstanceInternal()
9dae56ea 428{
93a37866 429 static VM* sharedInstance;
9dae56ea
A
430 return sharedInstance;
431}
432
14957cd0 433#if ENABLE(JIT)
6fe7ccc8 434static 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 470NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor)
6fe7ccc8 471{
6fe7ccc8 472 return jitStubs->hostFunctionStub(this, function, constructor);
14957cd0 473}
93a37866 474NativeExecutable* 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 482NativeExecutable* 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 492VM::ClientData::~ClientData()
9dae56ea
A
493{
494}
495
93a37866 496void 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 504void VM::startSampling()
f9bf01c6
A
505{
506 interpreter->startSampling();
507}
508
93a37866 509void VM::stopSampling()
f9bf01c6
A
510{
511 interpreter->stopSampling();
512}
513
81345200
A
514void 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
524void 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
534void 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
542SourceProviderCache* 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
550void VM::clearSourceProviderCaches()
551{
552 sourceProviderCacheMap.clear();
553}
554
6fe7ccc8 555struct 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 568void 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 602static 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
656JSValue 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
713JSObject* VM::throwException(ExecState* exec, JSObject* error)
714{
715 return asObject(throwException(exec, JSValue(error)));
716}
717void VM::getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack)
718{
719 exception = m_exception;
720 exceptionStack = m_exceptionStack;
721}
722void VM::setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack)
723{
724 m_exception = exception;
725 m_exceptionStack = exceptionStack;
726}
727
728void VM::clearException()
729{
730 m_exception = JSValue();
731}
732void VM:: clearExceptionStack()
733{
734 m_exceptionStack = RefCountedArray<StackFrame>();
735}
736
737void VM::setStackPointerAtVMEntry(void* sp)
738{
739 m_stackPointerAtVMEntry = sp;
740 updateStackLimit();
741}
742
743size_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
768static 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
778inline 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)
809void VM::updateFTLLargestStackSize(size_t stackSize)
810{
811 if (stackSize > m_largestFTLStackSize) {
812 m_largestFTLStackSize = stackSize;
813 updateStackLimit();
814 }
815}
816#endif
817
93a37866 818void releaseExecutableMemory(VM& vm)
14957cd0 819{
93a37866 820 vm.releaseExecutableMemory();
14957cd0 821}
14957cd0 822
6fe7ccc8 823#if ENABLE(DFG_JIT)
93a37866 824void 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
836void 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 849void VM::addRegExpToTrace(RegExp* regExp)
14957cd0 850{
81345200 851 gcProtect(regExp);
14957cd0
A
852 m_rtTraceList->add(regExp);
853}
854
93a37866 855void 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 879void VM::dumpRegExpTrace()
14957cd0 880{
b80e6193 881}
14957cd0 882#endif
b80e6193 883
81345200
A
884void 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
892void VM::addImpureProperty(const String& propertyName)
893{
894 if (RefPtr<WatchpointSet> watchpointSet = m_impurePropertyWatchpointSets.take(propertyName))
895 watchpointSet->fireAll();
896}
897
898class SetEnabledProfilerFunctor {
899public:
900 bool operator()(CodeBlock* codeBlock)
901 {
902 if (JITCode::isOptimizingJIT(codeBlock->jitType()))
903 codeBlock->jettison(Profiler::JettisonDueToLegacyProfiler);
904 return false;
905 }
906};
907
908void 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
918void 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