Versioning.
[WebKit-https.git] / Source / JavaScriptCore / jsc.cpp
index f0f4560..6336642 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2004-2017 Apple Inc. All rights reserved.
+ *  Copyright (C) 2004-2018 Apple Inc. All rights reserved.
  *  Copyright (C) 2006 Bjoern Graf (bjoern.graf@gmail.com)
  *
  *  This library is free software; you can redistribute it and/or
@@ -28,6 +28,7 @@
 #include "ButterflyInlines.h"
 #include "CatchScope.h"
 #include "CodeBlock.h"
+#include "CodeCache.h"
 #include "Completion.h"
 #include "ConfigFile.h"
 #include "Disassembler.h"
@@ -54,7 +55,6 @@
 #include "JSTypedArrays.h"
 #include "JSWebAssemblyInstance.h"
 #include "JSWebAssemblyMemory.h"
-#include "LLIntData.h"
 #include "LLIntThunks.h"
 #include "ObjectConstructor.h"
 #include "ParserError.h"
@@ -69,6 +69,7 @@
 #include "SuperSampler.h"
 #include "TestRunnerUtils.h"
 #include "TypedArrayInlines.h"
+#include "WasmCapabilities.h"
 #include "WasmContext.h"
 #include "WasmFaultSignalHandler.h"
 #include "WasmMemory.h"
 #include <sys/types.h>
 #include <thread>
 #include <type_traits>
+#include <wtf/Box.h>
 #include <wtf/CommaPrinter.h>
 #include <wtf/MainThread.h>
+#include <wtf/MemoryPressureHandler.h>
+#include <wtf/MonotonicTime.h>
 #include <wtf/NeverDestroyed.h>
+#include <wtf/Scope.h>
 #include <wtf/StringPrintStream.h>
+#include <wtf/URL.h>
 #include <wtf/WallTime.h>
 #include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringConcatenateNumbers.h>
 
 #if OS(WINDOWS)
 #include <direct.h>
-#include <wtf/text/win/WCharStringExtras.h>
+#include <fcntl.h>
+#include <io.h>
 #else
 #include <unistd.h>
 #endif
 #include <windows.h>
 #endif
 
-#if PLATFORM(IOS) && CPU(ARM_THUMB2)
+#if PLATFORM(IOS_FAMILY) && CPU(ARM_THUMB2)
 #include <fenv.h>
 #include <arm/arch.h>
 #endif
 
+#if __has_include(<WebKitAdditions/MemoryFootprint.h>)
+#include <WebKitAdditions/MemoryFootprint.h>
+#else
+struct MemoryFootprint {
+    uint64_t current;
+    uint64_t peak;
+    
+    static MemoryFootprint now()
+    {
+        return { 0L, 0L };
+    }
+    
+    static void resetPeak()
+    {
+    }
+};
+#endif
+
 #if !defined(PATH_MAX)
 #define PATH_MAX 4096
 #endif
 
 using namespace JSC;
-using namespace WTF;
 
 namespace {
 
@@ -187,7 +212,8 @@ static unsigned asyncTestExpectedPasses { 0 };
 
 }
 
-static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
+template<typename Vector>
+static bool fillBufferWithContentsOfFile(const String& fileName, Vector& buffer);
 static RefPtr<Uint8Array> fillBufferWithContentsOfFile(const String& fileName);
 
 class CommandLine;
@@ -195,8 +221,8 @@ class GlobalObject;
 class Workers;
 
 template<typename Func>
