// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #pragma once //----------------------------------------------------------------------------- // V8 headers //----------------------------------------------------------------------------- #pragma warning(push, 3) #pragma warning(disable: 4996) // deprecated item usage #define V8_DEPRECATION_WARNINGS #define V8_IMMINENT_DEPRECATION_WARNINGS #ifdef _DEBUG #define V8_ENABLE_CHECKS 1 #endif // _DEBUG // #define CLEARSCRIPT_V8_POINTER_COMPRESSION_ENABLED #ifdef CLEARSCRIPT_V8_POINTER_COMPRESSION_ENABLED #if INTPTR_MAX == INT64_MAX #define V8_COMPRESS_POINTERS #define V8_31BIT_SMIS_ON_64BIT_ARCH #endif // INTPTR_MAX == INT64_MAX #endif // CLEARSCRIPT_V8_POINTER_COMPRESSION_ENABLED #include "v8.h" #include "v8-platform.h" #include "v8-inspector.h" #include "v8-profiler.h" #include "libplatform/libplatform.h" #pragma warning(pop) //----------------------------------------------------------------------------- // V8FastPersistent - a (nearly) drop-in replacement for classic v8::Persistent // // WARNING: This class breaks encapsulation in order to avoid heap allocation. // It makes assumptions about v8::Persistent implementation and memory layout. //----------------------------------------------------------------------------- template class V8FastPersistent final { template friend class V8FastPersistent; public: V8FastPersistent(): m_pValue(nullptr) { } template static V8FastPersistent New(v8::Isolate* pIsolate, const v8::Local& hValue) { v8::Persistent hTemp(pIsolate, hValue); return V8FastPersistent(GetPtrAndClear(hTemp)); } template static V8FastPersistent New(v8::Isolate* pIsolate, const V8FastPersistent& hValue) { v8::Persistent hTemp(pIsolate, hValue.AsPersistent()); return V8FastPersistent(GetPtrAndClear(hTemp)); } template bool operator==(const v8::Local& hValue) const { return AsPersistent() == hValue; } template bool operator==(const V8FastPersistent& hValue) const { return AsPersistent() == hValue.AsPersistent(); } template bool operator!=(const v8::Local& hValue) const { return AsPersistent() != hValue; } template bool operator!=(const V8FastPersistent& hValue) const { return AsPersistent() != hValue.AsPersistent(); } bool IsEmpty() const { return AsPersistent().IsEmpty(); } void* ToPtr() const { return m_pValue; } static V8FastPersistent FromPtr(void* pvValue) { return V8FastPersistent(static_cast(pvValue)); } v8::Local operator->() const { return CreateLocal(); } template operator v8::Local() const { return CreateLocal(); } v8::Local CreateLocal(v8::Isolate* pIsolate) const { return v8::Local::New(pIsolate, AsPersistent()); } bool IsWeak() const { return AsPersistent().IsWeak(); } template V8FastPersistent MakeWeak(v8::Isolate* pIsolate, TArg1* pArg1, TArg2* pArg2, void (*pCallback)(v8::Isolate*, V8FastPersistent*, TArg1*, TArg2*)) { IGNORE_UNUSED(pIsolate); _ASSERTE(!IsWeak() && !IsEmpty()); AsPersistent().SetWeak(new WeakCallbackContext(m_pValue, pArg1, pArg2, pCallback), WeakCallback, v8::WeakCallbackType::kParameter); return *this; } void ClearWeak() { _ASSERTE(IsWeak()); auto pContext = AsPersistent().template ClearWeak(); _ASSERTE(pContext); delete pContext; } void Dispose() { AsPersistent().Reset(); } private: explicit V8FastPersistent(T* pValue): m_pValue(pValue) { } v8::Local CreateLocal() const { return v8::Local::New(v8::Isolate::GetCurrent(), AsPersistent()); } const v8::Persistent& AsPersistent() const { return *(reinterpret_cast*>(&m_pValue)); } v8::Persistent& AsPersistent() { return *(reinterpret_cast<:persistent>*>(&m_pValue)); } static T* GetPtrAndClear(v8::Persistent& hValue) { auto ppValue = reinterpret_cast(&hValue); auto pValue = *ppValue; *ppValue = nullptr; _ASSERTE(hValue.IsEmpty()); return pValue; } class WeakCallbackContextBase { public: virtual ~WeakCallbackContextBase() {} }; template class WeakCallbackContext final: public WeakCallbackContextBase { public: WeakCallbackContext(T* pValue, TArg1* pArg1, TArg2* pArg2, void (*pCallback)(v8::Isolate*, V8FastPersistent*, TArg1*, TArg2*)): m_pValue(pValue), m_pArg1(pArg1), m_pArg2(pArg2), m_pCallback(pCallback) { } void InvokeCallback(v8::Isolate* pIsolate) const { V8FastPersistent hTarget(m_pValue); m_pCallback(pIsolate, &hTarget, m_pArg1, m_pArg2); } private: T* m_pValue; TArg1* m_pArg1; TArg2* m_pArg2; void (*m_pCallback)(v8::Isolate*, V8FastPersistent*, TArg1*, TArg2*); }; template static void WeakCallback(const v8::WeakCallbackInfo& data) { auto pContext = data.GetParameter(); _ASSERTE(pContext); pContext->InvokeCallback(data.GetIsolate()); delete pContext; } T* m_pValue; }; //----------------------------------------------------------------------------- // V8SafePersistent - a (nearly) drop-in replacement for classic v8::Persistent //----------------------------------------------------------------------------- template class V8SafePersistent final { template friend class V8SafePersistent; public: V8SafePersistent(): m_pImpl(nullptr) { } template static V8SafePersistent New(v8::Isolate* pIsolate, const v8::Local& hValue) { return V8SafePersistent(new v8::Persistent(pIsolate, hValue)); } template static V8SafePersistent New(v8::Isolate* pIsolate, const V8SafePersistent& hValue) { return V8SafePersistent(new v8::Persistent(pIsolate, hValue.GetImpl())); } template bool operator==(const v8::Local& hValue) const { return GetImpl() == hValue; } template bool operator==(const V8SafePersistent& hValue) const { return GetImpl() == hValue.GetImpl(); } template bool operator!=(const v8::Local& hValue) const { return GetImpl() != hValue; } template bool operator!=(const V8SafePersistent& hValue) const { return GetImpl() != hValue.GetImpl(); } bool IsEmpty() const { return (m_pImpl == nullptr) || m_pImpl->IsEmpty(); } void* ToPtr() const { return m_pImpl; } static V8SafePersistent FromPtr(void* pvImpl) { return V8SafePersistent(static_cast<:persistent>*>(pvImpl)); } v8::Local operator->() const { return CreateLocal(); } template operator v8::Local() const { return CreateLocal(); } v8::Local CreateLocal(v8::Isolate* pIsolate) const { return v8::Local::New(pIsolate, GetImpl()); } bool IsWeak() const { return (m_pImpl != nullptr) && m_pImpl->IsWeak(); } template V8SafePersistent MakeWeak(v8::Isolate* pIsolate, TArg1* pArg1, TArg2* pArg2, void (*pCallback)(v8::Isolate*, V8SafePersistent*, TArg1*, TArg2*)) { IGNORE_UNUSED(pIsolate); _ASSERTE(!IsWeak() && !IsEmpty()); m_pImpl->SetWeak(new WeakCallbackContext(m_pImpl, pArg1, pArg2, pCallback), WeakCallback, v8::WeakCallbackType::kParameter); return *this; } void ClearWeak() { _ASSERTE(IsWeak()); auto pContext = m_pImpl->template ClearWeak(); _ASSERTE(pContext); delete pContext; } void Dispose() { if (m_pImpl != nullptr) { m_pImpl->Reset(); delete m_pImpl; m_pImpl = nullptr; } } private: explicit V8SafePersistent(v8::Persistent* pImpl): m_pImpl(pImpl) { } v8::Local CreateLocal() const { return v8::Local::New(v8::Isolate::GetCurrent(), GetImpl()); } const v8::Persistent& GetImpl() const { return (m_pImpl != nullptr) ? *m_pImpl : ms_EmptyImpl; } class WeakCallbackContextBase { public: virtual ~WeakCallbackContextBase() {} }; template class WeakCallbackContext final: public WeakCallbackContextBase { public: WeakCallbackContext(v8::Persistent* pImpl, TArg1* pArg1, TArg2* pArg2, void (*pCallback)(v8::Isolate*, V8SafePersistent*, TArg1*, TArg2*)): m_pImpl(pImpl), m_pArg1(pArg1), m_pArg2(pArg2), m_pCallback(pCallback) { } void InvokeCallback(v8::Isolate* pIsolate) const { V8SafePersistent hTarget(m_pImpl); m_pCallback(pIsolate, &hTarget, m_pArg1, m_pArg2); } private: v8::Persistent* m_pImpl; TArg1* m_pArg1; TArg2* m_pArg2; void (*m_pCallback)(v8::Isolate*, V8SafePersistent*, TArg1*, TArg2*); }; template static void WeakCallback(const v8::WeakCallbackInfo& data) { auto pContext = data.GetParameter(); _ASSERTE(pContext); pContext->InvokeCallback(data.GetIsolate()); delete pContext; } v8::Persistent* m_pImpl; static const v8::Persistent ms_EmptyImpl; }; template const v8::Persistent V8SafePersistent::ms_EmptyImpl; //----------------------------------------------------------------------------- // define classic v8::Persistent replacement //----------------------------------------------------------------------------- template using Persistent = V8FastPersistent; //----------------------------------------------------------------------------- // helper functions //----------------------------------------------------------------------------- template inline void* PtrFromHandle(const Persistent& handle) { return handle.ToPtr(); } //----------------------------------------------------------------------------- template inline Persistent HandleFromPtr(void* pvObject) { return Persistent::FromPtr(pvObject); }