From ee406de67922dba7c0fb7d2a63bb9df3f8c8cf15 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 24 Jan 2025 15:23:56 +0800 Subject: [PATCH 01/70] =?UTF-8?q?=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 1 + include/JSClassRegister.h | 176 ++++++ include/PString.h | 227 ++++++++ include/TypeInfo.hpp | 536 +++++++++++++++++++ include/pesapi.h | 359 +++++++++++++ source/PapiQuickjsImpl.cpp | 1032 +++++++++++++++++++++++++++++++++++- 6 files changed, 2330 insertions(+), 1 deletion(-) create mode 100644 include/JSClassRegister.h create mode 100644 include/PString.h create mode 100644 include/TypeInfo.hpp create mode 100644 include/pesapi.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a732bbf..12f816f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,7 @@ add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_SCL_SECURE_NO_WARNINGS) add_definitions(-DEASTL_OPENSOURCE=1) +include_directories(include quickjs) include_directories(EASTL/include) file(GLOB eastl_sources "EASTL/source/*.cpp") diff --git a/include/JSClassRegister.h b/include/JSClassRegister.h new file mode 100644 index 0000000..9d1ab06 --- /dev/null +++ b/include/JSClassRegister.h @@ -0,0 +1,176 @@ +/* + * 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 "functional" + +#if USING_IN_UNREAL_ENGINE +#include "CoreMinimal.h" + +PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS +#pragma warning(push, 0) +#include "v8.h" +#pragma warning(pop) +PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS +#else +#define JSENV_API +#define FORCEINLINE V8_INLINE +#define UPTRINT uintptr_t +#endif + +#include + +#include "PuertsNamespaceDef.h" + +#include "pesapi.h" +#include "TypeInfo.hpp" +#include "PString.h" + +#if USING_IN_UNREAL_ENGINE +static const FAnsiStringView EditorOnlyPropertySuffix = "_EditorOnly"; +#endif + +namespace PUERTS_NAMESPACE +{ +class CFunctionInfo; + +MSVC_PRAGMA(warning(push)) +MSVC_PRAGMA(warning(disable : 4191)) +struct JSENV_API JSFunctionInfo +{ + JSFunctionInfo() : Name(nullptr), Callback(nullptr) + { + } + + JSFunctionInfo( + const char* InName, pesapi_callback InCallback, void* InData = nullptr, const CFunctionInfo* InReflectionInfo = nullptr) + : Name(InName), Callback(InCallback), Data(InData), ReflectionInfo(InReflectionInfo) + { + } + + template + JSFunctionInfo( + const char* InName, CallbackType InCallback, void* InData = nullptr, const CFunctionInfo* InReflectionInfo = nullptr) + : Name(InName), Callback(reinterpret_cast(InCallback)), Data(InData), ReflectionInfo(InReflectionInfo) + { + } + + const char* Name; + pesapi_callback Callback; + void* Data = nullptr; + const CFunctionInfo* ReflectionInfo = nullptr; +}; + +struct JSENV_API JSPropertyInfo +{ + JSPropertyInfo() : Name(nullptr), Getter(nullptr), Setter(nullptr) + { + } + + JSPropertyInfo(const char* InName, pesapi_callback InGetter, pesapi_callback InSetter, void* InGetterData = nullptr, + void* InSetterData = nullptr) + : Name(InName), Getter(InGetter), Setter(InSetter), GetterData(InGetterData), SetterData(InSetterData) + { + } + + template + JSPropertyInfo(const char* InName, CallbackType InGetter, CallbackType InSetter, void* InGetterData = nullptr, + void* InSetterData = nullptr) + : Name(InName) + , Getter(reinterpret_cast(InGetter)) + , Setter(reinterpret_cast(InSetter)) + , GetterData(InGetterData) + , SetterData(InSetterData) + { + } + + const char* Name; + pesapi_callback Getter; + pesapi_callback Setter; + void* GetterData = nullptr; + void* SetterData = nullptr; +}; + +struct NamedFunctionInfo; +struct NamedPropertyInfo; + +struct JSENV_API JSClassDefinition +{ + const void* TypeId; + const void* SuperTypeId; + const char* ScriptName; + const char* UETypeName; + pesapi_constructor Initialize; + template + void SetInitialize(InitializeType InInitialize) + { + Initialize = reinterpret_cast(InInitialize); + } + JSFunctionInfo* Methods; //成员方法 + JSFunctionInfo* Functions; //静态方法 + JSPropertyInfo* Properties; //成员属性 + JSPropertyInfo* Variables; //静态属性 + pesapi_finalize Finalize; + // int InternalFieldCount; + NamedFunctionInfo* ConstructorInfos; + NamedFunctionInfo* MethodInfos; + NamedFunctionInfo* FunctionInfos; + NamedPropertyInfo* PropertyInfos; + NamedPropertyInfo* VariableInfos; + void* Data = nullptr; + pesapi_on_native_object_enter OnEnter = nullptr; + pesapi_on_native_object_exit OnExit = nullptr; +}; +MSVC_PRAGMA(warning(pop)) + +#define JSClassEmptyDefinition \ + { \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ + } + +void JSENV_API RegisterJSClass(const JSClassDefinition& ClassDefinition); + +void JSENV_API SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos, + const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, const NamedPropertyInfo* VariableInfos); + +void JSENV_API ForeachRegisterClass(std::function); + +JSENV_API const JSClassDefinition* FindClassByID(const void* TypeId); + +JSENV_API void OnClassNotFound(pesapi_class_not_found_callback Callback); + +JSENV_API const JSClassDefinition* LoadClassByID(const void* TypeId); + +JSENV_API const JSClassDefinition* FindCppTypeClassByName(const PString& Name); + +JSENV_API bool TraceObjectLifecycle(const void* TypeId, pesapi_on_native_object_enter OnEnter, pesapi_on_native_object_exit OnExit); + +#if USING_IN_UNREAL_ENGINE +typedef void (*AddonRegisterFunc)(v8::Local Context, v8::Local Exports); + +AddonRegisterFunc FindAddonRegisterFunc(const PString& Name); + +void RegisterAddon(const char* Name, AddonRegisterFunc RegisterFunc); + +JSENV_API const JSClassDefinition* FindClassByType(UStruct* Type); + +JSENV_API bool IsEditorOnlyUFunction(const UFunction* Func); + +#endif + +} // namespace PUERTS_NAMESPACE + +#define PUERTS_MODULE(Name, RegFunc) \ + static struct FAutoRegisterFor##Name \ + { \ + FAutoRegisterFor##Name() \ + { \ + PUERTS_NAMESPACE::RegisterAddon(#Name, (RegFunc)); \ + } \ + } _AutoRegisterFor##Name diff --git a/include/PString.h b/include/PString.h new file mode 100644 index 0000000..3ebd183 --- /dev/null +++ b/include/PString.h @@ -0,0 +1,227 @@ +/* + * 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 +#include +#include "NamespaceDef.h" + +namespace PUERTS_NAMESPACE +{ +class PString +{ +public: + // Constructors + PString() : data_(nullptr), size_(0) + { + data_ = new char[1]; + data_[0] = '\0'; + } + + PString(const char* str) + { + if (str) + { + size_ = std::strlen(str); + data_ = new char[size_ + 1]; +#ifdef _MSC_VER + strncpy_s(data_, size_ + 1, str, size_); +#else + strncpy(data_, str, size_); +#endif + data_[size_] = '\0'; + } + else + { + size_ = 0; + data_ = new char[1]; + data_[0] = '\0'; + } + } + + PString(const char* str, size_t length) + { + if (str) + { + size_ = length; + data_ = new char[size_ + 1]; +#ifdef _MSC_VER + strncpy_s(data_, size_ + 1, str, length); +#else + strncpy(data_, str, length); +#endif + data_[size_] = '\0'; + } + else + { + size_ = 0; + data_ = new char[1]; + data_[0] = '\0'; + } + } + + PString(const PString& other) + { + size_ = other.size_; + data_ = new char[size_ + 1]; +#ifdef _MSC_VER + strncpy_s(data_, size_ + 1, other.data_, size_); +#else + strncpy(data_, other.data_, size_); +#endif + data_[size_] = '\0'; + } + + PString& operator=(const PString& other) + { + if (this != &other) + { + delete[] data_; + size_ = other.size_; + data_ = new char[size_ + 1]; +#ifdef _MSC_VER + strncpy_s(data_, size_ + 1, other.data_, size_); +#else + strncpy(data_, other.data_, size_); +#endif + data_[size_] = '\0'; + } + return *this; + } + + ~PString() + { + delete[] data_; + } + + PString operator+(const PString& other) const + { + PString result; + result.size_ = size_ + other.size_; + delete[] result.data_; + result.data_ = new char[result.size_ + 1]; +#ifdef _MSC_VER + strncpy_s(result.data_, result.size_ + 1, data_, size_); + strncpy_s(result.data_ + size_, result.size_ - size_ + 1, other.data_, other.size_); +#else + strncpy(result.data_, data_, size_); + strncpy(result.data_ + size_, other.data_, other.size_); +#endif + result.data_[result.size_] = '\0'; + return result; + } + + friend PString operator+(const char* lhs, const PString& rhs) + { + PString result; + size_t lhs_size = std::strlen(lhs); + result.size_ = lhs_size + rhs.size_; + delete[] result.data_; + result.data_ = new char[result.size_ + 1]; +#ifdef _MSC_VER + strncpy_s(result.data_, result.size_ + 1, lhs, lhs_size); + strncpy_s(result.data_ + lhs_size, result.size_ - lhs_size + 1, rhs.data_, rhs.size_); +#else + strncpy(result.data_, lhs, lhs_size); + strncpy(result.data_ + lhs_size, rhs.data_, rhs.size_); +#endif + result.data_[result.size_] = '\0'; + return result; + } + + PString& operator+=(const PString& other) + { + size_t new_size = size_ + other.size_; + char* new_data = new char[new_size + 1]; +#ifdef _MSC_VER + strncpy_s(new_data, new_size + 1, data_, size_); + strncpy_s(new_data + size_, new_size - size_ + 1, other.data_, other.size_); +#else + strncpy(new_data, data_, size_); + strncpy(new_data + size_, other.data_, other.size_); +#endif + new_data[new_size] = '\0'; + + delete[] data_; + data_ = new_data; + size_ = new_size; + + return *this; + } + + PString& operator+=(const char* str) + { + if (str) + { + size_t str_size = std::strlen(str); + size_t new_size = size_ + str_size; + char* new_data = new char[new_size + 1]; +#ifdef _MSC_VER + strncpy_s(new_data, new_size + 1, data_, size_); + strncpy_s(new_data + size_, new_size - size_ + 1, str, str_size); +#else + strncpy(new_data, data_, size_); + strncpy(new_data + size_, str, str_size); +#endif + new_data[new_size] = '\0'; + + delete[] data_; + data_ = new_data; + size_ = new_size; + } + return *this; + } + + const char* c_str() const + { + return data_; + } + + size_t size() const + { + return size_; + } + + bool empty() const + { + return size_ == 0; + } + + bool operator<(const PString& other) const + { + return std::strcmp(data_, other.data_) < 0; + } + + bool operator==(const PString& other) const + { + return std::strcmp(data_, other.data_) == 0; + } + +private: + char* data_; + size_t size_; +}; +} // namespace PUERTS_NAMESPACE + +namespace std +{ +template <> +struct hash +{ + size_t operator()(const PUERTS_NAMESPACE::PString& str) const + { + size_t hash = 5381; // DJB2 + for (size_t i = 0; i < str.size(); ++i) + { + hash = ((hash << 5) + hash) + str.c_str()[i]; // hash * 33 + c + } + return hash; + } +}; +} // namespace std diff --git a/include/TypeInfo.hpp b/include/TypeInfo.hpp new file mode 100644 index 0000000..2400fd9 --- /dev/null +++ b/include/TypeInfo.hpp @@ -0,0 +1,536 @@ +/* + * 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 +#ifdef WITH_V8_FAST_CALL +#include "V8FastCall.hpp" +#endif +#include "PuertsNamespaceDef.h" + +#define __DefScriptTTypeName(CLSNAME, CLS) \ + namespace PUERTS_NAMESPACE \ + { \ + template <> \ + struct ScriptTypeName \ + { \ + static constexpr auto value() \ + { \ + return internal::Literal(#CLSNAME); \ + } \ + }; \ + } + +#define PUERTS_BINDING_PROTO_ID() "fdq4falqlqcq" + +#if defined(WITH_QJS_NAMESPACE_SUFFIX) +namespace v8_qjs +{ +class CFunction; +} + +namespace v8 = v8_qjs; +#else +namespace v8 +{ +class CFunction; +} +#endif + +namespace PUERTS_NAMESPACE +{ +namespace internal +{ +template +class StringLiteral +{ +public: + template + constexpr StringLiteral(Characters... characters) : m_value{characters..., '\0'} + { + } + + template + constexpr StringLiteral(const char (&value)[N + 1], std::index_sequence dummy) : StringLiteral(value[Indexes]...) + { + } + + constexpr StringLiteral(const char (&value)[N + 1]) : StringLiteral(value, std::make_index_sequence{}) + { + } + + constexpr char operator[](const std::size_t index) const + { + return m_value[index]; + } + + constexpr const char* Data() const + { + return m_value; + } + + template + constexpr StringLiteral Sub(std::index_sequence dummy) const + { + return StringLiteral(m_value[Start + Index]...); + } + + template + constexpr StringLiteral Sub() const + { + return Sub(std::make_index_sequence()); + } + +private: + const char m_value[N + 1]; +}; + +template +constexpr StringLiteral ConcatStrings( + const Left& lhs, const Right& rhs, std::index_sequence dummy1, std::index_sequence dummy2) +{ + return StringLiteral(lhs[IndexesLeft]..., rhs[IndexesRight]...); +} + +template +constexpr StringLiteral operator+(const StringLiteral& lhs, const StringLiteral& rhs) +{ + return ConcatStrings(lhs, rhs, std::make_index_sequence(), std::make_index_sequence()); +} + +template +constexpr auto Literal(const char (&value)[N]) +{ + return StringLiteral(value, typename std::make_index_sequence{}); +} + +} // namespace internal + +template +struct ScriptTypeName +{ +}; + +template +struct ScriptTypeNameWithNamespace +{ + static constexpr auto value() + { + return ScriptTypeName::value(); + } +}; + +template +struct ScriptTypeName +{ + static constexpr auto value() + { + return ScriptTypeName::type>::value(); + } +}; + +template +struct ScriptTypeName +{ + static constexpr auto value() + { + return ScriptTypeName::type>::value(); + } +}; + +template +struct ScriptTypeName +{ + static constexpr auto value() + { + return ScriptTypeName::type>::value(); + } +}; + +template +struct ScriptTypeName::value && sizeof(T) == 8>::type> +{ + static constexpr auto value() + { + return internal::Literal("bigint"); + } +}; + +template +struct ScriptTypeName::value>::type> +{ + static constexpr auto value() + { + return internal::Literal("number"); + } +}; + +template +struct ScriptTypeName::value || (std::is_integral::value && sizeof(T) < 8)>::type> +{ + static constexpr auto value() + { + return internal::Literal("number"); + } +}; + +template <> +struct ScriptTypeName +{ + static constexpr auto value() + { + return internal::Literal("string"); + } +}; + +template <> +struct ScriptTypeName +{ + static constexpr auto value() + { + return internal::Literal("cstring"); + } +}; + +template <> +struct ScriptTypeName +{ + static constexpr auto value() + { + return internal::Literal("boolean"); + } +}; + +template <> +struct ScriptTypeName +{ + static constexpr auto value() + { + return internal::Literal("void"); + } +}; + +template +struct StaticTypeId +{ + static const void* get() + { + static T* dummy = nullptr; + return &dummy; + } +}; + +template +struct DynamicTypeId +{ + static const void* get(T* Obj) + { + return StaticTypeId::get(); + } +}; + +template +struct is_uetype : std::false_type +{ +}; + +template +struct is_objecttype : std::false_type +{ +}; + +template +struct is_script_type : std::false_type +{ +}; + +template +struct is_script_type::value && !std::is_same::value>::type> + : std::true_type +{ +}; + +template <> +struct is_script_type : std::true_type +{ +}; + +template +struct ScriptTypeName::value && !std::is_const::value>::type> +{ + static constexpr auto value() + { + return internal::Literal("ArrayBuffer"); + } +}; + +template <> +struct ScriptTypeName +{ + static constexpr auto value() + { + return internal::Literal("any"); + } +}; + +template <> +struct ScriptTypeName +{ + static constexpr auto value() + { + return internal::Literal("any"); + } +}; + +class CTypeInfo +{ +public: + virtual const char* Name() const = 0; + virtual bool IsPointer() const = 0; + virtual bool IsRef() const = 0; + virtual bool IsConst() const = 0; + virtual bool IsUEType() const = 0; + virtual bool IsObjectType() const = 0; +}; + +class CFunctionInfo +{ +public: + virtual const CTypeInfo* Return() const = 0; + virtual unsigned int ArgumentCount() const = 0; + virtual unsigned int DefaultCount() const = 0; + virtual const CTypeInfo* Argument(unsigned int index) const = 0; + virtual const char* CustomSignature() const = 0; + virtual const class v8::CFunction* FastCallInfo() const = 0; +}; + +template +class CTypeInfoImpl : CTypeInfo +{ +public: + virtual const char* Name() const override + { + static auto NameLiteral = ScriptTypeName::value(); + return NameLiteral.Data(); + } + virtual bool IsPointer() const override + { + return std::is_pointer::value && !ScriptTypePtrAsRef; + }; + virtual bool IsRef() const override + { + return (std::is_reference::value && !std::is_const::type>::value) || + (std::is_pointer::value && + !std::is_same::type>::type>::value && + !std::is_same::type>::type>::value && + ScriptTypePtrAsRef && !IsUEType() && !IsObjectType()); + }; + virtual bool IsConst() const override + { + return std::is_const::type>::type>::value; + }; + virtual bool IsUEType() const override + { + return is_uetype::type>::type>::type>::value; + }; + virtual bool IsObjectType() const override + { + return is_objecttype< + typename std::remove_const::type>::type>::type>::value; + }; + + static const CTypeInfo* get() + { + static CTypeInfoImpl instance; + return &instance; + } +}; + +template +class CFunctionInfoImpl : public CFunctionInfo +{ +protected: + const CTypeInfo* return_; + const unsigned int argCount_; + const CTypeInfo* arguments_[sizeof...(Args) + 1]; + unsigned int defaultCount_; + + CFunctionInfoImpl() + : return_(CTypeInfoImpl::get()) + , argCount_(sizeof...(Args)) + , arguments_{CTypeInfoImpl::get()...} + , defaultCount_(0) + { + } + + virtual ~CFunctionInfoImpl() + { + } + +public: + virtual const CTypeInfo* Return() const override + { + return return_; + } + virtual unsigned int ArgumentCount() const override + { + return argCount_ - StartParameter; + } + virtual unsigned int DefaultCount() const override + { + return defaultCount_; + } + virtual const CTypeInfo* Argument(unsigned int index) const override + { + return arguments_[index + StartParameter]; + } + virtual const char* CustomSignature() const override + { + return nullptr; + } + virtual const class v8::CFunction* FastCallInfo() const override + { + return nullptr; + }; + + static const CFunctionInfo* get(unsigned int defaultCount) + { + static CFunctionInfoImpl instance{}; + instance.defaultCount_ = defaultCount; + return &instance; + } +}; + +template +class CFunctionInfoByPtrImpl +{ +}; + +template +class CFunctionInfoByPtrImpl + : public CFunctionInfoImpl +{ +public: + virtual ~CFunctionInfoByPtrImpl() + { + } +#ifdef WITH_V8_FAST_CALL + virtual const class v8::CFunction* FastCallInfo() const override + { + return V8FastCall::info(); + }; +#endif + + static const CFunctionInfo* get(unsigned int defaultCount) + { + static CFunctionInfoByPtrImpl instance{}; + instance.defaultCount_ = defaultCount; + return &instance; + } +}; + +template +class CFunctionInfoByPtrImpl + : public CFunctionInfoImpl +{ +public: + virtual ~CFunctionInfoByPtrImpl() + { + } +#ifdef WITH_V8_FAST_CALL + virtual const class v8::CFunction* FastCallInfo() const override + { + return V8FastCall::info(); + }; +#endif + + static const CFunctionInfo* get(unsigned int defaultCount) + { + static CFunctionInfoByPtrImpl instance{}; + instance.defaultCount_ = defaultCount; + return &instance; + } +}; + +template +class CFunctionInfoByPtrImpl + : public CFunctionInfoImpl +{ +public: + virtual ~CFunctionInfoByPtrImpl() + { + } +#ifdef WITH_V8_FAST_CALL + virtual const class v8::CFunction* FastCallInfo() const override + { + return V8FastCall::info(); + }; +#endif + + static const CFunctionInfo* get(unsigned int defaultCount) + { + static CFunctionInfoByPtrImpl instance{}; + instance.defaultCount_ = defaultCount; + return &instance; + } +}; + +class CFunctionInfoWithCustomSignature : public CFunctionInfo +{ + const char* _signature; + +public: + CFunctionInfoWithCustomSignature(const char* signature) : _signature(signature) + { + } + + virtual ~CFunctionInfoWithCustomSignature() + { + } + + virtual const CTypeInfo* Return() const override + { + return nullptr; + } + virtual unsigned int ArgumentCount() const override + { + return 0; + } + virtual unsigned int DefaultCount() const override + { + return 0; + } + virtual const CTypeInfo* Argument(unsigned int index) const override + { + return nullptr; + } + virtual const char* CustomSignature() const override + { + return _signature; + } + virtual const class v8::CFunction* FastCallInfo() const override + { + return nullptr; + }; +}; + +struct NamedFunctionInfo +{ + const char* Name; + const CFunctionInfo* Type; +}; + +struct NamedPropertyInfo +{ + const char* Name; + const CTypeInfo* Type; +}; + +} // namespace PUERTS_NAMESPACE diff --git a/include/pesapi.h b/include/pesapi.h new file mode 100644 index 0000000..b8bc9b9 --- /dev/null +++ b/include/pesapi.h @@ -0,0 +1,359 @@ +/* + * 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. + */ + +#ifndef PS_API_H_ +#define PS_API_H_ + +#include +#include +#include + +// Portable Embedded Scripting API + +#define PESAPI_VERSION 11 + +#define PESAPI_EXTERN + +#if defined(__APPLE__) && defined(BUILDING_PES_EXTENSION) && !defined(PESAPI_ADPT_C) +#include "TargetConditionals.h" +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR +#define USING_OBJC_REFLECTION +#endif +#endif + +#ifdef USING_OBJC_REFLECTION +#import +#endif + +#ifdef _WIN32 +#define PESAPI_MODULE_EXPORT __declspec(dllexport) +#else +#define PESAPI_MODULE_EXPORT __attribute__((visibility("default"))) +#endif + +#if defined(__GNUC__) +#define PESAPI_NO_RETURN __attribute__((noreturn)) +#elif defined(_WIN32) +#define PESAPI_NO_RETURN __declspec(noreturn) +#else +#define PESAPI_NO_RETURN +#endif + +#ifdef __cplusplus +#define EXTERN_C_START \ + extern "C" \ + { +#define EXTERN_C_END } +#else +#define EXTERN_C_START +#define EXTERN_C_END +#endif + +#define PESAPI_MODULE_INITIALIZER_X(base, module, version) PESAPI_MODULE_INITIALIZER_X_HELPER(base, module, version) + +#define PESAPI_MODULE_INITIALIZER_X_HELPER(base, module, version) base##module##_v##version + +#define PESAPI_MODULE_INITIALIZER_BASE pesapi_register_ + +#define PESAPI_MODULE_INITIALIZER(modname) PESAPI_MODULE_INITIALIZER_X(PESAPI_MODULE_INITIALIZER_BASE, modname, PESAPI_VERSION) + +#define PESAPI_MODULE_VERSION() PESAPI_MODULE_INITIALIZER_X(PESAPI_MODULE_INITIALIZER_BASE, version, 0) + +#ifdef USING_OBJC_REFLECTION + +#define PESAPI_MODULE(modname, initfunc) \ + @interface PESAPI_MODULE_INITIALIZER (modname) : NSObject \ +@end \ + @implementation PESAPI_MODULE_INITIALIZER (modname) \ + +(void) initlib : (pesapi_func_ptr*) func_ptr_array \ + { \ + pesapi_init(func_ptr_array); \ + initfunc(); \ + } \ + @end + +#else + +#define PESAPI_MODULE(modname, initfunc) \ + EXTERN_C_START \ + PESAPI_MODULE_EXPORT void PESAPI_MODULE_INITIALIZER(modname)(pesapi_func_ptr * func_ptr_array); \ + PESAPI_MODULE_EXPORT const char* PESAPI_MODULE_INITIALIZER(dynamic)(pesapi_func_ptr * func_ptr_array); \ + PESAPI_MODULE_EXPORT int PESAPI_MODULE_VERSION()(); \ + EXTERN_C_END \ + PESAPI_MODULE_EXPORT void PESAPI_MODULE_INITIALIZER(modname)(pesapi_func_ptr * func_ptr_array) \ + { \ + pesapi_init(func_ptr_array); \ + initfunc(); \ + } \ + PESAPI_MODULE_EXPORT const char* PESAPI_MODULE_INITIALIZER(dynamic)(pesapi_func_ptr * func_ptr_array) \ + { \ + if (func_ptr_array) \ + { \ + pesapi_init(func_ptr_array); \ + initfunc(); \ + } \ + return #modname; \ + } \ + PESAPI_MODULE_EXPORT int PESAPI_MODULE_VERSION()() \ + { \ + return PESAPI_VERSION; \ + } + +#endif + +EXTERN_C_START + +// alloc on stack +struct pesapi_scope_memory +{ + int padding__[32]; +}; + +typedef struct pesapi_env__* pesapi_env; +typedef struct pesapi_env_ref__* pesapi_env_ref; +typedef struct pesapi_value__* pesapi_value; +typedef struct pesapi_value_ref__* pesapi_value_ref; +typedef struct pesapi_callback_info__* pesapi_callback_info; +typedef struct pesapi_scope__* pesapi_scope; +typedef struct pesapi_type_info__* pesapi_type_info; +typedef struct pesapi_signature_info__* pesapi_signature_info; +typedef struct pesapi_property_descriptor__* pesapi_property_descriptor; + +typedef void (*pesapi_callback)(struct pesapi_ffi* apis, pesapi_callback_info info); +typedef void* (*pesapi_constructor)(struct pesapi_ffi* apis, pesapi_callback_info info); +typedef void (*pesapi_finalize)(struct pesapi_ffi* apis, void* ptr, void* class_data, void* env_private); +typedef void (*pesapi_function_finalize)(struct pesapi_ffi* apis, void* data, void* env_private); +typedef void* (*pesapi_on_native_object_enter)(void* ptr, void* class_data, void* env_private); +// userdata: return of pesapi_on_native_object_enter +typedef void (*pesapi_on_native_object_exit)(void* ptr, void* class_data, void* env_private, void* userdata); +typedef bool (*pesapi_class_not_found_callback)(const void* type_id); +typedef void (*pesapi_func_ptr)(void); + +#ifdef BUILDING_PES_EXTENSION +PESAPI_EXTERN void pesapi_init(pesapi_func_ptr* func_array); +#else +PESAPI_MODULE_EXPORT int pesapi_load_addon(const char* path, const char* module_name); +#endif + +// value process +typedef pesapi_value (*pesapi_create_null_func)(pesapi_env env); +typedef pesapi_value (*pesapi_create_undefined_func)(pesapi_env env); +typedef pesapi_value (*pesapi_create_boolean_func)(pesapi_env env, bool value); +typedef pesapi_value (*pesapi_create_int32_func)(pesapi_env env, int32_t value); +typedef pesapi_value (*pesapi_create_uint32_func)(pesapi_env env, uint32_t value); +typedef pesapi_value (*pesapi_create_int64_func)(pesapi_env env, int64_t value); +typedef pesapi_value (*pesapi_create_uint64_func)(pesapi_env env, uint64_t value); +typedef pesapi_value (*pesapi_create_double_func)(pesapi_env env, double value); +typedef pesapi_value (*pesapi_create_string_utf8_func)(pesapi_env env, const char* str, size_t length); +typedef pesapi_value (*pesapi_create_binary_func)(pesapi_env env, void* str, size_t length); +typedef pesapi_value (*pesapi_create_array_func)(pesapi_env env); +typedef pesapi_value (*pesapi_create_object_func)(pesapi_env env); +typedef pesapi_value (*pesapi_create_function_func)(pesapi_env env, pesapi_callback native_impl, void* data, pesapi_function_finalize finalize); +typedef pesapi_value (*pesapi_create_class_func)(pesapi_env env, const void* type_id); + +typedef bool (*pesapi_get_value_bool_func)(pesapi_env env, pesapi_value value); +typedef int32_t (*pesapi_get_value_int32_func)(pesapi_env env, pesapi_value value); +typedef uint32_t (*pesapi_get_value_uint32_func)(pesapi_env env, pesapi_value value); +typedef int64_t (*pesapi_get_value_int64_func)(pesapi_env env, pesapi_value value); +typedef uint64_t (*pesapi_get_value_uint64_func)(pesapi_env env, pesapi_value value); +typedef double (*pesapi_get_value_double_func)(pesapi_env env, pesapi_value value); +typedef const char* (*pesapi_get_value_string_utf8_func)(pesapi_env env, pesapi_value value, char* buf, size_t* bufsize); +typedef void* (*pesapi_get_value_binary_func)(pesapi_env env, pesapi_value pvalue, size_t* bufsize); +typedef uint32_t (*pesapi_get_array_length_func)(pesapi_env env, pesapi_value value); + +typedef bool (*pesapi_is_null_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_undefined_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_boolean_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_int32_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_uint32_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_int64_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_uint64_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_double_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_string_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_object_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_function_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_binary_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_array_func)(pesapi_env env, pesapi_value value); + +typedef pesapi_value (*pesapi_native_object_to_value_func)(pesapi_env env, const void* type_id, void* object_ptr, bool call_finalize); +typedef void* (*pesapi_get_native_object_ptr_func)(pesapi_env env, pesapi_value value); +typedef const void* (*pesapi_get_native_object_typeid_func)(pesapi_env env, pesapi_value value); +typedef bool (*pesapi_is_instance_of_func)(pesapi_env env, const void* type_id, pesapi_value value); + +typedef pesapi_value (*pesapi_boxing_func)(pesapi_env env, pesapi_value value); +typedef pesapi_value (*pesapi_unboxing_func)(pesapi_env env, pesapi_value value); +typedef void (*pesapi_update_boxed_value_func)(pesapi_env env, pesapi_value boxed_value, pesapi_value value); +typedef bool (*pesapi_is_boxed_value_func)(pesapi_env env, pesapi_value value); + +typedef int (*pesapi_get_args_len_func)(pesapi_callback_info info); +typedef pesapi_value (*pesapi_get_arg_func)(pesapi_callback_info info, int index); +typedef pesapi_env (*pesapi_get_env_func)(pesapi_callback_info info); +typedef pesapi_value (*pesapi_get_this_func)(pesapi_callback_info info); +typedef pesapi_value (*pesapi_get_holder_func)(pesapi_callback_info info); +typedef void* (*pesapi_get_userdata_func)(pesapi_callback_info info); +typedef void (*pesapi_add_return_func)(pesapi_callback_info info, pesapi_value value); +typedef void (*pesapi_throw_by_string_func)(pesapi_callback_info pinfo, const char* msg); + +typedef pesapi_env_ref (*pesapi_create_env_ref_func)(pesapi_env env); +typedef bool (*pesapi_env_ref_is_valid_func)(pesapi_env_ref env); +typedef pesapi_env (*pesapi_get_env_from_ref_func)(pesapi_env_ref env_ref); +typedef pesapi_env_ref (*pesapi_duplicate_env_ref_func)(pesapi_env_ref env_ref); +typedef void (*pesapi_release_env_ref_func)(pesapi_env_ref env_ref); +typedef pesapi_scope (*pesapi_open_scope_func)(pesapi_env_ref env_ref); +typedef pesapi_scope (*pesapi_open_scope_placement_func)(pesapi_env_ref env_ref, struct pesapi_scope_memory* memory); +typedef bool (*pesapi_has_caught_func)(pesapi_scope scope); +typedef const char* (*pesapi_get_exception_as_string_func)(pesapi_scope scope, bool with_stack); +typedef void (*pesapi_close_scope_func)(pesapi_scope scope); +typedef void (*pesapi_close_scope_placement_func)(pesapi_scope scope); + +typedef pesapi_value_ref (*pesapi_create_value_ref_func)(pesapi_env env, pesapi_value value, uint32_t internal_field_count); +typedef pesapi_value_ref (*pesapi_duplicate_value_ref_func)(pesapi_value_ref value_ref); +typedef void (*pesapi_release_value_ref_func)(pesapi_value_ref value_ref); +typedef pesapi_value (*pesapi_get_value_from_ref_func)(pesapi_env env, pesapi_value_ref value_ref); +typedef void (*pesapi_set_ref_weak_func)(pesapi_env env, pesapi_value_ref value_ref); +// Optional api: return false if can not fulfill +typedef bool (*pesapi_set_owner_func)(pesapi_env env, pesapi_value value, pesapi_value owner); +// suggestion: struct pesapi_value_ref : pesapi_env_ref {...}; +typedef pesapi_env_ref (*pesapi_get_ref_associated_env_func)(pesapi_value_ref value_ref); +typedef void** (*pesapi_get_ref_internal_fields_func)(pesapi_value_ref value_ref, uint32_t* pinternal_field_count); + +typedef pesapi_value (*pesapi_get_property_func)(pesapi_env env, pesapi_value object, const char* key); +typedef void (*pesapi_set_property_func)(pesapi_env env, pesapi_value object, const char* key, pesapi_value value); +typedef bool (*pesapi_get_private_func)(pesapi_env env, pesapi_value object, void** out_ptr); +typedef bool (*pesapi_set_private_func)(pesapi_env env, pesapi_value object, void* ptr); +typedef pesapi_value (*pesapi_get_property_uint32_func)(pesapi_env env, pesapi_value object, uint32_t key); +typedef void (*pesapi_set_property_uint32_func)(pesapi_env env, pesapi_value object, uint32_t key, pesapi_value value); + +typedef pesapi_value (*pesapi_call_function_func)(pesapi_env env, pesapi_value func, pesapi_value this_object, int argc, const pesapi_value argv[]); +typedef pesapi_value (*pesapi_eval_func)(pesapi_env env, const uint8_t* code, size_t code_size, const char* path); +typedef pesapi_value (*pesapi_global_func)(pesapi_env env); +typedef const void* (*pesapi_get_env_private_func)(pesapi_env env); +typedef void (*pesapi_set_env_private_func)(pesapi_env env, const void* ptr); + +struct pesapi_ffi +{ + pesapi_create_null_func create_null; + pesapi_create_undefined_func create_undefined; + pesapi_create_boolean_func create_boolean; + pesapi_create_int32_func create_int32; + pesapi_create_uint32_func create_uint32; + pesapi_create_int64_func create_int64; + pesapi_create_uint64_func create_uint64; + pesapi_create_double_func create_double; + pesapi_create_string_utf8_func create_string_utf8; + pesapi_create_binary_func create_binary; + pesapi_create_array_func create_array; + pesapi_create_object_func create_object; + pesapi_create_function_func create_function; + pesapi_create_class_func create_class; + pesapi_get_value_bool_func get_value_bool; + pesapi_get_value_int32_func get_value_int32; + pesapi_get_value_uint32_func get_value_uint32; + pesapi_get_value_int64_func get_value_int64; + pesapi_get_value_uint64_func get_value_uint64; + pesapi_get_value_double_func get_value_double; + pesapi_get_value_string_utf8_func get_value_string_utf8; + pesapi_get_value_binary_func get_value_binary; + pesapi_get_array_length_func get_array_length; + pesapi_is_null_func is_null; + pesapi_is_undefined_func is_undefined; + pesapi_is_boolean_func is_boolean; + pesapi_is_int32_func is_int32; + pesapi_is_uint32_func is_uint32; + pesapi_is_int64_func is_int64; + pesapi_is_uint64_func is_uint64; + pesapi_is_double_func is_double; + pesapi_is_string_func is_string; + pesapi_is_object_func is_object; + pesapi_is_function_func is_function; + pesapi_is_binary_func is_binary; + pesapi_is_array_func is_array; + pesapi_native_object_to_value_func native_object_to_value; + pesapi_get_native_object_ptr_func get_native_object_ptr; + pesapi_get_native_object_typeid_func get_native_object_typeid; + pesapi_is_instance_of_func is_instance_of; + pesapi_boxing_func boxing; + pesapi_unboxing_func unboxing; + pesapi_update_boxed_value_func update_boxed_value; + pesapi_is_boxed_value_func is_boxed_value; + pesapi_get_args_len_func get_args_len; + pesapi_get_arg_func get_arg; + pesapi_get_env_func get_env; + pesapi_get_this_func get_this; + pesapi_get_holder_func get_holder; + pesapi_get_userdata_func get_userdata; + pesapi_add_return_func add_return; + pesapi_throw_by_string_func throw_by_string; + pesapi_create_env_ref_func create_env_ref; + pesapi_env_ref_is_valid_func env_ref_is_valid; + pesapi_get_env_from_ref_func get_env_from_ref; + pesapi_duplicate_env_ref_func duplicate_env_ref; + pesapi_release_env_ref_func release_env_ref; + pesapi_open_scope_func open_scope; + pesapi_open_scope_placement_func open_scope_placement; + pesapi_has_caught_func has_caught; + pesapi_get_exception_as_string_func get_exception_as_string; + pesapi_close_scope_func close_scope; + pesapi_close_scope_placement_func close_scope_placement; + pesapi_create_value_ref_func create_value_ref; + pesapi_duplicate_value_ref_func duplicate_value_ref; + pesapi_release_value_ref_func release_value_ref; + pesapi_get_value_from_ref_func get_value_from_ref; + pesapi_set_ref_weak_func set_ref_weak; + pesapi_set_owner_func set_owner; + pesapi_get_ref_associated_env_func get_ref_associated_env; + pesapi_get_ref_internal_fields_func get_ref_internal_fields; + pesapi_get_property_func get_property; + pesapi_set_property_func set_property; + pesapi_get_private_func get_private; + pesapi_set_private_func set_private; + pesapi_get_property_uint32_func get_property_uint32; + pesapi_set_property_uint32_func set_property_uint32; + pesapi_call_function_func call_function; + pesapi_eval_func eval; + pesapi_global_func global; + pesapi_get_env_private_func get_env_private; + pesapi_set_env_private_func set_env_private; +}; + +PESAPI_EXTERN pesapi_type_info pesapi_alloc_type_infos(size_t count); + +PESAPI_EXTERN void pesapi_set_type_info( + pesapi_type_info type_infos, size_t index, const char* name, bool is_pointer, bool is_const, bool is_ref, bool is_primitive); + +PESAPI_EXTERN pesapi_signature_info pesapi_create_signature_info( + pesapi_type_info return_type, size_t parameter_count, pesapi_type_info parameter_types); + +PESAPI_EXTERN pesapi_property_descriptor pesapi_alloc_property_descriptors(size_t count); + +// using pesapi_get_userdata obtain userdata in callback +PESAPI_EXTERN void pesapi_set_method_info(pesapi_property_descriptor properties, size_t index, const char* name, bool is_static, + pesapi_callback method, void* data, pesapi_signature_info signature_info); + +PESAPI_EXTERN void pesapi_set_property_info(pesapi_property_descriptor properties, size_t index, const char* name, bool is_static, + pesapi_callback getter, pesapi_callback setter, void* getter_data, void* setter_data, pesapi_type_info type_info); + +PESAPI_EXTERN void pesapi_define_class(const void* type_id, const void* super_type_id, const char* type_name, + pesapi_constructor constructor, pesapi_finalize finalize, size_t property_count, pesapi_property_descriptor properties, + void* data); + +PESAPI_EXTERN void* pesapi_get_class_data(const void* type_id, bool force_load); + +PESAPI_EXTERN bool pesapi_trace_native_object_lifecycle( + const void* type_id, pesapi_on_native_object_enter on_enter, pesapi_on_native_object_exit on_exit); + +PESAPI_EXTERN void pesapi_on_class_not_found(pesapi_class_not_found_callback callback); + +PESAPI_EXTERN void pesapi_class_type_info(const char* proto_magic_id, const void* type_id, const void* constructor_info, + const void* methods_info, const void* functions_info, const void* properties_info, const void* variables_info); + +PESAPI_EXTERN const void* pesapi_find_type_id(const char* module_name, const char* type_name); + +EXTERN_C_END + +#endif diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index c0ad3f8..6a7d565 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -1,7 +1,1037 @@ +#include "pesapi.h" +#include "quickjs.h" +#include #include +#include #include void GetPapiQuickjsImpl() { eastl::basic_string str = "hello world"; -} \ No newline at end of file +} + +struct pesapi_env_ref__ +{ + explicit pesapi_env_ref__(JSContext *ctx) + : context_persistent(JS_DupContext(ctx)) + , ref_count(1) + //, env_life_cycle_tracker(puerts::DataTransfer::GetJsEnvLifeCycleTracker(context->GetIsolate())) + { + } + + ~pesapi_env_ref__() + { + JS_FreeContext(context_persistent); + } + + JSContext *context_persistent; + int ref_count; + eastl::weak_ptr env_life_cycle_tracker; +}; + +struct pesapi_value_ref__ : pesapi_env_ref__ +{ + explicit pesapi_value_ref__(JSContext *ctx, JSValue v, uint32_t field_count) + : pesapi_env_ref__(ctx), value_persistent(JS_DupValue(ctx, v)), internal_field_count(field_count) + { + } + + ~pesapi_value_ref__() + { + JS_FreeValue(context_persistent, value_persistent); + } + + JSValue value_persistent; + uint32_t internal_field_count; + void* internal_fields[0]; +}; + +namespace qjsimpl +{ +static struct pesapi_scope__ *getCurrentScope(JSContext *ctx) +{ + return (struct pesapi_scope__ *) JS_GetContextOpaque(ctx); +} + +static void setCurrentScope(JSContext *ctx, struct pesapi_scope__ *scope) +{ + JS_SetContextOpaque(ctx, scope); +} +} + +struct pesapi_scope__ +{ + const static size_t SCOPE_FIX_SIZE_VALUES_SIZE = 4; + + explicit pesapi_scope__(JSContext *ctx) + { + this->ctx = ctx; + prev_scope = qjsimpl::getCurrentScope(ctx); + qjsimpl::setCurrentScope(ctx, this); + + values_used = 0; + + exception = JS_NULL; + } + + JSContext *ctx; + + pesapi_scope__ *prev_scope; + + JSValue values[SCOPE_FIX_SIZE_VALUES_SIZE]; + + size_t values_used; + + eastl::vector dynamic_alloc_values; + + JSValue exception; + + JSValue *allocValue() + { + JSValue *ret; + if (values_used < SCOPE_FIX_SIZE_VALUES_SIZE) + { + ret = &(values[values_used++]); + } + else + { + ret = (JSValue *) js_malloc(ctx, sizeof(JSValue)); + dynamic_alloc_values.push_back(ret); + } + *ret = JS_UNDEFINED; + return ret; + } + + + ~pesapi_scope__() + { + JS_FreeValue(ctx, exception); + for (size_t i = 0; i < values_used; i++) + { + JS_FreeValue(ctx, values[i]); + } + + for (size_t i = 0; i < dynamic_alloc_values.size(); i++) + { + JS_FreeValue(ctx, *dynamic_alloc_values[i]); + js_free(ctx, dynamic_alloc_values[i]); + } + dynamic_alloc_values.clear(); + qjsimpl::setCurrentScope(ctx, prev_scope); + } +}; + +static_assert(sizeof(pesapi_scope_memory) >= sizeof(pesapi_scope__), "sizeof(pesapi_scope__) > sizeof(pesapi_scope_memory__)"); + +namespace qjsimpl +{ +inline pesapi_value pesapiValueFromQjsValue(JSValue* v) +{ + return reinterpret_cast(v); +} + +inline JSValue* qjsValueFromPesapiValue(pesapi_value v) +{ + return reinterpret_cast(v); +} + +inline pesapi_env pesapiEnvFromQjsContext(JSContext * ctx) +{ + return reinterpret_cast(ctx); +} + +inline JSContext* qjsContextFromPesapiEnv(pesapi_env v) +{ + return reinterpret_cast(v); +} + +static JSValue *allocValueInCurrentScope(JSContext *ctx) +{ + auto scope = getCurrentScope(ctx); + return scope->allocValue(); +} + +JSValue literal_values_undefined = JS_UNDEFINED; +JSValue literal_values_null = JS_NULL; +JSValue literal_values_true = JS_TRUE; +JSValue literal_values_false = JS_FALSE; + +// value process +pesapi_value pesapi_create_null(pesapi_env env) +{ + return pesapiValueFromQjsValue(&literal_values_null); +} + +pesapi_value pesapi_create_undefined(pesapi_env env) +{ + return pesapiValueFromQjsValue(&literal_values_undefined); +} + +pesapi_value pesapi_create_boolean(pesapi_env env, bool value) +{ + return pesapiValueFromQjsValue(value ? &literal_values_true : &literal_values_false); +} + +pesapi_value pesapi_create_int32(pesapi_env env, int32_t value) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret) + { + *ret = JS_NewInt32(ctx, value); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} + +pesapi_value pesapi_create_uint32(pesapi_env env, uint32_t value) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret) + { + *ret = JS_NewUint32(ctx, value); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} + +pesapi_value pesapi_create_int64(pesapi_env env, int64_t value) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret) + { + *ret = JS_NewInt64(ctx, value); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} + +pesapi_value pesapi_create_uint64(pesapi_env env, uint64_t value) +{ + return pesapi_create_int64(env, value); +} + +pesapi_value pesapi_create_double(pesapi_env env, double value) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret) + { + *ret = JS_NewFloat64(ctx, value); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} + +pesapi_value pesapi_create_string_utf8(pesapi_env env, const char* str, size_t length) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (str && ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret && str) + { + *ret = JS_NewStringLen(ctx, str, length); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} + +pesapi_value pesapi_create_binary(pesapi_env env, void* bin, size_t length) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (bin && ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret) + { + *ret = JS_NewArrayBuffer(ctx, (uint8_t *) bin, length, nullptr, nullptr, false); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} + +pesapi_value pesapi_create_array(pesapi_env env) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret) + { + *ret = JS_NewArray(ctx); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} + +pesapi_value pesapi_create_object(pesapi_env env) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret) + { + *ret = JS_NewObject(ctx); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} +/* +pesapi_value pesapi_create_function(pesapi_env env, pesapi_callback native_impl, void* data, pesapi_function_finalize finalize) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto func = puerts::DataTransfer::IsolateData(context->GetIsolate())->CreateFunction(context, native_impl, data, finalize); + if (func.IsEmpty()) + return nullptr; + return v8impl::PesapiValueFromV8LocalValue(func.ToLocalChecked()); +} + +pesapi_value pesapi_create_class(pesapi_env env, const void* type_id) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto cls = puerts::DataTransfer::IsolateData(context->GetIsolate())->LoadTypeById(context, type_id); + if (cls.IsEmpty()) + return nullptr; + return v8impl::PesapiValueFromV8LocalValue(cls.ToLocalChecked()); +} + +bool pesapi_get_value_bool(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->BooleanValue(context->GetIsolate()); +} + +int32_t pesapi_get_value_int32(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->Int32Value(context).ToChecked(); +} + +uint32_t pesapi_get_value_uint32(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->Uint32Value(context).ToChecked(); +} + +int64_t pesapi_get_value_int64(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsBigInt() ? value->ToBigInt(context).ToLocalChecked()->Int64Value() : 0; +} + +uint64_t pesapi_get_value_uint64(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsBigInt() ? value->ToBigInt(context).ToLocalChecked()->Uint64Value() : 0; +} + +double pesapi_get_value_double(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->NumberValue(context).ToChecked(); +} + +const char* pesapi_get_value_string_utf8(pesapi_env env, pesapi_value pvalue, char* buf, size_t* bufsize) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + + if (buf == nullptr) + { + auto str = value->ToString(context).ToLocalChecked(); + *bufsize = str->Utf8Length(context->GetIsolate()); + } + else + { + auto str = value->ToString(context).ToLocalChecked(); + str->WriteUtf8(context->GetIsolate(), buf, *bufsize); + } + return buf; +} + +void* pesapi_get_value_binary(pesapi_env env, pesapi_value pvalue, size_t* bufsize) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + + if (value->IsArrayBufferView()) + { + v8::Local buffView = value.As(); + *bufsize = buffView->ByteLength(); + auto Ab = buffView->Buffer(); + return static_cast(puerts::DataTransfer::GetArrayBufferData(Ab)) + buffView->ByteOffset(); + } + if (value->IsArrayBuffer()) + { + auto ab = v8::Local::Cast(value); + return puerts::DataTransfer::GetArrayBufferData(ab, *bufsize); + } + return nullptr; +} + +uint32_t pesapi_get_array_length(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + if (value->IsArray()) + { + return value.As()->Length(); + } + return 0; +} + +bool pesapi_is_null(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsNull(); +} + +bool pesapi_is_undefined(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsUndefined(); +} + +bool pesapi_is_boolean(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsBoolean(); +} + +bool pesapi_is_int32(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsInt32(); +} + +bool pesapi_is_uint32(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsUint32(); +} + +bool pesapi_is_int64(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsBigInt(); +} + +bool pesapi_is_uint64(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsBigInt(); +} + +bool pesapi_is_double(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsNumber(); +} + +bool pesapi_is_string(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsString(); +} + +bool pesapi_is_object(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsObject(); +} + +bool pesapi_is_function(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsFunction(); +} + +bool pesapi_is_binary(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsArrayBuffer() || value->IsArrayBufferView(); +} + +bool pesapi_is_array(pesapi_env env, pesapi_value pvalue) +{ + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return value->IsArray(); +} + +pesapi_value pesapi_native_object_to_value(pesapi_env env, const void* type_id, void* object_ptr, bool call_finalize) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + return v8impl::PesapiValueFromV8LocalValue( + ::puerts::DataTransfer::FindOrAddCData(context->GetIsolate(), context, type_id, object_ptr, !call_finalize)); +} + +void* pesapi_get_native_object_ptr(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + if (value.IsEmpty() || !value->IsObject()) + return nullptr; + return puerts::DataTransfer::GetPointerFast(value.As()); +} + +const void* pesapi_get_native_object_typeid(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + if (value.IsEmpty() || !value->IsObject()) + return nullptr; + return puerts::DataTransfer::GetPointerFast(value.As(), 1); +} + +bool pesapi_is_instance_of(pesapi_env env, const void* type_id, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + return ::puerts::DataTransfer::IsInstanceOf(context->GetIsolate(), static_cast(type_id), value.As()); +} + +pesapi_value pesapi_boxing(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + + auto result = v8::Object::New(context->GetIsolate()); + auto _unused = result->Set(context, 0, value); + return v8impl::PesapiValueFromV8LocalValue(result); +} + +pesapi_value pesapi_unboxing(pesapi_env env, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + + auto outer = value->ToObject(context).ToLocalChecked(); + auto realvalue = outer->Get(context, 0).ToLocalChecked(); + return v8impl::PesapiValueFromV8LocalValue(realvalue); +} + +void pesapi_update_boxed_value(pesapi_env env, pesapi_value boxed_value, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto holder = v8impl::V8LocalValueFromPesapiValue(boxed_value); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + if (holder->IsObject()) + { + auto outer = holder->ToObject(context).ToLocalChecked(); + auto _unused = outer->Set(context, 0, value); + } +} + +bool pesapi_is_boxed_value(pesapi_env env, pesapi_value value) +{ + return pesapi_is_object(env, value); +} + +int pesapi_get_args_len(pesapi_callback_info pinfo) +{ + auto info = reinterpret_cast*>(pinfo); + return (*info).Length(); +} + +pesapi_value pesapi_get_arg(pesapi_callback_info pinfo, int index) +{ + auto info = reinterpret_cast*>(pinfo); + return v8impl::PesapiValueFromV8LocalValue((*info)[index]); +} + +PESAPI_EXTERN pesapi_env pesapi_get_env(pesapi_callback_info pinfo) +{ + auto info = reinterpret_cast*>(pinfo); + return v8impl::PesapiEnvFromV8LocalContext((*info).GetIsolate()->GetCurrentContext()); +} + +pesapi_value pesapi_get_this(pesapi_callback_info pinfo) +{ + auto info = reinterpret_cast*>(pinfo); + return v8impl::PesapiValueFromV8LocalValue((*info).This()); +} + +pesapi_value pesapi_get_holder(pesapi_callback_info pinfo) +{ + auto info = reinterpret_cast*>(pinfo); + return v8impl::PesapiValueFromV8LocalValue((*info).Holder()); +} + +void* pesapi_get_userdata(pesapi_callback_info pinfo) +{ + auto info = reinterpret_cast*>(pinfo); + return *(static_cast(v8::Local::Cast((*info).Data())->Value())); +} + +void pesapi_add_return(pesapi_callback_info pinfo, pesapi_value value) +{ + auto info = reinterpret_cast*>(pinfo); + (*info).GetReturnValue().Set(v8impl::V8LocalValueFromPesapiValue(value)); +} + +void pesapi_throw_by_string(pesapi_callback_info pinfo, const char* msg) +{ + auto info = reinterpret_cast*>(pinfo); + v8::Isolate* isolate = info->GetIsolate(); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, msg, v8::NewStringType::kNormal).ToLocalChecked())); +} + +pesapi_env_ref pesapi_create_env_ref(pesapi_env env) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + return new pesapi_env_ref__(context); +} + +bool pesapi_env_ref_is_valid(pesapi_env_ref env_ref) +{ + return !env_ref->env_life_cycle_tracker.expired(); +} + +pesapi_env pesapi_get_env_from_ref(pesapi_env_ref env_ref) +{ + if (env_ref->env_life_cycle_tracker.expired()) + { + return nullptr; + } + return v8impl::PesapiEnvFromV8LocalContext(env_ref->context_persistent.Get(env_ref->isolate)); +} + +pesapi_env_ref pesapi_duplicate_env_ref(pesapi_env_ref env_ref) +{ + ++env_ref->ref_count; + return env_ref; +} + +void pesapi_release_env_ref(pesapi_env_ref env_ref) +{ + if (--env_ref->ref_count == 0) + { + if (env_ref->env_life_cycle_tracker.expired()) + { +#if V8_MAJOR_VERSION < 11 + env_ref->context_persistent.Empty(); + delete env_ref; +#else + ::operator delete(static_cast(env_ref)); +#endif + } + else + { + delete env_ref; + } + } +} + +pesapi_scope pesapi_open_scope(pesapi_env_ref env_ref) +{ + if (env_ref->env_life_cycle_tracker.expired()) + { + return nullptr; + } + env_ref->isolate->Enter(); + auto scope = new pesapi_scope__(env_ref->isolate); + env_ref->context_persistent.Get(env_ref->isolate)->Enter(); + return scope; +} + +pesapi_scope pesapi_open_scope_placement(pesapi_env_ref env_ref, struct pesapi_scope_memory* memory) +{ + if (env_ref->env_life_cycle_tracker.expired()) + { + return nullptr; + } + env_ref->isolate->Enter(); + auto scope = new (memory) pesapi_scope__(env_ref->isolate); + env_ref->context_persistent.Get(env_ref->isolate)->Enter(); + return scope; +} + +bool pesapi_has_caught(pesapi_scope scope) +{ + return scope && scope->trycatch.HasCaught(); +} + +const char* pesapi_get_exception_as_string(pesapi_scope scope, bool with_stack) +{ + if (!scope) + return nullptr; + scope->errinfo = *v8::String::Utf8Value(scope->scope.GetIsolate(), scope->trycatch.Exception()); + if (with_stack) + { + auto isolate = scope->scope.GetIsolate(); + v8::Local context(isolate->GetCurrentContext()); + v8::Local message = scope->trycatch.Message(); + + // 输出 (filename):(line number): (message). + std::ostringstream stm; + v8::String::Utf8Value fileName(isolate, message->GetScriptResourceName()); + int lineNum = message->GetLineNumber(context).FromJust(); + stm << *fileName << ":" << lineNum << ": " << scope->errinfo.c_str(); + + stm << std::endl; + + // 输出调用栈信息 + v8::Local stackTrace; + if (scope->trycatch.StackTrace(context).ToLocal(&stackTrace)) + { + v8::String::Utf8Value stackTraceVal(isolate, stackTrace); + stm << std::endl << *stackTraceVal; + } + scope->errinfo = stm.str().c_str(); + } + return scope->errinfo.c_str(); +} + +void pesapi_close_scope(pesapi_scope scope) +{ + if (!scope) + return; + auto isolate = scope->scope.GetIsolate(); + isolate->GetCurrentContext()->Exit(); + delete (scope); + isolate->Exit(); +} + +void pesapi_close_scope_placement(pesapi_scope scope) +{ + if (!scope) + return; + auto isolate = scope->scope.GetIsolate(); + isolate->GetCurrentContext()->Exit(); + scope->~pesapi_scope__(); + isolate->Exit(); +} + +pesapi_value_ref pesapi_create_value_ref(pesapi_env env, pesapi_value pvalue, uint32_t internal_field_count) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + size_t totalSize = sizeof(pesapi_value_ref__) + sizeof(void*) * internal_field_count; + void* buffer = ::operator new(totalSize); + return new (buffer) pesapi_value_ref__(context, value, internal_field_count); +} + +pesapi_value_ref pesapi_duplicate_value_ref(pesapi_value_ref value_ref) +{ + ++value_ref->ref_count; + return value_ref; +} + +void pesapi_release_value_ref(pesapi_value_ref value_ref) +{ + if (--value_ref->ref_count == 0) + { + if (!value_ref->env_life_cycle_tracker.expired()) + { + value_ref->~pesapi_value_ref__(); + } + ::operator delete(static_cast(value_ref)); + } +} + +pesapi_value pesapi_get_value_from_ref(pesapi_env env, pesapi_value_ref value_ref) +{ + return v8impl::PesapiValueFromV8LocalValue(value_ref->value_persistent.Get(value_ref->isolate)); +} + +void pesapi_set_ref_weak(pesapi_env env, pesapi_value_ref value_ref) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + value_ref->value_persistent.SetWeak(); +} + +bool pesapi_set_owner(pesapi_env env, pesapi_value pvalue, pesapi_value powner) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + auto owner = v8impl::V8LocalValueFromPesapiValue(powner); + + if (owner->IsObject()) + { + auto jsObj = owner.template As(); +#if V8_MAJOR_VERSION < 8 + jsObj->Set(context, v8::String::NewFromUtf8(context->GetIsolate(), "_p_i_only_one_child").ToLocalChecked(), value).Check(); +#else + jsObj->Set(context, v8::String::NewFromUtf8Literal(context->GetIsolate(), "_p_i_only_one_child"), value).Check(); +#endif + return true; + } + return false; +} + +pesapi_env_ref pesapi_get_ref_associated_env(pesapi_value_ref value_ref) +{ + return value_ref; +} + +void** pesapi_get_ref_internal_fields(pesapi_value_ref value_ref, uint32_t* pinternal_field_count) +{ + *pinternal_field_count = value_ref->internal_field_count; + return &value_ref->internal_fields[0]; +} + +pesapi_value pesapi_get_property(pesapi_env env, pesapi_value pobject, const char* key) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto object = v8impl::V8LocalValueFromPesapiValue(pobject); + if (object->IsObject()) + { + auto MaybeValue = object.As()->Get( + context, v8::String::NewFromUtf8(context->GetIsolate(), key, v8::NewStringType::kNormal).ToLocalChecked()); + v8::Local Val; + if (MaybeValue.ToLocal(&Val)) + { + return v8impl::PesapiValueFromV8LocalValue(Val); + } + } + return pesapi_create_undefined(env); +} + +void pesapi_set_property(pesapi_env env, pesapi_value pobject, const char* key, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto object = v8impl::V8LocalValueFromPesapiValue(pobject); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + + if (object->IsObject()) + { + auto _un_used = object.As()->Set( + context, v8::String::NewFromUtf8(context->GetIsolate(), key, v8::NewStringType::kNormal).ToLocalChecked(), value); + } +} + +bool pesapi_get_private(pesapi_env env, pesapi_value pobject, void** out_ptr) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto object = v8impl::V8LocalValueFromPesapiValue(pobject); + if (object.IsEmpty() || !object->IsObject()) + { + *out_ptr = nullptr; + return false; + } + *out_ptr = puerts::DataTransfer::IsolateData(context->GetIsolate()) + ->GetPrivateData(context, object.As()); + return true; +} + +bool pesapi_set_private(pesapi_env env, pesapi_value pobject, void* ptr) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto object = v8impl::V8LocalValueFromPesapiValue(pobject); + if (object.IsEmpty() || !object->IsObject()) + { + return false; + } + puerts::DataTransfer::IsolateData(context->GetIsolate()) + ->SetPrivateData(context, object.As(), ptr); + return true; +} + +pesapi_value pesapi_get_property_uint32(pesapi_env env, pesapi_value pobject, uint32_t key) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto object = v8impl::V8LocalValueFromPesapiValue(pobject); + if (object->IsObject()) + { + auto MaybeValue = object.As()->Get(context, key); + v8::Local Val; + if (MaybeValue.ToLocal(&Val)) + { + return v8impl::PesapiValueFromV8LocalValue(Val); + } + } + return pesapi_create_undefined(env); +} + +void pesapi_set_property_uint32(pesapi_env env, pesapi_value pobject, uint32_t key, pesapi_value pvalue) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto object = v8impl::V8LocalValueFromPesapiValue(pobject); + auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); + + if (object->IsObject()) + { + auto _un_used = object.As()->Set(context, key, value); + } +} + +pesapi_value pesapi_call_function(pesapi_env env, pesapi_value pfunc, pesapi_value this_object, int argc, const pesapi_value argv[]) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + v8::Local recv = v8::Undefined(context->GetIsolate()); + if (this_object) + { + recv = v8impl::V8LocalValueFromPesapiValue(this_object); + } + v8::Local func = v8impl::V8LocalValueFromPesapiValue(pfunc).As(); + + auto maybe_ret = func->Call(context, recv, argc, reinterpret_cast*>(const_cast(argv))); + if (maybe_ret.IsEmpty()) + { + return nullptr; + } + return v8impl::PesapiValueFromV8LocalValue(maybe_ret.ToLocalChecked()); +} + +pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size, const char* path) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto isolate = context->GetIsolate(); + v8::Local url = + v8::String::NewFromUtf8(isolate, path == nullptr ? "" : path, v8::NewStringType::kNormal).ToLocalChecked(); + std::vector buff; + buff.reserve(code_size + 1); + memcpy(buff.data(), code, code_size); + buff.data()[code_size] = '\0'; + v8::Local source = v8::String::NewFromUtf8(isolate, buff.data(), v8::NewStringType::kNormal).ToLocalChecked(); +#if V8_MAJOR_VERSION > 8 + v8::ScriptOrigin origin(isolate, url); +#else + v8::ScriptOrigin origin(url); +#endif + + auto CompiledScript = v8::Script::Compile(context, source, &origin); + if (CompiledScript.IsEmpty()) + { + return nullptr; + } + auto maybe_ret = CompiledScript.ToLocalChecked()->Run(context); + if (maybe_ret.IsEmpty()) + { + return nullptr; + } + return v8impl::PesapiValueFromV8LocalValue(maybe_ret.ToLocalChecked()); +} + +pesapi_value pesapi_global(pesapi_env env) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + auto global = context->Global(); + return v8impl::PesapiValueFromV8LocalValue(global); +} + +const void* pesapi_get_env_private(pesapi_env env) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + return puerts::DataTransfer::GetIsolatePrivateData(context->GetIsolate()); +} + +void pesapi_set_env_private(pesapi_env env, const void* ptr) +{ + auto context = v8impl::V8LocalContextFromPesapiEnv(env); + puerts::DataTransfer::SetIsolatePrivateData(context->GetIsolate(), const_cast(ptr)); +} + +pesapi_ffi g_pesapi_ffi { + &pesapi_create_null, + &pesapi_create_undefined, + &pesapi_create_boolean, + &pesapi_create_int32, + &pesapi_create_uint32, + &pesapi_create_int64, + &pesapi_create_uint64, + &pesapi_create_double, + &pesapi_create_string_utf8, + &pesapi_create_binary, + &pesapi_create_array, + &pesapi_create_object, + &pesapi_create_function, + &pesapi_create_class, + &pesapi_get_value_bool, + &pesapi_get_value_int32, + &pesapi_get_value_uint32, + &pesapi_get_value_int64, + &pesapi_get_value_uint64, + &pesapi_get_value_double, + &pesapi_get_value_string_utf8, + &pesapi_get_value_binary, + &pesapi_get_array_length, + &pesapi_is_null, + &pesapi_is_undefined, + &pesapi_is_boolean, + &pesapi_is_int32, + &pesapi_is_uint32, + &pesapi_is_int64, + &pesapi_is_uint64, + &pesapi_is_double, + &pesapi_is_string, + &pesapi_is_object, + &pesapi_is_function, + &pesapi_is_binary, + &pesapi_is_array, + &pesapi_native_object_to_value, + &pesapi_get_native_object_ptr, + &pesapi_get_native_object_typeid, + &pesapi_is_instance_of, + &pesapi_boxing, + &pesapi_unboxing, + &pesapi_update_boxed_value, + &pesapi_is_boxed_value, + &pesapi_get_args_len, + &pesapi_get_arg, + &pesapi_get_env, + &pesapi_get_this, + &pesapi_get_holder, + &pesapi_get_userdata, + &pesapi_add_return, + &pesapi_throw_by_string, + &pesapi_create_env_ref, + &pesapi_env_ref_is_valid, + &pesapi_get_env_from_ref, + &pesapi_duplicate_env_ref, + &pesapi_release_env_ref, + &pesapi_open_scope, + &pesapi_open_scope_placement, + &pesapi_has_caught, + &pesapi_get_exception_as_string, + &pesapi_close_scope, + &pesapi_close_scope_placement, + &pesapi_create_value_ref, + &pesapi_duplicate_value_ref, + &pesapi_release_value_ref, + &pesapi_get_value_from_ref, + &pesapi_set_ref_weak, + &pesapi_set_owner, + &pesapi_get_ref_associated_env, + &pesapi_get_ref_internal_fields, + &pesapi_get_property, + &pesapi_set_property, + &pesapi_get_private, + &pesapi_set_private, + &pesapi_get_property_uint32, + &pesapi_set_property_uint32, + &pesapi_call_function, + &pesapi_eval, + &pesapi_global, + &pesapi_get_env_private, + &pesapi_set_env_private +}; +*/ +} // namespace qjsimpl From bbe2ce57eb0c7e9b78b68248ee48d1adba4ac470 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 24 Jan 2025 16:20:11 +0800 Subject: [PATCH 02/70] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 212 ++++++++++++++++++------------------- 1 file changed, 101 insertions(+), 111 deletions(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 6a7d565..5f39911 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -29,6 +29,14 @@ struct pesapi_env_ref__ eastl::weak_ptr env_life_cycle_tracker; }; +struct pesapi_value__ { + explicit pesapi_value__(JSValue jsvalue) + : v(jsvalue) + { + } + JSValue v; +}; + struct pesapi_value_ref__ : pesapi_env_ref__ { explicit pesapi_value_ref__(JSContext *ctx, JSValue v, uint32_t field_count) @@ -156,10 +164,72 @@ JSValue literal_values_null = JS_NULL; JSValue literal_values_true = JS_TRUE; JSValue literal_values_false = JS_FALSE; +template +pesapi_value pesapi_create_generic0(pesapi_env env, Func createFunc) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret) + { + *ret = createFunc(ctx); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} + +template +pesapi_value pesapi_create_generic1(pesapi_env env, T value, Func createFunc) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret) + { + *ret = createFunc(ctx, value); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} + +template +pesapi_value pesapi_create_generic2(pesapi_env env, T1 v1, T2 v2, Func createFunc) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx) + { + auto ret = allocValueInCurrentScope(ctx); + if (ret) + { + *ret = createFunc(ctx, v1, v2); + return pesapiValueFromQjsValue(ret); + } + } + return nullptr; +} + +template +T pesapi_get_value_generic(pesapi_env env, pesapi_value pvalue, Func convertFunc) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx != nullptr) + { + T ret = 0; + convertFunc(ctx, &ret, pvalue->v); + return ret; + } + return 0; +} + + // value process pesapi_value pesapi_create_null(pesapi_env env) { - return pesapiValueFromQjsValue(&literal_values_null); + return pesapiValueFromQjsValue(&literal_values_null); //避免在Scope上分配 } pesapi_value pesapi_create_undefined(pesapi_env env) @@ -174,127 +244,52 @@ pesapi_value pesapi_create_boolean(pesapi_env env, bool value) pesapi_value pesapi_create_int32(pesapi_env env, int32_t value) { - auto ctx = qjsContextFromPesapiEnv(env); - if (ctx) - { - auto ret = allocValueInCurrentScope(ctx); - if (ret) - { - *ret = JS_NewInt32(ctx, value); - return pesapiValueFromQjsValue(ret); - } - } - return nullptr; + return pesapi_create_generic1(env, value, JS_NewInt32); } pesapi_value pesapi_create_uint32(pesapi_env env, uint32_t value) { - auto ctx = qjsContextFromPesapiEnv(env); - if (ctx) - { - auto ret = allocValueInCurrentScope(ctx); - if (ret) - { - *ret = JS_NewUint32(ctx, value); - return pesapiValueFromQjsValue(ret); - } - } - return nullptr; + return pesapi_create_generic1(env, value, JS_NewUint32); } pesapi_value pesapi_create_int64(pesapi_env env, int64_t value) { - auto ctx = qjsContextFromPesapiEnv(env); - if (ctx) - { - auto ret = allocValueInCurrentScope(ctx); - if (ret) - { - *ret = JS_NewInt64(ctx, value); - return pesapiValueFromQjsValue(ret); - } - } - return nullptr; + return pesapi_create_generic1(env, value, JS_NewInt64); } pesapi_value pesapi_create_uint64(pesapi_env env, uint64_t value) { - return pesapi_create_int64(env, value); + return pesapi_create_generic1(env, value, JS_NewInt64); } pesapi_value pesapi_create_double(pesapi_env env, double value) { - auto ctx = qjsContextFromPesapiEnv(env); - if (ctx) - { - auto ret = allocValueInCurrentScope(ctx); - if (ret) - { - *ret = JS_NewFloat64(ctx, value); - return pesapiValueFromQjsValue(ret); - } - } - return nullptr; + return pesapi_create_generic1(env, value, JS_NewFloat64); } -pesapi_value pesapi_create_string_utf8(pesapi_env env, const char* str, size_t length) +pesapi_value pesapi_create_string_utf8(pesapi_env env, const char *str, size_t length) { - auto ctx = qjsContextFromPesapiEnv(env); - if (str && ctx) - { - auto ret = allocValueInCurrentScope(ctx); - if (ret && str) - { - *ret = JS_NewStringLen(ctx, str, length); - return pesapiValueFromQjsValue(ret); - } - } - return nullptr; + return pesapi_create_generic2(env, str, length, JS_NewStringLen); } -pesapi_value pesapi_create_binary(pesapi_env env, void* bin, size_t length) +static JSValue JS_NewArrayBufferWrap(JSContext *ctx, void *bin, size_t len) { - auto ctx = qjsContextFromPesapiEnv(env); - if (bin && ctx) - { - auto ret = allocValueInCurrentScope(ctx); - if (ret) - { - *ret = JS_NewArrayBuffer(ctx, (uint8_t *) bin, length, nullptr, nullptr, false); - return pesapiValueFromQjsValue(ret); - } - } - return nullptr; + return JS_NewArrayBuffer(ctx, (uint8_t *) bin, len, nullptr, nullptr, false); +} + +pesapi_value pesapi_create_binary(pesapi_env env, void *bin, size_t length) +{ + return pesapi_create_generic2(env, bin, length, JS_NewArrayBufferWrap); } pesapi_value pesapi_create_array(pesapi_env env) { - auto ctx = qjsContextFromPesapiEnv(env); - if (ctx) - { - auto ret = allocValueInCurrentScope(ctx); - if (ret) - { - *ret = JS_NewArray(ctx); - return pesapiValueFromQjsValue(ret); - } - } - return nullptr; + return pesapi_create_generic0(env, JS_NewArray); } pesapi_value pesapi_create_object(pesapi_env env) { - auto ctx = qjsContextFromPesapiEnv(env); - if (ctx) - { - auto ret = allocValueInCurrentScope(ctx); - if (ret) - { - *ret = JS_NewObject(ctx); - return pesapiValueFromQjsValue(ret); - } - } - return nullptr; + return pesapi_create_generic0(env, JS_NewObject); } /* pesapi_value pesapi_create_function(pesapi_env env, pesapi_callback native_impl, void* data, pesapi_function_finalize finalize) @@ -314,49 +309,44 @@ pesapi_value pesapi_create_class(pesapi_env env, const void* type_id) return nullptr; return v8impl::PesapiValueFromV8LocalValue(cls.ToLocalChecked()); } +*/ bool pesapi_get_value_bool(pesapi_env env, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->BooleanValue(context->GetIsolate()); + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx != nullptr) + { + return JS_ToBool(ctx, pvalue->v); + } + return false; } int32_t pesapi_get_value_int32(pesapi_env env, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->Int32Value(context).ToChecked(); + return pesapi_get_value_generic(env, pvalue, JS_ToInt32); } uint32_t pesapi_get_value_uint32(pesapi_env env, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->Uint32Value(context).ToChecked(); + return pesapi_get_value_generic(env, pvalue, JS_ToUint32); } -int64_t pesapi_get_value_int64(pesapi_env env, pesapi_value pvalue) +int64_t pesapi_get_value_int64(pesapi_env env, pesapi_value pvalue) // TODO: 得用Bigint?? { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsBigInt() ? value->ToBigInt(context).ToLocalChecked()->Int64Value() : 0; + return pesapi_get_value_generic(env, pvalue, JS_ToInt64); } uint64_t pesapi_get_value_uint64(pesapi_env env, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsBigInt() ? value->ToBigInt(context).ToLocalChecked()->Uint64Value() : 0; + return (uint64_t)pesapi_get_value_int64(env, pvalue); } double pesapi_get_value_double(pesapi_env env, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->NumberValue(context).ToChecked(); + return pesapi_get_value_generic(env, pvalue, JS_ToFloat64); } +/* const char* pesapi_get_value_string_utf8(pesapi_env env, pesapi_value pvalue, char* buf, size_t* bufsize) { auto context = v8impl::V8LocalContextFromPesapiEnv(env); From ef792d6450dc6d0958a9b322d40e11b4961facf8 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 24 Jan 2025 16:38:13 +0800 Subject: [PATCH 03/70] =?UTF-8?q?=E6=94=B9=E4=B8=BA=E7=94=A8bigint?= =?UTF-8?q?=E6=9D=A5=E6=94=AF=E6=8C=8164=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 5f39911..d079005 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -254,12 +254,12 @@ pesapi_value pesapi_create_uint32(pesapi_env env, uint32_t value) pesapi_value pesapi_create_int64(pesapi_env env, int64_t value) { - return pesapi_create_generic1(env, value, JS_NewInt64); + return pesapi_create_generic1(env, value, JS_NewBigInt64); } pesapi_value pesapi_create_uint64(pesapi_env env, uint64_t value) { - return pesapi_create_generic1(env, value, JS_NewInt64); + return pesapi_create_generic1(env, value, JS_NewBigUint64); } pesapi_value pesapi_create_double(pesapi_env env, double value) @@ -331,14 +331,14 @@ uint32_t pesapi_get_value_uint32(pesapi_env env, pesapi_value pvalue) return pesapi_get_value_generic(env, pvalue, JS_ToUint32); } -int64_t pesapi_get_value_int64(pesapi_env env, pesapi_value pvalue) // TODO: 得用Bigint?? +int64_t pesapi_get_value_int64(pesapi_env env, pesapi_value pvalue) { - return pesapi_get_value_generic(env, pvalue, JS_ToInt64); + return pesapi_get_value_generic(env, pvalue, JS_ToBigInt64); } uint64_t pesapi_get_value_uint64(pesapi_env env, pesapi_value pvalue) { - return (uint64_t)pesapi_get_value_int64(env, pvalue); + return pesapi_get_value_generic(env, pvalue, JS_ToBigUint64); } double pesapi_get_value_double(pesapi_env env, pesapi_value pvalue) From b89e613a517d0010ee6399a6371494217ad30e11 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 7 Feb 2025 15:26:29 +0800 Subject: [PATCH 04/70] =?UTF-8?q?=E6=8A=8Apesapi=5Fget=5Fvalue=5Fbool?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E7=94=A8pesapi=5Fget=5Fvalue=5Fgeneric?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index d079005..da8c7b0 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -311,14 +311,19 @@ pesapi_value pesapi_create_class(pesapi_env env, const void* type_id) } */ -bool pesapi_get_value_bool(pesapi_env env, pesapi_value pvalue) +int JS_ToBool2(JSContext *ctx, bool *pres, JSValue val) { - auto ctx = qjsContextFromPesapiEnv(env); - if (ctx != nullptr) + int res = JS_ToBool(ctx, val); + if (res != -1) { - return JS_ToBool(ctx, pvalue->v); + *pres = (bool)res; } - return false; + return res; +} + +bool pesapi_get_value_bool(pesapi_env env, pesapi_value pvalue) +{ + return pesapi_get_value_generic(env, pvalue, JS_ToBool2); } int32_t pesapi_get_value_int32(pesapi_env env, pesapi_value pvalue) From 87e67b3022d9215313ecf7b6bc82a48b24b82d99 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 7 Feb 2025 16:39:34 +0800 Subject: [PATCH 05/70] =?UTF-8?q?=E5=AE=9E=E7=8E=B0pesapi=5Fget=5Fvalue=5F?= =?UTF-8?q?string=5Futf8=E3=80=81pesapi=5Fget=5Fvalue=5Fbinary=E3=80=81pes?= =?UTF-8?q?api=5Fget=5Farray=5Flength=E4=BB=A5=E5=8F=8Apesapi=5Fis=5Fxxx?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- quickjs/quickjs.c | 66 ++++++++++++++ quickjs/quickjs.h | 13 +++ source/PapiQuickjsImpl.cpp | 170 +++++++++++++++++++++++-------------- 3 files changed, 184 insertions(+), 65 deletions(-) diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c index 900dec4..7923022 100644 --- a/quickjs/quickjs.c +++ b/quickjs/quickjs.c @@ -55828,3 +55828,69 @@ uintptr_t js_std_cmd(int cmd, ...) { #undef malloc #undef free #undef realloc + +/*-------begin additional function---------*/ + +JS_BOOL JS_IsArrayBufferView(JSValueConst obj) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + { + return FALSE; + } + p = JS_VALUE_GET_OBJ(obj); + return JS_CLASS_DATAVIEW == p->class_id || (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY); +} + +JSValue JS_GetArrayBufferView(JSContext *ctx, JSValueConst obj) +{ + JSObject *p; + JSTypedArray *ta; + + if (!JS_IsArrayBufferView(obj)) { + JS_ThrowTypeError(ctx, "not a ArrayBufferView"); + return JS_UNDEFINED; + } + p = JS_VALUE_GET_OBJ(obj); + + p = get_typed_array(ctx, obj); + if (!p) + return JS_EXCEPTION; + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + ta = p->u.typed_array; + return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)); +} + +JS_BOOL JS_GetArrayBufferViewInfo(JSContext *ctx, JSValueConst obj, + size_t *pbyte_offset, + size_t *pbyte_length, + size_t *pbytes_per_element) +{ + JSObject *p; + JSTypedArray *ta; + + if (!JS_IsArrayBufferView(obj)) { + JS_ThrowTypeError(ctx, "not a ArrayBufferView"); + return FALSE; + } + p = JS_VALUE_GET_OBJ(obj); + + p = get_typed_array(ctx, obj); + + if (!p) + return FALSE; + if (typed_array_is_oob(p)) + return FALSE; + ta = p->u.typed_array; + if (pbyte_offset) + *pbyte_offset = ta->offset; + if (pbyte_length) + *pbyte_length = ta->length; + if (pbytes_per_element) { + *pbytes_per_element = 1 << typed_array_size_log2(p->class_id); + } + return TRUE; +} + +/*-------end additional function---------*/ diff --git a/quickjs/quickjs.h b/quickjs/quickjs.h index 482ebb1..dfefc06 100644 --- a/quickjs/quickjs.h +++ b/quickjs/quickjs.h @@ -1038,6 +1038,19 @@ JS_EXTERN uintptr_t js_std_cmd(int cmd, ...); #undef js_force_inline #undef __js_printf_like +/*-------begin additional function---------*/ + +JS_BOOL JS_IsArrayBufferView(JSValueConst obj); + +JSValue JS_GetArrayBufferView(JSContext *ctx, JSValueConst obj); + +JS_BOOL JS_GetArrayBufferViewInfo(JSContext *ctx, JSValueConst obj, + size_t *pbyte_offset, + size_t *pbyte_length, + size_t *pbytes_per_element); + +/*-------end additional function---------*/ + #ifdef __cplusplus } /* extern "C" { */ #endif diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index da8c7b0..1ae313d 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -10,6 +10,15 @@ void GetPapiQuickjsImpl() eastl::basic_string str = "hello world"; } +enum +{ + JS_ATOM_NULL_, +#define DEF(name, str) JS_ATOM_##name, +#include "quickjs-atom.h" +#undef DEF + JS_ATOM_END, +}; + struct pesapi_env_ref__ { explicit pesapi_env_ref__(JSContext *ctx) @@ -225,6 +234,27 @@ T pesapi_get_value_generic(pesapi_env env, pesapi_value pvalue, Func convertFunc return 0; } +template +bool pesapi_is_generic(pesapi_env env, pesapi_value pvalue, Func convertFunc) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx != nullptr) + { + return convertFunc(pvalue->v); + } + return false; +} + +template +bool pesapi_is_generic_ctx(pesapi_env env, pesapi_value pvalue, Func convertFunc) +{ + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx != nullptr) + { + return convertFunc(ctx, pvalue->v); + } + return false; +} // value process pesapi_value pesapi_create_null(pesapi_env env) @@ -351,134 +381,144 @@ double pesapi_get_value_double(pesapi_env env, pesapi_value pvalue) return pesapi_get_value_generic(env, pvalue, JS_ToFloat64); } -/* + const char* pesapi_get_value_string_utf8(pesapi_env env, pesapi_value pvalue, char* buf, size_t* bufsize) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - - if (buf == nullptr) - { - auto str = value->ToString(context).ToLocalChecked(); - *bufsize = str->Utf8Length(context->GetIsolate()); - } - else - { - auto str = value->ToString(context).ToLocalChecked(); - str->WriteUtf8(context->GetIsolate(), buf, *bufsize); - } - return buf; + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx != nullptr) + { + if (buf == nullptr) + { + auto ret = JS_ToCString(ctx, pvalue->v); // TODO: 优化 + if (ret) + { + *bufsize = strlen(ret); + JS_FreeCString(ctx, ret); + } + } + else + { + auto ret = JS_ToCStringLen(ctx, bufsize, pvalue->v); + if (ret) + { + strcpy(buf, ret); + JS_FreeCString(ctx, ret); + } + } + } + return buf; } void* pesapi_get_value_binary(pesapi_env env, pesapi_value pvalue, size_t* bufsize) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - - if (value->IsArrayBufferView()) - { - v8::Local buffView = value.As(); - *bufsize = buffView->ByteLength(); - auto Ab = buffView->Buffer(); - return static_cast(puerts::DataTransfer::GetArrayBufferData(Ab)) + buffView->ByteOffset(); - } - if (value->IsArrayBuffer()) - { - auto ab = v8::Local::Cast(value); - return puerts::DataTransfer::GetArrayBufferData(ab, *bufsize); - } - return nullptr; + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx != nullptr) + { + if (JS_IsArrayBuffer(pvalue->v)) + { + return JS_GetArrayBuffer(ctx, bufsize, pvalue->v); + } + if (JS_IsArrayBufferView(pvalue->v)) + { + size_t byte_offset; + size_t byte_length; + size_t bytes_per_element; + JS_GetArrayBufferViewInfo(ctx, pvalue->v, &byte_offset, &byte_length, &bytes_per_element); + JSValue ab = JS_GetArrayBufferView(ctx, pvalue->v); + uint8_t* buf = JS_GetArrayBuffer(ctx, bufsize, ab); + JS_FreeValue(ctx, ab); + *bufsize = byte_length; + return buf + byte_offset; + } + } + return nullptr; } uint32_t pesapi_get_array_length(pesapi_env env, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - if (value->IsArray()) - { - return value.As()->Length(); - } - return 0; + auto ctx = qjsContextFromPesapiEnv(env); + if (ctx != nullptr) + { + auto len = JS_GetProperty(ctx, pvalue->v, JS_ATOM_length); + if (JS_IsException(len)) + { + return 0; + } + uint32_t ret; + JS_ToUint32(ctx, &ret, len); + JS_FreeValue(ctx, len); + return ret; + } + return 0; } bool pesapi_is_null(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsNull(); + return pesapi_is_generic(env, pvalue, JS_IsNull); } bool pesapi_is_undefined(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsUndefined(); + return pesapi_is_generic(env, pvalue, JS_IsUndefined); } bool pesapi_is_boolean(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsBoolean(); + return pesapi_is_generic(env, pvalue, JS_IsBool); } bool pesapi_is_int32(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsInt32(); + return pesapi_is_generic(env, pvalue, JS_IsNumber); } bool pesapi_is_uint32(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsUint32(); + return pesapi_is_generic(env, pvalue, JS_IsNumber); } bool pesapi_is_int64(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsBigInt(); + return pesapi_is_generic_ctx(env, pvalue, JS_IsBigInt); } bool pesapi_is_uint64(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsBigInt(); + return pesapi_is_generic_ctx(env, pvalue, JS_IsBigInt); } bool pesapi_is_double(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsNumber(); + return pesapi_is_generic(env, pvalue, JS_IsNumber); } bool pesapi_is_string(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsString(); + return pesapi_is_generic(env, pvalue, JS_IsString); } bool pesapi_is_object(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsObject(); + return pesapi_is_generic(env, pvalue, JS_IsObject); } bool pesapi_is_function(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsFunction(); + return pesapi_is_generic_ctx(env, pvalue, JS_IsFunction); } bool pesapi_is_binary(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsArrayBuffer() || value->IsArrayBufferView(); + return pesapi_is_generic(env, pvalue, [](JSValue val) -> JS_BOOL { + return JS_IsArrayBuffer(val) || JS_IsArrayBufferView(val); + }); } bool pesapi_is_array(pesapi_env env, pesapi_value pvalue) { - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return value->IsArray(); + return pesapi_is_generic_ctx(env, pvalue, JS_IsArray); } - +/* pesapi_value pesapi_native_object_to_value(pesapi_env env, const void* type_id, void* object_ptr, bool call_finalize) { auto context = v8impl::V8LocalContextFromPesapiEnv(env); From c52105620c1527a48232508d47badd83a72c9589 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 18 Feb 2025 11:08:14 +0800 Subject: [PATCH 06/70] =?UTF-8?q?window=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 12f816f..1cc5835 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,5 +156,5 @@ target_link_libraries(PapiQjs PUBLIC ${qjs_libs}) target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2024_APRIL=EA_DISABLED) target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2024_SEPT=EA_DISABLED) target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2025_APRIL=EA_DISABLED) -target_compile_definitions(PapiQjs PUBLIC EASTL_DLL) +#target_compile_definitions(PapiQjs PUBLIC EASTL_DLL) From 1c0dc1b1fcdfdc7d27196811adf7af9918745a9d Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 18 Feb 2025 15:07:08 +0800 Subject: [PATCH 07/70] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E6=80=A7=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 1 + include/CppObjectMapper.h | 23 ++++++ include/JSClassRegister.h | 27 ++++--- include/NamespaceDef.h | 15 ++++ include/ObjectCacheNode.h | 138 +++++++++++++++++++++++++++++++++++ include/PuertsNamespaceDef.h | 79 ++++++++++++++++++++ source/CppObjectMapper.cpp | 9 +++ source/PapiQuickjsImpl.cpp | 13 +++- 8 files changed, 287 insertions(+), 18 deletions(-) create mode 100644 include/CppObjectMapper.h create mode 100644 include/NamespaceDef.h create mode 100644 include/ObjectCacheNode.h create mode 100644 include/PuertsNamespaceDef.h create mode 100644 source/CppObjectMapper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cc5835..ed96956 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,4 +157,5 @@ target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2024_APRIL=EA_DISA target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2024_SEPT=EA_DISABLED) target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2025_APRIL=EA_DISABLED) #target_compile_definitions(PapiQjs PUBLIC EASTL_DLL) +target_compile_definitions(PapiQjs PUBLIC USING_REGISTER_API_SHARED) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h new file mode 100644 index 0000000..89bf13d --- /dev/null +++ b/include/CppObjectMapper.h @@ -0,0 +1,23 @@ +#pragma once + +#include "pesapi.h" +#include "quickjs.h" +#include +#include +#include "ObjectCacheNode.h" + +namespace puerts +{ +namespace qjsimpl +{ + +class CppObjectMapper +{ +public: +private: + eastl::unordered_map, eastl::equal_to, eastl::allocator_malloc> CDataCache; + eastl::unordered_map, eastl::equal_to, eastl::allocator_malloc> TypeIdToFunctionMap; +}; + +} // namespace qjsimpl +} // namespace puerts \ No newline at end of file diff --git a/include/JSClassRegister.h b/include/JSClassRegister.h index 9d1ab06..0d2f7ea 100644 --- a/include/JSClassRegister.h +++ b/include/JSClassRegister.h @@ -19,7 +19,6 @@ PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS #pragma warning(pop) PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS #else -#define JSENV_API #define FORCEINLINE V8_INLINE #define UPTRINT uintptr_t #endif @@ -42,7 +41,7 @@ class CFunctionInfo; MSVC_PRAGMA(warning(push)) MSVC_PRAGMA(warning(disable : 4191)) -struct JSENV_API JSFunctionInfo +struct REGISTER_API JSFunctionInfo { JSFunctionInfo() : Name(nullptr), Callback(nullptr) { @@ -67,7 +66,7 @@ struct JSENV_API JSFunctionInfo const CFunctionInfo* ReflectionInfo = nullptr; }; -struct JSENV_API JSPropertyInfo +struct REGISTER_API JSPropertyInfo { JSPropertyInfo() : Name(nullptr), Getter(nullptr), Setter(nullptr) { @@ -100,7 +99,7 @@ struct JSENV_API JSPropertyInfo struct NamedFunctionInfo; struct NamedPropertyInfo; -struct JSENV_API JSClassDefinition +struct REGISTER_API JSClassDefinition { const void* TypeId; const void* SuperTypeId; @@ -134,22 +133,22 @@ MSVC_PRAGMA(warning(pop)) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ } -void JSENV_API RegisterJSClass(const JSClassDefinition& ClassDefinition); +void REGISTER_API RegisterJSClass(const JSClassDefinition& ClassDefinition); -void JSENV_API SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos, +void REGISTER_API SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos, const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, const NamedPropertyInfo* VariableInfos); -void JSENV_API ForeachRegisterClass(std::function); +void REGISTER_API ForeachRegisterClass(std::function); -JSENV_API const JSClassDefinition* FindClassByID(const void* TypeId); +REGISTER_API const JSClassDefinition* FindClassByID(const void* TypeId); -JSENV_API void OnClassNotFound(pesapi_class_not_found_callback Callback); +REGISTER_API void OnClassNotFound(pesapi_class_not_found_callback Callback); -JSENV_API const JSClassDefinition* LoadClassByID(const void* TypeId); +REGISTER_API const JSClassDefinition* LoadClassByID(const void* TypeId); -JSENV_API const JSClassDefinition* FindCppTypeClassByName(const PString& Name); +REGISTER_API const JSClassDefinition* FindCppTypeClassByName(const PString& Name); -JSENV_API bool TraceObjectLifecycle(const void* TypeId, pesapi_on_native_object_enter OnEnter, pesapi_on_native_object_exit OnExit); +REGISTER_API bool TraceObjectLifecycle(const void* TypeId, pesapi_on_native_object_enter OnEnter, pesapi_on_native_object_exit OnExit); #if USING_IN_UNREAL_ENGINE typedef void (*AddonRegisterFunc)(v8::Local Context, v8::Local Exports); @@ -158,9 +157,9 @@ AddonRegisterFunc FindAddonRegisterFunc(const PString& Name); void RegisterAddon(const char* Name, AddonRegisterFunc RegisterFunc); -JSENV_API const JSClassDefinition* FindClassByType(UStruct* Type); +REGISTER_API const JSClassDefinition* FindClassByType(UStruct* Type); -JSENV_API bool IsEditorOnlyUFunction(const UFunction* Func); +REGISTER_API bool IsEditorOnlyUFunction(const UFunction* Func); #endif diff --git a/include/NamespaceDef.h b/include/NamespaceDef.h new file mode 100644 index 0000000..3a55a8c --- /dev/null +++ b/include/NamespaceDef.h @@ -0,0 +1,15 @@ +/* + * 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 "PuertsNamespaceDef.h" + +#if defined(WITH_QJS_NAMESPACE_SUFFIX) +namespace v8 = v8_qjs; +#endif diff --git a/include/ObjectCacheNode.h b/include/ObjectCacheNode.h new file mode 100644 index 0000000..96789d2 --- /dev/null +++ b/include/ObjectCacheNode.h @@ -0,0 +1,138 @@ +/* + * 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 "NamespaceDef.h" +#include "quickjs.h" +#include +namespace puerts +{ +namespace qjsimpl +{ +class FObjectCacheNode +{ +public: + inline FObjectCacheNode(JSRuntime* RT_, void* TypeId_) : RT(RT_), TypeId(TypeId_), UserData(nullptr), Next(nullptr), MustCallFinalize(false) + { + } + + inline FObjectCacheNode(JSRuntime* RT_, const void* TypeId_, FObjectCacheNode* Next_) + : RT(RT_), TypeId(TypeId_), UserData(nullptr), Next(Next_), MustCallFinalize(false) + { + } + + inline FObjectCacheNode(FObjectCacheNode&& other) noexcept + : RT(other.RT) + , TypeId(other.TypeId) + , UserData(other.UserData) + , Next(other.Next) + , Value(JS_DupValueRT(other.RT, other.Value)) + , MustCallFinalize(other.MustCallFinalize) + { + other.RT = nullptr; + other.TypeId = nullptr; + other.UserData = nullptr; + other.Next = nullptr; + other.MustCallFinalize = false; + } + + inline FObjectCacheNode& operator=(FObjectCacheNode&& rhs) noexcept + { + RT = rhs.RT; + TypeId = rhs.TypeId; + Next = rhs.Next; + Value = JS_DupValueRT(RT, rhs.Value); + UserData = rhs.UserData; + MustCallFinalize = rhs.MustCallFinalize; + rhs.UserData = nullptr; + rhs.TypeId = nullptr; + rhs.Next = nullptr; + rhs.MustCallFinalize = false; + return *this; + } + + ~FObjectCacheNode() + { + if (Next) + delete Next; + JS_FreeValueRT(RT, Value); + } + + FObjectCacheNode* Find(const void* TypeId_) + { + if (TypeId_ == TypeId) + { + return this; + } + if (Next) + { + return Next->Find(TypeId_); + } + return nullptr; + } + + FObjectCacheNode* Remove(const void* TypeId_, bool IsHead) + { + if (TypeId_ == TypeId) + { + if (IsHead) + { + if (Next) + { + auto PreNext = Next; + *this = std::move(*Next); + delete PreNext; + } + else + { + TypeId = nullptr; + Next = nullptr; + JS_FreeValueRT(RT, Value); + } + } + return this; + } + if (Next) + { + auto Removed = Next->Remove(TypeId_, false); + if (Removed && Removed == Next) // detach & delete by prev node + { + Next = Removed->Next; + Removed->Next = nullptr; + delete Removed; + } + return Removed; + } + return nullptr; + } + + inline FObjectCacheNode* Add(const void* TypeId_) + { + Next = new FObjectCacheNode(RT, TypeId_, Next); + return Next; + } + + JSRuntime* RT; + + const void* TypeId; + + void* UserData; + + FObjectCacheNode* Next; + + JSValue Value; + + bool MustCallFinalize; + + FObjectCacheNode(const FObjectCacheNode&) = delete; + void operator=(const FObjectCacheNode&) = delete; +}; + +} // namespace qjsimpl +} // namespace pesapi \ No newline at end of file diff --git a/include/PuertsNamespaceDef.h b/include/PuertsNamespaceDef.h new file mode 100644 index 0000000..8f6ff75 --- /dev/null +++ b/include/PuertsNamespaceDef.h @@ -0,0 +1,79 @@ +/* + * 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 + +#if !defined(PUERTS_NAMESPACE) +#if defined(WITH_QJS_NAMESPACE_SUFFIX) +#define PUERTS_NAMESPACE puerts_qjs +#else +#define PUERTS_NAMESPACE puerts +#endif +#endif + +#ifndef PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS +#if defined(_MSC_VER) +#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS __pragma(warning(push)) __pragma(warning(disable : 4668)) +#elif defined(__clang__) +#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS \ + _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wundef\"") +#elif defined(__GNUC__) +#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wundef\"") +#endif +#endif // PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS + +#ifndef PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS +#if defined(_MSC_VER) +#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS __pragma(warning(pop)) +#elif defined(__clang__) +#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("clang diagnostic pop") +#elif defined(__GNUC__) +#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("GCC diagnostic pop") +#endif +#endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS + +#ifndef MSVC_PRAGMA +#if !defined(__clang__) && defined(_MSC_VER) +#define MSVC_PRAGMA(Pragma) __pragma(Pragma) +#else +#define MSVC_PRAGMA(...) +#endif +#endif + +#if defined(__clang__) +# define PUERTS_HAS_ATTRIBUTE_VISIBILITY (__has_attribute(visibility)) +#elif defined(__GNUC__) +# define PUERTS_HAS_ATTRIBUTE_VISIBILITY 1 +#else +# define PUERTS_HAS_ATTRIBUTE_VISIBILITY 0 +#endif + +#ifndef REGISTER_API +#ifdef _MSC_VER +#ifdef BUILDING_REGISTER_API_SHARED +# define REGISTER_API __declspec(dllexport) +#elif USING_REGISTER_API_SHARED +# define REGISTER_API __declspec(dllimport) +#else +# define REGISTER_API +#endif // BUILDING_V8_SHARED + +#else // _MSC_VER + +#if PUERTS_HAS_ATTRIBUTE_VISIBILITY +# ifdef BUILDING_REGISTER_API_SHARED +# define REGISTER_API __attribute__ ((visibility("default"))) +# else +# define REGISTER_API +# endif +#else +# define REGISTER_API +#endif + +#endif // _MSC_VER +#endif diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp new file mode 100644 index 0000000..a874ab8 --- /dev/null +++ b/source/CppObjectMapper.cpp @@ -0,0 +1,9 @@ +#include "CppObjectMapper.h" + +namespace puerts +{ +namespace qjsimpl +{ + +} +} \ No newline at end of file diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 1ae313d..eca1fcf 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -62,7 +62,8 @@ struct pesapi_value_ref__ : pesapi_env_ref__ uint32_t internal_field_count; void* internal_fields[0]; }; - +namespace pesapi +{ namespace qjsimpl { static struct pesapi_scope__ *getCurrentScope(JSContext *ctx) @@ -75,6 +76,7 @@ static void setCurrentScope(JSContext *ctx, struct pesapi_scope__ *scope) JS_SetContextOpaque(ctx, scope); } } +} struct pesapi_scope__ { @@ -83,8 +85,8 @@ struct pesapi_scope__ explicit pesapi_scope__(JSContext *ctx) { this->ctx = ctx; - prev_scope = qjsimpl::getCurrentScope(ctx); - qjsimpl::setCurrentScope(ctx, this); + prev_scope = pesapi::qjsimpl::getCurrentScope(ctx); + pesapi::qjsimpl::setCurrentScope(ctx, this); values_used = 0; @@ -134,12 +136,14 @@ struct pesapi_scope__ js_free(ctx, dynamic_alloc_values[i]); } dynamic_alloc_values.clear(); - qjsimpl::setCurrentScope(ctx, prev_scope); + pesapi::qjsimpl::setCurrentScope(ctx, prev_scope); } }; static_assert(sizeof(pesapi_scope_memory) >= sizeof(pesapi_scope__), "sizeof(pesapi_scope__) > sizeof(pesapi_scope_memory__)"); +namespace pesapi +{ namespace qjsimpl { inline pesapi_value pesapiValueFromQjsValue(JSValue* v) @@ -1070,3 +1074,4 @@ pesapi_ffi g_pesapi_ffi { }; */ } // namespace qjsimpl +} // namespace pesapi \ No newline at end of file From 23e65bf469633bda7095292304168c36a7ffe0c5 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 18 Feb 2025 16:53:28 +0800 Subject: [PATCH 08/70] =?UTF-8?q?=E6=B7=BB=E5=8A=A0gtest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 56 +++++++++++++++++++++++++++++++++++- include/CppObjectMapper.h | 5 ++-- include/ObjectCacheNode.h | 2 +- source/CppObjectMapper.cpp | 6 +++- test/CppObjectMapperTest.cpp | 56 ++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 test/CppObjectMapperTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ed96956..3cd53da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ macro(xcheck_add_c_compiler_flag FLAG) endif() endmacro() -xcheck_add_c_compiler_flag(-Wall) +#xcheck_add_c_compiler_flag(-Wall) if(NOT MSVC AND NOT IOS) xcheck_add_c_compiler_flag(-Werror) xcheck_add_c_compiler_flag(-Wextra) @@ -143,7 +143,20 @@ endif() if ( APPLE AND IOS ) add_library(PapiQjs STATIC ${qjs_sources} ${eastl_sources} ${papi_sources}) else () + # 在Windows上需要显式生成导入库 add_library(PapiQjs SHARED ${qjs_sources} ${eastl_sources} ${papi_sources}) # if add eastl_headers will undefined symbol: __udivti3 __udivmodti4 + # 设置导出符号 + set_target_properties(PapiQjs PROPERTIES + WINDOWS_EXPORT_ALL_SYMBOLS TRUE + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN TRUE + ) + # 确保生成导入库路径正确 + set_target_properties(PapiQjs PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} + ) endif() target_compile_definitions(PapiQjs PRIVATE ${qjs_defines}) target_include_directories(PapiQjs PUBLIC @@ -159,3 +172,44 @@ target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2025_APRIL=EA_DISA #target_compile_definitions(PapiQjs PUBLIC EASTL_DLL) target_compile_definitions(PapiQjs PUBLIC USING_REGISTER_API_SHARED) +# 配置GTest +set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) +set(BUILD_GTEST ON CACHE BOOL "" FORCE) +set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.8.0 +) +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +enable_testing() + +add_executable(cpp_object_mapper_test + test/CppObjectMapperTest.cpp +) +target_link_libraries(cpp_object_mapper_test + PRIVATE + PapiQjs + gtest + gtest_main +) + +include(GoogleTest) +gtest_discover_tests(cpp_object_mapper_test) + +target_include_directories(cpp_object_mapper_test PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/source + ${CMAKE_CURRENT_SOURCE_DIR}/quickjs + ${googletest_SOURCE_DIR}/googletest/include +) + +if(MSVC) + add_compile_options( + /wd4625 # 禁用C4625警告 + /wd4668 # 禁用C4668警告 + ) +endif() \ No newline at end of file diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index 89bf13d..5855913 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -6,7 +6,7 @@ #include #include "ObjectCacheNode.h" -namespace puerts +namespace pesapi { namespace qjsimpl { @@ -14,10 +14,11 @@ namespace qjsimpl class CppObjectMapper { public: + void Initialize(JSContext* ctx); private: eastl::unordered_map, eastl::equal_to, eastl::allocator_malloc> CDataCache; eastl::unordered_map, eastl::equal_to, eastl::allocator_malloc> TypeIdToFunctionMap; }; } // namespace qjsimpl -} // namespace puerts \ No newline at end of file +} // namespace pesapi diff --git a/include/ObjectCacheNode.h b/include/ObjectCacheNode.h index 96789d2..1c6354c 100644 --- a/include/ObjectCacheNode.h +++ b/include/ObjectCacheNode.h @@ -11,7 +11,7 @@ #include "NamespaceDef.h" #include "quickjs.h" #include -namespace puerts +namespace pesapi { namespace qjsimpl { diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index a874ab8..831539f 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -1,9 +1,13 @@ #include "CppObjectMapper.h" -namespace puerts +namespace pesapi { namespace qjsimpl { +void CppObjectMapper::Initialize(JSContext* ctx) +{ + +} } } \ No newline at end of file diff --git a/test/CppObjectMapperTest.cpp b/test/CppObjectMapperTest.cpp new file mode 100644 index 0000000..c067eba --- /dev/null +++ b/test/CppObjectMapperTest.cpp @@ -0,0 +1,56 @@ +#include +#include "CppObjectMapper.h" +#include + +namespace pesapi { +namespace qjsimpl { + +class CppObjectMapperTest : public ::testing::Test { +protected: + void SetUp() override { + rt = JS_NewRuntime(); + ASSERT_NE(rt, nullptr); + ctx = JS_NewContext(rt); + ASSERT_NE(ctx, nullptr); + //mapper = std::make_unique(); + } + + void TearDown() override { + //mapper.reset(); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + } + + JSRuntime* rt; + JSContext* ctx; + //std::unique_ptr mapper; +}; + +TEST_F(CppObjectMapperTest, InitializeShouldSetContext) { + // 测试正常初始化 + //EXPECT_NO_THROW(mapper->Initialize(ctx)); + + // 验证上下文是否被正确设置 + // 这里假设CppObjectMapper有GetContext方法用于测试验证 + // EXPECT_EQ(mapper->GetContext(), ctx); +} + +TEST_F(CppObjectMapperTest, InitializeWithNullContextShouldHandleGracefully) { + // 测试空指针处理 + //EXPECT_NO_THROW(mapper->Initialize(nullptr)); +} + +TEST_F(CppObjectMapperTest, DoubleInitializationShouldBeSafe) { + // 测试重复初始化 + //EXPECT_NO_THROW(mapper->Initialize(ctx)); + //EXPECT_NO_THROW(mapper->Initialize(ctx)); +} + +} // namespace qjsimpl +} // namespace pesapi + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + From 00103c0c7e8209225bfdf52d81043840d72c82e3 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 18 Feb 2025 17:01:43 +0800 Subject: [PATCH 09/70] =?UTF-8?q?mac=E4=B8=8B=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cd53da..b837674 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,10 +28,10 @@ macro(xcheck_add_c_compiler_flag FLAG) endmacro() #xcheck_add_c_compiler_flag(-Wall) -if(NOT MSVC AND NOT IOS) - xcheck_add_c_compiler_flag(-Werror) - xcheck_add_c_compiler_flag(-Wextra) -endif() +#if(NOT MSVC AND NOT IOS) +# xcheck_add_c_compiler_flag(-Werror) +# xcheck_add_c_compiler_flag(-Wextra) +#endif() xcheck_add_c_compiler_flag(-Wno-implicit-fallthrough) xcheck_add_c_compiler_flag(-Wno-sign-compare) xcheck_add_c_compiler_flag(-Wno-missing-field-initializers) @@ -207,9 +207,7 @@ target_include_directories(cpp_object_mapper_test PRIVATE ${googletest_SOURCE_DIR}/googletest/include ) -if(MSVC) - add_compile_options( - /wd4625 # 禁用C4625警告 - /wd4668 # 禁用C4668警告 - ) -endif() \ No newline at end of file +add_test(NAME cpp_object_mapper_test + COMMAND cpp_object_mapper_test + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} +) From 930294901348c48b1bf6dba9364e752500af20ad Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 18 Feb 2025 17:07:16 +0800 Subject: [PATCH 10/70] =?UTF-8?q?=E5=8F=AA=E6=9C=89window=E3=80=81linux?= =?UTF-8?q?=E3=80=81mac=E6=89=8D=E7=BC=96=E8=AF=91=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b837674..c1d5cc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -172,6 +172,8 @@ target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2025_APRIL=EA_DISA #target_compile_definitions(PapiQjs PUBLIC EASTL_DLL) target_compile_definitions(PapiQjs PUBLIC USING_REGISTER_API_SHARED) +if ( APPLE AND NOT IOS OR MSVC OR LINUX ) + # 配置GTest set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) set(BUILD_GTEST ON CACHE BOOL "" FORCE) @@ -211,3 +213,5 @@ add_test(NAME cpp_object_mapper_test COMMAND cpp_object_mapper_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) + +endif() From 64641b9e5529942008b9632ab7f8e19d7aa92daf Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 18 Feb 2025 17:29:00 +0800 Subject: [PATCH 11/70] =?UTF-8?q?=E4=B8=8D=E6=89=8B=E5=8A=A8=E5=8A=A0test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1d5cc1..cd8788c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,10 +188,13 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) enable_testing() +include(GoogleTest) + add_executable(cpp_object_mapper_test test/CppObjectMapperTest.cpp ) + target_link_libraries(cpp_object_mapper_test PRIVATE PapiQjs @@ -199,9 +202,6 @@ target_link_libraries(cpp_object_mapper_test gtest_main ) -include(GoogleTest) -gtest_discover_tests(cpp_object_mapper_test) - target_include_directories(cpp_object_mapper_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/source @@ -209,9 +209,6 @@ target_include_directories(cpp_object_mapper_test PRIVATE ${googletest_SOURCE_DIR}/googletest/include ) -add_test(NAME cpp_object_mapper_test - COMMAND cpp_object_mapper_test - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} -) +gtest_discover_tests(cpp_object_mapper_test) endif() From 915a94fc57365ec3efe9955ac9fa4ad80bd44834 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 18 Feb 2025 19:39:25 +0800 Subject: [PATCH 12/70] =?UTF-8?q?=E6=B7=BB=E5=8A=A0CppObjectMapper.cpp?= =?UTF-8?q?=E5=88=B0=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 1 + include/CppObjectMapper.h | 3 + source/CppObjectMapper.cpp | 13 +- source/PapiQuickjsImpl.cpp | 289 +++++------------------------------ test/CppObjectMapperTest.cpp | 2 +- 5 files changed, 51 insertions(+), 257 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd8788c..651f2e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,7 @@ set(qjs_sources set(papi_sources source/PapiQuickjsImpl.cpp + source/CppObjectMapper.cpp ) add_definitions(-D_CHAR16T) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index 5855913..12d8223 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -22,3 +22,6 @@ class CppObjectMapper } // namespace qjsimpl } // namespace pesapi + + +PESAPI_MODULE_EXPORT pesapi_env_ref create_qjs_env(); \ No newline at end of file diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 831539f..5ee2b62 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -1,13 +1,24 @@ #include "CppObjectMapper.h" +#include "pesapi.h" namespace pesapi { namespace qjsimpl { +extern pesapi_ffi g_pesapi_ffi; void CppObjectMapper::Initialize(JSContext* ctx) { } } -} \ No newline at end of file +} + +pesapi_env_ref create_qjs_env() +{ + JSRuntime* rt = JS_NewRuntime(); + JSContext* ctx = JS_NewContext(rt); + pesapi::qjsimpl::CppObjectMapper* mapper = new pesapi::qjsimpl::CppObjectMapper(); + mapper->Initialize(ctx); + return pesapi::qjsimpl::g_pesapi_ffi.create_env_ref(reinterpret_cast(ctx)); +} diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index eca1fcf..3ecc513 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -1,4 +1,4 @@ -#include "pesapi.h" +#include "pesapi.h" #include "quickjs.h" #include #include @@ -325,25 +325,16 @@ pesapi_value pesapi_create_object(pesapi_env env) { return pesapi_create_generic0(env, JS_NewObject); } -/* + pesapi_value pesapi_create_function(pesapi_env env, pesapi_callback native_impl, void* data, pesapi_function_finalize finalize) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto func = puerts::DataTransfer::IsolateData(context->GetIsolate())->CreateFunction(context, native_impl, data, finalize); - if (func.IsEmpty()) - return nullptr; - return v8impl::PesapiValueFromV8LocalValue(func.ToLocalChecked()); + return {}; } pesapi_value pesapi_create_class(pesapi_env env, const void* type_id) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto cls = puerts::DataTransfer::IsolateData(context->GetIsolate())->LoadTypeById(context, type_id); - if (cls.IsEmpty()) - return nullptr; - return v8impl::PesapiValueFromV8LocalValue(cls.ToLocalChecked()); + return {}; } -*/ int JS_ToBool2(JSContext *ctx, bool *pres, JSValue val) { @@ -522,69 +513,39 @@ bool pesapi_is_array(pesapi_env env, pesapi_value pvalue) { return pesapi_is_generic_ctx(env, pvalue, JS_IsArray); } -/* + pesapi_value pesapi_native_object_to_value(pesapi_env env, const void* type_id, void* object_ptr, bool call_finalize) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - return v8impl::PesapiValueFromV8LocalValue( - ::puerts::DataTransfer::FindOrAddCData(context->GetIsolate(), context, type_id, object_ptr, !call_finalize)); + return {}; } void* pesapi_get_native_object_ptr(pesapi_env env, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - if (value.IsEmpty() || !value->IsObject()) - return nullptr; - return puerts::DataTransfer::GetPointerFast(value.As()); + return {}; } const void* pesapi_get_native_object_typeid(pesapi_env env, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - if (value.IsEmpty() || !value->IsObject()) - return nullptr; - return puerts::DataTransfer::GetPointerFast(value.As(), 1); + return {}; } bool pesapi_is_instance_of(pesapi_env env, const void* type_id, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - return ::puerts::DataTransfer::IsInstanceOf(context->GetIsolate(), static_cast(type_id), value.As()); + return false; } pesapi_value pesapi_boxing(pesapi_env env, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - - auto result = v8::Object::New(context->GetIsolate()); - auto _unused = result->Set(context, 0, value); - return v8impl::PesapiValueFromV8LocalValue(result); + return {}; } pesapi_value pesapi_unboxing(pesapi_env env, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - - auto outer = value->ToObject(context).ToLocalChecked(); - auto realvalue = outer->Get(context, 0).ToLocalChecked(); - return v8impl::PesapiValueFromV8LocalValue(realvalue); + return {}; } void pesapi_update_boxed_value(pesapi_env env, pesapi_value boxed_value, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto holder = v8impl::V8LocalValueFromPesapiValue(boxed_value); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - if (holder->IsObject()) - { - auto outer = holder->ToObject(context).ToLocalChecked(); - auto _unused = outer->Set(context, 0, value); - } } bool pesapi_is_boxed_value(pesapi_env env, pesapi_value value) @@ -594,58 +555,46 @@ bool pesapi_is_boxed_value(pesapi_env env, pesapi_value value) int pesapi_get_args_len(pesapi_callback_info pinfo) { - auto info = reinterpret_cast*>(pinfo); - return (*info).Length(); + return 0; } pesapi_value pesapi_get_arg(pesapi_callback_info pinfo, int index) { - auto info = reinterpret_cast*>(pinfo); - return v8impl::PesapiValueFromV8LocalValue((*info)[index]); + return {}; } PESAPI_EXTERN pesapi_env pesapi_get_env(pesapi_callback_info pinfo) { - auto info = reinterpret_cast*>(pinfo); - return v8impl::PesapiEnvFromV8LocalContext((*info).GetIsolate()->GetCurrentContext()); + return {}; } pesapi_value pesapi_get_this(pesapi_callback_info pinfo) { - auto info = reinterpret_cast*>(pinfo); - return v8impl::PesapiValueFromV8LocalValue((*info).This()); + return {}; } pesapi_value pesapi_get_holder(pesapi_callback_info pinfo) { - auto info = reinterpret_cast*>(pinfo); - return v8impl::PesapiValueFromV8LocalValue((*info).Holder()); + return {}; } void* pesapi_get_userdata(pesapi_callback_info pinfo) { - auto info = reinterpret_cast*>(pinfo); - return *(static_cast(v8::Local::Cast((*info).Data())->Value())); + return {}; } void pesapi_add_return(pesapi_callback_info pinfo, pesapi_value value) { - auto info = reinterpret_cast*>(pinfo); - (*info).GetReturnValue().Set(v8impl::V8LocalValueFromPesapiValue(value)); } void pesapi_throw_by_string(pesapi_callback_info pinfo, const char* msg) { - auto info = reinterpret_cast*>(pinfo); - v8::Isolate* isolate = info->GetIsolate(); - isolate->ThrowException( - v8::Exception::Error(v8::String::NewFromUtf8(isolate, msg, v8::NewStringType::kNormal).ToLocalChecked())); } pesapi_env_ref pesapi_create_env_ref(pesapi_env env) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - return new pesapi_env_ref__(context); + auto ctx = qjsContextFromPesapiEnv(env); + return new pesapi_env_ref__(ctx); } bool pesapi_env_ref_is_valid(pesapi_env_ref env_ref) @@ -659,7 +608,7 @@ pesapi_env pesapi_get_env_from_ref(pesapi_env_ref env_ref) { return nullptr; } - return v8impl::PesapiEnvFromV8LocalContext(env_ref->context_persistent.Get(env_ref->isolate)); + return pesapiEnvFromQjsContext(env_ref->context_persistent); } pesapi_env_ref pesapi_duplicate_env_ref(pesapi_env_ref env_ref) @@ -674,12 +623,7 @@ void pesapi_release_env_ref(pesapi_env_ref env_ref) { if (env_ref->env_life_cycle_tracker.expired()) { -#if V8_MAJOR_VERSION < 11 - env_ref->context_persistent.Empty(); - delete env_ref; -#else ::operator delete(static_cast(env_ref)); -#endif } else { @@ -694,10 +638,7 @@ pesapi_scope pesapi_open_scope(pesapi_env_ref env_ref) { return nullptr; } - env_ref->isolate->Enter(); - auto scope = new pesapi_scope__(env_ref->isolate); - env_ref->context_persistent.Get(env_ref->isolate)->Enter(); - return scope; + return nullptr; } pesapi_scope pesapi_open_scope_placement(pesapi_env_ref env_ref, struct pesapi_scope_memory* memory) @@ -706,75 +647,30 @@ pesapi_scope pesapi_open_scope_placement(pesapi_env_ref env_ref, struct pesapi_s { return nullptr; } - env_ref->isolate->Enter(); - auto scope = new (memory) pesapi_scope__(env_ref->isolate); - env_ref->context_persistent.Get(env_ref->isolate)->Enter(); - return scope; + return nullptr; } bool pesapi_has_caught(pesapi_scope scope) { - return scope && scope->trycatch.HasCaught(); + return false; } const char* pesapi_get_exception_as_string(pesapi_scope scope, bool with_stack) { - if (!scope) - return nullptr; - scope->errinfo = *v8::String::Utf8Value(scope->scope.GetIsolate(), scope->trycatch.Exception()); - if (with_stack) - { - auto isolate = scope->scope.GetIsolate(); - v8::Local context(isolate->GetCurrentContext()); - v8::Local message = scope->trycatch.Message(); - - // 输出 (filename):(line number): (message). - std::ostringstream stm; - v8::String::Utf8Value fileName(isolate, message->GetScriptResourceName()); - int lineNum = message->GetLineNumber(context).FromJust(); - stm << *fileName << ":" << lineNum << ": " << scope->errinfo.c_str(); - - stm << std::endl; - - // 输出调用栈信息 - v8::Local stackTrace; - if (scope->trycatch.StackTrace(context).ToLocal(&stackTrace)) - { - v8::String::Utf8Value stackTraceVal(isolate, stackTrace); - stm << std::endl << *stackTraceVal; - } - scope->errinfo = stm.str().c_str(); - } - return scope->errinfo.c_str(); + return nullptr;; } void pesapi_close_scope(pesapi_scope scope) { - if (!scope) - return; - auto isolate = scope->scope.GetIsolate(); - isolate->GetCurrentContext()->Exit(); - delete (scope); - isolate->Exit(); } void pesapi_close_scope_placement(pesapi_scope scope) { - if (!scope) - return; - auto isolate = scope->scope.GetIsolate(); - isolate->GetCurrentContext()->Exit(); - scope->~pesapi_scope__(); - isolate->Exit(); } pesapi_value_ref pesapi_create_value_ref(pesapi_env env, pesapi_value pvalue, uint32_t internal_field_count) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - size_t totalSize = sizeof(pesapi_value_ref__) + sizeof(void*) * internal_field_count; - void* buffer = ::operator new(totalSize); - return new (buffer) pesapi_value_ref__(context, value, internal_field_count); + return {}; } pesapi_value_ref pesapi_duplicate_value_ref(pesapi_value_ref value_ref) @@ -797,31 +693,15 @@ void pesapi_release_value_ref(pesapi_value_ref value_ref) pesapi_value pesapi_get_value_from_ref(pesapi_env env, pesapi_value_ref value_ref) { - return v8impl::PesapiValueFromV8LocalValue(value_ref->value_persistent.Get(value_ref->isolate)); + return {}; } void pesapi_set_ref_weak(pesapi_env env, pesapi_value_ref value_ref) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - value_ref->value_persistent.SetWeak(); } bool pesapi_set_owner(pesapi_env env, pesapi_value pvalue, pesapi_value powner) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - auto owner = v8impl::V8LocalValueFromPesapiValue(powner); - - if (owner->IsObject()) - { - auto jsObj = owner.template As(); -#if V8_MAJOR_VERSION < 8 - jsObj->Set(context, v8::String::NewFromUtf8(context->GetIsolate(), "_p_i_only_one_child").ToLocalChecked(), value).Check(); -#else - jsObj->Set(context, v8::String::NewFromUtf8Literal(context->GetIsolate(), "_p_i_only_one_child"), value).Check(); -#endif - return true; - } return false; } @@ -832,160 +712,59 @@ pesapi_env_ref pesapi_get_ref_associated_env(pesapi_value_ref value_ref) void** pesapi_get_ref_internal_fields(pesapi_value_ref value_ref, uint32_t* pinternal_field_count) { - *pinternal_field_count = value_ref->internal_field_count; - return &value_ref->internal_fields[0]; + return {}; } pesapi_value pesapi_get_property(pesapi_env env, pesapi_value pobject, const char* key) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto object = v8impl::V8LocalValueFromPesapiValue(pobject); - if (object->IsObject()) - { - auto MaybeValue = object.As()->Get( - context, v8::String::NewFromUtf8(context->GetIsolate(), key, v8::NewStringType::kNormal).ToLocalChecked()); - v8::Local Val; - if (MaybeValue.ToLocal(&Val)) - { - return v8impl::PesapiValueFromV8LocalValue(Val); - } - } - return pesapi_create_undefined(env); + return {}; } void pesapi_set_property(pesapi_env env, pesapi_value pobject, const char* key, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto object = v8impl::V8LocalValueFromPesapiValue(pobject); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - - if (object->IsObject()) - { - auto _un_used = object.As()->Set( - context, v8::String::NewFromUtf8(context->GetIsolate(), key, v8::NewStringType::kNormal).ToLocalChecked(), value); - } } bool pesapi_get_private(pesapi_env env, pesapi_value pobject, void** out_ptr) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto object = v8impl::V8LocalValueFromPesapiValue(pobject); - if (object.IsEmpty() || !object->IsObject()) - { - *out_ptr = nullptr; - return false; - } - *out_ptr = puerts::DataTransfer::IsolateData(context->GetIsolate()) - ->GetPrivateData(context, object.As()); return true; } bool pesapi_set_private(pesapi_env env, pesapi_value pobject, void* ptr) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto object = v8impl::V8LocalValueFromPesapiValue(pobject); - if (object.IsEmpty() || !object->IsObject()) - { - return false; - } - puerts::DataTransfer::IsolateData(context->GetIsolate()) - ->SetPrivateData(context, object.As(), ptr); return true; } pesapi_value pesapi_get_property_uint32(pesapi_env env, pesapi_value pobject, uint32_t key) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto object = v8impl::V8LocalValueFromPesapiValue(pobject); - if (object->IsObject()) - { - auto MaybeValue = object.As()->Get(context, key); - v8::Local Val; - if (MaybeValue.ToLocal(&Val)) - { - return v8impl::PesapiValueFromV8LocalValue(Val); - } - } - return pesapi_create_undefined(env); + return {}; } void pesapi_set_property_uint32(pesapi_env env, pesapi_value pobject, uint32_t key, pesapi_value pvalue) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto object = v8impl::V8LocalValueFromPesapiValue(pobject); - auto value = v8impl::V8LocalValueFromPesapiValue(pvalue); - - if (object->IsObject()) - { - auto _un_used = object.As()->Set(context, key, value); - } } pesapi_value pesapi_call_function(pesapi_env env, pesapi_value pfunc, pesapi_value this_object, int argc, const pesapi_value argv[]) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - v8::Local recv = v8::Undefined(context->GetIsolate()); - if (this_object) - { - recv = v8impl::V8LocalValueFromPesapiValue(this_object); - } - v8::Local func = v8impl::V8LocalValueFromPesapiValue(pfunc).As(); - - auto maybe_ret = func->Call(context, recv, argc, reinterpret_cast*>(const_cast(argv))); - if (maybe_ret.IsEmpty()) - { - return nullptr; - } - return v8impl::PesapiValueFromV8LocalValue(maybe_ret.ToLocalChecked()); + return {}; } pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size, const char* path) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto isolate = context->GetIsolate(); - v8::Local url = - v8::String::NewFromUtf8(isolate, path == nullptr ? "" : path, v8::NewStringType::kNormal).ToLocalChecked(); - std::vector buff; - buff.reserve(code_size + 1); - memcpy(buff.data(), code, code_size); - buff.data()[code_size] = '\0'; - v8::Local source = v8::String::NewFromUtf8(isolate, buff.data(), v8::NewStringType::kNormal).ToLocalChecked(); -#if V8_MAJOR_VERSION > 8 - v8::ScriptOrigin origin(isolate, url); -#else - v8::ScriptOrigin origin(url); -#endif - - auto CompiledScript = v8::Script::Compile(context, source, &origin); - if (CompiledScript.IsEmpty()) - { - return nullptr; - } - auto maybe_ret = CompiledScript.ToLocalChecked()->Run(context); - if (maybe_ret.IsEmpty()) - { - return nullptr; - } - return v8impl::PesapiValueFromV8LocalValue(maybe_ret.ToLocalChecked()); + return {}; } pesapi_value pesapi_global(pesapi_env env) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - auto global = context->Global(); - return v8impl::PesapiValueFromV8LocalValue(global); + return {}; } const void* pesapi_get_env_private(pesapi_env env) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - return puerts::DataTransfer::GetIsolatePrivateData(context->GetIsolate()); + return {}; } void pesapi_set_env_private(pesapi_env env, const void* ptr) { - auto context = v8impl::V8LocalContextFromPesapiEnv(env); - puerts::DataTransfer::SetIsolatePrivateData(context->GetIsolate(), const_cast(ptr)); } pesapi_ffi g_pesapi_ffi { @@ -1072,6 +851,6 @@ pesapi_ffi g_pesapi_ffi { &pesapi_get_env_private, &pesapi_set_env_private }; -*/ + } // namespace qjsimpl } // namespace pesapi \ No newline at end of file diff --git a/test/CppObjectMapperTest.cpp b/test/CppObjectMapperTest.cpp index c067eba..43be51b 100644 --- a/test/CppObjectMapperTest.cpp +++ b/test/CppObjectMapperTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include "CppObjectMapper.h" #include From 63ba54bc335c33d2b9660ad28cb34caf8ab965a9 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 18 Feb 2025 20:08:27 +0800 Subject: [PATCH 13/70] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E5=A4=B4=E6=96=87=E4=BB=B6=E7=9A=84=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 1 + {include => ClassRegister/include}/JSClassRegister.h | 0 {include => ClassRegister/include}/NamespaceDef.h | 0 {include => ClassRegister/include}/PString.h | 0 {include => ClassRegister/include}/PuertsNamespaceDef.h | 0 {include => ClassRegister/include}/TypeInfo.hpp | 0 source/CppObjectMapper.cpp | 1 + 7 files changed, 2 insertions(+) rename {include => ClassRegister/include}/JSClassRegister.h (100%) rename {include => ClassRegister/include}/NamespaceDef.h (100%) rename {include => ClassRegister/include}/PString.h (100%) rename {include => ClassRegister/include}/PuertsNamespaceDef.h (100%) rename {include => ClassRegister/include}/TypeInfo.hpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 651f2e3..5214367 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,7 @@ add_definitions(-DEASTL_OPENSOURCE=1) include_directories(include quickjs) include_directories(EASTL/include) +include_directories(ClassRegister/include) file(GLOB eastl_sources "EASTL/source/*.cpp") file(GLOB_RECURSE eastl_headers "EASTL/include/EASTL/**.h") diff --git a/include/JSClassRegister.h b/ClassRegister/include/JSClassRegister.h similarity index 100% rename from include/JSClassRegister.h rename to ClassRegister/include/JSClassRegister.h diff --git a/include/NamespaceDef.h b/ClassRegister/include/NamespaceDef.h similarity index 100% rename from include/NamespaceDef.h rename to ClassRegister/include/NamespaceDef.h diff --git a/include/PString.h b/ClassRegister/include/PString.h similarity index 100% rename from include/PString.h rename to ClassRegister/include/PString.h diff --git a/include/PuertsNamespaceDef.h b/ClassRegister/include/PuertsNamespaceDef.h similarity index 100% rename from include/PuertsNamespaceDef.h rename to ClassRegister/include/PuertsNamespaceDef.h diff --git a/include/TypeInfo.hpp b/ClassRegister/include/TypeInfo.hpp similarity index 100% rename from include/TypeInfo.hpp rename to ClassRegister/include/TypeInfo.hpp diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 5ee2b62..e00f435 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -6,6 +6,7 @@ namespace pesapi namespace qjsimpl { extern pesapi_ffi g_pesapi_ffi; + void CppObjectMapper::Initialize(JSContext* ctx) { From 73eb78e39a0ff37f9863f72d7b42f4b3b5323e02 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 18 Feb 2025 20:23:34 +0800 Subject: [PATCH 14/70] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E7=B1=BB=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 7 + ClassRegister/source/JSClassRegister.cpp | 392 +++++++++++++++++++++++ 2 files changed, 399 insertions(+) create mode 100644 ClassRegister/source/JSClassRegister.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5214367..44739ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,8 +142,13 @@ if(NOT MSVC) list(APPEND qjs_libs m) endif() +set(papi_register_sources + ClassRegister/source/JSClassRegister.cpp +) + if ( APPLE AND IOS ) add_library(PapiQjs STATIC ${qjs_sources} ${eastl_sources} ${papi_sources}) + add_library(PapiRegister STATIC ${papi_register_sources}) else () # 在Windows上需要显式生成导入库 add_library(PapiQjs SHARED ${qjs_sources} ${eastl_sources} ${papi_sources}) # if add eastl_headers will undefined symbol: __udivti3 __udivmodti4 @@ -159,6 +164,7 @@ else () LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} ) + add_library(PapiRegister SHARED ${papi_register_sources}) endif() target_compile_definitions(PapiQjs PRIVATE ${qjs_defines}) target_include_directories(PapiQjs PUBLIC @@ -173,6 +179,7 @@ target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2024_SEPT=EA_DISAB target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2025_APRIL=EA_DISABLED) #target_compile_definitions(PapiQjs PUBLIC EASTL_DLL) target_compile_definitions(PapiQjs PUBLIC USING_REGISTER_API_SHARED) +target_compile_definitions(PapiRegister PUBLIC BUILD_REGISTER_API_SHARED) if ( APPLE AND NOT IOS OR MSVC OR LINUX ) diff --git a/ClassRegister/source/JSClassRegister.cpp b/ClassRegister/source/JSClassRegister.cpp new file mode 100644 index 0000000..c33ff9e --- /dev/null +++ b/ClassRegister/source/JSClassRegister.cpp @@ -0,0 +1,392 @@ +/* + * 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 "JSClassRegister.h" +#if USING_IN_UNREAL_ENGINE +#include "UObject/Class.h" +#endif +#include +#include + +namespace PUERTS_NAMESPACE +{ +template +static T* PropertyInfoDuplicate(T* Arr) +{ + if (Arr == nullptr) + return nullptr; + int Count = 0; + ; + while (true) + { + if (Arr[Count++].Name == nullptr) + break; + } + T* Ret = new T[Count]; + ::memcpy(Ret, Arr, sizeof(T) * Count); + return Ret; +} + +JSClassDefinition* JSClassDefinitionDuplicate(const JSClassDefinition* ClassDefinition) +{ + auto Ret = new JSClassDefinition; + ::memcpy(Ret, ClassDefinition, sizeof(JSClassDefinition)); + Ret->Methods = PropertyInfoDuplicate(ClassDefinition->Methods); + Ret->Functions = PropertyInfoDuplicate(ClassDefinition->Functions); + Ret->Properties = PropertyInfoDuplicate(ClassDefinition->Properties); + Ret->Variables = PropertyInfoDuplicate(ClassDefinition->Variables); + Ret->ConstructorInfos = PropertyInfoDuplicate(ClassDefinition->ConstructorInfos); + Ret->MethodInfos = PropertyInfoDuplicate(ClassDefinition->MethodInfos); + Ret->FunctionInfos = PropertyInfoDuplicate(ClassDefinition->FunctionInfos); + Ret->PropertyInfos = PropertyInfoDuplicate(ClassDefinition->PropertyInfos); + Ret->VariableInfos = PropertyInfoDuplicate(ClassDefinition->VariableInfos); + return Ret; +} + +void JSClassDefinitionDelete(JSClassDefinition* ClassDefinition) +{ + delete[] ClassDefinition->Methods; + delete[] ClassDefinition->Functions; + delete[] ClassDefinition->Properties; + delete[] ClassDefinition->Variables; + delete[] ClassDefinition->ConstructorInfos; + delete[] ClassDefinition->MethodInfos; + delete[] ClassDefinition->FunctionInfos; + delete[] ClassDefinition->PropertyInfos; + delete[] ClassDefinition->VariableInfos; + delete ClassDefinition; +} + +class JSClassRegister +{ +public: + JSClassRegister(); + ~JSClassRegister(); + + void RegisterClass(const JSClassDefinition& ClassDefinition); + + void SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos, + const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, const NamedPropertyInfo* VariableInfos); + + void ForeachRegisterClass(std::function); + + const JSClassDefinition* FindClassByID(const void* TypeId); + + void OnClassNotFound(pesapi_class_not_found_callback InCallback) + { + ClassNotFoundCallback = InCallback; + } + + const JSClassDefinition* LoadClassByID(const void* TypeId) + { + if (!TypeId) + { + return nullptr; + } + auto clsDef = FindClassByID(TypeId); + if (!clsDef && ClassNotFoundCallback) + { + if (!ClassNotFoundCallback(TypeId)) + { + return nullptr; + } + clsDef = FindClassByID(TypeId); + } + return clsDef; + } + + const JSClassDefinition* FindCppTypeClassByName(const PString& Name); + +#if USING_IN_UNREAL_ENGINE + void RegisterAddon(const PString& Name, AddonRegisterFunc RegisterFunc); + + AddonRegisterFunc FindAddonRegisterFunc(const PString& Name); + + const JSClassDefinition* FindClassByType(UStruct* Type); +#endif + +private: + std::map CDataIdToClassDefinition; + std::map CDataNameToClassDefinition; + pesapi_class_not_found_callback ClassNotFoundCallback = nullptr; +#if USING_IN_UNREAL_ENGINE + std::map AddonRegisterInfos; + std::map StructNameToClassDefinition; +#endif +}; + +JSClassRegister::JSClassRegister() +{ +} + +JSClassRegister::~JSClassRegister() +{ + for (auto& KV : CDataIdToClassDefinition) + { + JSClassDefinitionDelete(KV.second); + } + CDataIdToClassDefinition.clear(); +#if USING_IN_UNREAL_ENGINE + for (auto& KV : StructNameToClassDefinition) + { + JSClassDefinitionDelete(KV.second); + } + StructNameToClassDefinition.clear(); +#endif +} + +void JSClassRegister::RegisterClass(const JSClassDefinition& ClassDefinition) +{ + if (ClassDefinition.TypeId && ClassDefinition.ScriptName) + { + auto cd_iter = CDataIdToClassDefinition.find(ClassDefinition.TypeId); + if (cd_iter != CDataIdToClassDefinition.end()) + { + JSClassDefinitionDelete(cd_iter->second); + } + CDataIdToClassDefinition[ClassDefinition.TypeId] = JSClassDefinitionDuplicate(&ClassDefinition); + PString SN = ClassDefinition.ScriptName; + CDataNameToClassDefinition[SN] = CDataIdToClassDefinition[ClassDefinition.TypeId]; + CDataIdToClassDefinition[ClassDefinition.TypeId]->ScriptName = CDataNameToClassDefinition.find(SN)->first.c_str(); + } +#if USING_IN_UNREAL_ENGINE + else if (ClassDefinition.UETypeName) + { + FString SN = UTF8_TO_TCHAR(ClassDefinition.UETypeName); + auto ud_iter = StructNameToClassDefinition.find(SN); + if (ud_iter != StructNameToClassDefinition.end()) + { + JSClassDefinitionDelete(ud_iter->second); + } + StructNameToClassDefinition[SN] = JSClassDefinitionDuplicate(&ClassDefinition); + } +#endif +} + +void SetReflectoinInfo(JSFunctionInfo* Methods, const NamedFunctionInfo* MethodInfos) +{ + std::map> InfoMap; + const NamedFunctionInfo* MethodInfo = MethodInfos; + while (MethodInfo->Name) + { + auto Iter = InfoMap.find(MethodInfo->Name); + if (Iter == InfoMap.end()) + { + InfoMap[MethodInfo->Name] = std::make_tuple(1, MethodInfo); + } + else + { + std::get<0>(Iter->second) = 2; + } + ++MethodInfo; + } + + JSFunctionInfo* Method = Methods; + while (Method->Name) + { + auto Iter = InfoMap.find(Method->Name); + if (Iter != InfoMap.end() && std::get<0>(Iter->second) == 1) + { + Method->ReflectionInfo = std::get<1>(Iter->second)->Type; + } + ++Method; + } +} + +void JSClassRegister::SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, + const NamedFunctionInfo* MethodInfos, const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, + const NamedPropertyInfo* VariableInfos) +{ + auto ClassDef = const_cast(FindClassByID(TypeId)); + if (ClassDef) + { + ClassDef->ConstructorInfos = PropertyInfoDuplicate(const_cast(ConstructorInfos)); + ClassDef->MethodInfos = PropertyInfoDuplicate(const_cast(MethodInfos)); + ClassDef->FunctionInfos = PropertyInfoDuplicate(const_cast(FunctionInfos)); + ClassDef->PropertyInfos = PropertyInfoDuplicate(const_cast(PropertyInfos)); + ClassDef->VariableInfos = PropertyInfoDuplicate(const_cast(VariableInfos)); + SetReflectoinInfo(ClassDef->Methods, ClassDef->MethodInfos); + SetReflectoinInfo(ClassDef->Functions, ClassDef->FunctionInfos); + } +} + +const JSClassDefinition* JSClassRegister::FindClassByID(const void* TypeId) +{ + if (!TypeId) + { + return nullptr; + } + auto Iter = CDataIdToClassDefinition.find(TypeId); + if (Iter == CDataIdToClassDefinition.end()) + { + return nullptr; + } + else + { + return Iter->second; + } +} + +const JSClassDefinition* JSClassRegister::FindCppTypeClassByName(const PString& Name) +{ + auto Iter = CDataNameToClassDefinition.find(Name); + if (Iter == CDataNameToClassDefinition.end()) + { + return nullptr; + } + else + { + return Iter->second; + } +} + +#if USING_IN_UNREAL_ENGINE +void JSClassRegister::RegisterAddon(const PString& Name, AddonRegisterFunc RegisterFunc) +{ + AddonRegisterInfos[Name] = RegisterFunc; +} + +AddonRegisterFunc JSClassRegister::FindAddonRegisterFunc(const PString& Name) +{ + auto Iter = AddonRegisterInfos.find(Name); + if (Iter == AddonRegisterInfos.end()) + { + return nullptr; + } + else + { + return Iter->second; + } +} + +const JSClassDefinition* JSClassRegister::FindClassByType(UStruct* Type) +{ + auto Iter = StructNameToClassDefinition.find(Type->GetName()); + if (Iter == StructNameToClassDefinition.end()) + { + return nullptr; + } + else + { + return Iter->second; + } +} +#endif + +void JSClassRegister::ForeachRegisterClass(std::function Callback) +{ + for (auto& KV : CDataNameToClassDefinition) + { + Callback(KV.second); + } +#if USING_IN_UNREAL_ENGINE + for (auto& KV : StructNameToClassDefinition) + { + Callback(KV.second); + } +#endif +} + +JSClassRegister* GetJSClassRegister() +{ + static JSClassRegister S_JSClassRegister; + return &S_JSClassRegister; +} + +void RegisterJSClass(const JSClassDefinition& ClassDefinition) +{ + GetJSClassRegister()->RegisterClass(ClassDefinition); +} + +void SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos, + const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, const NamedPropertyInfo* VariableInfos) +{ + GetJSClassRegister()->SetClassTypeInfo(TypeId, ConstructorInfos, MethodInfos, FunctionInfos, PropertyInfos, VariableInfos); +} + +void ForeachRegisterClass(std::function Callback) +{ + GetJSClassRegister()->ForeachRegisterClass(Callback); +} + +const JSClassDefinition* FindClassByID(const void* TypeId) +{ + return GetJSClassRegister()->FindClassByID(TypeId); +} + +void OnClassNotFound(pesapi_class_not_found_callback Callback) +{ + GetJSClassRegister()->OnClassNotFound(Callback); +} + +const JSClassDefinition* LoadClassByID(const void* TypeId) +{ + return GetJSClassRegister()->LoadClassByID(TypeId); +} + +const JSClassDefinition* FindCppTypeClassByName(const PString& Name) +{ + return GetJSClassRegister()->FindCppTypeClassByName(Name); +} + +bool TraceObjectLifecycle(const void* TypeId, pesapi_on_native_object_enter OnEnter, pesapi_on_native_object_exit OnExit) +{ + if (auto clsDef = const_cast(GetJSClassRegister()->FindClassByID(TypeId))) + { + clsDef->OnEnter = OnEnter; + clsDef->OnExit = OnExit; + return true; + } + return false; +} + +#if USING_IN_UNREAL_ENGINE + +bool IsEditorOnlyUFunction(const UFunction* Func) +{ + // a simplified version of IsEditorOnlyObject(), sadly it's a EditorOnly Function so I have to reimplement a toy one + if (!Func) + { + return false; + } + if (Func->HasAnyFunctionFlags(FUNC_EditorOnly)) + { + return true; + } + auto InObject = Func; + if (InObject->HasAnyMarks(OBJECTMARK_EditorOnly) || InObject->IsEditorOnly()) + { + return true; + } + + auto Package = Func->GetPackage(); + if (Package && Package->HasAnyPackageFlags(PKG_EditorOnly)) + { + return true; + } + + return false; +} + +void RegisterAddon(const char* Name, AddonRegisterFunc RegisterFunc) +{ + GetJSClassRegister()->RegisterAddon(Name, RegisterFunc); +} + +AddonRegisterFunc FindAddonRegisterFunc(const PString& Name) +{ + return GetJSClassRegister()->FindAddonRegisterFunc(Name); +} + +const JSClassDefinition* FindClassByType(UStruct* Type) +{ + return GetJSClassRegister()->FindClassByType(Type); +} +#endif + +} // namespace PUERTS_NAMESPACE From a6991d696a1015b1252817728ce13fa6b39b0ffd Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 18 Feb 2025 20:34:40 +0800 Subject: [PATCH 15/70] =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 4 ++-- {ClassRegister => papi-register}/include/JSClassRegister.h | 0 {ClassRegister => papi-register}/include/NamespaceDef.h | 0 {ClassRegister => papi-register}/include/PString.h | 0 {ClassRegister => papi-register}/include/PuertsNamespaceDef.h | 0 {ClassRegister => papi-register}/include/TypeInfo.hpp | 0 {ClassRegister => papi-register}/source/JSClassRegister.cpp | 0 7 files changed, 2 insertions(+), 2 deletions(-) rename {ClassRegister => papi-register}/include/JSClassRegister.h (100%) rename {ClassRegister => papi-register}/include/NamespaceDef.h (100%) rename {ClassRegister => papi-register}/include/PString.h (100%) rename {ClassRegister => papi-register}/include/PuertsNamespaceDef.h (100%) rename {ClassRegister => papi-register}/include/TypeInfo.hpp (100%) rename {ClassRegister => papi-register}/source/JSClassRegister.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 44739ad..21a9004 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,7 @@ add_definitions(-DEASTL_OPENSOURCE=1) include_directories(include quickjs) include_directories(EASTL/include) -include_directories(ClassRegister/include) +include_directories(papi-register/include) file(GLOB eastl_sources "EASTL/source/*.cpp") file(GLOB_RECURSE eastl_headers "EASTL/include/EASTL/**.h") @@ -143,7 +143,7 @@ if(NOT MSVC) endif() set(papi_register_sources - ClassRegister/source/JSClassRegister.cpp + papi-register/source/JSClassRegister.cpp ) if ( APPLE AND IOS ) diff --git a/ClassRegister/include/JSClassRegister.h b/papi-register/include/JSClassRegister.h similarity index 100% rename from ClassRegister/include/JSClassRegister.h rename to papi-register/include/JSClassRegister.h diff --git a/ClassRegister/include/NamespaceDef.h b/papi-register/include/NamespaceDef.h similarity index 100% rename from ClassRegister/include/NamespaceDef.h rename to papi-register/include/NamespaceDef.h diff --git a/ClassRegister/include/PString.h b/papi-register/include/PString.h similarity index 100% rename from ClassRegister/include/PString.h rename to papi-register/include/PString.h diff --git a/ClassRegister/include/PuertsNamespaceDef.h b/papi-register/include/PuertsNamespaceDef.h similarity index 100% rename from ClassRegister/include/PuertsNamespaceDef.h rename to papi-register/include/PuertsNamespaceDef.h diff --git a/ClassRegister/include/TypeInfo.hpp b/papi-register/include/TypeInfo.hpp similarity index 100% rename from ClassRegister/include/TypeInfo.hpp rename to papi-register/include/TypeInfo.hpp diff --git a/ClassRegister/source/JSClassRegister.cpp b/papi-register/source/JSClassRegister.cpp similarity index 100% rename from ClassRegister/source/JSClassRegister.cpp rename to papi-register/source/JSClassRegister.cpp From 24de9165fddd4eaad1c50324982c991e54d95211 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 19 Feb 2025 09:35:55 +0800 Subject: [PATCH 16/70] =?UTF-8?q?register=E6=94=B9=E4=B8=BA=E7=94=A8eastl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- include/CppObjectMapper.h | 4 +++- papi-register/source/JSClassRegister.cpp | 21 +++++++++++---------- source/CppObjectMapper.cpp | 5 +++-- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21a9004..24cfd60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -164,7 +164,7 @@ else () LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} ) - add_library(PapiRegister SHARED ${papi_register_sources}) + add_library(PapiRegister SHARED ${eastl_sources} ${papi_register_sources}) endif() target_compile_definitions(PapiQjs PRIVATE ${qjs_defines}) target_include_directories(PapiQjs PUBLIC diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index 12d8223..6c80703 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -14,10 +14,12 @@ namespace qjsimpl class CppObjectMapper { public: - void Initialize(JSContext* ctx); + void Initialize(JSContext* ctx_); private: eastl::unordered_map, eastl::equal_to, eastl::allocator_malloc> CDataCache; eastl::unordered_map, eastl::equal_to, eastl::allocator_malloc> TypeIdToFunctionMap; + + JSContext* ctx; }; } // namespace qjsimpl diff --git a/papi-register/source/JSClassRegister.cpp b/papi-register/source/JSClassRegister.cpp index c33ff9e..f0f76b2 100644 --- a/papi-register/source/JSClassRegister.cpp +++ b/papi-register/source/JSClassRegister.cpp @@ -10,7 +10,8 @@ #if USING_IN_UNREAL_ENGINE #include "UObject/Class.h" #endif -#include +#include +#include #include namespace PUERTS_NAMESPACE @@ -111,12 +112,12 @@ class JSClassRegister #endif private: - std::map CDataIdToClassDefinition; - std::map CDataNameToClassDefinition; + eastl::map, eastl::allocator_malloc> CDataIdToClassDefinition; + eastl::map, eastl::allocator_malloc> CDataNameToClassDefinition; pesapi_class_not_found_callback ClassNotFoundCallback = nullptr; #if USING_IN_UNREAL_ENGINE - std::map AddonRegisterInfos; - std::map StructNameToClassDefinition; + eastl::map, eastl::allocator_malloc> AddonRegisterInfos; + eastl::map, eastl::allocator_malloc> StructNameToClassDefinition; #endif }; @@ -170,18 +171,18 @@ void JSClassRegister::RegisterClass(const JSClassDefinition& ClassDefinition) void SetReflectoinInfo(JSFunctionInfo* Methods, const NamedFunctionInfo* MethodInfos) { - std::map> InfoMap; + eastl::map, eastl::less, eastl::allocator_malloc> InfoMap; const NamedFunctionInfo* MethodInfo = MethodInfos; while (MethodInfo->Name) { auto Iter = InfoMap.find(MethodInfo->Name); if (Iter == InfoMap.end()) { - InfoMap[MethodInfo->Name] = std::make_tuple(1, MethodInfo); + InfoMap[MethodInfo->Name] = eastl::make_tuple(1, MethodInfo); } else { - std::get<0>(Iter->second) = 2; + eastl::get<0>(Iter->second) = 2; } ++MethodInfo; } @@ -190,9 +191,9 @@ void SetReflectoinInfo(JSFunctionInfo* Methods, const NamedFunctionInfo* MethodI while (Method->Name) { auto Iter = InfoMap.find(Method->Name); - if (Iter != InfoMap.end() && std::get<0>(Iter->second) == 1) + if (Iter != InfoMap.end() && eastl::get<0>(Iter->second) == 1) { - Method->ReflectionInfo = std::get<1>(Iter->second)->Type; + Method->ReflectionInfo = eastl::get<1>(Iter->second)->Type; } ++Method; } diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index e00f435..799bbe0 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -7,9 +7,10 @@ namespace qjsimpl { extern pesapi_ffi g_pesapi_ffi; -void CppObjectMapper::Initialize(JSContext* ctx) +void CppObjectMapper::Initialize(JSContext* ctx_) { - + ctx = ctx_; + JS_SetContextOpaque(ctx, this); } } From 45ac7a550ac55afeb2bcc68b383628f02fa9e78d Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 19 Feb 2025 11:51:40 +0800 Subject: [PATCH 17/70] =?UTF-8?q?=E7=A7=BB=E9=99=A4register=E5=AF=B9libstd?= =?UTF-8?q?c++/libc++=E7=9A=84=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 14 ++++++ papi-register/include/JSClassRegister.h | 8 ++-- papi-register/include/PString.h | 55 ++++++++++++------------ papi-register/include/TypeInfo.hpp | 1 + papi-register/source/JSClassRegister.cpp | 42 +++++++++--------- 5 files changed, 67 insertions(+), 53 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 24cfd60..34dbd4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,7 +179,21 @@ target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2024_SEPT=EA_DISAB target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2025_APRIL=EA_DISABLED) #target_compile_definitions(PapiQjs PUBLIC EASTL_DLL) target_compile_definitions(PapiQjs PUBLIC USING_REGISTER_API_SHARED) + target_compile_definitions(PapiRegister PUBLIC BUILD_REGISTER_API_SHARED) +target_compile_options(PapiRegister PRIVATE + $<$,$>: + -fno-exceptions + -fno-unwind-tables + -fno-asynchronous-unwind-tables + -fno-rtti + > + $<$: + /EHa- + /EHsc- + /GR- # 禁用RTTI + > +) if ( APPLE AND NOT IOS OR MSVC OR LINUX ) diff --git a/papi-register/include/JSClassRegister.h b/papi-register/include/JSClassRegister.h index 0d2f7ea..f2c7d70 100644 --- a/papi-register/include/JSClassRegister.h +++ b/papi-register/include/JSClassRegister.h @@ -8,8 +8,6 @@ #pragma once -#include "functional" - #if USING_IN_UNREAL_ENGINE #include "CoreMinimal.h" @@ -23,8 +21,6 @@ PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS #define UPTRINT uintptr_t #endif -#include - #include "PuertsNamespaceDef.h" #include "pesapi.h" @@ -138,7 +134,9 @@ void REGISTER_API RegisterJSClass(const JSClassDefinition& ClassDefinition); void REGISTER_API SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos, const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, const NamedPropertyInfo* VariableInfos); -void REGISTER_API ForeachRegisterClass(std::function); +typedef void (*ClassDefinitionForeachCallback)(const JSClassDefinition* ClassDefinition); + +void REGISTER_API ForeachRegisterClass(ClassDefinitionForeachCallback Callback); REGISTER_API const JSClassDefinition* FindClassByID(const void* TypeId); diff --git a/papi-register/include/PString.h b/papi-register/include/PString.h index 3ebd183..3df5356 100644 --- a/papi-register/include/PString.h +++ b/papi-register/include/PString.h @@ -8,8 +8,7 @@ #pragma once -#include -#include +#include #include "NamespaceDef.h" namespace PUERTS_NAMESPACE @@ -18,9 +17,9 @@ class PString { public: // Constructors - PString() : data_(nullptr), size_(0) + PString() noexcept: data_(nullptr), size_(0) { - data_ = new char[1]; + data_ = (char*)malloc(1); data_[0] = '\0'; } @@ -28,8 +27,8 @@ class PString { if (str) { - size_ = std::strlen(str); - data_ = new char[size_ + 1]; + size_ = strlen(str); + data_ = (char*)malloc(size_ + 1); #ifdef _MSC_VER strncpy_s(data_, size_ + 1, str, size_); #else @@ -40,7 +39,7 @@ class PString else { size_ = 0; - data_ = new char[1]; + data_ = (char*)malloc(1); data_[0] = '\0'; } } @@ -50,7 +49,7 @@ class PString if (str) { size_ = length; - data_ = new char[size_ + 1]; + data_ = (char*)malloc(size_ + 1); #ifdef _MSC_VER strncpy_s(data_, size_ + 1, str, length); #else @@ -61,15 +60,15 @@ class PString else { size_ = 0; - data_ = new char[1]; + data_ = (char*)malloc(1); data_[0] = '\0'; } } - PString(const PString& other) + PString(const PString& other) noexcept { size_ = other.size_; - data_ = new char[size_ + 1]; + data_ = (char*)malloc(size_ + 1); #ifdef _MSC_VER strncpy_s(data_, size_ + 1, other.data_, size_); #else @@ -78,13 +77,13 @@ class PString data_[size_] = '\0'; } - PString& operator=(const PString& other) + PString& operator=(const PString& other) noexcept { if (this != &other) { - delete[] data_; + free(data_); size_ = other.size_; - data_ = new char[size_ + 1]; + data_ = (char*)malloc(size_ + 1); #ifdef _MSC_VER strncpy_s(data_, size_ + 1, other.data_, size_); #else @@ -95,17 +94,17 @@ class PString return *this; } - ~PString() + ~PString() noexcept { - delete[] data_; + free(data_); } PString operator+(const PString& other) const { PString result; result.size_ = size_ + other.size_; - delete[] result.data_; - result.data_ = new char[result.size_ + 1]; + free(result.data_); + result.data_ = (char*)malloc(result.size_ + 1); #ifdef _MSC_VER strncpy_s(result.data_, result.size_ + 1, data_, size_); strncpy_s(result.data_ + size_, result.size_ - size_ + 1, other.data_, other.size_); @@ -120,10 +119,10 @@ class PString friend PString operator+(const char* lhs, const PString& rhs) { PString result; - size_t lhs_size = std::strlen(lhs); + size_t lhs_size = strlen(lhs); result.size_ = lhs_size + rhs.size_; - delete[] result.data_; - result.data_ = new char[result.size_ + 1]; + free(result.data_); + result.data_ = (char*)malloc(result.size_ + 1); #ifdef _MSC_VER strncpy_s(result.data_, result.size_ + 1, lhs, lhs_size); strncpy_s(result.data_ + lhs_size, result.size_ - lhs_size + 1, rhs.data_, rhs.size_); @@ -138,7 +137,7 @@ class PString PString& operator+=(const PString& other) { size_t new_size = size_ + other.size_; - char* new_data = new char[new_size + 1]; + char* new_data = (char*)malloc(new_size + 1); #ifdef _MSC_VER strncpy_s(new_data, new_size + 1, data_, size_); strncpy_s(new_data + size_, new_size - size_ + 1, other.data_, other.size_); @@ -148,7 +147,7 @@ class PString #endif new_data[new_size] = '\0'; - delete[] data_; + free(data_); data_ = new_data; size_ = new_size; @@ -159,9 +158,9 @@ class PString { if (str) { - size_t str_size = std::strlen(str); + size_t str_size = strlen(str); size_t new_size = size_ + str_size; - char* new_data = new char[new_size + 1]; + char* new_data = (char*)malloc(new_size + 1); #ifdef _MSC_VER strncpy_s(new_data, new_size + 1, data_, size_); strncpy_s(new_data + size_, new_size - size_ + 1, str, str_size); @@ -171,7 +170,7 @@ class PString #endif new_data[new_size] = '\0'; - delete[] data_; + free(data_); data_ = new_data; size_ = new_size; } @@ -195,12 +194,12 @@ class PString bool operator<(const PString& other) const { - return std::strcmp(data_, other.data_) < 0; + return strcmp(data_, other.data_) < 0; } bool operator==(const PString& other) const { - return std::strcmp(data_, other.data_) == 0; + return strcmp(data_, other.data_) == 0; } private: diff --git a/papi-register/include/TypeInfo.hpp b/papi-register/include/TypeInfo.hpp index 2400fd9..4e42233 100644 --- a/papi-register/include/TypeInfo.hpp +++ b/papi-register/include/TypeInfo.hpp @@ -8,6 +8,7 @@ #pragma once +#include #include #ifdef WITH_V8_FAST_CALL #include "V8FastCall.hpp" diff --git a/papi-register/source/JSClassRegister.cpp b/papi-register/source/JSClassRegister.cpp index f0f76b2..ded02af 100644 --- a/papi-register/source/JSClassRegister.cpp +++ b/papi-register/source/JSClassRegister.cpp @@ -12,7 +12,7 @@ #endif #include #include -#include +#include namespace PUERTS_NAMESPACE { @@ -28,14 +28,14 @@ static T* PropertyInfoDuplicate(T* Arr) if (Arr[Count++].Name == nullptr) break; } - T* Ret = new T[Count]; + T* Ret = (T*)::malloc(sizeof(T) *Count); ::memcpy(Ret, Arr, sizeof(T) * Count); return Ret; } JSClassDefinition* JSClassDefinitionDuplicate(const JSClassDefinition* ClassDefinition) { - auto Ret = new JSClassDefinition; + auto Ret = (JSClassDefinition*)::malloc(sizeof(JSClassDefinition)); ::memcpy(Ret, ClassDefinition, sizeof(JSClassDefinition)); Ret->Methods = PropertyInfoDuplicate(ClassDefinition->Methods); Ret->Functions = PropertyInfoDuplicate(ClassDefinition->Functions); @@ -51,16 +51,16 @@ JSClassDefinition* JSClassDefinitionDuplicate(const JSClassDefinition* ClassDefi void JSClassDefinitionDelete(JSClassDefinition* ClassDefinition) { - delete[] ClassDefinition->Methods; - delete[] ClassDefinition->Functions; - delete[] ClassDefinition->Properties; - delete[] ClassDefinition->Variables; - delete[] ClassDefinition->ConstructorInfos; - delete[] ClassDefinition->MethodInfos; - delete[] ClassDefinition->FunctionInfos; - delete[] ClassDefinition->PropertyInfos; - delete[] ClassDefinition->VariableInfos; - delete ClassDefinition; + ::free(ClassDefinition->Methods); + ::free(ClassDefinition->Functions); + ::free(ClassDefinition->Properties); + ::free(ClassDefinition->Variables); + ::free(ClassDefinition->ConstructorInfos); + ::free(ClassDefinition->MethodInfos); + ::free(ClassDefinition->FunctionInfos); + ::free(ClassDefinition->PropertyInfos); + ::free(ClassDefinition->VariableInfos); + ::free(ClassDefinition); } class JSClassRegister @@ -74,7 +74,7 @@ class JSClassRegister void SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos, const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, const NamedPropertyInfo* VariableInfos); - void ForeachRegisterClass(std::function); + void ForeachRegisterClass(ClassDefinitionForeachCallback Callback); const JSClassDefinition* FindClassByID(const void* TypeId); @@ -113,11 +113,11 @@ class JSClassRegister private: eastl::map, eastl::allocator_malloc> CDataIdToClassDefinition; - eastl::map, eastl::allocator_malloc> CDataNameToClassDefinition; + eastl::map, eastl::allocator_malloc> CDataNameToClassDefinition; //需要禁用rtti,否则含析构函数的类会导致对libstdc++/libc++的依赖,尽管没有使用c++的api pesapi_class_not_found_callback ClassNotFoundCallback = nullptr; #if USING_IN_UNREAL_ENGINE - eastl::map, eastl::allocator_malloc> AddonRegisterInfos; - eastl::map, eastl::allocator_malloc> StructNameToClassDefinition; + eastl::map, eastl::allocator_malloc> AddonRegisterInfos; + eastl::map, eastl::allocator_malloc> StructNameToClassDefinition; #endif }; @@ -279,7 +279,7 @@ const JSClassDefinition* JSClassRegister::FindClassByType(UStruct* Type) } #endif -void JSClassRegister::ForeachRegisterClass(std::function Callback) +void JSClassRegister::ForeachRegisterClass(ClassDefinitionForeachCallback Callback) { for (auto& KV : CDataNameToClassDefinition) { @@ -293,9 +293,11 @@ void JSClassRegister::ForeachRegisterClass(std::functionSetClassTypeInfo(TypeId, ConstructorInfos, MethodInfos, FunctionInfos, PropertyInfos, VariableInfos); } -void ForeachRegisterClass(std::function Callback) +void ForeachRegisterClass(ClassDefinitionForeachCallback Callback) { GetJSClassRegister()->ForeachRegisterClass(Callback); } From 7bf3a60f1a857690fc27ab4de9a814b1badccc62 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 19 Feb 2025 14:45:56 +0800 Subject: [PATCH 18/70] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E4=B8=BB=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=AF=B9libstdc++/libc++=E7=9A=84=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/CppObjectMapper.cpp | 7 ++-- source/PapiQuickjsImpl.cpp | 67 ++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 799bbe0..a4404a8 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -20,7 +20,8 @@ pesapi_env_ref create_qjs_env() { JSRuntime* rt = JS_NewRuntime(); JSContext* ctx = JS_NewContext(rt); - pesapi::qjsimpl::CppObjectMapper* mapper = new pesapi::qjsimpl::CppObjectMapper(); - mapper->Initialize(ctx); - return pesapi::qjsimpl::g_pesapi_ffi.create_env_ref(reinterpret_cast(ctx)); + //pesapi::qjsimpl::CppObjectMapper* mapper = new pesapi::qjsimpl::CppObjectMapper(); + //mapper->Initialize(ctx); + //return pesapi::qjsimpl::g_pesapi_ffi.create_env_ref(reinterpret_cast(ctx)); + return nullptr; } diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 3ecc513..404d792 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -21,18 +21,6 @@ enum struct pesapi_env_ref__ { - explicit pesapi_env_ref__(JSContext *ctx) - : context_persistent(JS_DupContext(ctx)) - , ref_count(1) - //, env_life_cycle_tracker(puerts::DataTransfer::GetJsEnvLifeCycleTracker(context->GetIsolate())) - { - } - - ~pesapi_env_ref__() - { - JS_FreeContext(context_persistent); - } - JSContext *context_persistent; int ref_count; eastl::weak_ptr env_life_cycle_tracker; @@ -48,16 +36,6 @@ struct pesapi_value__ { struct pesapi_value_ref__ : pesapi_env_ref__ { - explicit pesapi_value_ref__(JSContext *ctx, JSValue v, uint32_t field_count) - : pesapi_env_ref__(ctx), value_persistent(JS_DupValue(ctx, v)), internal_field_count(field_count) - { - } - - ~pesapi_value_ref__() - { - JS_FreeValue(context_persistent, value_persistent); - } - JSValue value_persistent; uint32_t internal_field_count; void* internal_fields[0]; @@ -66,6 +44,33 @@ namespace pesapi { namespace qjsimpl { + +static void pesapi_env_ref_init(pesapi_env_ref__* env_ref, JSContext *ctx) +{ + env_ref->context_persistent = JS_DupContext(ctx); + env_ref->ref_count = 1; + // TODO: env_life_cycle_tracker init; +} + + +static void pesapi_env_ref_cleanup(pesapi_env_ref__* env_ref) +{ + JS_FreeContext(env_ref->context_persistent); +} + +static void pesapi_value_ref_init(pesapi_value_ref__* value_ref, JSContext *ctx, JSValue v, uint32_t field_count) +{ + pesapi_env_ref_init(value_ref, ctx); + value_ref->value_persistent = JS_DupValue(ctx, v); + value_ref->internal_field_count = field_count; +} + +static void pesapi_value_ref_cleanup(pesapi_value_ref__* value_ref) +{ + JS_FreeValue(value_ref->context_persistent, value_ref->value_persistent); + pesapi_env_ref_cleanup(value_ref); +} + static struct pesapi_scope__ *getCurrentScope(JSContext *ctx) { return (struct pesapi_scope__ *) JS_GetContextOpaque(ctx); @@ -594,7 +599,10 @@ void pesapi_throw_by_string(pesapi_callback_info pinfo, const char* msg) pesapi_env_ref pesapi_create_env_ref(pesapi_env env) { auto ctx = qjsContextFromPesapiEnv(env); - return new pesapi_env_ref__(ctx); + auto ret = (pesapi_env_ref)malloc(sizeof(pesapi_env_ref__)); + memset(ret, 0, sizeof(pesapi_env_ref__)); + pesapi_env_ref_init(ret, ctx); + return ret; } bool pesapi_env_ref_is_valid(pesapi_env_ref env_ref) @@ -621,14 +629,11 @@ void pesapi_release_env_ref(pesapi_env_ref env_ref) { if (--env_ref->ref_count == 0) { - if (env_ref->env_life_cycle_tracker.expired()) - { - ::operator delete(static_cast(env_ref)); - } - else + if (!env_ref->env_life_cycle_tracker.expired()) { - delete env_ref; + pesapi_env_ref_cleanup(env_ref); } + free(env_ref); } } @@ -685,9 +690,9 @@ void pesapi_release_value_ref(pesapi_value_ref value_ref) { if (!value_ref->env_life_cycle_tracker.expired()) { - value_ref->~pesapi_value_ref__(); + pesapi_value_ref_cleanup(value_ref); } - ::operator delete(static_cast(value_ref)); + free(value_ref); } } From d0de5aa25068aa3f7c3c0f53fb81dba96d2a0564 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 19 Feb 2025 15:02:21 +0800 Subject: [PATCH 19/70] =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 14 +++++++-- source/PapiQuickjsImpl.cpp | 58 +++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index 6c80703..d1b2a89 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -11,11 +11,19 @@ namespace pesapi namespace qjsimpl { -class CppObjectMapper +struct CppObjectMapper { -public: void Initialize(JSContext* ctx_); -private: + + CppObjectMapper(const CppObjectMapper&) = delete; + CppObjectMapper& operator=(const CppObjectMapper&) = delete; + + void* operator new(size_t) = delete; + void operator delete(void*) = delete; + + CppObjectMapper() = default; + ~CppObjectMapper() = default; + eastl::unordered_map, eastl::equal_to, eastl::allocator_malloc> CDataCache; eastl::unordered_map, eastl::equal_to, eastl::allocator_malloc> TypeIdToFunctionMap; diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 404d792..5966c2c 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -24,6 +24,18 @@ struct pesapi_env_ref__ JSContext *context_persistent; int ref_count; eastl::weak_ptr env_life_cycle_tracker; + + void init(JSContext *ctx) + { + context_persistent = JS_DupContext(ctx); + ref_count = 1; + // TODO: env_life_cycle_tracker init; + } + + void cleanup() + { + JS_FreeContext(context_persistent); + } }; struct pesapi_value__ { @@ -39,37 +51,25 @@ struct pesapi_value_ref__ : pesapi_env_ref__ JSValue value_persistent; uint32_t internal_field_count; void* internal_fields[0]; -}; -namespace pesapi -{ -namespace qjsimpl -{ - -static void pesapi_env_ref_init(pesapi_env_ref__* env_ref, JSContext *ctx) -{ - env_ref->context_persistent = JS_DupContext(ctx); - env_ref->ref_count = 1; - // TODO: env_life_cycle_tracker init; -} + void init(JSContext *ctx, JSValue v, uint32_t field_count) + { + pesapi_env_ref__::init(ctx); + value_persistent = JS_DupValue(ctx, v); + internal_field_count = field_count; + } -static void pesapi_env_ref_cleanup(pesapi_env_ref__* env_ref) -{ - JS_FreeContext(env_ref->context_persistent); -} + void cleanup() + { + JS_FreeValue(context_persistent, value_persistent); + pesapi_env_ref__::cleanup(); + } +}; -static void pesapi_value_ref_init(pesapi_value_ref__* value_ref, JSContext *ctx, JSValue v, uint32_t field_count) +namespace pesapi { - pesapi_env_ref_init(value_ref, ctx); - value_ref->value_persistent = JS_DupValue(ctx, v); - value_ref->internal_field_count = field_count; -} - -static void pesapi_value_ref_cleanup(pesapi_value_ref__* value_ref) +namespace qjsimpl { - JS_FreeValue(value_ref->context_persistent, value_ref->value_persistent); - pesapi_env_ref_cleanup(value_ref); -} static struct pesapi_scope__ *getCurrentScope(JSContext *ctx) { @@ -601,7 +601,7 @@ pesapi_env_ref pesapi_create_env_ref(pesapi_env env) auto ctx = qjsContextFromPesapiEnv(env); auto ret = (pesapi_env_ref)malloc(sizeof(pesapi_env_ref__)); memset(ret, 0, sizeof(pesapi_env_ref__)); - pesapi_env_ref_init(ret, ctx); + ret->init(ctx); return ret; } @@ -631,7 +631,7 @@ void pesapi_release_env_ref(pesapi_env_ref env_ref) { if (!env_ref->env_life_cycle_tracker.expired()) { - pesapi_env_ref_cleanup(env_ref); + env_ref->cleanup(); } free(env_ref); } @@ -690,7 +690,7 @@ void pesapi_release_value_ref(pesapi_value_ref value_ref) { if (!value_ref->env_life_cycle_tracker.expired()) { - pesapi_value_ref_cleanup(value_ref); + value_ref->cleanup(); } free(value_ref); } From 340ebf36f5b2c3e8af512f6ec057c7443d995704 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 19 Feb 2025 17:26:02 +0800 Subject: [PATCH 20/70] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E6=9E=90=E6=9E=84?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84libstdc++=E7=9A=84=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 13 +++++++++++++ include/CppObjectMapper.h | 2 ++ include/ObjectCacheNode.h | 15 +++++++++++---- source/CppObjectMapper.cpp | 14 ++++++++++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34dbd4c..93301b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,6 +179,19 @@ target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2024_SEPT=EA_DISAB target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2025_APRIL=EA_DISABLED) #target_compile_definitions(PapiQjs PUBLIC EASTL_DLL) target_compile_definitions(PapiQjs PUBLIC USING_REGISTER_API_SHARED) +target_compile_options(PapiQjs PRIVATE + $<$,$>: + -fno-exceptions + -fno-unwind-tables + -fno-asynchronous-unwind-tables + -fno-rtti + > + $<$: + /EHa- + /EHsc- + /GR- # 禁用RTTI + > +) target_compile_definitions(PapiRegister PUBLIC BUILD_REGISTER_API_SHARED) target_compile_options(PapiRegister PRIVATE diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index d1b2a89..244f995 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -14,6 +14,8 @@ namespace qjsimpl struct CppObjectMapper { void Initialize(JSContext* ctx_); + + void Cleanup(); CppObjectMapper(const CppObjectMapper&) = delete; CppObjectMapper& operator=(const CppObjectMapper&) = delete; diff --git a/include/ObjectCacheNode.h b/include/ObjectCacheNode.h index 1c6354c..860b4a5 100644 --- a/include/ObjectCacheNode.h +++ b/include/ObjectCacheNode.h @@ -60,7 +60,10 @@ class FObjectCacheNode ~FObjectCacheNode() { if (Next) - delete Next; + { + Next->~FObjectCacheNode(); + free(Next); + } JS_FreeValueRT(RT, Value); } @@ -87,7 +90,8 @@ class FObjectCacheNode { auto PreNext = Next; *this = std::move(*Next); - delete PreNext; + PreNext->~FObjectCacheNode(); + free(PreNext); } else { @@ -105,7 +109,8 @@ class FObjectCacheNode { Next = Removed->Next; Removed->Next = nullptr; - delete Removed; + Removed->~FObjectCacheNode(); + free(Removed); } return Removed; } @@ -114,7 +119,9 @@ class FObjectCacheNode inline FObjectCacheNode* Add(const void* TypeId_) { - Next = new FObjectCacheNode(RT, TypeId_, Next); + FObjectCacheNode* newNode = static_cast(malloc(sizeof(FObjectCacheNode))); + new (newNode) FObjectCacheNode(RT, TypeId_, Next); + Next = newNode; return Next; } diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index a4404a8..e697e8f 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -11,6 +11,20 @@ void CppObjectMapper::Initialize(JSContext* ctx_) { ctx = ctx_; JS_SetContextOpaque(ctx, this); + new (&CDataCache) eastl::unordered_map, + eastl::equal_to, eastl::allocator_malloc>(); + new (&TypeIdToFunctionMap) eastl::unordered_map, + eastl::equal_to, eastl::allocator_malloc>(); +} + +void CppObjectMapper::Cleanup() +{ + if (ctx) + { + JS_SetContextOpaque(ctx, nullptr); + } + CDataCache.~hash_map(); + TypeIdToFunctionMap.~hash_map(); } } From e3857e4b52089f0b3dde5896e59e318657dcaff7 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 20 Feb 2025 10:35:25 +0800 Subject: [PATCH 21/70] =?UTF-8?q?=E7=A6=81=E7=94=A8=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E5=90=8E=EF=BC=8C=E6=9E=90=E6=9E=84=E5=87=BD=E6=95=B0=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E4=B8=8D=E4=BC=9A=E5=AF=BC=E8=87=B4libc++=E5=BC=95?= =?UTF-8?q?=E7=94=A8=EF=BC=8C=E6=89=80=E4=BB=A5=E5=8F=AF=E4=BB=A5=E6=94=B9?= =?UTF-8?q?=E5=9B=9Eplacement=20new=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 45 ++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 5966c2c..79c302b 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -21,21 +21,21 @@ enum struct pesapi_env_ref__ { - JSContext *context_persistent; - int ref_count; - eastl::weak_ptr env_life_cycle_tracker; - - void init(JSContext *ctx) + explicit pesapi_env_ref__(JSContext *ctx) + : context_persistent(JS_DupContext(ctx)) + , ref_count(1) + //, env_life_cycle_tracker(puerts::DataTransfer::GetJsEnvLifeCycleTracker(context->GetIsolate())) { - context_persistent = JS_DupContext(ctx); - ref_count = 1; - // TODO: env_life_cycle_tracker init; } - - void cleanup() + + ~pesapi_env_ref__() { JS_FreeContext(context_persistent); } + + JSContext *context_persistent; + int ref_count; + eastl::weak_ptr env_life_cycle_tracker; }; struct pesapi_value__ { @@ -48,22 +48,19 @@ struct pesapi_value__ { struct pesapi_value_ref__ : pesapi_env_ref__ { - JSValue value_persistent; - uint32_t internal_field_count; - void* internal_fields[0]; - - void init(JSContext *ctx, JSValue v, uint32_t field_count) + explicit pesapi_value_ref__(JSContext *ctx, JSValue v, uint32_t field_count) + : pesapi_env_ref__(ctx), value_persistent(JS_DupValue(ctx, v)), internal_field_count(field_count) { - pesapi_env_ref__::init(ctx); - value_persistent = JS_DupValue(ctx, v); - internal_field_count = field_count; } - - void cleanup() + + ~pesapi_value_ref__() { JS_FreeValue(context_persistent, value_persistent); - pesapi_env_ref__::cleanup(); } + + JSValue value_persistent; + uint32_t internal_field_count; + void* internal_fields[0]; }; namespace pesapi @@ -601,7 +598,7 @@ pesapi_env_ref pesapi_create_env_ref(pesapi_env env) auto ctx = qjsContextFromPesapiEnv(env); auto ret = (pesapi_env_ref)malloc(sizeof(pesapi_env_ref__)); memset(ret, 0, sizeof(pesapi_env_ref__)); - ret->init(ctx); + new (ret) pesapi_env_ref__(ctx); return ret; } @@ -631,7 +628,7 @@ void pesapi_release_env_ref(pesapi_env_ref env_ref) { if (!env_ref->env_life_cycle_tracker.expired()) { - env_ref->cleanup(); + env_ref->~pesapi_env_ref__(); } free(env_ref); } @@ -690,7 +687,7 @@ void pesapi_release_value_ref(pesapi_value_ref value_ref) { if (!value_ref->env_life_cycle_tracker.expired()) { - value_ref->cleanup(); + value_ref->~pesapi_value_ref__(); } free(value_ref); } From 43005cf79aff26dbd1b4db92fae87f416fd31cbe Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 20 Feb 2025 11:16:44 +0800 Subject: [PATCH 22/70] =?UTF-8?q?=E6=B7=BB=E5=8A=A0GetEnvLifeCycleTracker?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E6=B7=BB=E5=8A=A0env=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=92=8C=E9=94=80=E6=AF=81=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 21 ++++++++++-- source/CppObjectMapper.cpp | 63 +++++++++++++++++++++++++++++------- source/PapiQuickjsImpl.cpp | 3 +- test/CppObjectMapperTest.cpp | 39 +++++++--------------- 4 files changed, 83 insertions(+), 43 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index 244f995..e4594e4 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -4,6 +4,7 @@ #include "quickjs.h" #include #include +#include #include "ObjectCacheNode.h" namespace pesapi @@ -20,7 +21,7 @@ struct CppObjectMapper CppObjectMapper(const CppObjectMapper&) = delete; CppObjectMapper& operator=(const CppObjectMapper&) = delete; - void* operator new(size_t) = delete; + //void* operator new(size_t) = delete; void operator delete(void*) = delete; CppObjectMapper() = default; @@ -29,11 +30,27 @@ struct CppObjectMapper eastl::unordered_map, eastl::equal_to, eastl::allocator_malloc> CDataCache; eastl::unordered_map, eastl::equal_to, eastl::allocator_malloc> TypeIdToFunctionMap; + JSRuntime* rt; JSContext* ctx; + JSClassID class_id; + eastl::shared_ptr Ref = eastl::allocate_shared(eastl::allocator_malloc("shared_ptr"), 0); + + static eastl::weak_ptr GetEnvLifeCycleTracker(JSContext* ctx) + { + JSRuntime* rt = JS_GetRuntime(ctx); + CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); + return mapper->GetEnvLifeCycleTracker(); + } + + eastl::weak_ptr GetEnvLifeCycleTracker() + { + return eastl::weak_ptr(Ref); + } }; } // namespace qjsimpl } // namespace pesapi -PESAPI_MODULE_EXPORT pesapi_env_ref create_qjs_env(); \ No newline at end of file +PESAPI_MODULE_EXPORT pesapi_env_ref create_qjs_env(); +PESAPI_MODULE_EXPORT void destroy_qjs_env(pesapi_env_ref env_ref); diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index e697e8f..d37d017 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -7,24 +7,42 @@ namespace qjsimpl { extern pesapi_ffi g_pesapi_ffi; +void PApiObjectFinalizer(JSRuntime* rt, JSValue val) +{ + CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); + JS_GetOpaque(val, mapper->class_id); +} + void CppObjectMapper::Initialize(JSContext* ctx_) { ctx = ctx_; - JS_SetContextOpaque(ctx, this); - new (&CDataCache) eastl::unordered_map, - eastl::equal_to, eastl::allocator_malloc>(); - new (&TypeIdToFunctionMap) eastl::unordered_map, - eastl::equal_to, eastl::allocator_malloc>(); + rt = JS_GetRuntime(ctx); + JS_SetRuntimeOpaque(rt, this); + //new (&CDataCache) eastl::unordered_map, + // eastl::equal_to, eastl::allocator_malloc>(); + //new (&TypeIdToFunctionMap) eastl::unordered_map, + // eastl::equal_to, eastl::allocator_malloc>(); + + JSClassDef cls_def; + cls_def.class_name = "__papi_obj"; + cls_def.finalizer = PApiObjectFinalizer; + cls_def.exotic = NULL; + cls_def.gc_mark = NULL; + cls_def.call = NULL; + + class_id = 0; + JS_NewClassID(rt, &class_id); + JS_NewClass(rt, class_id, &cls_def); } void CppObjectMapper::Cleanup() { - if (ctx) + if (rt) { - JS_SetContextOpaque(ctx, nullptr); + JS_SetRuntimeOpaque(rt, nullptr); } - CDataCache.~hash_map(); - TypeIdToFunctionMap.~hash_map(); + //CDataCache.~hash_map(); + //TypeIdToFunctionMap.~hash_map(); } } @@ -34,8 +52,29 @@ pesapi_env_ref create_qjs_env() { JSRuntime* rt = JS_NewRuntime(); JSContext* ctx = JS_NewContext(rt); - //pesapi::qjsimpl::CppObjectMapper* mapper = new pesapi::qjsimpl::CppObjectMapper(); - //mapper->Initialize(ctx); - //return pesapi::qjsimpl::g_pesapi_ffi.create_env_ref(reinterpret_cast(ctx)); + pesapi::qjsimpl::CppObjectMapper* mapper = static_cast(malloc(sizeof(pesapi::qjsimpl::CppObjectMapper))); + + if (mapper) + { + memset(mapper, 0, sizeof(pesapi::qjsimpl::CppObjectMapper)); + new (mapper) pesapi::qjsimpl::CppObjectMapper(); + mapper->Initialize(ctx); + return pesapi::qjsimpl::g_pesapi_ffi.create_env_ref(reinterpret_cast(ctx)); + } return nullptr; } + +void destroy_qjs_env(pesapi_env_ref env_ref) +{ + auto scope = pesapi::qjsimpl::g_pesapi_ffi.open_scope(env_ref); + JSContext* ctx = reinterpret_cast(pesapi::qjsimpl::g_pesapi_ffi.get_env_from_ref(env_ref)); + JSRuntime* rt = JS_GetRuntime(ctx); + pesapi::qjsimpl::CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); + pesapi::qjsimpl::g_pesapi_ffi.close_scope(scope); + if (mapper) + { + mapper->Cleanup(); + mapper->~CppObjectMapper(); + free(mapper); + } +} diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 79c302b..8030e3e 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "CppObjectMapper.h" void GetPapiQuickjsImpl() { @@ -24,7 +25,7 @@ struct pesapi_env_ref__ explicit pesapi_env_ref__(JSContext *ctx) : context_persistent(JS_DupContext(ctx)) , ref_count(1) - //, env_life_cycle_tracker(puerts::DataTransfer::GetJsEnvLifeCycleTracker(context->GetIsolate())) + , env_life_cycle_tracker(pesapi::qjsimpl::CppObjectMapper::GetEnvLifeCycleTracker(ctx)) { } diff --git a/test/CppObjectMapperTest.cpp b/test/CppObjectMapperTest.cpp index 43be51b..83835a7 100644 --- a/test/CppObjectMapperTest.cpp +++ b/test/CppObjectMapperTest.cpp @@ -8,43 +8,26 @@ namespace qjsimpl { class CppObjectMapperTest : public ::testing::Test { protected: void SetUp() override { - rt = JS_NewRuntime(); - ASSERT_NE(rt, nullptr); - ctx = JS_NewContext(rt); - ASSERT_NE(ctx, nullptr); - //mapper = std::make_unique(); + env_ref = create_qjs_env(); } void TearDown() override { - //mapper.reset(); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); + if (env_ref) { + destroy_qjs_env(env_ref); + } } - JSRuntime* rt; - JSContext* ctx; - //std::unique_ptr mapper; + pesapi_env_ref env_ref; }; -TEST_F(CppObjectMapperTest, InitializeShouldSetContext) { - // 测试正常初始化 - //EXPECT_NO_THROW(mapper->Initialize(ctx)); - - // 验证上下文是否被正确设置 - // 这里假设CppObjectMapper有GetContext方法用于测试验证 - // EXPECT_EQ(mapper->GetContext(), ctx); -} - -TEST_F(CppObjectMapperTest, InitializeWithNullContextShouldHandleGracefully) { - // 测试空指针处理 - //EXPECT_NO_THROW(mapper->Initialize(nullptr)); +TEST_F(CppObjectMapperTest, CreateAndDestroyMultQjsEnv) { + //多次调用create_qjs_env和destroy_qjs_env + for (int i = 0; i < 10; i++) { + pesapi_env_ref env_ref = create_qjs_env(); + destroy_qjs_env(env_ref); + } } -TEST_F(CppObjectMapperTest, DoubleInitializationShouldBeSafe) { - // 测试重复初始化 - //EXPECT_NO_THROW(mapper->Initialize(ctx)); - //EXPECT_NO_THROW(mapper->Initialize(ctx)); -} } // namespace qjsimpl } // namespace pesapi From 0d365b3bccea7d9f37a10af402e1a6567f660d20 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 20 Feb 2025 11:21:12 +0800 Subject: [PATCH 23/70] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 10 +++++----- ...{CppObjectMapperTest.cpp => papi_qjs_base_test.cpp} | 0 2 files changed, 5 insertions(+), 5 deletions(-) rename test/{CppObjectMapperTest.cpp => papi_qjs_base_test.cpp} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 93301b7..c53cc95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -227,24 +227,24 @@ enable_testing() include(GoogleTest) -add_executable(cpp_object_mapper_test - test/CppObjectMapperTest.cpp +add_executable(papi_qjs_test + test/papi_qjs_base_test.cpp ) -target_link_libraries(cpp_object_mapper_test +target_link_libraries(papi_qjs_test PRIVATE PapiQjs gtest gtest_main ) -target_include_directories(cpp_object_mapper_test PRIVATE +target_include_directories(papi_qjs_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/source ${CMAKE_CURRENT_SOURCE_DIR}/quickjs ${googletest_SOURCE_DIR}/googletest/include ) -gtest_discover_tests(cpp_object_mapper_test) +gtest_discover_tests(papi_qjs_test) endif() diff --git a/test/CppObjectMapperTest.cpp b/test/papi_qjs_base_test.cpp similarity index 100% rename from test/CppObjectMapperTest.cpp rename to test/papi_qjs_base_test.cpp From 8ba1b375357b6fe78d253d371d002de4fe99cc85 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 20 Feb 2025 12:20:06 +0800 Subject: [PATCH 24/70] =?UTF-8?q?=E8=99=9A=E6=9E=90=E6=9E=84=E4=BC=9A?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E5=AF=B9=5FZdlPvm@CXXABI=5F1.3.9=E7=AC=A6?= =?UTF-8?q?=E5=8F=B7=E7=9A=84=E5=BC=95=E7=94=A8=EF=BC=8C=E8=BF=9B=E8=80=8C?= =?UTF-8?q?=E4=BE=9D=E8=B5=96libc++=EF=BC=8C=E7=9C=8B=E4=B8=8A=E5=8E=BB?= =?UTF-8?q?=E5=AD=90=E7=B1=BB=E9=83=BD=E6=B2=A1=E8=A6=86=E7=9B=96=E8=AF=A5?= =?UTF-8?q?=E6=9E=90=E6=9E=84=E5=87=BD=E6=95=B0=EF=BC=8C=E5=85=88=E5=8E=BB?= =?UTF-8?q?=E6=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EASTL/include/EASTL/shared_ptr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EASTL/include/EASTL/shared_ptr.h b/EASTL/include/EASTL/shared_ptr.h index 9e37a09..558c0d9 100644 --- a/EASTL/include/EASTL/shared_ptr.h +++ b/EASTL/include/EASTL/shared_ptr.h @@ -125,7 +125,7 @@ namespace eastl public: ref_count_sp(int32_t refCount = 1, int32_t weakRefCount = 1) EA_NOEXCEPT; - virtual ~ref_count_sp() EA_NOEXCEPT {} + //virtual ~ref_count_sp() EA_NOEXCEPT {} int32_t use_count() const EA_NOEXCEPT; void addref() EA_NOEXCEPT; From 0e613589a88de3f4762187a6a2b52079f273c7e9 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 20 Feb 2025 15:00:49 +0800 Subject: [PATCH 25/70] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E5=86=8Capi?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 1 + papi-register/source/RapiImpl.cpp | 249 ++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 papi-register/source/RapiImpl.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c53cc95..9794985 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,7 @@ endif() set(papi_register_sources papi-register/source/JSClassRegister.cpp + papi-register/source/RapiImpl.cpp ) if ( APPLE AND IOS ) diff --git a/papi-register/source/RapiImpl.cpp b/papi-register/source/RapiImpl.cpp new file mode 100644 index 0000000..883f088 --- /dev/null +++ b/papi-register/source/RapiImpl.cpp @@ -0,0 +1,249 @@ +#include "pesapi.h" +#include "JSClassRegister.h" +#include +#include +#include + +EXTERN_C_START + +struct pesapi_type_info__ +{ + const char* name; + bool is_pointer; + bool is_const; + bool is_ref; + bool is_primitive; +}; + +struct pesapi_signature_info__ +{ + pesapi_type_info return_type; + size_t parameter_count; + pesapi_type_info parameter_types; +}; + +struct pesapi_property_descriptor__ +{ + const char* name; + bool is_static; + pesapi_callback method; + pesapi_callback getter; + pesapi_callback setter; + void* data0; + void* data1; + + union + { + pesapi_type_info type_info; + pesapi_signature_info signature_info; + } info; +}; + +pesapi_type_info pesapi_alloc_type_infos(size_t count) +{ + auto ret = static_cast(malloc(sizeof(pesapi_type_info__) * count)); + memset(ret, 0, sizeof(pesapi_type_info__) * count); + return ret; +} + +void pesapi_set_type_info( + pesapi_type_info type_infos, size_t index, const char* name, bool is_pointer, bool is_const, bool is_ref, bool is_primitive) +{ + type_infos[index] = {name, is_pointer, is_const, is_ref, is_primitive}; +} + +pesapi_signature_info pesapi_create_signature_info( + pesapi_type_info return_type, size_t parameter_count, pesapi_type_info parameter_types) +{ + auto info = static_cast(malloc(sizeof(pesapi_signature_info__))); + memset(info, 0, sizeof(pesapi_signature_info__)); + info->return_type = return_type; + info->parameter_count = parameter_count; + info->parameter_types = parameter_types; + return info; +} + +pesapi_property_descriptor pesapi_alloc_property_descriptors(size_t count) +{ + auto ret = static_cast(malloc(sizeof(pesapi_property_descriptor__) * count)); + memset(ret, 0, sizeof(pesapi_property_descriptor__) * count); + return ret; +} + +void pesapi_set_method_info(pesapi_property_descriptor properties, size_t index, const char* name, bool is_static, + pesapi_callback method, void* data, pesapi_signature_info signature_info) +{ + properties[index].name = name; + properties[index].is_static = is_static; + properties[index].method = method; + properties[index].data0 = data; + properties[index].info.signature_info = signature_info; +} + +void pesapi_set_property_info(pesapi_property_descriptor properties, size_t index, const char* name, bool is_static, + pesapi_callback getter, pesapi_callback setter, void* getter_data, void* setter_data, pesapi_type_info type_info) +{ + properties[index].name = name; + properties[index].is_static = is_static; + properties[index].getter = getter; + properties[index].setter = setter; + properties[index].data0 = getter_data; + properties[index].data1 = setter_data; + properties[index].info.type_info = type_info; +} + +static void free_property_descriptor(pesapi_property_descriptor properties, size_t property_count) +{ + for (size_t i = 0; i < property_count; i++) + { + pesapi_property_descriptor p = properties + i; + if (p->getter != nullptr || p->setter != nullptr) + { + if (p->info.type_info) + { + free(p->info.type_info); + } + } + else if (p->method != nullptr) + { + if (p->info.signature_info) + { + if (p->info.signature_info->return_type) + { + free(p->info.signature_info->return_type); + } + if (p->info.signature_info->parameter_types) + { + free(p->info.signature_info->parameter_types); + } + p->info.signature_info->~pesapi_signature_info__(); + free(p->info.signature_info); + } + } + } +} + +// set module name here during loading, set nullptr after module loaded +const char* GPesapiModuleName = nullptr; + +void pesapi_define_class(const void* type_id, const void* super_type_id, const char* type_name, pesapi_constructor constructor, + pesapi_finalize finalize, size_t property_count, pesapi_property_descriptor properties, void* data) +{ + puerts::JSClassDefinition classDef = JSClassEmptyDefinition; + classDef.TypeId = type_id; + classDef.SuperTypeId = super_type_id; + puerts::PString ScriptNameWithModuleName = GPesapiModuleName == nullptr ? puerts::PString() : GPesapiModuleName; + if (GPesapiModuleName) + { + ScriptNameWithModuleName += "."; + ScriptNameWithModuleName += type_name; + classDef.ScriptName = ScriptNameWithModuleName.c_str(); + } + else + { + classDef.ScriptName = type_name; + } + classDef.Data = data; + + classDef.Initialize = constructor; + classDef.Finalize = finalize; + + eastl::vector p_methods; + eastl::vector p_functions; + eastl::vector p_properties; + eastl::vector p_variables; + + for (int i = 0; i < property_count; i++) + { + pesapi_property_descriptor p = properties + i; + if (p->getter != nullptr || p->setter != nullptr) + { + if (p->is_static) + { + p_variables.push_back({p->name, p->getter, p->setter, p->data0, p->data1}); + } + else + { + p_properties.push_back({p->name, p->getter, p->setter, p->data0, p->data1}); + } + } + else if (p->method != nullptr) + { + puerts::JSFunctionInfo finfo{p->name, p->method, p->data0}; + if (p->is_static) + { + p_functions.push_back(finfo); + } + else + { + p_methods.push_back(finfo); + } + } + } + + free_property_descriptor(properties, property_count); + + p_methods.push_back(puerts::JSFunctionInfo()); + p_functions.push_back(puerts::JSFunctionInfo()); + p_properties.push_back(puerts::JSPropertyInfo()); + p_variables.push_back(puerts::JSPropertyInfo()); + + classDef.Methods = p_methods.data(); + classDef.Functions = p_functions.data(); + classDef.Properties = p_properties.data(); + classDef.Variables = p_variables.data(); + + puerts::RegisterJSClass(classDef); +} + +void* pesapi_get_class_data(const void* type_id, bool force_load) +{ + auto clsDef = force_load ? puerts::LoadClassByID(type_id) : puerts::FindClassByID(type_id); + return clsDef ? clsDef->Data : nullptr; +} + +bool pesapi_trace_native_object_lifecycle( + const void* type_id, pesapi_on_native_object_enter on_enter, pesapi_on_native_object_exit on_exit) +{ + return puerts::TraceObjectLifecycle(type_id, on_enter, on_exit); +} + +void pesapi_on_class_not_found(pesapi_class_not_found_callback callback) +{ + puerts::OnClassNotFound(callback); +} + +void pesapi_class_type_info(const char* proto_magic_id, const void* type_id, const void* constructor_info, const void* methods_info, + const void* functions_info, const void* properties_info, const void* variables_info) +{ + if (strcmp(proto_magic_id, PUERTS_BINDING_PROTO_ID()) != 0) + { + return; + } + + puerts::SetClassTypeInfo(type_id, static_cast(constructor_info), + static_cast(methods_info), static_cast(functions_info), + static_cast(properties_info), + static_cast(variables_info)); +} + +const void* pesapi_find_type_id(const char* module_name, const char* type_name) +{ + puerts::PString fullname = module_name; + fullname += "."; + fullname += type_name; + const auto class_def = puerts::FindCppTypeClassByName(fullname); + return class_def ? class_def->TypeId : nullptr; +} + +EXTERN_C_END + +MSVC_PRAGMA(warning(push)) +MSVC_PRAGMA(warning(disable : 4191)) +pesapi_func_ptr reg_apis[] = {(pesapi_func_ptr) &pesapi_alloc_type_infos, (pesapi_func_ptr) &pesapi_set_type_info, + (pesapi_func_ptr) &pesapi_create_signature_info, (pesapi_func_ptr) &pesapi_alloc_property_descriptors, + (pesapi_func_ptr) &pesapi_set_method_info, (pesapi_func_ptr) &pesapi_set_property_info, (pesapi_func_ptr) &pesapi_define_class, + (pesapi_func_ptr) &pesapi_get_class_data, (pesapi_func_ptr) &pesapi_trace_native_object_lifecycle, + (pesapi_func_ptr) &pesapi_on_class_not_found, (pesapi_func_ptr) &pesapi_class_type_info, + (pesapi_func_ptr) &pesapi_find_type_id}; +MSVC_PRAGMA(warning(pop)) From adb9b73ad9956c0c47ed4773adbc72b64f2b63b1 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 20 Feb 2025 19:54:44 +0800 Subject: [PATCH 26/70] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E5=86=8Capi?= =?UTF-8?q?=E7=9A=84=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 20 +++++++++++++++----- test/papi_qjs_base_test.cpp | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9794985..b2a9a14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,12 +160,17 @@ else () VISIBILITY_INLINES_HIDDEN TRUE ) # 确保生成导入库路径正确 - set_target_properties(PapiQjs PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} - ) + #set_target_properties(PapiQjs PROPERTIES + # ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} + # LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} + # RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} + #) add_library(PapiRegister SHARED ${eastl_sources} ${papi_register_sources}) + set_target_properties(PapiRegister PROPERTIES + WINDOWS_EXPORT_ALL_SYMBOLS TRUE + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN TRUE + ) endif() target_compile_definitions(PapiQjs PRIVATE ${qjs_defines}) target_include_directories(PapiQjs PUBLIC @@ -189,10 +194,14 @@ target_compile_options(PapiQjs PRIVATE > $<$: /EHa- + /EHsc /EHsc- /GR- # 禁用RTTI > ) +#if(MSVC) +#target_compile_options(PapiQjs PRIVATE /EHsc) +#endif() target_compile_definitions(PapiRegister PUBLIC BUILD_REGISTER_API_SHARED) target_compile_options(PapiRegister PRIVATE @@ -235,6 +244,7 @@ add_executable(papi_qjs_test target_link_libraries(papi_qjs_test PRIVATE PapiQjs + PapiRegister gtest gtest_main ) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 83835a7..8d6d0bb 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -1,11 +1,18 @@ #include #include "CppObjectMapper.h" #include +#include "pesapi.h" +#include "JSClassRegister.h" namespace pesapi { namespace qjsimpl { class CppObjectMapperTest : public ::testing::Test { +public: + static void Foo(struct pesapi_ffi* apis, pesapi_callback_info info) + { + + } protected: void SetUp() override { env_ref = create_qjs_env(); @@ -28,6 +35,19 @@ TEST_F(CppObjectMapperTest, CreateAndDestroyMultQjsEnv) { } } +TEST_F(CppObjectMapperTest, RegApi) { + pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(1); + pesapi_set_method_info(properties, 0, "Foo", true, Foo, NULL, NULL); + pesapi_define_class("Test", NULL, "Test", NULL, NULL, 1, properties, NULL); + + auto clsDef = puerts::FindClassByID("Test"); + ASSERT_TRUE(clsDef != nullptr); + + ASSERT_TRUE(strcmp(clsDef->Functions[0].Name, "Foo") == 0); + + ASSERT_TRUE(clsDef->Functions[0].Callback == Foo); +} + } // namespace qjsimpl } // namespace pesapi From f2a5a31c8c0a252e94f9cb9073d79460bdd7af53 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 20 Feb 2025 20:16:17 +0800 Subject: [PATCH 27/70] =?UTF-8?q?=E8=A7=A3=E5=86=B3linux=E6=89=BE=E4=B8=8D?= =?UTF-8?q?=E5=88=B0=E7=AC=A6=E5=8F=B7=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 22 +++++++++++----------- include/pesapi.h | 4 ++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2a9a14..490724e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,11 +154,11 @@ else () # 在Windows上需要显式生成导入库 add_library(PapiQjs SHARED ${qjs_sources} ${eastl_sources} ${papi_sources}) # if add eastl_headers will undefined symbol: __udivti3 __udivmodti4 # 设置导出符号 - set_target_properties(PapiQjs PROPERTIES - WINDOWS_EXPORT_ALL_SYMBOLS TRUE - CXX_VISIBILITY_PRESET hidden - VISIBILITY_INLINES_HIDDEN TRUE - ) + #set_target_properties(PapiQjs PROPERTIES + # WINDOWS_EXPORT_ALL_SYMBOLS TRUE + # CXX_VISIBILITY_PRESET hidden + # VISIBILITY_INLINES_HIDDEN TRUE + #) # 确保生成导入库路径正确 #set_target_properties(PapiQjs PROPERTIES # ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} @@ -166,11 +166,11 @@ else () # RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} #) add_library(PapiRegister SHARED ${eastl_sources} ${papi_register_sources}) - set_target_properties(PapiRegister PROPERTIES - WINDOWS_EXPORT_ALL_SYMBOLS TRUE - CXX_VISIBILITY_PRESET hidden - VISIBILITY_INLINES_HIDDEN TRUE - ) + #set_target_properties(PapiRegister PROPERTIES + # WINDOWS_EXPORT_ALL_SYMBOLS TRUE + # CXX_VISIBILITY_PRESET hidden + # VISIBILITY_INLINES_HIDDEN TRUE + #) endif() target_compile_definitions(PapiQjs PRIVATE ${qjs_defines}) target_include_directories(PapiQjs PUBLIC @@ -203,7 +203,7 @@ target_compile_options(PapiQjs PRIVATE #target_compile_options(PapiQjs PRIVATE /EHsc) #endif() -target_compile_definitions(PapiRegister PUBLIC BUILD_REGISTER_API_SHARED) +target_compile_definitions(PapiRegister PUBLIC BUILDING_REGISTER_API_SHARED) target_compile_options(PapiRegister PRIVATE $<$,$>: -fno-exceptions diff --git a/include/pesapi.h b/include/pesapi.h index b8bc9b9..cfa4a0f 100644 --- a/include/pesapi.h +++ b/include/pesapi.h @@ -17,7 +17,11 @@ #define PESAPI_VERSION 11 +#if BUILDING_REGISTER_API_SHARED +#define PESAPI_EXTERN PESAPI_MODULE_EXPORT +#else #define PESAPI_EXTERN +#endif #if defined(__APPLE__) && defined(BUILDING_PES_EXTENSION) && !defined(PESAPI_ADPT_C) #include "TargetConditionals.h" From 0c6ab1bd5382fd0215bfb6ef7765c4cda40853cf Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 11:35:17 +0800 Subject: [PATCH 28/70] =?UTF-8?q?g=5Fpesapi=5Fffi=E5=A3=B0=E6=98=8E?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E5=88=B0=E5=A4=B4=E6=96=87=E4=BB=B6=EF=BC=8C?= =?UTF-8?q?=E4=BE=BF=E4=BA=8E=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 5 ++++- source/CppObjectMapper.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index e4594e4..0b0d9e9 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -12,6 +12,8 @@ namespace pesapi namespace qjsimpl { +extern pesapi_ffi g_pesapi_ffi; + struct CppObjectMapper { void Initialize(JSContext* ctx_); @@ -51,6 +53,7 @@ struct CppObjectMapper } // namespace qjsimpl } // namespace pesapi - +// ----------------begin test interface---------------- PESAPI_MODULE_EXPORT pesapi_env_ref create_qjs_env(); PESAPI_MODULE_EXPORT void destroy_qjs_env(pesapi_env_ref env_ref); +// ----------------end test interface---------------- diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index d37d017..1608c36 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -5,7 +5,6 @@ namespace pesapi { namespace qjsimpl { -extern pesapi_ffi g_pesapi_ffi; void PApiObjectFinalizer(JSRuntime* rt, JSValue val) { @@ -48,6 +47,8 @@ void CppObjectMapper::Cleanup() } } +// ----------------begin test interface---------------- + pesapi_env_ref create_qjs_env() { JSRuntime* rt = JS_NewRuntime(); @@ -78,3 +79,5 @@ void destroy_qjs_env(pesapi_env_ref env_ref) free(mapper); } } + +// ----------------end test interface---------------- \ No newline at end of file From e61b0b47b9daed0fc7a91c51880f545e854dd6af Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 13:06:00 +0800 Subject: [PATCH 29/70] =?UTF-8?q?eval=EF=BC=8Cscope=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=92=8C=E5=9F=BA=E7=A1=80=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 3 +-- source/CppObjectMapper.cpp | 6 ++++++ source/PapiQuickjsImpl.cpp | 33 +++++++++++++++++++++++++++++++-- test/papi_qjs_base_test.cpp | 15 +++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index 0b0d9e9..ac2df37 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -12,8 +12,6 @@ namespace pesapi namespace qjsimpl { -extern pesapi_ffi g_pesapi_ffi; - struct CppObjectMapper { void Initialize(JSContext* ctx_); @@ -56,4 +54,5 @@ struct CppObjectMapper // ----------------begin test interface---------------- PESAPI_MODULE_EXPORT pesapi_env_ref create_qjs_env(); PESAPI_MODULE_EXPORT void destroy_qjs_env(pesapi_env_ref env_ref); +PESAPI_MODULE_EXPORT struct pesapi_ffi* get_papi_ffi(); // ----------------end test interface---------------- diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 1608c36..7437b83 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -5,6 +5,7 @@ namespace pesapi { namespace qjsimpl { +extern pesapi_ffi g_pesapi_ffi; void PApiObjectFinalizer(JSRuntime* rt, JSValue val) { @@ -80,4 +81,9 @@ void destroy_qjs_env(pesapi_env_ref env_ref) } } +struct pesapi_ffi* get_papi_ffi() +{ + return &pesapi::qjsimpl::g_pesapi_ffi; +} + // ----------------end test interface---------------- \ No newline at end of file diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 8030e3e..6fb3a94 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -641,6 +641,9 @@ pesapi_scope pesapi_open_scope(pesapi_env_ref env_ref) { return nullptr; } + pesapi_scope ret = static_cast(malloc(sizeof(pesapi_scope))); + memset(ret, 0, sizeof(pesapi_scope)); + new (ret) pesapi_scope__(env_ref->context_persistent); return nullptr; } @@ -650,7 +653,9 @@ pesapi_scope pesapi_open_scope_placement(pesapi_env_ref env_ref, struct pesapi_s { return nullptr; } - return nullptr; + memset(memory, 0, sizeof(struct pesapi_scope_memory)); + new (memory) pesapi_scope__(env_ref->context_persistent); + return reinterpret_cast(memory); } bool pesapi_has_caught(pesapi_scope scope) @@ -665,10 +670,21 @@ const char* pesapi_get_exception_as_string(pesapi_scope scope, bool with_stack) void pesapi_close_scope(pesapi_scope scope) { + if (!scope) + { + return; + } + scope->~pesapi_scope__(); + free(scope); } void pesapi_close_scope_placement(pesapi_scope scope) { + if (!scope) + { + return; + } + scope->~pesapi_scope__(); } pesapi_value_ref pesapi_create_value_ref(pesapi_env env, pesapi_value pvalue, uint32_t internal_field_count) @@ -753,7 +769,20 @@ pesapi_value pesapi_call_function(pesapi_env env, pesapi_value pfunc, pesapi_val pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size, const char* path) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + auto rt = JS_GetRuntime(ctx); + JS_UpdateStackTop(rt); + JSValue retOrEx = JS_Eval(ctx, (const char *)code, code_size, path, JS_EVAL_TYPE_GLOBAL); + if (JS_IsException(retOrEx)) { + auto scope = getCurrentScope(ctx); + scope->exception = JS_GetException(ctx); + + return pesapi_create_undefined(env); + } else { + auto ret = allocValueInCurrentScope(ctx); + *ret = retOrEx; + return pesapiValueFromQjsValue(ret); + } } pesapi_value pesapi_global(pesapi_env env) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 8d6d0bb..a1c748b 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -16,6 +16,7 @@ class CppObjectMapperTest : public ::testing::Test { protected: void SetUp() override { env_ref = create_qjs_env(); + api = get_papi_ffi(); } void TearDown() override { @@ -25,6 +26,7 @@ class CppObjectMapperTest : public ::testing::Test { } pesapi_env_ref env_ref; + struct pesapi_ffi* api; }; TEST_F(CppObjectMapperTest, CreateAndDestroyMultQjsEnv) { @@ -48,6 +50,19 @@ TEST_F(CppObjectMapperTest, RegApi) { ASSERT_TRUE(clsDef->Functions[0].Callback == Foo); } +TEST_F(CppObjectMapperTest, EvalJavaScript) { + auto scope = api->open_scope(env_ref); + auto env = api->get_env_from_ref(env_ref); + + auto code = "123+789"; + auto ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + ASSERT_TRUE(ret != nullptr); + ASSERT_TRUE(api->is_int32(env, ret)); + ASSERT_TRUE(api->get_value_int32(env, ret) == 912); + + api->close_scope(scope); +} + } // namespace qjsimpl } // namespace pesapi From dfbef9df2d2a2b51874cc599c829992f96966d42 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 13:19:42 +0800 Subject: [PATCH 30/70] =?UTF-8?q?=E5=86=85=E5=AD=98=E5=88=86=E9=85=8D?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 4 ++-- test/papi_qjs_base_test.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 6fb3a94..46de6a6 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -641,8 +641,8 @@ pesapi_scope pesapi_open_scope(pesapi_env_ref env_ref) { return nullptr; } - pesapi_scope ret = static_cast(malloc(sizeof(pesapi_scope))); - memset(ret, 0, sizeof(pesapi_scope)); + pesapi_scope ret = static_cast(malloc(sizeof(pesapi_scope__))); + memset(ret, 0, sizeof(pesapi_scope__)); new (ret) pesapi_scope__(env_ref->context_persistent); return nullptr; } diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index a1c748b..fb02b45 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -7,7 +7,7 @@ namespace pesapi { namespace qjsimpl { -class CppObjectMapperTest : public ::testing::Test { +class PApiBaseTest : public ::testing::Test { public: static void Foo(struct pesapi_ffi* apis, pesapi_callback_info info) { @@ -29,7 +29,7 @@ class CppObjectMapperTest : public ::testing::Test { struct pesapi_ffi* api; }; -TEST_F(CppObjectMapperTest, CreateAndDestroyMultQjsEnv) { +TEST_F(PApiBaseTest, CreateAndDestroyMultQjsEnv) { //多次调用create_qjs_env和destroy_qjs_env for (int i = 0; i < 10; i++) { pesapi_env_ref env_ref = create_qjs_env(); @@ -37,7 +37,7 @@ TEST_F(CppObjectMapperTest, CreateAndDestroyMultQjsEnv) { } } -TEST_F(CppObjectMapperTest, RegApi) { +TEST_F(PApiBaseTest, RegApi) { pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(1); pesapi_set_method_info(properties, 0, "Foo", true, Foo, NULL, NULL); pesapi_define_class("Test", NULL, "Test", NULL, NULL, 1, properties, NULL); @@ -50,7 +50,7 @@ TEST_F(CppObjectMapperTest, RegApi) { ASSERT_TRUE(clsDef->Functions[0].Callback == Foo); } -TEST_F(CppObjectMapperTest, EvalJavaScript) { +TEST_F(PApiBaseTest, EvalJavaScript) { auto scope = api->open_scope(env_ref); auto env = api->get_env_from_ref(env_ref); From 20bc7e68fc1d37c60bec75f9d8b1c23cf62887e9 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 14:02:36 +0800 Subject: [PATCH 31/70] =?UTF-8?q?=E6=89=A7=E8=A1=8C=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a935dcd..fa611ee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,6 +23,7 @@ jobs: cd $GITHUB_WORKSPACE chmod +x make_osx.sh sh ./make_osx.sh + ./bulid/papi_qjs_test build_ios: name: iOS @@ -85,6 +86,7 @@ jobs: cd $GITHUB_WORKSPACE chmod +x make_linux64.sh ./make_linux64.sh + ./build_linux64/papi_qjs_test build_wasm: name: wasm @@ -114,5 +116,6 @@ jobs: - name: Build run: | .\make_win64.bat + .\build\Release\papi_qjs_test.exe From 8e2243b12f98b5a9c27be2a9425b283038fe98a2 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 14:07:03 +0800 Subject: [PATCH 32/70] =?UTF-8?q?mac=E7=9A=84=E6=B5=8B=E8=AF=95=E7=94=A8?= =?UTF-8?q?=E4=BE=8B=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fa611ee..1b334f8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: cd $GITHUB_WORKSPACE chmod +x make_osx.sh sh ./make_osx.sh - ./bulid/papi_qjs_test + ./build/Release/papi_qjs_test build_ios: name: iOS From 5445f38d03a1946bedbe387e5140e12cf72be2eb Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 14:39:42 +0800 Subject: [PATCH 33/70] =?UTF-8?q?eval=E5=BC=82=E5=B8=B8=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 17 ++++++++++++----- test/papi_qjs_base_test.cpp | 11 +++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 46de6a6..8154880 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -93,7 +93,8 @@ struct pesapi_scope__ values_used = 0; - exception = JS_NULL; + exception = JS_UNDEFINED; + hasCaught = false; } JSContext *ctx; @@ -102,7 +103,9 @@ struct pesapi_scope__ JSValue values[SCOPE_FIX_SIZE_VALUES_SIZE]; - size_t values_used; + uint32_t values_used; + + bool hasCaught; eastl::vector dynamic_alloc_values; @@ -644,7 +647,7 @@ pesapi_scope pesapi_open_scope(pesapi_env_ref env_ref) pesapi_scope ret = static_cast(malloc(sizeof(pesapi_scope__))); memset(ret, 0, sizeof(pesapi_scope__)); new (ret) pesapi_scope__(env_ref->context_persistent); - return nullptr; + return ret; } pesapi_scope pesapi_open_scope_placement(pesapi_env_ref env_ref, struct pesapi_scope_memory* memory) @@ -660,12 +663,15 @@ pesapi_scope pesapi_open_scope_placement(pesapi_env_ref env_ref, struct pesapi_s bool pesapi_has_caught(pesapi_scope scope) { - return false; + return scope->hasCaught; } const char* pesapi_get_exception_as_string(pesapi_scope scope, bool with_stack) { - return nullptr;; + if (scope->hasCaught) + { + } + return nullptr; } void pesapi_close_scope(pesapi_scope scope) @@ -775,6 +781,7 @@ pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size, JSValue retOrEx = JS_Eval(ctx, (const char *)code, code_size, path, JS_EVAL_TYPE_GLOBAL); if (JS_IsException(retOrEx)) { auto scope = getCurrentScope(ctx); + scope->hasCaught = true; scope->exception = JS_GetException(ctx); return pesapi_create_undefined(env); diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index fb02b45..f7d7720 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -63,6 +63,17 @@ TEST_F(PApiBaseTest, EvalJavaScript) { api->close_scope(scope); } +TEST_F(PApiBaseTest, EvalJavaScriptEx) { + auto scope = api->open_scope(env_ref); + auto env = api->get_env_from_ref(env_ref); + + auto code = " function() { return 123 / 0; } ();"; + auto ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + ASSERT_TRUE(api->has_caught(scope)); + + api->close_scope(scope); +} + } // namespace qjsimpl } // namespace pesapi From 092ae5d75cac18359930f0b97622a41012175acb Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 15:50:09 +0800 Subject: [PATCH 34/70] =?UTF-8?q?pesapi=5Fget=5Fexception=5Fas=5Fstring?= =?UTF-8?q?=E5=8F=8A=E5=85=B6=E6=B5=8B=E8=AF=95=EF=BC=8C=E4=B8=8D=E8=BF=87?= =?UTF-8?q?with=5Fstack=E5=8F=82=E6=95=B0=E7=94=B1=E4=BA=8E=E7=94=A8?= =?UTF-8?q?=E5=BE=97qjs=E7=89=88=E6=9C=AC=E4=B8=8D=E6=94=AF=E6=8C=81JS=5FA?= =?UTF-8?q?TOM=5FfileName=EF=BC=8CJS=5FATOM=5FlineNumber=E5=85=88=E4=B8=8D?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 52 ++++++++++++++++++++++++++++--------- test/papi_qjs_base_test.cpp | 6 ++++- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 8154880..d9c0c51 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -78,6 +78,13 @@ static void setCurrentScope(JSContext *ctx, struct pesapi_scope__ *scope) { JS_SetContextOpaque(ctx, scope); } + +struct caught_exception_info +{ + JSValue exception = JS_UNDEFINED; + eastl::basic_string message; +}; + } } @@ -90,11 +97,8 @@ struct pesapi_scope__ this->ctx = ctx; prev_scope = pesapi::qjsimpl::getCurrentScope(ctx); pesapi::qjsimpl::setCurrentScope(ctx, this); - values_used = 0; - - exception = JS_UNDEFINED; - hasCaught = false; + caught = nullptr; } JSContext *ctx; @@ -105,11 +109,9 @@ struct pesapi_scope__ uint32_t values_used; - bool hasCaught; - eastl::vector dynamic_alloc_values; - JSValue exception; + pesapi::qjsimpl::caught_exception_info* caught; JSValue *allocValue() { @@ -127,10 +129,26 @@ struct pesapi_scope__ return ret; } + void setCaughtException(JSValue exception) + { + if (caught == nullptr) + { + caught = (pesapi::qjsimpl::caught_exception_info *) js_malloc(ctx, sizeof(pesapi::qjsimpl::caught_exception_info)); + memset(caught, 0, sizeof(pesapi::qjsimpl::caught_exception_info)); + new (caught) pesapi::qjsimpl::caught_exception_info(); + } + caught->exception = exception; + } + ~pesapi_scope__() { - JS_FreeValue(ctx, exception); + if (caught) + { + JS_FreeValue(ctx, caught->exception); + caught->~caught_exception_info(); + js_free(ctx, caught); + } for (size_t i = 0; i < values_used; i++) { JS_FreeValue(ctx, values[i]); @@ -663,13 +681,24 @@ pesapi_scope pesapi_open_scope_placement(pesapi_env_ref env_ref, struct pesapi_s bool pesapi_has_caught(pesapi_scope scope) { - return scope->hasCaught; + return scope->caught != nullptr; } const char* pesapi_get_exception_as_string(pesapi_scope scope, bool with_stack) { - if (scope->hasCaught) + if (scope->caught != nullptr) { + auto ctx = scope->ctx; + auto msg = JS_ToCString(ctx, scope->caught->exception); + scope->caught->message = msg; + JS_FreeCString(ctx, msg); + + if (with_stack) + { + //JSValue fileNameVal = JS_GetProperty(ctx, scope->caught->exception, JS_ATOM_fileName); + //JSValue lineNumVal = JS_GetProperty(ctx, scope->caught->exception, JS_ATOM_lineNumber); + } + return scope->caught->message.c_str(); } return nullptr; } @@ -781,8 +810,7 @@ pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size, JSValue retOrEx = JS_Eval(ctx, (const char *)code, code_size, path, JS_EVAL_TYPE_GLOBAL); if (JS_IsException(retOrEx)) { auto scope = getCurrentScope(ctx); - scope->hasCaught = true; - scope->exception = JS_GetException(ctx); + scope->setCaughtException(JS_GetException(ctx)); return pesapi_create_undefined(env); } else { diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index f7d7720..9651b3d 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -67,10 +67,14 @@ TEST_F(PApiBaseTest, EvalJavaScriptEx) { auto scope = api->open_scope(env_ref); auto env = api->get_env_from_ref(env_ref); - auto code = " function() { return 123 / 0; } ();"; + auto code = " (function() { throw new Error('abc'); }) ();"; auto ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); ASSERT_TRUE(api->has_caught(scope)); + EXPECT_STREQ("Error: abc", api->get_exception_as_string(scope, false)); + //printf("%s\n", api->get_exception_as_string(scope, false)); + //printf("%s\n", api->get_exception_as_string(scope, true)); + api->close_scope(scope); } From 408b0eacb15f28bf727291b437fac794da55d108 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 17:02:32 +0800 Subject: [PATCH 35/70] =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=A0=88=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 6 ++++++ test/papi_qjs_base_test.cpp | 1 + 2 files changed, 7 insertions(+) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index d9c0c51..7229581 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -697,6 +697,12 @@ const char* pesapi_get_exception_as_string(pesapi_scope scope, bool with_stack) { //JSValue fileNameVal = JS_GetProperty(ctx, scope->caught->exception, JS_ATOM_fileName); //JSValue lineNumVal = JS_GetProperty(ctx, scope->caught->exception, JS_ATOM_lineNumber); + JSValue stackVal = JS_GetProperty(ctx, scope->caught->exception, JS_ATOM_stack); + auto stack = JS_ToCString(ctx, stackVal); + scope->caught->message += "\n"; + scope->caught->message += stack; + JS_FreeCString(ctx, stack); + JS_FreeValue(ctx, stackVal); } return scope->caught->message.c_str(); } diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 9651b3d..44c7296 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -72,6 +72,7 @@ TEST_F(PApiBaseTest, EvalJavaScriptEx) { ASSERT_TRUE(api->has_caught(scope)); EXPECT_STREQ("Error: abc", api->get_exception_as_string(scope, false)); + EXPECT_STREQ("Error: abc\n at (test.js:1:21)\n at (test.js:1:42)\n", api->get_exception_as_string(scope, true)); //printf("%s\n", api->get_exception_as_string(scope, false)); //printf("%s\n", api->get_exception_as_string(scope, true)); From 1ce463bd32c6f88c85b7f5c5999f6d0304c12230 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 19:39:11 +0800 Subject: [PATCH 36/70] =?UTF-8?q?=E4=B8=80=E4=BA=9Bapi=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 8 ++ source/CppObjectMapper.cpp | 47 ++++++++++ source/PapiData.h | 174 ++++++++++++++++++++++++++++++++++ source/PapiQuickjsImpl.cpp | 187 +++---------------------------------- 4 files changed, 242 insertions(+), 174 deletions(-) create mode 100644 source/PapiData.h diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index ac2df37..42ce45d 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -14,6 +14,11 @@ namespace qjsimpl struct CppObjectMapper { + inline static CppObjectMapper* Get(JSContext* ctx) + { + return reinterpret_cast(JS_GetRuntimeOpaque(JS_GetRuntime(ctx))); + } + void Initialize(JSContext* ctx_); void Cleanup(); @@ -33,6 +38,7 @@ struct CppObjectMapper JSRuntime* rt; JSContext* ctx; JSClassID class_id; + JSClassID func_tracer_class_id; eastl::shared_ptr Ref = eastl::allocate_shared(eastl::allocator_malloc("shared_ptr"), 0); static eastl::weak_ptr GetEnvLifeCycleTracker(JSContext* ctx) @@ -46,6 +52,8 @@ struct CppObjectMapper { return eastl::weak_ptr(Ref); } + + JSValue CreateFunction(pesapi_callback Callback, void* Data, pesapi_function_finalize Finalize); }; } // namespace qjsimpl diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 7437b83..ecedf3b 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -1,5 +1,8 @@ #include "CppObjectMapper.h" #include "pesapi.h" +#include "PapiData.h" + +#define JS_TAG_EXTERNAL (JS_TAG_FLOAT64 + 1) namespace pesapi { @@ -13,6 +16,38 @@ void PApiObjectFinalizer(JSRuntime* rt, JSValue val) JS_GetOpaque(val, mapper->class_id); } +void PApiFuncFinalizer(JSRuntime* rt, JSValue val) +{ + CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); + JS_GetOpaque(val, mapper->func_tracer_class_id); +} + +JSValue CppObjectMapper::CreateFunction(pesapi_callback Callback, void* Data, pesapi_function_finalize Finalize) +{ + JSValue func_data[3] { + JS_MKPTR(JS_TAG_EXTERNAL, Callback), + JS_MKPTR(JS_TAG_EXTERNAL, Data), + JS_MKPTR(JS_TAG_EXTERNAL, Finalize) + }; + + JSValue func = JS_NewCFunctionData(ctx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data) -> JSValue { + pesapi_callback callback = (pesapi_callback)(JS_VALUE_GET_PTR(func_data[0])); + pesapi_callback_info__ callbackInfo { ctx, this_val, argc, argv, JS_VALUE_GET_PTR(func_data[0]), JS_UNDEFINED, JS_UNDEFINED }; + + callback(&g_pesapi_ffi, &callbackInfo); + if (JS_IsException(callbackInfo.res)) + { + return JS_Throw(ctx, callbackInfo.ex); + } + else + { + return callbackInfo.res; + } + }, 0, 0, 3, &func_data[0]); + + return func; +} + void CppObjectMapper::Initialize(JSContext* ctx_) { ctx = ctx_; @@ -33,6 +68,18 @@ void CppObjectMapper::Initialize(JSContext* ctx_) class_id = 0; JS_NewClassID(rt, &class_id); JS_NewClass(rt, class_id, &cls_def); + + + JSClassDef func_tracer_cls_def; + func_tracer_cls_def.class_name = "__papi_func_tracer"; + func_tracer_cls_def.finalizer = PApiFuncFinalizer; + func_tracer_cls_def.exotic = NULL; + func_tracer_cls_def.gc_mark = NULL; + func_tracer_cls_def.call = NULL; + + func_tracer_class_id = 0; + JS_NewClassID(rt, &func_tracer_class_id); + JS_NewClass(rt, func_tracer_class_id, &func_tracer_cls_def); } void CppObjectMapper::Cleanup() diff --git a/source/PapiData.h b/source/PapiData.h new file mode 100644 index 0000000..2c160b1 --- /dev/null +++ b/source/PapiData.h @@ -0,0 +1,174 @@ +#pragma once + +#include "pesapi.h" +#include "quickjs.h" +#include +#include +#include +#include +#include "CppObjectMapper.h" + +enum +{ + JS_ATOM_NULL_, +#define DEF(name, str) JS_ATOM_##name, +#include "quickjs-atom.h" +#undef DEF + JS_ATOM_END, +}; + +struct pesapi_env_ref__ +{ + explicit pesapi_env_ref__(JSContext *ctx) + : context_persistent(JS_DupContext(ctx)) + , ref_count(1) + , env_life_cycle_tracker(pesapi::qjsimpl::CppObjectMapper::GetEnvLifeCycleTracker(ctx)) + { + } + + ~pesapi_env_ref__() + { + JS_FreeContext(context_persistent); + } + + JSContext *context_persistent; + int ref_count; + eastl::weak_ptr env_life_cycle_tracker; +}; + +struct pesapi_value__ { + explicit pesapi_value__(JSValue jsvalue) + : v(jsvalue) + { + } + JSValue v; +}; + +struct pesapi_value_ref__ : pesapi_env_ref__ +{ + explicit pesapi_value_ref__(JSContext *ctx, JSValue v, uint32_t field_count) + : pesapi_env_ref__(ctx), value_persistent(JS_DupValue(ctx, v)), internal_field_count(field_count) + { + } + + ~pesapi_value_ref__() + { + JS_FreeValue(context_persistent, value_persistent); + } + + JSValue value_persistent; + uint32_t internal_field_count; + void* internal_fields[0]; +}; + +namespace pesapi +{ +namespace qjsimpl +{ + +static struct pesapi_scope__ *getCurrentScope(JSContext *ctx) +{ + return (struct pesapi_scope__ *) JS_GetContextOpaque(ctx); +} + +static void setCurrentScope(JSContext *ctx, struct pesapi_scope__ *scope) +{ + JS_SetContextOpaque(ctx, scope); +} + +struct caught_exception_info +{ + JSValue exception = JS_UNDEFINED; + eastl::basic_string message; +}; + +} +} + +struct pesapi_scope__ +{ + const static size_t SCOPE_FIX_SIZE_VALUES_SIZE = 4; + + explicit pesapi_scope__(JSContext *ctx) + { + this->ctx = ctx; + prev_scope = pesapi::qjsimpl::getCurrentScope(ctx); + pesapi::qjsimpl::setCurrentScope(ctx, this); + values_used = 0; + caught = nullptr; + } + + JSContext *ctx; + + pesapi_scope__ *prev_scope; + + JSValue values[SCOPE_FIX_SIZE_VALUES_SIZE]; + + uint32_t values_used; + + eastl::vector dynamic_alloc_values; + + pesapi::qjsimpl::caught_exception_info* caught; + + JSValue *allocValue() + { + JSValue *ret; + if (values_used < SCOPE_FIX_SIZE_VALUES_SIZE) + { + ret = &(values[values_used++]); + } + else + { + ret = (JSValue *) js_malloc(ctx, sizeof(JSValue)); + dynamic_alloc_values.push_back(ret); + } + *ret = JS_UNDEFINED; + return ret; + } + + void setCaughtException(JSValue exception) + { + if (caught == nullptr) + { + caught = (pesapi::qjsimpl::caught_exception_info *) js_malloc(ctx, sizeof(pesapi::qjsimpl::caught_exception_info)); + memset(caught, 0, sizeof(pesapi::qjsimpl::caught_exception_info)); + new (caught) pesapi::qjsimpl::caught_exception_info(); + } + caught->exception = exception; + } + + + ~pesapi_scope__() + { + if (caught) + { + JS_FreeValue(ctx, caught->exception); + caught->~caught_exception_info(); + js_free(ctx, caught); + } + for (size_t i = 0; i < values_used; i++) + { + JS_FreeValue(ctx, values[i]); + } + + for (size_t i = 0; i < dynamic_alloc_values.size(); i++) + { + JS_FreeValue(ctx, *dynamic_alloc_values[i]); + js_free(ctx, dynamic_alloc_values[i]); + } + dynamic_alloc_values.clear(); + pesapi::qjsimpl::setCurrentScope(ctx, prev_scope); + } +}; + +static_assert(sizeof(pesapi_scope_memory) >= sizeof(pesapi_scope__), "sizeof(pesapi_scope__) > sizeof(pesapi_scope_memory__)"); + +struct pesapi_callback_info__ { + JSContext *ctx; + JSValueConst this_val; + int argc; + JSValueConst *argv; + void* data; + JSValue res; + JSValue ex; +}; diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 7229581..6da1310 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -1,170 +1,4 @@ -#include "pesapi.h" -#include "quickjs.h" -#include -#include -#include -#include -#include "CppObjectMapper.h" - -void GetPapiQuickjsImpl() -{ - eastl::basic_string str = "hello world"; -} - -enum -{ - JS_ATOM_NULL_, -#define DEF(name, str) JS_ATOM_##name, -#include "quickjs-atom.h" -#undef DEF - JS_ATOM_END, -}; - -struct pesapi_env_ref__ -{ - explicit pesapi_env_ref__(JSContext *ctx) - : context_persistent(JS_DupContext(ctx)) - , ref_count(1) - , env_life_cycle_tracker(pesapi::qjsimpl::CppObjectMapper::GetEnvLifeCycleTracker(ctx)) - { - } - - ~pesapi_env_ref__() - { - JS_FreeContext(context_persistent); - } - - JSContext *context_persistent; - int ref_count; - eastl::weak_ptr env_life_cycle_tracker; -}; - -struct pesapi_value__ { - explicit pesapi_value__(JSValue jsvalue) - : v(jsvalue) - { - } - JSValue v; -}; - -struct pesapi_value_ref__ : pesapi_env_ref__ -{ - explicit pesapi_value_ref__(JSContext *ctx, JSValue v, uint32_t field_count) - : pesapi_env_ref__(ctx), value_persistent(JS_DupValue(ctx, v)), internal_field_count(field_count) - { - } - - ~pesapi_value_ref__() - { - JS_FreeValue(context_persistent, value_persistent); - } - - JSValue value_persistent; - uint32_t internal_field_count; - void* internal_fields[0]; -}; - -namespace pesapi -{ -namespace qjsimpl -{ - -static struct pesapi_scope__ *getCurrentScope(JSContext *ctx) -{ - return (struct pesapi_scope__ *) JS_GetContextOpaque(ctx); -} - -static void setCurrentScope(JSContext *ctx, struct pesapi_scope__ *scope) -{ - JS_SetContextOpaque(ctx, scope); -} - -struct caught_exception_info -{ - JSValue exception = JS_UNDEFINED; - eastl::basic_string message; -}; - -} -} - -struct pesapi_scope__ -{ - const static size_t SCOPE_FIX_SIZE_VALUES_SIZE = 4; - - explicit pesapi_scope__(JSContext *ctx) - { - this->ctx = ctx; - prev_scope = pesapi::qjsimpl::getCurrentScope(ctx); - pesapi::qjsimpl::setCurrentScope(ctx, this); - values_used = 0; - caught = nullptr; - } - - JSContext *ctx; - - pesapi_scope__ *prev_scope; - - JSValue values[SCOPE_FIX_SIZE_VALUES_SIZE]; - - uint32_t values_used; - - eastl::vector dynamic_alloc_values; - - pesapi::qjsimpl::caught_exception_info* caught; - - JSValue *allocValue() - { - JSValue *ret; - if (values_used < SCOPE_FIX_SIZE_VALUES_SIZE) - { - ret = &(values[values_used++]); - } - else - { - ret = (JSValue *) js_malloc(ctx, sizeof(JSValue)); - dynamic_alloc_values.push_back(ret); - } - *ret = JS_UNDEFINED; - return ret; - } - - void setCaughtException(JSValue exception) - { - if (caught == nullptr) - { - caught = (pesapi::qjsimpl::caught_exception_info *) js_malloc(ctx, sizeof(pesapi::qjsimpl::caught_exception_info)); - memset(caught, 0, sizeof(pesapi::qjsimpl::caught_exception_info)); - new (caught) pesapi::qjsimpl::caught_exception_info(); - } - caught->exception = exception; - } - - - ~pesapi_scope__() - { - if (caught) - { - JS_FreeValue(ctx, caught->exception); - caught->~caught_exception_info(); - js_free(ctx, caught); - } - for (size_t i = 0; i < values_used; i++) - { - JS_FreeValue(ctx, values[i]); - } - - for (size_t i = 0; i < dynamic_alloc_values.size(); i++) - { - JS_FreeValue(ctx, *dynamic_alloc_values[i]); - js_free(ctx, dynamic_alloc_values[i]); - } - dynamic_alloc_values.clear(); - pesapi::qjsimpl::setCurrentScope(ctx, prev_scope); - } -}; - -static_assert(sizeof(pesapi_scope_memory) >= sizeof(pesapi_scope__), "sizeof(pesapi_scope__) > sizeof(pesapi_scope_memory__)"); +#include "PapiData.h" namespace pesapi { @@ -190,7 +24,7 @@ inline JSContext* qjsContextFromPesapiEnv(pesapi_env v) return reinterpret_cast(v); } -static JSValue *allocValueInCurrentScope(JSContext *ctx) +inline JSValue *allocValueInCurrentScope(JSContext *ctx) { auto scope = getCurrentScope(ctx); return scope->allocValue(); @@ -579,40 +413,45 @@ bool pesapi_is_boxed_value(pesapi_env env, pesapi_value value) int pesapi_get_args_len(pesapi_callback_info pinfo) { - return 0; + return pinfo->argc; } pesapi_value pesapi_get_arg(pesapi_callback_info pinfo, int index) { - return {}; + return pesapiValueFromQjsValue(&(pinfo->argv[index])); } PESAPI_EXTERN pesapi_env pesapi_get_env(pesapi_callback_info pinfo) { - return {}; + return pesapiEnvFromQjsContext(pinfo->ctx); } pesapi_value pesapi_get_this(pesapi_callback_info pinfo) { - return {}; + return pesapiValueFromQjsValue(&(pinfo->this_val)); } pesapi_value pesapi_get_holder(pesapi_callback_info pinfo) { - return {}; + return pesapiValueFromQjsValue(&(pinfo->this_val)); } void* pesapi_get_userdata(pesapi_callback_info pinfo) { - return {}; + return pinfo->data; } void pesapi_add_return(pesapi_callback_info pinfo, pesapi_value value) { + pinfo->res = *qjsValueFromPesapiValue(value); } void pesapi_throw_by_string(pesapi_callback_info pinfo, const char* msg) { + pinfo->res = JS_EXCEPTION; + pinfo->ex = JS_NewError(pinfo->ctx); + JS_DefinePropertyValue(pinfo->ctx, pinfo->ex, JS_ATOM_message, JS_NewString(pinfo->ctx, msg), + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); } pesapi_env_ref pesapi_create_env_ref(pesapi_env env) From edd7d3565eff19792875efe1d84ef508f8ffc75f Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 19:56:41 +0800 Subject: [PATCH 37/70] =?UTF-8?q?=E7=BC=96=E8=AF=91=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/CppObjectMapper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index ecedf3b..cb4e506 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -25,9 +25,9 @@ void PApiFuncFinalizer(JSRuntime* rt, JSValue val) JSValue CppObjectMapper::CreateFunction(pesapi_callback Callback, void* Data, pesapi_function_finalize Finalize) { JSValue func_data[3] { - JS_MKPTR(JS_TAG_EXTERNAL, Callback), + JS_MKPTR(JS_TAG_EXTERNAL, (void*)Callback), JS_MKPTR(JS_TAG_EXTERNAL, Data), - JS_MKPTR(JS_TAG_EXTERNAL, Finalize) + JS_MKPTR(JS_TAG_EXTERNAL, (void*)Finalize) }; JSValue func = JS_NewCFunctionData(ctx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data) -> JSValue { From eef406aa8ba3b4c2308c9bc8d339701f2cdbc4d1 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 21 Feb 2025 20:31:43 +0800 Subject: [PATCH 38/70] =?UTF-8?q?create=5Ffunction=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=92=8C=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/CppObjectMapper.cpp | 2 +- source/PapiQuickjsImpl.cpp | 23 +++++++++++++++--- test/papi_qjs_base_test.cpp | 48 +++++++++++++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index cb4e506..189f597 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -32,7 +32,7 @@ JSValue CppObjectMapper::CreateFunction(pesapi_callback Callback, void* Data, pe JSValue func = JS_NewCFunctionData(ctx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data) -> JSValue { pesapi_callback callback = (pesapi_callback)(JS_VALUE_GET_PTR(func_data[0])); - pesapi_callback_info__ callbackInfo { ctx, this_val, argc, argv, JS_VALUE_GET_PTR(func_data[0]), JS_UNDEFINED, JS_UNDEFINED }; + pesapi_callback_info__ callbackInfo { ctx, this_val, argc, argv, JS_VALUE_GET_PTR(func_data[1]), JS_UNDEFINED, JS_UNDEFINED }; callback(&g_pesapi_ffi, &callbackInfo); if (JS_IsException(callbackInfo.res)) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 6da1310..692c117 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -186,7 +186,10 @@ pesapi_value pesapi_create_object(pesapi_env env) pesapi_value pesapi_create_function(pesapi_env env, pesapi_callback native_impl, void* data, pesapi_function_finalize finalize) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + auto ret = allocValueInCurrentScope(ctx); + *ret = pesapi::qjsimpl::CppObjectMapper::Get(ctx)->CreateFunction(native_impl, data, finalize); + return pesapiValueFromQjsValue(ret); } pesapi_value pesapi_create_class(pesapi_env env, const void* type_id) @@ -418,7 +421,14 @@ int pesapi_get_args_len(pesapi_callback_info pinfo) pesapi_value pesapi_get_arg(pesapi_callback_info pinfo, int index) { - return pesapiValueFromQjsValue(&(pinfo->argv[index])); + if (index >= 0 && index < pinfo->argc) + { + return pesapiValueFromQjsValue(&(pinfo->argv[index])); + } + else + { + return pesapiValueFromQjsValue(&literal_values_undefined); + } } PESAPI_EXTERN pesapi_env pesapi_get_env(pesapi_callback_info pinfo) @@ -621,6 +631,10 @@ pesapi_value pesapi_get_property(pesapi_env env, pesapi_value pobject, const cha void pesapi_set_property(pesapi_env env, pesapi_value pobject, const char* key, pesapi_value pvalue) { + auto ctx = qjsContextFromPesapiEnv(env); + JSValue* obj = qjsValueFromPesapiValue(pobject); + JSValue* val = qjsValueFromPesapiValue(pvalue); + JS_SetPropertyStr(ctx, *obj, key, *val); } bool pesapi_get_private(pesapi_env env, pesapi_value pobject, void** out_ptr) @@ -667,7 +681,10 @@ pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size, pesapi_value pesapi_global(pesapi_env env) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + auto ret = allocValueInCurrentScope(ctx); + *ret = JS_GetGlobalObject(ctx); + return pesapiValueFromQjsValue(ret); } const void* pesapi_get_env_private(pesapi_env env) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 44c7296..c5ddc71 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -13,6 +13,20 @@ class PApiBaseTest : public ::testing::Test { { } + + static void Bar(struct pesapi_ffi* apis, pesapi_callback_info info) + { + auto env = apis->get_env(info); + PApiBaseTest* self = (PApiBaseTest*)apis->get_userdata(info); + auto arg0 = apis->get_arg(info, 0); + if (apis->is_int32(env, arg0)) + { + self->bar_data = apis->get_value_int32(env, arg0); + } + } + + int bar_data = 0; + protected: void SetUp() override { env_ref = create_qjs_env(); @@ -73,8 +87,38 @@ TEST_F(PApiBaseTest, EvalJavaScriptEx) { EXPECT_STREQ("Error: abc", api->get_exception_as_string(scope, false)); EXPECT_STREQ("Error: abc\n at (test.js:1:21)\n at (test.js:1:42)\n", api->get_exception_as_string(scope, true)); - //printf("%s\n", api->get_exception_as_string(scope, false)); - //printf("%s\n", api->get_exception_as_string(scope, true)); + + api->close_scope(scope); +} + +TEST_F(PApiBaseTest, SetToGlobal) { + auto scope = api->open_scope(env_ref); + auto env = api->get_env_from_ref(env_ref); + + auto g = api->global(env); + api->set_property(env, g, "SetToGlobal", api->create_int32(env, 123)); + + auto code = " SetToGlobal;"; + auto ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + ASSERT_TRUE(ret != nullptr); + ASSERT_TRUE(api->is_int32(env, ret)); + ASSERT_TRUE(api->get_value_int32(env, ret) == 123); + + api->close_scope(scope); +} + + +TEST_F(PApiBaseTest, CreateJsFunction) { + auto scope = api->open_scope(env_ref); + auto env = api->get_env_from_ref(env_ref); + + auto g = api->global(env); + api->set_property(env, g, "Bar__", api->create_function(env, Bar, this, nullptr)); + auto code = "Bar__(3344);"; + bar_data = 100; + auto ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + ASSERT_FALSE(api->has_caught(scope)); + EXPECT_EQ(bar_data, 3344); api->close_scope(scope); } From 12f7a8bd4203e68db351e05bb585beb1bb72d77b Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 10:26:43 +0800 Subject: [PATCH 39/70] =?UTF-8?q?window=E7=B3=BB=E7=BB=9F=E8=B0=83?= =?UTF-8?q?=E8=AF=95=E7=89=88=E6=9C=AC=E7=9A=84=E5=AD=97=E7=AC=A6=E4=B8=B2?= =?UTF-8?q?=E5=90=8C=E6=A0=B7=E7=9A=84=E5=AD=97=E9=9D=A2=E5=80=BC=EF=BC=8C?= =?UTF-8?q?=E5=85=B6=E6=8C=87=E9=92=88=E5=80=BC=E5=8F=AF=E8=83=BD=E4=B8=8D?= =?UTF-8?q?=E4=B8=80=E6=A0=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index c5ddc71..0a98dff 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -54,9 +54,10 @@ TEST_F(PApiBaseTest, CreateAndDestroyMultQjsEnv) { TEST_F(PApiBaseTest, RegApi) { pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(1); pesapi_set_method_info(properties, 0, "Foo", true, Foo, NULL, NULL); - pesapi_define_class("Test", NULL, "Test", NULL, NULL, 1, properties, NULL); + const void* typeId = "Test"; + pesapi_define_class(typeId, NULL, "Test", NULL, NULL, 1, properties, NULL); - auto clsDef = puerts::FindClassByID("Test"); + auto clsDef = puerts::FindClassByID(typeId); ASSERT_TRUE(clsDef != nullptr); ASSERT_TRUE(strcmp(clsDef->Functions[0].Name, "Foo") == 0); From 89260ef3130f68e6f3be830d5e8ad3c65a2a6f80 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 12:06:17 +0800 Subject: [PATCH 40/70] =?UTF-8?q?=E8=84=9A=E6=9C=AC=E9=87=8C=E9=87=8A?= =?UTF-8?q?=E6=94=BEcreate=5Ffunction=E5=88=9B=E5=BB=BA=E7=9A=84=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=B4=A9=E6=BA=83=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 19 ++++++++++++++---- source/CppObjectMapper.cpp | 40 ++++++++++++++++++++++++++++--------- source/PapiQuickjsImpl.cpp | 28 +++++++++++++++++++++++--- test/papi_qjs_base_test.cpp | 17 +++++++++++++++- 4 files changed, 87 insertions(+), 17 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index 42ce45d..dd0811b 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -37,9 +37,10 @@ struct CppObjectMapper JSRuntime* rt; JSContext* ctx; - JSClassID class_id; - JSClassID func_tracer_class_id; - eastl::shared_ptr Ref = eastl::allocate_shared(eastl::allocator_malloc("shared_ptr"), 0); + JSClassID classId; + JSClassID funcTracerClassId; + const void* envPrivate = nullptr; + eastl::shared_ptr ref = eastl::allocate_shared(eastl::allocator_malloc("shared_ptr"), 0); static eastl::weak_ptr GetEnvLifeCycleTracker(JSContext* ctx) { @@ -50,7 +51,17 @@ struct CppObjectMapper eastl::weak_ptr GetEnvLifeCycleTracker() { - return eastl::weak_ptr(Ref); + return eastl::weak_ptr(ref); + } + + const void* GetEnvPrivate() const + { + return envPrivate; + } + + void SetEnvPrivate(const void* envPrivate_) + { + envPrivate = envPrivate_; } JSValue CreateFunction(pesapi_callback Callback, void* Data, pesapi_function_finalize Finalize); diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 189f597..87b4622 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -13,21 +13,43 @@ extern pesapi_ffi g_pesapi_ffi; void PApiObjectFinalizer(JSRuntime* rt, JSValue val) { CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); - JS_GetOpaque(val, mapper->class_id); + JS_GetOpaque(val, mapper->classId); } +struct FuncFinalizeData +{ + pesapi_function_finalize finalize; + void* data; + CppObjectMapper* mapper; +}; + void PApiFuncFinalizer(JSRuntime* rt, JSValue val) { + printf("func_finalizer\n"); CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); - JS_GetOpaque(val, mapper->func_tracer_class_id); + FuncFinalizeData* data = (FuncFinalizeData*)JS_GetOpaque(val, mapper->funcTracerClassId); + if (data->finalize) + { + data->finalize(&g_pesapi_ffi, data->data, (void*)(data->mapper->GetEnvPrivate())); // TODO: env_private 和 get_env_private 的const修饰统一 + } + js_free_rt(rt, data); } JSValue CppObjectMapper::CreateFunction(pesapi_callback Callback, void* Data, pesapi_function_finalize Finalize) { + FuncFinalizeData* data = (FuncFinalizeData*)js_malloc(ctx, sizeof(FuncFinalizeData)); + data->finalize = Finalize; + data->data = Data; + data->mapper = this; + + JSValue traceObj = JS_NewObjectClass(ctx, funcTracerClassId); + printf("func_tracer_class_id: %d\n", funcTracerClassId); + JS_SetOpaque(traceObj, data); JSValue func_data[3] { JS_MKPTR(JS_TAG_EXTERNAL, (void*)Callback), JS_MKPTR(JS_TAG_EXTERNAL, Data), - JS_MKPTR(JS_TAG_EXTERNAL, (void*)Finalize) + traceObj + //JS_MKPTR(JS_TAG_EXTERNAL, (void*)Finalize) }; JSValue func = JS_NewCFunctionData(ctx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data) -> JSValue { @@ -65,9 +87,9 @@ void CppObjectMapper::Initialize(JSContext* ctx_) cls_def.gc_mark = NULL; cls_def.call = NULL; - class_id = 0; - JS_NewClassID(rt, &class_id); - JS_NewClass(rt, class_id, &cls_def); + classId = 0; + JS_NewClassID(rt, &classId); + JS_NewClass(rt, classId, &cls_def); JSClassDef func_tracer_cls_def; @@ -77,9 +99,9 @@ void CppObjectMapper::Initialize(JSContext* ctx_) func_tracer_cls_def.gc_mark = NULL; func_tracer_cls_def.call = NULL; - func_tracer_class_id = 0; - JS_NewClassID(rt, &func_tracer_class_id); - JS_NewClass(rt, func_tracer_class_id, &func_tracer_cls_def); + funcTracerClassId = 0; + JS_NewClassID(rt, &funcTracerClassId); + JS_NewClass(rt, funcTracerClassId, &func_tracer_cls_def); } void CppObjectMapper::Cleanup() diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 692c117..8bb346e 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -189,6 +189,7 @@ pesapi_value pesapi_create_function(pesapi_env env, pesapi_callback native_impl, auto ctx = qjsContextFromPesapiEnv(env); auto ret = allocValueInCurrentScope(ctx); *ret = pesapi::qjsimpl::CppObjectMapper::Get(ctx)->CreateFunction(native_impl, data, finalize); + //JS_DupValue(ctx, *ret); return pesapiValueFromQjsValue(ret); } @@ -626,7 +627,11 @@ void** pesapi_get_ref_internal_fields(pesapi_value_ref value_ref, uint32_t* pint pesapi_value pesapi_get_property(pesapi_env env, pesapi_value pobject, const char* key) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + JSValue* obj = qjsValueFromPesapiValue(pobject); + auto ret = allocValueInCurrentScope(ctx); + *ret = JS_GetPropertyStr(ctx, *obj, key); + return pesapiValueFromQjsValue(ret); } void pesapi_set_property(pesapi_env env, pesapi_value pobject, const char* key, pesapi_value pvalue) @@ -634,6 +639,9 @@ void pesapi_set_property(pesapi_env env, pesapi_value pobject, const char* key, auto ctx = qjsContextFromPesapiEnv(env); JSValue* obj = qjsValueFromPesapiValue(pobject); JSValue* val = qjsValueFromPesapiValue(pvalue); + if (JS_VALUE_HAS_REF_COUNT(*val)) { + JS_DupValue(ctx, *val); + } JS_SetPropertyStr(ctx, *obj, key, *val); } @@ -649,11 +657,22 @@ bool pesapi_set_private(pesapi_env env, pesapi_value pobject, void* ptr) pesapi_value pesapi_get_property_uint32(pesapi_env env, pesapi_value pobject, uint32_t key) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + JSValue* obj = qjsValueFromPesapiValue(pobject); + auto ret = allocValueInCurrentScope(ctx); + *ret = JS_GetPropertyUint32(ctx, *obj, key); + return pesapiValueFromQjsValue(ret); } void pesapi_set_property_uint32(pesapi_env env, pesapi_value pobject, uint32_t key, pesapi_value pvalue) { + auto ctx = qjsContextFromPesapiEnv(env); + JSValue* obj = qjsValueFromPesapiValue(pobject); + JSValue* val = qjsValueFromPesapiValue(pvalue); + if (JS_VALUE_HAS_REF_COUNT(*val)) { + JS_DupValue(ctx, *val); + } + JS_SetPropertyUint32(ctx, *obj, key, *val); } pesapi_value pesapi_call_function(pesapi_env env, pesapi_value pfunc, pesapi_value this_object, int argc, const pesapi_value argv[]) @@ -689,11 +708,14 @@ pesapi_value pesapi_global(pesapi_env env) const void* pesapi_get_env_private(pesapi_env env) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + return CppObjectMapper::Get(ctx)->GetEnvPrivate(); } void pesapi_set_env_private(pesapi_env env, const void* ptr) { + auto ctx = qjsContextFromPesapiEnv(env); + CppObjectMapper::Get(ctx)->SetEnvPrivate(ptr); } pesapi_ffi g_pesapi_ffi { diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 0a98dff..97a9509 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -25,15 +25,22 @@ class PApiBaseTest : public ::testing::Test { } } + static void JsFuncFinalizer(struct pesapi_ffi* apis, void* data, void* env_private) + { + printf("JsFuncFinalizer %p, %p\n", data, env_private); + } + int bar_data = 0; protected: void SetUp() override { + //printf("SetUp\n"); env_ref = create_qjs_env(); api = get_papi_ffi(); } void TearDown() override { + //printf("TearDown\n"); if (env_ref) { destroy_qjs_env(env_ref); } @@ -114,13 +121,21 @@ TEST_F(PApiBaseTest, CreateJsFunction) { auto env = api->get_env_from_ref(env_ref); auto g = api->global(env); - api->set_property(env, g, "Bar__", api->create_function(env, Bar, this, nullptr)); + api->set_property(env, g, "Bar__", api->create_function(env, Bar, this, JsFuncFinalizer)); auto code = "Bar__(3344);"; bar_data = 100; auto ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (api->has_caught (scope)) { + printf("%s\n", api->get_exception_as_string(scope, true)); + } ASSERT_FALSE(api->has_caught(scope)); EXPECT_EQ(bar_data, 3344); + code = "globalThis.Bar__ = undefined;"; + //code = "Bar__(8899);"; + ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test2.js"); + //ASSERT_FALSE(api->has_caught(scope)); + api->close_scope(scope); } From 432118b31742f62d0c91582a655b815f805c2f68 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 13:13:11 +0800 Subject: [PATCH 41/70] =?UTF-8?q?=E7=94=A8debug=E7=89=88=E6=9C=AC=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 6 +++--- make_linux64.sh | 7 +++++-- make_osx.sh | 5 ++++- make_win64.bat | 16 ++++++++++------ 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1b334f8..7661b2b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: run: | cd $GITHUB_WORKSPACE chmod +x make_osx.sh - sh ./make_osx.sh + sh ./make_osx.sh Debug ./build/Release/papi_qjs_test build_ios: @@ -85,7 +85,7 @@ jobs: run: | cd $GITHUB_WORKSPACE chmod +x make_linux64.sh - ./make_linux64.sh + ./make_linux64.sh Debug ./build_linux64/papi_qjs_test build_wasm: @@ -115,7 +115,7 @@ jobs: uses: microsoft/setup-msbuild@v1.1 - name: Build run: | - .\make_win64.bat + .\make_win64.bat Debug .\build\Release\papi_qjs_test.exe diff --git a/make_linux64.sh b/make_linux64.sh index c72d797..9c22135 100644 --- a/make_linux64.sh +++ b/make_linux64.sh @@ -1,4 +1,7 @@ +#!/bin/bash +CONFIG=${1:-Release} + mkdir -p build_linux64 && cd build_linux64 -cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON ../ +cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_BUILD_TYPE=$CONFIG .. cd .. -cmake --build build_linux64 --config Release +cmake --build build_linux64 --config $CONFIG diff --git a/make_osx.sh b/make_osx.sh index ce3af41..a3b8a0e 100644 --- a/make_osx.sh +++ b/make_osx.sh @@ -1,4 +1,7 @@ +#!/bin/bash +CONFIG=${1:-Release} + mkdir -p build && cd build cmake -GXcode ../ cd .. -cmake --build build --config Release +cmake --build build --config $CONFIG diff --git a/make_win64.bat b/make_win64.bat index fb3bd3c..b7a3833 100644 --- a/make_win64.bat +++ b/make_win64.bat @@ -1,11 +1,15 @@ -mkdir build & pushd build +@echo off +setlocal enabledelayedexpansion -if "%1" == "1" ( - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DQJS_NS=1 -G "Visual Studio 16 2019" -A x64 .. -) else ( - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -G "Visual Studio 16 2019" -A x64 .. +set CONFIG=Release +if not "%1"=="" ( + set CONFIG=%1 ) +mkdir build & pushd build + +cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -G "Visual Studio 16 2019" -A x64 .. + popd -cmake --build build --config Release +cmake --build build --config %CONFIG% pause From 7c168992cf9d1c2fbd9ecab84bef4cbaf08eb49e Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 13:23:48 +0800 Subject: [PATCH 42/70] =?UTF-8?q?ut=E7=A8=8B=E5=BA=8F=E7=9A=84=E8=B7=AF?= =?UTF-8?q?=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7661b2b..e9f9a56 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: cd $GITHUB_WORKSPACE chmod +x make_osx.sh sh ./make_osx.sh Debug - ./build/Release/papi_qjs_test + ./build/Debug/papi_qjs_test build_ios: name: iOS @@ -116,6 +116,6 @@ jobs: - name: Build run: | .\make_win64.bat Debug - .\build\Release\papi_qjs_test.exe + .\build\Debug\papi_qjs_test.exe From 496b72f9c5e0cf954ee4e00b68af7b5940459359 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 13:31:03 +0800 Subject: [PATCH 43/70] =?UTF-8?q?=E9=87=8A=E6=94=BE=E8=99=9A=E6=8B=9F?= =?UTF-8?q?=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/CppObjectMapper.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 87b4622..05a6d8c 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -1,4 +1,4 @@ -#include "CppObjectMapper.h" +#include "CppObjectMapper.h" #include "pesapi.h" #include "PapiData.h" @@ -106,6 +106,8 @@ void CppObjectMapper::Initialize(JSContext* ctx_) void CppObjectMapper::Cleanup() { + CDataCache.clear(); + TypeIdToFunctionMap.clear(); if (rt) { JS_SetRuntimeOpaque(rt, nullptr); @@ -137,17 +139,21 @@ pesapi_env_ref create_qjs_env() void destroy_qjs_env(pesapi_env_ref env_ref) { - auto scope = pesapi::qjsimpl::g_pesapi_ffi.open_scope(env_ref); + //auto scope = pesapi::qjsimpl::g_pesapi_ffi.open_scope(env_ref); JSContext* ctx = reinterpret_cast(pesapi::qjsimpl::g_pesapi_ffi.get_env_from_ref(env_ref)); JSRuntime* rt = JS_GetRuntime(ctx); pesapi::qjsimpl::CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); - pesapi::qjsimpl::g_pesapi_ffi.close_scope(scope); + //pesapi::qjsimpl::g_pesapi_ffi.close_scope(scope); + pesapi::qjsimpl::g_pesapi_ffi.release_env_ref(env_ref); if (mapper) { mapper->Cleanup(); mapper->~CppObjectMapper(); free(mapper); } + + JS_FreeContext(ctx); + JS_FreeRuntime(rt); } struct pesapi_ffi* get_papi_ffi() From 67558a2dc0a9f028a6003528cd750390da186a3e Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 13:38:10 +0800 Subject: [PATCH 44/70] Assertion failed: list_empty(&rt->gc_obj_list) --- source/CppObjectMapper.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 05a6d8c..6302653 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -25,7 +25,6 @@ struct FuncFinalizeData void PApiFuncFinalizer(JSRuntime* rt, JSValue val) { - printf("func_finalizer\n"); CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); FuncFinalizeData* data = (FuncFinalizeData*)JS_GetOpaque(val, mapper->funcTracerClassId); if (data->finalize) @@ -43,13 +42,11 @@ JSValue CppObjectMapper::CreateFunction(pesapi_callback Callback, void* Data, pe data->mapper = this; JSValue traceObj = JS_NewObjectClass(ctx, funcTracerClassId); - printf("func_tracer_class_id: %d\n", funcTracerClassId); JS_SetOpaque(traceObj, data); JSValue func_data[3] { JS_MKPTR(JS_TAG_EXTERNAL, (void*)Callback), JS_MKPTR(JS_TAG_EXTERNAL, Data), traceObj - //JS_MKPTR(JS_TAG_EXTERNAL, (void*)Finalize) }; JSValue func = JS_NewCFunctionData(ctx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data) -> JSValue { @@ -67,6 +64,8 @@ JSValue CppObjectMapper::CreateFunction(pesapi_callback Callback, void* Data, pe } }, 0, 0, 3, &func_data[0]); + JS_FreeValue(ctx, traceObj); // 在JS_NewCFunctionData有个dup的过程 + return func; } From cc14d5510e3cb2efbedc6867986eb34a4f8ceb5c Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 14:16:08 +0800 Subject: [PATCH 45/70] =?UTF-8?q?=E5=8A=A0=E4=B8=8Acreate=5Ffunction?= =?UTF-8?q?=E7=9A=84finalize=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 97a9509..6882e51 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -27,11 +27,14 @@ class PApiBaseTest : public ::testing::Test { static void JsFuncFinalizer(struct pesapi_ffi* apis, void* data, void* env_private) { - printf("JsFuncFinalizer %p, %p\n", data, env_private); + PApiBaseTest* self = (PApiBaseTest*)data; + self->finalizer_env_private = env_private; } int bar_data = 0; + void* finalizer_env_private = nullptr; + protected: void SetUp() override { //printf("SetUp\n"); @@ -132,11 +135,16 @@ TEST_F(PApiBaseTest, CreateJsFunction) { EXPECT_EQ(bar_data, 3344); code = "globalThis.Bar__ = undefined;"; - //code = "Bar__(8899);"; + finalizer_env_private = nullptr; + api->set_env_private(env, &bar_data); ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test2.js"); - //ASSERT_FALSE(api->has_caught(scope)); + ASSERT_FALSE(api->has_caught(scope)); api->close_scope(scope); + + EXPECT_EQ((void*)&bar_data, finalizer_env_private); + EXPECT_EQ(api->get_env_private(env), finalizer_env_private); + api->set_env_private(env, nullptr); } From 84174c5334c67ff0aeb4196d52a14409c01b71df Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 14:31:17 +0800 Subject: [PATCH 46/70] =?UTF-8?q?=E5=B1=9E=E6=80=A7=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=92=8C=E8=8E=B7=E5=8F=96=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 6882e51..0df9f47 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -148,6 +148,37 @@ TEST_F(PApiBaseTest, CreateJsFunction) { } +TEST_F(PApiBaseTest, PropertyGetSet) { + auto scope = api->open_scope(env_ref); + auto env = api->get_env_from_ref(env_ref); + + auto g = api->global(env); + api->set_property(env, g, "PropertyGetSet", api->create_string_utf8(env, "123", 3)); + + auto str = api->get_property(env, g, "PropertyGetSet"); + ASSERT_TRUE(api->is_string(env, str)); + size_t len = 0; + api->get_value_string_utf8(env, str, nullptr, &len); + ASSERT_EQ(len, 3); + char buff[4] = {0}; + api->get_value_string_utf8(env, str, buff, &len); + buff[3] = 0; + EXPECT_STREQ("123", buff); + + api->set_property_uint32(env, g, 5, api->create_string_utf8(env, "888", 3)); + str = api->get_property_uint32(env, g, 5); + ASSERT_TRUE(api->is_string(env, str)); + len = 0; + api->get_value_string_utf8(env, str, nullptr, &len); + ASSERT_EQ(len, 3); + buff[3] = 0; + api->get_value_string_utf8(env, str, buff, &len); + EXPECT_STREQ("888", buff); + + api->close_scope(scope); +} + + } // namespace qjsimpl } // namespace pesapi From 4bb220ab967ed49dec07c58261cefc1c4619979b Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 19:00:24 +0800 Subject: [PATCH 47/70] =?UTF-8?q?=E5=8E=9F=E7=94=9F=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- include/CppObjectMapper.h | 11 +++ include/ObjectCacheNode.h | 2 +- source/CppObjectMapper.cpp | 157 ++++++++++++++++++++++++++++++++---- source/PapiQuickjsImpl.cpp | 6 +- test/papi_qjs_base_test.cpp | 53 +++++++++++- 6 files changed, 209 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 490724e..d8d7c8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,7 +177,7 @@ target_include_directories(PapiQjs PUBLIC $ $ ) -target_link_libraries(PapiQjs PUBLIC ${qjs_libs}) +target_link_libraries(PapiQjs PUBLIC ${qjs_libs} PapiRegister) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib") target_compile_definitions(PapiQjs PUBLIC EA_DEPRECATIONS_FOR_2024_APRIL=EA_DISABLED) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index dd0811b..b3be4f3 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -6,6 +6,7 @@ #include #include #include "ObjectCacheNode.h" +#include "JSClassRegister.h" namespace pesapi { @@ -65,6 +66,16 @@ struct CppObjectMapper } JSValue CreateFunction(pesapi_callback Callback, void* Data, pesapi_function_finalize Finalize); + + JSValue CreateClassByID(const void* typeId); + + static JSValue CreateError(JSContext* ctx, const char* message); + + JSValue CreateClass(const puerts::JSClassDefinition* ClassDefinition); + + void AddToCache(const puerts::JSClassDefinition* typeInfo, const void* ptr, JSValue value, bool callFinalize); + + void RemoveFromCache(const puerts::JSClassDefinition* typeInfo, const void* ptr); }; } // namespace qjsimpl diff --git a/include/ObjectCacheNode.h b/include/ObjectCacheNode.h index 860b4a5..5265882 100644 --- a/include/ObjectCacheNode.h +++ b/include/ObjectCacheNode.h @@ -18,7 +18,7 @@ namespace qjsimpl class FObjectCacheNode { public: - inline FObjectCacheNode(JSRuntime* RT_, void* TypeId_) : RT(RT_), TypeId(TypeId_), UserData(nullptr), Next(nullptr), MustCallFinalize(false) + inline FObjectCacheNode(JSRuntime* RT_, const void* TypeId_) : RT(RT_), TypeId(TypeId_), UserData(nullptr), Next(nullptr), MustCallFinalize(false) { } diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 6302653..9e412d5 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -10,12 +10,6 @@ namespace qjsimpl { extern pesapi_ffi g_pesapi_ffi; -void PApiObjectFinalizer(JSRuntime* rt, JSValue val) -{ - CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); - JS_GetOpaque(val, mapper->classId); -} - struct FuncFinalizeData { pesapi_function_finalize finalize; @@ -23,6 +17,13 @@ struct FuncFinalizeData CppObjectMapper* mapper; }; +struct ObjectUserData +{ + const puerts::JSClassDefinition* typeInfo; + const void* ptr; + bool callFinalize; +}; + void PApiFuncFinalizer(JSRuntime* rt, JSValue val) { CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); @@ -64,11 +65,144 @@ JSValue CppObjectMapper::CreateFunction(pesapi_callback Callback, void* Data, pe } }, 0, 0, 3, &func_data[0]); - JS_FreeValue(ctx, traceObj); // 在JS_NewCFunctionData有个dup的过程 + JS_FreeValue(ctx, traceObj); // 在JS_NewCFunctionData有个duplicate操作,所以这里要free return func; } +JSValue CppObjectMapper::CreateError(JSContext* ctx, const char* message) +{ + JSValue ret = JS_NewError(ctx); + JS_DefinePropertyValue(ctx, ret, JS_ATOM_message, JS_NewString(ctx, message), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + return ret; +} + +void PApiObjectFinalizer(JSRuntime* rt, JSValue val) +{ + CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); + ObjectUserData* object_udata = (ObjectUserData*)JS_GetOpaque(val, mapper->classId); + + if (object_udata->callFinalize && object_udata->typeInfo->Finalize) + { + object_udata->typeInfo->Finalize(&g_pesapi_ffi, (void*)object_udata->ptr, object_udata->typeInfo->Data, (void*)(mapper->GetEnvPrivate())); + } + mapper->RemoveFromCache(object_udata->typeInfo, object_udata->ptr); + js_free_rt(rt, object_udata); +} + +void CppObjectMapper::AddToCache(const puerts::JSClassDefinition* typeInfo, const void* ptr, JSValue value, bool callFinalize) +{ + ObjectUserData* object_udata = (ObjectUserData*)js_malloc(ctx, sizeof(ObjectUserData)); + object_udata->typeInfo = typeInfo; + object_udata->ptr = ptr; + object_udata->callFinalize = callFinalize; + + JS_SetOpaque(value, object_udata); + + auto Iter = CDataCache.find(ptr); + FObjectCacheNode* CacheNodePtr; + if (Iter != CDataCache.end()) + { + CacheNodePtr = Iter->second.Add(typeInfo->TypeId); + } + else + { + auto Ret = CDataCache.insert({ptr, FObjectCacheNode(JS_GetRuntime(ctx), typeInfo->TypeId)}); + CacheNodePtr = &Ret.first->second; + } + CacheNodePtr->Value = value; +} + +void CppObjectMapper::RemoveFromCache(const puerts::JSClassDefinition* typeInfo, const void* ptr) +{ + auto Iter = CDataCache.find(ptr); + if (Iter != CDataCache.end()) + { + auto Removed = Iter->second.Remove(typeInfo->TypeId, true); + if (!Iter->second.TypeId) // last one + { + CDataCache.erase(ptr); + } + } +} + +JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefinition) +{ + auto it = TypeIdToFunctionMap.find(ClassDefinition->TypeId); + if (it == TypeIdToFunctionMap.end()) + { + puerts::JSPropertyInfo* PropertyInfo = ClassDefinition->Properties; + while (PropertyInfo && PropertyInfo->Name) + { + + } + + PropertyInfo = ClassDefinition->Variables; + while (PropertyInfo && PropertyInfo->Name) + { + + } + + puerts::JSFunctionInfo* FunctionInfo = ClassDefinition->Methods; + while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) + { + + } + + FunctionInfo = ClassDefinition->Functions; + while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) + { + + } + + JSValue ctor_data[2] { + JS_MKPTR(JS_TAG_EXTERNAL, (void*)ClassDefinition), + JS_MKPTR(JS_TAG_EXTERNAL, this) + }; + + JSValue func = JS_NewCFunctionData(ctx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *ctor_data) -> JSValue { + const puerts::JSClassDefinition* clsDef = (const puerts::JSClassDefinition*)(JS_VALUE_GET_PTR(ctor_data[0])); + CppObjectMapper* mapper = (CppObjectMapper*)(JS_VALUE_GET_PTR(ctor_data[1])); + + if (clsDef->Initialize) + { + pesapi_callback_info__ callbackInfo { ctx, this_val, argc, argv, JS_VALUE_GET_PTR(ctor_data[1]), JS_UNDEFINED, JS_UNDEFINED }; + JSValue proto = JS_GetProperty(ctx, this_val, JS_ATOM_prototype); + callbackInfo.this_val = JS_NewObjectProtoClass(ctx, proto, mapper->classId); + JS_FreeValue(ctx, proto); + void* ptr = clsDef->Initialize(&g_pesapi_ffi, &callbackInfo); + mapper->AddToCache(clsDef, ptr, callbackInfo.this_val, true); + if (JS_IsException(callbackInfo.res)) + { + return JS_Throw(ctx, callbackInfo.ex); + } + else + { + return callbackInfo.res; + } + } + else + { + return JS_Throw(ctx, CppObjectMapper::CreateError(ctx, "no initialize function")); + } + }, 0, 0, 2, &ctor_data[0]); + + TypeIdToFunctionMap[ClassDefinition->TypeId] = func; + return func; + } + return it->second; +} + +JSValue CppObjectMapper::CreateClassByID(const void* typeId) +{ + auto clsDef = puerts::LoadClassByID(typeId); + if (!clsDef) + { + return JS_UNDEFINED; + } + return CreateClass(clsDef); +} + void CppObjectMapper::Initialize(JSContext* ctx_) { ctx = ctx_; @@ -107,10 +241,6 @@ void CppObjectMapper::Cleanup() { CDataCache.clear(); TypeIdToFunctionMap.clear(); - if (rt) - { - JS_SetRuntimeOpaque(rt, nullptr); - } //CDataCache.~hash_map(); //TypeIdToFunctionMap.~hash_map(); } @@ -144,15 +274,14 @@ void destroy_qjs_env(pesapi_env_ref env_ref) pesapi::qjsimpl::CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); //pesapi::qjsimpl::g_pesapi_ffi.close_scope(scope); pesapi::qjsimpl::g_pesapi_ffi.release_env_ref(env_ref); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); if (mapper) { mapper->Cleanup(); mapper->~CppObjectMapper(); free(mapper); } - - JS_FreeContext(ctx); - JS_FreeRuntime(rt); } struct pesapi_ffi* get_papi_ffi() diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 8bb346e..b7abb5b 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -189,13 +189,15 @@ pesapi_value pesapi_create_function(pesapi_env env, pesapi_callback native_impl, auto ctx = qjsContextFromPesapiEnv(env); auto ret = allocValueInCurrentScope(ctx); *ret = pesapi::qjsimpl::CppObjectMapper::Get(ctx)->CreateFunction(native_impl, data, finalize); - //JS_DupValue(ctx, *ret); return pesapiValueFromQjsValue(ret); } pesapi_value pesapi_create_class(pesapi_env env, const void* type_id) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + auto ret = allocValueInCurrentScope(ctx); + *ret = pesapi::qjsimpl::CppObjectMapper::Get(ctx)->CreateClassByID(type_id); + return pesapiValueFromQjsValue(ret); } int JS_ToBool2(JSContext *ctx, bool *pres, JSValue val) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 0df9f47..d67c5e3 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -36,10 +36,45 @@ class PApiBaseTest : public ::testing::Test { void* finalizer_env_private = nullptr; protected: + static void EmptyFinalizer(struct pesapi_ffi* apis, void* data, void* env_private) + { + + } + void SetUp() override { //printf("SetUp\n"); env_ref = create_qjs_env(); api = get_papi_ffi(); + + auto scope = api->open_scope(env_ref); + auto env = api->get_env_from_ref(env_ref); + + auto g = api->global(env); + api->set_property(env, g, "loadClass", api->create_function(env, LoadClass, this, EmptyFinalizer)); + api->close_scope(scope); + } + + static void LoadClass(struct pesapi_ffi* apis, pesapi_callback_info info) + { + auto env = apis->get_env(info); + auto arg0 = apis->get_arg(info, 0); + if (apis->is_string(env, arg0)) + { + char buff[1024]; + size_t len = sizeof(buff); + const char* className = apis->get_value_string_utf8(env, arg0, buff, &len); + printf("LoadClass className: %s\n", className); + auto clsDef = puerts::FindCppTypeClassByName(className); + if (clsDef) + { + auto ret = apis->create_class(env, clsDef->TypeId); + apis->add_return(info, ret); + } + else + { + printf("LoadClass className: %s fail!!!\n", className); + } + } } void TearDown() override { @@ -55,10 +90,10 @@ class PApiBaseTest : public ::testing::Test { TEST_F(PApiBaseTest, CreateAndDestroyMultQjsEnv) { //多次调用create_qjs_env和destroy_qjs_env - for (int i = 0; i < 10; i++) { - pesapi_env_ref env_ref = create_qjs_env(); - destroy_qjs_env(env_ref); - } + //for (int i = 0; i < 10; i++) { + // pesapi_env_ref env_ref = create_qjs_env(); + // destroy_qjs_env(env_ref); + //} } TEST_F(PApiBaseTest, RegApi) { @@ -178,6 +213,16 @@ TEST_F(PApiBaseTest, PropertyGetSet) { api->close_scope(scope); } +TEST_F(PApiBaseTest, ClassCtorFinalize) { + /*auto scope = api->open_scope(env_ref); + auto env = api->get_env_from_ref(env_ref); + + auto code = "loadClass(Test');"; + api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + + api->close_scope(scope);*/ +} + } // namespace qjsimpl } // namespace pesapi From 2a1424250f99f8d4adcffd099fdaee686ff20812 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 19:03:29 +0800 Subject: [PATCH 48/70] =?UTF-8?q?loadClass=E6=B5=8B=E8=AF=95=E7=94=A8?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index d67c5e3..e960032 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -50,7 +50,7 @@ class PApiBaseTest : public ::testing::Test { auto env = api->get_env_from_ref(env_ref); auto g = api->global(env); - api->set_property(env, g, "loadClass", api->create_function(env, LoadClass, this, EmptyFinalizer)); + api->set_property(env, g, "loadClass", api->create_function(env, LoadClass, this, nullptr)); api->close_scope(scope); } @@ -214,13 +214,14 @@ TEST_F(PApiBaseTest, PropertyGetSet) { } TEST_F(PApiBaseTest, ClassCtorFinalize) { - /*auto scope = api->open_scope(env_ref); + auto scope = api->open_scope(env_ref); auto env = api->get_env_from_ref(env_ref); - auto code = "loadClass(Test');"; + auto code = "loadClass('Test');"; api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + ASSERT_FALSE(api->has_caught(scope)); - api->close_scope(scope);*/ + api->close_scope(scope); } From 0efbe502421de8780838dafd343d814fb98887ee Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 19:59:47 +0800 Subject: [PATCH 49/70] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=A5=BD=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E5=87=BD=E6=95=B0=E7=9A=84=E5=BC=95=E7=94=A8=E8=AE=A1?= =?UTF-8?q?=E6=95=B0=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/CppObjectMapper.cpp | 15 ++++++++++----- source/PapiQuickjsImpl.cpp | 4 ++++ test/papi_qjs_base_test.cpp | 15 +++++---------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 9e412d5..f12df12 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -134,25 +134,25 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin puerts::JSPropertyInfo* PropertyInfo = ClassDefinition->Properties; while (PropertyInfo && PropertyInfo->Name) { - + ++PropertyInfo; } PropertyInfo = ClassDefinition->Variables; while (PropertyInfo && PropertyInfo->Name) { - + ++PropertyInfo; } puerts::JSFunctionInfo* FunctionInfo = ClassDefinition->Methods; while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) { - + ++FunctionInfo; } FunctionInfo = ClassDefinition->Functions; while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) { - + ++FunctionInfo; } JSValue ctor_data[2] { @@ -188,6 +188,7 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin }, 0, 0, 2, &ctor_data[0]); TypeIdToFunctionMap[ClassDefinition->TypeId] = func; + JS_DupValue(ctx, func); return func; } return it->second; @@ -239,6 +240,10 @@ void CppObjectMapper::Initialize(JSContext* ctx_) void CppObjectMapper::Cleanup() { + for(auto& kv : TypeIdToFunctionMap) + { + JS_FreeValue(ctx, kv.second); + } CDataCache.clear(); TypeIdToFunctionMap.clear(); //CDataCache.~hash_map(); @@ -274,11 +279,11 @@ void destroy_qjs_env(pesapi_env_ref env_ref) pesapi::qjsimpl::CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); //pesapi::qjsimpl::g_pesapi_ffi.close_scope(scope); pesapi::qjsimpl::g_pesapi_ffi.release_env_ref(env_ref); + mapper->Cleanup(); JS_FreeContext(ctx); JS_FreeRuntime(rt); if (mapper) { - mapper->Cleanup(); mapper->~CppObjectMapper(); free(mapper); } diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index b7abb5b..c3e6e03 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -457,6 +457,10 @@ void* pesapi_get_userdata(pesapi_callback_info pinfo) void pesapi_add_return(pesapi_callback_info pinfo, pesapi_value value) { pinfo->res = *qjsValueFromPesapiValue(value); + if (JS_VALUE_HAS_REF_COUNT(pinfo->res)) { + JS_DupValue(pinfo->ctx, pinfo->res); + } + } void pesapi_throw_by_string(pesapi_callback_info pinfo, const char* msg) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index e960032..42429a7 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -36,10 +36,7 @@ class PApiBaseTest : public ::testing::Test { void* finalizer_env_private = nullptr; protected: - static void EmptyFinalizer(struct pesapi_ffi* apis, void* data, void* env_private) - { - - } + const void* typeId = "Test"; void SetUp() override { //printf("SetUp\n"); @@ -89,17 +86,15 @@ class PApiBaseTest : public ::testing::Test { }; TEST_F(PApiBaseTest, CreateAndDestroyMultQjsEnv) { - //多次调用create_qjs_env和destroy_qjs_env - //for (int i = 0; i < 10; i++) { - // pesapi_env_ref env_ref = create_qjs_env(); - // destroy_qjs_env(env_ref); - //} + for (int i = 0; i < 10; i++) { + pesapi_env_ref env_ref = create_qjs_env(); + destroy_qjs_env(env_ref); + } } TEST_F(PApiBaseTest, RegApi) { pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(1); pesapi_set_method_info(properties, 0, "Foo", true, Foo, NULL, NULL); - const void* typeId = "Test"; pesapi_define_class(typeId, NULL, "Test", NULL, NULL, 1, properties, NULL); auto clsDef = puerts::FindClassByID(typeId); From 7d4e735f91c1e342af50c1b2ca6a12671ee1e3d1 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 20:02:09 +0800 Subject: [PATCH 50/70] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/CppObjectMapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index f12df12..da587cd 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -188,7 +188,7 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin }, 0, 0, 2, &ctor_data[0]); TypeIdToFunctionMap[ClassDefinition->TypeId] = func; - JS_DupValue(ctx, func); + JS_DupValue(ctx, func); //JS_FreeValue in Cleanup return func; } return it->second; From 730e8e4b2371bcafbe99d5d400cb66df03143bfa Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 20:49:00 +0800 Subject: [PATCH 51/70] =?UTF-8?q?=E8=B0=83=E9=80=9A=E6=9E=84=E9=80=A0?= =?UTF-8?q?=E5=92=8C=E6=9E=90=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/ObjectCacheNode.h | 7 +++--- source/CppObjectMapper.cpp | 5 ++++- test/papi_qjs_base_test.cpp | 44 ++++++++++++++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/include/ObjectCacheNode.h b/include/ObjectCacheNode.h index 5265882..7f45e04 100644 --- a/include/ObjectCacheNode.h +++ b/include/ObjectCacheNode.h @@ -32,7 +32,7 @@ class FObjectCacheNode , TypeId(other.TypeId) , UserData(other.UserData) , Next(other.Next) - , Value(JS_DupValueRT(other.RT, other.Value)) + , Value(other.Value) , MustCallFinalize(other.MustCallFinalize) { other.RT = nullptr; @@ -47,7 +47,7 @@ class FObjectCacheNode RT = rhs.RT; TypeId = rhs.TypeId; Next = rhs.Next; - Value = JS_DupValueRT(RT, rhs.Value); + Value = rhs.Value; UserData = rhs.UserData; MustCallFinalize = rhs.MustCallFinalize; rhs.UserData = nullptr; @@ -63,8 +63,8 @@ class FObjectCacheNode { Next->~FObjectCacheNode(); free(Next); + Next = nullptr; } - JS_FreeValueRT(RT, Value); } FObjectCacheNode* Find(const void* TypeId_) @@ -97,7 +97,6 @@ class FObjectCacheNode { TypeId = nullptr; Next = nullptr; - JS_FreeValueRT(RT, Value); } } return this; diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index da587cd..4c71cb0 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -174,11 +174,12 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin mapper->AddToCache(clsDef, ptr, callbackInfo.this_val, true); if (JS_IsException(callbackInfo.res)) { + JS_FreeValue(ctx, callbackInfo.this_val); return JS_Throw(ctx, callbackInfo.ex); } else { - return callbackInfo.res; + return callbackInfo.this_val; } } else @@ -187,6 +188,8 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin } }, 0, 0, 2, &ctor_data[0]); + JS_SetConstructorBit(ctx, func, 1); + TypeIdToFunctionMap[ClassDefinition->TypeId] = func; JS_DupValue(ctx, func); //JS_FreeValue in Cleanup return func; diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 42429a7..082f201 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -36,8 +36,6 @@ class PApiBaseTest : public ::testing::Test { void* finalizer_env_private = nullptr; protected: - const void* typeId = "Test"; - void SetUp() override { //printf("SetUp\n"); env_ref = create_qjs_env(); @@ -93,6 +91,8 @@ TEST_F(PApiBaseTest, CreateAndDestroyMultQjsEnv) { } TEST_F(PApiBaseTest, RegApi) { + const void* typeId = "Test"; + pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(1); pesapi_set_method_info(properties, 0, "Foo", true, Foo, NULL, NULL); pesapi_define_class(typeId, NULL, "Test", NULL, NULL, 1, properties, NULL); @@ -208,12 +208,50 @@ TEST_F(PApiBaseTest, PropertyGetSet) { api->close_scope(scope); } +struct TestStruct { + TestStruct(int a) { + printf("TestStruct ctor: %d, %p\n", a, this); + this->a = a; + } + + int a; + ~TestStruct() { + printf("TestStruct dtor: %d, %p\n", a, this); + } +}; + +void* TestStructCtor(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto p0 = apis->get_arg(info, 0); + int a = apis->get_value_int32(env, p0); + return new TestStruct(a); +} + +void TestStructFinalize(struct pesapi_ffi* apis, void* ptr, void* class_data, void* env_private) +{ + delete (TestStruct*)ptr; +} + TEST_F(PApiBaseTest, ClassCtorFinalize) { auto scope = api->open_scope(env_ref); auto env = api->get_env_from_ref(env_ref); - auto code = "loadClass('Test');"; + const void* typeId = "TestStruct"; + + pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, 0, NULL, NULL); + + auto code = R"( + (function() { + const TestStruct = loadClass('TestStruct'); + const obj = new TestStruct(123); + })(); + )"; api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (api->has_caught(scope)) + { + printf("%s\n", api->get_exception_as_string(scope, true)); + } ASSERT_FALSE(api->has_caught(scope)); api->close_scope(scope); From 6bca519d51f9102da0d0fe6c6ce0c229492e6023 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 24 Feb 2025 20:53:48 +0800 Subject: [PATCH 52/70] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E7=9A=84runtime=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/ObjectCacheNode.h | 15 +++++---------- source/CppObjectMapper.cpp | 2 +- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/ObjectCacheNode.h b/include/ObjectCacheNode.h index 7f45e04..7a8b9fe 100644 --- a/include/ObjectCacheNode.h +++ b/include/ObjectCacheNode.h @@ -18,24 +18,22 @@ namespace qjsimpl class FObjectCacheNode { public: - inline FObjectCacheNode(JSRuntime* RT_, const void* TypeId_) : RT(RT_), TypeId(TypeId_), UserData(nullptr), Next(nullptr), MustCallFinalize(false) + inline FObjectCacheNode(const void* TypeId_) :TypeId(TypeId_), UserData(nullptr), Next(nullptr), MustCallFinalize(false) { } - inline FObjectCacheNode(JSRuntime* RT_, const void* TypeId_, FObjectCacheNode* Next_) - : RT(RT_), TypeId(TypeId_), UserData(nullptr), Next(Next_), MustCallFinalize(false) + inline FObjectCacheNode(const void* TypeId_, FObjectCacheNode* Next_) + : TypeId(TypeId_), UserData(nullptr), Next(Next_), MustCallFinalize(false) { } inline FObjectCacheNode(FObjectCacheNode&& other) noexcept - : RT(other.RT) - , TypeId(other.TypeId) + : TypeId(other.TypeId) , UserData(other.UserData) , Next(other.Next) , Value(other.Value) , MustCallFinalize(other.MustCallFinalize) { - other.RT = nullptr; other.TypeId = nullptr; other.UserData = nullptr; other.Next = nullptr; @@ -44,7 +42,6 @@ class FObjectCacheNode inline FObjectCacheNode& operator=(FObjectCacheNode&& rhs) noexcept { - RT = rhs.RT; TypeId = rhs.TypeId; Next = rhs.Next; Value = rhs.Value; @@ -119,13 +116,11 @@ class FObjectCacheNode inline FObjectCacheNode* Add(const void* TypeId_) { FObjectCacheNode* newNode = static_cast(malloc(sizeof(FObjectCacheNode))); - new (newNode) FObjectCacheNode(RT, TypeId_, Next); + new (newNode) FObjectCacheNode(TypeId_, Next); Next = newNode; return Next; } - JSRuntime* RT; - const void* TypeId; void* UserData; diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 4c71cb0..cd33191 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -107,7 +107,7 @@ void CppObjectMapper::AddToCache(const puerts::JSClassDefinition* typeInfo, cons } else { - auto Ret = CDataCache.insert({ptr, FObjectCacheNode(JS_GetRuntime(ctx), typeInfo->TypeId)}); + auto Ret = CDataCache.insert({ptr, FObjectCacheNode(typeInfo->TypeId)}); CacheNodePtr = &Ret.first->second; } CacheNodePtr->Value = value; From 9ee2cd646edee67686c9df86841fda469e271bbd Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 10:02:37 +0800 Subject: [PATCH 53/70] =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E5=90=8D=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/CppObjectMapper.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index cd33191..5c704bc 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -190,6 +190,16 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin JS_SetConstructorBit(ctx, func, 1); + auto clsName = JS_NewAtom(ctx, ClassDefinition->ScriptName); + JS_DefinePropertyValue( + ctx, + func, + JS_ATOM_name, + JS_AtomToString(ctx, clsName), + JS_PROP_CONFIGURABLE + ); + JS_FreeAtom(ctx, clsName); + TypeIdToFunctionMap[ClassDefinition->TypeId] = func; JS_DupValue(ctx, func); //JS_FreeValue in Cleanup return func; From 5dc7218778e78039dae83605a49d36f486a2843f Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 10:09:22 +0800 Subject: [PATCH 54/70] =?UTF-8?q?=E7=94=A8=E4=BE=8B=E5=8A=A0=E4=B8=8A?= =?UTF-8?q?=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 082f201..cdf0aab 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -58,7 +58,6 @@ class PApiBaseTest : public ::testing::Test { char buff[1024]; size_t len = sizeof(buff); const char* className = apis->get_value_string_utf8(env, arg0, buff, &len); - printf("LoadClass className: %s\n", className); auto clsDef = puerts::FindCppTypeClassByName(className); if (clsDef) { @@ -209,17 +208,28 @@ TEST_F(PApiBaseTest, PropertyGetSet) { } struct TestStruct { + static int ctor_count; + static int dtor_count; + static TestStruct* lastCtorObject; + static TestStruct* lastDtorObject; TestStruct(int a) { - printf("TestStruct ctor: %d, %p\n", a, this); this->a = a; + ctor_count++; + lastCtorObject = this; } int a; ~TestStruct() { - printf("TestStruct dtor: %d, %p\n", a, this); + dtor_count++; + lastDtorObject = this; } }; +int TestStruct::ctor_count = 0; +int TestStruct::dtor_count = 0; +TestStruct* TestStruct::lastCtorObject = nullptr; +TestStruct* TestStruct::lastDtorObject = nullptr; + void* TestStructCtor(struct pesapi_ffi* apis, pesapi_callback_info info) { auto env = apis->get_env(info); @@ -241,6 +251,11 @@ TEST_F(PApiBaseTest, ClassCtorFinalize) { pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, 0, NULL, NULL); + TestStruct::ctor_count = 0; + TestStruct::dtor_count = 0; + TestStruct::lastCtorObject = nullptr; + TestStruct::lastDtorObject = nullptr; + auto code = R"( (function() { const TestStruct = loadClass('TestStruct'); @@ -254,6 +269,11 @@ TEST_F(PApiBaseTest, ClassCtorFinalize) { } ASSERT_FALSE(api->has_caught(scope)); + ASSERT_EQ(TestStruct::ctor_count, 1); + ASSERT_EQ(TestStruct::dtor_count, 1); + ASSERT_EQ(TestStruct::lastCtorObject, TestStruct::lastDtorObject); + + api->close_scope(scope); } From 036c89b70e3cd01714f669587b9b72307ef6e0f2 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 10:20:49 +0800 Subject: [PATCH 55/70] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=EF=BC=8C=E5=AF=B9=E7=B1=BB=E5=8F=AA=E6=B3=A8=E5=86=8C=E4=B8=80?= =?UTF-8?q?=E6=AC=A1=EF=BC=8C=E5=A4=9A=E4=B8=AA=E7=94=A8=E4=BE=8B=E5=85=B1?= =?UTF-8?q?=E4=BA=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 84 +++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index cdf0aab..cfe1fa8 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -7,8 +7,52 @@ namespace pesapi { namespace qjsimpl { +struct TestStruct { + static int ctor_count; + static int dtor_count; + static TestStruct* lastCtorObject; + static TestStruct* lastDtorObject; + TestStruct(int a) { + this->a = a; + ctor_count++; + lastCtorObject = this; + } + + int a; + ~TestStruct() { + dtor_count++; + lastDtorObject = this; + } +}; + +int TestStruct::ctor_count = 0; +int TestStruct::dtor_count = 0; +TestStruct* TestStruct::lastCtorObject = nullptr; +TestStruct* TestStruct::lastDtorObject = nullptr; + +void* TestStructCtor(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto p0 = apis->get_arg(info, 0); + int a = apis->get_value_int32(env, p0); + return new TestStruct(a); +} + +void TestStructFinalize(struct pesapi_ffi* apis, void* ptr, void* class_data, void* env_private) +{ + delete (TestStruct*)ptr; +} + class PApiBaseTest : public ::testing::Test { public: + static void SetUpTestCase() { + const void* typeId = "TestStruct"; + pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, 0, NULL, NULL); + } + + static void TearDownTestCase() { + } + static void Foo(struct pesapi_ffi* apis, pesapi_callback_info info) { @@ -207,50 +251,10 @@ TEST_F(PApiBaseTest, PropertyGetSet) { api->close_scope(scope); } -struct TestStruct { - static int ctor_count; - static int dtor_count; - static TestStruct* lastCtorObject; - static TestStruct* lastDtorObject; - TestStruct(int a) { - this->a = a; - ctor_count++; - lastCtorObject = this; - } - - int a; - ~TestStruct() { - dtor_count++; - lastDtorObject = this; - } -}; - -int TestStruct::ctor_count = 0; -int TestStruct::dtor_count = 0; -TestStruct* TestStruct::lastCtorObject = nullptr; -TestStruct* TestStruct::lastDtorObject = nullptr; - -void* TestStructCtor(struct pesapi_ffi* apis, pesapi_callback_info info) -{ - auto env = apis->get_env(info); - auto p0 = apis->get_arg(info, 0); - int a = apis->get_value_int32(env, p0); - return new TestStruct(a); -} - -void TestStructFinalize(struct pesapi_ffi* apis, void* ptr, void* class_data, void* env_private) -{ - delete (TestStruct*)ptr; -} - TEST_F(PApiBaseTest, ClassCtorFinalize) { auto scope = api->open_scope(env_ref); auto env = api->get_env_from_ref(env_ref); - const void* typeId = "TestStruct"; - - pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, 0, NULL, NULL); - TestStruct::ctor_count = 0; TestStruct::dtor_count = 0; TestStruct::lastCtorObject = nullptr; From 7e458bf831ff9be10963b62a3245f185747bb2ba Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 10:25:16 +0800 Subject: [PATCH 56/70] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 127 ++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 64 deletions(-) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index cfe1fa8..66b5490 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -83,14 +83,14 @@ class PApiBaseTest : public ::testing::Test { void SetUp() override { //printf("SetUp\n"); env_ref = create_qjs_env(); - api = get_papi_ffi(); + apis = get_papi_ffi(); - auto scope = api->open_scope(env_ref); - auto env = api->get_env_from_ref(env_ref); + auto scope = apis->open_scope(env_ref); + auto env = apis->get_env_from_ref(env_ref); - auto g = api->global(env); - api->set_property(env, g, "loadClass", api->create_function(env, LoadClass, this, nullptr)); - api->close_scope(scope); + auto g = apis->global(env); + apis->set_property(env, g, "loadClass", apis->create_function(env, LoadClass, this, nullptr)); + apis->close_scope(scope); } static void LoadClass(struct pesapi_ffi* apis, pesapi_callback_info info) @@ -123,7 +123,7 @@ class PApiBaseTest : public ::testing::Test { } pesapi_env_ref env_ref; - struct pesapi_ffi* api; + struct pesapi_ffi* apis; }; TEST_F(PApiBaseTest, CreateAndDestroyMultQjsEnv) { @@ -149,111 +149,111 @@ TEST_F(PApiBaseTest, RegApi) { } TEST_F(PApiBaseTest, EvalJavaScript) { - auto scope = api->open_scope(env_ref); - auto env = api->get_env_from_ref(env_ref); + auto scope = apis->open_scope(env_ref); + auto env = apis->get_env_from_ref(env_ref); auto code = "123+789"; - auto ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); ASSERT_TRUE(ret != nullptr); - ASSERT_TRUE(api->is_int32(env, ret)); - ASSERT_TRUE(api->get_value_int32(env, ret) == 912); + ASSERT_TRUE(apis->is_int32(env, ret)); + ASSERT_TRUE(apis->get_value_int32(env, ret) == 912); - api->close_scope(scope); + apis->close_scope(scope); } TEST_F(PApiBaseTest, EvalJavaScriptEx) { - auto scope = api->open_scope(env_ref); - auto env = api->get_env_from_ref(env_ref); + auto scope = apis->open_scope(env_ref); + auto env = apis->get_env_from_ref(env_ref); auto code = " (function() { throw new Error('abc'); }) ();"; - auto ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); - ASSERT_TRUE(api->has_caught(scope)); + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + ASSERT_TRUE(apis->has_caught(scope)); - EXPECT_STREQ("Error: abc", api->get_exception_as_string(scope, false)); - EXPECT_STREQ("Error: abc\n at (test.js:1:21)\n at (test.js:1:42)\n", api->get_exception_as_string(scope, true)); + EXPECT_STREQ("Error: abc", apis->get_exception_as_string(scope, false)); + EXPECT_STREQ("Error: abc\n at (test.js:1:21)\n at (test.js:1:42)\n", apis->get_exception_as_string(scope, true)); - api->close_scope(scope); + apis->close_scope(scope); } TEST_F(PApiBaseTest, SetToGlobal) { - auto scope = api->open_scope(env_ref); - auto env = api->get_env_from_ref(env_ref); + auto scope = apis->open_scope(env_ref); + auto env = apis->get_env_from_ref(env_ref); - auto g = api->global(env); - api->set_property(env, g, "SetToGlobal", api->create_int32(env, 123)); + auto g = apis->global(env); + apis->set_property(env, g, "SetToGlobal", apis->create_int32(env, 123)); auto code = " SetToGlobal;"; - auto ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); ASSERT_TRUE(ret != nullptr); - ASSERT_TRUE(api->is_int32(env, ret)); - ASSERT_TRUE(api->get_value_int32(env, ret) == 123); + ASSERT_TRUE(apis->is_int32(env, ret)); + ASSERT_TRUE(apis->get_value_int32(env, ret) == 123); - api->close_scope(scope); + apis->close_scope(scope); } TEST_F(PApiBaseTest, CreateJsFunction) { - auto scope = api->open_scope(env_ref); - auto env = api->get_env_from_ref(env_ref); + auto scope = apis->open_scope(env_ref); + auto env = apis->get_env_from_ref(env_ref); - auto g = api->global(env); - api->set_property(env, g, "Bar__", api->create_function(env, Bar, this, JsFuncFinalizer)); + auto g = apis->global(env); + apis->set_property(env, g, "Bar__", apis->create_function(env, Bar, this, JsFuncFinalizer)); auto code = "Bar__(3344);"; bar_data = 100; - auto ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); - if (api->has_caught (scope)) { - printf("%s\n", api->get_exception_as_string(scope, true)); + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught (scope)) { + printf("%s\n", apis->get_exception_as_string(scope, true)); } - ASSERT_FALSE(api->has_caught(scope)); + ASSERT_FALSE(apis->has_caught(scope)); EXPECT_EQ(bar_data, 3344); code = "globalThis.Bar__ = undefined;"; finalizer_env_private = nullptr; - api->set_env_private(env, &bar_data); - ret = api->eval(env, (const uint8_t*)(code), strlen(code), "test2.js"); - ASSERT_FALSE(api->has_caught(scope)); + apis->set_env_private(env, &bar_data); + ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test2.js"); + ASSERT_FALSE(apis->has_caught(scope)); - api->close_scope(scope); + apis->close_scope(scope); EXPECT_EQ((void*)&bar_data, finalizer_env_private); - EXPECT_EQ(api->get_env_private(env), finalizer_env_private); - api->set_env_private(env, nullptr); + EXPECT_EQ(apis->get_env_private(env), finalizer_env_private); + apis->set_env_private(env, nullptr); } TEST_F(PApiBaseTest, PropertyGetSet) { - auto scope = api->open_scope(env_ref); - auto env = api->get_env_from_ref(env_ref); + auto scope = apis->open_scope(env_ref); + auto env = apis->get_env_from_ref(env_ref); - auto g = api->global(env); - api->set_property(env, g, "PropertyGetSet", api->create_string_utf8(env, "123", 3)); + auto g = apis->global(env); + apis->set_property(env, g, "PropertyGetSet", apis->create_string_utf8(env, "123", 3)); - auto str = api->get_property(env, g, "PropertyGetSet"); - ASSERT_TRUE(api->is_string(env, str)); + auto str = apis->get_property(env, g, "PropertyGetSet"); + ASSERT_TRUE(apis->is_string(env, str)); size_t len = 0; - api->get_value_string_utf8(env, str, nullptr, &len); + apis->get_value_string_utf8(env, str, nullptr, &len); ASSERT_EQ(len, 3); char buff[4] = {0}; - api->get_value_string_utf8(env, str, buff, &len); + apis->get_value_string_utf8(env, str, buff, &len); buff[3] = 0; EXPECT_STREQ("123", buff); - api->set_property_uint32(env, g, 5, api->create_string_utf8(env, "888", 3)); - str = api->get_property_uint32(env, g, 5); - ASSERT_TRUE(api->is_string(env, str)); + apis->set_property_uint32(env, g, 5, apis->create_string_utf8(env, "888", 3)); + str = apis->get_property_uint32(env, g, 5); + ASSERT_TRUE(apis->is_string(env, str)); len = 0; - api->get_value_string_utf8(env, str, nullptr, &len); + apis->get_value_string_utf8(env, str, nullptr, &len); ASSERT_EQ(len, 3); buff[3] = 0; - api->get_value_string_utf8(env, str, buff, &len); + apis->get_value_string_utf8(env, str, buff, &len); EXPECT_STREQ("888", buff); - api->close_scope(scope); + apis->close_scope(scope); } TEST_F(PApiBaseTest, ClassCtorFinalize) { - auto scope = api->open_scope(env_ref); - auto env = api->get_env_from_ref(env_ref); + auto scope = apis->open_scope(env_ref); + auto env = apis->get_env_from_ref(env_ref); TestStruct::ctor_count = 0; TestStruct::dtor_count = 0; @@ -266,19 +266,19 @@ TEST_F(PApiBaseTest, ClassCtorFinalize) { const obj = new TestStruct(123); })(); )"; - api->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); - if (api->has_caught(scope)) + apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught(scope)) { - printf("%s\n", api->get_exception_as_string(scope, true)); + printf("%s\n", apis->get_exception_as_string(scope, true)); } - ASSERT_FALSE(api->has_caught(scope)); + ASSERT_FALSE(apis->has_caught(scope)); ASSERT_EQ(TestStruct::ctor_count, 1); ASSERT_EQ(TestStruct::dtor_count, 1); ASSERT_EQ(TestStruct::lastCtorObject, TestStruct::lastDtorObject); - api->close_scope(scope); + apis->close_scope(scope); } @@ -289,4 +289,3 @@ int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } - From fa14d4cce4c740e70fd7b9a22298d1b798e54080 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 11:28:08 +0800 Subject: [PATCH 57/70] =?UTF-8?q?=E9=9D=99=E6=80=81=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 2 ++ source/CppObjectMapper.cpp | 72 ++++++++++++++++++++++++++----------- test/papi_qjs_base_test.cpp | 49 +++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 24 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index b3be4f3..cb907f7 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -71,6 +71,8 @@ struct CppObjectMapper static JSValue CreateError(JSContext* ctx, const char* message); + void CreateMethod(puerts::JSFunctionInfo* FunctionInfo, JSValue Obj); + JSValue CreateClass(const puerts::JSClassDefinition* ClassDefinition); void AddToCache(const puerts::JSClassDefinition* typeInfo, const void* ptr, JSValue value, bool callFinalize); diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 5c704bc..2fb84e1 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -126,35 +126,40 @@ void CppObjectMapper::RemoveFromCache(const puerts::JSClassDefinition* typeInfo, } } -JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefinition) +void CppObjectMapper::CreateMethod(puerts::JSFunctionInfo* FunctionInfo, JSValue Obj) { - auto it = TypeIdToFunctionMap.find(ClassDefinition->TypeId); - if (it == TypeIdToFunctionMap.end()) - { - puerts::JSPropertyInfo* PropertyInfo = ClassDefinition->Properties; - while (PropertyInfo && PropertyInfo->Name) - { - ++PropertyInfo; - } + JSValue method_data[2] { + JS_MKPTR(JS_TAG_EXTERNAL, (void*)FunctionInfo), + JS_MKPTR(JS_TAG_EXTERNAL, this) + }; - PropertyInfo = ClassDefinition->Variables; - while (PropertyInfo && PropertyInfo->Name) + JSValue func = JS_NewCFunctionData(ctx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *method_data) -> JSValue { + const puerts::JSFunctionInfo* funcInfo = (const puerts::JSFunctionInfo*)(JS_VALUE_GET_PTR(method_data[0])); + CppObjectMapper* mapper = (CppObjectMapper*)(JS_VALUE_GET_PTR(method_data[1])); + + pesapi_callback_info__ callbackInfo { ctx, this_val, argc, argv, JS_VALUE_GET_PTR(method_data[1]), JS_UNDEFINED, JS_UNDEFINED }; + funcInfo->Callback(&g_pesapi_ffi, &callbackInfo); + if (JS_IsException(callbackInfo.res)) { - ++PropertyInfo; + JS_FreeValue(ctx, callbackInfo.res); + return JS_Throw(ctx, callbackInfo.ex); } - - puerts::JSFunctionInfo* FunctionInfo = ClassDefinition->Methods; - while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) + else { - ++FunctionInfo; + return callbackInfo.res; } + }, 0, 0, 2, &method_data[0]); - FunctionInfo = ClassDefinition->Functions; - while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) - { - ++FunctionInfo; - } + JSAtom methodName = JS_NewAtom(ctx, FunctionInfo->Name); + JS_DefinePropertyValue(ctx, Obj, methodName, func, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE); + JS_FreeAtom(ctx, methodName); +} +JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefinition) +{ + auto it = TypeIdToFunctionMap.find(ClassDefinition->TypeId); + if (it == TypeIdToFunctionMap.end()) + { JSValue ctor_data[2] { JS_MKPTR(JS_TAG_EXTERNAL, (void*)ClassDefinition), JS_MKPTR(JS_TAG_EXTERNAL, this) @@ -200,6 +205,31 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin ); JS_FreeAtom(ctx, clsName); + puerts::JSPropertyInfo* PropertyInfo = ClassDefinition->Properties; + while (PropertyInfo && PropertyInfo->Name) + { + ++PropertyInfo; + } + + PropertyInfo = ClassDefinition->Variables; + while (PropertyInfo && PropertyInfo->Name) + { + ++PropertyInfo; + } + + puerts::JSFunctionInfo* FunctionInfo = ClassDefinition->Methods; + while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) + { + ++FunctionInfo; + } + + FunctionInfo = ClassDefinition->Functions; + while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) + { + CreateMethod(FunctionInfo, func); + ++FunctionInfo; + } + TypeIdToFunctionMap[ClassDefinition->TypeId] = func; JS_DupValue(ctx, func); //JS_FreeValue in Cleanup return func; diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 66b5490..3cc9737 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -23,6 +23,14 @@ struct TestStruct { dtor_count++; lastDtorObject = this; } + + int Calc(int x, int y) { + return a + x + y; + } + + static int Add(int x, int y) { + return x + y; + } }; int TestStruct::ctor_count = 0; @@ -30,7 +38,7 @@ int TestStruct::dtor_count = 0; TestStruct* TestStruct::lastCtorObject = nullptr; TestStruct* TestStruct::lastDtorObject = nullptr; -void* TestStructCtor(struct pesapi_ffi* apis, pesapi_callback_info info) +static void* TestStructCtor(struct pesapi_ffi* apis, pesapi_callback_info info) { auto env = apis->get_env(info); auto p0 = apis->get_arg(info, 0); @@ -38,16 +46,29 @@ void* TestStructCtor(struct pesapi_ffi* apis, pesapi_callback_info info) return new TestStruct(a); } -void TestStructFinalize(struct pesapi_ffi* apis, void* ptr, void* class_data, void* env_private) +static void TestStructFinalize(struct pesapi_ffi* apis, void* ptr, void* class_data, void* env_private) { delete (TestStruct*)ptr; } +static void AddWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto p0 = apis->get_arg(info, 0); + auto p1 = apis->get_arg(info, 1); + int a = apis->get_value_int32(env, p0); + int b = apis->get_value_int32(env, p1); + apis->add_return(info, apis->create_int32(env, TestStruct::Add(a, b))); +} + class PApiBaseTest : public ::testing::Test { public: static void SetUpTestCase() { const void* typeId = "TestStruct"; - pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, 0, NULL, NULL); + const int properties_count = 1; + pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(properties_count); + pesapi_set_method_info(properties, 0, "Add", true, AddWrap, NULL, NULL); + pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, properties_count, properties, NULL); } static void TearDownTestCase() { @@ -281,6 +302,28 @@ TEST_F(PApiBaseTest, ClassCtorFinalize) { apis->close_scope(scope); } +TEST_F(PApiBaseTest, StaticFunctionCall) { + auto scope = apis->open_scope(env_ref); + auto env = apis->get_env_from_ref(env_ref); + + auto code = R"( + (function() { + const TestStruct = loadClass('TestStruct'); + return TestStruct.Add(123, 456); + })(); + )"; + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught(scope)) + { + printf("%s\n", apis->get_exception_as_string(scope, true)); + } + ASSERT_FALSE(apis->has_caught(scope)); + ASSERT_TRUE(apis->is_int32(env, ret)); + ASSERT_TRUE(apis->get_value_int32(env, ret) == 579); + + apis->close_scope(scope); +} + } // namespace qjsimpl } // namespace pesapi From a9740ce642f5300b0d368ee3cabf9d99f729947a Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 11:36:24 +0800 Subject: [PATCH 58/70] =?UTF-8?q?=E6=B7=BB=E5=8A=A0DUMP=5FLEAKS,=20DUMP=5F?= =?UTF-8?q?ATOM=5FLEAKS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/CppObjectMapper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 2fb84e1..3bde095 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -301,6 +301,8 @@ void CppObjectMapper::Cleanup() pesapi_env_ref create_qjs_env() { JSRuntime* rt = JS_NewRuntime(); + // 0x4000: DUMP_LEAKS, 0x8000: DUMP_ATOM_LEAKS + JS_SetDumpFlags(rt, 0x4000 | 0x8000); JSContext* ctx = JS_NewContext(rt); pesapi::qjsimpl::CppObjectMapper* mapper = static_cast(malloc(sizeof(pesapi::qjsimpl::CppObjectMapper))); From d9318bfa77697410eae2d0fbe26f3f916fbb618e Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 14:14:20 +0800 Subject: [PATCH 59/70] =?UTF-8?q?pesapi=5Fget=5Fnative=5Fobject=5Fptr?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0=EF=BC=8C=E6=88=90=E5=91=98=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 21 +++++++++++++++++---- source/CppObjectMapper.cpp | 13 ++++++------- source/PapiQuickjsImpl.cpp | 5 ++++- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index cb907f7..85967dd 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -13,6 +13,13 @@ namespace pesapi namespace qjsimpl { +struct ObjectUserData +{ + const puerts::JSClassDefinition* typeInfo; + const void* ptr; + bool callFinalize; +}; + struct CppObjectMapper { inline static CppObjectMapper* Get(JSContext* ctx) @@ -43,28 +50,34 @@ struct CppObjectMapper const void* envPrivate = nullptr; eastl::shared_ptr ref = eastl::allocate_shared(eastl::allocator_malloc("shared_ptr"), 0); - static eastl::weak_ptr GetEnvLifeCycleTracker(JSContext* ctx) + inline static eastl::weak_ptr GetEnvLifeCycleTracker(JSContext* ctx) { JSRuntime* rt = JS_GetRuntime(ctx); CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); return mapper->GetEnvLifeCycleTracker(); } - eastl::weak_ptr GetEnvLifeCycleTracker() + inline eastl::weak_ptr GetEnvLifeCycleTracker() { return eastl::weak_ptr(ref); } - const void* GetEnvPrivate() const + inline const void* GetEnvPrivate() const { return envPrivate; } - void SetEnvPrivate(const void* envPrivate_) + inline void SetEnvPrivate(const void* envPrivate_) { envPrivate = envPrivate_; } + inline const void* GetNativeObjectPtr(JSValue val) + { + ObjectUserData* object_udata = (ObjectUserData*)JS_GetOpaque(val, classId); + return object_udata ? object_udata->ptr : nullptr; + } + JSValue CreateFunction(pesapi_callback Callback, void* Data, pesapi_function_finalize Finalize); JSValue CreateClassByID(const void* typeId); diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 3bde095..f3a1b8c 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -17,13 +17,6 @@ struct FuncFinalizeData CppObjectMapper* mapper; }; -struct ObjectUserData -{ - const puerts::JSClassDefinition* typeInfo; - const void* ptr; - bool callFinalize; -}; - void PApiFuncFinalizer(JSRuntime* rt, JSValue val) { CppObjectMapper* mapper = reinterpret_cast(JS_GetRuntimeOpaque(rt)); @@ -205,6 +198,8 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin ); JS_FreeAtom(ctx, clsName); + JSValue proto = JS_NewObject(ctx); + puerts::JSPropertyInfo* PropertyInfo = ClassDefinition->Properties; while (PropertyInfo && PropertyInfo->Name) { @@ -220,6 +215,7 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin puerts::JSFunctionInfo* FunctionInfo = ClassDefinition->Methods; while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) { + CreateMethod(FunctionInfo, proto); ++FunctionInfo; } @@ -230,6 +226,9 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin ++FunctionInfo; } + JS_SetConstructor(ctx, func, proto); + JS_FreeValue(ctx, proto); + TypeIdToFunctionMap[ClassDefinition->TypeId] = func; JS_DupValue(ctx, func); //JS_FreeValue in Cleanup return func; diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index c3e6e03..d8a8734 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -385,7 +385,10 @@ pesapi_value pesapi_native_object_to_value(pesapi_env env, const void* type_id, void* pesapi_get_native_object_ptr(pesapi_env env, pesapi_value pvalue) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + auto mapper = pesapi::qjsimpl::CppObjectMapper::Get(ctx); + auto value = qjsValueFromPesapiValue(pvalue); + return (void*)mapper->GetNativeObjectPtr(*value); } const void* pesapi_get_native_object_typeid(pesapi_env env, pesapi_value pvalue) From 21956ba101756c0af0179befd34f207ebb6ecfcc Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 14:16:43 +0800 Subject: [PATCH 60/70] =?UTF-8?q?=E6=88=90=E5=91=98=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=EF=BC=8C=E4=BB=A5=E5=8F=8A=E6=8A=8Ascope?= =?UTF-8?q?=E6=94=BE=E5=9C=A8Setup=E5=92=8CTearDown=EF=BC=8C=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E7=94=A8=E4=BE=8B=E6=96=AD=E8=A8=80=E5=AF=BC=E8=87=B4?= =?UTF-8?q?close=5Fscope=E6=9C=AA=E8=B0=83=E7=94=A8=EF=BC=8C=E8=BF=9B?= =?UTF-8?q?=E8=80=8C=E5=BC=95=E5=8F=91list=5Fempty(&rt->gc=5Fobj=5Flist)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 61 ++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 3cc9737..bd15c7b 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -61,13 +61,27 @@ static void AddWrap(struct pesapi_ffi* apis, pesapi_callback_info info) apis->add_return(info, apis->create_int32(env, TestStruct::Add(a, b))); } + +static void CalcWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto self = apis->get_this(info); + auto obj = (TestStruct*)apis->get_native_object_ptr(env, self); + auto p0 = apis->get_arg(info, 0); + auto p1 = apis->get_arg(info, 1); + int a = apis->get_value_int32(env, p0); + int b = apis->get_value_int32(env, p1); + apis->add_return(info, apis->create_int32(env, obj->Calc(a, b))); +} + class PApiBaseTest : public ::testing::Test { public: static void SetUpTestCase() { const void* typeId = "TestStruct"; - const int properties_count = 1; + const int properties_count = 2; pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(properties_count); pesapi_set_method_info(properties, 0, "Add", true, AddWrap, NULL, NULL); + pesapi_set_method_info(properties, 1, "Calc", false, CalcWrap, NULL, NULL); pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, properties_count, properties, NULL); } @@ -106,12 +120,14 @@ class PApiBaseTest : public ::testing::Test { env_ref = create_qjs_env(); apis = get_papi_ffi(); - auto scope = apis->open_scope(env_ref); + scope = apis->open_scope(env_ref); auto env = apis->get_env_from_ref(env_ref); auto g = apis->global(env); apis->set_property(env, g, "loadClass", apis->create_function(env, LoadClass, this, nullptr)); apis->close_scope(scope); + + scope = apis->open_scope(env_ref); } static void LoadClass(struct pesapi_ffi* apis, pesapi_callback_info info) @@ -137,6 +153,7 @@ class PApiBaseTest : public ::testing::Test { } void TearDown() override { + apis->close_scope(scope); //printf("TearDown\n"); if (env_ref) { destroy_qjs_env(env_ref); @@ -145,6 +162,7 @@ class PApiBaseTest : public ::testing::Test { pesapi_env_ref env_ref; struct pesapi_ffi* apis; + pesapi_scope scope; }; TEST_F(PApiBaseTest, CreateAndDestroyMultQjsEnv) { @@ -170,7 +188,6 @@ TEST_F(PApiBaseTest, RegApi) { } TEST_F(PApiBaseTest, EvalJavaScript) { - auto scope = apis->open_scope(env_ref); auto env = apis->get_env_from_ref(env_ref); auto code = "123+789"; @@ -178,12 +195,9 @@ TEST_F(PApiBaseTest, EvalJavaScript) { ASSERT_TRUE(ret != nullptr); ASSERT_TRUE(apis->is_int32(env, ret)); ASSERT_TRUE(apis->get_value_int32(env, ret) == 912); - - apis->close_scope(scope); } TEST_F(PApiBaseTest, EvalJavaScriptEx) { - auto scope = apis->open_scope(env_ref); auto env = apis->get_env_from_ref(env_ref); auto code = " (function() { throw new Error('abc'); }) ();"; @@ -192,12 +206,9 @@ TEST_F(PApiBaseTest, EvalJavaScriptEx) { EXPECT_STREQ("Error: abc", apis->get_exception_as_string(scope, false)); EXPECT_STREQ("Error: abc\n at (test.js:1:21)\n at (test.js:1:42)\n", apis->get_exception_as_string(scope, true)); - - apis->close_scope(scope); } TEST_F(PApiBaseTest, SetToGlobal) { - auto scope = apis->open_scope(env_ref); auto env = apis->get_env_from_ref(env_ref); auto g = apis->global(env); @@ -208,13 +219,11 @@ TEST_F(PApiBaseTest, SetToGlobal) { ASSERT_TRUE(ret != nullptr); ASSERT_TRUE(apis->is_int32(env, ret)); ASSERT_TRUE(apis->get_value_int32(env, ret) == 123); - - apis->close_scope(scope); } TEST_F(PApiBaseTest, CreateJsFunction) { - auto scope = apis->open_scope(env_ref); + auto scope = apis->open_scope(env_ref); // 为了可以提前释放 auto env = apis->get_env_from_ref(env_ref); auto g = apis->global(env); @@ -243,7 +252,6 @@ TEST_F(PApiBaseTest, CreateJsFunction) { TEST_F(PApiBaseTest, PropertyGetSet) { - auto scope = apis->open_scope(env_ref); auto env = apis->get_env_from_ref(env_ref); auto g = apis->global(env); @@ -268,12 +276,9 @@ TEST_F(PApiBaseTest, PropertyGetSet) { buff[3] = 0; apis->get_value_string_utf8(env, str, buff, &len); EXPECT_STREQ("888", buff); - - apis->close_scope(scope); } TEST_F(PApiBaseTest, ClassCtorFinalize) { - auto scope = apis->open_scope(env_ref); auto env = apis->get_env_from_ref(env_ref); TestStruct::ctor_count = 0; @@ -297,13 +302,9 @@ TEST_F(PApiBaseTest, ClassCtorFinalize) { ASSERT_EQ(TestStruct::ctor_count, 1); ASSERT_EQ(TestStruct::dtor_count, 1); ASSERT_EQ(TestStruct::lastCtorObject, TestStruct::lastDtorObject); - - - apis->close_scope(scope); } TEST_F(PApiBaseTest, StaticFunctionCall) { - auto scope = apis->open_scope(env_ref); auto env = apis->get_env_from_ref(env_ref); auto code = R"( @@ -320,8 +321,26 @@ TEST_F(PApiBaseTest, StaticFunctionCall) { ASSERT_FALSE(apis->has_caught(scope)); ASSERT_TRUE(apis->is_int32(env, ret)); ASSERT_TRUE(apis->get_value_int32(env, ret) == 579); +} - apis->close_scope(scope); +TEST_F(PApiBaseTest, InstanceMethodCall) { + auto env = apis->get_env_from_ref(env_ref); + + auto code = R"( + (function() { + const TestStruct = loadClass('TestStruct'); + const obj = new TestStruct(123); + return obj.Calc(123, 456); + })(); + )"; + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught(scope)) + { + printf("%s\n", apis->get_exception_as_string(scope, true)); + } + ASSERT_FALSE(apis->has_caught(scope)); + //ASSERT_TRUE(apis->is_int32(env, ret)); + //ASSERT_TRUE(apis->get_value_int32(env, ret) == 702); } From e816754310b7262716421cd24f9644ea4af5aa6e Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 14:30:47 +0800 Subject: [PATCH 61/70] =?UTF-8?q?=E6=94=AF=E6=8C=81Data?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 2 +- source/CppObjectMapper.cpp | 32 +++++++++++++++++--------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index 85967dd..ad3d685 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -84,7 +84,7 @@ struct CppObjectMapper static JSValue CreateError(JSContext* ctx, const char* message); - void CreateMethod(puerts::JSFunctionInfo* FunctionInfo, JSValue Obj); + void CreateMethod(const char* Name, pesapi_callback Callback, void* Data, JSValue Obj); JSValue CreateClass(const puerts::JSClassDefinition* ClassDefinition); diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index f3a1b8c..1de90df 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -119,19 +119,20 @@ void CppObjectMapper::RemoveFromCache(const puerts::JSClassDefinition* typeInfo, } } -void CppObjectMapper::CreateMethod(puerts::JSFunctionInfo* FunctionInfo, JSValue Obj) +void CppObjectMapper::CreateMethod(const char* Name, pesapi_callback Callback, void* Data, JSValue Obj) { - JSValue method_data[2] { - JS_MKPTR(JS_TAG_EXTERNAL, (void*)FunctionInfo), - JS_MKPTR(JS_TAG_EXTERNAL, this) + JSValue method_data[3] { + JS_MKPTR(JS_TAG_EXTERNAL, (void*)Callback), + JS_MKPTR(JS_TAG_EXTERNAL, this), + JS_MKPTR(JS_TAG_EXTERNAL, Data) }; JSValue func = JS_NewCFunctionData(ctx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *method_data) -> JSValue { - const puerts::JSFunctionInfo* funcInfo = (const puerts::JSFunctionInfo*)(JS_VALUE_GET_PTR(method_data[0])); + pesapi_callback callback = (pesapi_callback)(JS_VALUE_GET_PTR(method_data[0])); CppObjectMapper* mapper = (CppObjectMapper*)(JS_VALUE_GET_PTR(method_data[1])); - pesapi_callback_info__ callbackInfo { ctx, this_val, argc, argv, JS_VALUE_GET_PTR(method_data[1]), JS_UNDEFINED, JS_UNDEFINED }; - funcInfo->Callback(&g_pesapi_ffi, &callbackInfo); + pesapi_callback_info__ callbackInfo { ctx, this_val, argc, argv, JS_VALUE_GET_PTR(method_data[2]), JS_UNDEFINED, JS_UNDEFINED }; + callback(&g_pesapi_ffi, &callbackInfo); if (JS_IsException(callbackInfo.res)) { JS_FreeValue(ctx, callbackInfo.res); @@ -141,9 +142,9 @@ void CppObjectMapper::CreateMethod(puerts::JSFunctionInfo* FunctionInfo, JSValue { return callbackInfo.res; } - }, 0, 0, 2, &method_data[0]); + }, 0, 0, 3, &method_data[0]); - JSAtom methodName = JS_NewAtom(ctx, FunctionInfo->Name); + JSAtom methodName = JS_NewAtom(ctx, Name); JS_DefinePropertyValue(ctx, Obj, methodName, func, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE); JS_FreeAtom(ctx, methodName); } @@ -153,9 +154,10 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin auto it = TypeIdToFunctionMap.find(ClassDefinition->TypeId); if (it == TypeIdToFunctionMap.end()) { - JSValue ctor_data[2] { + JSValue ctor_data[3] { JS_MKPTR(JS_TAG_EXTERNAL, (void*)ClassDefinition), - JS_MKPTR(JS_TAG_EXTERNAL, this) + JS_MKPTR(JS_TAG_EXTERNAL, this), + JS_MKPTR(JS_TAG_EXTERNAL, ClassDefinition->Data) }; JSValue func = JS_NewCFunctionData(ctx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *ctor_data) -> JSValue { @@ -164,7 +166,7 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin if (clsDef->Initialize) { - pesapi_callback_info__ callbackInfo { ctx, this_val, argc, argv, JS_VALUE_GET_PTR(ctor_data[1]), JS_UNDEFINED, JS_UNDEFINED }; + pesapi_callback_info__ callbackInfo { ctx, this_val, argc, argv, JS_VALUE_GET_PTR(ctor_data[2]), JS_UNDEFINED, JS_UNDEFINED }; JSValue proto = JS_GetProperty(ctx, this_val, JS_ATOM_prototype); callbackInfo.this_val = JS_NewObjectProtoClass(ctx, proto, mapper->classId); JS_FreeValue(ctx, proto); @@ -184,7 +186,7 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin { return JS_Throw(ctx, CppObjectMapper::CreateError(ctx, "no initialize function")); } - }, 0, 0, 2, &ctor_data[0]); + }, 0, 0, 3, &ctor_data[0]); JS_SetConstructorBit(ctx, func, 1); @@ -215,14 +217,14 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin puerts::JSFunctionInfo* FunctionInfo = ClassDefinition->Methods; while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) { - CreateMethod(FunctionInfo, proto); + CreateMethod(FunctionInfo->Name, FunctionInfo->Callback, FunctionInfo->Data, proto); ++FunctionInfo; } FunctionInfo = ClassDefinition->Functions; while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) { - CreateMethod(FunctionInfo, func); + CreateMethod(FunctionInfo->Name, FunctionInfo->Callback, FunctionInfo->Data, func); ++FunctionInfo; } From 9974ebe07bad8a941f48fd07f00f7dec682cc169 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 15:04:07 +0800 Subject: [PATCH 62/70] =?UTF-8?q?=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 4 ++- source/CppObjectMapper.cpp | 43 +++++++++++++++++++++++++++--- test/papi_qjs_base_test.cpp | 52 ++++++++++++++++++++++++++++++++++--- 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index ad3d685..a545147 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -84,7 +84,9 @@ struct CppObjectMapper static JSValue CreateError(JSContext* ctx, const char* message); - void CreateMethod(const char* Name, pesapi_callback Callback, void* Data, JSValue Obj); + JSValue MakeMethod(pesapi_callback Callback, void* Data); + void InitMethod(puerts::JSFunctionInfo* FuncInfo, JSValue Obj); + void InitProperty(puerts::JSPropertyInfo* PropInfo, JSValue Obj); JSValue CreateClass(const puerts::JSClassDefinition* ClassDefinition); diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 1de90df..33073db 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -119,7 +119,7 @@ void CppObjectMapper::RemoveFromCache(const puerts::JSClassDefinition* typeInfo, } } -void CppObjectMapper::CreateMethod(const char* Name, pesapi_callback Callback, void* Data, JSValue Obj) +JSValue CppObjectMapper::MakeMethod(pesapi_callback Callback, void* Data) { JSValue method_data[3] { JS_MKPTR(JS_TAG_EXTERNAL, (void*)Callback), @@ -143,12 +143,45 @@ void CppObjectMapper::CreateMethod(const char* Name, pesapi_callback Callback, v return callbackInfo.res; } }, 0, 0, 3, &method_data[0]); + + return func; +} + +void CppObjectMapper::InitMethod(puerts::JSFunctionInfo* FuncInfo, JSValue Obj) +{ + JSValue func = MakeMethod(FuncInfo->Callback, FuncInfo->Data); - JSAtom methodName = JS_NewAtom(ctx, Name); + JSAtom methodName = JS_NewAtom(ctx, FuncInfo->Name); JS_DefinePropertyValue(ctx, Obj, methodName, func, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE); JS_FreeAtom(ctx, methodName); } +void CppObjectMapper::InitProperty(puerts::JSPropertyInfo* PropInfo, JSValue Obj) +{ + JSValue getter = JS_UNDEFINED; + JSValue setter = JS_UNDEFINED; + int flag = JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE; + + if (PropInfo->Getter) + { + getter = MakeMethod(PropInfo->Getter, PropInfo->GetterData); + flag |= JS_PROP_HAS_GET; + } + + if (PropInfo->Setter) + { + setter = MakeMethod(PropInfo->Setter, PropInfo->SetterData); + flag |= JS_PROP_HAS_SET; + flag |= JS_PROP_WRITABLE; + } + + JSAtom propName = JS_NewAtom(ctx, PropInfo->Name); + JS_DefineProperty(ctx, Obj, propName, JS_UNDEFINED, getter, setter, flag); + JS_FreeAtom(ctx, propName); + JS_FreeValue(ctx, getter); + JS_FreeValue(ctx, setter); +} + JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefinition) { auto it = TypeIdToFunctionMap.find(ClassDefinition->TypeId); @@ -205,26 +238,28 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin puerts::JSPropertyInfo* PropertyInfo = ClassDefinition->Properties; while (PropertyInfo && PropertyInfo->Name) { + InitProperty(PropertyInfo, proto); ++PropertyInfo; } PropertyInfo = ClassDefinition->Variables; while (PropertyInfo && PropertyInfo->Name) { + InitProperty(PropertyInfo, func); ++PropertyInfo; } puerts::JSFunctionInfo* FunctionInfo = ClassDefinition->Methods; while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) { - CreateMethod(FunctionInfo->Name, FunctionInfo->Callback, FunctionInfo->Data, proto); + InitMethod(FunctionInfo, proto); ++FunctionInfo; } FunctionInfo = ClassDefinition->Functions; while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) { - CreateMethod(FunctionInfo->Name, FunctionInfo->Callback, FunctionInfo->Data, func); + InitMethod(FunctionInfo, func); ++FunctionInfo; } diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index bd15c7b..037821b 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -61,7 +61,6 @@ static void AddWrap(struct pesapi_ffi* apis, pesapi_callback_info info) apis->add_return(info, apis->create_int32(env, TestStruct::Add(a, b))); } - static void CalcWrap(struct pesapi_ffi* apis, pesapi_callback_info info) { auto env = apis->get_env(info); @@ -74,14 +73,32 @@ static void CalcWrap(struct pesapi_ffi* apis, pesapi_callback_info info) apis->add_return(info, apis->create_int32(env, obj->Calc(a, b))); } +static void AGetterWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto self = apis->get_this(info); + auto obj = (TestStruct*)apis->get_native_object_ptr(env, self); + apis->add_return(info, apis->create_int32(env, obj->a)); +} + +static void ASetterWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto self = apis->get_this(info); + auto obj = (TestStruct*)apis->get_native_object_ptr(env, self); + auto p0 = apis->get_arg(info, 0); + obj->a = apis->get_value_int32(env, p0); +} + class PApiBaseTest : public ::testing::Test { public: static void SetUpTestCase() { const void* typeId = "TestStruct"; - const int properties_count = 2; + const int properties_count = 3; pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(properties_count); pesapi_set_method_info(properties, 0, "Add", true, AddWrap, NULL, NULL); pesapi_set_method_info(properties, 1, "Calc", false, CalcWrap, NULL, NULL); + pesapi_set_property_info(properties, 2, "a", false, AGetterWrap, ASetterWrap, NULL, NULL, NULL); pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, properties_count, properties, NULL); } @@ -339,8 +356,35 @@ TEST_F(PApiBaseTest, InstanceMethodCall) { printf("%s\n", apis->get_exception_as_string(scope, true)); } ASSERT_FALSE(apis->has_caught(scope)); - //ASSERT_TRUE(apis->is_int32(env, ret)); - //ASSERT_TRUE(apis->get_value_int32(env, ret) == 702); + ASSERT_TRUE(apis->is_int32(env, ret)); + ASSERT_TRUE(apis->get_value_int32(env, ret) == 702); +} + +TEST_F(PApiBaseTest, PropertyAccess) { + auto env = apis->get_env_from_ref(env_ref); + + auto code = R"( + (function() { + const TestStruct = loadClass('TestStruct'); + const obj = new TestStruct(123); + let ret = "" + obj.a + ":"; + obj.a = 0; + ret += obj.Calc(123, 456); + return ret; + })(); + )"; + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught(scope)) + { + printf("%s\n", apis->get_exception_as_string(scope, true)); + } + ASSERT_FALSE(apis->has_caught(scope)); + ASSERT_TRUE(apis->is_string(env, ret)); + char buff[1024]; + size_t len = sizeof(buff); + const char* str = apis->get_value_string_utf8(env, ret, buff, &len); + //printf("%s, %d\n", str, len); + EXPECT_STREQ("123:579", str); } From fff141bc8b4f66c5447ba6e47d79b1bfd8cf2730 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 15:12:38 +0800 Subject: [PATCH 63/70] =?UTF-8?q?=E9=9D=99=E6=80=81=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E7=9A=84=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 40 ++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 037821b..3abd9c3 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -90,15 +90,29 @@ static void ASetterWrap(struct pesapi_ffi* apis, pesapi_callback_info info) obj->a = apis->get_value_int32(env, p0); } +static void CtorCountGetterWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + apis->add_return(info, apis->create_int32(env, TestStruct::ctor_count)); +} + +static void CtorCountSetterWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto p0 = apis->get_arg(info, 0); + TestStruct::ctor_count = apis->get_value_int32(env, p0); +} + class PApiBaseTest : public ::testing::Test { public: static void SetUpTestCase() { const void* typeId = "TestStruct"; - const int properties_count = 3; + const int properties_count = 4; pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(properties_count); pesapi_set_method_info(properties, 0, "Add", true, AddWrap, NULL, NULL); pesapi_set_method_info(properties, 1, "Calc", false, CalcWrap, NULL, NULL); pesapi_set_property_info(properties, 2, "a", false, AGetterWrap, ASetterWrap, NULL, NULL, NULL); + pesapi_set_property_info(properties, 3, "ctor_count", true, CtorCountGetterWrap, CtorCountSetterWrap, NULL, NULL, NULL); pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, properties_count, properties, NULL); } @@ -387,6 +401,30 @@ TEST_F(PApiBaseTest, PropertyAccess) { EXPECT_STREQ("123:579", str); } +TEST_F(PApiBaseTest, VariableAccess) { + auto env = apis->get_env_from_ref(env_ref); + + auto code = R"( + (function() { + const TestStruct = loadClass('TestStruct'); + const obj = new TestStruct(123); + const ret = TestStruct.ctor_count + TestStruct.ctor_count = 999; + return ret; + })(); + )"; + TestStruct::ctor_count = 100; + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught(scope)) + { + printf("%s\n", apis->get_exception_as_string(scope, true)); + } + ASSERT_FALSE(apis->has_caught(scope)); + EXPECT_EQ(999, TestStruct::ctor_count); + ASSERT_TRUE(apis->is_int32(env, ret)); + ASSERT_TRUE(apis->get_value_int32(env, ret) == 101); +} + } // namespace qjsimpl } // namespace pesapi From 7f5a4fcae07da4c83ac9a4c62caaf990adcb579d Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 15:59:25 +0800 Subject: [PATCH 64/70] =?UTF-8?q?native=5Fobject=5Fto=5Fvalue=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E4=BB=A5=E5=8F=8A=E5=AF=B9=E8=B1=A1=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 6 +++++- source/CppObjectMapper.cpp | 41 +++++++++++++++++++++++++++++++++++-- source/PapiQuickjsImpl.cpp | 6 +++++- test/papi_qjs_base_test.cpp | 35 +++++++++++++++++++++++++++++-- 4 files changed, 82 insertions(+), 6 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index a545147..937b884 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -50,6 +50,8 @@ struct CppObjectMapper const void* envPrivate = nullptr; eastl::shared_ptr ref = eastl::allocate_shared(eastl::allocator_malloc("shared_ptr"), 0); + puerts::JSClassDefinition PtrClassDef = JSClassEmptyDefinition; + inline static eastl::weak_ptr GetEnvLifeCycleTracker(JSContext* ctx) { JSRuntime* rt = JS_GetRuntime(ctx); @@ -90,9 +92,11 @@ struct CppObjectMapper JSValue CreateClass(const puerts::JSClassDefinition* ClassDefinition); - void AddToCache(const puerts::JSClassDefinition* typeInfo, const void* ptr, JSValue value, bool callFinalize); + void BindAndAddToCache(const puerts::JSClassDefinition* typeInfo, const void* ptr, JSValue value, bool callFinalize); void RemoveFromCache(const puerts::JSClassDefinition* typeInfo, const void* ptr); + + JSValue PushNativeObject(const void* TypeId, void* ObjectPtr, bool callFinalize); }; } // namespace qjsimpl diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 33073db..7d61abd 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -83,7 +83,7 @@ void PApiObjectFinalizer(JSRuntime* rt, JSValue val) js_free_rt(rt, object_udata); } -void CppObjectMapper::AddToCache(const puerts::JSClassDefinition* typeInfo, const void* ptr, JSValue value, bool callFinalize) +void CppObjectMapper::BindAndAddToCache(const puerts::JSClassDefinition* typeInfo, const void* ptr, JSValue value, bool callFinalize) { ObjectUserData* object_udata = (ObjectUserData*)js_malloc(ctx, sizeof(ObjectUserData)); object_udata->typeInfo = typeInfo; @@ -119,6 +119,40 @@ void CppObjectMapper::RemoveFromCache(const puerts::JSClassDefinition* typeInfo, } } +JSValue CppObjectMapper::PushNativeObject(const void* TypeId, void* ObjectPtr, bool callFinalize) +{ + if (!ObjectPtr) + { + return JS_UNDEFINED; + } + + if (!callFinalize) + { + auto Iter = CDataCache.find(ObjectPtr); + if (Iter != CDataCache.end()) + { + auto CacheNodePtr = Iter->second.Find(TypeId); + if (CacheNodePtr) + { + return JS_DupValue(ctx, CacheNodePtr->Value); + } + } + } + + auto ClassDefinition = puerts::FindClassByID(TypeId); + if (!ClassDefinition) + { + ClassDefinition = &PtrClassDef; + } + JSValue ctor = CreateClass(ClassDefinition); + JSValue proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype); + JSValue obj = JS_NewObjectProtoClass(ctx, proto, classId); + JS_FreeValue(ctx, proto); + BindAndAddToCache(ClassDefinition, ObjectPtr, obj, callFinalize); + + return obj; +} + JSValue CppObjectMapper::MakeMethod(pesapi_callback Callback, void* Data) { JSValue method_data[3] { @@ -204,7 +238,7 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin callbackInfo.this_val = JS_NewObjectProtoClass(ctx, proto, mapper->classId); JS_FreeValue(ctx, proto); void* ptr = clsDef->Initialize(&g_pesapi_ffi, &callbackInfo); - mapper->AddToCache(clsDef, ptr, callbackInfo.this_val, true); + mapper->BindAndAddToCache(clsDef, ptr, callbackInfo.this_val, true); if (JS_IsException(callbackInfo.res)) { JS_FreeValue(ctx, callbackInfo.this_val); @@ -315,6 +349,9 @@ void CppObjectMapper::Initialize(JSContext* ctx_) funcTracerClassId = 0; JS_NewClassID(rt, &funcTracerClassId); JS_NewClass(rt, funcTracerClassId, &func_tracer_cls_def); + + PtrClassDef.TypeId = &PtrClassDef; + PtrClassDef.ScriptName = "__Pointer"; } void CppObjectMapper::Cleanup() diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index d8a8734..3d5f4ca 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -380,7 +380,11 @@ bool pesapi_is_array(pesapi_env env, pesapi_value pvalue) pesapi_value pesapi_native_object_to_value(pesapi_env env, const void* type_id, void* object_ptr, bool call_finalize) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + auto mapper = pesapi::qjsimpl::CppObjectMapper::Get(ctx); + auto ret = allocValueInCurrentScope(ctx); + *ret = mapper->PushNativeObject(type_id, object_ptr, call_finalize); + return pesapiValueFromQjsValue(ret); } void* pesapi_get_native_object_ptr(pesapi_env env, pesapi_value pvalue) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 3abd9c3..3e56cb6 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -33,6 +33,8 @@ struct TestStruct { } }; +const void* typeId = "TestStruct"; + int TestStruct::ctor_count = 0; int TestStruct::dtor_count = 0; TestStruct* TestStruct::lastCtorObject = nullptr; @@ -103,16 +105,24 @@ static void CtorCountSetterWrap(struct pesapi_ffi* apis, pesapi_callback_info in TestStruct::ctor_count = apis->get_value_int32(env, p0); } +static void GetSelfWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto self = apis->get_this(info); + auto obj = (TestStruct*)apis->get_native_object_ptr(env, self); + apis->add_return(info, apis->native_object_to_value(env, typeId, obj, false)); +} + class PApiBaseTest : public ::testing::Test { public: static void SetUpTestCase() { - const void* typeId = "TestStruct"; - const int properties_count = 4; + const int properties_count = 5; pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(properties_count); pesapi_set_method_info(properties, 0, "Add", true, AddWrap, NULL, NULL); pesapi_set_method_info(properties, 1, "Calc", false, CalcWrap, NULL, NULL); pesapi_set_property_info(properties, 2, "a", false, AGetterWrap, ASetterWrap, NULL, NULL, NULL); pesapi_set_property_info(properties, 3, "ctor_count", true, CtorCountGetterWrap, CtorCountSetterWrap, NULL, NULL, NULL); + pesapi_set_method_info(properties, 4, "GetSelf", false, GetSelfWrap, NULL, NULL); pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, properties_count, properties, NULL); } @@ -425,6 +435,27 @@ TEST_F(PApiBaseTest, VariableAccess) { ASSERT_TRUE(apis->get_value_int32(env, ret) == 101); } +TEST_F(PApiBaseTest, ReturnAObject) { + auto env = apis->get_env_from_ref(env_ref); + + auto code = R"( + (function() { + const TestStruct = loadClass('TestStruct'); + const obj = new TestStruct(123); + const self = obj.GetSelf(); + return obj == self; + })(); + )"; + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught(scope)) + { + printf("%s\n", apis->get_exception_as_string(scope, true)); + } + ASSERT_FALSE(apis->has_caught(scope)); + ASSERT_TRUE(apis->is_boolean(env, ret)); + ASSERT_TRUE(apis->get_value_bool(env, ret)); +} + } // namespace qjsimpl } // namespace pesapi From 82eb9774631878ac6864435bb74adedc746e2ed7 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 16:05:24 +0800 Subject: [PATCH 65/70] pesapi_get_native_object_typeid --- include/CppObjectMapper.h | 6 ++++++ source/PapiQuickjsImpl.cpp | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index 937b884..499b711 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -80,6 +80,12 @@ struct CppObjectMapper return object_udata ? object_udata->ptr : nullptr; } + inline const void* GetNativeObjectTypeId(JSValue val) + { + ObjectUserData* object_udata = (ObjectUserData*)JS_GetOpaque(val, classId); + return object_udata ? object_udata->typeInfo->TypeId : nullptr; + } + JSValue CreateFunction(pesapi_callback Callback, void* Data, pesapi_function_finalize Finalize); JSValue CreateClassByID(const void* typeId); diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 3d5f4ca..2b6b859 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -397,7 +397,10 @@ void* pesapi_get_native_object_ptr(pesapi_env env, pesapi_value pvalue) const void* pesapi_get_native_object_typeid(pesapi_env env, pesapi_value pvalue) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + auto mapper = pesapi::qjsimpl::CppObjectMapper::Get(ctx); + auto value = qjsValueFromPesapiValue(pvalue); + return mapper->GetNativeObjectTypeId(*value); } bool pesapi_is_instance_of(pesapi_env env, const void* type_id, pesapi_value pvalue) From df5415db8aa52699b3188fd458a234286c7c9df8 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 16:08:33 +0800 Subject: [PATCH 66/70] pesapi_is_instance_of --- source/PapiQuickjsImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 2b6b859..b05d9ad 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -405,7 +405,7 @@ const void* pesapi_get_native_object_typeid(pesapi_env env, pesapi_value pvalue) bool pesapi_is_instance_of(pesapi_env env, const void* type_id, pesapi_value pvalue) { - return false; + return pesapi_get_native_object_typeid(env, pvalue) == type_id; // TODO: api 不正交 } pesapi_value pesapi_boxing(pesapi_env env, pesapi_value pvalue) From f7f80c3d99e42c0bf10ae0bcd0b4b92cd8d2f451 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 16:27:24 +0800 Subject: [PATCH 67/70] fix Atom leaks --- quickjs/quickjs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c index 7923022..8704e8e 100644 --- a/quickjs/quickjs.c +++ b/quickjs/quickjs.c @@ -3177,7 +3177,9 @@ JSValue JS_NewSymbol(JSContext *ctx, const char *description, JS_BOOL is_global) JSAtom atom = JS_NewAtom(ctx, description); if (atom == JS_ATOM_NULL) return JS_EXCEPTION; - return JS_NewSymbolFromAtom(ctx, atom, is_global ? JS_ATOM_TYPE_GLOBAL_SYMBOL : JS_ATOM_TYPE_SYMBOL); + JSValue res = JS_NewSymbolFromAtom(ctx, atom, is_global ? JS_ATOM_TYPE_GLOBAL_SYMBOL : JS_ATOM_TYPE_SYMBOL); + JS_FreeAtom(ctx, atom); + return res; } #define ATOM_GET_STR_BUF_SIZE 64 From bc632b596cd16d44ffd5ae4fac63661fb2b6190f Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 16:46:59 +0800 Subject: [PATCH 68/70] =?UTF-8?q?=E5=85=88=E4=B8=8D=E7=94=A8=E8=BF=99?= =?UTF-8?q?=E4=B8=AAapi=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- quickjs/quickjs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c index 8704e8e..7923022 100644 --- a/quickjs/quickjs.c +++ b/quickjs/quickjs.c @@ -3177,9 +3177,7 @@ JSValue JS_NewSymbol(JSContext *ctx, const char *description, JS_BOOL is_global) JSAtom atom = JS_NewAtom(ctx, description); if (atom == JS_ATOM_NULL) return JS_EXCEPTION; - JSValue res = JS_NewSymbolFromAtom(ctx, atom, is_global ? JS_ATOM_TYPE_GLOBAL_SYMBOL : JS_ATOM_TYPE_SYMBOL); - JS_FreeAtom(ctx, atom); - return res; + return JS_NewSymbolFromAtom(ctx, atom, is_global ? JS_ATOM_TYPE_GLOBAL_SYMBOL : JS_ATOM_TYPE_SYMBOL); } #define ATOM_GET_STR_BUF_SIZE 64 From 017f3dc89cbd6072d3583e61b8ae6ad14c782e36 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 17:00:01 +0800 Subject: [PATCH 69/70] =?UTF-8?q?pesapi=5Fget=5Fprivate=E3=80=81pesapi=5Fs?= =?UTF-8?q?et=5Fprivate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/CppObjectMapper.h | 33 +++++++++++++++++++++++++++++++++ source/CppObjectMapper.cpp | 6 ++++-- source/PapiQuickjsImpl.cpp | 10 ++++++++-- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/include/CppObjectMapper.h b/include/CppObjectMapper.h index 499b711..bcb8bff 100644 --- a/include/CppObjectMapper.h +++ b/include/CppObjectMapper.h @@ -8,6 +8,8 @@ #include "ObjectCacheNode.h" #include "JSClassRegister.h" +#define JS_TAG_EXTERNAL (JS_TAG_FLOAT64 + 1) + namespace pesapi { namespace qjsimpl @@ -52,6 +54,8 @@ struct CppObjectMapper puerts::JSClassDefinition PtrClassDef = JSClassEmptyDefinition; + JSAtom privateDataKey; + inline static eastl::weak_ptr GetEnvLifeCycleTracker(JSContext* ctx) { JSRuntime* rt = JS_GetRuntime(ctx); @@ -86,6 +90,35 @@ struct CppObjectMapper return object_udata ? object_udata->typeInfo->TypeId : nullptr; } + inline bool GetPrivate(JSValue val, void** outPrr) const + { + if (!JS_IsObject(val)) + { + return false; + } + + JSValue data = JS_GetProperty(ctx, val, privateDataKey); + if (JS_VALUE_GET_TAG(data) == JS_TAG_EXTERNAL) + { + *outPrr = JS_VALUE_GET_PTR(data); + } + else + { + JS_FreeValue(ctx, data); + } + return true; + } + + inline bool SetPrivate(JSValue val, void* ptr) + { + if (!JS_IsObject(val)) + { + return false; + } + JS_SetProperty(ctx, val, privateDataKey, JS_MKPTR(JS_TAG_EXTERNAL, ptr)); + return true; + } + JSValue CreateFunction(pesapi_callback Callback, void* Data, pesapi_function_finalize Finalize); JSValue CreateClassByID(const void* typeId); diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index 7d61abd..ec910c3 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -2,8 +2,6 @@ #include "pesapi.h" #include "PapiData.h" -#define JS_TAG_EXTERNAL (JS_TAG_FLOAT64 + 1) - namespace pesapi { namespace qjsimpl @@ -352,10 +350,14 @@ void CppObjectMapper::Initialize(JSContext* ctx_) PtrClassDef.TypeId = &PtrClassDef; PtrClassDef.ScriptName = "__Pointer"; + + privateDataKey = JS_NewAtom(ctx, "__papi_private_data"); } void CppObjectMapper::Cleanup() { + JS_FreeAtom(ctx, privateDataKey); + for(auto& kv : TypeIdToFunctionMap) { JS_FreeValue(ctx, kv.second); diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index b05d9ad..67466ee 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -663,12 +663,18 @@ void pesapi_set_property(pesapi_env env, pesapi_value pobject, const char* key, bool pesapi_get_private(pesapi_env env, pesapi_value pobject, void** out_ptr) { - return true; + auto ctx = qjsContextFromPesapiEnv(env); + auto mapper = pesapi::qjsimpl::CppObjectMapper::Get(ctx); + JSValue* obj = qjsValueFromPesapiValue(pobject); + return mapper->GetPrivate(*obj, out_ptr); } bool pesapi_set_private(pesapi_env env, pesapi_value pobject, void* ptr) { - return true; + auto ctx = qjsContextFromPesapiEnv(env); + auto mapper = pesapi::qjsimpl::CppObjectMapper::Get(ctx); + JSValue* obj = qjsValueFromPesapiValue(pobject); + return mapper->SetPrivate(*obj, ptr); } pesapi_value pesapi_get_property_uint32(pesapi_env env, pesapi_value pobject, uint32_t key) From 8ecdf6781f1c9dc134e7e1a3a28a437e48a84485 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 17:32:14 +0800 Subject: [PATCH 70/70] =?UTF-8?q?=E8=A3=85=E7=AE=B1=E7=9B=B8=E5=85=B3api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 35 +++++++++++++++++++++++--- test/papi_qjs_base_test.cpp | 49 +++++++++++++++++++++++++++++++++---- 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 67466ee..7ee4c97 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -410,16 +410,43 @@ bool pesapi_is_instance_of(pesapi_env env, const void* type_id, pesapi_value pva pesapi_value pesapi_boxing(pesapi_env env, pesapi_value pvalue) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + JSValue* boxed_value = allocValueInCurrentScope(ctx); + *boxed_value = JS_NewObject(ctx); + JSValue* val = qjsValueFromPesapiValue(pvalue); + if (JS_VALUE_HAS_REF_COUNT(*val)) { + JS_DupValue(ctx, *val); + } + JS_SetPropertyUint32(ctx, *boxed_value, 0, *val); + return pesapiValueFromQjsValue(boxed_value); } -pesapi_value pesapi_unboxing(pesapi_env env, pesapi_value pvalue) +pesapi_value pesapi_unboxing(pesapi_env env, pesapi_value p_boxed_value) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + JSValue* boxed_value = qjsValueFromPesapiValue(p_boxed_value); + if (!boxed_value || !JS_IsObject(*boxed_value)) + { + return pesapiValueFromQjsValue(&literal_values_undefined); + } + JSValue* ret = allocValueInCurrentScope(ctx); + *ret = JS_GetPropertyUint32(ctx, *boxed_value, 0); + return pesapiValueFromQjsValue(ret); } -void pesapi_update_boxed_value(pesapi_env env, pesapi_value boxed_value, pesapi_value pvalue) +void pesapi_update_boxed_value(pesapi_env env, pesapi_value p_boxed_value, pesapi_value pvalue) { + auto ctx = qjsContextFromPesapiEnv(env); + JSValue* boxed_value = qjsValueFromPesapiValue(p_boxed_value); + if (!boxed_value || !JS_IsObject(*boxed_value)) + { + return; + } + JSValue* val = qjsValueFromPesapiValue(pvalue); + if (JS_VALUE_HAS_REF_COUNT(*val)) { + JS_DupValue(ctx, *val); + } + JS_SetPropertyUint32(ctx, *boxed_value, 0, *val); } bool pesapi_is_boxed_value(pesapi_env env, pesapi_value value) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 3e56cb6..91a5774 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -28,6 +28,10 @@ struct TestStruct { return a + x + y; } + void Inc(int &x) { + x += a; + } + static int Add(int x, int y) { return x + y; } @@ -113,16 +117,29 @@ static void GetSelfWrap(struct pesapi_ffi* apis, pesapi_callback_info info) apis->add_return(info, apis->native_object_to_value(env, typeId, obj, false)); } +static void IncWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto self = apis->get_this(info); + auto obj = (TestStruct*)apis->get_native_object_ptr(env, self); + auto p0 = apis->get_arg(info, 0); + auto unboxed = apis->unboxing(env, p0); + int p = apis->get_value_int32(env, unboxed); + obj->Inc(p); + apis->update_boxed_value(env, p0, apis->create_int32(env, p)); +} + class PApiBaseTest : public ::testing::Test { public: static void SetUpTestCase() { - const int properties_count = 5; + const int properties_count = 6; pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(properties_count); pesapi_set_method_info(properties, 0, "Add", true, AddWrap, NULL, NULL); pesapi_set_method_info(properties, 1, "Calc", false, CalcWrap, NULL, NULL); pesapi_set_property_info(properties, 2, "a", false, AGetterWrap, ASetterWrap, NULL, NULL, NULL); pesapi_set_property_info(properties, 3, "ctor_count", true, CtorCountGetterWrap, CtorCountSetterWrap, NULL, NULL, NULL); pesapi_set_method_info(properties, 4, "GetSelf", false, GetSelfWrap, NULL, NULL); + pesapi_set_method_info(properties, 5, "Inc", false, IncWrap, NULL, NULL); pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, properties_count, properties, NULL); } @@ -259,7 +276,7 @@ TEST_F(PApiBaseTest, SetToGlobal) { auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); ASSERT_TRUE(ret != nullptr); ASSERT_TRUE(apis->is_int32(env, ret)); - ASSERT_TRUE(apis->get_value_int32(env, ret) == 123); + EXPECT_EQ(123, apis->get_value_int32(env, ret)); } @@ -361,7 +378,7 @@ TEST_F(PApiBaseTest, StaticFunctionCall) { } ASSERT_FALSE(apis->has_caught(scope)); ASSERT_TRUE(apis->is_int32(env, ret)); - ASSERT_TRUE(apis->get_value_int32(env, ret) == 579); + EXPECT_EQ(579, apis->get_value_int32(env, ret)); } TEST_F(PApiBaseTest, InstanceMethodCall) { @@ -381,7 +398,7 @@ TEST_F(PApiBaseTest, InstanceMethodCall) { } ASSERT_FALSE(apis->has_caught(scope)); ASSERT_TRUE(apis->is_int32(env, ret)); - ASSERT_TRUE(apis->get_value_int32(env, ret) == 702); + EXPECT_EQ(702, apis->get_value_int32(env, ret)); } TEST_F(PApiBaseTest, PropertyAccess) { @@ -432,7 +449,7 @@ TEST_F(PApiBaseTest, VariableAccess) { ASSERT_FALSE(apis->has_caught(scope)); EXPECT_EQ(999, TestStruct::ctor_count); ASSERT_TRUE(apis->is_int32(env, ret)); - ASSERT_TRUE(apis->get_value_int32(env, ret) == 101); + EXPECT_EQ(101, apis->get_value_int32(env, ret)); } TEST_F(PApiBaseTest, ReturnAObject) { @@ -456,6 +473,28 @@ TEST_F(PApiBaseTest, ReturnAObject) { ASSERT_TRUE(apis->get_value_bool(env, ret)); } +TEST_F(PApiBaseTest, RefArgument) { + auto env = apis->get_env_from_ref(env_ref); + + auto code = R"( + (function() { + const TestStruct = loadClass('TestStruct'); + const obj = new TestStruct(2); + const r = [3]; + const self = obj.Inc(r); + return r[0]; + })(); + )"; + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught(scope)) + { + printf("%s\n", apis->get_exception_as_string(scope, true)); + } + ASSERT_FALSE(apis->has_caught(scope)); + ASSERT_TRUE(apis->is_int32(env, ret)); + EXPECT_EQ(5, apis->get_value_int32(env, ret)); +} + } // namespace qjsimpl } // namespace pesapi