-int runJSC(CommandLine, bool isWorker, const Func&);
-static void checkException(GlobalObject*, bool isLastFile, bool hasException, JSValue, CommandLine&, bool& success);
+int runJSC(const CommandLine&, bool isWorker, const Func&);
+static void checkException(ExecState*, GlobalObject*, bool isLastFile, bool hasException, JSValue, CommandLine&, bool& success);
 
 class Message : public ThreadSafeRefCounted<Message> {
 public:
@@ -229,6 +255,8 @@ private:
 };
 
 class Workers {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(Workers);
 public:
     Workers();
     ~Workers();
@@ -236,7 +264,7 @@ public:
     template<typename Func>
     void broadcast(const Func&);
     
-    void report(String);
+    void report(const String&);
     String tryGetReport();
     String getReport();
     
@@ -266,10 +294,9 @@ static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionCreateMemoryFootprint(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionResetMemoryPeak(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState*);
-#ifndef NDEBUG
-static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
-#endif
 static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionRunString(ExecState*);
@@ -294,6 +321,7 @@ static EncodedJSValue JSC_HOST_CALL functionFalse(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionIsPureNaN(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
@@ -301,10 +329,10 @@ static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*);
-static EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshotForGCDebugging(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionResetSuperSamplerState(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionEnsureArrayStorage(ExecState*);
 #if ENABLE(SAMPLING_PROFILER)
@@ -339,11 +367,13 @@ static EncodedJSValue JSC_HOST_CALL functionDollarAgentSleep(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionDollarAgentBroadcast(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionDollarAgentGetReport(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionDollarAgentLeaving(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDollarAgentMonotonicNow(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionWaitForReport(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionHeapCapacity(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionFlashHeapAccess(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionDisableRichSourceInfo(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionMallocInALoop(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionTotalCompileTime(ExecState*);
 
 struct Script {
     enum class StrictMode {
@@ -384,17 +414,19 @@ public:
         parseArguments(argc, argv);
     }
 
+    Vector<Script> m_scripts;
+    Vector<String> m_arguments;
+    String m_profilerOutput;
+    String m_uncaughtExceptionName;
     bool m_interactive { false };
     bool m_dump { false };
     bool m_module { false };
     bool m_exitCode { false };
-    Vector<Script> m_scripts;
-    Vector<String> m_arguments;
+    bool m_destroyVM { false };
     bool m_profile { false };
-    String m_profilerOutput;
-    String m_uncaughtExceptionName;
     bool m_treatWatchdogExceptionAsSuccess { false };
     bool m_alwaysDumpUncaughtException { false };
+    bool m_dumpMemoryFootprint { false };
     bool m_dumpSamplingProfilerData { false };
     bool m_enableRemoteDebugging { false };
 
@@ -435,13 +467,6 @@ static inline String stringFromUTF(const Vector& utf8)
     return String::fromUTF8WithLatin1Fallback(utf8.data(), utf8.size());
 }
 
-template<typename Vector>
-static inline SourceCode jscSource(const Vector& utf8, const SourceOrigin& sourceOrigin, const String& filename)
-{
-    String str = stringFromUTF(utf8);
-    return makeSource(str, sourceOrigin, filename);
-}
-
 class GlobalObject : public JSGlobalObject {
 private:
     GlobalObject(VM&, Structure*);
@@ -472,7 +497,7 @@ protected:
     void finishCreation(VM& vm, const Vector<String>& arguments)
     {
         Base::finishCreation(vm);
-        
+
         addFunction(vm, "debug", functionDebug, 1);
         addFunction(vm, "describe", functionDescribe, 1);
         addFunction(vm, "describeArray", functionDescribeArray, 1);
@@ -484,10 +509,9 @@ protected:
         addFunction(vm, "edenGC", functionEdenGC, 0);
         addFunction(vm, "forceGCSlowPaths", functionForceGCSlowPaths, 0);
         addFunction(vm, "gcHeapSize", functionHeapSize, 0);
+        addFunction(vm, "MemoryFootprint", functionCreateMemoryFootprint, 0);
+        addFunction(vm, "resetMemoryPeak", functionResetMemoryPeak, 0);
         addFunction(vm, "addressOf", functionAddressOf, 1);
-#ifndef NDEBUG
-        addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
-#endif
         addFunction(vm, "version", functionVersion, 1);
         addFunction(vm, "run", functionRun, 1);
         addFunction(vm, "runString", functionRunString, 1);
@@ -520,6 +544,7 @@ protected:
         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isFinalTier"), 0, functionFalse, IsFinalTierIntrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum));
         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum));
         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isInt32"), 0, functionIsInt32, CheckInt32Intrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum));
+        putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isPureNaN"), 0, functionIsPureNaN, CheckInt32Intrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum));
         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum));
         
         addFunction(vm, "effectful42", functionEffectful42, 0);
@@ -539,11 +564,11 @@ protected:
 
         addFunction(vm, "is32BitPlatform", functionIs32BitPlatform, 0);
 
-        addFunction(vm, "loadModule", functionLoadModule, 1);
         addFunction(vm, "checkModuleSyntax", functionCheckModuleSyntax, 1);
 
         addFunction(vm, "platformSupportsSamplingProfiler", functionPlatformSupportsSamplingProfiler, 0);
         addFunction(vm, "generateHeapSnapshot", functionGenerateHeapSnapshot, 0);
+        addFunction(vm, "generateHeapSnapshotForGCDebugging", functionGenerateHeapSnapshotForGCDebugging, 0);
         addFunction(vm, "resetSuperSamplerState", functionResetSuperSamplerState, 0);
         addFunction(vm, "ensureArrayStorage", functionEnsureArrayStorage, 0);
 #if ENABLE(SAMPLING_PROFILER)
@@ -593,7 +618,8 @@ protected:
         addFunction(vm, agent, "broadcast", functionDollarAgentBroadcast, 1);
         addFunction(vm, agent, "getReport", functionDollarAgentGetReport, 0);
         addFunction(vm, agent, "leaving", functionDollarAgentLeaving, 0);
-        
+        addFunction(vm, agent, "monotonicNow", functionDollarAgentMonotonicNow, 0);
+
         addFunction(vm, "waitForReport", functionWaitForReport, 0);
 
         addFunction(vm, "heapCapacity", functionHeapCapacity, 0);
@@ -601,6 +627,7 @@ protected:
 
         addFunction(vm, "disableRichSourceInfo", functionDisableRichSourceInfo, 0);
         addFunction(vm, "mallocInALoop", functionMallocInALoop, 0);
+        addFunction(vm, "totalCompileTime", functionTotalCompileTime, 0);
     }
     
     void addFunction(VM& vm, JSObject* object, const char* name, NativeFunction function, unsigned arguments)
@@ -640,6 +667,8 @@ const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = {
     nullptr, // moduleLoaderEvaluate
     nullptr, // promiseRejectionTracker
     nullptr, // defaultLanguage
+    nullptr, // compileStreaming
+    nullptr, // instantinateStreaming
 };
 
 GlobalObject::GlobalObject(VM& vm, Structure* structure)
@@ -678,14 +707,14 @@ struct ModuleName {
 ModuleName::ModuleName(const String& moduleName)
 {
     // A module name given from code is represented as the UNIX style path. Like, `./A/B.js`.
-    moduleName.split('/', true, queries);
+    queries = moduleName.splitAllowingEmptyEntries('/');
 }
 
-static std::optional<DirectoryName> extractDirectoryName(const String& absolutePathToFile)
+static Optional<DirectoryName> extractDirectoryName(const String& absolutePathToFile)
 {
     size_t firstSeparatorPosition = absolutePathToFile.find(pathSeparator());
     if (firstSeparatorPosition == notFound)
-        return std::nullopt;
+        return WTF::nullopt;
     DirectoryName directoryName;
     directoryName.rootName = absolutePathToFile.substring(0, firstSeparatorPosition + 1); // Include the separator.
     size_t lastSeparatorPosition = absolutePathToFile.reverseFind(pathSeparator());
@@ -700,7 +729,7 @@ static std::optional<DirectoryName> extractDirectoryName(const String& absoluteP
     return directoryName;
 }
 
-static std::optional<DirectoryName> currentWorkingDirectory()
+static Optional<DirectoryName> currentWorkingDirectory()
 {
 #if OS(WINDOWS)
     // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364934.aspx
@@ -714,24 +743,24 @@ static std::optional<DirectoryName> currentWorkingDirectory()
     // In the path utility functions inside the JSC shell, we does not handle the UNC and UNCW including the network host name.
     DWORD bufferLength = ::GetCurrentDirectoryW(0, nullptr);
     if (!bufferLength)
-        return std::nullopt;
+        return WTF::nullopt;
     // In Windows, wchar_t is the UTF-16LE.
     // https://msdn.microsoft.com/en-us/library/dd374081.aspx
     // https://msdn.microsoft.com/en-us/library/windows/desktop/ff381407.aspx
-    auto buffer = std::make_unique<wchar_t[]>(bufferLength);
-    DWORD lengthNotIncludingNull = ::GetCurrentDirectoryW(bufferLength, buffer.get());
-    String directoryString = wcharToString(buffer.get(), lengthNotIncludingNull);
+    Vector<wchar_t> buffer(bufferLength);
+    DWORD lengthNotIncludingNull = ::GetCurrentDirectoryW(bufferLength, buffer.data());
+    String directoryString(buffer.data(), lengthNotIncludingNull);
     // We don't support network path like \\host\share\<path name>.
     if (directoryString.startsWith("\\\\"))
-        return std::nullopt;
+        return WTF::nullopt;
 #else
-    auto buffer = std::make_unique<char[]>(PATH_MAX);
-    if (!getcwd(buffer.get(), PATH_MAX))
-        return std::nullopt;
-    String directoryString = String::fromUTF8(buffer.get());
+    Vector<char> buffer(PATH_MAX);
+    if (!getcwd(buffer.data(), PATH_MAX))
+        return WTF::nullopt;
+    String directoryString = String::fromUTF8(buffer.data());
 #endif
     if (directoryString.isEmpty())
-        return std::nullopt;
+        return WTF::nullopt;
 
     if (directoryString[directoryString.length() - 1] == pathSeparator())
         return extractDirectoryName(directoryString);
@@ -741,18 +770,17 @@ static std::optional<DirectoryName> currentWorkingDirectory()
 
 static String resolvePath(const DirectoryName& directoryName, const ModuleName& moduleName)
 {
-    Vector<String> directoryPieces;
-    directoryName.queryName.split(pathSeparator(), false, directoryPieces);
+    Vector<String> directoryPieces = directoryName.queryName.split(pathSeparator());
 
     // Only first '/' is recognized as the path from the root.
     if (moduleName.startsWithRoot())
         directoryPieces.clear();
 
     for (const auto& query : moduleName.queries) {
-        if (query == String(ASCIILiteral(".."))) {
+        if (query == String(".."_s)) {
             if (!directoryPieces.isEmpty())
                 directoryPieces.removeLast();
-        } else if (!query.isEmpty() && query != String(ASCIILiteral(".")))
+        } else if (!query.isEmpty() && query != String("."_s))
             directoryPieces.append(query);
     }
 
@@ -777,29 +805,34 @@ static String absolutePath(const String& fileName)
 JSInternalPromise* GlobalObject::moduleLoaderImportModule(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSString* moduleNameValue, JSValue parameters, const SourceOrigin& sourceOrigin)
 {
     VM& vm = globalObject->vm();
-    auto scope = DECLARE_CATCH_SCOPE(vm);
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
 
-    auto rejectPromise = [&] (JSValue error) {
-        return JSInternalPromiseDeferred::create(exec, globalObject)->reject(exec, error);
+    auto* deferred = JSInternalPromiseDeferred::tryCreate(exec, globalObject);
+    RETURN_IF_EXCEPTION(throwScope, nullptr);
+
+    auto catchScope = DECLARE_CATCH_SCOPE(vm);
+    auto reject = [&] (JSValue rejectionReason) {
+        catchScope.clearException();
+        auto result = deferred->reject(exec, rejectionReason);
+        catchScope.clearException();
+        return result;
     };
 
     if (sourceOrigin.isNull())
-        return rejectPromise(createError(exec, ASCIILiteral("Could not resolve the module specifier.")));
+        return reject(createError(exec, "Could not resolve the module specifier."_s));
 
-    auto referrer = sourceOrigin.string();
-    auto moduleName = moduleNameValue->value(exec);
-    if (UNLIKELY(scope.exception())) {
-        JSValue exception = scope.exception();
-        scope.clearException();
-        return rejectPromise(exception);
-    }
+    const auto& referrer = sourceOrigin.string();
+    const auto& moduleName = moduleNameValue->value(exec);
+    if (UNLIKELY(catchScope.exception()))
+        return reject(catchScope.exception());
 
     auto directoryName = extractDirectoryName(referrer.impl());
     if (!directoryName)
-        return rejectPromise(createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
+        return reject(createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
 
     auto result = JSC::importModule(exec, Identifier::fromString(&vm, resolvePath(directoryName.value(), ModuleName(moduleName))), parameters, jsUndefined());
-    scope.releaseAssertNoException();
+    if (UNLIKELY(catchScope.exception()))
+        return reject(catchScope.exception());
     return result;
 }
 
@@ -818,7 +851,7 @@ Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecS
     if (referrerValue.isUndefined()) {
         auto directoryName = currentWorkingDirectory();
         if (!directoryName) {
-            throwException(exec, scope, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
+            throwException(exec, scope, createError(exec, "Could not resolve the current working directory."_s));
             return { };
         }
         return Identifier::fromString(&vm, resolvePath(directoryName.value(), ModuleName(key.impl())));
@@ -830,7 +863,7 @@ Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecS
     if (referrer.isSymbol()) {
         auto directoryName = currentWorkingDirectory();
         if (!directoryName) {
-            throwException(exec, scope, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
+            throwException(exec, scope, createError(exec, "Could not resolve the current working directory."_s));
             return { };
         }
         return Identifier::fromString(&vm, resolvePath(directoryName.value(), ModuleName(key.impl())));
@@ -845,7 +878,8 @@ Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecS
     return Identifier::fromString(&vm, resolvePath(directoryName.value(), ModuleName(key.impl())));
 }
 
-static void convertShebangToJSComment(Vector<char>& buffer)
+template<typename Vector>
+static void convertShebangToJSComment(Vector& buffer)
 {
     if (buffer.size() >= 2) {
         if (buffer[0] == '#' && buffer[1] == '!')
@@ -862,7 +896,9 @@ static RefPtr<Uint8Array> fillBufferWithContentsOfFile(FILE* file)
         return nullptr;
     if (fseek(file, 0, SEEK_SET) == -1)
         return nullptr;
-    RefPtr<Uint8Array> result = Uint8Array::create(bufferCapacity);
+    auto result = Uint8Array::tryCreate(bufferCapacity);
+    if (!result)
+        return nullptr;
     size_t readSize = fread(result->data(), 1, bufferCapacity, file);
     if (readSize != static_cast<size_t>(bufferCapacity))
         return nullptr;
@@ -883,7 +919,8 @@ static RefPtr<Uint8Array> fillBufferWithContentsOfFile(const String& fileName)
     return result;
 }
 
-static bool fillBufferWithContentsOfFile(FILE* file, Vector<char>& buffer)
+template<typename Vector>
+static bool fillBufferWithContentsOfFile(FILE* file, Vector& buffer)
 {
     // We might have injected "use strict"; at the top.
     size_t initialSize = buffer.size();
@@ -921,14 +958,112 @@ static bool fetchScriptFromLocalFileSystem(const String& fileName, Vector<char>&
     return true;
 }
 
-static bool fetchModuleFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
+class ShellSourceProvider : public StringSourceProvider {
+public:
+    static Ref<ShellSourceProvider> create(const String& source, const SourceOrigin& sourceOrigin, URL&& url, const TextPosition& startPosition, SourceProviderSourceType sourceType)
+    {
+        return adoptRef(*new ShellSourceProvider(source, sourceOrigin, WTFMove(url), startPosition, sourceType));
+    }
+
+    ~ShellSourceProvider()
+    {
+#if OS(DARWIN)
+        if (m_cachedBytecode.size())
+            munmap(const_cast<void*>(m_cachedBytecode.data()), m_cachedBytecode.size());
+#endif
+    }
+
+    const CachedBytecode* cachedBytecode() const override
+    {
+        return &m_cachedBytecode;
+    }
+
+    void cacheBytecode(const BytecodeCacheGenerator& generator) const override
+    {
+#if OS(DARWIN)
+        String filename = cachePath();
+        if (filename.isNull())
+            return;
+        int fd = open(filename.utf8().data(), O_CREAT | O_WRONLY | O_TRUNC | O_EXLOCK | O_NONBLOCK, 0666);
+        if (fd == -1)
+            return;
+        CachedBytecode cachedBytecode = generator();
+        write(fd, cachedBytecode.data(), cachedBytecode.size());
+        close(fd);
+#else
+        UNUSED_PARAM(generator);
+#endif
+    }
+
+private:
+    String cachePath() const
+    {
+        const char* cachePath = Options::diskCachePath();
+        if (!cachePath)
+            return static_cast<const char*>(nullptr);
+        String filename = sourceOrigin().string();
+        filename.replace('/', '_');
+        return makeString(cachePath, '/', source().toString().hash(), '-', filename, ".bytecode-cache");
+    }
+
+    void loadBytecode()
+    {
+#if OS(DARWIN)
+        String filename = cachePath();
+        if (filename.isNull())
+            return;
+
+        int fd = open(filename.utf8().data(), O_RDONLY | O_SHLOCK | O_NONBLOCK);
+        if (fd == -1)
+            return;
+
+        auto closeFD = makeScopeExit([&] {
+            close(fd);
+        });
+
+        struct stat sb;
+        int res = fstat(fd, &sb);
+        size_t size = static_cast<size_t>(sb.st_size);
+        if (res || !size)
+            return;
+
+        void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
+        if (buffer == MAP_FAILED)
+            return;
+        m_cachedBytecode = CachedBytecode { buffer, size };
+#endif
+    }
+
+    ShellSourceProvider(const String& source, const SourceOrigin& sourceOrigin, URL&& url, const TextPosition& startPosition, SourceProviderSourceType sourceType)
+        : StringSourceProvider(source, sourceOrigin, WTFMove(url), startPosition, sourceType)
+    {
+        loadBytecode();
+    }
+
+    CachedBytecode m_cachedBytecode;
+};
+
+static inline SourceCode jscSource(const String& source, const SourceOrigin& sourceOrigin, URL&& url = URL(), const TextPosition& startPosition = TextPosition(), SourceProviderSourceType sourceType = SourceProviderSourceType::Program)
+{
+    return SourceCode(ShellSourceProvider::create(source, sourceOrigin, WTFMove(url), startPosition, sourceType), startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt());
+}
+
+template<typename Vector>
+static inline SourceCode jscSource(const Vector& utf8, const SourceOrigin& sourceOrigin, const String& filename)
+{
+    // FIXME: This should use an absolute file URL https://bugs.webkit.org/show_bug.cgi?id=193077
+    String str = stringFromUTF(utf8);
+    return jscSource(str, sourceOrigin, URL({ }, filename));
+}
+
+template<typename Vector>
+static bool fetchModuleFromLocalFileSystem(const String& fileName, Vector& buffer)
 {
     // We assume that fileName is always an absolute path.
 #if OS(WINDOWS)
     // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath
     // Use long UNC to pass the long path name to the Windows APIs.
-    String longUNCPathName = WTF::makeString("\\\\?\\", fileName);
-    auto pathName = stringToNullTerminatedWChar(longUNCPathName);
+    auto pathName = makeString("\\\\?\\", fileName).wideCharacters();
     struct _stat status { };
     if (_wstat(pathName.data(), &status))
         return false;
@@ -962,25 +1097,48 @@ static bool fetchModuleFromLocalFileSystem(const String& fileName, Vector<char>&
 JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue key, JSValue, JSValue)
 {
     VM& vm = globalObject->vm();
-    auto scope = DECLARE_CATCH_SCOPE(vm);
-    JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+    JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::tryCreate(exec, globalObject);
+    RETURN_IF_EXCEPTION(throwScope, nullptr);
+
+    auto catchScope = DECLARE_CATCH_SCOPE(vm);
+    auto reject = [&] (JSValue rejectionReason) {
+        catchScope.clearException();
+        auto result = deferred->reject(exec, rejectionReason);
+        catchScope.clearException();
+        return result;
+    };
+
     String moduleKey = key.toWTFString(exec);
-    if (UNLIKELY(scope.exception())) {
-        JSValue exception = scope.exception();
-        scope.clearException();
-        return deferred->reject(exec, exception);
-    }
+    if (UNLIKELY(catchScope.exception()))
+        return reject(catchScope.exception());
 
     // Here, now we consider moduleKey as the fileName.
-    Vector<char> utf8;
-    if (!fetchModuleFromLocalFileSystem(moduleKey, utf8)) {
-        auto result = deferred->reject(exec, createError(exec, makeString("Could not open file '", moduleKey, "'.")));
-        scope.releaseAssertNoException();
-        return result;
+    Vector<uint8_t> buffer;
+    if (!fetchModuleFromLocalFileSystem(moduleKey, buffer))
+        return reject(createError(exec, makeString("Could not open file '", moduleKey, "'.")));
+
+
+    URL moduleURL = URL({ }, moduleKey);
+#if ENABLE(WEBASSEMBLY)
+    // FileSystem does not have mime-type header. The JSC shell recognizes WebAssembly's magic header.
+    if (buffer.size() >= 4) {
+        if (buffer[0] == '\0' && buffer[1] == 'a' && buffer[2] == 's' && buffer[3] == 'm') {
+            auto source = SourceCode(WebAssemblySourceProvider::create(WTFMove(buffer), SourceOrigin { moduleKey }, WTFMove(moduleURL)));
+            catchScope.releaseAssertNoException();
+            auto sourceCode = JSSourceCode::create(vm, WTFMove(source));
+            catchScope.releaseAssertNoException();
+            auto result = deferred->resolve(exec, sourceCode);
+            catchScope.clearException();
+            return result;
+        }
     }
+#endif
 
-    auto result = deferred->resolve(exec, JSSourceCode::create(vm, makeSource(stringFromUTF(utf8), SourceOrigin { moduleKey }, moduleKey, TextPosition(), SourceProviderSourceType::Module)));
-    scope.releaseAssertNoException();
+    auto sourceCode = JSSourceCode::create(vm, jscSource(stringFromUTF(buffer), SourceOrigin { moduleKey }, WTFMove(moduleURL), TextPosition(), SourceProviderSourceType::Module));
+    catchScope.releaseAssertNoException();
+    auto result = deferred->resolve(exec, sourceCode);
+    catchScope.clearException();
     return result;
 }
 
@@ -998,6 +1156,27 @@ JSObject* GlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObject* g
     return metaProperties;
 }
 
+static CString cStringFromViewWithString(ExecState* exec, ThrowScope& scope, StringViewWithUnderlyingString& viewWithString)
+{
+    Expected<CString, UTF8ConversionError> expectedString = viewWithString.view.tryGetUtf8();
+    if (expectedString)
+        return expectedString.value();
+    switch (expectedString.error()) {
+    case UTF8ConversionError::OutOfMemory:
+        throwOutOfMemoryError(exec, scope);
+        break;
+    case UTF8ConversionError::IllegalSource:
+        scope.throwException(exec, createError(exec, "Illegal source encountered during UTF8 conversion"));
+        break;
+    case UTF8ConversionError::SourceExhausted:
+        scope.throwException(exec, createError(exec, "Source exhausted during UTF8 conversion"));
+        break;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+    return { };
+}
+
 static EncodedJSValue printInternal(ExecState* exec, FILE* out)
 {
     VM& vm = exec->vm();
@@ -1018,7 +1197,9 @@ static EncodedJSValue printInternal(ExecState* exec, FILE* out)
 
         auto viewWithString = exec->uncheckedArgument(i).toString(exec)->viewWithUnderlyingString(exec);
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
-        if (fprintf(out, "%s", viewWithString.view.utf8().data()) < 0)
+        auto string = cStringFromViewWithString(exec, scope, viewWithString);
+        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+        if (fprintf(out, "%s", string.data()) < 0)
             goto fail;
     }
 
@@ -1031,25 +1212,15 @@ fail:
 EncodedJSValue JSC_HOST_CALL functionPrintStdOut(ExecState* exec) { return printInternal(exec, stdout); }
 EncodedJSValue JSC_HOST_CALL functionPrintStdErr(ExecState* exec) { return printInternal(exec, stderr); }
 
-#ifndef NDEBUG
-EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
-{
-    VM& vm = exec->vm();
-    EntryFrame* topEntryFrame = vm.topEntryFrame;
-    ExecState* callerFrame = exec->callerFrame(topEntryFrame);
-    if (callerFrame)
-        vm.interpreter->dumpCallFrame(callerFrame);
-    return JSValue::encode(jsUndefined());
-}
-#endif
-
 EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
     auto viewWithString = exec->argument(0).toString(exec)->viewWithUnderlyingString(exec);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    fprintf(stderr, "--> %s\n", viewWithString.view.utf8().data());
+    auto string = cStringFromViewWithString(exec, scope, viewWithString);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    fprintf(stderr, "--> %s\n", string.data());
     return JSValue::encode(jsUndefined());
 }
 
@@ -1067,7 +1238,7 @@ EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
     VM& vm = exec->vm();
     JSObject* object = jsDynamicCast<JSObject*>(vm, exec->argument(0));
     if (!object)
-        return JSValue::encode(jsNontrivialString(exec, ASCIILiteral("<not object>")));
+        return JSValue::encode(jsNontrivialString(exec, "<not object>"_s));
     return JSValue::encode(jsNontrivialString(exec, toString("<Butterfly: ", RawPointer(object->butterfly()), "; public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
 }
 
@@ -1094,7 +1265,7 @@ public:
 
     StackVisitor::Status operator()(StackVisitor& visitor) const
     {
-        m_trace.append(String::format("    %zu   %s\n", visitor->index(), visitor->toString().utf8().data()));
+        m_trace.append(makeString("    ", visitor->index(), "   ", visitor->toString(), '\n'));
         return StackVisitor::Continue;
     }
 
@@ -1152,6 +1323,65 @@ EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState* exec)
     return JSValue::encode(jsNumber(vm.heap.size()));
 }
 
+class JSCMemoryFootprint : public JSDestructibleObject {
+    using Base = JSDestructibleObject;
+public:
+    JSCMemoryFootprint(VM& vm, Structure* structure)
+        : Base(vm, structure)
+    { }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+    }
+
+    static JSCMemoryFootprint* create(VM& vm, JSGlobalObject* globalObject)
+    {
+        Structure* structure = createStructure(vm, globalObject, jsNull());
+        JSCMemoryFootprint* footprint = new (NotNull, allocateCell<JSCMemoryFootprint>(vm.heap, sizeof(JSCMemoryFootprint))) JSCMemoryFootprint(vm, structure);
+        footprint->finishCreation(vm);
+        return footprint;
+    }
+
+    void finishCreation(VM& vm)
+    {
+        Base::finishCreation(vm);
+
+        auto addProperty = [&] (VM& vm, const char* name, JSValue value) {
+            JSCMemoryFootprint::addProperty(vm, name, value);
+        };
+
+        MemoryFootprint footprint = MemoryFootprint::now();
+
+        addProperty(vm, "current", jsNumber(footprint.current));
+        addProperty(vm, "peak", jsNumber(footprint.peak));
+    }
+
+    DECLARE_INFO;
+
+private:
+    void addProperty(VM& vm, const char* name, JSValue value)
+    {
+        Identifier identifier = Identifier::fromString(&vm, name);
+        putDirect(vm, identifier, value);
+    }
+};
+
+const ClassInfo JSCMemoryFootprint::s_info = { "MemoryFootprint", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCMemoryFootprint) };
+
+EncodedJSValue JSC_HOST_CALL functionCreateMemoryFootprint(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    JSLockHolder lock(vm);
+    return JSValue::encode(JSCMemoryFootprint::create(vm, exec->lexicalGlobalObject()));
+}
+
+EncodedJSValue JSC_HOST_CALL functionResetMemoryPeak(ExecState*)
+{
+    MemoryFootprint::resetPeak();
+    return JSValue::encode(jsUndefined());
+}
+
 // This function is not generally very helpful in 64-bit code as the tag and payload
 // share a register. But in 32-bit JITed code the tag may not be checked if an
 // optimization removes type checking requirements, such as in ===.
@@ -1182,7 +1412,7 @@ EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     Vector<char> script;
     if (!fetchScriptFromLocalFileSystem(fileName, script))
-        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
+        return JSValue::encode(throwException(exec, scope, createError(exec, "Could not open file."_s)));
 
     GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
 
@@ -1229,7 +1459,7 @@ EncodedJSValue JSC_HOST_CALL functionRunString(ExecState* exec)
         vm, Identifier::fromString(globalObject->globalExec(), "arguments"), array);
 
     NakedPtr<Exception> exception;
-    evaluate(globalObject->globalExec(), makeSource(source, exec->callerSourceOrigin()), JSValue(), exception);
+    evaluate(globalObject->globalExec(), jscSource(source, exec->callerSourceOrigin()), JSValue(), exception);
 
     if (exception) {
         scope.throwException(globalObject->globalExec(), exception);
@@ -1248,7 +1478,7 @@ EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     Vector<char> script;
     if (!fetchScriptFromLocalFileSystem(fileName, script))
-        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
+        return JSValue::encode(throwException(exec, scope, createError(exec, "Could not open file."_s)));
 
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     
@@ -1269,7 +1499,7 @@ EncodedJSValue JSC_HOST_CALL functionLoadString(ExecState* exec)
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
 
     NakedPtr<Exception> evaluationException;
-    JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode, exec->callerSourceOrigin()), JSValue(), evaluationException);
+    JSValue result = evaluate(globalObject->globalExec(), jscSource(sourceCode, exec->callerSourceOrigin()), JSValue(), evaluationException);
     if (evaluationException)
         throwException(exec, scope, evaluationException);
     return JSValue::encode(result);
@@ -1315,7 +1545,7 @@ EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     Vector<char> script;
     if (!fetchScriptFromLocalFileSystem(fileName, script))
-        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
+        return JSValue::encode(throwException(exec, scope, createError(exec, "Could not open file."_s)));
 
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
 
@@ -1417,12 +1647,11 @@ EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL functionNoFTL(ExecState* exec)
 {
-    VM& vm = exec->vm();
-    if (JSFunction* function = jsDynamicCast<JSFunction*>(vm, exec->argument(0))) {
-        FunctionExecutable* executable = function->jsExecutable();
-        executable->setNeverFTLOptimize(true);
+    if (exec->argumentCount()) {
+        FunctionExecutable* executable = getExecutableForFunction(exec->argument(0));
+        if (executable)
+            executable->setNeverFTLOptimize(true);
     }
-
     return JSValue::encode(jsUndefined());
 }
 
@@ -1517,7 +1746,7 @@ void Workers::broadcast(const Func& func)
     m_condition.notifyAll();
 }
 
-void Workers::report(String string)
+void Workers::report(const String& string)
 {
     auto locker = holdLock(m_lock);
     m_reports.append(string.isolatedCopy());
@@ -1576,10 +1805,10 @@ EncodedJSValue JSC_HOST_CALL functionDollarEvalScript(ExecState* exec)
         exec->thisValue().get(exec, Identifier::fromString(exec, "global")));
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     if (!globalObject)
-        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected global to point to a global object"))));
+        return JSValue::encode(throwException(exec, scope, createError(exec, "Expected global to point to a global object"_s)));
     
     NakedPtr<Exception> evaluationException;
-    JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode, exec->callerSourceOrigin()), JSValue(), evaluationException);
+    JSValue result = evaluate(globalObject->globalExec(), jscSource(sourceCode, exec->callerSourceOrigin()), JSValue(), evaluationException);
     if (evaluationException)
         throwException(exec, scope, evaluationException);
     return JSValue::encode(result);
@@ -1604,7 +1833,7 @@ EncodedJSValue JSC_HOST_CALL functionDollarAgentStart(ExecState* exec)
             commandLine.m_interactive = false;
             runJSC(
                 commandLine, true,
-                [&] (VM&, GlobalObject* globalObject) {
+                [&] (VM&, GlobalObject* globalObject, bool& success) {
                     // Notify the thread that started us that we have registered a worker.
                     {
                         auto locker = holdLock(didStartLock);
@@ -1613,15 +1842,13 @@ EncodedJSValue JSC_HOST_CALL functionDollarAgentStart(ExecState* exec)
                     }
                     
                     NakedPtr<Exception> evaluationException;
-                    bool success = true;
                     JSValue result;
-                    result = evaluate(globalObject->globalExec(), makeSource(sourceCode, SourceOrigin(ASCIILiteral("worker"))), JSValue(), evaluationException);
+                    result = evaluate(globalObject->globalExec(), jscSource(sourceCode, SourceOrigin("worker"_s)), JSValue(), evaluationException);
                     if (evaluationException)
                         result = evaluationException->value();
-                    checkException(globalObject, true, evaluationException, result, commandLine, success);
+                    checkException(globalObject->globalExec(), globalObject, true, evaluationException, result, commandLine, success);
                     if (!success)
                         exit(1);
-                    return success;
                 });
         })->detach();
     
@@ -1641,9 +1868,9 @@ EncodedJSValue JSC_HOST_CALL functionDollarAgentReceiveBroadcast(ExecState* exec
 
     JSValue callback = exec->argument(0);
     CallData callData;
-    CallType callType = getCallData(callback, callData);
+    CallType callType = getCallData(vm, callback, callData);
     if (callType == CallType::None)
-        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected callback"))));
+        return JSValue::encode(throwException(exec, scope, createError(exec, "Expected callback"_s)));
     
     RefPtr<Message> message;
     {
@@ -1651,7 +1878,7 @@ EncodedJSValue JSC_HOST_CALL functionDollarAgentReceiveBroadcast(ExecState* exec
         message = Worker::current().dequeue();
     }
     
-    RefPtr<ArrayBuffer> nativeBuffer = ArrayBuffer::create(message->releaseContents());
+    auto nativeBuffer = ArrayBuffer::create(message->releaseContents());
     ArrayBufferSharingMode sharingMode = nativeBuffer->sharingMode();
     JSArrayBuffer* jsBuffer = JSArrayBuffer::create(vm, exec->lexicalGlobalObject()->arrayBufferStructure(sharingMode), WTFMove(nativeBuffer));
     
@@ -1660,8 +1887,7 @@ EncodedJSValue JSC_HOST_CALL functionDollarAgentReceiveBroadcast(ExecState* exec
     args.append(jsNumber(message->index()));
     if (UNLIKELY(args.hasOverflowed()))
         return JSValue::encode(throwOutOfMemoryError(exec, scope));
-    scope.release();
-    return JSValue::encode(call(exec, callback, callType, callData, jsNull(), args));
+    RELEASE_AND_RETURN(scope, JSValue::encode(call(exec, callback, callType, callData, jsNull(), args)));
 }
 
 EncodedJSValue JSC_HOST_CALL functionDollarAgentReport(ExecState* exec)
@@ -1697,7 +1923,7 @@ EncodedJSValue JSC_HOST_CALL functionDollarAgentBroadcast(ExecState* exec)
 
     JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(vm, exec->argument(0));
     if (!jsBuffer || !jsBuffer->isShared())
-        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected SharedArrayBuffer"))));
+        return JSValue::encode(throwException(exec, scope, createError(exec, "Expected SharedArrayBuffer"_s)));
     
     int32_t index = exec->argument(1).toInt32(exec);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
@@ -1730,6 +1956,11 @@ EncodedJSValue JSC_HOST_CALL functionDollarAgentLeaving(ExecState*)
     return JSValue::encode(jsUndefined());
 }
 
+EncodedJSValue JSC_HOST_CALL functionDollarAgentMonotonicNow(ExecState*)
+{
+    return JSValue::encode(jsNumber(MonotonicTime::now().secondsSinceEpoch().milliseconds()));
+}
+
 EncodedJSValue JSC_HOST_CALL functionWaitForReport(ExecState* exec)
 {
     VM& vm = exec->vm();
@@ -1785,11 +2016,20 @@ EncodedJSValue JSC_HOST_CALL functionMallocInALoop(ExecState*)
     return JSValue::encode(jsUndefined());
 }
 
+EncodedJSValue JSC_HOST_CALL functionTotalCompileTime(ExecState*)
+{
+#if ENABLE(JIT)
+    return JSValue::encode(jsNumber(JIT::totalCompileTime().milliseconds()));
+#else
+    return JSValue::encode(jsNumber(0));
+#endif
+}
+
 template<typename ValueType>
-typename std::enable_if<!std::is_fundamental<ValueType>::value>::type addOption(VM&, JSObject*, Identifier, ValueType) { }
+typename std::enable_if<!std::is_fundamental<ValueType>::value>::type addOption(VM&, JSObject*, const Identifier&, ValueType) { }
 
 template<typename ValueType>
-typename std::enable_if<std::is_fundamental<ValueType>::value>::type addOption(VM& vm, JSObject* optionsObject, Identifier identifier, ValueType value)
+typename std::enable_if<std::is_fundamental<ValueType>::value>::type addOption(VM& vm, JSObject* optionsObject, const Identifier& identifier, ValueType value)
 {
     optionsObject->putDirect(vm, identifier, JSValue(value));
 }
@@ -1823,11 +2063,11 @@ EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     if (exec->argumentCount() < 1)
-        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Not enough arguments"))));
+        return JSValue::encode(throwException(exec, scope, createError(exec, "Not enough arguments"_s)));
     
     JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(vm, exec->argument(0));
     if (!buffer)
-        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected an array buffer"))));
+        return JSValue::encode(throwException(exec, scope, createError(exec, "Expected an array buffer"_s)));
     
     ArrayBufferContents dummyContents;
     buffer->impl()->transferTo(vm, dummyContents);
@@ -1842,8 +2082,11 @@ EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState* exec)
     return JSValue::encode(jsUndefined());
 }
 
-EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
+EncodedJSValue JSC_HOST_CALL functionQuit(ExecState* exec)
 {
+    VM& vm = exec->vm();
+    vm.codeCache()->write(vm);
+
     jscExit(EXIT_SUCCESS);
 
 #if COMPILER(MSVC)
@@ -1865,6 +2108,21 @@ EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState* exec)
     return JSValue::encode(jsBoolean(true));
 }
 
+EncodedJSValue JSC_HOST_CALL functionIsPureNaN(ExecState* exec)
+{
+    for (size_t i = 0; i < exec->argumentCount(); ++i) {
+        JSValue value = exec->argument(i);
+        if (!value.isNumber())
+            return JSValue::encode(jsBoolean(false));
+        double number = value.asNumber();
+        if (!std::isnan(number))
+            return JSValue::encode(jsBoolean(false));
+        if (isImpureNaN(number))
+            return JSValue::encode(jsBoolean(false));
+    }
+    return JSValue::encode(jsBoolean(true));
+}
+
 EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
 
 EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
@@ -1882,7 +2140,7 @@ EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
 {
     JSValue value = exec->argument(0);
     if (value.isObject())
-        return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
+        return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties(exec->vm())));
     return JSValue::encode(jsBoolean(false));
 }
 
@@ -1909,34 +2167,6 @@ EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*)
 #endif
 }
 
-EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState* exec)
-{
-    VM& vm = exec->vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    String fileName = exec->argument(0).toWTFString(exec);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    Vector<char> script;
-    if (!fetchScriptFromLocalFileSystem(fileName, script))
-        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
-
-    JSInternalPromise* promise = loadAndEvaluateModule(exec, fileName, jsUndefined(), jsUndefined());
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-
-    JSValue error;
-    JSFunction* errorHandler = JSNativeStdFunction::create(vm, exec->lexicalGlobalObject(), 1, String(), [&](ExecState* exec) {
-        error = exec->argument(0);
-        return JSValue::encode(jsUndefined());
-    });
-
-    promise->then(exec, nullptr, errorHandler);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    vm.drainMicrotasks();
-    if (error)
-        return JSValue::encode(throwException(exec, scope, error));
-    return JSValue::encode(jsUndefined());
-}
-
 EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState* exec)
 {
     VM& vm = exec->vm();
@@ -1955,7 +2185,7 @@ EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState* exec)
     stopWatch.start();
 
     ParserError error;
-    bool validSyntax = checkModuleSyntax(exec, makeSource(source, { }, String(), TextPosition(), SourceProviderSourceType::Module), error);
+    bool validSyntax = checkModuleSyntax(exec, jscSource(source, { }, URL(), TextPosition(), SourceProviderSourceType::Module), error);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     stopWatch.stop();
 
@@ -1988,6 +2218,24 @@ EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState* exec)
     return result;
 }
 
+EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshotForGCDebugging(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    JSLockHolder lock(vm);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    String jsonString;
+    {
+        DeferGCForAWhile deferGC(vm.heap); // Prevent concurrent GC from interfering with the full GC that the snapshot does.
+
+        HeapSnapshotBuilder snapshotBuilder(vm.ensureHeapProfiler(), HeapSnapshotBuilder::SnapshotType::GCDebuggingSnapshot);
+        snapshotBuilder.buildSnapshot();
+
+        jsonString = snapshotBuilder.json();
+    }
+    scope.releaseAssertNoException();
+    return JSValue::encode(jsString(&vm, jsonString));
+}
+
 EncodedJSValue JSC_HOST_CALL functionResetSuperSamplerState(ExecState*)
 {
     resetSuperSamplerState();
@@ -1998,7 +2246,7 @@ EncodedJSValue JSC_HOST_CALL functionEnsureArrayStorage(ExecState* exec)
 {
     VM& vm = exec->vm();
     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
-        if (JSObject* object = jsDynamicCast<JSObject*>(vm, exec->argument(0)))
+        if (JSObject* object = jsDynamicCast<JSObject*>(vm, exec->argument(i)))
             object->ensureArrayStorage(vm);
     }
     return JSValue::encode(jsUndefined());
@@ -2020,7 +2268,7 @@ EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState* exec
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     if (!vm.samplingProfiler())
-        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Sampling profiler was never started"))));
+        return JSValue::encode(throwException(exec, scope, createError(exec, "Sampling profiler was never started"_s)));
 
     String jsonString = vm.samplingProfiler()->stackTracesAsJSON();
     EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
@@ -2041,7 +2289,7 @@ EncodedJSValue JSC_HOST_CALL functionAsyncTestStart(ExecState* exec)
 
     JSValue numberOfAsyncPasses = exec->argument(0);
     if (!numberOfAsyncPasses.isUInt32())
-        return throwVMError(exec, scope, ASCIILiteral("Expected first argument to a uint32"));
+        return throwVMError(exec, scope, "Expected first argument to a uint32"_s);
 
     asyncTestExpectedPasses += numberOfAsyncPasses.asUInt32();
     return encodedJSUndefined();
@@ -2060,8 +2308,8 @@ static EncodedJSValue JSC_HOST_CALL functionWebAssemblyMemoryMode(ExecState* exe
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
     
-    if (!Options::useWebAssembly())
-        return throwVMTypeError(exec, scope, ASCIILiteral("WebAssemblyMemoryMode should only be called if the useWebAssembly option is set"));
+    if (!Wasm::isSupported())
+        return throwVMTypeError(exec, scope, "WebAssemblyMemoryMode should only be called if the useWebAssembly option is set"_s);
 
     if (JSObject* object = exec->argument(0).getObject()) {
         if (auto* memory = jsDynamicCast<JSWebAssemblyMemory*>(vm, object))
@@ -2070,10 +2318,10 @@ static EncodedJSValue JSC_HOST_CALL functionWebAssemblyMemoryMode(ExecState* exe
             return JSValue::encode(jsString(&vm, makeString(instance->memoryMode())));
     }
 
-    return throwVMTypeError(exec, scope, ASCIILiteral("WebAssemblyMemoryMode expects either a WebAssembly.Memory or WebAssembly.Instance"));
+    return throwVMTypeError(exec, scope, "WebAssemblyMemoryMode expects either a WebAssembly.Memory or WebAssembly.Instance"_s);
 }
 
-#endif // ENABLE(WEBASSEBLY)
+#endif // ENABLE(WEBASSEMBLY)
 
 // Use SEH for Release builds only to get rid of the crash report dialog
 // (luckily the same tests fail in Release and Debug builds so far). Need to
@@ -2112,7 +2360,7 @@ static void startTimeoutThreadIfNeeded()
 
 int main(int argc, char** argv)
 {
-#if PLATFORM(IOS) && CPU(ARM_THUMB2)
+#if PLATFORM(IOS_FAMILY) && CPU(ARM_THUMB2)
     // Enabled IEEE754 denormal support.
     fenv_t env;
     fegetenv( &env );
@@ -2126,6 +2374,9 @@ int main(int argc, char** argv)
     // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
     ::SetErrorMode(0);
 
+    _setmode(_fileno(stdout), _O_BINARY);
+    _setmode(_fileno(stderr), _O_BINARY);
+
 #if defined(_DEBUG)
     _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
@@ -2148,7 +2399,7 @@ int main(int argc, char** argv)
     // have a chance to parse options.
     WTF::initializeThreading();
 
-#if PLATFORM(IOS)
+#if PLATFORM(IOS_FAMILY)
     Options::crashIfCantAllocateJITMemory() = true;
 #endif
 
@@ -2175,7 +2426,12 @@ static void dumpException(GlobalObject* globalObject, JSValue exception)
         } \
     } while (false)
 
-    printf("Exception: %s\n", exception.toWTFString(globalObject->globalExec()).utf8().data());
+    auto exceptionString = exception.toWTFString(globalObject->globalExec());
+    Expected<CString, UTF8ConversionError> expectedCString = exceptionString.tryGetUtf8();
+    if (expectedCString)
+        printf("Exception: %s\n", expectedCString.value().data());
+    else
+        printf("Exception: <out of memory while extracting exception string>\n");
 
     Identifier nameID = Identifier::fromString(globalObject->globalExec(), "name");
     CHECK_EXCEPTION();
@@ -2245,11 +2501,11 @@ static bool checkUncaughtException(VM& vm, GlobalObject* globalObject, JSValue e
     return false;
 }
 
-static void checkException(GlobalObject* globalObject, bool isLastFile, bool hasException, JSValue value, CommandLine& options, bool& success)
+static void checkException(ExecState* exec, GlobalObject* globalObject, bool isLastFile, bool hasException, JSValue value, CommandLine& options, bool& success)
 {
     VM& vm = globalObject->vm();
 
-    if (options.m_treatWatchdogExceptionAsSuccess && value.inherits(vm, TerminatedExecutionError::info())) {
+    if (options.m_treatWatchdogExceptionAsSuccess && value.inherits<TerminatedExecutionError>(vm)) {
         ASSERT(hasException);
         return;
     }
@@ -2257,14 +2513,14 @@ static void checkException(GlobalObject* globalObject, bool isLastFile, bool has
     if (!options.m_uncaughtExceptionName || !isLastFile) {
         success = success && !hasException;
         if (options.m_dump && !hasException)
-            printf("End: %s\n", value.toWTFString(globalObject->globalExec()).utf8().data());
+            printf("End: %s\n", value.toWTFString(exec).utf8().data());
         if (hasException)
             dumpException(globalObject, value);
     } else
         success = success && checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), options);
 }
 
-static bool runWithOptions(GlobalObject* globalObject, CommandLine& options)
+static void runWithOptions(GlobalObject* globalObject, CommandLine& options, bool& success)
 {
     Vector<Script>& scripts = options.m_scripts;
     String fileName;
@@ -2275,7 +2531,6 @@ static bool runWithOptions(GlobalObject* globalObject, CommandLine& options)
 
     VM& vm = globalObject->vm();
     auto scope = DECLARE_CATCH_SCOPE(vm);
-    bool success = true;
 
 #if ENABLE(SAMPLING_FLAGS)
     SamplingFlags::start();
@@ -2293,29 +2548,33 @@ static bool runWithOptions(GlobalObject* globalObject, CommandLine& options)
                 promise = loadAndEvaluateModule(globalObject->globalExec(), fileName, jsUndefined(), jsUndefined());
                 scope.releaseAssertNoException();
             } else {
-                if (!fetchScriptFromLocalFileSystem(fileName, scriptBuffer))
-                    return false; // fail early so we can catch missing files
+                if (!fetchScriptFromLocalFileSystem(fileName, scriptBuffer)) {
+                    success = false; // fail early so we can catch missing files
+                    return;
+                }
             }
         } else {
             size_t commandLineLength = strlen(scripts[i].argument);
             scriptBuffer.resize(commandLineLength);
             std::copy(scripts[i].argument, scripts[i].argument + commandLineLength, scriptBuffer.begin());
-            fileName = ASCIILiteral("[Command Line]");
+            fileName = "[Command Line]"_s;
         }
 
         bool isLastFile = i == scripts.size() - 1;
         if (isModule) {
-            if (!promise)
-                promise = loadAndEvaluateModule(globalObject->globalExec(), makeSource(stringFromUTF(scriptBuffer), SourceOrigin { absolutePath(fileName) }, fileName, TextPosition(), SourceProviderSourceType::Module), jsUndefined());
+            if (!promise) {
+                // FIXME: This should use an absolute file URL https://bugs.webkit.org/show_bug.cgi?id=193077
+                promise = loadAndEvaluateModule(globalObject->globalExec(), jscSource(stringFromUTF(scriptBuffer), SourceOrigin { absolutePath(fileName) }, URL({ }, fileName), TextPosition(), SourceProviderSourceType::Module), jsUndefined());
+            }
             scope.clearException();
 
-            JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
-                checkException(globalObject, isLastFile, false, exec->argument(0), options, success);
+            JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&success, &options, isLastFile](ExecState* exec) {
+                checkException(exec, jsCast<GlobalObject*>(exec->lexicalGlobalObject()), isLastFile, false, exec->argument(0), options, success);
                 return JSValue::encode(jsUndefined());
             });
 
-            JSFunction* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
-                checkException(globalObject, isLastFile, true, exec->argument(0), options, success);
+            JSFunction* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&success, &options, isLastFile](ExecState* exec) {
+                checkException(exec, jsCast<GlobalObject*>(exec->lexicalGlobalObject()), isLastFile, true, exec->argument(0), options, success);
                 return JSValue::encode(jsUndefined());
             });
 
@@ -2328,7 +2587,7 @@ static bool runWithOptions(GlobalObject* globalObject, CommandLine& options)
             scope.assertNoException();
             if (evaluationException)
                 returnValue = evaluationException->value();
-            checkException(globalObject, isLastFile, evaluationException, returnValue, options, success);
+            checkException(globalObject->globalExec(), globalObject, isLastFile, evaluationException, returnValue, options, success);
         }
 
         scriptBuffer.clear();
@@ -2338,7 +2597,6 @@ static bool runWithOptions(GlobalObject* globalObject, CommandLine& options)
 #if ENABLE(REGEXP_TRACING)
     vm.dumpRegExpTrace();
 #endif
-    return success;
 }
 
 #define RUNNING_FROM_XCODE 0
@@ -2348,7 +2606,7 @@ static void runInteractive(GlobalObject* globalObject)
     VM& vm = globalObject->vm();
     auto scope = DECLARE_CATCH_SCOPE(vm);
 
-    std::optional<DirectoryName> directoryName = currentWorkingDirectory();
+    Optional<DirectoryName> directoryName = currentWorkingDirectory();
     if (!directoryName)
         return;
     SourceOrigin sourceOrigin(resolvePath(directoryName.value(), ModuleName("interpreter")));
@@ -2366,7 +2624,7 @@ static void runInteractive(GlobalObject* globalObject)
                 break;
             source = source + String::fromUTF8(line);
             source = source + '\n';
-            checkSyntax(vm, makeSource(source, sourceOrigin), error);
+            checkSyntax(vm, jscSource(source, sourceOrigin), error);
             if (!line[0]) {
                 free(line);
                 break;
@@ -2382,7 +2640,7 @@ static void runInteractive(GlobalObject* globalObject)
         
         
         NakedPtr<Exception> evaluationException;
-        JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, sourceOrigin), JSValue(), evaluationException);
+        JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(source, sourceOrigin), JSValue(), evaluationException);
 #else
         printf("%s", interactivePrompt);
         Vector<char, 256> line;
@@ -2432,14 +2690,28 @@ static NO_RETURN void printUsageStatement(bool help = false)
     fprintf(stderr, "  --exception=<name>         Check the last script exits with an uncaught exception with the specified name\n");
     fprintf(stderr, "  --watchdog-exception-ok    Uncaught watchdog exceptions exit with success\n");
     fprintf(stderr, "  --dumpException            Dump uncaught exception text\n");
+    fprintf(stderr, "  --footprint                Dump memory footprint after done executing\n");
     fprintf(stderr, "  --options                  Dumps all JSC VM options and exits\n");
     fprintf(stderr, "  --dumpOptions              Dumps all non-default JSC VM options before continuing\n");
     fprintf(stderr, "  --<jsc VM option>=<value>  Sets the specified JSC VM option\n");
+    fprintf(stderr, "  --destroy-vm               Destroy VM before exiting\n");
+    fprintf(stderr, "\n");
+    fprintf(stderr, "Files with a .mjs extension will always be evaluated as modules.\n");
     fprintf(stderr, "\n");
 
     jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
 }
 
