diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/runtime/VM.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/runtime/VM.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/VM.cpp | 729 |
1 files changed, 322 insertions, 407 deletions
diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp index de96ca07f..d7e50ed61 100644 --- a/Source/JavaScriptCore/runtime/VM.cpp +++ b/Source/JavaScriptCore/runtime/VM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2011, 2013-2016 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2011, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -31,78 +31,54 @@ #include "ArgList.h" #include "ArrayBufferNeuteringWatchpoint.h" -#include "BuiltinExecutables.h" -#include "BytecodeIntrinsicRegistry.h" +#include "CallFrameInlines.h" #include "CodeBlock.h" #include "CodeCache.h" #include "CommonIdentifiers.h" -#include "CommonSlowPaths.h" -#include "CustomGetterSetter.h" #include "DFGLongLivedState.h" #include "DFGWorklist.h" -#include "Disassembler.h" +#include "DebuggerActivation.h" #include "ErrorInstance.h" -#include "Exception.h" #include "FTLThunks.h" #include "FunctionConstructor.h" #include "GCActivityCallback.h" -#include "GeneratorFrame.h" #include "GetterSetter.h" #include "Heap.h" #include "HeapIterationScope.h" #include "HostCallReturnValue.h" #include "Identifier.h" #include "IncrementalSweeper.h" -#include "InferredTypeTable.h" #include "Interpreter.h" -#include "JITCode.h" #include "JSAPIValueWrapper.h" +#include "JSActivation.h" #include "JSArray.h" -#include "JSCInlines.h" #include "JSFunction.h" #include "JSGlobalObjectFunctions.h" -#include "JSInternalPromiseDeferred.h" -#include "JSLexicalEnvironment.h" #include "JSLock.h" +#include "JSNameScope.h" #include "JSNotAnObject.h" #include "JSPromiseDeferred.h" -#include "JSPropertyNameEnumerator.h" -#include "JSTemplateRegistryKey.h" +#include "JSPromiseReaction.h" +#include "JSPropertyNameIterator.h" #include "JSWithScope.h" #include "Lexer.h" #include "Lookup.h" #include "MapData.h" -#include "NativeStdFunctionCell.h" #include "Nodes.h" -#include "Parser.h" -#include "ProfilerDatabase.h" -#include "PropertyMapHashTable.h" +#include "ParserArena.h" #include "RegExpCache.h" #include "RegExpObject.h" -#include "RegisterAtOffsetList.h" -#include "RuntimeType.h" -#include "SamplingProfiler.h" #include "SimpleTypedArrayController.h" #include "SourceProviderCache.h" -#include "StackVisitor.h" #include "StrictEvalActivation.h" #include "StrongInlines.h" -#include "StructureInlines.h" -#include "TypeProfiler.h" -#include "TypeProfilerLog.h" #include "UnlinkedCodeBlock.h" -#include "VMEntryScope.h" -#include "Watchdog.h" -#include "WeakGCMapInlines.h" #include "WeakMapData.h" -#include <wtf/CurrentTime.h> #include <wtf/ProcessID.h> #include <wtf/RetainPtr.h> #include <wtf/StringPrintStream.h> #include <wtf/Threading.h> #include <wtf/WTFThreadData.h> -#include <wtf/text/AtomicStringTable.h> -#include <wtf/text/SymbolRegistry.h> #if ENABLE(DFG_JIT) #include "ConservativeRoots.h" @@ -120,6 +96,28 @@ using namespace WTF; namespace JSC { +extern const HashTable arrayConstructorTable; +extern const HashTable arrayPrototypeTable; +extern const HashTable booleanPrototypeTable; +extern const HashTable jsonTable; +extern const HashTable dataViewTable; +extern const HashTable dateTable; +extern const HashTable dateConstructorTable; +extern const HashTable errorPrototypeTable; +extern const HashTable globalObjectTable; +extern const HashTable numberConstructorTable; +extern const HashTable numberPrototypeTable; +JS_EXPORTDATA extern const HashTable objectConstructorTable; +extern const HashTable privateNamePrototypeTable; +extern const HashTable regExpTable; +extern const HashTable regExpConstructorTable; +extern const HashTable regExpPrototypeTable; +extern const HashTable stringConstructorTable; +#if ENABLE(PROMISES) +extern const HashTable promisePrototypeTable; +extern const HashTable promiseConstructorTable; +#endif + // Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either // ENABLE(JIT) or ENABLE(YARR_JIT) or both are enabled. The code below // just checks for ENABLE(JIT) or ENABLE(YARR_JIT) with this premise in mind. @@ -136,6 +134,20 @@ static bool enableAssembler(ExecutableAllocator& executableAllocator) return false; } +#if USE(CF) +#if COMPILER(GCC) && !COMPILER(CLANG) + // FIXME: remove this once the EWS have been upgraded to LLVM. + // Work around a bug of GCC with strict-aliasing. + RetainPtr<CFStringRef> canUseJITKeyRetain = adoptCF(CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman)); + CFStringRef canUseJITKey = canUseJITKeyRetain.get(); +#else + CFStringRef canUseJITKey = CFSTR("JavaScriptCoreUseJIT"); +#endif // COMPILER(GCC) && !COMPILER(CLANG) + RetainPtr<CFTypeRef> canUseJIT = adoptCF(CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication)); + if (canUseJIT) + return kCFBooleanTrue == canUseJIT.get(); +#endif + #if USE(CF) || OS(UNIX) char* canUseJITString = getenv("JavaScriptCoreUseJIT"); return !canUseJITString || atoi(canUseJITString); @@ -153,14 +165,33 @@ VM::VM(VMType vmType, HeapType heapType) , heap(this, heapType) , vmType(vmType) , clientData(0) - , topVMEntryFrame(nullptr) , topCallFrame(CallFrame::noCaller()) - , m_atomicStringTable(vmType == Default ? wtfThreadData().atomicStringTable() : new AtomicStringTable) - , propertyNames(nullptr) + , arrayConstructorTable(adoptPtr(new HashTable(JSC::arrayConstructorTable))) + , arrayPrototypeTable(adoptPtr(new HashTable(JSC::arrayPrototypeTable))) + , booleanPrototypeTable(adoptPtr(new HashTable(JSC::booleanPrototypeTable))) + , dataViewTable(adoptPtr(new HashTable(JSC::dataViewTable))) + , dateTable(adoptPtr(new HashTable(JSC::dateTable))) + , dateConstructorTable(adoptPtr(new HashTable(JSC::dateConstructorTable))) + , errorPrototypeTable(adoptPtr(new HashTable(JSC::errorPrototypeTable))) + , globalObjectTable(adoptPtr(new HashTable(JSC::globalObjectTable))) + , jsonTable(adoptPtr(new HashTable(JSC::jsonTable))) + , numberConstructorTable(adoptPtr(new HashTable(JSC::numberConstructorTable))) + , numberPrototypeTable(adoptPtr(new HashTable(JSC::numberPrototypeTable))) + , objectConstructorTable(adoptPtr(new HashTable(JSC::objectConstructorTable))) + , privateNamePrototypeTable(adoptPtr(new HashTable(JSC::privateNamePrototypeTable))) + , regExpTable(adoptPtr(new HashTable(JSC::regExpTable))) + , regExpConstructorTable(adoptPtr(new HashTable(JSC::regExpConstructorTable))) + , regExpPrototypeTable(adoptPtr(new HashTable(JSC::regExpPrototypeTable))) + , stringConstructorTable(adoptPtr(new HashTable(JSC::stringConstructorTable))) +#if ENABLE(PROMISES) + , promisePrototypeTable(adoptPtr(new HashTable(JSC::promisePrototypeTable))) + , promiseConstructorTable(adoptPtr(new HashTable(JSC::promiseConstructorTable))) +#endif + , identifierTable(vmType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable()) + , propertyNames(new CommonIdentifiers(this)) , emptyList(new MarkedArgumentBuffer) - , customGetterSetterFunctionMap(*this) - , stringCache(*this) - , prototypeMap(*this) + , parserArena(adoptPtr(new ParserArena)) + , keywords(adoptPtr(new Keywords(*this))) , interpreter(0) , jsArrayClassInfo(JSArray::info()) , jsFinalObjectClassInfo(JSFinalObject::info()) @@ -170,6 +201,8 @@ VM::VM(VMType vmType, HeapType heapType) #if ENABLE(REGEXP_TRACING) , m_rtTraceList(new RTTraceList()) #endif + , exclusiveThread(0) + , m_newStringsSinceLastHashCons(0) #if ENABLE(ASSEMBLER) , m_canUseAssembler(enableAssembler(executableAllocator)) #endif @@ -182,43 +215,29 @@ VM::VM(VMType vmType, HeapType heapType) #if ENABLE(GC_VALIDATION) , m_initializingObjectClass(0) #endif - , m_stackPointerAtVMEntry(0) , m_stackLimit(0) -#if !ENABLE(JIT) +#if USE(SEPARATE_C_AND_JS_STACK) , m_jsStackLimit(0) #endif -#if ENABLE(FTL_JIT) - , m_ftlStackLimit(0) - , m_largestFTLStackSize(0) -#endif , m_inDefineOwnProperty(false) - , m_codeCache(std::make_unique<CodeCache>()) + , m_codeCache(CodeCache::create()) , m_enabledProfiler(nullptr) - , m_builtinExecutables(std::make_unique<BuiltinExecutables>(*this)) - , m_typeProfilerEnabledCount(0) - , m_controlFlowProfilerEnabledCount(0) { interpreter = new Interpreter(*this); StackBounds stack = wtfThreadData().stack(); - updateReservedZoneSize(Options::reservedZoneSize()); -#if !ENABLE(JIT) - interpreter->stack().setReservedZoneSize(Options::reservedZoneSize()); -#endif - setLastStackTop(stack.origin()); + setStackLimit(stack.recursionLimit()); // Need to be careful to keep everything consistent here JSLockHolder lock(this); - AtomicStringTable* existingEntryAtomicStringTable = wtfThreadData().setCurrentAtomicStringTable(m_atomicStringTable); - propertyNames = new CommonIdentifiers(this); + IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable); structureStructure.set(*this, Structure::createStructure(*this)); structureRareDataStructure.set(*this, StructureRareData::createStructure(*this, 0, jsNull())); + debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull())); terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull())); stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull())); notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull())); - propertyNameEnumeratorStructure.set(*this, JSPropertyNameEnumerator::createStructure(*this, 0, jsNull())); + propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull())); getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull())); - customGetterSetterStructure.set(*this, CustomGetterSetter::createStructure(*this, 0, jsNull())); - scopedArgumentsTableStructure.set(*this, ScopedArgumentsTable::createStructure(*this, 0, jsNull())); apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull())); JSScopeStructure.set(*this, JSScope::createStructure(*this, 0, jsNull())); executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull())); @@ -226,138 +245,84 @@ VM::VM(VMType vmType, HeapType heapType) evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, 0, jsNull())); programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull())); functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull())); -#if ENABLE(WEBASSEMBLY) - webAssemblyExecutableStructure.set(*this, WebAssemblyExecutable::createStructure(*this, 0, jsNull())); -#endif - moduleProgramExecutableStructure.set(*this, ModuleProgramExecutable::createStructure(*this, 0, jsNull())); regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull())); - symbolStructure.set(*this, Symbol::createStructure(*this, 0, jsNull())); symbolTableStructure.set(*this, SymbolTable::createStructure(*this, 0, jsNull())); structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull())); sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull())); - templateRegistryKeyStructure.set(*this, JSTemplateRegistryKey::createStructure(*this, 0, jsNull())); arrayBufferNeuteringWatchpointStructure.set(*this, ArrayBufferNeuteringWatchpoint::createStructure(*this)); + withScopeStructure.set(*this, JSWithScope::createStructure(*this, 0, jsNull())); unlinkedFunctionExecutableStructure.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull())); unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull())); unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull())); unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull())); - unlinkedModuleProgramCodeBlockStructure.set(*this, UnlinkedModuleProgramCodeBlock::createStructure(*this, 0, jsNull())); propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull())); + mapDataStructure.set(*this, MapData::createStructure(*this, 0, jsNull())); weakMapDataStructure.set(*this, WeakMapData::createStructure(*this, 0, jsNull())); - inferredValueStructure.set(*this, InferredValue::createStructure(*this, 0, jsNull())); - inferredTypeStructure.set(*this, InferredType::createStructure(*this, 0, jsNull())); - inferredTypeTableStructure.set(*this, InferredTypeTable::createStructure(*this, 0, jsNull())); - functionRareDataStructure.set(*this, FunctionRareData::createStructure(*this, 0, jsNull())); - generatorFrameStructure.set(*this, GeneratorFrame::createStructure(*this, 0, jsNull())); - exceptionStructure.set(*this, Exception::createStructure(*this, 0, jsNull())); promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull())); - internalPromiseDeferredStructure.set(*this, JSInternalPromiseDeferred::createStructure(*this, 0, jsNull())); - programCodeBlockStructure.set(*this, ProgramCodeBlock::createStructure(*this, 0, jsNull())); - moduleProgramCodeBlockStructure.set(*this, ModuleProgramCodeBlock::createStructure(*this, 0, jsNull())); - evalCodeBlockStructure.set(*this, EvalCodeBlock::createStructure(*this, 0, jsNull())); - functionCodeBlockStructure.set(*this, FunctionCodeBlock::createStructure(*this, 0, jsNull())); -#if ENABLE(WEBASSEMBLY) - webAssemblyCodeBlockStructure.set(*this, WebAssemblyCodeBlock::createStructure(*this, 0, jsNull())); -#endif - + promiseReactionStructure.set(*this, JSPromiseReaction::createStructure(*this, 0, jsNull())); iterationTerminator.set(*this, JSFinalObject::create(*this, JSFinalObject::createStructure(*this, 0, jsNull(), 1))); - nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull())); smallStrings.initializeCommonStrings(*this); - wtfThreadData().setCurrentAtomicStringTable(existingEntryAtomicStringTable); + wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable); #if ENABLE(JIT) - jitStubs = std::make_unique<JITThunks>(); - allCalleeSaveRegisterOffsets = std::make_unique<RegisterAtOffsetList>(RegisterSet::vmCalleeSaveRegisters(), RegisterAtOffsetList::ZeroBased); + jitStubs = adoptPtr(new JITThunks()); #endif - arityCheckData = std::make_unique<CommonSlowPaths::ArityCheckData>(); #if ENABLE(FTL_JIT) ftlThunks = std::make_unique<FTL::Thunks>(); #endif // ENABLE(FTL_JIT) - interpreter->initialize(); + interpreter->initialize(this->canUseJIT()); #if ENABLE(JIT) initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support. #endif heap.notifyIsSafeToCollect(); - + LLInt::Data::performAssertions(*this); - if (Options::useProfiler()) { - m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*this); + if (Options::enableProfiler()) { + m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*this)); StringPrintStream pathOut; +#if !OS(WINCE) const char* profilerPath = getenv("JSC_PROFILER_PATH"); if (profilerPath) pathOut.print(profilerPath, "/"); +#endif pathOut.print("JSCProfile-", getCurrentProcessID(), "-", m_perBytecodeProfiler->databaseID(), ".json"); m_perBytecodeProfiler->registerToSaveAtExit(pathOut.toCString().data()); } - callFrameForCatch = nullptr; - #if ENABLE(DFG_JIT) if (canUseJIT()) - dfgState = std::make_unique<DFG::LongLivedState>(); + dfgState = adoptPtr(new DFG::LongLivedState()); #endif // Initialize this last, as a free way of asserting that VM initialization itself // won't use this. m_typedArrayController = adoptRef(new SimpleTypedArrayController()); - - m_bytecodeIntrinsicRegistry = std::make_unique<BytecodeIntrinsicRegistry>(*this); - - if (Options::useTypeProfiler()) - enableTypeProfiler(); - if (Options::useControlFlowProfiler()) - enableControlFlowProfiler(); -#if ENABLE(SAMPLING_PROFILER) - if (Options::useSamplingProfiler()) { - setShouldBuildPCToCodeOriginMapping(); - m_samplingProfiler = adoptRef(new SamplingProfiler(*this, Stopwatch::create())); - m_samplingProfiler->start(); - } -#endif // ENABLE(SAMPLING_PROFILER) - - if (Options::alwaysGeneratePCToCodeOriginMap()) - setShouldBuildPCToCodeOriginMapping(); - - if (Options::watchdog()) { - std::chrono::milliseconds timeoutMillis(Options::watchdog()); - Watchdog& watchdog = ensureWatchdog(); - watchdog.setTimeLimit(timeoutMillis); - } } VM::~VM() { // Never GC, ever again. heap.incrementDeferralDepth(); - -#if ENABLE(SAMPLING_PROFILER) - if (m_samplingProfiler) - m_samplingProfiler->shutdown(); -#endif // ENABLE(SAMPLING_PROFILER) #if ENABLE(DFG_JIT) // Make sure concurrent compilations are done, but don't install them, since there is // no point to doing so. - for (unsigned i = DFG::numberOfWorklists(); i--;) { - if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) { - worklist->waitUntilAllPlansForVMAreReady(*this); - worklist->removeAllReadyPlansForVM(*this); - } + if (worklist) { + worklist->waitUntilAllPlansForVMAreReady(*this); + worklist->removeAllReadyPlansForVM(*this); } #endif // ENABLE(DFG_JIT) - waitForAsynchronousDisassembly(); - // Clear this first to ensure that nobody tries to remove themselves from it. - m_perBytecodeProfiler = nullptr; - + m_perBytecodeProfiler.clear(); + ASSERT(m_apiLock->currentThreadIsHoldingLock()); m_apiLock->willDestroyVM(this); heap.lastChanceToFinalize(); @@ -367,11 +332,33 @@ VM::~VM() interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef); #endif + arrayPrototypeTable->deleteTable(); + arrayConstructorTable->deleteTable(); + booleanPrototypeTable->deleteTable(); + dataViewTable->deleteTable(); + dateTable->deleteTable(); + dateConstructorTable->deleteTable(); + errorPrototypeTable->deleteTable(); + globalObjectTable->deleteTable(); + jsonTable->deleteTable(); + numberConstructorTable->deleteTable(); + numberPrototypeTable->deleteTable(); + objectConstructorTable->deleteTable(); + privateNamePrototypeTable->deleteTable(); + regExpTable->deleteTable(); + regExpConstructorTable->deleteTable(); + regExpPrototypeTable->deleteTable(); + stringConstructorTable->deleteTable(); +#if ENABLE(PROMISES) + promisePrototypeTable->deleteTable(); + promiseConstructorTable->deleteTable(); +#endif + delete emptyList; delete propertyNames; if (vmType != Default) - delete m_atomicStringTable; + deleteIdentifierTable(identifierTable); delete clientData; delete m_regExpCache; @@ -385,22 +372,17 @@ VM::~VM() #endif } -void VM::setLastStackTop(void* lastStackTop) -{ - m_lastStackTop = lastStackTop; -} - -Ref<VM> VM::createContextGroup(HeapType heapType) +PassRefPtr<VM> VM::createContextGroup(HeapType heapType) { - return adoptRef(*new VM(APIContextGroup, heapType)); + return adoptRef(new VM(APIContextGroup, heapType)); } -Ref<VM> VM::create(HeapType heapType) +PassRefPtr<VM> VM::create(HeapType heapType) { - return adoptRef(*new VM(Default, heapType)); + return adoptRef(new VM(Default, heapType)); } -Ref<VM> VM::createLeaked(HeapType heapType) +PassRefPtr<VM> VM::createLeaked(HeapType heapType) { return create(heapType); } @@ -414,8 +396,10 @@ VM& VM::sharedInstance() { GlobalJSLock globalLock; VM*& instance = sharedInstanceInternal(); - if (!instance) + if (!instance) { instance = adoptRef(new VM(APIShared, SmallHeap)).leakRef(); + instance->makeUsableFromMultipleThreads(); + } return *instance; } @@ -425,32 +409,6 @@ VM*& VM::sharedInstanceInternal() return sharedInstance; } -Watchdog& VM::ensureWatchdog() -{ - if (!m_watchdog) { - m_watchdog = adoptRef(new Watchdog()); - - // The LLINT peeks into the Watchdog object directly. In order to do that, - // the LLINT assumes that the internal shape of a std::unique_ptr is the - // same as a plain C++ pointer, and loads the address of Watchdog from it. - RELEASE_ASSERT(*reinterpret_cast<Watchdog**>(&m_watchdog) == m_watchdog.get()); - - // And if we've previously compiled any functions, we need to revert - // them because they don't have the needed polling checks for the watchdog - // yet. - deleteAllCode(); - } - return *m_watchdog; -} - -#if ENABLE(SAMPLING_PROFILER) -void VM::ensureSamplingProfiler(RefPtr<Stopwatch>&& stopwatch) -{ - if (!m_samplingProfiler) - m_samplingProfiler = adoptRef(new SamplingProfiler(*this, WTFMove(stopwatch))); -} -#endif // ENABLE(SAMPLING_PROFILER) - #if ENABLE(JIT) static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) { @@ -459,8 +417,6 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) return charCodeAtThunkGenerator; case CharAtIntrinsic: return charAtThunkGenerator; - case Clz32Intrinsic: - return clz32ThunkGenerator; case FromCharCodeIntrinsic: return fromCharCodeThunkGenerator; case SqrtIntrinsic: @@ -481,31 +437,33 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) return logThunkGenerator; case IMulIntrinsic: return imulThunkGenerator; - case RandomIntrinsic: - return randomThunkGenerator; + case ArrayIteratorNextKeyIntrinsic: + return arrayIteratorNextKeyThunkGenerator; + case ArrayIteratorNextValueIntrinsic: + return arrayIteratorNextValueThunkGenerator; default: return 0; } } -NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor, const String& name) +NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor) { - return jitStubs->hostFunctionStub(this, function, constructor, name); + return jitStubs->hostFunctionStub(this, function, constructor); } -NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic, const String& name) +NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic) { ASSERT(canUseJIT()); - return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic, name); + return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic); } #else // !ENABLE(JIT) -NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor, const String& name) +NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor) { return NativeExecutable::create(*this, - adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_call_trampoline), JITCode::HostCallThunk)), function, - adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_construct_trampoline), JITCode::HostCallThunk)), constructor, - NoIntrinsic, name); + MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_call_trampoline), function, + MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_construct_trampoline), constructor, + NoIntrinsic); } #endif // !ENABLE(JIT) @@ -518,7 +476,7 @@ void VM::resetDateCache() { localTimeOffsetCache.reset(); cachedDateString = String(); - cachedDateStringValue = std::numeric_limits<double>::quiet_NaN(); + cachedDateStringValue = QNaN; dateInstanceCache.reset(); } @@ -532,33 +490,22 @@ void VM::stopSampling() interpreter->stopSampling(); } -void VM::whenIdle(std::function<void()> callback) +void VM::prepareToDiscardCode() { - if (!entryScope) { - callback(); +#if ENABLE(DFG_JIT) + if (!worklist) return; - } - - entryScope->addDidPopListener(callback); -} - -void VM::deleteAllLinkedCode() -{ - whenIdle([this]() { - heap.deleteAllCodeBlocks(); - heap.reportAbandonedObjectGraph(); - }); + + worklist->completeAllPlansForVM(*this); +#endif } -void VM::deleteAllCode() +void VM::discardAllCode() { - whenIdle([this]() { - m_codeCache->clear(); - m_regExpCache->deleteAllCode(); - heap.deleteAllCodeBlocks(); - heap.deleteAllUnlinkedCodeBlocks(); - heap.reportAbandonedObjectGraph(); - }); + prepareToDiscardCode(); + m_codeCache->clear(); + heap.deleteAllCompiledCode(); + heap.reportAbandonedObjectGraph(); } void VM::dumpSampleData(ExecState* exec) @@ -582,115 +529,187 @@ void VM::clearSourceProviderCaches() sourceProviderCacheMap.clear(); } -void VM::throwException(ExecState* exec, Exception* exception) -{ - if (Options::breakOnThrow()) { - dataLog("In call frame ", RawPointer(exec), " for code block ", *exec->codeBlock(), "\n"); - CRASH(); +struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor { + HashSet<FunctionExecutable*> currentlyExecutingFunctions; + void operator()(JSCell* cell) + { + if (!cell->inherits(FunctionExecutable::info())) + return; + FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); + if (currentlyExecutingFunctions.contains(executable)) + return; + executable->clearCodeIfNotCompiling(); } +}; - ASSERT(exec == topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec()); - - interpreter->notifyDebuggerOfExceptionToBeThrown(exec, exception); - - setException(exception); +void VM::releaseExecutableMemory() +{ + prepareToDiscardCode(); + + if (entryScope) { + StackPreservingRecompiler recompiler; + HeapIterationScope iterationScope(heap); + HashSet<JSCell*> roots; + heap.getConservativeRegisterRoots(roots); + HashSet<JSCell*>::iterator end = roots.end(); + for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) { + ScriptExecutable* executable = 0; + JSCell* cell = *ptr; + if (cell->inherits(ScriptExecutable::info())) + executable = static_cast<ScriptExecutable*>(*ptr); + else if (cell->inherits(JSFunction::info())) { + JSFunction* function = jsCast<JSFunction*>(*ptr); + if (function->isHostFunction()) + continue; + executable = function->jsExecutable(); + } else + continue; + ASSERT(executable->inherits(ScriptExecutable::info())); + executable->unlinkCalls(); + if (executable->inherits(FunctionExecutable::info())) + recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable)); + + } + heap.objectSpace().forEachLiveCell<StackPreservingRecompiler>(iterationScope, recompiler); + } + m_regExpCache->invalidateCode(); + heap.collectAllGarbage(); } -JSValue VM::throwException(ExecState* exec, JSValue thrownValue) +static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset) { - Exception* exception = jsDynamicCast<Exception*>(thrownValue); - if (!exception) - exception = Exception::create(*this, thrownValue); - - throwException(exec, exception); - return JSValue(exception); + exception->clearAppendSourceToMessage(); + + if (!callFrame->codeBlock()->hasExpressionInfo()) + return; + + int startOffset = 0; + int endOffset = 0; + int divotPoint = 0; + unsigned line = 0; + unsigned column = 0; + + CodeBlock* codeBlock = callFrame->codeBlock(); + codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column); + + int expressionStart = divotPoint - startOffset; + int expressionStop = divotPoint + endOffset; + + const String& sourceString = codeBlock->source()->source(); + if (!expressionStop || expressionStart > static_cast<int>(sourceString.length())) + return; + + VM* vm = &callFrame->vm(); + JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message); + if (!jsMessage || !jsMessage.isString()) + return; + + String message = asString(jsMessage)->value(callFrame); + + if (expressionStart < expressionStop) + message = makeString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')"); + else { + // No range information, so give a few characters of context. + const StringImpl* data = sourceString.impl(); + int dataLength = sourceString.length(); + int start = expressionStart; + int stop = expressionStart; + // Get up to 20 characters of context to the left and right of the divot, clamping to the line. + // Then strip whitespace. + while (start > 0 && (expressionStart - start < 20) && (*data)[start - 1] != '\n') + start--; + while (start < (expressionStart - 1) && isStrWhiteSpace((*data)[start])) + start++; + while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n') + stop++; + while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1])) + stop--; + message = makeString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')"); + } + + exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message)); } + +JSValue VM::throwException(ExecState* exec, JSValue error) +{ + ASSERT(exec == topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec()); + + Vector<StackFrame> stackTrace; + interpreter->getStackTrace(stackTrace); + m_exceptionStack = RefCountedArray<StackFrame>(stackTrace); + m_exception = error; + + if (stackTrace.isEmpty() || !error.isObject()) + return error; + JSObject* exception = asObject(error); + + StackFrame stackFrame; + for (unsigned i = 0 ; i < stackTrace.size(); ++i) { + stackFrame = stackTrace.at(i); + if (stackFrame.bytecodeOffset) + break; + } + unsigned bytecodeOffset = stackFrame.bytecodeOffset; + if (!hasErrorInfo(exec, exception)) { + // FIXME: We should only really be adding these properties to VM generated exceptions, + // but the inspector currently requires these for all thrown objects. + unsigned line; + unsigned column; + stackFrame.computeLineAndColumn(line, column); + exception->putDirect(*this, Identifier(this, "line"), jsNumber(line), ReadOnly | DontDelete); + exception->putDirect(*this, Identifier(this, "column"), jsNumber(column), ReadOnly | DontDelete); + if (!stackFrame.sourceURL.isEmpty()) + exception->putDirect(*this, Identifier(this, "sourceURL"), jsString(this, stackFrame.sourceURL), ReadOnly | DontDelete); + } + if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage()) { + unsigned stackIndex = 0; + CallFrame* callFrame; + for (callFrame = exec; callFrame && !callFrame->codeBlock(); ) { + stackIndex++; + callFrame = callFrame->callerFrameSkippingVMEntrySentinel(); + } + if (callFrame && callFrame->codeBlock()) { + stackFrame = stackTrace.at(stackIndex); + bytecodeOffset = stackFrame.bytecodeOffset; + appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset); + } + } + if (exception->hasProperty(exec, this->propertyNames->stack)) + return error; + + exception->putDirect(*this, propertyNames->stack, interpreter->stackTraceAsString(topCallFrame, stackTrace), DontEnum); + return error; +} + JSObject* VM::throwException(ExecState* exec, JSObject* error) { return asObject(throwException(exec, JSValue(error))); } - -void VM::setStackPointerAtVMEntry(void* sp) +void VM::getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack) { - m_stackPointerAtVMEntry = sp; - updateStackLimit(); + exception = m_exception; + exceptionStack = m_exceptionStack; } - -size_t VM::updateReservedZoneSize(size_t reservedZoneSize) +void VM::setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack) { - size_t oldReservedZoneSize = m_reservedZoneSize; - m_reservedZoneSize = reservedZoneSize; - - updateStackLimit(); - - return oldReservedZoneSize; + m_exception = exception; + m_exceptionStack = exceptionStack; } -#if PLATFORM(WIN) -// On Windows the reserved stack space consists of committed memory, a guard page, and uncommitted memory, -// where the guard page is a barrier between committed and uncommitted memory. -// When data from the guard page is read or written, the guard page is moved, and memory is committed. -// This is how the system grows the stack. -// When using the C stack on Windows we need to precommit the needed stack space. -// Otherwise we might crash later if we access uncommitted stack memory. -// This can happen if we allocate stack space larger than the page guard size (4K). -// The system does not get the chance to move the guard page, and commit more memory, -// and we crash if uncommitted memory is accessed. -// The MSVC compiler fixes this by inserting a call to the _chkstk() function, -// when needed, see http://support.microsoft.com/kb/100775. -// By touching every page up to the stack limit with a dummy operation, -// we force the system to move the guard page, and commit memory. - -static void preCommitStackMemory(void* stackLimit) +void VM::clearException() { - const int pageSize = 4096; - for (volatile char* p = reinterpret_cast<char*>(&stackLimit); p > stackLimit; p -= pageSize) { - char ch = *p; - *p = ch; - } + m_exception = JSValue(); } -#endif - -inline void VM::updateStackLimit() +void VM:: clearExceptionStack() { -#if PLATFORM(WIN) - void* lastStackLimit = m_stackLimit; -#endif - - if (m_stackPointerAtVMEntry) { - ASSERT(wtfThreadData().stack().isGrowingDownward()); - char* startOfStack = reinterpret_cast<char*>(m_stackPointerAtVMEntry); -#if ENABLE(FTL_JIT) - m_stackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize + m_largestFTLStackSize); - m_ftlStackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize + 2 * m_largestFTLStackSize); -#else - m_stackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize); -#endif - } else { -#if ENABLE(FTL_JIT) - m_stackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize + m_largestFTLStackSize); - m_ftlStackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize + 2 * m_largestFTLStackSize); -#else - m_stackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize); -#endif - } - -#if PLATFORM(WIN) - if (lastStackLimit != m_stackLimit) - preCommitStackMemory(m_stackLimit); -#endif + m_exceptionStack = RefCountedArray<StackFrame>(); } -#if ENABLE(FTL_JIT) -void VM::updateFTLLargestStackSize(size_t stackSize) +void releaseExecutableMemory(VM& vm) { - if (stackSize > m_largestFTLStackSize) { - m_largestFTLStackSize = stackSize; - updateStackLimit(); - } + vm.releaseExecutableMemory(); } -#endif #if ENABLE(DFG_JIT) void VM::gatherConservativeRoots(ConservativeRoots& conservativeRoots) @@ -703,24 +722,20 @@ void VM::gatherConservativeRoots(ConservativeRoots& conservativeRoots) } } } -#endif -void logSanitizeStack(VM* vm) +DFG::Worklist* VM::ensureWorklist() { - if (Options::verboseSanitizeStack() && vm->topCallFrame) { - int dummy; - dataLog( - "Sanitizing stack with top call frame at ", RawPointer(vm->topCallFrame), - ", current stack pointer at ", RawPointer(&dummy), ", in ", - pointerDump(vm->topCallFrame->codeBlock()), " and last code origin = ", - vm->topCallFrame->codeOrigin(), "\n"); - } + if (!DFG::enableConcurrentJIT()) + return 0; + if (!worklist) + worklist = DFG::globalWorklist(); + return worklist.get(); } +#endif #if ENABLE(REGEXP_TRACING) void VM::addRegExpToTrace(RegExp* regExp) { - gcProtect(regExp); m_rtTraceList->add(regExp); } @@ -731,16 +746,14 @@ void VM::dumpRegExpTrace() if (iter != m_rtTraceList->end()) { dataLogF("\nRegExp Tracing\n"); - dataLogF("Regular Expression 8 Bit 16 Bit match() Matches Average\n"); - dataLogF(" <Match only / Match> JIT Addr JIT Address calls found String len\n"); - dataLogF("----------------------------------------+----------------+----------------+----------+----------+-----------\n"); + dataLogF(" match() matches\n"); + dataLogF("Regular Expression JIT Address calls found\n"); + dataLogF("----------------------------------------+----------------+----------+----------\n"); unsigned reCount = 0; - for (; iter != m_rtTraceList->end(); ++iter, ++reCount) { + for (; iter != m_rtTraceList->end(); ++iter, ++reCount) (*iter)->printTraceData(); - gcUnprotect(*iter); - } dataLogF("%d Regular Expressions\n", reCount); } @@ -764,15 +777,15 @@ void VM::registerWatchpointForImpureProperty(const Identifier& propertyName, Wat void VM::addImpureProperty(const String& propertyName) { if (RefPtr<WatchpointSet> watchpointSet = m_impurePropertyWatchpointSets.take(propertyName)) - watchpointSet->fireAll("Impure property added"); + watchpointSet->fireAll(); } class SetEnabledProfilerFunctor { public: bool operator()(CodeBlock* codeBlock) { - if (JITCode::isOptimizingJIT(codeBlock->jitType())) - codeBlock->jettison(Profiler::JettisonDueToLegacyProfiler); + if (codeBlock->jitType() == JITCode::DFGJIT) + codeBlock->jettison(); return false; } }; @@ -786,102 +799,4 @@ void VM::setEnabledProfiler(LegacyProfiler* profiler) } } -static bool enableProfilerWithRespectToCount(unsigned& counter, std::function<void()> doEnableWork) -{ - bool needsToRecompile = false; - if (!counter) { - doEnableWork(); - needsToRecompile = true; - } - counter++; - - return needsToRecompile; -} - -static bool disableProfilerWithRespectToCount(unsigned& counter, std::function<void()> doDisableWork) -{ - RELEASE_ASSERT(counter > 0); - bool needsToRecompile = false; - counter--; - if (!counter) { - doDisableWork(); - needsToRecompile = true; - } - - return needsToRecompile; -} - -bool VM::enableTypeProfiler() -{ - auto enableTypeProfiler = [this] () { - this->m_typeProfiler = std::make_unique<TypeProfiler>(); - this->m_typeProfilerLog = std::make_unique<TypeProfilerLog>(); - }; - - return enableProfilerWithRespectToCount(m_typeProfilerEnabledCount, enableTypeProfiler); -} - -bool VM::disableTypeProfiler() -{ - auto disableTypeProfiler = [this] () { - this->m_typeProfiler.reset(nullptr); - this->m_typeProfilerLog.reset(nullptr); - }; - - return disableProfilerWithRespectToCount(m_typeProfilerEnabledCount, disableTypeProfiler); -} - -bool VM::enableControlFlowProfiler() -{ - auto enableControlFlowProfiler = [this] () { - this->m_controlFlowProfiler = std::make_unique<ControlFlowProfiler>(); - }; - - return enableProfilerWithRespectToCount(m_controlFlowProfilerEnabledCount, enableControlFlowProfiler); -} - -bool VM::disableControlFlowProfiler() -{ - auto disableControlFlowProfiler = [this] () { - this->m_controlFlowProfiler.reset(nullptr); - }; - - return disableProfilerWithRespectToCount(m_controlFlowProfilerEnabledCount, disableControlFlowProfiler); -} - -void VM::dumpTypeProfilerData() -{ - if (!typeProfiler()) - return; - - typeProfilerLog()->processLogEntries(ASCIILiteral("VM Dump Types")); - typeProfiler()->dumpTypeProfilerData(*this); -} - -void VM::queueMicrotask(JSGlobalObject* globalObject, PassRefPtr<Microtask> task) -{ - m_microtaskQueue.append(std::make_unique<QueuedTask>(*this, globalObject, task)); -} - -void VM::drainMicrotasks() -{ - while (!m_microtaskQueue.isEmpty()) - m_microtaskQueue.takeFirst()->run(); -} - -void QueuedTask::run() -{ - m_microtask->run(m_globalObject->globalExec()); -} - -void sanitizeStackForVM(VM* vm) -{ - logSanitizeStack(vm); -#if !ENABLE(JIT) - vm->interpreter->stack().sanitizeStack(); -#else - sanitizeStackForVMImpl(vm); -#endif -} - } // namespace JSC |