// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
#pragma once
//-----------------------------------------------------------------------------
// V8BigInt
//-----------------------------------------------------------------------------
class V8BigInt final
{
public:
V8BigInt(int signBit, std::vector&& words):
m_SignBit(signBit),
m_Words(std::move(words))
{
}
V8BigInt(const V8BigInt& that):
m_SignBit(that.m_SignBit),
m_Words(that.m_Words)
{
}
V8BigInt(V8BigInt&& that) noexcept:
m_SignBit(that.m_SignBit),
m_Words(std::move(that.m_Words))
{
}
const V8BigInt& operator=(const V8BigInt& that)
{
if (&that != this)
{
m_SignBit = that.m_SignBit;
m_Words = that.m_Words;
}
return *this;
}
const V8BigInt& operator=(V8BigInt&& that) noexcept
{
if (&that != this)
{
m_SignBit = that.m_SignBit;
m_Words = std::move(that.m_Words);
}
return *this;
}
int GetSignBit() const
{
return m_SignBit;
}
const std::vector& GetWords() const
{
return m_Words;
}
private:
int m_SignBit;
std::vector m_Words;
};
//-----------------------------------------------------------------------------
// V8Value
//-----------------------------------------------------------------------------
class V8Value
{
public:
enum NonexistentInitializer
{
Nonexistent
};
enum UndefinedInitializer
{
Undefined
};
enum NullInitializer
{
Null
};
enum DateTimeInitializer
{
DateTime
};
enum class Type: uint8_t
{
// IMPORTANT: maintain bitwise equivalence with managed enum V8.SplitProxy.V8Value.Type
Nonexistent,
Undefined,
Null,
Boolean,
Number,
String,
DateTime,
BigInt,
V8Object,
HostObject
};
enum class Subtype: uint8_t
{
// IMPORTANT: maintain bitwise equivalence with managed enum V8.SplitProxy.V8Value.Subtype
None,
Function,
Iterator,
Promise,
Array,
ArrayBuffer,
DataView,
Uint8Array,
Uint8ClampedArray,
Int8Array,
Uint16Array,
Int16Array,
Uint32Array,
Int32Array,
BigUint64Array,
BigInt64Array,
Float32Array,
Float64Array
};
enum class Flags : uint16_t
{
// IMPORTANT: maintain bitwise equivalence with managed enum V8.SplitProxy.V8Value.Flags
None = 0,
Shared = 0x0001,
Fast = 0x0001,
Async = 0x0002,
Generator = 0x0004,
Pending = 0x0008,
Rejected = 0x0010,
Iterable = 0x0020,
AsyncIterable = 0x0040,
Disposable = 0x0080,
AsyncDisposable = 0x0100
};
struct WireData;
struct Decoded;
struct FastArg;
struct FastResult;
struct FastScriptArg;
struct FastScriptResult;
explicit V8Value(NonexistentInitializer):
m_Type(Type::Nonexistent)
{
}
explicit V8Value(UndefinedInitializer):
m_Type(Type::Undefined)
{
}
explicit V8Value(NullInitializer):
m_Type(Type::Null)
{
}
explicit V8Value(bool value):
m_Type(Type::Boolean)
{
m_Data.BooleanValue = value;
}
explicit V8Value(double value):
m_Type(Type::Number)
{
m_Data.DoubleValue = value;
}
explicit V8Value(const StdString* pString):
m_Type(Type::String)
{
m_Data.pString = pString;
}
V8Value(DateTimeInitializer, double value):
m_Type(Type::DateTime)
{
m_Data.DoubleValue = value;
}
explicit V8Value(const V8BigInt* pBigInt):
m_Type(Type::BigInt)
{
m_Data.pBigInt = pBigInt;
}
V8Value(V8ObjectHolder* pV8ObjectHolder, Subtype subtype, Flags flags):
m_Type(Type::V8Object),
m_Subtype(subtype),
m_Flags(flags)
{
m_Data.pV8ObjectHolder = pV8ObjectHolder;
}
explicit V8Value(HostObjectHolder* pHostObjectHolder):
m_Type(Type::HostObject),
m_Subtype(::ToEnum(pHostObjectHolder->GetSubtype())),
m_Flags(::ToEnum(pHostObjectHolder->GetFlags()))
{
m_Data.pHostObjectHolder = pHostObjectHolder;
}
V8Value(const V8Value& that)
{
Copy(that);
}
V8Value(V8Value&& that) noexcept
{
Move(that);
}
explicit V8Value(const FastResult& result)
{
InitializeFromFastResult(result);
}
explicit V8Value(void*) = delete;
const V8Value& operator=(const V8Value& that)
{
Dispose();
Copy(that);
return *this;
}
const V8Value& operator=(V8Value&& that) noexcept
{
Dispose();
Move(that);
return *this;
}
bool IsNonexistent() const
{
return m_Type == Type::Nonexistent;
}
bool IsUndefined() const
{
return m_Type == Type::Undefined;
}
bool IsNull() const
{
return m_Type == Type::Null;
}
bool AsBoolean(bool& result) const
{
if (m_Type == Type::Boolean)
{
result = m_Data.BooleanValue;
return true;
}
return false;
}
bool AsNumber(double& result) const
{
if (m_Type == Type::Number)
{
result = m_Data.DoubleValue;
return true;
}
return false;
}
bool AsString(const StdString*& pString) const
{
if (m_Type == Type::String)
{
pString = m_Data.pString;
return true;
}
return false;
}
bool AsDateTime(double& result) const
{
if (m_Type == Type::DateTime)
{
result = m_Data.DoubleValue;
return true;
}
return false;
}
bool AsBigInt(const V8BigInt*& pBigInt) const
{
if (m_Type == Type::BigInt)
{
pBigInt = m_Data.pBigInt;
return true;
}
return false;
}
bool AsV8Object(V8ObjectHolder*& pV8ObjectHolder, Subtype& subtype, Flags& flags) const
{
if (m_Type == Type::V8Object)
{
pV8ObjectHolder = m_Data.pV8ObjectHolder;
subtype = m_Subtype;
flags = m_Flags;
return true;
}
return false;
}
bool AsHostObject(HostObjectHolder*& pHostObjectHolder, Subtype& subtype, Flags& flags) const
{
if (m_Type == Type::HostObject)
{
pHostObjectHolder = m_Data.pHostObjectHolder;
subtype = m_Subtype;
flags = m_Flags;
return true;
}
return false;
}
Type GetType() const
{
return m_Type;
}
void Decode(Decoded& decoded) const;
~V8Value()
{
Dispose();
}
private:
union Data
{
bool BooleanValue;
double DoubleValue;
const StdString* pString;
V8ObjectHolder* pV8ObjectHolder;
HostObjectHolder* pHostObjectHolder;
const V8BigInt* pBigInt;
};
void Copy(const V8Value& that)
{
m_Type = that.m_Type;
m_Subtype = that.m_Subtype;
m_Flags = that.m_Flags;
if (m_Type == Type::Boolean)
{
m_Data.BooleanValue = that.m_Data.BooleanValue;
}
else if (m_Type == Type::Number)
{
m_Data.DoubleValue = that.m_Data.DoubleValue;
}
else if (m_Type == Type::String)
{
m_Data.pString = new StdString(*that.m_Data.pString);
}
else if (m_Type == Type::DateTime)
{
m_Data.DoubleValue = that.m_Data.DoubleValue;
}
else if (m_Type == Type::BigInt)
{
m_Data.pBigInt = new V8BigInt(*that.m_Data.pBigInt);
}
else if (m_Type == Type::V8Object)
{
m_Data.pV8ObjectHolder = that.m_Data.pV8ObjectHolder->Clone();
}
else if (m_Type == Type::HostObject)
{
m_Data.pHostObjectHolder = that.m_Data.pHostObjectHolder->Clone();
}
}
void Move(V8Value& that)
{
m_Type = that.m_Type;
m_Subtype = that.m_Subtype;
m_Flags = that.m_Flags;
m_Data = that.m_Data;
that.m_Type = Type::Nonexistent;
}
void InitializeFromFastResult(const FastResult& result);
void Dispose()
{
if (m_Type == Type::String)
{
delete m_Data.pString;
}
else if (m_Type == Type::BigInt)
{
delete m_Data.pBigInt;
}
else if (m_Type == Type::V8Object)
{
delete m_Data.pV8ObjectHolder;
}
else if (m_Type == Type::HostObject)
{
delete m_Data.pHostObjectHolder;
}
}
Type m_Type;
Subtype m_Subtype;
Flags m_Flags;
int32_t m_Padding;
Data m_Data;
};
static_assert(sizeof(V8Value) == 16, "The managed SplitProxy code assumes that sizeof(V8Value) is 16 on all platforms.");
//-----------------------------------------------------------------------------
// DefaultInitializedV8Value
//-----------------------------------------------------------------------------
template
class DefaultInitializedV8Value final: public V8Value
{
public:
using V8Value::V8Value;
DefaultInitializedV8Value():
V8Value(ms_Initializer)
{
static_assert(sizeof(DefaultInitializedV8Value) == sizeof(V8Value));
}
using V8Value::operator=;
private:
static const TInitializer ms_Initializer {};
};
using NonexistentV8Value = DefaultInitializedV8Value;
using UndefinedV8Value = DefaultInitializedV8Value;
using NullV8Value = DefaultInitializedV8Value;