summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/VM.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
commit32761a6cee1d0dee366b885b7b9c777e67885688 (patch)
treed6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/runtime/VM.cpp
parenta4e969f4965059196ca948db781e52f7cfebf19e (diff)
downloadWebKitGtk-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.cpp729
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