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