Files
MingSimulator/Plugins/Puerts/Source/JsEnv/Public/V8Backend.hpp
T
starmen1265 ed21658256 从master分支拉取puerts,并拉取v8制品,修改puerts插件部分UE5_5以下兼容的宏代码。保证puerts编译通过。包括
CSharpParamDefaultValueMetas.cs和ubtplugin.csproj和declarationGenerator.cpp和PropertyTranslator.cpp对UserDefinedStruct.h的引用
2024-12-02 01:03:52 +08:00

670 lines
26 KiB
C++

/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <type_traits>
#include <string>
#include <functional>
#include "DataTransfer.h"
#include "JSClassRegister.h"
#define __DefObjectType_v8_impl(CLS) \
namespace PUERTS_NAMESPACE \
{ \
template <> \
struct is_objecttype<CLS> : public std::true_type \
{ \
}; \
}
#define __DefCDataPointerConverter_v8_impl(CLS) \
namespace PUERTS_NAMESPACE \
{ \
namespace v8_impl \
{ \
template <> \
struct Converter<CLS*> \
{ \
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, CLS* value) \
{ \
return ::PUERTS_NAMESPACE::DataTransfer::FindOrAddCData( \
context->GetIsolate(), context, DynamicTypeId<CLS>::get(value), value, true); \
} \
static CLS* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value) \
{ \
return ::PUERTS_NAMESPACE::DataTransfer::GetPointerFast<CLS>(value.As<v8::Object>()); \
} \
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value) \
{ \
return ::PUERTS_NAMESPACE::DataTransfer::IsInstanceOf( \
context->GetIsolate(), StaticTypeId<CLS>::get(), value.As<v8::Object>()); \
} \
}; \
} \
}
#define __DefCDataConverter_v8_impl(CLS) \
namespace PUERTS_NAMESPACE \
{ \
namespace v8_impl \
{ \
template <> \
struct Converter<CLS> \
{ \
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, CLS value) \
{ \
return ::PUERTS_NAMESPACE::DataTransfer::FindOrAddCData( \
context->GetIsolate(), context, DynamicTypeId<CLS>::get(&value), new CLS(value), false); \
} \
static CLS toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value) \
{ \
return *::PUERTS_NAMESPACE::DataTransfer::GetPointerFast<CLS>(value.As<v8::Object>()); \
} \
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value) \
{ \
return ::PUERTS_NAMESPACE::DataTransfer::IsInstanceOf( \
context->GetIsolate(), StaticTypeId<CLS>::get(), value.As<v8::Object>()); \
} \
}; \
} \
}
namespace PUERTS_NAMESPACE
{
namespace v8_impl
{
template <typename T, typename Enable = void>
struct Converter;
template <typename T, typename = void>
struct CustomArgumentBufferType
{
static constexpr bool enable = false;
};
struct API
{
typedef const v8::FunctionCallbackInfo<v8::Value>& CallbackInfoType;
typedef v8::Local<v8::Context> ContextType;
typedef v8::Local<v8::Value> ValueType;
typedef v8::FunctionCallback FunctionCallbackType;
typedef void* (*InitializeFuncType)(const v8::FunctionCallbackInfo<v8::Value>& Info);
typedef void (*FinalizeFuncType)(void* Ptr, void* ClassData, void* EnvData);
typedef JSFunctionInfo GeneralFunctionInfo;
typedef JSPropertyInfo GeneralPropertyInfo;
typedef NamedFunctionInfo GeneralFunctionReflectionInfo;
typedef NamedPropertyInfo GeneralPropertyReflectionInfo;
V8_INLINE static int GetArgsLen(const v8::FunctionCallbackInfo<v8::Value>& info)
{
return info.Length();
}
V8_INLINE static v8::Local<v8::Value> GetArg(const v8::FunctionCallbackInfo<v8::Value>& info, int index)
{
return info[index];
}
V8_INLINE static v8::Local<v8::Context> GetContext(const v8::FunctionCallbackInfo<v8::Value>& info)
{
return info.GetIsolate()->GetCurrentContext();
}
V8_INLINE static v8::Local<v8::Object> GetThis(const v8::FunctionCallbackInfo<v8::Value>& info)
{
return info.This();
}
V8_INLINE static v8::Local<v8::Object> GetHolder(const v8::FunctionCallbackInfo<v8::Value>& info)
{
return info.Holder();
}
// use where GetSelfFromData is true
V8_INLINE static void* GetFunctionData(const v8::FunctionCallbackInfo<v8::Value>& info)
{
return v8::Local<v8::External>::Cast(info.Data())->Value();
}
V8_INLINE static void ThrowException(const v8::FunctionCallbackInfo<v8::Value>& info, const char* msg)
{
v8::Isolate* isolate = info.GetIsolate();
isolate->ThrowException(
v8::Exception::Error(v8::String::NewFromUtf8(isolate, msg, v8::NewStringType::kNormal).ToLocalChecked()));
}
V8_INLINE static void SetReturn(const v8::FunctionCallbackInfo<v8::Value>& info, v8::Local<v8::Value> value)
{
info.GetReturnValue().Set(value);
}
template <typename T1, typename T2>
V8_INLINE static void LinkOuter(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
{
LinkOuterImpl(Context, Outer, Inner);
}
V8_INLINE static void UpdateRefValue(v8::Local<v8::Context> context, v8::Local<v8::Value> holder, v8::Local<v8::Value> value)
{
if (holder->IsObject())
{
auto outer = holder->ToObject(context).ToLocalChecked();
(void) (outer->Set(context, 0, value));
}
}
template <typename T>
V8_INLINE static T* FastGetNativeObjectPointer(v8::Local<v8::Context> context, v8::Local<v8::Object> Object)
{
return DataTransfer::GetPointerFast<T>(Object);
}
V8_INLINE static v8::Local<v8::Value> GetUndefined(v8::Local<v8::Context> context)
{
return v8::Undefined(context->GetIsolate());
}
V8_INLINE static bool IsNullOrUndefined(v8::Local<v8::Context> context, v8::Local<v8::Value> val)
{
return val->IsNullOrUndefined();
}
template <typename T, typename CDB>
static void Register(FinalizeFuncType Finalize, const CDB& Cdb)
{
const bool isUEType = is_uetype<T>::value;
static std::vector<JSFunctionInfo> s_functions_{};
static std::vector<JSFunctionInfo> s_methods_{};
static std::vector<JSPropertyInfo> s_properties_{};
static std::vector<JSPropertyInfo> s_variables_{};
static std::vector<NamedFunctionInfo> s_constructorInfos_{};
static std::vector<NamedFunctionInfo> s_methodInfos_{};
static std::vector<NamedFunctionInfo> s_functionInfos_{};
static std::vector<NamedPropertyInfo> s_propertyInfos_{};
static std::vector<NamedPropertyInfo> s_variableInfos_{};
JSClassDefinition ClassDef = JSClassEmptyDefinition;
if (isUEType)
{
ClassDef.UETypeName = Cdb.className_;
}
else
{
ClassDef.ScriptName = Cdb.className_;
ClassDef.TypeId = StaticTypeId<T>::get();
ClassDef.SuperTypeId = Cdb.superTypeId_;
}
ClassDef.SetInitialize(Cdb.constructor_);
ClassDef.Finalize = Finalize;
s_functions_ = std::move(Cdb.functions_);
s_functions_.push_back(JSFunctionInfo());
ClassDef.Functions = s_functions_.data();
s_methods_ = std::move(Cdb.methods_);
s_methods_.push_back(JSFunctionInfo());
ClassDef.Methods = s_methods_.data();
s_properties_ = std::move(Cdb.properties_);
s_properties_.push_back(JSPropertyInfo());
ClassDef.Properties = s_properties_.data();
s_variables_ = std::move(Cdb.variables_);
s_variables_.push_back(JSPropertyInfo());
ClassDef.Variables = s_variables_.data();
s_constructorInfos_ = std::move(Cdb.constructorInfos_);
s_constructorInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
ClassDef.ConstructorInfos = s_constructorInfos_.data();
s_methodInfos_ = std::move(Cdb.methodInfos_);
s_methodInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
ClassDef.MethodInfos = s_methodInfos_.data();
s_functionInfos_ = std::move(Cdb.functionInfos_);
s_functionInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
ClassDef.FunctionInfos = s_functionInfos_.data();
s_propertyInfos_ = std::move(Cdb.propertyInfos_);
s_propertyInfos_.push_back(NamedPropertyInfo{nullptr, nullptr});
ClassDef.PropertyInfos = s_propertyInfos_.data();
s_variableInfos_ = std::move(Cdb.variableInfos_);
s_variableInfos_.push_back(NamedPropertyInfo{nullptr, nullptr});
ClassDef.VariableInfos = s_variableInfos_.data();
RegisterJSClass(ClassDef);
}
template <typename T>
using Converter = Converter<T>;
template <typename T>
using CustomArgumentBufferType = CustomArgumentBufferType<T>;
};
class StringHolder
{
public:
StringHolder(v8::Local<v8::Context> context, const v8::Local<v8::Value> value)
{
needFree = false;
if (value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
auto Ab = BuffView->Buffer();
data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
}
else if (value->IsArrayBuffer())
{
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab));
}
else
{
if (value.IsEmpty())
return;
const auto isolate = context->GetIsolate();
v8::TryCatch try_catch(isolate);
v8::Local<v8::String> str;
if (!value->ToString(context).ToLocal(&str))
return;
const int length = str->Utf8Length(isolate);
data = new char[length + 1];
str->WriteUtf8(isolate, data);
needFree = true;
}
}
~StringHolder()
{
if (needFree && data)
{
delete[] data;
}
}
const char* Data() const
{
return data;
}
// Disallow copying and assigning.
StringHolder(const StringHolder&) = delete;
void operator=(const StringHolder&) = delete;
private:
char* data;
bool needFree;
};
template <>
struct CustomArgumentBufferType<const char*>
{
using type = StringHolder;
static constexpr bool enable = true;
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 8 && std::is_signed<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::BigInt::New(context->GetIsolate(), value);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsBigInt() ? static_cast<T>(value->ToBigInt(context).ToLocalChecked()->Int64Value()) : 0;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsBigInt();
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 8 && !std::is_signed<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::BigInt::NewFromUnsigned(context->GetIsolate(), value);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsBigInt() ? static_cast<T>(value->ToBigInt(context).ToLocalChecked()->Uint64Value()) : 0;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsBigInt();
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) < 8 && std::is_signed<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::Integer::New(context->GetIsolate(), value);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return static_cast<T>(value->Int32Value(context).ToChecked());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsInt32();
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) < 8 && !std::is_signed<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::Integer::NewFromUnsigned(context->GetIsolate(), value);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return static_cast<T>(value->Uint32Value(context).ToChecked());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsUint32();
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::Integer::New(context->GetIsolate(), static_cast<int>(value));
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return static_cast<T>(value->Int32Value(context).ToChecked());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsInt32();
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::Number::New(context->GetIsolate(), value);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return static_cast<T>(value->NumberValue(context).ToChecked());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsNumber();
}
};
template <>
struct Converter<std::string>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, std::string value)
{
return v8::String::NewFromUtf8(context->GetIsolate(), value.c_str(), v8::NewStringType::kNormal).ToLocalChecked();
}
static std::string toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return *v8::String::Utf8Value(context->GetIsolate(), value);
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsString();
}
};
template <>
struct Converter<const char*>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const char* value)
{
return v8::String::NewFromUtf8(context->GetIsolate(), value, v8::NewStringType::kNormal).ToLocalChecked();
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsString();
}
};
template <>
struct Converter<void*>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, void* value)
{
return DataTransfer::NewArrayBuffer(context, value, 0);
}
static void* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
auto Ab = BuffView->Buffer();
return static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
}
if (value->IsArrayBuffer())
{
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
return DataTransfer::GetArrayBufferData(Ab);
}
if (value->IsObject())
{
return DataTransfer::GetPointerFast<void>(value.As<v8::Object>());
}
return nullptr;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsArrayBuffer() || value->IsArrayBufferView();
}
};
template <>
struct Converter<bool>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, bool value)
{
return v8::Boolean::New(context->GetIsolate(), value);
}
static bool toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->BooleanValue(context->GetIsolate());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsBoolean();
}
};
template <typename T>
struct Converter<std::reference_wrapper<T>, typename std::enable_if<!is_objecttype<T>::value && !is_uetype<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const T& value)
{
auto result = v8::Object::New(context->GetIsolate());
auto _unused = result->Set(context, 0, Converter<T>::toScript(context, value));
return result;
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (value->IsObject())
{
auto outer = value->ToObject(context).ToLocalChecked();
auto realvalue = outer->Get(context, 0).ToLocalChecked();
return Converter<T>::toCpp(context, realvalue);
}
return {};
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsObject(); // do not checked inner
}
};
template <typename T>
struct Converter<std::reference_wrapper<T>, typename std::enable_if<is_objecttype<T>::value || is_uetype<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const T& value)
{
auto result = v8::Object::New(context->GetIsolate());
auto _unused = result->Set(context, 0, Converter<T>::toScript(context, value));
return result;
}
static T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (!value.IsEmpty() && value->IsObject())
{
auto outer = value->ToObject(context).ToLocalChecked();
auto realvalue = outer->Get(context, 0).ToLocalChecked();
return Converter<typename std::decay<T>::type*>::toCpp(context, realvalue);
}
return nullptr;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsObject(); // do not checked inner
}
};
template <typename T>
struct Converter<T,
typename std::enable_if<is_script_type<typename std::remove_pointer<T>::type>::value && !std::is_array<T>::value &&
!std::is_const<typename std::remove_pointer<T>::type>::value && std::is_pointer<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return DataTransfer::NewArrayBuffer(context, value, 0);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
auto Ab = BuffView->Buffer();
return reinterpret_cast<T>(static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset());
}
if (value->IsArrayBuffer())
{
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
return static_cast<T>(DataTransfer::GetArrayBufferData(Ab));
}
return nullptr;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsArrayBuffer() || value->IsArrayBufferView();
}
};
template <typename T, std::size_t Size>
struct Converter<T[Size], typename std::enable_if<is_script_type<T>::value && !std::is_const<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value[Size])
{
return DataTransfer::NewArrayBuffer(context, &(value[0]), sizeof(T) * Size);
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> buffView = value.As<v8::ArrayBufferView>();
return buffView->ByteLength() >= sizeof(T) * Size;
}
if (value->IsArrayBuffer())
{
auto ab = v8::Local<v8::ArrayBuffer>::Cast(value);
size_t byteLength;
(void) (DataTransfer::GetArrayBufferData(ab, byteLength));
return byteLength >= sizeof(T) * Size;
}
return false;
}
};
template <class T>
struct Converter<T, typename std::enable_if<std::is_copy_constructible<T>::value && std::is_constructible<T>::value &&
is_objecttype<T>::value && !is_uetype<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return DataTransfer::FindOrAddCData(context->GetIsolate(), context, DynamicTypeId<T>::get(&value), new T(value), false);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
T* ptr = DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
return ptr ? *ptr : T{};
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return DataTransfer::IsInstanceOf(context->GetIsolate(), StaticTypeId<T>::get(), value.As<v8::Object>());
}
};
template <class T>
struct Converter<const T*,
typename std::enable_if<(is_objecttype<T>::value || std::is_same<T, void>::value || is_script_type<T>::value) &&
!is_uetype<T>::value && !std::is_same<T, char>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const T* value)
{
return Converter<T*>::toScript(context, const_cast<T*>(value));
}
static const T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return Converter<T*>::toCpp(context, value);
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return Converter<T*>::accept(context, value);
}
};
} // namespace v8_impl
} // namespace PUERTS_NAMESPACE