[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/PascalMing/ClearScript/master/ClearScriptV8/V8ContextImpl.cpp [Back]  [Original]

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

#include "ClearScriptV8Native.h"

//-----------------------------------------------------------------------------
// FromMaybeScope
//-----------------------------------------------------------------------------

class FromMaybeScope final
{
};

//-----------------------------------------------------------------------------
// FromMaybeFailure
//-----------------------------------------------------------------------------

class FromMaybeFailure final
{
};

//-----------------------------------------------------------------------------
// local helper functions
//-----------------------------------------------------------------------------

template 
inline T FromMaybe(FromMaybeScope& /*scope*/, const v8::Maybe& maybe)
{
    T result;
    if (maybe.To(&result))
    {
        return result;
    }

    throw FromMaybeFailure();
}

//-----------------------------------------------------------------------------

template 
inline v8::Local FromMaybe(FromMaybeScope& /*scope*/, const v8::MaybeLocal& maybe)
{
    v8::Local result;
    if (maybe.ToLocal(&result))
    {
        return result;
    }

    throw FromMaybeFailure();
}

//-----------------------------------------------------------------------------

template 
inline T FromMaybeDefault(const v8::Maybe& maybe, const T& defaultValue = T())
{
    return maybe.FromMaybe(defaultValue);
}

//-----------------------------------------------------------------------------

template 
inline v8::Local FromMaybeDefault(const v8::MaybeLocal& maybe, const v8::Local& defaultValue = v8::Local())
{
    return maybe.FromMaybe(defaultValue);
}

//-----------------------------------------------------------------------------

inline v8::Local ValueAsString(const v8::Local& hValue)
{
    return (!hValue.IsEmpty() && hValue->IsString()) ? hValue.As() : v8::Local();
}

//-----------------------------------------------------------------------------

inline v8::Local ValueAsObject(const v8::Local& hValue)
{
    return (!hValue.IsEmpty() && hValue->IsObject()) ? hValue.As() : v8::Local();
}

//-----------------------------------------------------------------------------

inline v8::Local ValueAsExternal(const v8::Local& hValue)
{
    return (!hValue.IsEmpty() && hValue->IsExternal()) ? hValue.As() : v8::Local();
}

//-----------------------------------------------------------------------------

inline v8::Local ValueAsBigInt(const v8::Local& hValue)
{
    return (!hValue.IsEmpty() && hValue->IsBigInt()) ? hValue.As() : v8::Local();
}

//-----------------------------------------------------------------------------

template 
static V8ContextImpl* GetContextImplFromHolder(const TInfo& info)
{
    auto hHolder = info.Holder();
    if (!hHolder.IsEmpty() && hHolder->InternalFieldCount() > 0)
    {
        auto hField = hHolder->GetInternalField(0);
        if (!hField.IsEmpty() && !hField->IsUndefined())
        {
            return static_cast(hHolder->GetAlignedPointerFromInternalField(0));
        }
    }

    return nullptr;
}

//-----------------------------------------------------------------------------

template 
static V8ContextImpl* GetContextImplFromData(const TInfo& info)
{
    auto hContextImpl = ::ValueAsExternal(info.Data());
    return !hContextImpl.IsEmpty() ? static_cast(hContextImpl->Value()) : nullptr;
}

//-----------------------------------------------------------------------------
// V8ContextImpl implementation
//-----------------------------------------------------------------------------

#define BEGIN_ISOLATE_SCOPE \
    { \
        DISABLE_WARNING(4456) /* declaration hides previous local declaration */ \
        V8IsolateImpl::Scope t_IsolateScope(*m_spIsolateImpl); \
        DEFAULT_WARNING(4456)

#define END_ISOLATE_SCOPE \
        IGNORE_UNUSED(t_IsolateScope); \
    }

#define FROM_MAYBE_TRY \
    { \
        DISABLE_WARNING(4456) /* declaration hides previous local declaration */ \
        FromMaybeScope t_FromMaybeScope; \
        DEFAULT_WARNING(4456) \
        try \
        {

#define FROM_MAYBE_CATCH \
            IGNORE_UNUSED(t_FromMaybeScope); \
        } \
        catch (const FromMaybeFailure&) \
        { \

#define FROM_MAYBE_END \
            IGNORE_UNUSED(t_FromMaybeScope); \
        } \
    }

#define FROM_MAYBE_CATCH_CONSUME \
    FROM_MAYBE_CATCH \
    FROM_MAYBE_END

#define FROM_MAYBE(...) \
    (::FromMaybe(t_FromMaybeScope, __VA_ARGS__))

#define FROM_MAYBE_DEFAULT(...) \
    (::FromMaybeDefault(__VA_ARGS__))

#define BEGIN_CONTEXT_SCOPE \
    { \
        DISABLE_WARNING(4456) /* declaration hides previous local declaration */ \
        Scope t_ContextScope(this); \
        DEFAULT_WARNING(4456)

#define END_CONTEXT_SCOPE \
        IGNORE_UNUSED(t_ContextScope); \
    }

#define BEGIN_EXECUTION_SCOPE \
    { \
        DISABLE_WARNING(4456) /* declaration hides previous local declaration */ \
        V8IsolateImpl::ExecutionScope t_ExecutionScope(*m_spIsolateImpl); \
        V8IsolateImpl::TryCatch t_TryCatch(*m_spIsolateImpl); \
        DEFAULT_WARNING(4456)

#define END_EXECUTION_SCOPE \
        IGNORE_UNUSED(t_TryCatch); \
        IGNORE_UNUSED(t_ExecutionScope); \
    }

#define EXECUTION_STARTED \
    (t_ExecutionScope.ExecutionStarted())

#define BEGIN_DOCUMENT_SCOPE(DOCUMENT_INFO) \
    { \
        DISABLE_WARNING(4456) /* declaration hides previous local declaration */ \
        V8IsolateImpl::DocumentScope t_DocumentScope(*m_spIsolateImpl, DOCUMENT_INFO); \
        DEFAULT_WARNING(4456)

#define END_DOCUMENT_SCOPE \
        IGNORE_UNUSED(t_DocumentScope); \
    }

#define VERIFY(RESULT) \
    (Verify(t_ExecutionScope, t_TryCatch, RESULT))

#define VERIFY_MAYBE(RESULT) \
    VERIFY(FROM_MAYBE_DEFAULT(RESULT))

#define VERIFY_CHECKPOINT() \
    (Verify(t_ExecutionScope, t_TryCatch))

#define CALLBACK_RETURN(RESULT) \
    BEGIN_COMPOUND_MACRO \
        info.GetReturnValue().Set(RESULT); \
        return; \
    END_COMPOUND_MACRO

//-----------------------------------------------------------------------------

static std::atomic s_InstanceCount(0);

//-----------------------------------------------------------------------------

V8ContextImpl::V8ContextImpl(V8IsolateImpl* pIsolateImpl, const StdString& name):
    V8ContextImpl(SharedPtr(pIsolateImpl), name, Options())
{
}

//-----------------------------------------------------------------------------

V8ContextImpl::V8ContextImpl(SharedPtr&& spIsolateImpl, const StdString& name, const Options& options):
    m_Name(name),
    m_spIsolateImpl(std::move(spIsolateImpl)),
    m_DateTimeConversionEnabled(HasFlag(options.Flags, Flags::EnableDateTimeConversion)),
    m_HideHostExceptions(HasFlag(options.Flags, Flags::HideHostExceptions)),
    m_pvV8ObjectCache(nullptr),
    m_AllowHostObjectConstructorCall(false)
{
    VerifyNotOutOfMemory();

    BEGIN_ISOLATE_SCOPE
    FROM_MAYBE_TRY

        if (HasFlag(options.Flags, Flags::DisableGlobalMembers))
        {
            m_hContext = CreatePersistent(CreateContext());
        }
        else
        {
            auto hGlobalTemplate = CreateObjectTemplate();
            hGlobalTemplate->SetInternalFieldCount(1);
            hGlobalTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(GetGlobalProperty, SetGlobalProperty, QueryGlobalProperty, DeleteGlobalProperty, GetGlobalPropertyNames, v8::Local(), v8::PropertyHandlerFlags::kNonMasking));
            hGlobalTemplate->SetHandler(v8::IndexedPropertyHandlerConfiguration(GetGlobalProperty, SetGlobalProperty, QueryGlobalProperty, DeleteGlobalProperty, GetGlobalPropertyIndices));

            m_hContext = CreatePersistent(CreateContext(nullptr, hGlobalTemplate));

            auto hGlobal = ::ValueAsObject(m_hContext->Global()->GetPrototype());
            if (!hGlobal.IsEmpty() && (hGlobal->InternalFieldCount() > 0))
            {
                hGlobal->SetAlignedPointerInInternalField(0, this);
            }
        }

        auto hContextImpl = CreateExternal(this);

        v8::Local hGetIteratorFunction;
        v8::Local hGetAsyncIteratorFunction;
        v8::Local hGetJsonFunction;
        v8::Local hToFunctionFunction;

        BEGIN_CONTEXT_SCOPE

            m_hContext->SetAlignedPointerInEmbedderData(1, this);

            m_hIsHostObjectKey = CreatePersistent(CreateSymbol());
            FROM_MAYBE(m_hContext->Global()->Set(m_hContext, CreateString("isHostObjectKey"), m_hIsHostObjectKey));

            m_hHostExceptionKey = CreatePersistent(CreateString("hostException"));
            m_hCacheKey = CreatePersistent(CreatePrivate());
            m_hAccessTokenKey = CreatePersistent(CreatePrivate());
            m_hInternalUseOnly = CreatePersistent(CreateString("The invoked function is for ClearScript internal use only"));
            m_hStackKey = CreatePersistent(CreateString("stack"));
            m_hObjectNotInvocable = CreatePersistent(CreateString("The object does not support invocation"));
            m_hMethodOrPropertyNotFound = CreatePersistent(CreateString("Method or property not found"));
            m_hPropertyValueNotInvocable = CreatePersistent(CreateString("The property value does not support invocation"));
            m_hInvalidModuleRequest = CreatePersistent(CreateString("Invalid module load request"));
            m_hConstructorKey = CreatePersistent(CreateString("constructor"));

            hGetIteratorFunction = CreateFunctionTemplate(GetHostObjectIterator, hContextImpl);
            hGetAsyncIteratorFunction = CreateFunctionTemplate(GetHostObjectAsyncIterator, hContextImpl);
            hGetJsonFunction = CreateFunctionTemplate(GetHostObjectJson, hContextImpl);
            hToFunctionFunction = CreateFunctionTemplate(CreateFunctionForHostDelegate, hContextImpl);

            m_hAccessToken = CreatePersistent(CreateObject());
            m_hFlushFunction = CreatePersistent(FROM_MAYBE(v8::Function::New(m_hContext, FlushCallback)));
            m_hTerminationException = CreatePersistent(v8::Exception::Error(CreateString("Script execution was interrupted")));

        END_CONTEXT_SCOPE

        auto hToJSON = CreateString("toJSON");

        m_hHostObjectTemplate = CreatePersistent(CreateFunctionTemplate());
        m_hHostObjectTemplate->SetClassName(CreateString("HostObject"));
        m_hHostObjectTemplate->SetCallHandler(HostObjectConstructorCallHandler, hContextImpl);
        m_hHostObjectTemplate->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyNames, hContextImpl, v8::PropertyHandlerFlags::kNone));
        m_hHostObjectTemplate->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyIndices, hContextImpl));
        m_hHostObjectTemplate->PrototypeTemplate()->Set(GetIteratorSymbol(), hGetIteratorFunction);
        m_hHostObjectTemplate->PrototypeTemplate()->Set(GetAsyncIteratorSymbol(), hGetAsyncIteratorFunction);
        m_hHostObjectTemplate->PrototypeTemplate()->Set(hToJSON, hGetJsonFunction);

        m_hHostInvocableTemplate = CreatePersistent(CreateFunctionTemplate());
        m_hHostInvocableTemplate->SetClassName(CreateString("HostInvocable"));
        m_hHostInvocableTemplate->SetCallHandler(HostObjectConstructorCallHandler, hContextImpl);
        m_hHostInvocableTemplate->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyNames, hContextImpl, v8::PropertyHandlerFlags::kNone));
        m_hHostInvocableTemplate->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyIndices, hContextImpl));
        m_hHostInvocableTemplate->PrototypeTemplate()->Set(GetIteratorSymbol(), hGetIteratorFunction);
        m_hHostInvocableTemplate->PrototypeTemplate()->Set(GetAsyncIteratorSymbol(), hGetAsyncIteratorFunction);
        m_hHostInvocableTemplate->PrototypeTemplate()->Set(hToJSON, hGetJsonFunction);
        m_hHostInvocableTemplate->InstanceTemplate()->SetCallAsFunctionHandler(InvokeHostObject, hContextImpl);

        m_hHostDelegateTemplate = CreatePersistent(CreateFunctionTemplate());
        m_hHostDelegateTemplate->SetClassName(CreateString("HostDelegate"));
        m_hHostDelegateTemplate->SetCallHandler(HostObjectConstructorCallHandler, hContextImpl);
        m_hHostDelegateTemplate->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyNames, hContextImpl, v8::PropertyHandlerFlags::kNone));
        m_hHostDelegateTemplate->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(GetHostObjectProperty, SetHostObjectProperty, QueryHostObjectProperty, DeleteHostObjectProperty, GetHostObjectPropertyIndices, hContextImpl));
        m_hHostDelegateTemplate->PrototypeTemplate()->Set(GetIteratorSymbol(), hGetIteratorFunction);
        m_hHostDelegateTemplate->PrototypeTemplate()->Set(GetAsyncIteratorSymbol(), hGetAsyncIteratorFunction);
        m_hHostDelegateTemplate->PrototypeTemplate()->Set(hToJSON, hGetJsonFunction);
        m_hHostDelegateTemplate->InstanceTemplate()->SetCallAsFunctionHandler(InvokeHostObject, hContextImpl);
        m_hHostDelegateTemplate->InstanceTemplate()->SetHostDelegate(); // instructs our patched V8 typeof implementation to return "function" 
        m_hHostDelegateTemplate->PrototypeTemplate()->Set(CreateString("toFunction"), hToFunctionFunction);

        m_pvV8ObjectCache = HostObjectUtil::GetInstance().CreateV8ObjectCache();
        m_spIsolateImpl->AddContext(this, options);

    FROM_MAYBE_CATCH

        Teardown();
        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot initialize the script engine because a script exception is pending")), false /*executionStarted*/);

    FROM_MAYBE_END
    END_ISOLATE_SCOPE

    ++s_InstanceCount;
}

