// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include "ClearScriptV8Native.h" //----------------------------------------------------------------------------- // support for v8::Maybe and v8::MaybeLocal //----------------------------------------------------------------------------- class FromMaybeScope final { }; //----------------------------------------------------------------------------- class FromMaybeFailure final { }; //----------------------------------------------------------------------------- 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); } //----------------------------------------------------------------------------- #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__)) //----------------------------------------------------------------------------- // local helper functions //----------------------------------------------------------------------------- inline v8::Local<:string> ValueAsString(const v8::Local<:value>& hValue) { if (hValue.IsEmpty()) { return v8::Local<:string>(); } if (hValue->IsString()) { return hValue.As<:string>(); } if (hValue->IsStringObject()) { return hValue.As<:stringobject>()->ValueOf(); } return v8::Local<:string>(); } //----------------------------------------------------------------------------- inline v8::Local<:object> ValueAsObject(const v8::Local<:value>& hValue) { return (!hValue.IsEmpty() && hValue->IsObject()) ? hValue.As<:object>() : v8::Local<:object>(); } //----------------------------------------------------------------------------- inline v8::Local<:external> ValueAsExternal(const v8::Local<:value>& hValue) { return (!hValue.IsEmpty() && hValue->IsExternal()) ? hValue.As<:external>() : v8::Local<:external>(); } //----------------------------------------------------------------------------- inline v8::Local<:bigint> ValueAsBigInt(const v8::Local<:value>& hValue) { if (hValue.IsEmpty()) { return v8::Local<:bigint>(); } if (hValue->IsBigInt()) { return hValue.As<:bigint>(); } if (hValue->IsBigIntObject()) { return hValue.As<:bigintobject>()->ValueOf(); } return v8::Local<:bigint>(); } //----------------------------------------------------------------------------- inline bool TryGetValueAsBoolean(const SharedPtr& spIsolateImpl, const v8::Local<:value>& hValue, bool& value) { if (hValue.IsEmpty()) { return false; } if (hValue->IsBoolean()) { value = spIsolateImpl->BooleanValue(hValue); return true; } if (hValue->IsBooleanObject()) { value = hValue.As<:booleanobject>()->ValueOf(); return true; } return false; } //----------------------------------------------------------------------------- inline bool TryGetValueAsNumber(v8::Local<:context> hContext, const v8::Local<:value>& hValue, double& value) { if (hValue.IsEmpty()) { return false; } FROM_MAYBE_TRY if (hValue->IsNumber()) { value = FROM_MAYBE(hValue->NumberValue(hContext)); return true; } if (hValue->IsNumberObject()) { value = hValue.As<:numberobject>()->ValueOf(); return true; } FROM_MAYBE_CATCH_CONSUME return false; } //----------------------------------------------------------------------------- template inline V8ContextImpl* GetContextImplFromHolder(const TInfo& info) { auto hHolder = info.HolderV2(); if (!hHolder.IsEmpty() && hHolder->InternalFieldCount() > 0) { auto hField = hHolder->GetInternalField(0); if (!hField.IsEmpty() && hField->IsValue() && !hField.template As<:value>()->IsUndefined()) { return static_cast(hHolder->GetAlignedPointerFromInternalField(0)); } } return nullptr; } //----------------------------------------------------------------------------- template inline V8ContextImpl* GetContextImplFromData(const TInfo& info) { auto hContextImpl = ::ValueAsExternal(info.Data()); return !hContextImpl.IsEmpty() ? static_cast(hContextImpl->Value()) : nullptr; } //----------------------------------------------------------------------------- template inline void SetIfSameType(TVariable& /*variable*/, TValue /*value*/) { } //----------------------------------------------------------------------------- template inline void SetIfSameType(TVariable& variable, TVariable value) { variable = value; } //----------------------------------------------------------------------------- template inline v8::Intercepted GetCallbackStatus(const T& /*value*/) { return v8::Intercepted::kYes; } //----------------------------------------------------------------------------- template inline v8::Intercepted GetCallbackStatus(const v8::Local& hValue) { return hValue.IsEmpty() ? v8::Intercepted::kNo : v8::Intercepted::kYes; } //----------------------------------------------------------------------------- template inline void ProcessCallbackResult(const TResult& result, const TInfo& info, TStatus& status) { ::SetIfSameType(status, ::GetCallbackStatus(result)); info.GetReturnValue().Set(result); } //----------------------------------------------------------------------------- template inline void ProcessVoidCallbackResult(const TInfo& info, TStatus& status) { IGNORE_UNUSED(info); ::SetIfSameType(status, v8::Intercepted::kYes); } //----------------------------------------------------------------------------- // 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 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 \ ::ProcessCallbackResult(RESULT, info, t_CallbackStatus); \ return; \ END_COMPOUND_MACRO #define CALLBACK_RETURN_VOID() \ BEGIN_COMPOUND_MACRO \ ::ProcessVoidCallbackResult(info, t_CallbackStatus); \ return; \ END_COMPOUND_MACRO #define CALLBACK_ENTER \ auto t_CallbackStatus = v8::Intercepted::kNo; \ ([&] () noexcept -> void \ { \ #define CALLBACK_EXIT \ } \ )(); \ return t_CallbackStatus; constexpr enum class DummyCallbackStatus {} t_CallbackStatus {}; //----------------------------------------------------------------------------- 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_AllowHostObjectConstructorCall(false), m_ChangedTimerResolution(false), m_pvV8ObjectCache(nullptr) { VerifyNotOutOfMemory(); if (::HasAllFlags(options.Flags, Flags::AddPerformanceObject, Flags::SetTimerResolution)) { m_ChangedTimerResolution = HighResolutionClock::SetTimerResolution(); } auto timeOrigin = HighResolutionClock::GetMillisecondsSinceUnixEpoch(); m_RelativeTimeOrigin = HighResolutionClock::GetRelativeMilliseconds(); 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<:value>(), v8::PropertyHandlerFlags::kNonMasking)); hGlobalTemplate->SetHandler(v8::IndexedPropertyHandlerConfiguration(GetGlobalProperty, SetGlobalProperty, QueryGlobalProperty, DeleteGlobalProperty, GetGlobalPropertyIndices)); m_hContext = CreatePersistent(CreateContext(nullptr, hGlobalTemplate)); if (!m_hContext.IsEmpty()) { auto hGlobal = m_hContext->Global(); if (!hGlobal.IsEmpty() && (hGlobal->InternalFieldCount() > 0)) { hGlobal->SetAlignedPointerInInternalField(0, this); } } } if (m_hContext.IsEmpty()) { throw FromMaybeFailure(); } auto hContextImpl = CreateExternal(this); v8::Local<:functiontemplate> hGetHostObjectIteratorFunction; v8::Local<:functiontemplate> hGetHostObjectAsyncIteratorFunction; v8::Local<:functiontemplate> hGetFastHostObjectIteratorFunction; v8::Local<:functiontemplate> hGetFastHostObjectAsyncIteratorFunction; v8::Local<:functiontemplate> hGetHostObjectJsonFunction; v8::Local<:functiontemplate> hHostDelegateToFunctionFunction; BEGIN_CONTEXT_SCOPE m_hContext->SetAlignedPointerInEmbedderData(1, this); m_hIsHostObjectKey = CreatePersistent(CreateSymbol()); ASSERT_EVAL(FROM_MAYBE(m_hContext->Global()->Set(m_hContext, CreateString("isHostObjectKey"), m_hIsHostObjectKey))); m_hModuleResultKey = CreatePersistent(CreateSymbol()); ASSERT_EVAL(FROM_MAYBE(m_hContext->Global()->Set(m_hContext, CreateString("moduleResultKey"), m_hModuleResultKey))); ASSERT_EVAL(FROM_MAYBE(m_hContext->Global()->Set(m_hContext, CreateString("getPromiseState"), FROM_MAYBE(v8::Function::New(m_hContext, GetPromiseStateCallback, hContextImpl))))); ASSERT_EVAL(FROM_MAYBE(m_hContext->Global()->Set(m_hContext, CreateString("getPromiseResult"), FROM_MAYBE(v8::Function::New(m_hContext, GetPromiseResultCallback, hContextImpl))))); m_hMissingPropertyValue = CreatePersistent(CreateSymbol()); 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")); m_hSetModuleResultKey = CreatePersistent(CreateString("setResult")); hGetHostObjectIteratorFunction = CreateFunctionTemplate(GetHostObjectIterator, hContextImpl); hGetHostObjectAsyncIteratorFunction = CreateFunctionTemplate(GetHostObjectAsyncIterator, hContextImpl); hGetFastHostObjectIteratorFunction = CreateFunctionTemplate(GetFastHostObjectIterator, hContextImpl); hGetFastHostObjectAsyncIteratorFunction = CreateFunctionTemplate(GetFastHostObjectAsyncIterator, hContextImpl); hGetHostObjectJsonFunction = CreateFunctionTemplate(GetHostObjectJson, hContextImpl); hHostDelegateToFunctionFunction = 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"))); if (::HasFlag(options.Flags, Flags::AddPerformanceObject)) { auto hPerformance = CreateObject(); ASSERT_EVAL(FROM_MAYBE(hPerformance->DefineOwnProperty(m_hContext, CreateString("timeOrigin"), CreateNumber(timeOrigin), ::CombineFlags(v8::ReadOnly, v8::DontDelete)))); ASSERT_EVAL(FROM_MAYBE(hPerformance->DefineOwnProperty(m_hContext, CreateString("now"), FROM_MAYBE(v8::Function::New(m_hContext, PerformanceNowCallback, hContextImpl)), ::CombineFlags(v8::ReadOnly, v8::DontDelete)))); ASSERT_EVAL(FROM_MAYBE(hPerformance->DefineOwnProperty(m_hContext, CreateString("sleep"), FROM_MAYBE(v8::Function::New(m_hContext, PerformanceSleepCallback, hContextImpl)), ::CombineFlags(v8::ReadOnly, v8::DontDelete)))); ASSERT_EVAL(FROM_MAYBE(m_hContext->Global()->DefineOwnProperty(m_hContext, CreateString("Performance"), hPerformance, v8::DontEnum))); } 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(), hGetHostObjectIteratorFunction); m_hHostObjectTemplate->PrototypeTemplate()->Set(GetAsyncIteratorSymbol(), hGetHostObjectAsyncIteratorFunction); m_hHostObjectTemplate->PrototypeTemplate()->Set(hToJSON, hGetHostObjectJsonFunction, ::CombineFlags(v8::ReadOnly, v8::DontDelete, v8::DontEnum)); 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(), hGetHostObjectIteratorFunction); m_hHostInvocableTemplate->PrototypeTemplate()->Set(GetAsyncIteratorSymbol(), hGetHostObjectAsyncIteratorFunction); m_hHostInvocableTemplate->PrototypeTemplate()->Set(hToJSON, hGetHostObjectJsonFunction, ::CombineFlags(v8::ReadOnly, v8::DontDelete, v8::DontEnum)); 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(), hGetHostObjectIteratorFunction); m_hHostDelegateTemplate->PrototypeTemplate()->Set(GetAsyncIteratorSymbol(), hGetHostObjectAsyncIteratorFunction); m_hHostDelegateTemplate->PrototypeTemplate()->Set(hToJSON, hGetHostObjectJsonFunction, ::CombineFlags(v8::ReadOnly, v8::DontDelete, v8::DontEnum)); 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"), hHostDelegateToFunctionFunction); m_hFastHostObjectTemplate = CreatePersistent(CreateFunctionTemplate()); m_hFastHostObjectTemplate->SetClassName(CreateString("FastHostObject")); m_hFastHostObjectTemplate->SetCallHandler(HostObjectConstructorCallHandler, hContextImpl); m_hFastHostObjectTemplate->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(GetFastHostObjectProperty, SetFastHostObjectProperty, QueryFastHostObjectProperty, DeleteFastHostObjectProperty, GetFastHostObjectPropertyNames, hContextImpl, v8::PropertyHandlerFlags::kNone)); m_hFastHostObjectTemplate->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(GetFastHostObjectProperty, SetFastHostObjectProperty, QueryFastHostObjectProperty, DeleteFastHostObjectProperty, GetFastHostObjectPropertyIndices, hContextImpl)); m_hFastHostObjectTemplate->PrototypeTemplate()->Set(GetIteratorSymbol(), hGetFastHostObjectIteratorFunction); m_hFastHostObjectTemplate->PrototypeTemplate()->Set(GetAsyncIteratorSymbol(), hGetFastHostObjectAsyncIteratorFunction); m_hFastHostFunctionTemplate = CreatePersistent(CreateFunctionTemplate()); m_hFastHostFunctionTemplate->SetClassName(CreateString("FastHostFunction")); m_hFastHostFunctionTemplate->SetCallHandler(HostObjectConstructorCallHandler, hContextImpl); m_hFastHostFunctionTemplate->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(GetFastHostObjectProperty, SetFastHostObjectProperty, QueryFastHostObjectProperty, DeleteFastHostObjectProperty, GetFastHostObjectPropertyNames, hContextImpl, v8::PropertyHandlerFlags::kNone)); m_hFastHostFunctionTemplate->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(GetFastHostObjectProperty, SetFastHostObjectProperty, QueryFastHostObjectProperty, DeleteFastHostObjectProperty, GetFastHostObjectPropertyIndices, hContextImpl)); m_hFastHostFunctionTemplate->PrototypeTemplate()->Set(GetIteratorSymbol(), hGetFastHostObjectIteratorFunction); m_hFastHostFunctionTemplate->PrototypeTemplate()->Set(GetAsyncIteratorSymbol(), hGetFastHostObjectAsyncIteratorFunction); m_hFastHostFunctionTemplate->InstanceTemplate()->SetCallAsFunctionHandler(InvokeFastHostObject, hContextImpl); m_hFastHostFunctionTemplate->InstanceTemplate()->SetHostDelegate(); // instructs our patched V8 typeof implementation to return "function" m_hFastHostFunctionTemplate->PrototypeTemplate()->Set(CreateString("toFunction"), hHostDelegateToFunctionFunction); m_pvV8ObjectCache = HostObjectUtil::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); 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* pvAction) { VerifyNotOutOfMemory(); BEGIN_ISOLATE_SCOPE (*pCallback)(pvAction); END_ISOLATE_SCOPE } //----------------------------------------------------------------------------- void V8ContextImpl::CallWithLockWithArg(CallWithLockWithArgCallback* pCallback, void* pvAction, void* pvArg) { VerifyNotOutOfMemory(); BEGIN_ISOLATE_SCOPE (*pCallback)(pvAction, 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<:object> 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); 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<:value> 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); } 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 (hResult->IsPromise()) { auto hPromise = hResult.As<:promise>(); if (hModule->IsGraphAsync() || (hPromise->State() == v8::Promise::PromiseState::kPending)) { v8::Local<:object> hMetaHolder; if (TryGetCachedModuleMetaHolder(hModule, hMetaHolder)) { if (m_hGetModuleResultFunction.IsEmpty()) { auto hEngineInternal = FROM_MAYBE(m_hContext->Global()->Get(m_hContext, CreateString("EngineInternal"))).As<:object>(); m_hGetModuleResultFunction = CreatePersistent(FROM_MAYBE(hEngineInternal->Get(m_hContext, CreateString("getModuleResult"))).As<:function>()); } v8::Local<:value> args[] = { hResult, hMetaHolder }; hResult = FROM_MAYBE(m_hGetModuleResultFunction->Call(m_hContext, GetUndefined(), 2, args)); } } else if (hPromise->State() == v8::Promise::PromiseState::kFulfilled) { hResult = hPromise->Result(); if (evaluate && (hResult.IsEmpty() || hResult->IsUndefined())) { v8::Local<:object> hMetaHolder; if (TryGetCachedModuleMetaHolder(hModule, hMetaHolder)) { auto hMeta = ::ValueAsObject(FROM_MAYBE(hMetaHolder->Get(m_hContext, 0))); if (!hMeta.IsEmpty()) { hResult = FROM_MAYBE(hMeta->Get(m_hContext, m_hModuleResultKey)); } } } } else if (hPromise->State() == v8::Promise::PromiseState::kRejected) { auto hException = hPromise->Result(); if (hException->IsObject()) { auto hExceptionObject = hException.As<:object>(); 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); } 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); } 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); } 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, V8CacheKind cacheKind, std::vector& cacheBytes) { if (cacheKind == V8CacheKind::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; if (documentInfo.IsModule()) { auto hModule = GetCachedModule(documentInfo.GetUniqueId(), codeDigest, cacheBytes); 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); } std::unique_ptr<:scriptcompiler::cacheddata> upCachedData(v8::ScriptCompiler::CreateCodeCache(hModule->GetUnboundModuleScript())); if (upCachedData && (upCachedData->length > 0) && (upCachedData->data != nullptr)) { cacheBytes.resize(upCachedData->length); memcpy(cacheBytes.data(), upCachedData->data, upCachedData->length); } CacheModule(documentInfo, codeDigest, hModule, cacheBytes); } else if (cacheBytes.empty()) { std::unique_ptr<:scriptcompiler::cacheddata> upCachedData(v8::ScriptCompiler::CreateCodeCache(hModule->GetUnboundModuleScript())); if (upCachedData && (upCachedData->length > 0) && (upCachedData->data != nullptr)) { cacheBytes.resize(upCachedData->length); memcpy(cacheBytes.data(), upCachedData->data, upCachedData->length); SetCachedModuleCacheBytes(documentInfo.GetUniqueId(), codeDigest, cacheBytes); } } upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hModule)), documentInfo, codeDigest, std::move(code))); } else { auto hScript = GetCachedScript(documentInfo.GetUniqueId(), codeDigest, cacheBytes); 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); } std::unique_ptr<:scriptcompiler::cacheddata> upCachedData(v8::ScriptCompiler::CreateCodeCache(hScript)); if (upCachedData && (upCachedData->length > 0) && (upCachedData->data != nullptr)) { cacheBytes.resize(upCachedData->length); memcpy(cacheBytes.data(), upCachedData->data, upCachedData->length); } CacheScript(documentInfo, codeDigest, hScript, cacheBytes); } else if (cacheBytes.empty()) { std::unique_ptr<:scriptcompiler::cacheddata> upCachedData(v8::ScriptCompiler::CreateCodeCache(hScript)); if (upCachedData && (upCachedData->length > 0) && (upCachedData->data != nullptr)) { cacheBytes.resize(upCachedData->length); memcpy(cacheBytes.data(), upCachedData->data, upCachedData->length); SetCachedScriptCacheBytes(documentInfo.GetUniqueId(), codeDigest, cacheBytes); } } upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hScript)), documentInfo, codeDigest)); } if (!cacheBytes.empty() && 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, V8CacheKind cacheKind, const std::vector& cacheBytes, bool& cacheAccepted) { cacheAccepted = false; if ((cacheKind == V8CacheKind::None) || cacheBytes.empty()) { 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); } cacheAccepted = !pCachedData->rejected; CacheModule(documentInfo, codeDigest, hModule, cacheAccepted ? cacheBytes : std::vector()); } 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); } cacheAccepted = !pCachedData->rejected; CacheScript(documentInfo, codeDigest, hScript, cacheAccepted ? cacheBytes : std::vector()); } upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hScript)), documentInfo, codeDigest)); } 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 } //----------------------------------------------------------------------------- V8ScriptHolder* V8ContextImpl::Compile(const V8DocumentInfo& documentInfo, StdString&& code, V8CacheKind cacheKind, std::vector& cacheBytes, V8CacheResult& cacheResult) { if (cacheKind == V8CacheKind::None) { cacheResult = V8CacheResult::Disabled; return Compile(documentInfo, std::move(code)); } if (cacheBytes.empty()) { auto pScriptHolder = Compile(documentInfo, std::move(code), cacheKind, cacheBytes); cacheResult = !cacheBytes.empty() ? V8CacheResult::Updated : V8CacheResult::UpdateFailed; return pScriptHolder; } 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; std::vector cachedCacheBytes; if (documentInfo.IsModule()) { auto hModule = GetCachedModule(documentInfo.GetUniqueId(), codeDigest, cachedCacheBytes); 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); } if (!pCachedData->rejected) { cacheResult = V8CacheResult::Accepted; } else { std::unique_ptr<:scriptcompiler::cacheddata> upCachedData(v8::ScriptCompiler::CreateCodeCache(hModule->GetUnboundModuleScript())); if (upCachedData && (upCachedData->length > 0) && (upCachedData->data != nullptr)) { cacheBytes.resize(upCachedData->length); memcpy(cacheBytes.data(), upCachedData->data, upCachedData->length); cacheResult = V8CacheResult::Updated; } else { cacheResult = V8CacheResult::UpdateFailed; } } CacheModule(documentInfo, codeDigest, hModule, (cacheResult != V8CacheResult::UpdateFailed) ? cacheBytes : std::vector()); } else if (cachedCacheBytes.empty()) { std::unique_ptr<:scriptcompiler::cacheddata> upCachedData(v8::ScriptCompiler::CreateCodeCache(hModule->GetUnboundModuleScript())); if (upCachedData && (upCachedData->length > 0) && (upCachedData->data != nullptr)) { cacheBytes.resize(upCachedData->length); memcpy(cacheBytes.data(), upCachedData->data, upCachedData->length); SetCachedModuleCacheBytes(documentInfo.GetUniqueId(), codeDigest, cacheBytes); cacheResult = V8CacheResult::Updated; } else { cacheResult = V8CacheResult::UpdateFailed; } } else if (cachedCacheBytes == cacheBytes) { cacheResult = V8CacheResult::Verified; } else { cacheBytes = cachedCacheBytes; cacheResult = V8CacheResult::Updated; } upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hModule)), documentInfo, codeDigest, std::move(code))); } else { auto hScript = GetCachedScript(documentInfo.GetUniqueId(), codeDigest, cachedCacheBytes); 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); } if (!pCachedData->rejected) { cacheResult = V8CacheResult::Accepted; } else { std::unique_ptr<:scriptcompiler::cacheddata> upCachedData(v8::ScriptCompiler::CreateCodeCache(hScript)); if (upCachedData && (upCachedData->length > 0) && (upCachedData->data != nullptr)) { cacheBytes.resize(upCachedData->length); memcpy(cacheBytes.data(), upCachedData->data, upCachedData->length); cacheResult = V8CacheResult::Updated; } else { cacheResult = V8CacheResult::UpdateFailed; } } CacheScript(documentInfo, codeDigest, hScript, (cacheResult != V8CacheResult::UpdateFailed) ? cacheBytes : std::vector()); } else if (cachedCacheBytes.empty()) { std::unique_ptr<:scriptcompiler::cacheddata> upCachedData(v8::ScriptCompiler::CreateCodeCache(hScript)); if (upCachedData && (upCachedData->length > 0) && (upCachedData->data != nullptr)) { cacheBytes.resize(upCachedData->length); memcpy(cacheBytes.data(), upCachedData->data, upCachedData->length); SetCachedScriptCacheBytes(documentInfo.GetUniqueId(), codeDigest, cacheBytes); cacheResult = V8CacheResult::Updated; } else { cacheResult = V8CacheResult::UpdateFailed; } } else if (cachedCacheBytes == cacheBytes) { cacheResult = V8CacheResult::Verified; } else { cacheBytes = cachedCacheBytes; cacheResult = V8CacheResult::Updated; } upScriptHolder.reset(new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromHandle(CreatePersistent(hScript)), documentInfo, codeDigest)); } if (cacheResult != V8CacheResult::UpdateFailed) { 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); } v8::Local<:value> hResult; if (spHolder->GetDocumentInfo().IsModule()) { auto codeDigest = spHolder->GetCode().GetDigest(); auto hModule = GetCachedModule(spHolder->GetDocumentInfo().GetUniqueId(), codeDigest); if (hModule.IsEmpty()) { if (!spHolder->GetCacheBytes().empty()) { 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); } 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 (hResult->IsPromise()) { auto hPromise = hResult.As<:promise>(); if (hModule->IsGraphAsync() || (hPromise->State() == v8::Promise::PromiseState::kPending)) { v8::Local<:object> hMetaHolder; if (TryGetCachedModuleMetaHolder(hModule, hMetaHolder)) { if (m_hGetModuleResultFunction.IsEmpty()) { auto hEngineInternal = FROM_MAYBE(m_hContext->Global()->Get(m_hContext, CreateString("EngineInternal"))).As<:object>(); m_hGetModuleResultFunction = CreatePersistent(FROM_MAYBE(hEngineInternal->Get(m_hContext, CreateString("getModuleResult"))).As<:function>()); } v8::Local<:value> args[] = { hResult, hMetaHolder }; hResult = FROM_MAYBE(m_hGetModuleResultFunction->Call(m_hContext, GetUndefined(), 2, args)); } } else if (hPromise->State() == v8::Promise::PromiseState::kFulfilled) { hResult = hPromise->Result(); if (evaluate && (hResult.IsEmpty() || hResult->IsUndefined())) { v8::Local<:object> hMetaHolder; if (TryGetCachedModuleMetaHolder(hModule, hMetaHolder)) { auto hMeta = ::ValueAsObject(FROM_MAYBE(hMetaHolder->Get(m_hContext, 0))); if (!hMeta.IsEmpty()) { hResult = FROM_MAYBE(hMeta->Get(m_hContext, m_hModuleResultKey)); } } } } else if (hPromise->State() == v8::Promise::PromiseState::kRejected) { auto hException = hPromise->Result(); if (hException->IsObject()) { auto hExceptionObject = hException.As<:object>(); 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<:unboundscript>(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(false); } //----------------------------------------------------------------------------- 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, [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<:object>(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<:object>(pvObject); auto hName = FROM_MAYBE(CreateString(name)); if (FROM_MAYBE(hObject->Has(m_hContext, hName))) { value = ExportValue(FROM_MAYBE(::HandleFromPtr<:object>(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<:object>(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<:object>(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); FROM_MAYBE_END END_CONTEXT_SCOPE } //----------------------------------------------------------------------------- void V8ContextImpl::GetV8ObjectPropertyNames(void* pvObject, bool includeIndices, std::vector& names) { BEGIN_CONTEXT_SCOPE GetV8ObjectPropertyNames(::HandleFromPtr<:object>(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<:object>(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<:object>(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<:object>(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); FROM_MAYBE_END END_CONTEXT_SCOPE } //----------------------------------------------------------------------------- void V8ContextImpl::GetV8ObjectPropertyIndices(void* pvObject, std::vector& indices) { BEGIN_CONTEXT_SCOPE GetV8ObjectPropertyIndices(::HandleFromPtr<:object>(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<:object> hObject = ::HandleFromPtr<:object>(pvObject); if (!hObject->IsCallable()) { FROM_MAYBE_TRY auto hError = v8::Exception::TypeError(m_hObjectNotInvocable).As<:object>(); 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<:local>> 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<:object> hObject = ::HandleFromPtr<:object>(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<:object>(); 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<:object>(); 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<:local>> 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<:object> hObject = ::HandleFromPtr<:object>(pvObject); if (hObject->IsArrayBuffer()) { auto hArrayBuffer = hObject.As<:arraybuffer>(); arrayBuffer = ExportValue(hObject); offset = 0; size = hArrayBuffer->ByteLength(); length = size; return; } if (hObject->IsSharedArrayBuffer()) { auto hSharedArrayBuffer = hObject.As<:sharedarraybuffer>(); arrayBuffer = ExportValue(hObject); offset = 0; size = hSharedArrayBuffer->ByteLength(); length = size; return; } if (hObject->IsDataView()) { auto hDataView = hObject.As<:dataview>(); arrayBuffer = ExportValue(hDataView->Buffer()); offset = hDataView->ByteOffset(); size = hDataView->ByteLength(); length = size; return; } if (hObject->IsTypedArray()) { auto hTypedArray = hObject.As<:typedarray>(); 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); END_CONTEXT_SCOPE } //----------------------------------------------------------------------------- void V8ContextImpl::InvokeWithV8ObjectArrayBufferOrViewData(void* pvObject, V8ObjectHelpers::ArrayBufferOrViewDataCallback* pCallback, void* pvArg) { BEGIN_CONTEXT_SCOPE v8::Local<:object> hObject = ::HandleFromPtr<:object>(pvObject); if (hObject->IsArrayBuffer()) { auto hArrayBuffer = hObject.As<:arraybuffer>(); auto spBackingStore = hArrayBuffer->GetBackingStore(); (*pCallback)(spBackingStore->Data(), pvArg); return; } if (hObject->IsSharedArrayBuffer()) { auto hSharedArrayBuffer = hObject.As<:sharedarraybuffer>(); auto spBackingStore = hSharedArrayBuffer->GetBackingStore(); (*pCallback)(spBackingStore->Data(), pvArg); return; } if (hObject->IsDataView()) { auto hDataView = hObject.As<:dataview>(); auto spBackingStore = hDataView->Buffer()->GetBackingStore(); (*pCallback)(static_cast(spBackingStore->Data()) + hDataView->ByteOffset(), pvArg); return; } if (hObject->IsTypedArray()) { auto hTypedArray = hObject.As<:typedarray>(); 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); END_CONTEXT_SCOPE } //----------------------------------------------------------------------------- void V8ContextImpl::InitializeImportMeta(v8::Local<:context> hContext, v8::Local<:module> hModule, v8::Local<:object> hMeta) { BEGIN_CONTEXT_SCOPE FROM_MAYBE_TRY try { for (auto& entry : m_ModuleCache) { if (entry.hModule == hModule) { ASSERT_EVAL(FROM_MAYBE(entry.hMetaHolder->Set(hContext, 0, hMeta))); auto hSetModuleResultFunction = FROM_MAYBE(v8::Function::New(m_hContext, SetModuleResultCallback, hMeta)); ASSERT_EVAL(FROM_MAYBE(hMeta->DefineOwnProperty(m_hContext, m_hSetModuleResultKey, hSetModuleResultFunction, v8::DontEnum))); for (const auto& pair : HostObjectUtil::CreateModuleContext(entry.DocumentInfo)) { ASSERT_EVAL(FROM_MAYBE(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<:promise> V8ContextImpl::ImportModule(v8::Local<:data> hHostDefinedOptions, v8::Local<:value> /*hResourceName*/, v8::Local<:string> hSpecifier, v8::Local<:fixedarray> /*hImportAssertions*/) { V8DocumentInfo sourceDocumentInfo; const V8DocumentInfo* pSourceDocumentInfo = nullptr; if (!hHostDefinedOptions.IsEmpty()) { auto hOptions = hHostDefinedOptions.As<:primitivearray>(); 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<:promise> V8ContextImpl::ImportModule(const V8DocumentInfo* pSourceDocumentInfo, v8::Local<:string> 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) { ASSERT_EVAL(FROM_MAYBE(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<:promise>(); END_CONTEXT_SCOPE } //----------------------------------------------------------------------------- v8::MaybeLocal<:module> V8ContextImpl::ResolveModule(v8::Local<:string> hSpecifier, v8::Local<:module> hReferrer) { V8DocumentInfo sourceDocumentInfo; const V8DocumentInfo* pSourceDocumentInfo = nullptr; if (TryGetCachedModuleInfo(hReferrer, sourceDocumentInfo)) { pSourceDocumentInfo = &sourceDocumentInfo; } return ResolveModule(hSpecifier, pSourceDocumentInfo); } //----------------------------------------------------------------------------- v8::MaybeLocal<:module> V8ContextImpl::ResolveModule(v8::Local<:string> 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::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<:local>> names; std::vector exports; auto hExportsValue = ImportValue(exportsValue); if (hExportsValue.IsEmpty()) { hExportsValue = GetUndefined(); } if ((documentInfo.GetKind() == DocumentKind::Json) || !hExportsValue->IsObject()) { auto hName = CreateString("default"); names.push_back(hName); exports.push_back({ CreatePersistent(hName), CreatePersistent(hExportsValue) }); } else { auto hExports = hExportsValue.As<:object>(); auto hOwnPropertyNames = FROM_MAYBE(hExports->GetOwnPropertyNames(m_hContext, v8::SKIP_SYMBOLS, v8::KeyConversionMode::kConvertToString)); 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<:module>(); END_CONTEXT_SCOPE } //----------------------------------------------------------------------------- v8::MaybeLocal<:value> V8ContextImpl::PopulateSyntheticModule(v8::Local<:context> hContext, v8::Local<:module> hModule) { if (hContext->GetNumberOfEmbedderDataFields() > 1) { auto pContextImpl = static_cast(hContext->GetAlignedPointerFromEmbedderData(1)); if (pContextImpl != nullptr) { return pContextImpl->PopulateSyntheticModule(hModule); } } return v8::MaybeLocal<:value>(); } //----------------------------------------------------------------------------- v8::MaybeLocal<:value> V8ContextImpl::PopulateSyntheticModule(v8::Local<:module> 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<:value>(); 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::GetAllCachedV8Objects(m_pvV8ObjectCache, v8ObjectPtrs); for (auto pvV8Object : v8ObjectPtrs) { auto hObject = ::HandleFromPtr<:object>(pvV8Object); auto pHolder = GetHostObjectHolder(hObject); if (pHolder != nullptr) { delete pHolder; } ClearWeak(hObject); Dispose(hObject); } HostObjectUtil::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_hGetModuleResultFunction); Dispose(m_hToJsonFunction); Dispose(m_hToAsyncIteratorFunction); Dispose(m_hToIteratorFunction); Dispose(m_hFastHostFunctionTemplate); Dispose(m_hFastHostObjectTemplate); Dispose(m_hHostDelegateTemplate); Dispose(m_hHostInvocableTemplate); Dispose(m_hHostObjectTemplate); Dispose(m_hTerminationException); Dispose(m_hFlushFunction); Dispose(m_hSetModuleResultKey); 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_hMissingPropertyValue); Dispose(m_hModuleResultKey); 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. if (!m_hContext.IsEmpty()) { auto hGlobal = m_hContext->Global(); if (!hGlobal.IsEmpty() && (hGlobal->InternalFieldCount() > 0)) { hGlobal->SetAlignedPointerInInternalField(0, nullptr); } if (m_hContext->GetNumberOfEmbedderDataFields() > 1) { m_hContext->SetAlignedPointerInEmbedderData(1, nullptr); } Dispose(m_hContext); } if (m_ChangedTimerResolution) { HighResolutionClock::RestoreTimerResolution(); m_ChangedTimerResolution = false; } } //----------------------------------------------------------------------------- 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<:object> 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<:object> hObject, HostObjectHolder* pHolder) { if (!hObject.IsEmpty()) { return FROM_MAYBE_DEFAULT(hObject->SetPrivate(m_hContext, GetHostObjectHolderKey(), CreateExternal(pHolder))); } return false; } //----------------------------------------------------------------------------- void* V8ContextImpl::GetHostObject(v8::Local<:object> 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<:object> 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<:propertyfilter>(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 = ::ValueAsString(FROM_MAYBE(hNames->Get(m_hContext, index))); if (!hName.IsEmpty()) { names.push_back(CreateStdString(hName)); } } FROM_MAYBE_CATCH_CONSUME } //----------------------------------------------------------------------------- void V8ContextImpl::GetV8ObjectPropertyIndices(v8::Local<:object> 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<:propertyfilter>(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 <= static_cast(INT_MAX)) { indices.push_back(static_cast(value)); } } else { double value; if (::TryGetValueAsNumber(m_hContext, hName, value)) { if (value == std::round(value) && (value >= static_cast(INT_MIN)) && (value <= static_cast(INT_MAX))) { indices.push_back(static_cast(value)); } } } } FROM_MAYBE_CATCH_CONSUME } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::GetGlobalProperty(v8::Local<:name> hKey, const v8::PropertyCallbackInfo<:value>& info) { CALLBACK_ENTER 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.empty()) { 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 CALLBACK_EXIT } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::SetGlobalProperty(v8::Local<:name> hKey, v8::Local<:value> hValue, const v8::PropertyCallbackInfo& info) { CALLBACK_ENTER 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.empty()) { for (auto it = stack.rbegin(); it != stack.rend(); it++) { if (FROM_MAYBE(it->second->HasOwnProperty(pContextImpl->m_hContext, hName))) { ASSERT_EVAL(FROM_MAYBE(it->second->Set(pContextImpl->m_hContext, hName, hValue))); CALLBACK_RETURN_VOID(); } } } } FROM_MAYBE_CATCH_CONSUME CALLBACK_EXIT } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::QueryGlobalProperty(v8::Local<:name> hKey, const v8::PropertyCallbackInfo<:integer>& info) { CALLBACK_ENTER 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.empty()) { 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 CALLBACK_EXIT } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::DeleteGlobalProperty(v8::Local<:name> hKey, const v8::PropertyCallbackInfo<:boolean>& info) { CALLBACK_ENTER 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.empty()) { 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::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 CALLBACK_EXIT } //----------------------------------------------------------------------------- void V8ContextImpl::GetGlobalPropertyNames(const v8::PropertyCallbackInfo<:array>& info) { FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromHolder(info); if (CheckContextImplForGlobalObjectCallback(pContextImpl)) { try { const auto& stack = pContextImpl->m_GlobalMembersStack; if (!stack.empty()) { 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::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 } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::GetGlobalProperty(uint32_t index, const v8::PropertyCallbackInfo<:value>& info) { CALLBACK_ENTER FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromHolder(info); if (CheckContextImplForGlobalObjectCallback(pContextImpl)) { const auto& stack = pContextImpl->m_GlobalMembersStack; if (!stack.empty()) { 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 CALLBACK_EXIT } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::SetGlobalProperty(uint32_t index, v8::Local<:value> hValue, const v8::PropertyCallbackInfo& info) { CALLBACK_ENTER FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromHolder(info); if (CheckContextImplForGlobalObjectCallback(pContextImpl)) { const auto& stack = pContextImpl->m_GlobalMembersStack; if (!stack.empty()) { 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))) { ASSERT_EVAL(FROM_MAYBE(it->second->Set(pContextImpl->m_hContext, index, hValue))); CALLBACK_RETURN_VOID(); } } } } FROM_MAYBE_CATCH_CONSUME CALLBACK_EXIT } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::QueryGlobalProperty(uint32_t index, const v8::PropertyCallbackInfo<:integer>& info) { CALLBACK_ENTER FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromHolder(info); if (CheckContextImplForGlobalObjectCallback(pContextImpl)) { const auto& stack = pContextImpl->m_GlobalMembersStack; if (!stack.empty()) { 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 CALLBACK_EXIT } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::DeleteGlobalProperty(uint32_t index, const v8::PropertyCallbackInfo<:boolean>& info) { CALLBACK_ENTER FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromHolder(info); if (CheckContextImplForGlobalObjectCallback(pContextImpl)) { const auto& stack = pContextImpl->m_GlobalMembersStack; if (!stack.empty()) { 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 CALLBACK_EXIT } //----------------------------------------------------------------------------- void V8ContextImpl::GetGlobalPropertyIndices(const v8::PropertyCallbackInfo<:array>& info) { FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromHolder(info); if (CheckContextImplForGlobalObjectCallback(pContextImpl)) { try { const auto& stack = pContextImpl->m_GlobalMembersStack; if (!stack.empty()) { 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::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<:value>& 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<:value>& info) { FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromData(info); if (pContextImpl != nullptr) { auto pvObject = pContextImpl->GetHostObject(info.This()); 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<:object>(); pContextImpl->m_hToIteratorFunction = pContextImpl->CreatePersistent(FROM_MAYBE(hEngineInternal->Get(pContextImpl->m_hContext, pContextImpl->CreateString("toIterator"))).As<:function>()); } v8::Local<:value> args[] = { pContextImpl->ImportValue(HostObjectUtil::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<:value>& info) { FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromData(info); if (pContextImpl != nullptr) { auto pvObject = pContextImpl->GetHostObject(info.This()); 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<:object>(); pContextImpl->m_hToAsyncIteratorFunction = pContextImpl->CreatePersistent(FROM_MAYBE(hEngineInternal->Get(pContextImpl->m_hContext, pContextImpl->CreateString("toAsyncIterator"))).As<:function>()); } v8::Local<:value> args[] = { pContextImpl->ImportValue(HostObjectUtil::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::GetFastHostObjectIterator(const v8::FunctionCallbackInfo<:value>& info) { FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromData(info); if (pContextImpl != nullptr) { auto pvObject = pContextImpl->GetHostObject(info.This()); 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<:object>(); pContextImpl->m_hToIteratorFunction = pContextImpl->CreatePersistent(FROM_MAYBE(hEngineInternal->Get(pContextImpl->m_hContext, pContextImpl->CreateString("toIterator"))).As<:function>()); } v8::Local<:value> args[] = { pContextImpl->ImportValue(FastHostObjectUtil::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::GetFastHostObjectAsyncIterator(const v8::FunctionCallbackInfo<:value>& info) { FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromData(info); if (pContextImpl != nullptr) { auto pvObject = pContextImpl->GetHostObject(info.This()); 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<:object>(); pContextImpl->m_hToAsyncIteratorFunction = pContextImpl->CreatePersistent(FROM_MAYBE(hEngineInternal->Get(pContextImpl->m_hContext, pContextImpl->CreateString("toAsyncIterator"))).As<:function>()); } v8::Local<:value> args[] = { pContextImpl->ImportValue(FastHostObjectUtil::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<:value>& info) { FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromData(info); if (pContextImpl != nullptr) { auto hObject = info.This(); 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<:object>(); pContextImpl->m_hToJsonFunction = pContextImpl->CreatePersistent(FROM_MAYBE(hEngineInternal->Get(pContextImpl->m_hContext, pContextImpl->CreateString("toJson"))).As<:function>()); } v8::Local<:value> 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<:value>& info) { FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromData(info); if (pContextImpl != nullptr) { CALLBACK_RETURN(FROM_MAYBE(v8::Function::New(pContextImpl->m_hContext, InvokeHostDelegate, info.This()))); } FROM_MAYBE_CATCH_CONSUME } //----------------------------------------------------------------------------- void V8ContextImpl::InvokeHostDelegate(const v8::FunctionCallbackInfo<:value>& info) { auto hTarget = ::ValueAsObject(info.Data()); if (!hTarget.IsEmpty()) { auto argCount = static_cast(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))); } if (argCount <= Constants::MaxInlineArgCount) { v8::Local<:value> args[argCount]; for (size_t index = 0; index < argCount; index++) { args[index] = info[index]; } if (info.IsConstructCall()) { CALLBACK_RETURN(FROM_MAYBE_DEFAULT(hTarget->CallAsConstructor(info.GetIsolate()->GetCurrentContext(), argCount, args))); } CALLBACK_RETURN(FROM_MAYBE_DEFAULT(hTarget->CallAsFunction(info.GetIsolate()->GetCurrentContext(), hTarget, argCount, args))); } std::vector<:local>> args; args.reserve(argCount); for (size_t 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()))); } } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::GetHostObjectProperty(v8::Local<:name> hKey, const v8::PropertyCallbackInfo<:value>& info) { CALLBACK_ENTER FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromData(info); if (CheckContextImplForHostObjectCallback(pContextImpl)) { auto hHolder = info.HolderV2(); 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()); } } else 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))) { auto hValue = FROM_MAYBE(hCache->Get(pContextImpl->m_hContext, hName)); CALLBACK_RETURN(!hValue->StrictEquals(pContextImpl->m_hMissingPropertyValue) ? hValue : v8::Local<:value>()); } } bool isCacheable; auto hResult = pContextImpl->ImportValue(HostObjectUtil::GetProperty(pvObject, pContextImpl->CreateStdString(hName), isCacheable)); if (isCacheable) { 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.IsEmpty() ? hResult : pContextImpl->m_hMissingPropertyValue))); } CALLBACK_RETURN(hResult); } catch (const HostException& exception) { pContextImpl->ThrowScriptException(exception); } } } FROM_MAYBE_CATCH_CONSUME CALLBACK_EXIT } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::SetHostObjectProperty(v8::Local<:name> hKey, v8::Local<:value> hValue, const v8::PropertyCallbackInfo& info) { CALLBACK_ENTER auto hName = ::ValueAsString(hKey); if (hName.IsEmpty()) { return; } auto pContextImpl = ::GetContextImplFromData(info); if (CheckContextImplForHostObjectCallback(pContextImpl)) { auto pvObject = pContextImpl->GetHostObject(info.HolderV2()); if (pvObject != nullptr) { try { HostObjectUtil::SetProperty(pvObject, pContextImpl->CreateStdString(hName), pContextImpl->ExportValue(hValue)); CALLBACK_RETURN_VOID(); } catch (const HostException& exception) { pContextImpl->ThrowScriptException(exception); } } } CALLBACK_EXIT } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::QueryHostObjectProperty(v8::Local<:name> hKey, const v8::PropertyCallbackInfo<:integer>& info) { CALLBACK_ENTER auto hName = ::ValueAsString(hKey); if (hName.IsEmpty()) { return; } auto pContextImpl = ::GetContextImplFromData(info); if (CheckContextImplForHostObjectCallback(pContextImpl)) { auto pvObject = pContextImpl->GetHostObject(info.HolderV2()); if (pvObject != nullptr) { try { std::vector names; HostObjectUtil::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); } } } CALLBACK_EXIT } //----------------------------------------------------------------------------- v8::Intercepted V8ContextImpl::DeleteHostObjectProperty(v8::Local<:name> hKey, const v8::PropertyCallbackInfo<:boolean>& info) { CALLBACK_ENTER auto hName = ::ValueAsString(hKey); if (hName.IsEmpty()) { return; } auto pContextImpl = ::GetContextImplFromData(info); if (CheckContextImplForHostObjectCallback(pContextImpl)) { auto pvObject = pContextImpl->GetHostObject(info.HolderV2()); if (pvObject != nullptr) { try { CALLBACK_RETURN(HostObjectUtil::DeleteProperty(pvObject, pContextImpl->CreateStdString(hName))); } catch (const HostException& exception) { pContextImpl->ThrowScriptException(exception); } } } CALLBACK_EXIT } //----------------------------------------------------------------------------- void V8ContextImpl::GetHostObjectPropertyNames(const v8::PropertyCallbackInfo<:array>& info) { FROM_MAYBE_TRY auto pContextImpl = ::GetContextImplFromData(info); if (CheckContextImplForHostObjectCallback(pContextImpl)) { auto pvObject = pContextImpl->GetHostObject(info.HolderV2()); if (pvObject != nullptr) { try { std::vector names; HostObjectUtil::GetPropertyNames(pvObject, names); auto nameCount = static_cast