+static bool isMJSFile(char *filename)
+{
+    filename = strrchr(filename, '.');
+
+    if (filename)
+        return !strcmp(filename, ".mjs");
+
+    return false;
+}
+
 void CommandLine::parseArguments(int argc, char** argv)
 {
     Options::initialize();
@@ -2531,6 +2803,10 @@ void CommandLine::parseArguments(int argc, char** argv)
             m_dumpSamplingProfilerData = true;
             continue;
         }
+        if (!strcmp(arg, "--destroy-vm")) {
+            m_destroyVM = true;
+            continue;
+        }
 
         static const char* timeoutMultiplierOptStr = "--timeoutMultiplier=";
         static const unsigned timeoutMultiplierOptStrLength = strlen(timeoutMultiplierOptStr);
@@ -2568,6 +2844,11 @@ void CommandLine::parseArguments(int argc, char** argv)
             continue;
         }
 
+        if (!strcmp(arg, "--footprint")) {
+            m_dumpMemoryFootprint = true;
+            continue;
+        }
+
         static const unsigned exceptionStrLength = strlen("--exception=");
         if (!strncmp(arg, "--exception=", exceptionStrLength)) {
             m_uncaughtExceptionName = String(arg + exceptionStrLength);
@@ -2590,7 +2871,8 @@ void CommandLine::parseArguments(int argc, char** argv)
 
         // This arg is not recognized by the VM nor by jsc. Pass it on to the
         // script.
-        m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Script, argv[i]));
+        Script::ScriptType scriptType = isMJSFile(argv[i]) ? Script::ScriptType::Module : Script::ScriptType::Script;
+        m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, scriptType, argv[i]));
     }
 
     if (hasBadJSCOptions && JSC::Options::validateOptions())