//-----------------------------------------------------------------------------

size_t V8ContextImpl::GetInstanceCount()
{
    return s_InstanceCount;
}

//-----------------------------------------------------------------------------

size_t V8ContextImpl::GetMaxIsolateHeapSize()
{
    return m_spIsolateImpl->GetMaxHeapSize();
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetMaxIsolateHeapSize(size_t value)
{
    m_spIsolateImpl->SetMaxHeapSize(value);
}

//-----------------------------------------------------------------------------

double V8ContextImpl::GetIsolateHeapSizeSampleInterval()
{
    return m_spIsolateImpl->GetHeapSizeSampleInterval();
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetIsolateHeapSizeSampleInterval(double value)
{
    m_spIsolateImpl->SetHeapSizeSampleInterval(value);
}

//-----------------------------------------------------------------------------

size_t V8ContextImpl::GetMaxIsolateStackUsage()
{
    return m_spIsolateImpl->GetMaxStackUsage();
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetMaxIsolateStackUsage(size_t value)
{
    m_spIsolateImpl->SetMaxStackUsage(value);
}

//-----------------------------------------------------------------------------

void V8ContextImpl::CallWithLock(CallWithLockCallback* pCallback, void* pvArg)
{
    VerifyNotOutOfMemory();

    BEGIN_ISOLATE_SCOPE

        (*pCallback)(pvArg);

    END_ISOLATE_SCOPE
}

//-----------------------------------------------------------------------------

V8Value V8ContextImpl::GetRootObject()
{
    BEGIN_CONTEXT_SCOPE

        return ExportValue(m_hContext->Global());

    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetGlobalProperty(const StdString& name, const V8Value& value, bool globalMembers)
{
    BEGIN_CONTEXT_SCOPE
    FROM_MAYBE_TRY

        auto hName = FROM_MAYBE(CreateString(name));
        auto hValue = ::ValueAsObject(ImportValue(value));

        v8::Local hOldValue;
        if (FROM_MAYBE(m_hContext->Global()->HasOwnProperty(m_hContext, hName)))
        {
            hOldValue = ::ValueAsObject(FROM_MAYBE(m_hContext->Global()->GetRealNamedProperty(m_hContext, hName)));
        }

        auto result = FROM_MAYBE(m_hContext->Global()->DefineOwnProperty(m_hContext, hName, hValue, v8::ReadOnly));
        if (result && globalMembers && !hValue.IsEmpty())
        {
            if (!hOldValue.IsEmpty())
            {
                for (auto it = m_GlobalMembersStack.begin(); it != m_GlobalMembersStack.end(); it++)
                {
                    if (it->first == name)
                    {
                        Dispose(it->second);
                        m_GlobalMembersStack.erase(it);
                        break;
                    }
                }
            }

            m_GlobalMembersStack.emplace_back(name, CreatePersistent(hValue));
        }

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), false /*executionStarted*/);

    FROM_MAYBE_END
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::AwaitDebuggerAndPause()
{
    m_spIsolateImpl->AwaitDebuggerAndPause();
}

//-----------------------------------------------------------------------------

void V8ContextImpl::CancelAwaitDebugger()
{
    m_spIsolateImpl->CancelAwaitDebugger();
}

//-----------------------------------------------------------------------------

V8Value V8ContextImpl::Execute(const V8DocumentInfo& documentInfo, const StdString& code, bool evaluate)
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_DOCUMENT_SCOPE(documentInfo)
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        auto codeDigest = code.GetDigest();
        v8::ScriptCompiler::Source source(FROM_MAYBE(CreateString(code)), CreateScriptOrigin(documentInfo));
        v8::Local hResult;

        if (documentInfo.IsModule())
        {
            auto hModule = GetCachedModule(documentInfo.GetUniqueId(), codeDigest);
            if (hModule.IsEmpty())
            {
                hModule = VERIFY_MAYBE(CompileModule(&source));
                if (hModule.IsEmpty())
                {
                    throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Module compilation failed; no additional information was provided by the V8 runtime")), false /*executionStarted*/);
                }

                CacheModule(documentInfo, codeDigest, hModule);
            }

            if (hModule->GetStatus() == v8::Module::kUninstantiated)
            {
                ASSERT_EVAL(VERIFY_MAYBE(hModule->InstantiateModule(m_hContext, V8IsolateImpl::ModuleResolveCallback)));
            }

            if (hModule->GetStatus() == v8::Module::kInstantiated)
            {
                hResult = VERIFY_MAYBE(hModule->Evaluate(m_hContext));
                if (!hModule->IsGraphAsync() && hResult->IsPromise())
                {
                    auto hPromise = hResult.As();
                    if (hPromise->State() == v8::Promise::PromiseState::kFulfilled)
                    {
                        hResult = hPromise->Result();
                    }
                    else if (hPromise->State() == v8::Promise::PromiseState::kRejected)
                    {
                        auto hException = hPromise->Result();

                        if (hException->IsObject())
                        {
                            auto hExceptionObject = hException.As();
                            auto hHostException = FROM_MAYBE(hExceptionObject->Get(m_hContext, m_hHostExceptionKey));
                            throw V8Exception(V8Exception::Type::General, m_Name, CreateStdString(hExceptionObject), CreateStdString(FROM_MAYBE(hExceptionObject->Get(m_hContext, m_hStackKey))), EXECUTION_STARTED, ExportValue(hException), ExportValue(hHostException));
                        }

                        throw V8Exception(V8Exception::Type::General, m_Name, CreateStdString(hException), StdString(), EXECUTION_STARTED, ExportValue(hException), V8Value(V8Value::Undefined));
                    }
                }
            }
            else
            {
                evaluate = false;
            }
        }
        else
        {
            auto hScript = GetCachedScript(documentInfo.GetUniqueId(), codeDigest);
            if (hScript.IsEmpty())
            {
                hScript = VERIFY_MAYBE(CompileUnboundScript(&source));
                if (hScript.IsEmpty())
                {
                    throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Script compilation failed; no additional information was provided by the V8 runtime")), false /*executionStarted*/);
                }

                CacheScript(documentInfo, codeDigest, hScript);
            }

            hResult = VERIFY_MAYBE(hScript->BindToCurrentContext()->Run(m_hContext));
        }

        if (!evaluate)
        {
            hResult = GetUndefined();
        }

        return ExportValue(hResult);

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_DOCUMENT_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

V8ScriptHolder* V8ContextImpl::Compile(const V8DocumentInfo& documentInfo, StdString&& code)
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_DOCUMENT_SCOPE(documentInfo)
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        auto codeDigest = code.GetDigest();
        v8::ScriptCompiler::Source source(FROM_MAYBE(CreateString(code)), CreateScriptOrigin(documentInfo));
        std::unique_ptr upScriptHolder;

        if (documentInfo.IsModule())
        {
            auto hModule = GetCachedModule(documentInfo.GetUniqueId(), codeDigest);
            if (hModule.IsEmpty())
            {
                hModule = VERIFY_MAYBE(CompileModule(&source));
                if (hModule.IsEmpty())
                {
                    throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Module compilation failed; no additional information was provided by the V8 runtime")), false /*executionStarted*/);
                }

                CacheModule(documentInfo, codeDigest, hModule);
            }

            upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hModule)), documentInfo, codeDigest, std::move(code)));
        }
        else
        {
            auto hScript = GetCachedScript(documentInfo.GetUniqueId(), codeDigest);
            if (hScript.IsEmpty())
            {
                hScript = VERIFY_MAYBE(CompileUnboundScript(&source));
                if (hScript.IsEmpty())
                {
                    throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Script compilation failed; no additional information was provided by the V8 runtime")), false /*executionStarted*/);
                }

                CacheScript(documentInfo, codeDigest, hScript);
            }

            upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hScript)), documentInfo, codeDigest));
        }

        return upScriptHolder.release();

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_DOCUMENT_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

V8ScriptHolder* V8ContextImpl::Compile(const V8DocumentInfo& documentInfo, StdString&& code, V8CacheType cacheType, std::vector& cacheBytes)
{
    if (cacheType == V8CacheType::None)
    {
        cacheBytes.clear();
        return Compile(documentInfo, std::move(code));
    }

    BEGIN_CONTEXT_SCOPE
    BEGIN_DOCUMENT_SCOPE(documentInfo)
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        auto codeDigest = code.GetDigest();
        v8::ScriptCompiler::Source source(FROM_MAYBE(CreateString(code)), CreateScriptOrigin(documentInfo));
        std::unique_ptr upScriptHolder;
        std::unique_ptr upCachedData;

        if (documentInfo.IsModule())
        {
            auto hModule = GetCachedModule(documentInfo.GetUniqueId(), codeDigest);
            if (hModule.IsEmpty())
            {
                hModule = VERIFY_MAYBE(CompileModule(&source));
                if (hModule.IsEmpty())
                {
                    throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Module compilation failed; no additional information was provided by the V8 runtime")), false /*executionStarted*/);
                }

                CacheModule(documentInfo, codeDigest, hModule);
            }

            upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hModule)), documentInfo, codeDigest, std::move(code)));
            upCachedData.reset(v8::ScriptCompiler::CreateCodeCache(hModule->GetUnboundModuleScript()));
        }
        else
        {
            auto hScript = GetCachedScript(documentInfo.GetUniqueId(), codeDigest);
            if (hScript.IsEmpty())
            {
                hScript = VERIFY_MAYBE(CompileUnboundScript(&source));
                if (hScript.IsEmpty())
                {
                    throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Script compilation failed; no additional information was provided by the V8 runtime")), false /*executionStarted*/);
                }

                CacheScript(documentInfo, codeDigest, hScript);
            }

            upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hScript)), documentInfo, codeDigest));
            upCachedData.reset(v8::ScriptCompiler::CreateCodeCache(hScript));
        }

        cacheBytes.clear();
        if (upCachedData && (upCachedData->length > 0) && (upCachedData->data != nullptr))
        {
            cacheBytes.resize(upCachedData->length);
            memcpy(cacheBytes.data(), upCachedData->data, upCachedData->length);

            if (documentInfo.IsModule())
            {
                upScriptHolder->SetCacheBytes(cacheBytes);
            }
        }

        return upScriptHolder.release();

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_DOCUMENT_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

V8ScriptHolder* V8ContextImpl::Compile(const V8DocumentInfo& documentInfo, StdString&& code, V8CacheType cacheType, const std::vector& cacheBytes, bool& cacheAccepted)
{
    if ((cacheType == V8CacheType::None) || (cacheBytes.size() < 1))
    {
        cacheAccepted = false;
        return Compile(documentInfo, std::move(code));
    }

    BEGIN_CONTEXT_SCOPE
    BEGIN_DOCUMENT_SCOPE(documentInfo)
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        auto codeDigest = code.GetDigest();
        auto pCachedData = new v8::ScriptCompiler::CachedData(cacheBytes.data(), static_cast(cacheBytes.size()), v8::ScriptCompiler::CachedData::BufferNotOwned);
        v8::ScriptCompiler::Source source(FROM_MAYBE(CreateString(code)), CreateScriptOrigin(documentInfo), pCachedData);
        std::unique_ptr upScriptHolder;

        if (documentInfo.IsModule())
        {
            auto hModule = GetCachedModule(documentInfo.GetUniqueId(), codeDigest);
            if (hModule.IsEmpty())
            {
                hModule = VERIFY_MAYBE(CompileModule(&source, v8::ScriptCompiler::kConsumeCodeCache));
                if (hModule.IsEmpty())
                {
                    throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Module compilation failed; no additional information was provided by the V8 runtime")), false /*executionStarted*/);
                }

                CacheModule(documentInfo, codeDigest, hModule);
            }

            upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hModule)), documentInfo, codeDigest, std::move(code)));
        }
        else
        {
            auto hScript = GetCachedScript(documentInfo.GetUniqueId(), codeDigest);
            if (hScript.IsEmpty())
            {
                hScript = VERIFY_MAYBE(CompileUnboundScript(&source, v8::ScriptCompiler::kConsumeCodeCache));
                if (hScript.IsEmpty())
                {
                    throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Script compilation failed; no additional information was provided by the V8 runtime")), false /*executionStarted*/);
                }

                CacheScript(documentInfo, codeDigest, hScript);
            }

            upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hScript)), documentInfo, codeDigest));
        }

        cacheAccepted = !pCachedData->rejected;
        if (cacheAccepted && documentInfo.IsModule())
        {
            upScriptHolder->SetCacheBytes(cacheBytes);
        }

        return upScriptHolder.release();

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_DOCUMENT_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::CanExecute(const SharedPtr& spHolder)
{
    return spHolder->IsSameIsolate(m_spIsolateImpl);
}

//-----------------------------------------------------------------------------

