// 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);
}