@@ -2614,28 +2896,31 @@ void CommandLine::parseArguments(int argc, char** argv)
 }
 
 template<typename Func>
-int runJSC(CommandLine options, bool isWorker, const Func& func)
+int runJSC(const CommandLine& options, bool isWorker, const Func& func)
 {
     Worker worker(Workers::singleton());
     
     VM& vm = VM::create(LargeHeap).leakRef();
     int result;
-    bool success;
+    bool success = true;
+    GlobalObject* globalObject = nullptr;
     {
         JSLockHolder locker(vm);
 
         if (options.m_profile && !vm.m_perBytecodeProfiler)
             vm.m_perBytecodeProfiler = std::make_unique<Profiler::Database>(vm);
 
-        GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), options.m_arguments);
+        globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), options.m_arguments);
         globalObject->setRemoteDebuggingEnabled(options.m_enableRemoteDebugging);
-        success = func(vm, globalObject);
-        if (options.m_interactive && success)
-            runInteractive(globalObject);
-
+        func(vm, globalObject, success);
         vm.drainMicrotasks();
     }
     vm.promiseDeferredTimer->runRunLoop();
+    {
+        JSLockHolder locker(vm);
+        if (options.m_interactive && success)
+            runInteractive(globalObject);
+    }
 
     result = success && (asyncTestExpectedPasses == asyncTestPasses) ? 0 : 3;
 