V8Value V8ContextImpl::Execute(const SharedPtr& spHolder, bool evaluate)
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_DOCUMENT_SCOPE(spHolder->GetDocumentInfo())
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        if (!CanExecute(spHolder))
        {
            throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Invalid compiled script")), false /*executionStarted*/);
        }

        v8::Local hResult;

        if (spHolder->GetDocumentInfo().IsModule())
        {
            auto codeDigest = spHolder->GetCode().GetDigest();
            auto hModule = GetCachedModule(spHolder->GetDocumentInfo().GetUniqueId(), codeDigest);
            if (hModule.IsEmpty())
            {
                if (spHolder->GetCacheBytes().size() > 0)
                {
                    auto pCachedData = new v8::ScriptCompiler::CachedData(spHolder->GetCacheBytes().data(), static_cast(spHolder->GetCacheBytes().size()), v8::ScriptCompiler::CachedData::BufferNotOwned);
                    v8::ScriptCompiler::Source source(FROM_MAYBE(CreateString(spHolder->GetCode())), CreateScriptOrigin(spHolder->GetDocumentInfo()), pCachedData);
                    hModule = VERIFY_MAYBE(CompileModule(&source));
                    _ASSERTE(!pCachedData->rejected);
                }
                else
                {
                    v8::ScriptCompiler::Source source(FROM_MAYBE(CreateString(spHolder->GetCode())), CreateScriptOrigin(spHolder->GetDocumentInfo()));
                    hModule = VERIFY_MAYBE(CompileModule(&source));
                }

                if (hModule.IsEmpty())
                {
                    throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Module compilation failed; no additional information was provided by the V8 runtime")), false /*executionStarted*/);
                }

                CacheModule(spHolder->GetDocumentInfo(), codeDigest, hModule);
            }

            if (hModule->GetStatus() == v8::Module::kUninstantiated)
            {
                ASSERT_EVAL(VERIFY_MAYBE(hModule->InstantiateModule(m_hContext, V8IsolateImpl::ModuleResolveCallback)));
            }

            if (hModule->GetStatus() == v8::Module::kInstantiated)
            {
                hResult = VERIFY_MAYBE(hModule->Evaluate(m_hContext));
                if (!hModule->IsGraphAsync() && hResult->IsPromise())
                {
                    auto hPromise = hResult.As();
                    if (hPromise->State() == v8::Promise::PromiseState::kFulfilled)
                    {
                        hResult = hPromise->Result();
                    }
                    else if (hPromise->State() == v8::Promise::PromiseState::kRejected)
                    {
                        auto hException = hPromise->Result();

                        if (hException->IsObject())
                        {
                            auto hExceptionObject = hException.As();
                            auto hHostException = FROM_MAYBE(hExceptionObject->Get(m_hContext, m_hHostExceptionKey));
                            throw V8Exception(V8Exception::Type::General, m_Name, CreateStdString(hExceptionObject), CreateStdString(FROM_MAYBE(hExceptionObject->Get(m_hContext, m_hStackKey))), EXECUTION_STARTED, ExportValue(hException), ExportValue(hHostException));
                        }

                        throw V8Exception(V8Exception::Type::General, m_Name, CreateStdString(hException), StdString(), EXECUTION_STARTED, ExportValue(hException), V8Value(V8Value::Undefined));
                    }
                }
            }
            else
            {
                evaluate = false;
            }
        }
        else
        {
            auto hScript = ::HandleFromPtr(spHolder->GetScript());
            hResult = VERIFY_MAYBE(hScript->BindToCurrentContext()->Run(m_hContext));
        }

        if (!evaluate)
        {
            hResult = GetUndefined();
        }

        return ExportValue(hResult);

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_DOCUMENT_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::Interrupt()
{
    TerminateExecution();
}

//-----------------------------------------------------------------------------

