“初始化俯视角工程,带puerts,未编过”

This commit is contained in:
2024-12-01 02:11:25 +08:00
parent 04698dd585
commit 850d76173c
1491 changed files with 271579 additions and 0 deletions
@@ -0,0 +1,424 @@
/*
* 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.
*/
#include "CppObjectMapper.h"
#include "DataTransfer.h"
namespace PUERTS_NAMESPACE
{
template <typename T>
inline void __USE(T&&)
{
}
static void ThrowException(v8::Isolate* Isolate, const char* Message)
{
auto ExceptionStr = v8::String::NewFromUtf8(Isolate, Message, v8::NewStringType::kNormal).ToLocalChecked();
Isolate->ThrowException(v8::Exception::Error(ExceptionStr));
}
void FCppObjectMapper::LoadCppType(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (!Info[0]->IsString())
{
ThrowException(Isolate, "#0 argument expect a string");
return;
}
std::string TypeName = *(v8::String::Utf8Value(Isolate, Info[0]));
auto ClassDef = FindCppTypeClassByName(TypeName);
if (ClassDef)
{
Info.GetReturnValue().Set(GetTemplateOfClass(Isolate, ClassDef)->GetFunction(Context).ToLocalChecked());
}
else
{
const std::string ErrMsg = "can not find type: " + TypeName;
ThrowException(Isolate, ErrMsg.c_str());
}
}
v8::MaybeLocal<v8::Function> FCppObjectMapper::LoadTypeById(v8::Local<v8::Context> Context, const void* TypeId)
{
auto ClassDef = puerts::LoadClassByID(TypeId);
if (!ClassDef)
{
return v8::MaybeLocal<v8::Function>();
}
auto Template = GetTemplateOfClass(Context->GetIsolate(), ClassDef);
return Template->GetFunction(Context);
}
static void PointerNew(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
// do nothing
}
void FCppObjectMapper::Initialize(v8::Isolate* InIsolate, v8::Local<v8::Context> InContext)
{
auto LocalTemplate = v8::FunctionTemplate::New(InIsolate, PointerNew);
LocalTemplate->InstanceTemplate()->SetInternalFieldCount(4); // 0 Ptr, 1, CDataName
PointerTemplate = v8::UniquePersistent<v8::FunctionTemplate>(InIsolate, LocalTemplate);
#ifndef WITH_QUICKJS
PrivateKey.Reset(InIsolate, v8::Symbol::New(InIsolate));
#endif
}
v8::Local<v8::Value> FCppObjectMapper::FindOrAddCppObject(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const void* TypeId, void* Ptr, bool PassByPointer)
{
if (Ptr == nullptr)
{
return v8::Null(Isolate);
}
if (PassByPointer)
{
auto Iter = CDataCache.find(Ptr);
if (Iter != CDataCache.end())
{
auto CacheNodePtr = Iter->second.Find(TypeId);
if (CacheNodePtr)
{
return CacheNodePtr->Value.Get(Isolate);
}
}
}
// create and link
auto ClassDefinition = LoadClassByID(TypeId);
if (ClassDefinition)
{
auto Result = GetTemplateOfClass(Isolate, ClassDefinition)->InstanceTemplate()->NewInstance(Context).ToLocalChecked();
BindCppObject(Isolate, const_cast<JSClassDefinition*>(ClassDefinition), Ptr, Result, PassByPointer);
return Result;
}
else
{
auto Result = PointerTemplate.Get(Isolate)->InstanceTemplate()->NewInstance(Context).ToLocalChecked();
DataTransfer::SetPointer(Isolate, Result, Ptr, 0);
DataTransfer::SetPointer(Isolate, Result, TypeId, 1);
return Result;
}
}
bool FCppObjectMapper::IsInstanceOfCppObject(v8::Isolate* Isolate, const void* TypeId, v8::Local<v8::Object> JsObject)
{
if (DataTransfer::GetPointerFast<const void>(JsObject, 1) == TypeId)
{
return true;
}
auto ClassDefinition = FindClassByID(TypeId);
if (ClassDefinition)
{
auto Template = GetTemplateOfClass(Isolate, ClassDefinition);
return Template->HasInstance(JsObject);
}
return false;
}
std::weak_ptr<int> FCppObjectMapper::GetJsEnvLifeCycleTracker()
{
return std::weak_ptr<int>(Ref);
}
static void CDataNew(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (Info.IsConstructCall())
{
auto Self = Info.This();
JSClassDefinition* ClassDefinition = reinterpret_cast<JSClassDefinition*>(
reinterpret_cast<char*>(v8::Local<v8::External>::Cast(Info.Data())->Value()) - offsetof(JSClassDefinition, Data));
void* Ptr = nullptr;
if (ClassDefinition->Initialize)
Ptr = ClassDefinition->Initialize((pesapi_callback_info) &Info);
if (Ptr == nullptr)
return;
DataTransfer::IsolateData<ICppObjectMapper>(Isolate)->BindCppObject(Isolate, ClassDefinition, Ptr, Self, false);
}
else
{
ThrowException(Isolate, "only call as Construct is supported!");
}
}
MSVC_PRAGMA(warning(push))
MSVC_PRAGMA(warning(disable : 4191))
v8::Local<v8::FunctionTemplate> FCppObjectMapper::GetTemplateOfClass(v8::Isolate* Isolate, const JSClassDefinition* ClassDefinition)
{
auto Iter = TypeIdToTemplateMap.find(ClassDefinition->TypeId);
if (Iter == TypeIdToTemplateMap.end())
{
auto Template = v8::FunctionTemplate::New(
Isolate, CDataNew, v8::External::New(Isolate, &(const_cast<JSClassDefinition*>(ClassDefinition)->Data)));
Template->InstanceTemplate()->SetInternalFieldCount(4);
JSPropertyInfo* PropertyInfo = ClassDefinition->Properties;
while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Getter)
{
v8::PropertyAttribute PropertyAttribute = v8::DontDelete;
if (!PropertyInfo->Setter)
PropertyAttribute = (v8::PropertyAttribute)(PropertyAttribute | v8::ReadOnly);
auto GetterData = v8::External::New(Isolate, &PropertyInfo->GetterData);
auto SetterData = v8::External::New(Isolate, &PropertyInfo->SetterData);
Template->PrototypeTemplate()->SetAccessorProperty(
v8::String::NewFromUtf8(Isolate, PropertyInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
PropertyInfo->Getter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Getter, GetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyInfo->Setter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Setter, SetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyAttribute);
++PropertyInfo;
}
PropertyInfo = ClassDefinition->Variables;
while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Getter)
{
v8::PropertyAttribute PropertyAttribute = v8::DontDelete;
if (!PropertyInfo->Setter)
PropertyAttribute = (v8::PropertyAttribute)(PropertyAttribute | v8::ReadOnly);
auto GetterData = v8::External::New(Isolate, &PropertyInfo->GetterData);
auto SetterData = v8::External::New(Isolate, &PropertyInfo->SetterData);
Template->SetAccessorProperty(
v8::String::NewFromUtf8(Isolate, PropertyInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
PropertyInfo->Getter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Getter, GetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyInfo->Setter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Setter, SetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyAttribute);
++PropertyInfo;
}
JSFunctionInfo* FunctionInfo = ClassDefinition->Methods;
while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback)
{
#ifndef WITH_QUICKJS
auto FastCallInfo = FunctionInfo->ReflectionInfo ? FunctionInfo->ReflectionInfo->FastCallInfo() : nullptr;
if (FastCallInfo)
{
Template->PrototypeTemplate()->Set(
v8::String::NewFromUtf8(Isolate, FunctionInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback,
v8::External::New(Isolate, &FunctionInfo->Data), v8::Local<v8::Signature>(), 0,
v8::ConstructorBehavior::kThrow, v8::SideEffectType::kHasSideEffect, FastCallInfo));
}
else
#endif
{
Template->PrototypeTemplate()->Set(
v8::String::NewFromUtf8(Isolate, FunctionInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(
Isolate, (v8::FunctionCallback) FunctionInfo->Callback, v8::External::New(Isolate, &FunctionInfo->Data)
#ifndef WITH_QUICKJS
,
v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow
#endif
));
}
++FunctionInfo;
}
FunctionInfo = ClassDefinition->Functions;
while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback)
{
#ifndef WITH_QUICKJS
auto FastCallInfo = FunctionInfo->ReflectionInfo ? FunctionInfo->ReflectionInfo->FastCallInfo() : nullptr;
if (FastCallInfo)
{
Template->Set(v8::String::NewFromUtf8(Isolate, FunctionInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback,
v8::External::New(Isolate, &FunctionInfo->Data), v8::Local<v8::Signature>(), 0,
v8::ConstructorBehavior::kThrow, v8::SideEffectType::kHasSideEffect, FastCallInfo));
}
else
#endif
{
Template->Set(v8::String::NewFromUtf8(Isolate, FunctionInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(
Isolate, (v8::FunctionCallback) FunctionInfo->Callback, v8::External::New(Isolate, &FunctionInfo->Data)
#ifndef WITH_QUICKJS
,
v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow
#endif
));
}
++FunctionInfo;
}
if (ClassDefinition->SuperTypeId)
{
if (auto SuperDefinition = LoadClassByID(ClassDefinition->SuperTypeId))
{
Template->Inherit(GetTemplateOfClass(Isolate, SuperDefinition));
}
}
TypeIdToTemplateMap[ClassDefinition->TypeId] = v8::UniquePersistent<v8::FunctionTemplate>(Isolate, Template);
return Template;
}
else
{
return v8::Local<v8::FunctionTemplate>::New(Isolate, Iter->second);
}
}
MSVC_PRAGMA(warning(pop))
static void CDataGarbageCollectedWithFree(const v8::WeakCallbackInfo<JSClassDefinition>& Data)
{
JSClassDefinition* ClassDefinition = Data.GetParameter();
void* Ptr = DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1));
if (ClassDefinition->Finalize)
ClassDefinition->Finalize(Ptr, ClassDefinition->Data, DataTransfer::GetIsolatePrivateData(Data.GetIsolate()));
DataTransfer::IsolateData<ICppObjectMapper>(Data.GetIsolate())->UnBindCppObject(Data.GetIsolate(), ClassDefinition, Ptr);
}
static void CDataGarbageCollectedWithoutFree(const v8::WeakCallbackInfo<JSClassDefinition>& Data)
{
JSClassDefinition* ClassDefinition = Data.GetParameter();
void* Ptr = DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1));
DataTransfer::IsolateData<ICppObjectMapper>(Data.GetIsolate())->UnBindCppObject(Data.GetIsolate(), ClassDefinition, Ptr);
}
void FCppObjectMapper::BindCppObject(
v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr, v8::Local<v8::Object> JSObject, bool PassByPointer)
{
DataTransfer::SetPointer(Isolate, JSObject, Ptr, 0);
DataTransfer::SetPointer(Isolate, JSObject, ClassDefinition->TypeId, 1);
auto Iter = CDataCache.find(Ptr);
FObjectCacheNode* CacheNodePtr;
if (Iter != CDataCache.end())
{
CacheNodePtr = Iter->second.Add(ClassDefinition->TypeId);
}
else
{
auto Ret = CDataCache.insert({Ptr, FObjectCacheNode(ClassDefinition->TypeId)});
CacheNodePtr = &Ret.first->second;
}
CacheNodePtr->Value.Reset(Isolate, JSObject);
if (!PassByPointer)
{
CacheNodePtr->MustCallFinalize = true;
CacheNodePtr->Value.SetWeak<JSClassDefinition>(
ClassDefinition, CDataGarbageCollectedWithFree, v8::WeakCallbackType::kInternalFields);
}
else
{
CacheNodePtr->Value.SetWeak<JSClassDefinition>(
ClassDefinition, CDataGarbageCollectedWithoutFree, v8::WeakCallbackType::kInternalFields);
}
if (ClassDefinition->OnEnter)
{
CacheNodePtr->UserData = ClassDefinition->OnEnter(Ptr, ClassDefinition->Data, DataTransfer::GetIsolatePrivateData(Isolate));
}
}
#define QJS_PRIVATE_KEY_STR "__,kp@"
void* FCppObjectMapper::GetPrivateData(v8::Local<v8::Context> Context, v8::Local<v8::Object> JSObject)
{
#ifndef WITH_QUICKJS
auto Key = PrivateKey.Get(Context->GetIsolate());
#else
auto Key = FV8Utils::InternalString(Context->GetIsolate(), QJS_PRIVATE_KEY_STR);
#endif
v8::MaybeLocal<v8::Value> maybeValue = JSObject->Get(Context, Key);
if (maybeValue.IsEmpty())
{
return nullptr;
}
v8::Local<v8::Value> maybeExternal = maybeValue.ToLocalChecked();
if (!maybeExternal->IsExternal())
{
return nullptr;
}
return v8::Local<v8::External>::Cast(maybeExternal)->Value();
}
void FCppObjectMapper::SetPrivateData(v8::Local<v8::Context> Context, v8::Local<v8::Object> JSObject, void* Ptr)
{
#ifndef WITH_QUICKJS
auto Key = PrivateKey.Get(Context->GetIsolate());
#else
auto Key = FV8Utils::InternalString(Context->GetIsolate(), QJS_PRIVATE_KEY_STR);
#endif
(void) (JSObject->Set(Context, Key, v8::External::New(Context->GetIsolate(), Ptr)));
}
void FCppObjectMapper::UnBindCppObject(v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr)
{
auto Iter = CDataCache.find(Ptr);
if (Iter != CDataCache.end())
{
if (ClassDefinition->OnExit)
{
ClassDefinition->OnExit(
Ptr, ClassDefinition->Data, DataTransfer::GetIsolatePrivateData(Isolate), Iter->second.UserData);
}
auto Removed = Iter->second.Remove(ClassDefinition->TypeId, true);
if (!Iter->second.TypeId) // last one
{
CDataCache.erase(Ptr);
}
}
}
void FCppObjectMapper::UnInitialize(v8::Isolate* InIsolate)
{
auto PData = DataTransfer::GetIsolatePrivateData(InIsolate);
for (auto& KV : CDataCache)
{
FObjectCacheNode* PNode = &KV.second;
while (PNode)
{
const JSClassDefinition* ClassDefinition = FindClassByID(PNode->TypeId);
if (PNode->MustCallFinalize)
{
if (ClassDefinition && ClassDefinition->Finalize)
{
ClassDefinition->Finalize(KV.first, ClassDefinition->Data, PData);
}
PNode->MustCallFinalize = false;
}
if (ClassDefinition->OnExit)
{
ClassDefinition->OnExit(
KV.first, ClassDefinition->Data, DataTransfer::GetIsolatePrivateData(InIsolate), PNode->UserData);
}
PNode = PNode->Next;
}
}
CDataCache.clear();
TypeIdToTemplateMap.clear();
#ifndef WITH_QUICKJS
PrivateKey.Reset();
#endif
PointerTemplate.Reset();
}
} // namespace PUERTS_NAMESPACE