/*
- * Copyright (C) 2008, 2011, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2011, 2013-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "CustomGetterSetter.h"
#include "DFGLongLivedState.h"
#include "DFGWorklist.h"
-#include "DebuggerActivation.h"
+#include "Disassembler.h"
#include "ErrorInstance.h"
+#include "Exception.h"
#include "FTLThunks.h"
#include "FunctionConstructor.h"
#include "GCActivityCallback.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 "JSLexicalEnvironment.h"
#include "JSLock.h"
#include "JSNameScope.h"
#include "JSNotAnObject.h"
#include "JSPromiseDeferred.h"
-#include "JSPromiseReaction.h"
-#include "JSPropertyNameIterator.h"
+#include "JSPropertyNameEnumerator.h"
+#include "JSTemplateRegistryKey.h"
#include "JSWithScope.h"
#include "Lexer.h"
#include "Lookup.h"
#include "MapData.h"
#include "Nodes.h"
#include "Parser.h"
-#include "ParserArena.h"
#include "ProfilerDatabase.h"
#include "PropertyMapHashTable.h"
#include "RegExpCache.h"
#include "RegExpObject.h"
+#include "RuntimeType.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 "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"
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.
return false;
}
-#if USE(CF)
- CFStringRef canUseJITKey = CFSTR("JavaScriptCoreUseJIT");
- 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);
, heap(this, heapType)
, vmType(vmType)
, clientData(0)
+ , topVMEntryFrame(nullptr)
, topCallFrame(CallFrame::noCaller())
- , 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
, m_atomicStringTable(vmType == Default ? wtfThreadData().atomicStringTable() : new AtomicStringTable)
, propertyNames(nullptr)
, emptyList(new MarkedArgumentBuffer)
- , parserArena(adoptPtr(new ParserArena))
- , keywords(adoptPtr(new Keywords(*this)))
+ , stringCache(*this)
+ , prototypeMap(*this)
+ , keywords(std::make_unique<Keywords>(*this))
, interpreter(0)
, jsArrayClassInfo(JSArray::info())
, jsFinalObjectClassInfo(JSFinalObject::info())
- , varargsLength(0)
, sizeOfLastScratchBuffer(0)
, entryScope(0)
, m_regExpCache(new RegExpCache(this))
, m_largestFTLStackSize(0)
#endif
, m_inDefineOwnProperty(false)
- , m_codeCache(CodeCache::create())
+ , m_codeCache(std::make_unique<CodeCache>())
, m_enabledProfiler(nullptr)
- , m_builtinExecutables(BuiltinExecutables::create(*this))
+ , m_builtinExecutables(std::make_unique<BuiltinExecutables>(*this))
+ , m_typeProfilerEnabledCount(0)
+ , m_controlFlowProfilerEnabledCount(0)
{
interpreter = new Interpreter(*this);
StackBounds stack = wtfThreadData().stack();
propertyNames = new CommonIdentifiers(this);
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()));
- propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
+ propertyNameEnumeratorStructure.set(*this, JSPropertyNameEnumerator::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()));
programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
functionExecutableStructure.set(*this, FunctionExecutable::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()));
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()));
+ functionRareDataStructure.set(*this, FunctionRareData::createStructure(*this, 0, jsNull()));
+ exceptionStructure.set(*this, Exception::createStructure(*this, 0, jsNull()));
#if ENABLE(PROMISES)
promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull()));
- promiseReactionStructure.set(*this, JSPromiseReaction::createStructure(*this, 0, jsNull()));
#endif
iterationTerminator.set(*this, JSFinalObject::create(*this, JSFinalObject::createStructure(*this, 0, jsNull(), 1)));
smallStrings.initializeCommonStrings(*this);
wtfThreadData().setCurrentAtomicStringTable(existingEntryAtomicStringTable);
#if ENABLE(JIT)
- jitStubs = adoptPtr(new JITThunks());
+ jitStubs = std::make_unique<JITThunks>();
arityCheckFailReturnThunks = std::make_unique<ArityCheckFailReturnThunks>();
#endif
arityCheckData = std::make_unique<CommonSlowPaths::ArityCheckData>();
LLInt::Data::performAssertions(*this);
if (Options::enableProfiler()) {
- m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*this));
+ m_perBytecodeProfiler = std::make_unique<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());
}
#if ENABLE(DFG_JIT)
if (canUseJIT())
- dfgState = adoptPtr(new DFG::LongLivedState());
+ dfgState = std::make_unique<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());
+
+ if (Options::enableTypeProfiler())
+ enableTypeProfiler();
+ if (Options::enableControlFlowProfiler())
+ enableControlFlowProfiler();
}
VM::~VM()
}
#endif // ENABLE(DFG_JIT)
- // Clear this first to ensure that nobody tries to remove themselves from it.
- m_perBytecodeProfiler.clear();
+ waitForAsynchronousDisassembly();
+ // Clear this first to ensure that nobody tries to remove themselves from it.
+ m_perBytecodeProfiler = nullptr;
+
ASSERT(m_apiLock->currentThreadIsHoldingLock());
m_apiLock->willDestroyVM(this);
heap.lastChanceToFinalize();
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;
#endif
}
-PassRefPtr<VM> VM::createContextGroup(HeapType heapType)
+Ref<VM> VM::createContextGroup(HeapType heapType)
{
- return adoptRef(new VM(APIContextGroup, heapType));
+ return adoptRef(*new VM(APIContextGroup, heapType));
}
-PassRefPtr<VM> VM::create(HeapType heapType)
+Ref<VM> VM::create(HeapType heapType)
{
- return adoptRef(new VM(Default, heapType));
+ return adoptRef(*new VM(Default, heapType));
}
-PassRefPtr<VM> VM::createLeaked(HeapType heapType)
+Ref<VM> VM::createLeaked(HeapType heapType)
{
return create(heapType);
}
{
GlobalJSLock globalLock;
VM*& instance = sharedInstanceInternal();
- if (!instance) {
+ if (!instance)
instance = adoptRef(new VM(APIShared, SmallHeap)).leakRef();
- instance->makeUsableFromMultipleThreads();
- }
return *instance;
}
return charCodeAtThunkGenerator;
case CharAtIntrinsic:
return charAtThunkGenerator;
+ case Clz32Intrinsic:
+ return clz32ThunkGenerator;
case FromCharCodeIntrinsic:
return fromCharCodeThunkGenerator;
case SqrtIntrinsic:
return logThunkGenerator;
case IMulIntrinsic:
return imulThunkGenerator;
- case ArrayIteratorNextKeyIntrinsic:
- return arrayIteratorNextKeyThunkGenerator;
- case ArrayIteratorNextValueIntrinsic:
- return arrayIteratorNextValueThunkGenerator;
default:
return 0;
}
interpreter->stopSampling();
}
-void VM::waitForCompilationsToComplete()
+void VM::prepareToDiscardCode()
{
#if ENABLE(DFG_JIT)
for (unsigned i = DFG::numberOfWorklists(); i--;) {
void VM::discardAllCode()
{
- waitForCompilationsToComplete();
+ prepareToDiscardCode();
m_codeCache->clear();
m_regExpCache->invalidateCode();
heap.deleteAllCompiledCode();
struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
HashSet<FunctionExecutable*> currentlyExecutingFunctions;
- void operator()(JSCell* cell)
+ inline void visit(JSCell* cell)
{
if (!cell->inherits(FunctionExecutable::info()))
return;
FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
if (currentlyExecutingFunctions.contains(executable))
return;
- executable->clearCodeIfNotCompiling();
+ executable->clearCode();
+ }
+ IterationStatus operator()(JSCell* cell)
+ {
+ visit(cell);
+ return IterationStatus::Continue;
}
};
void VM::releaseExecutableMemory()
{
- waitForCompilationsToComplete();
+ prepareToDiscardCode();
if (entryScope) {
StackPreservingRecompiler recompiler;
heap.collectAllGarbage();
}
-static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
-{
- 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)
+void VM::throwException(ExecState* exec, Exception* exception)
{
if (Options::breakOnThrow()) {
dataLog("In call frame ", RawPointer(exec), " for code block ", *exec->codeBlock(), "\n");
}
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::getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack)
-{
- exception = m_exception;
- exceptionStack = m_exceptionStack;
-}
-void VM::setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack)
-{
- m_exception = exception;
- m_exceptionStack = exceptionStack;
+ setException(exception);
}
-void VM::clearException()
+JSValue VM::throwException(ExecState* exec, JSValue thrownValue)
{
- m_exception = JSValue();
+ Exception* exception = jsDynamicCast<Exception*>(thrownValue);
+ if (!exception)
+ exception = Exception::create(*this, thrownValue);
+
+ throwException(exec, exception);
+ return JSValue(exception);
}
-void VM:: clearExceptionStack()
+
+JSObject* VM::throwException(ExecState* exec, JSObject* error)
{
- m_exceptionStack = RefCountedArray<StackFrame>();
+ return asObject(throwException(exec, JSValue(error)));
}
void VM::setStackPointerAtVMEntry(void* sp)
void VM::addImpureProperty(const String& propertyName)
{
if (RefPtr<WatchpointSet> watchpointSet = m_impurePropertyWatchpointSets.take(propertyName))
- watchpointSet->fireAll();
+ watchpointSet->fireAll("Impure property added");
}
class SetEnabledProfilerFunctor {
{
m_enabledProfiler = profiler;
if (m_enabledProfiler) {
- waitForCompilationsToComplete();
+ prepareToDiscardCode();
SetEnabledProfilerFunctor functor;
heap.forEachCodeBlock(functor);
}
}
+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 sanitizeStackForVM(VM* vm)
{
logSanitizeStack(vm);