void V8ContextImpl::CancelInterrupt()
{
    CancelTerminateExecution();
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::GetEnableIsolateInterruptPropagation()
{
    return m_spIsolateImpl->GetEnableInterruptPropagation();
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetEnableIsolateInterruptPropagation(bool value)
{
    m_spIsolateImpl->SetEnableInterruptPropagation(value);
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::GetDisableIsolateHeapSizeViolationInterrupt()
{
    return m_spIsolateImpl->GetDisableHeapSizeViolationInterrupt();
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetDisableIsolateHeapSizeViolationInterrupt(bool value)
{
    m_spIsolateImpl->SetDisableHeapSizeViolationInterrupt(value);
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetIsolateHeapStatistics(v8::HeapStatistics& heapStatistics)
{
    m_spIsolateImpl->GetHeapStatistics(heapStatistics);
}

//-----------------------------------------------------------------------------

V8Isolate::Statistics V8ContextImpl::GetIsolateStatistics()
{
    return m_spIsolateImpl->GetStatistics();
}

//-----------------------------------------------------------------------------

V8ContextImpl::Statistics V8ContextImpl::GetStatistics()
{
    _ASSERTE(m_spIsolateImpl->IsCurrent() && m_spIsolateImpl->IsLocked());

    return m_Statistics;
}

//-----------------------------------------------------------------------------

void V8ContextImpl::CollectGarbage(bool exhaustive)
{
    m_spIsolateImpl->CollectGarbage(exhaustive);
}

//-----------------------------------------------------------------------------

void V8ContextImpl::OnAccessSettingsChanged()
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_EXECUTION_SCOPE

        Dispose(m_hAccessToken);
        m_hAccessToken = CreatePersistent(CreateObject());

    END_EXECUTION_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::BeginCpuProfile(const StdString& name, v8::CpuProfilingMode mode, bool recordSamples)
{
    return m_spIsolateImpl->BeginCpuProfile(name, mode, recordSamples);
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::EndCpuProfile(const StdString& name, V8Isolate::CpuProfileCallback* pCallback, void* pvArg)
{
    return m_spIsolateImpl->EndCpuProfile(name, pCallback, pvArg);
}

//-----------------------------------------------------------------------------

void V8ContextImpl::CollectCpuProfileSample()
{
    return m_spIsolateImpl->CollectCpuProfileSample();
}

//-----------------------------------------------------------------------------

uint32_t V8ContextImpl::GetCpuProfileSampleInterval()
{
    return m_spIsolateImpl->GetCpuProfileSampleInterval();
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetCpuProfileSampleInterval(uint32_t value)
{
    m_spIsolateImpl->SetCpuProfileSampleInterval(value);
}

//-----------------------------------------------------------------------------

void V8ContextImpl::WriteIsolateHeapSnapshot(void* pvStream)
{
    m_spIsolateImpl->WriteHeapSnapshot(pvStream);
}

//-----------------------------------------------------------------------------

void V8ContextImpl::Flush()
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_EXECUTION_SCOPE

        (void)m_hFlushFunction->Call(m_hContext, GetUndefined(), 0, nullptr);

    END_EXECUTION_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::Destroy()
{
    m_spIsolateImpl->CallWithLockNoWait(true /*allowNesting*/, [this] (V8IsolateImpl* /*pIsolateImpl*/)
    {
        delete this;
    });
}

//-----------------------------------------------------------------------------

V8Value V8ContextImpl::GetV8ObjectProperty(void* pvObject, const StdString& name)
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        return ExportValue(FROM_MAYBE(::HandleFromPtr(pvObject)->Get(m_hContext, FROM_MAYBE(CreateString(name)))));

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::TryGetV8ObjectProperty(void* pvObject, const StdString& name, V8Value& value)
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        auto hObject = ::HandleFromPtr(pvObject);
        auto hName = FROM_MAYBE(CreateString(name));

        if (FROM_MAYBE(hObject->Has(m_hContext, hName)))
        {
            value = ExportValue(FROM_MAYBE(::HandleFromPtr(pvObject)->Get(m_hContext, hName)));
            return true;
        }

        return false;

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetV8ObjectProperty(void* pvObject, const StdString& name, const V8Value& value)
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        ASSERT_EVAL(FROM_MAYBE(::HandleFromPtr(pvObject)->Set(m_hContext, FROM_MAYBE(CreateString(name)), ImportValue(value))));

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::DeleteV8ObjectProperty(void* pvObject, const StdString& name)
{
    BEGIN_CONTEXT_SCOPE
    FROM_MAYBE_TRY

        return FROM_MAYBE(::HandleFromPtr(pvObject)->Delete(m_hContext, FROM_MAYBE(CreateString(name))));

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), false /*executionStarted*/);

    FROM_MAYBE_END
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetV8ObjectPropertyNames(void* pvObject, bool includeIndices, std::vector& names)
{
    BEGIN_CONTEXT_SCOPE

        GetV8ObjectPropertyNames(::HandleFromPtr(pvObject), names, v8::ONLY_ENUMERABLE, includeIndices ? v8::IndexFilter::kIncludeIndices : v8::IndexFilter::kSkipIndices);

    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

V8Value V8ContextImpl::GetV8ObjectProperty(void* pvObject, int index)
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        return ExportValue(FROM_MAYBE(::HandleFromPtr(pvObject)->Get(m_hContext, index)));

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetV8ObjectProperty(void* pvObject, int index, const V8Value& value)
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        ASSERT_EVAL(FROM_MAYBE(::HandleFromPtr(pvObject)->Set(m_hContext, index, ImportValue(value))));

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::DeleteV8ObjectProperty(void* pvObject, int index)
{
    BEGIN_CONTEXT_SCOPE
    FROM_MAYBE_TRY

        return FROM_MAYBE(::HandleFromPtr(pvObject)->Delete(m_hContext, index));

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), false /*executionStarted*/);

    FROM_MAYBE_END
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetV8ObjectPropertyIndices(void* pvObject, std::vector& indices)
{
    BEGIN_CONTEXT_SCOPE

        GetV8ObjectPropertyIndices(::HandleFromPtr(pvObject), indices, v8::ONLY_ENUMERABLE);

    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

V8Value V8ContextImpl::InvokeV8Object(void* pvObject, bool asConstructor, const std::vector& args)
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_EXECUTION_SCOPE

        v8::Local hObject = ::HandleFromPtr(pvObject);
        if (!hObject->IsCallable())
        {
            FROM_MAYBE_TRY

                auto hError = v8::Exception::TypeError(m_hObjectNotInvocable).As();
                throw V8Exception(V8Exception::Type::General, m_Name, CreateStdString(hError), CreateStdString(FROM_MAYBE(hError->Get(m_hContext, m_hStackKey))), EXECUTION_STARTED, ExportValue(hError), V8Value(V8Value::Undefined));

            FROM_MAYBE_CATCH

                throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The object does not support invocation")), EXECUTION_STARTED);

            FROM_MAYBE_END
        }

        std::vector importedArgs;
        ImportValues(args, importedArgs);

        if (asConstructor)
        {
            return ExportValue(VERIFY_MAYBE(hObject->CallAsConstructor(m_hContext, static_cast(importedArgs.size()), importedArgs.data())));
        }

        return ExportValue(VERIFY_MAYBE(hObject->CallAsFunction(m_hContext, hObject, static_cast(importedArgs.size()), importedArgs.data())));

    END_EXECUTION_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

V8Value V8ContextImpl::InvokeV8ObjectMethod(void* pvObject, const StdString& name, const std::vector& args)
{
    BEGIN_CONTEXT_SCOPE
    BEGIN_EXECUTION_SCOPE
    FROM_MAYBE_TRY

        v8::Local hObject = ::HandleFromPtr(pvObject);

        auto hMethod = ::ValueAsObject(VERIFY_MAYBE(hObject->Get(m_hContext, FROM_MAYBE(CreateString(name)))));
        if (hMethod.IsEmpty())
        {
            FROM_MAYBE_TRY

                auto hError = v8::Exception::TypeError(m_hMethodOrPropertyNotFound).As();
                throw V8Exception(V8Exception::Type::General, m_Name, CreateStdString(hError), CreateStdString(FROM_MAYBE(hError->Get(m_hContext, m_hStackKey))), EXECUTION_STARTED, ExportValue(hError), V8Value(V8Value::Undefined));

            FROM_MAYBE_CATCH

                throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("Method or property not found")), EXECUTION_STARTED);

            FROM_MAYBE_END
        }

        if (!hMethod->IsCallable())
        {
            FROM_MAYBE_TRY

                auto hError = v8::Exception::TypeError(m_hPropertyValueNotInvocable).As();
                throw V8Exception(V8Exception::Type::General, m_Name, CreateStdString(hError), CreateStdString(FROM_MAYBE(hError->Get(m_hContext, m_hStackKey))), EXECUTION_STARTED, ExportValue(hError), V8Value(V8Value::Undefined));

            FROM_MAYBE_CATCH

                throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The property value does not support invocation")), EXECUTION_STARTED);

            FROM_MAYBE_END
        }

        std::vector importedArgs;
        ImportValues(args, importedArgs);

        return ExportValue(VERIFY_MAYBE(hMethod->CallAsFunction(m_hContext, hObject, static_cast(importedArgs.size()), importedArgs.data())));

    FROM_MAYBE_CATCH

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The V8 runtime cannot perform the requested operation because a script exception is pending")), EXECUTION_STARTED);

    FROM_MAYBE_END
    END_EXECUTION_SCOPE
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetV8ObjectArrayBufferOrViewInfo(void* pvObject, V8Value& arrayBuffer, size_t& offset, size_t& size, size_t& length)
{
    BEGIN_CONTEXT_SCOPE

        v8::Local hObject = ::HandleFromPtr(pvObject);

        if (hObject->IsArrayBuffer())
        {
            auto hArrayBuffer = hObject.As();
            arrayBuffer = ExportValue(hObject);
            offset = 0;
            size = hArrayBuffer->ByteLength();
            length = size;
            return;
        }

        if (hObject->IsSharedArrayBuffer())
        {
            auto hSharedArrayBuffer = hObject.As();
            arrayBuffer = ExportValue(hObject);
            offset = 0;
            size = hSharedArrayBuffer->ByteLength();
            length = size;
            return;
        }

        if (hObject->IsDataView())
        {
            auto hDataView = hObject.As();
            arrayBuffer = ExportValue(hDataView->Buffer());
            offset = hDataView->ByteOffset();
            size = hDataView->ByteLength();
            length = size;
            return;
        }

        if (hObject->IsTypedArray())
        {
            auto hTypedArray = hObject.As();
            arrayBuffer = ExportValue(hTypedArray->Buffer());
            offset = hTypedArray->ByteOffset();
            size = hTypedArray->ByteLength();
            length = hTypedArray->Length();
            return;
        }

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The object is not a V8 array buffer or view")), false /*executionStarted*/);

    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::InvokeWithV8ObjectArrayBufferOrViewData(void* pvObject, V8ObjectHelpers::ArrayBufferOrViewDataCallback* pCallback, void* pvArg)
{
    BEGIN_CONTEXT_SCOPE

        v8::Local hObject = ::HandleFromPtr(pvObject);

        if (hObject->IsArrayBuffer())
        {
            auto hArrayBuffer = hObject.As();
            auto spBackingStore = hArrayBuffer->GetBackingStore();
            (*pCallback)(spBackingStore->Data(), pvArg);
            return;
        }

        if (hObject->IsSharedArrayBuffer())
        {
            auto hSharedArrayBuffer = hObject.As();
            auto spBackingStore = hSharedArrayBuffer->GetBackingStore();
            (*pCallback)(spBackingStore->Data(), pvArg);
            return;
        }

        if (hObject->IsDataView())
        {
            auto hDataView = hObject.As();
            auto spBackingStore = hDataView->Buffer()->GetBackingStore();
            (*pCallback)(static_cast(spBackingStore->Data()) + hDataView->ByteOffset(), pvArg);
            return;
        }

        if (hObject->IsTypedArray())
        {
            auto hTypedArray = hObject.As();
            auto spBackingStore = hTypedArray->Buffer()->GetBackingStore();
            (*pCallback)(static_cast(spBackingStore->Data()) + hTypedArray->ByteOffset(), pvArg);
            return;
        }

        throw V8Exception(V8Exception::Type::General, m_Name, StdString(SL("The object is not a V8 array buffer or view")), false /*executionStarted*/);

    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

void V8ContextImpl::InitializeImportMeta(v8::Local /*hContext*/, v8::Local hModule, v8::Local hMeta)
{
    BEGIN_CONTEXT_SCOPE
    FROM_MAYBE_TRY

        try
        {
            for (const auto& entry : m_ModuleCache)
            {
                if (entry.hModule == hModule)
                {
                    for (const auto& pair : HostObjectUtil::GetInstance().CreateModuleContext(entry.DocumentInfo))
                    {
                        (void)hMeta->Set(m_hContext, FROM_MAYBE(CreateString(pair.first)), ImportValue(pair.second));
                    }

                    return;
                }
            }
        }
        catch (const HostException& exception)
        {
            ThrowScriptException(exception);
        }

    FROM_MAYBE_CATCH_CONSUME
    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

v8::MaybeLocal V8ContextImpl::ImportModule(v8::Local hHostDefinedOptions, v8::Local /*hResourceName*/, v8::Local hSpecifier, v8::Local /*hImportAssertions*/)
{
    V8DocumentInfo sourceDocumentInfo;
    const V8DocumentInfo* pSourceDocumentInfo = nullptr;

    if (!hHostDefinedOptions.IsEmpty())
    {
        auto hOptions = hHostDefinedOptions.As();
        if (hOptions->Length() > 0)
        {
            auto hUniqueId = ::ValueAsBigInt(GetPrimitiveArrayItem(hOptions, 0));
            if (!hUniqueId.IsEmpty())
            {
                auto uniqueId = hUniqueId->Uint64Value();
                if (TryGetCachedScriptInfo(uniqueId, sourceDocumentInfo) || TryGetCachedModuleInfo(uniqueId, sourceDocumentInfo))
                {
                    pSourceDocumentInfo = &sourceDocumentInfo;
                }
            }
        }
    }

    return ImportModule(pSourceDocumentInfo, hSpecifier);
}

//-----------------------------------------------------------------------------

v8::MaybeLocal V8ContextImpl::ImportModule(const V8DocumentInfo* pSourceDocumentInfo, v8::Local hSpecifier)
{
    BEGIN_CONTEXT_SCOPE

        V8IsolateImpl::TryCatch outerTryCatch(*m_spIsolateImpl);

        FROM_MAYBE_TRY

            auto hResolver = FROM_MAYBE(v8::Promise::Resolver::New(m_hContext));

            V8IsolateImpl::TryCatch innerTryCatch(*m_spIsolateImpl);

            FROM_MAYBE_TRY

                auto hModule = FROM_MAYBE(ResolveModule(hSpecifier, pSourceDocumentInfo));

                if (hModule->GetStatus() == v8::Module::kUninstantiated)
                {
                    ASSERT_EVAL(FROM_MAYBE(hModule->InstantiateModule(m_hContext, V8IsolateImpl::ModuleResolveCallback)));
                }

                if (hModule->GetStatus() == v8::Module::kInstantiated)
                {
                    FROM_MAYBE(hModule->Evaluate(m_hContext));
                }

                ASSERT_EVAL(FROM_MAYBE(hResolver->Resolve(m_hContext, hModule->GetModuleNamespace())));
                return hResolver->GetPromise();

            FROM_MAYBE_CATCH_CONSUME

            auto innerHasCaught = innerTryCatch.HasCaught();
            _ASSERTE(innerHasCaught);

            if (innerHasCaught)
            {
                (void)hResolver->Reject(m_hContext, innerTryCatch.Exception());
            }

            return hResolver->GetPromise();

        FROM_MAYBE_CATCH_CONSUME

        auto outerHasCaught = outerTryCatch.HasCaught();
        _ASSERTE(outerHasCaught);

        if (outerHasCaught)
        {
            outerTryCatch.ReThrow();
        }

        return v8::MaybeLocal();

    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

v8::MaybeLocal V8ContextImpl::ResolveModule(v8::Local hSpecifier, v8::Local hReferrer)
{
    V8DocumentInfo sourceDocumentInfo;
    const V8DocumentInfo* pSourceDocumentInfo = nullptr;

    if (TryGetCachedModuleInfo(hReferrer, sourceDocumentInfo))
    {
        pSourceDocumentInfo = &sourceDocumentInfo;
    }

    return ResolveModule(hSpecifier, pSourceDocumentInfo);
}

//-----------------------------------------------------------------------------

v8::MaybeLocal V8ContextImpl::ResolveModule(v8::Local hSpecifier, const V8DocumentInfo* pSourceDocumentInfo)
{
    BEGIN_CONTEXT_SCOPE

        V8IsolateImpl::TryCatch tryCatch(*m_spIsolateImpl);

        FROM_MAYBE_TRY

            if (pSourceDocumentInfo == nullptr)
            {
                pSourceDocumentInfo = m_spIsolateImpl->GetDocumentInfo();
            }

            if (pSourceDocumentInfo == nullptr)
            {
                ThrowException(v8::Exception::Error(m_hInvalidModuleRequest));
            }
            else
            {
                try
                {
                    V8DocumentInfo documentInfo;
                    V8Value exportsValue(V8Value::Undefined);
                    auto code = HostObjectUtil::GetInstance().LoadModule(*pSourceDocumentInfo, CreateStdString(hSpecifier), documentInfo, exportsValue);

                    auto codeDigest = code.GetDigest();
                    auto hModule = GetCachedModule(documentInfo.GetUniqueId(), codeDigest);
                    if (!hModule.IsEmpty())
                    {
                        return hModule;
                    }

                    if (!documentInfo.IsModule())
                    {
                        std::vector names;
                        std::vector exports;

                        auto hExports = ::ValueAsObject(ImportValue(exportsValue));
                        if (!hExports.IsEmpty())
                        {
                            auto hOwnPropertyNames = FROM_MAYBE(hExports->GetOwnPropertyNames(m_hContext, v8::SKIP_SYMBOLS, v8::KeyConversionMode::kNoNumbers));
                            if (!hOwnPropertyNames.IsEmpty())
                            {
                                auto length = hOwnPropertyNames->Length();

                                names.reserve(length);
                                exports.reserve(length);

                                for (uint32_t index = 0; index < length; index++)
                                {
                                    auto hName = ::ValueAsString(FROM_MAYBE(hOwnPropertyNames->Get(m_hContext, index)));
                                    if (!hName.IsEmpty())
                                    {
                                        names.push_back(hName);
                                        exports.push_back({ CreatePersistent(hName), CreatePersistent(FROM_MAYBE(hExports->Get(m_hContext, hName))) });
                                    }
                                }
                            }
                        }

                        hModule = CreateSyntheticModule(FROM_MAYBE(CreateString(documentInfo.GetResourceName())), names, PopulateSyntheticModule);
                        m_SyntheticModuleData.push_back({ CreatePersistent(hModule), std::move(exports) });
                    }
                    else
                    {
                        BEGIN_DOCUMENT_SCOPE(documentInfo)

                            v8::ScriptCompiler::Source source(FROM_MAYBE(CreateString(code)), CreateScriptOrigin(documentInfo));
                            hModule = FROM_MAYBE(CompileModule(&source));

                        END_DOCUMENT_SCOPE
                    }

                    if (!hModule.IsEmpty())
                    {
                        CacheModule(documentInfo, codeDigest, hModule);
                    }

                    return hModule;
                }
                catch (const HostException& exception)
                {
                    ThrowScriptException(exception);
                }
            }

        FROM_MAYBE_CATCH_CONSUME

        auto hasCaught = tryCatch.HasCaught();
        _ASSERTE(hasCaught);

        if (hasCaught)
        {
            tryCatch.ReThrow();
        }

        return v8::MaybeLocal();

    END_CONTEXT_SCOPE
}

//-----------------------------------------------------------------------------

v8::MaybeLocal V8ContextImpl::PopulateSyntheticModule(v8::Local hContext, v8::Local hModule)
{
    if (hContext->GetNumberOfEmbedderDataFields() > 1)
    {
        auto pContextImpl = reinterpret_cast(hContext->GetAlignedPointerFromEmbedderData(1));
        if (pContextImpl != nullptr)
        {
            return pContextImpl->PopulateSyntheticModule(hModule);
        }
    }

    return v8::MaybeLocal();
}

//-----------------------------------------------------------------------------

v8::MaybeLocal V8ContextImpl::PopulateSyntheticModule(v8::Local hModule)
{
    FROM_MAYBE_TRY

        auto hResolver = FROM_MAYBE(v8::Promise::Resolver::New(m_hContext));
        ASSERT_EVAL(FROM_MAYBE(hResolver->Resolve(m_hContext, GetUndefined())));

        for (auto itModule = m_SyntheticModuleData.begin(); itModule != m_SyntheticModuleData.end(); itModule++)
        {
            if (itModule->hModule == hModule)
            {
                Dispose(itModule->hModule);
                for (auto itExport = itModule->Exports.begin(); itExport != itModule->Exports.end(); itExport++)
                {
                    FROM_MAYBE(SetSyntheticModuleExport(hModule, itExport->hName, itExport->hValue));
                    Dispose(itExport->hName);
                    Dispose(itExport->hValue);
                }

                m_SyntheticModuleData.erase(itModule);
                break;
            }
        }

        return hResolver->GetPromise();

    FROM_MAYBE_CATCH

        return v8::MaybeLocal();

    FROM_MAYBE_END
}

//-----------------------------------------------------------------------------

void V8ContextImpl::Teardown()
{
    _ASSERTE(m_spIsolateImpl->IsCurrent() && m_spIsolateImpl->IsLocked());

    m_spIsolateImpl->RemoveContext(this);

    if (m_pvV8ObjectCache != nullptr)
    {
        std::vector v8ObjectPtrs;
        HostObjectUtil::GetInstance().GetAllCachedV8Objects(m_pvV8ObjectCache, v8ObjectPtrs);
        for (auto pvV8Object : v8ObjectPtrs)
        {
            auto hObject = ::HandleFromPtr(pvV8Object);

            auto pHolder = GetHostObjectHolder(hObject);
            if (pHolder != nullptr)
            {
                delete pHolder;
            }

            ClearWeak(hObject);
            Dispose(hObject);
        }

        HostObjectUtil::GetInstance().Release(m_pvV8ObjectCache);
        m_pvV8ObjectCache = nullptr;
    }

    for (auto itModule = m_SyntheticModuleData.rbegin(); itModule != m_SyntheticModuleData.rend(); itModule++)
    {
        Dispose(itModule->hModule);
        for (auto itExport = itModule->Exports.begin(); itExport != itModule->Exports.end(); itExport++)
        {
            Dispose(itExport->hName);
            Dispose(itExport->hValue);
        }
    }

    ClearModuleCache();

    for (auto it = m_GlobalMembersStack.rbegin(); it != m_GlobalMembersStack.rend(); it++)
    {
        Dispose(it->second);
    }

    Dispose(m_hAsyncGeneratorConstructor);
    Dispose(m_hToJsonFunction);
    Dispose(m_hToAsyncIteratorFunction);
    Dispose(m_hToIteratorFunction);
    Dispose(m_hHostDelegateTemplate);
    Dispose(m_hHostInvocableTemplate);
    Dispose(m_hHostObjectTemplate);
    Dispose(m_hTerminationException);
    Dispose(m_hFlushFunction);
    Dispose(m_hConstructorKey);
    Dispose(m_hInvalidModuleRequest);
    Dispose(m_hPropertyValueNotInvocable);
    Dispose(m_hMethodOrPropertyNotFound);
    Dispose(m_hObjectNotInvocable);
    Dispose(m_hStackKey);
    Dispose(m_hInternalUseOnly);
    Dispose(m_hAccessToken);
    Dispose(m_hAccessTokenKey);
    Dispose(m_hCacheKey);
    Dispose(m_hHostExceptionKey);
    Dispose(m_hIsHostObjectKey);

    // As of V8 3.16.0, the global property getter for a disposed context
    // may be invoked during GC after the V8ContextImpl instance is gone.

    auto hGlobal = ::ValueAsObject(m_hContext->Global()->GetPrototype());
    if (!hGlobal.IsEmpty() && (hGlobal->InternalFieldCount() > 0))
    {
        hGlobal->SetAlignedPointerInInternalField(0, nullptr);
    }

    if (m_hContext->GetNumberOfEmbedderDataFields() > 1)
    {
        m_hContext->SetAlignedPointerInEmbedderData(1, nullptr);
    }

    Dispose(m_hContext);
}

//-----------------------------------------------------------------------------

V8ContextImpl::~V8ContextImpl()
{
    --s_InstanceCount;
    Teardown();
    ContextDisposedNotification();
}

//-----------------------------------------------------------------------------

SharedPtr V8ContextImpl::GetWeakBinding()
{
    if (m_spWeakBinding.IsEmpty())
    {
        m_spWeakBinding = new V8WeakContextBinding(m_spIsolateImpl, this);
    }

    return m_spWeakBinding;
}

//-----------------------------------------------------------------------------

HostObjectHolder* V8ContextImpl::GetHostObjectHolder(v8::Local hObject)
{
    if (!hObject.IsEmpty())
    {
        auto hHolder = ::ValueAsExternal(FROM_MAYBE_DEFAULT(hObject->GetPrivate(m_hContext, GetHostObjectHolderKey())));
        if (!hHolder.IsEmpty())
        {
            return static_cast(hHolder->Value());
        }
    }

    return nullptr;
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::SetHostObjectHolder(v8::Local hObject, HostObjectHolder* pHolder)
{
    if (!hObject.IsEmpty())
    {
        return FROM_MAYBE_DEFAULT(hObject->SetPrivate(m_hContext, GetHostObjectHolderKey(), CreateExternal(pHolder)));
    }

    return false;
}

//-----------------------------------------------------------------------------

void* V8ContextImpl::GetHostObject(v8::Local hObject)
{
    auto pHolder = GetHostObjectHolder(hObject);
    if (pHolder != nullptr)
    {
        return pHolder->GetObject();
    }

    return nullptr;
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::CheckContextImplForGlobalObjectCallback(V8ContextImpl* pContextImpl)
{
    if (pContextImpl == nullptr)
    {
        return false;
    }

    if (pContextImpl->IsExecutionTerminating())
    {
        pContextImpl->ThrowException(pContextImpl->m_hTerminationException);
        return false;
    }

    return true;
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::CheckContextImplForHostObjectCallback(V8ContextImpl* pContextImpl)
{
    if (pContextImpl == nullptr)
    {
        return false;
    }

    if (pContextImpl->IsExecutionTerminating())
    {
        pContextImpl->ThrowException(pContextImpl->m_hTerminationException);
        return false;
    }

    return true;
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetV8ObjectPropertyNames(v8::Local hObject, std::vector& names, v8::PropertyFilter filter, v8::IndexFilter indexFilter)
{
    names.clear();

    FROM_MAYBE_TRY

        auto hNames = FROM_MAYBE(hObject->GetPropertyNames(m_hContext, v8::KeyCollectionMode::kIncludePrototypes, static_cast(filter | v8::SKIP_SYMBOLS), indexFilter, v8::KeyConversionMode::kConvertToString));
        auto nameCount = static_cast(hNames->Length());

        names.reserve(nameCount);
        for (auto index = 0; index < nameCount; index++)
        {
            auto hName = FROM_MAYBE(hNames->Get(m_hContext, index));
            if (hName->IsString())
            {
                names.push_back(CreateStdString(hName));
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetV8ObjectPropertyIndices(v8::Local hObject, std::vector& indices, v8::PropertyFilter filter)
{
    indices.clear();

    FROM_MAYBE_TRY

        auto hNames = FROM_MAYBE(hObject->GetPropertyNames(m_hContext, v8::KeyCollectionMode::kIncludePrototypes, static_cast(filter | v8::SKIP_SYMBOLS), v8::IndexFilter::kIncludeIndices, v8::KeyConversionMode::kKeepNumbers));
        auto nameCount = static_cast(hNames->Length());

        indices.reserve(nameCount);
        for (auto index = 0; index < nameCount; index++)
        {
            auto hName = FROM_MAYBE(hNames->Get(m_hContext, index));
            if (hName->IsInt32())
            {
                indices.push_back(FROM_MAYBE(hName->Int32Value(m_hContext)));
            }
            else if (hName->IsUint32())
            {
                auto value = FROM_MAYBE(hName->Uint32Value(m_hContext));
                if (value IsNumber())
            {
                auto value = FROM_MAYBE(hName->NumberValue(m_hContext));
                if (value == std::round(value) && (value >= static_cast(INT_MIN)) && (value m_GlobalMembersStack;
            if (stack.size() > 0)
            {
                for (auto it = stack.rbegin(); it != stack.rend(); it++)
                {
                    if (FROM_MAYBE(it->second->HasOwnProperty(pContextImpl->m_hContext, hName)))
                    {
                        CALLBACK_RETURN(FROM_MAYBE(it->second->Get(pContextImpl->m_hContext, hName)));
                    }
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetGlobalProperty(v8::Local hKey, v8::Local hValue, const v8::PropertyCallbackInfo& info)
{
    auto hName = ::ValueAsString(hKey);
    if (hName.IsEmpty())
    {
        return;
    }

    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromHolder(info);
        if (CheckContextImplForGlobalObjectCallback(pContextImpl))
        {
            const auto& stack = pContextImpl->m_GlobalMembersStack;
            if (stack.size() > 0)
            {
                for (auto it = stack.rbegin(); it != stack.rend(); it++)
                {
                    if (FROM_MAYBE(it->second->HasOwnProperty(pContextImpl->m_hContext, hName)))
                    {
                        (void)it->second->Set(pContextImpl->m_hContext, hName, hValue);
                        CALLBACK_RETURN(hValue);
                    }
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::QueryGlobalProperty(v8::Local hKey, const v8::PropertyCallbackInfo& info)
{
    auto hName = ::ValueAsString(hKey);
    if (hName.IsEmpty())
    {
        return;
    }

    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromHolder(info);
        if (CheckContextImplForGlobalObjectCallback(pContextImpl))
        {
            const auto& stack = pContextImpl->m_GlobalMembersStack;
            if (stack.size() > 0)
            {
                for (auto it = stack.rbegin(); it != stack.rend(); it++)
                {
                    if (FROM_MAYBE(it->second->HasOwnProperty(pContextImpl->m_hContext, hName)))
                    {
                        CALLBACK_RETURN(FROM_MAYBE(it->second->GetPropertyAttributes(pContextImpl->m_hContext, hName)));
                    }
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::DeleteGlobalProperty(v8::Local hKey, const v8::PropertyCallbackInfo& info)
{
    auto hName = ::ValueAsString(hKey);
    if (hName.IsEmpty())
    {
        return;
    }

    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromHolder(info);
        if (CheckContextImplForGlobalObjectCallback(pContextImpl))
        {
            const auto& stack = pContextImpl->m_GlobalMembersStack;
            if (stack.size() > 0)
            {
                for (auto it = stack.rbegin(); it != stack.rend(); it++)
                {
                    if (FROM_MAYBE(it->second->HasOwnProperty(pContextImpl->m_hContext, hName)))
                    {
                        // WORKAROUND: v8::Object::Delete() crashes if a custom property deleter calls
                        // ThrowException(). Interestingly, there is no crash if the same deleter is
                        // invoked directly from script via the delete operator.

                        auto pvObject = pContextImpl->GetHostObject(it->second);
                        if (pvObject != nullptr)
                        {
                            try
                            {
                                CALLBACK_RETURN(HostObjectUtil::GetInstance().DeleteProperty(pvObject, pContextImpl->CreateStdString(hName)));
                            }
                            catch (const HostException&)
                            {
                                CALLBACK_RETURN(false);
                            }
                        }

                        CALLBACK_RETURN(FROM_MAYBE(it->second->Delete(pContextImpl->m_hContext, hName)));
                    }
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetGlobalPropertyNames(const v8::PropertyCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromHolder(info);
        if (CheckContextImplForGlobalObjectCallback(pContextImpl))
        {
            try
            {
                const auto& stack = pContextImpl->m_GlobalMembersStack;
                if (stack.size() > 0)
                {
                    std::vector names;
                    for (auto it = stack.rbegin(); it != stack.rend(); it++)
                    {
                        std::vector tempNames;

                        auto pvObject = pContextImpl->GetHostObject(it->second);
                        if (pvObject != nullptr)
                        {
                            HostObjectUtil::GetInstance().GetPropertyNames(pvObject, tempNames);
                        }
                        else
                        {
                            pContextImpl->GetV8ObjectPropertyNames(it->second, tempNames, v8::ONLY_ENUMERABLE, v8::IndexFilter::kSkipIndices);
                        }

                        names.insert(names.end(), tempNames.begin(), tempNames.end());
                    }

                    std::sort(names.begin(), names.end());
                    auto newEnd = std::unique(names.begin(), names.end());
                    auto nameCount = static_cast(newEnd - names.begin());

                    auto hImportedNames = pContextImpl->CreateArray(nameCount);
                    for (auto index = 0; index < nameCount; index++)
                    {
                        ASSERT_EVAL(FROM_MAYBE(hImportedNames->Set(pContextImpl->m_hContext, index, FROM_MAYBE(pContextImpl->CreateString(names[index])))));
                    }

                    CALLBACK_RETURN(hImportedNames);
                }
            }
            catch (const HostException& exception)
            {
                pContextImpl->ThrowScriptException(exception);
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetGlobalProperty(uint32_t index, const v8::PropertyCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromHolder(info);
        if (CheckContextImplForGlobalObjectCallback(pContextImpl))
        {
            const auto& stack = pContextImpl->m_GlobalMembersStack;
            if (stack.size() > 0)
            {
                auto hName = FROM_MAYBE(pContextImpl->CreateInteger(index)->ToString(pContextImpl->m_hContext));
                for (auto it = stack.rbegin(); it != stack.rend(); it++)
                {
                    if (FROM_MAYBE(it->second->HasOwnProperty(pContextImpl->m_hContext, hName)))
                    {
                        CALLBACK_RETURN(FROM_MAYBE(it->second->Get(pContextImpl->m_hContext, index)));
                    }
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetGlobalProperty(uint32_t index, v8::Local hValue, const v8::PropertyCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromHolder(info);
        if (CheckContextImplForGlobalObjectCallback(pContextImpl))
        {
            const auto& stack = pContextImpl->m_GlobalMembersStack;
            if (stack.size() > 0)
            {
                auto hName = FROM_MAYBE(pContextImpl->CreateInteger(index)->ToString(pContextImpl->m_hContext));
                for (auto it = stack.rbegin(); it != stack.rend(); it++)
                {
                    if (FROM_MAYBE(it->second->HasOwnProperty(pContextImpl->m_hContext, hName)))
                    {
                        (void)it->second->Set(pContextImpl->m_hContext, index, hValue);
                        CALLBACK_RETURN(hValue);
                    }
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::QueryGlobalProperty(uint32_t index, const v8::PropertyCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromHolder(info);
        if (CheckContextImplForGlobalObjectCallback(pContextImpl))
        {
            const auto& stack = pContextImpl->m_GlobalMembersStack;
            if (stack.size() > 0)
            {
                auto hIndex = pContextImpl->CreateInteger(index);
                auto hName = FROM_MAYBE(hIndex->ToString(pContextImpl->m_hContext));
                for (auto it = stack.rbegin(); it != stack.rend(); it++)
                {
                    if (FROM_MAYBE(it->second->HasOwnProperty(pContextImpl->m_hContext, hName)))
                    {
                        CALLBACK_RETURN(FROM_MAYBE(it->second->GetPropertyAttributes(pContextImpl->m_hContext, hIndex)));
                    }
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::DeleteGlobalProperty(uint32_t index, const v8::PropertyCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromHolder(info);
        if (CheckContextImplForGlobalObjectCallback(pContextImpl))
        {
            const auto& stack = pContextImpl->m_GlobalMembersStack;
            if (stack.size() > 0)
            {
                auto hName = FROM_MAYBE(pContextImpl->CreateInteger(index)->ToString(pContextImpl->m_hContext));
                for (auto it = stack.rbegin(); it != stack.rend(); it++)
                {
                    if (FROM_MAYBE(it->second->HasOwnProperty(pContextImpl->m_hContext, hName)))
                    {
                        CALLBACK_RETURN(FROM_MAYBE(it->second->Delete(pContextImpl->m_hContext, index)));
                    }
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetGlobalPropertyIndices(const v8::PropertyCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromHolder(info);
        if (CheckContextImplForGlobalObjectCallback(pContextImpl))
        {
            try
            {
                const auto& stack = pContextImpl->m_GlobalMembersStack;
                if (stack.size() > 0)
                {
                    std::vector indices;
                    for (auto it = stack.rbegin(); it != stack.rend(); it++)
                    {
                        std::vector tempIndices;

                        auto pvObject = pContextImpl->GetHostObject(it->second);
                        if (pvObject != nullptr)
                        {
                            HostObjectUtil::GetInstance().GetPropertyIndices(pvObject, tempIndices);
                        }
                        else
                        {
                            pContextImpl->GetV8ObjectPropertyIndices(it->second, tempIndices, v8::ONLY_ENUMERABLE);
                        }

                        indices.insert(indices.end(), tempIndices.begin(), tempIndices.end());
                    }

                    std::sort(indices.begin(), indices.end());
                    auto newEnd = std::unique(indices.begin(), indices.end());
                    auto indexCount = static_cast(newEnd - indices.begin());

                    auto hImportedIndices = pContextImpl->CreateArray(indexCount);
                    for (auto index = 0; index < indexCount; index++)
                    {
                        ASSERT_EVAL(FROM_MAYBE(hImportedIndices->Set(pContextImpl->m_hContext, index, pContextImpl->CreateInteger(indices[index]))));
                    }

                    CALLBACK_RETURN(hImportedIndices);
                }
            }
            catch (const HostException& exception)
            {
                pContextImpl->ThrowScriptException(exception);
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::HostObjectConstructorCallHandler(const v8::FunctionCallbackInfo& info)
{
    auto pContextImpl = ::GetContextImplFromData(info);
    if ((pContextImpl != nullptr) && !pContextImpl->m_AllowHostObjectConstructorCall)
    {
        pContextImpl->ThrowException(v8::Exception::Error(pContextImpl->m_hInternalUseOnly));
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetHostObjectIterator(const v8::FunctionCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromData(info);
        if (pContextImpl != nullptr)
        {
            auto pvObject = pContextImpl->GetHostObject(info.Holder());
            if (pvObject != nullptr)
            {
                try
                {
                    if (pContextImpl->m_hToIteratorFunction.IsEmpty())
                    {
                        auto hEngineInternal = FROM_MAYBE(pContextImpl->m_hContext->Global()->Get(pContextImpl->m_hContext, pContextImpl->CreateString("EngineInternal"))).As();
                        pContextImpl->m_hToIteratorFunction = pContextImpl->CreatePersistent(FROM_MAYBE(hEngineInternal->Get(pContextImpl->m_hContext, pContextImpl->CreateString("toIterator"))).As());
                    }

                    v8::Local args[] = { pContextImpl->ImportValue(HostObjectUtil::GetInstance().GetEnumerator(pvObject)) };
                    CALLBACK_RETURN(FROM_MAYBE(pContextImpl->m_hToIteratorFunction->Call(pContextImpl->m_hContext, pContextImpl->GetUndefined(), 1, args)));
                }
                catch (const HostException& exception)
                {
                    pContextImpl->ThrowScriptException(exception);
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetHostObjectAsyncIterator(const v8::FunctionCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromData(info);
        if (pContextImpl != nullptr)
        {
            auto pvObject = pContextImpl->GetHostObject(info.Holder());
            if (pvObject != nullptr)
            {
                try
                {
                    if (pContextImpl->m_hToAsyncIteratorFunction.IsEmpty())
                    {
                        auto hEngineInternal = FROM_MAYBE(pContextImpl->m_hContext->Global()->Get(pContextImpl->m_hContext, pContextImpl->CreateString("EngineInternal"))).As();
                        pContextImpl->m_hToAsyncIteratorFunction = pContextImpl->CreatePersistent(FROM_MAYBE(hEngineInternal->Get(pContextImpl->m_hContext, pContextImpl->CreateString("toAsyncIterator"))).As());
                    }

                    v8::Local args[] = { pContextImpl->ImportValue(HostObjectUtil::GetInstance().GetAsyncEnumerator(pvObject)) };
                    CALLBACK_RETURN(FROM_MAYBE(pContextImpl->m_hToAsyncIteratorFunction->Call(pContextImpl->m_hContext, pContextImpl->GetUndefined(), 1, args)));
                }
                catch (const HostException& exception)
                {
                    pContextImpl->ThrowScriptException(exception);
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetHostObjectJson(const v8::FunctionCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromData(info);
        if (pContextImpl != nullptr)
        {
            auto hObject = info.Holder();
            if (pContextImpl->GetHostObject(hObject) != nullptr)
            {
                try
                {
                    if (pContextImpl->m_hToJsonFunction.IsEmpty())
                    {
                        auto hEngineInternal = FROM_MAYBE(pContextImpl->m_hContext->Global()->Get(pContextImpl->m_hContext, pContextImpl->CreateString("EngineInternal"))).As();
                        pContextImpl->m_hToJsonFunction = pContextImpl->CreatePersistent(FROM_MAYBE(hEngineInternal->Get(pContextImpl->m_hContext, pContextImpl->CreateString("toJson"))).As());
                    }

                    v8::Local args[] = { info[0], hObject };
                    CALLBACK_RETURN(FROM_MAYBE(pContextImpl->m_hToJsonFunction->Call(pContextImpl->m_hContext, pContextImpl->GetUndefined(), 2, args)));
                }
                catch (const HostException& exception)
                {
                    pContextImpl->ThrowScriptException(exception);
                }
            }

            CALLBACK_RETURN(hObject);
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::CreateFunctionForHostDelegate(const v8::FunctionCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromData(info);
        if (pContextImpl != nullptr)
        {
            CALLBACK_RETURN(FROM_MAYBE(v8::Function::New(pContextImpl->m_hContext, InvokeHostDelegate, info.Holder())));
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::InvokeHostDelegate(const v8::FunctionCallbackInfo& info)
{
    auto hTarget = ::ValueAsObject(info.Data());
    if (!hTarget.IsEmpty())
    {
        auto argCount = info.Length();
        if (argCount < 1)
        {
            if (info.IsConstructCall())
            {
                CALLBACK_RETURN(FROM_MAYBE_DEFAULT(hTarget->CallAsConstructor(info.GetIsolate()->GetCurrentContext(), 0, nullptr)));
            }

            CALLBACK_RETURN(FROM_MAYBE_DEFAULT(hTarget->CallAsFunction(info.GetIsolate()->GetCurrentContext(), hTarget, 0, nullptr)));
        }

        std::vector args;
        args.reserve(argCount);

        for (auto index = 0; index < argCount; index++)
        {
            args.push_back(info[index]);
        }

        if (info.IsConstructCall())
        {
            CALLBACK_RETURN(FROM_MAYBE_DEFAULT(hTarget->CallAsConstructor(info.GetIsolate()->GetCurrentContext(), argCount, args.data())));
        }

        CALLBACK_RETURN(FROM_MAYBE_DEFAULT(hTarget->CallAsFunction(info.GetIsolate()->GetCurrentContext(), hTarget, argCount, args.data())));
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetHostObjectProperty(v8::Local hKey, const v8::PropertyCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromData(info);
        if (CheckContextImplForHostObjectCallback(pContextImpl))
        {
            auto hHolder = info.Holder();
            auto pvObject = pContextImpl->GetHostObject(hHolder);

            auto hName = ::ValueAsString(hKey);
            if (hName.IsEmpty())
            {
                if (!hKey.IsEmpty() && hKey->StrictEquals(pContextImpl->m_hIsHostObjectKey))
                {
                    CALLBACK_RETURN((pvObject != nullptr) ? pContextImpl->GetTrue() : pContextImpl->GetFalse());
                }

                return;
            }

            if (pvObject != nullptr)
            {
                try
                {
                    auto hAccessToken = FROM_MAYBE(hHolder->GetPrivate(pContextImpl->m_hContext, pContextImpl->m_hAccessTokenKey));
                    if (pContextImpl->m_hAccessToken != hAccessToken)
                    {
                        ASSERT_EVAL(FROM_MAYBE(hHolder->DeletePrivate(pContextImpl->m_hContext, pContextImpl->m_hCacheKey)));
                        ASSERT_EVAL(FROM_MAYBE(hHolder->SetPrivate(pContextImpl->m_hContext, pContextImpl->m_hAccessTokenKey, pContextImpl->m_hAccessToken)));
                    }
                    else
                    {
                        auto hCache = ::ValueAsObject(FROM_MAYBE(hHolder->GetPrivate(pContextImpl->m_hContext, pContextImpl->m_hCacheKey)));
                        if (!hCache.IsEmpty() && FROM_MAYBE(hCache->HasOwnProperty(pContextImpl->m_hContext, hName)))
                        {
                            CALLBACK_RETURN(FROM_MAYBE(hCache->Get(pContextImpl->m_hContext, hName)));
                        }
                    }

                    bool isCacheable;
                    auto hResult = pContextImpl->ImportValue(HostObjectUtil::GetInstance().GetProperty(pvObject, pContextImpl->CreateStdString(hName), isCacheable));
                    if (isCacheable && !hResult.IsEmpty())
                    {
                        auto hCache = ::ValueAsObject(FROM_MAYBE(hHolder->GetPrivate(pContextImpl->m_hContext, pContextImpl->m_hCacheKey)));
                        if (hCache.IsEmpty())
                        {
                            hCache = pContextImpl->CreateObject();
                            ASSERT_EVAL(FROM_MAYBE(hHolder->SetPrivate(pContextImpl->m_hContext, pContextImpl->m_hCacheKey, hCache)));
                        }

                        ASSERT_EVAL(FROM_MAYBE(hCache->Set(pContextImpl->m_hContext, hName, hResult)));
                    }

                    CALLBACK_RETURN(hResult);
                }
                catch (const HostException& exception)
                {
                    pContextImpl->ThrowScriptException(exception);
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetHostObjectProperty(v8::Local hKey, v8::Local hValue, const v8::PropertyCallbackInfo& info)
{
    auto hName = ::ValueAsString(hKey);
    if (hName.IsEmpty())
    {
        return;
    }

    auto pContextImpl = ::GetContextImplFromData(info);
    if (CheckContextImplForHostObjectCallback(pContextImpl))
    {
        auto pvObject = pContextImpl->GetHostObject(info.Holder());
        if (pvObject != nullptr)
        {
            try
            {
                HostObjectUtil::GetInstance().SetProperty(pvObject, pContextImpl->CreateStdString(hName), pContextImpl->ExportValue(hValue));
                CALLBACK_RETURN(hValue);
            }
            catch (const HostException& exception)
            {
                pContextImpl->ThrowScriptException(exception);
            }
        }
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::QueryHostObjectProperty(v8::Local hKey, const v8::PropertyCallbackInfo& info)
{
    auto hName = ::ValueAsString(hKey);
    if (hName.IsEmpty())
    {
        return;
    }

    auto pContextImpl = ::GetContextImplFromData(info);
    if (CheckContextImplForHostObjectCallback(pContextImpl))
    {
        auto pvObject = pContextImpl->GetHostObject(info.Holder());
        if (pvObject != nullptr)
        {
            try
            {
                std::vector names;
                HostObjectUtil::GetInstance().GetPropertyNames(pvObject, names);

                auto name = pContextImpl->CreateStdString(hName);
                for (auto it = names.begin(); it != names.end(); it++)
                {
                    if (it->Compare(name) == 0)
                    {
                        CALLBACK_RETURN(v8::None);
                    }
                }
            }
            catch (const HostException& exception)
            {
                pContextImpl->ThrowScriptException(exception);
            }
        }
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::DeleteHostObjectProperty(v8::Local hKey, const v8::PropertyCallbackInfo& info)
{
    auto hName = ::ValueAsString(hKey);
    if (hName.IsEmpty())
    {
        return;
    }

    auto pContextImpl = ::GetContextImplFromData(info);
    if (CheckContextImplForHostObjectCallback(pContextImpl))
    {
        auto pvObject = pContextImpl->GetHostObject(info.Holder());
        if (pvObject != nullptr)
        {
            try
            {
                CALLBACK_RETURN(HostObjectUtil::GetInstance().DeleteProperty(pvObject, pContextImpl->CreateStdString(hName)));
            }
            catch (const HostException& exception)
            {
                pContextImpl->ThrowScriptException(exception);
            }
        }
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetHostObjectPropertyNames(const v8::PropertyCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromData(info);
        if (CheckContextImplForHostObjectCallback(pContextImpl))
        {
            auto pvObject = pContextImpl->GetHostObject(info.Holder());
            if (pvObject != nullptr)
            {
                try
                {
                    std::vector names;
                    HostObjectUtil::GetInstance().GetPropertyNames(pvObject, names);
                    auto nameCount = static_cast(names.size());

                    auto hImportedNames = pContextImpl->CreateArray(nameCount);
                    for (auto index = 0; index < nameCount; index++)
                    {
                        ASSERT_EVAL(FROM_MAYBE(hImportedNames->Set(pContextImpl->m_hContext, index, FROM_MAYBE(pContextImpl->CreateString(names[index])))));
                    }

                    CALLBACK_RETURN(hImportedNames);
                }
                catch (const HostException& exception)
                {
                    pContextImpl->ThrowScriptException(exception);
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetHostObjectProperty(uint32_t index, const v8::PropertyCallbackInfo& info)
{
    auto pContextImpl = ::GetContextImplFromData(info);
    if (CheckContextImplForHostObjectCallback(pContextImpl))
    {
        auto pvObject = pContextImpl->GetHostObject(info.Holder());
        if (pvObject != nullptr)
        {
            try
            {
                CALLBACK_RETURN(pContextImpl->ImportValue(HostObjectUtil::GetInstance().GetProperty(pvObject, index)));
            }
            catch (const HostException& exception)
            {
                pContextImpl->ThrowScriptException(exception);
            }
        }
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::SetHostObjectProperty(uint32_t index, v8::Local hValue, const v8::PropertyCallbackInfo& info)
{
    auto pContextImpl = ::GetContextImplFromData(info);
    if (CheckContextImplForHostObjectCallback(pContextImpl))
    {
        auto pvObject = pContextImpl->GetHostObject(info.Holder());
        if (pvObject != nullptr)
        {
            try
            {
                HostObjectUtil::GetInstance().SetProperty(pvObject, index, pContextImpl->ExportValue(hValue));
                CALLBACK_RETURN(hValue);
            }
            catch (const HostException& exception)
            {
                pContextImpl->ThrowScriptException(exception);
            }
        }
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::QueryHostObjectProperty(uint32_t index, const v8::PropertyCallbackInfo& info)
{
    auto pContextImpl = ::GetContextImplFromData(info);
    if (CheckContextImplForHostObjectCallback(pContextImpl))
    {
        auto pvObject = pContextImpl->GetHostObject(info.Holder());
        if (pvObject != nullptr)
        {
            try
            {
                std::vector indices;
                HostObjectUtil::GetInstance().GetPropertyIndices(pvObject, indices);

                for (auto it = indices.begin(); it < indices.end(); it++)
                {
                    if (*it == static_cast(index))
                    {
                        CALLBACK_RETURN(v8::None);
                    }
                }
            }
            catch (const HostException& exception)
            {
                pContextImpl->ThrowScriptException(exception);
            }
        }
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::DeleteHostObjectProperty(uint32_t index, const v8::PropertyCallbackInfo& info)
{
    auto pContextImpl = ::GetContextImplFromData(info);
    if (CheckContextImplForHostObjectCallback(pContextImpl))
    {
        auto pvObject = pContextImpl->GetHostObject(info.Holder());
        if (pvObject != nullptr)
        {
            try
            {
                CALLBACK_RETURN(HostObjectUtil::GetInstance().DeleteProperty(pvObject, index));
            }
            catch (const HostException& exception)
            {
                pContextImpl->ThrowScriptException(exception);
            }
        }
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::GetHostObjectPropertyIndices(const v8::PropertyCallbackInfo& info)
{
    FROM_MAYBE_TRY

        auto pContextImpl = ::GetContextImplFromData(info);
        if (CheckContextImplForHostObjectCallback(pContextImpl))
        {
            auto pvObject = pContextImpl->GetHostObject(info.Holder());
            if (pvObject != nullptr)
            {
                try
                {
                    std::vector indices;
                    HostObjectUtil::GetInstance().GetPropertyIndices(pvObject, indices);
                    auto indexCount = static_cast(indices.size());

                    auto hImportedIndices = pContextImpl->CreateArray(indexCount);
                    for (auto index = 0; index < indexCount; index++)
                    {
                        ASSERT_EVAL(FROM_MAYBE(hImportedIndices->Set(pContextImpl->m_hContext, index, pContextImpl->CreateInteger(indices[index]))));
                    }

                    CALLBACK_RETURN(hImportedIndices);
                }
                catch (const HostException& exception)
                {
                    pContextImpl->ThrowScriptException(exception);
                }
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

//-----------------------------------------------------------------------------

void V8ContextImpl::InvokeHostObject(const v8::FunctionCallbackInfo& info)
{
    auto pContextImpl = ::GetContextImplFromData(info);
    if (CheckContextImplForHostObjectCallback(pContextImpl))
    {
        auto pvObject = pContextImpl->GetHostObject(info.Holder());
        if (pvObject != nullptr)
        {
            try
            {
                auto argCount = info.Length();

                std::vector exportedArgs;
                exportedArgs.reserve(argCount);

                for (auto index = 0; index < argCount; index++)
                {
                    exportedArgs.push_back(pContextImpl->ExportValue(info[index]));
                }

                CALLBACK_RETURN(pContextImpl->ImportValue(HostObjectUtil::GetInstance().Invoke(pvObject, info.IsConstructCall(), exportedArgs)));
            }
            catch (const HostException& exception)
            {
                pContextImpl->ThrowScriptException(exception);
            }
        }
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::FlushCallback(const v8::FunctionCallbackInfo& /*info*/)
{
}

//-----------------------------------------------------------------------------

void V8ContextImpl::DisposeWeakHandle(v8::Isolate* pIsolate, Persistent* phObject, HostObjectHolder* pHolder, void* pvV8ObjectCache)
{
    IGNORE_UNUSED(pIsolate);

    ASSERT_EVAL(HostObjectUtil::GetInstance().RemoveV8ObjectCacheEntry(pvV8ObjectCache, pHolder->GetObject()));
    delete pHolder;

    phObject->Dispose();
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::TryGetCachedModuleInfo(v8::Local hModule, V8DocumentInfo& documentInfo)
{
    _ASSERTE(m_spIsolateImpl->IsCurrent() && m_spIsolateImpl->IsLocked());

    for (auto it = m_ModuleCache.begin(); it != m_ModuleCache.end(); it++)
    {
        if (it->hModule == hModule)
        {
            m_ModuleCache.splice(m_ModuleCache.begin(), m_ModuleCache, it);
            documentInfo = it->DocumentInfo;
            return true;
        }
    }

    return false;
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::TryGetCachedModuleInfo(uint64_t uniqueId, V8DocumentInfo& documentInfo)
{
    _ASSERTE(m_spIsolateImpl->IsCurrent() && m_spIsolateImpl->IsLocked());

    for (auto it = m_ModuleCache.begin(); it != m_ModuleCache.end(); it++)
    {
        if (it->DocumentInfo.GetUniqueId() == uniqueId)
        {
            m_ModuleCache.splice(m_ModuleCache.begin(), m_ModuleCache, it);
            documentInfo = it->DocumentInfo;
            return true;
        }
    }

    return false;
}

//-----------------------------------------------------------------------------

v8::Local V8ContextImpl::GetCachedModule(uint64_t uniqueId, size_t codeDigest)
{
    _ASSERTE(m_spIsolateImpl->IsCurrent() && m_spIsolateImpl->IsLocked());

    for (auto it = m_ModuleCache.begin(); it != m_ModuleCache.end(); it++)
    {
        if ((it->DocumentInfo.GetUniqueId() == uniqueId) && (it->CodeDigest == codeDigest))
        {
            m_ModuleCache.splice(m_ModuleCache.begin(), m_ModuleCache, it);
            return it->hModule;
        }
    }

    return v8::Local();
}

//-----------------------------------------------------------------------------

void V8ContextImpl::CacheModule(const V8DocumentInfo& documentInfo, size_t codeDigest, v8::Local hModule)
{
    _ASSERTE(m_spIsolateImpl->IsCurrent() && m_spIsolateImpl->IsLocked());

    auto maxModuleCacheSize = HostObjectUtil::GetInstance().GetMaxModuleCacheSize();
    while (m_ModuleCache.size() >= maxModuleCacheSize)
    {
        Dispose(m_ModuleCache.back().hModule);
        m_ModuleCache.pop_back();
    }

    _ASSERTE(std::none_of(m_ModuleCache.begin(), m_ModuleCache.end(),
        [&documentInfo, codeDigest] (const ModuleCacheEntry& entry)
    {
        return (entry.DocumentInfo.GetUniqueId() == documentInfo.GetUniqueId()) && (entry.CodeDigest == codeDigest);
    }));

    ModuleCacheEntry entry { documentInfo, codeDigest, CreatePersistent(hModule) };
    m_ModuleCache.push_front(std::move(entry));

    m_Statistics.ModuleCacheSize = m_ModuleCache.size();
}

//-----------------------------------------------------------------------------

void V8ContextImpl::ClearModuleCache()
{
    _ASSERTE(m_spIsolateImpl->IsCurrent() && m_spIsolateImpl->IsLocked());

    while (m_ModuleCache.size() > 0)
    {
        Dispose(m_ModuleCache.front().hModule);
        m_ModuleCache.pop_front();
    }

    m_Statistics.ModuleCacheSize = m_ModuleCache.size();
}

//-----------------------------------------------------------------------------

bool V8ContextImpl::TryGetCachedScriptInfo(uint64_t uniqueId, V8DocumentInfo& documentInfo)
{
    return m_spIsolateImpl->TryGetCachedScriptInfo(uniqueId, documentInfo);
}

//-----------------------------------------------------------------------------

v8::Local V8ContextImpl::GetCachedScript(uint64_t uniqueId, size_t codeDigest)
{
    return m_spIsolateImpl->GetCachedScript(uniqueId, codeDigest);
}

//-----------------------------------------------------------------------------

void V8ContextImpl::CacheScript(const V8DocumentInfo& documentInfo, size_t codeDigest, v8::Local hScript)
{
    m_spIsolateImpl->CacheScript(documentInfo, codeDigest, hScript);
}

//-----------------------------------------------------------------------------

v8::Local V8ContextImpl::ImportValue(const V8Value& value)
{
    FROM_MAYBE_TRY

        if (value.IsNonexistent())
        {
            return v8::Local();
        }

        if (value.IsUndefined())
        {
            return GetUndefined();
        }

        if (value.IsNull())
        {
            return GetNull();
        }

        {
            bool result;
            if (value.AsBoolean(result))
            {
                return result ? GetTrue() : GetFalse();
            }
        }

        {
            double result;
            if (value.AsNumber(result))
            {
                return CreateNumber(result);
            }
        }

        {
            int32_t result;
            if (value.AsInt32(result))
            {
                return CreateInteger(result);
            }
        }

        {
            uint32_t result;
            if (value.AsUInt32(result))
            {
                return CreateInteger(result);
            }
        }

        {
            const StdString* pString;
            if (value.AsString(pString))
            {
                return FROM_MAYBE(CreateString(*pString));
            }
        }

        {
            HostObjectHolder* pHolder;
            if (value.AsHostObject(pHolder))
            {
                auto pvV8Object = HostObjectUtil::GetInstance().GetCachedV8Object(m_pvV8ObjectCache, pHolder->GetObject());
                if (pvV8Object != nullptr)
                {
                    return CreateLocal(::HandleFromPtr(pvV8Object));
                }

                v8::Local hObject;

                auto invocability = HostObjectUtil::GetInstance().GetInvocability(pHolder->GetObject());
                if (invocability == IHostObjectUtil::Invocability::None)
                {
                    BEGIN_PULSE_VALUE_SCOPE(&m_AllowHostObjectConstructorCall, true)
                        hObject = FROM_MAYBE(m_hHostObjectTemplate->InstanceTemplate()->NewInstance(m_hContext));
                    END_PULSE_VALUE_SCOPE
                }
                else if (invocability == IHostObjectUtil::Invocability::Delegate)
                {
                    BEGIN_PULSE_VALUE_SCOPE(&m_AllowHostObjectConstructorCall, true)
                        hObject = FROM_MAYBE(m_hHostDelegateTemplate->InstanceTemplate()->NewInstance(m_hContext));
                    END_PULSE_VALUE_SCOPE
                }
                else
                {
                    BEGIN_PULSE_VALUE_SCOPE(&m_AllowHostObjectConstructorCall, true)
                        hObject = FROM_MAYBE(m_hHostInvocableTemplate->InstanceTemplate()->NewInstance(m_hContext));
                    END_PULSE_VALUE_SCOPE
                }

                ASSERT_EVAL(SetHostObjectHolder(hObject, pHolder = pHolder->Clone()));
                ASSERT_EVAL(FROM_MAYBE(hObject->SetPrivate(m_hContext, m_hAccessTokenKey, m_hAccessToken)));
                pvV8Object = ::PtrFromHandle(MakeWeak(CreatePersistent(hObject), pHolder, m_pvV8ObjectCache, DisposeWeakHandle));
                HostObjectUtil::GetInstance().CacheV8Object(m_pvV8ObjectCache, pHolder->GetObject(), pvV8Object);

                return hObject;
            }
        }

        {
            V8ObjectHolder* pHolder;
            V8Value::Subtype subtype;
            V8Value::Flags flags;
            if (value.AsV8Object(pHolder, subtype, flags))
            {
                if (pHolder->IsSameIsolate(m_spIsolateImpl))
                {
                    return CreateLocal(::HandleFromPtr(pHolder->GetObject()));
                }

                if (HasFlag(flags, V8Value::Flags::Shared))
                {
                    const auto& spSharedObjectInfo = pHolder->GetSharedObjectInfo();
                    if (!spSharedObjectInfo.IsEmpty())
                    {
                        switch (subtype)
                        {
                            case V8Value::Subtype::ArrayBuffer:
                                return CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore());

                            case V8Value::Subtype::DataView:
                                return v8::DataView::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetSize());

                            case V8Value::Subtype::Uint8Array:
                                return v8::Uint8Array::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            case V8Value::Subtype::Uint8ClampedArray:
                                return v8::Uint8ClampedArray::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            case V8Value::Subtype::Int8Array:
                                return v8::Int8Array::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            case V8Value::Subtype::Uint16Array:
                                return v8::Uint16Array::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            case V8Value::Subtype::Int16Array:
                                return v8::Int16Array::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            case V8Value::Subtype::Uint32Array:
                                return v8::Uint32Array::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            case V8Value::Subtype::Int32Array:
                                return v8::Int32Array::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            case V8Value::Subtype::BigUint64Array:
                                return v8::BigUint64Array::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            case V8Value::Subtype::BigInt64Array:
                                return v8::BigInt64Array::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            case V8Value::Subtype::Float32Array:
                                return v8::Float32Array::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            case V8Value::Subtype::Float64Array:
                                return v8::Float64Array::New(CreateSharedArrayBuffer(spSharedObjectInfo->GetBackingStore()), spSharedObjectInfo->GetOffset(), spSharedObjectInfo->GetLength());

                            default:
                                break;
                        }
                    }
                }

                return GetUndefined();
            }
        }

        {
            double result;
            if (value.AsDateTime(result))
            {
                return FROM_MAYBE(v8::Date::New(m_hContext, result));
            }
        }

        {
            const V8BigInt* pBigInt;
            if (value.AsBigInt(pBigInt))
            {
                const auto& words = pBigInt->GetWords();
                const auto wordCount = static_cast(std::min(words.size(), static_cast(INT_MAX)));
                return FROM_MAYBE(v8::BigInt::NewFromWords(m_hContext, pBigInt->GetSignBit(), wordCount, words.data()));
            }
        }

    FROM_MAYBE_CATCH_CONSUME

    return GetUndefined();
}

//-----------------------------------------------------------------------------

V8Value V8ContextImpl::ExportValue(v8::Local hValue)
{
    FROM_MAYBE_TRY

        if (hValue.IsEmpty())
        {
            return V8Value(V8Value::Nonexistent);
        }

        if (hValue->IsUndefined())
        {
            return V8Value(V8Value::Undefined);
        }

        if (hValue->IsNull())
        {
            return V8Value(V8Value::Null);
        }

        if (hValue->IsBoolean())
        {
            return V8Value(m_spIsolateImpl->BooleanValue(hValue));
        }

        if (hValue->IsNumber())
        {
            return V8Value(FROM_MAYBE(hValue->NumberValue(m_hContext)));
        }

        if (hValue->IsInt32())
        {
            return V8Value(FROM_MAYBE(hValue->Int32Value(m_hContext)));
        }

        if (hValue->IsUint32())
        {
            return V8Value(FROM_MAYBE(hValue->Uint32Value(m_hContext)));
        }

        if (hValue->IsString())
        {
            return V8Value(new StdString(CreateStdString(hValue)));
        }

        if (m_DateTimeConversionEnabled && hValue->IsDate())
        {
            return V8Value(V8Value::DateTime, hValue.As()->ValueOf());
        }

        auto hBigInt = ::ValueAsBigInt(hValue);
        if (!hBigInt.IsEmpty())
        {
            auto signBit = 0;
            std::vector words;

            auto wordCount = hBigInt->WordCount();
            if (wordCount > 0)
            {
                words.resize(wordCount);
                hBigInt->ToWordsArray(&signBit, &wordCount, words.data());
            }

            return V8Value(new V8BigInt(signBit, std::move(words)));
        }

        auto hObject = ::ValueAsObject(hValue);
        if (!hObject.IsEmpty())
        {
            auto pHolder = GetHostObjectHolder(hObject);
            if (pHolder != nullptr)
            {
                return V8Value(pHolder->Clone());
            }

            auto subtype = V8Value::Subtype::None;
            auto flags = V8Value::Flags::None;
            SharedPtr spSharedObjectInfo;

            if (hObject->IsFunction())
            {
                subtype = V8Value::Subtype::Function;

                if (hObject->IsAsyncFunction())
                {
                    flags = CombineFlags(flags, V8Value::Flags::Async);
                }

                if (hObject->IsGeneratorFunction())
                {
                    flags = CombineFlags(flags, V8Value::Flags::Generator);
                }
            }
            else if (hObject->IsGeneratorObject())
            {
                subtype = V8Value::Subtype::Iterator;

                if (m_hAsyncGeneratorConstructor.IsEmpty())
                {
                    auto hEngineInternal = FROM_MAYBE(m_hContext->Global()->Get(m_hContext, CreateString("EngineInternal"))).As();
                    m_hAsyncGeneratorConstructor = CreatePersistent(FROM_MAYBE(hEngineInternal->Get(m_hContext, CreateString("asyncGenerator"))));
                }

                if (FROM_MAYBE(hObject->Get(m_hContext, m_hConstructorKey))->StrictEquals(m_hAsyncGeneratorConstructor))
                {
                    flags = CombineFlags(flags, V8Value::Flags::Async);
                }
            }
            else if (hObject->IsMapIterator() || hObject->IsSetIterator())
            {
                subtype = V8Value::Subtype::Iterator;
            }
            else if (hObject->IsPromise())
            {
                subtype = V8Value::Subtype::Promise;
            }
            else if (hObject->IsArray())
            {
                subtype = V8Value::Subtype::Array;
            }
            else if (hObject->IsArrayBuffer())
            {
                subtype = V8Value::Subtype::ArrayBuffer;
            }
            else if (hObject->IsSharedArrayBuffer())
            {
                subtype = V8Value::Subtype::ArrayBuffer;
                flags = CombineFlags(flags, V8Value::Flags::Shared);

                auto hSharedArrayBuffer = hObject.As();
                auto size = hSharedArrayBuffer->ByteLength();
                spSharedObjectInfo = new V8SharedObjectInfo(hSharedArrayBuffer->GetBackingStore(), 0, size, size);
            }
            else if (hObject->IsArrayBufferView())
            {
                auto hArrayBufferView = hObject.As();
                auto offset = hArrayBufferView->ByteOffset();
                auto size = hArrayBufferView->ByteLength();

                auto spBackingStore = hArrayBufferView->Buffer()->GetBackingStore();
                if (spBackingStore->IsShared())
                {
                    flags = CombineFlags(flags, V8Value::Flags::Shared);
                }

                if (hObject->IsDataView())
                {
                    subtype = V8Value::Subtype::DataView;
                    if (HasFlag(flags, V8Value::Flags::Shared))
                    {
                        spSharedObjectInfo = new V8SharedObjectInfo(std::move(spBackingStore), offset, size, size);
                    }
                }
                else if (hObject->IsTypedArray())
                {
                    if (hObject->IsUint8Array())
                    {
                        subtype = V8Value::Subtype::Uint8Array;
                    }
                    else if (hObject->IsUint8ClampedArray())
                    {
                        subtype = V8Value::Subtype::Uint8ClampedArray;
                    }
                    else if (hObject->IsInt8Array())
                    {
                        subtype = V8Value::Subtype::Int8Array;
                    }
                    else if (hObject->IsUint16Array())
                    {
                        subtype = V8Value::Subtype::Uint16Array;
                    }
                    else if (hObject->IsInt16Array())
                    {
                        subtype = V8Value::Subtype::Int16Array;
                    }
                    else if (hObject->IsUint32Array())
                    {
                        subtype = V8Value::Subtype::Uint32Array;
                    }
                    else if (hObject->IsInt32Array())
                    {
                        subtype = V8Value::Subtype::Int32Array;
                    }
                    else if (hObject->IsBigUint64Array())
                    {
                        subtype = V8Value::Subtype::BigUint64Array;
                    }
                    else if (hObject->IsBigInt64Array())
                    {
                        subtype = V8Value::Subtype::BigInt64Array;
                    }
                    else if (hObject->IsFloat32Array())
                    {
                        subtype = V8Value::Subtype::Float32Array;
                    }
                    else if (hObject->IsFloat64Array())
                    {
                        subtype = V8Value::Subtype::Float64Array;
                    }

                    if (HasFlag(flags, V8Value::Flags::Shared) && (subtype != V8Value::Subtype::None))
                    {
                        auto hTypedArray = hObject.As();
                        spSharedObjectInfo = new V8SharedObjectInfo(std::move(spBackingStore), offset, size, hTypedArray->Length());
                    }
                }
            }

            return V8Value(new V8ObjectHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hObject)), hObject->GetIdentityHash(), spSharedObjectInfo), subtype, flags);
        }

    FROM_MAYBE_CATCH_CONSUME

    return V8Value(V8Value::Undefined);
}

//-----------------------------------------------------------------------------

void V8ContextImpl::ImportValues(const std::vector& values, std::vector& importedValues)
{
    importedValues.clear();

    auto valueCount = static_cast(values.size());
    importedValues.reserve(valueCount);

    for (auto index = 0; index < valueCount; index++)
    {
        importedValues.push_back(ImportValue(values[index]));
    }
}

//-----------------------------------------------------------------------------

v8::ScriptOrigin V8ContextImpl::CreateScriptOrigin(const V8DocumentInfo& documentInfo)
{
    FROM_MAYBE_TRY

        auto uniqueId = documentInfo.GetUniqueId();
        _ASSERTE(uniqueId > 0);

        auto hHostDefinedOptions = CreatePrimitiveArray(1);
        SetPrimitiveArrayItem(hHostDefinedOptions, 0, CreateBigInt(uniqueId));

        return CreateScriptOrigin(
            FROM_MAYBE(CreateString(documentInfo.GetResourceName())),
            0,
            0,
            false,
            -1,
            (documentInfo.GetSourceMapUrl().GetLength() > 0) ? FROM_MAYBE(CreateString(documentInfo.GetSourceMapUrl())) : v8::Local(),
            false,
            false,
            documentInfo.IsModule(),
            hHostDefinedOptions
        );

    FROM_MAYBE_CATCH

        throw;

    FROM_MAYBE_END
}

//-----------------------------------------------------------------------------

void V8ContextImpl::Verify(const V8IsolateImpl::ExecutionScope& isolateExecutionScope, const v8::TryCatch& tryCatch)
{
    if (tryCatch.HasCaught())
    {
        if (!tryCatch.CanContinue())
        {
            VerifyNotOutOfMemory();
            throw V8Exception(V8Exception::Type::Interrupt, m_Name, StdString(SL("Script execution interrupted by host")), CreateStdString(FROM_MAYBE_DEFAULT(tryCatch.StackTrace(m_hContext))), isolateExecutionScope.ExecutionStarted(), V8Value(V8Value::Null), V8Value(V8Value::Undefined));
        }

        auto hException = tryCatch.Exception();
        if (hException->SameValue(m_hTerminationException))
        {
            VerifyNotOutOfMemory();
            throw V8Exception(V8Exception::Type::Interrupt, m_Name, StdString(SL("Script execution interrupted by host")), CreateStdString(FROM_MAYBE_DEFAULT(tryCatch.StackTrace(m_hContext))), isolateExecutionScope.ExecutionStarted(), V8Value(V8Value::Null), V8Value(V8Value::Undefined));
        }

        StdString message;
        bool stackOverflow;

        StdString constructorName;
        if (hException->IsObject())
        {
            constructorName = CreateStdString(hException.As()->GetConstructorName());
        }

        auto value = CreateStdString(hException);
        if (value.GetLength() > 0)
        {
            message = std::move(value);
            stackOverflow = (strcmp(message.ToUTF8().c_str(), "RangeError: Maximum call stack size exceeded") == 0);
        }
        else if (!hException->IsObject())
        {
            message = SL("Unknown error; an unrecognized value was thrown and not caught");
            stackOverflow = false;
        }
        else
        {
            if ((constructorName == SL("Error")) || (constructorName == SL("RangeError")))
            {
                // It is unclear why V8 sometimes throws Error or RangeError objects that convert
                // to empty strings, but it probably has to do with memory pressure. It seems to
                // happen only during stack overflow recovery.

                message = SL("Unknown error (");
                message += constructorName;
                message += SL("); potential stack overflow detected");
                stackOverflow = true;
            }
            else if (constructorName.GetLength() > 0)
            {
                message = SL("Unknown error (");
                message += constructorName;
                message += SL(")");
                stackOverflow = false;
            }
            else
            {
                message = SL("Unknown error; an unrecognized object was thrown and not caught");
                stackOverflow = false;
            }
        }

        StdString stackTrace;
        V8Value hostException(V8Value::Undefined);

        if (stackOverflow)
        {
            stackTrace = message;
        }
        else
        {
            auto hStackTrace = FROM_MAYBE_DEFAULT(tryCatch.StackTrace(m_hContext));
            if (!hStackTrace.IsEmpty())
            {
                stackTrace = CreateStdString(hStackTrace);
            }

            auto hMessage = tryCatch.Message();
            if (!hMessage.IsEmpty())
            {
                if (message.GetLength() < 1)
                {
                    message = CreateStdString(hMessage->Get());
                }

                stackTrace = message;

                auto hMessageStackTrace = hMessage->GetStackTrace();
                auto frameCount = !hMessageStackTrace.IsEmpty() ? hMessageStackTrace->GetFrameCount() : 0;
                auto usedSourceLine = false;

                if ((frameCount < 1) || (constructorName == SL("SyntaxError")))
                {
                    auto hScriptResourceName = hMessage->GetScriptResourceName();
                    if (!hScriptResourceName.IsEmpty() && !hScriptResourceName->IsNull() && !hScriptResourceName->IsUndefined())
                    {
                        auto hScriptName = FROM_MAYBE_DEFAULT(hScriptResourceName->ToString(m_hContext));
                        if (!hScriptName.IsEmpty() && (hScriptName->Length() > 0))
                        {
                            stackTrace += SL("\n    at ");
                            stackTrace += CreateStdString(hScriptName);
                        }
                        else
                        {
                            stackTrace += SL("\n    at ");
                        }
                    }
                    else
                    {
                        stackTrace += SL("\n    at ");
                    }

                    stackTrace += SL(':');
                    stackTrace += StdString(std::to_string(FROM_MAYBE_DEFAULT(hMessage->GetLineNumber(m_hContext))));
                    stackTrace += SL(':');
                    stackTrace += StdString(std::to_string(FROM_MAYBE_DEFAULT(hMessage->GetStartColumn(m_hContext)) + 1));

                    auto hSourceLine = FROM_MAYBE_DEFAULT(hMessage->GetSourceLine(m_hContext));
                    if (!hSourceLine.IsEmpty() && (hSourceLine->Length() > 0))
                    {
                        stackTrace += SL(" -> ");
                        stackTrace += CreateStdString(hSourceLine);
                    }

                    usedSourceLine = true;
                }

                for (int index = 0; index < frameCount; index++)
                {
                    auto hFrame = GetStackFrame(hMessageStackTrace, index);
                    stackTrace += SL("\n    at ");

                    auto hFunctionName = hFrame->GetFunctionName();
                    if (!hFunctionName.IsEmpty() && (hFunctionName->Length() > 0))
                    {
                        if (hFrame->IsConstructor())
                        {
                            stackTrace += SL("new ");
                        }

                        stackTrace += CreateStdString(hFunctionName);
                        stackTrace += SL(" (");
                    }

                    auto hScriptName = hFrame->GetScriptName();
                    if (!hScriptName.IsEmpty() && (hScriptName->Length() > 0))
                    {
                        stackTrace += CreateStdString(hScriptName);
                    }
                    else
                    {
                        stackTrace += SL("");
                    }

                    stackTrace += SL(':');
                    auto lineNumber = hFrame->GetLineNumber();
                    if (lineNumber != v8::Message::kNoLineNumberInfo)
                    {
                        stackTrace += StdString(std::to_string(lineNumber));
                    }

                    stackTrace += SL(':');
                    auto column = hFrame->GetColumn();
                    if (column != v8::Message::kNoColumnInfo)
                    {
                        stackTrace += StdString(std::to_string(column));
                    }

                    if (!hFunctionName.IsEmpty() && (hFunctionName->Length() > 0))
                    {
                        stackTrace += L')';
                    }

                    if (!usedSourceLine)
                    {
                        auto hSourceLine = FROM_MAYBE_DEFAULT(hMessage->GetSourceLine(m_hContext));
                        if (!hSourceLine.IsEmpty() && (hSourceLine->Length() > 0))
                        {
                            stackTrace += SL(" -> ");
                            stackTrace += CreateStdString(hSourceLine);
                        }

                        usedSourceLine = true;
                    }
                }
            }

            if (hException->IsObject())
            {
                hostException = ExportValue(FROM_MAYBE_DEFAULT(hException.As()->Get(m_hContext, m_hHostExceptionKey)));
            }
        }

        throw V8Exception(V8Exception::Type::General, m_Name, std::move(message), std::move(stackTrace), isolateExecutionScope.ExecutionStarted(), ExportValue(hException), std::move(hostException));
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::VerifyNotOutOfMemory()
{
    if (m_spIsolateImpl->IsOutOfMemory())
    {
        m_spIsolateImpl->ThrowOutOfMemoryException();
    }
}

//-----------------------------------------------------------------------------

void V8ContextImpl::ThrowScriptException(const HostException& exception)
{
    FROM_MAYBE_TRY

        // WARNING: Error instantiation may fail during script interruption. Check Exception::Error()
        // result to avoid access violations. Extra defense is warranted here.

        if (!IsExecutionTerminating())
        {
            auto hException = v8::Exception::Error(FROM_MAYBE(CreateString(exception.GetMessage()))).As();
            if (!hException.IsEmpty() && hException->IsObject())
            {
                if (!m_HideHostExceptions)
                {
                    auto hHostException = ImportValue(exception.GetException());
                    if (!hHostException.IsEmpty() && hHostException->IsObject())
                    {
                        ASSERT_EVAL(FROM_MAYBE(hException->Set(m_hContext, m_hHostExceptionKey, hHostException)));
                    }
                }

                ThrowException(hException);
            }
        }

    FROM_MAYBE_CATCH_CONSUME
}

Web Proxy Viewer  |  New URL  |  Original Page