@@ -2672,7 +2957,7 @@ int runJSC(CommandLine options, bool isWorker, const Func& func)
         for (auto& entry : compileTimeStats)
             compileTimeKeys.append(entry.key);
         std::sort(compileTimeKeys.begin(), compileTimeKeys.end());
-        for (CString key : compileTimeKeys)
+        for (const CString& key : compileTimeKeys)
             printf("%40s: %.3lf ms\n", key.data(), compileTimeStats.get(key).milliseconds());
     }
 #endif
@@ -2693,7 +2978,9 @@ int runJSC(CommandLine options, bool isWorker, const Func& func)
 #endif
     }
 
-    if (isWorker) {
+    vm.codeCache()->write(vm);
+
+    if (options.m_destroyVM || isWorker) {
         JSLockHolder locker(vm);
         // This is needed because we don't want the worker's main
         // thread to die before its compilation threads finish.
@@ -2723,15 +3010,61 @@ int jscmain(int argc, char** argv)
 #endif
     Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled();
 
-    int result;
-    result = runJSC(
+#if PLATFORM(COCOA)
+    auto& memoryPressureHandler = MemoryPressureHandler::singleton();
+    {
+        dispatch_queue_t queue = dispatch_queue_create("jsc shell memory pressure handler", DISPATCH_QUEUE_SERIAL);
+        memoryPressureHandler.setDispatchQueue(queue);
+        dispatch_release(queue);
+    }
+    Box<Critical> memoryPressureCriticalState = Box<Critical>::create(Critical::No);
+    Box<Synchronous> memoryPressureSynchronousState = Box<Synchronous>::create(Synchronous::No);
+    memoryPressureHandler.setLowMemoryHandler([=] (Critical critical, Synchronous synchronous) {
+        // We set these racily with respect to reading them from the JS execution thread.
+        *memoryPressureCriticalState = critical;
+        *memoryPressureSynchronousState = synchronous;
+    });
+    memoryPressureHandler.setShouldLogMemoryMemoryPressureEvents(false);
+    memoryPressureHandler.install();
+
+    auto onEachMicrotaskTick = [&] (VM& vm) {
+        if (*memoryPressureCriticalState == Critical::No)
+            return;
+
+        *memoryPressureCriticalState = Critical::No;
+        bool isSynchronous = *memoryPressureSynchronousState == Synchronous::Yes;
+
+        WTF::releaseFastMallocFreeMemory();
+        vm.deleteAllCode(DeleteAllCodeIfNotCollecting);
+
+        if (!vm.heap.isCurrentThreadBusy()) {
+            if (isSynchronous) {
+                vm.heap.collectNow(Sync, CollectionScope::Full);
+                WTF::releaseFastMallocFreeMemory();
+            } else
+                vm.heap.collectNowFullIfNotDoneRecently(Async);
+        }
+    };
+#endif
+
+    int result = runJSC(
         options, false,
-        [&] (VM&, GlobalObject* globalObject) {
-            return runWithOptions(globalObject, options);
+        [&] (VM& vm, GlobalObject* globalObject, bool& success) {
+            UNUSED_PARAM(vm);
+#if PLATFORM(COCOA)
+            vm.setOnEachMicrotaskTick(WTFMove(onEachMicrotaskTick));
+#endif
+            runWithOptions(globalObject, options, success);
         });
 
     printSuperSamplerState();
 
+    if (options.m_dumpMemoryFootprint) {
+        MemoryFootprint footprint = MemoryFootprint::now();
+
+        printf("Memory Footprint:\n    Current Footprint: %" PRIu64 "\n    Peak Footprint: %" PRIu64 "\n", footprint.current, footprint.peak);
+    }
+
     return result;
 }