├── pesapitest ├── pesaddon │ ├── make_win64.bat │ ├── make_osx.sh │ ├── make_ios.sh │ ├── CMakeLists.txt │ ├── make_android.sh │ └── src │ │ ├── TestClass.h │ │ ├── TestClass.cc │ │ └── hello.cc ├── pesv8app │ ├── make_win64.bat │ ├── CMakeLists.txt │ └── hello-world.cc └── pesapiv8impl │ ├── src │ └── PesapiAddonLoad.cpp │ └── include │ └── pesapi.h ├── puertstest ├── make_win64.bat ├── puerts │ ├── include │ │ ├── Binding.hpp │ │ ├── StdFunctionConverter.hpp │ │ ├── CppObjectMapper.h │ │ ├── Object.hpp │ │ ├── ObjectCacheNode.h │ │ ├── JSClassRegister.h │ │ ├── ObjectMapper.h │ │ ├── V8FastCall.hpp │ │ ├── PesapiObject.hpp │ │ ├── ScriptBackend.hpp │ │ ├── V8Object.hpp │ │ ├── DataTransfer.h │ │ ├── TypeInfo.hpp │ │ └── PesapiBackend.hpp │ └── src │ │ ├── DataTransfer.cpp │ │ ├── JSClassRegister.cpp │ │ └── CppObjectMapper.cpp ├── CMakeLists.txt └── hello-world.cc ├── nodeaddon ├── hello.js ├── package.json ├── CMakeLists.txt └── hello.cc ├── LICENSE ├── nodejstest ├── CMakeLists.txt └── embedtest.cc ├── .github └── workflows │ └── ci.yml ├── README.md ├── snapshottest ├── CMakeLists.txt └── hello-world.cc └── helloworld ├── hello-world.cc └── CMakeLists.txt /pesapitest/pesaddon/make_win64.bat: -------------------------------------------------------------------------------- 1 | mkdir build64 & pushd build64 2 | cmake -G "Visual Studio 16 2019" -A x64 .. 3 | popd 4 | cmake --build build64 --config Release 5 | -------------------------------------------------------------------------------- /pesapitest/pesaddon/make_osx.sh: -------------------------------------------------------------------------------- 1 | CONFIG="Release" 2 | 3 | mkdir -p build_osx && cd build_osx 4 | cmake -DCMAKE_BUILD_TYPE=$CONFIG -GXcode ../ 5 | cd .. 6 | cmake --build build_osx --config $CONFIG 7 | -------------------------------------------------------------------------------- /pesapitest/pesaddon/make_ios.sh: -------------------------------------------------------------------------------- 1 | CONFIG="Release" 2 | 3 | mkdir -p build_ios && cd build_ios 4 | cmake -DCMAKE_BUILD_TYPE=$CONFIG -DCMAKE_TOOLCHAIN_FILE=../cmake/ios.toolchain.cmake -DPLATFORM=OS64 -GXcode ../ 5 | cd .. 6 | cmake --build build_ios --config $CONFIG 7 | 8 | 9 | -------------------------------------------------------------------------------- /puertstest/make_win64.bat: -------------------------------------------------------------------------------- 1 | set ENGINE=%1 2 | if "%ENGINE%"=="" ( 3 | set ENGINE=v8 4 | ) 5 | 6 | mkdir build64_%ENGINE% & pushd build64_%ENGINE% 7 | cmake -DJS_ENGINE=%ENGINE% -G "Visual Studio 16 2019" -A x64 .. 8 | popd 9 | cmake --build build64_%ENGINE% --config Release 10 | -------------------------------------------------------------------------------- /pesapitest/pesv8app/make_win64.bat: -------------------------------------------------------------------------------- 1 | set ENGINE=%1 2 | if "%ENGINE%"=="" ( 3 | set ENGINE=v8 4 | ) 5 | 6 | mkdir build64_%ENGINE% & pushd build64_%ENGINE% 7 | cmake -DJS_ENGINE=%ENGINE% -G "Visual Studio 16 2019" -A x64 .. 8 | popd 9 | cmake --build build64_%ENGINE% --config Release 10 | -------------------------------------------------------------------------------- /nodeaddon/hello.js: -------------------------------------------------------------------------------- 1 | var addon = require('bindings')('hello'); 2 | 3 | const TestClass = addon.loadCppType('TestClass'); 4 | TestClass.Print('hello world'); 5 | let obj = new TestClass(123); 6 | 7 | TestClass.Print(obj.X); 8 | obj.X = 99; 9 | TestClass.Print(obj.X); 10 | 11 | TestClass.Print('ret = ' + obj.Add(1, 3)); -------------------------------------------------------------------------------- /nodeaddon/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "build-node-addon-api-with-cmake", 3 | "version": "0.0.0", 4 | "description": "Build native addon with CMake.", 5 | "main": "hello.js", 6 | "private": true, 7 | "dependencies": { 8 | "bindings": "~1.2.1", 9 | "node-addon-api": "^1.0.0" 10 | }, 11 | "scripts": { 12 | "install": "cmake-js compile", 13 | "test": "node hello.js" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /puertstest/puerts/include/Binding.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "StaticCall.hpp" 12 | #include "ScriptBackend.hpp" 13 | #include "Object.hpp" 14 | -------------------------------------------------------------------------------- /pesapitest/pesaddon/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9) 2 | cmake_policy(SET CMP0042 NEW) 3 | set (CMAKE_CXX_STANDARD 14) 4 | 5 | project (hello) 6 | 7 | set(PUERTS_LIB_ROOT ../../puertstest/puerts) 8 | set(PUERTS_INCLUDE ${PUERTS_LIB_ROOT}/include) 9 | set(PESAPI_ROOT ../pesapiv8impl) 10 | set(PESAPI_INCLUDE ${PESAPI_ROOT}/include) 11 | 12 | file(GLOB SOURCE_FILES "src/hello.cc", "src/TestClass.cc") 13 | 14 | 15 | include_directories( 16 | ${PESAPI_INCLUDE} 17 | ${PUERTS_INCLUDE} # for template support 18 | "src" 19 | ) 20 | 21 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} pesapi_adpt.c) 22 | 23 | target_compile_definitions (${PROJECT_NAME} PRIVATE BUILDING_PES_EXTENSION) 24 | -------------------------------------------------------------------------------- /nodeaddon/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9) 2 | cmake_policy(SET CMP0042 NEW) 3 | set (CMAKE_CXX_STANDARD 11) 4 | 5 | project (hello) 6 | 7 | set(PUERTS_LIB_ROOT ../puertstest/puerts) 8 | set(PUERTS_INCLUDE ${PUERTS_LIB_ROOT}/include) 9 | set(PUERTS_SRC 10 | ${PUERTS_LIB_ROOT}/src/CppObjectMapper.cpp 11 | ${PUERTS_LIB_ROOT}/src/DataTransfer.cpp 12 | ${PUERTS_LIB_ROOT}/src/JSClassRegister.cpp 13 | ) 14 | 15 | include_directories(${CMAKE_JS_INC} ${PUERTS_INCLUDE}) 16 | file(GLOB SOURCE_FILES "hello.cc" ) 17 | 18 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC} ${PUERTS_SRC}) 19 | set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node") 20 | target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB}) 21 | 22 | # define NPI_VERSION 23 | add_definitions(-DNAPI_VERSION=3) -------------------------------------------------------------------------------- /pesapitest/pesaddon/make_android.sh: -------------------------------------------------------------------------------- 1 | 2 | CONFIG="Release" 3 | 4 | if [ -n "$ANDROID_NDK" ]; then 5 | export NDK=${ANDROID_NDK} 6 | elif [ -n "$ANDROID_NDK_HOME" ]; then 7 | export NDK=${ANDROID_NDK_HOME} 8 | else 9 | export NDK=~/android-ndk-r21b 10 | fi 11 | 12 | if [ ! -d "$NDK" ]; then 13 | echo "Please set ANDROID_NDK environment to the root of NDK." 14 | exit 1 15 | fi 16 | 17 | function build() { 18 | API=$1 19 | ABI=$2 20 | TOOLCHAIN_ANME=$3 21 | BUILD_PATH=build.Android.${ABI} 22 | cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_BUILD_TYPE=${CONFIG} -DANDROID_ABI=${ABI} -H. -B${BUILD_PATH} -DCMAKE_TOOLCHAIN_FILE=${NDK}/build/cmake/android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=${API} -DANDROID_TOOLCHAIN=clang -DANDROID_TOOLCHAIN_NAME=${TOOLCHAIN_ANME} 23 | cmake --build ${BUILD_PATH} --config ${CONFIG} 24 | } 25 | 26 | build android-18 armeabi-v7a arm-linux-androideabi-4.9 27 | build android-18 arm64-v8a arm-linux-androideabi-clang 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 chexiongsheng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /nodejstest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Tencent is pleased to support the open source community by making xLua available. 2 | # Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | # Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 4 | # http://opensource.org/licenses/MIT 5 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 6 | 7 | cmake_minimum_required(VERSION 3.15) 8 | cmake_policy(SET CMP0091 NEW) 9 | 10 | project(embedtest) 11 | 12 | 13 | include_directories( 14 | ${CMAKE_SOURCE_DIR}/../src 15 | ${CMAKE_SOURCE_DIR}/../deps/v8/include 16 | ${CMAKE_SOURCE_DIR}/../deps/uv/include 17 | puerts/include 18 | ) 19 | 20 | add_executable(embedtest embedtest.cc 21 | puerts/src/CppObjectMapper.cpp 22 | puerts/src/DataTransfer.cpp 23 | puerts/src/JSClassRegister.cpp) 24 | 25 | #target_compile_definitions(embedtest PRIVATE MAPPER_ISOLATE_DATA_POS=2) 26 | 27 | target_link_libraries(embedtest ${CMAKE_SOURCE_DIR}/../out/Release/libnode.so.95) -------------------------------------------------------------------------------- /pesapitest/pesaddon/src/TestClass.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "Binding.hpp" 6 | 7 | class BaseClass 8 | { 9 | public: 10 | int A; 11 | int B; 12 | 13 | void Foo(int p); 14 | }; 15 | 16 | class TestClass : public BaseClass 17 | { 18 | public: 19 | int32_t X; 20 | int32_t Y; 21 | 22 | TestClass(); 23 | 24 | TestClass(int32_t InX, int32_t InY); 25 | 26 | static int32_t Add(int32_t a, int32_t b); 27 | 28 | static void Overload(); 29 | 30 | static void Overload(int32_t a); 31 | 32 | static void Overload(int32_t a, int32_t b); 33 | 34 | static void Overload(std::string a, int32_t b); 35 | 36 | int32_t OverloadMethod(); 37 | 38 | int32_t OverloadMethod(int32_t a); 39 | 40 | uint32_t OverloadMethod(uint32_t a); 41 | 42 | int64_t OverloadMethod(int64_t a); 43 | 44 | TestClass *GetSelf(); 45 | 46 | static void PrintInfo(TestClass *); 47 | 48 | int Ref(int32_t & a); 49 | 50 | void StrRef(std::string & str); 51 | 52 | int Ptr(int32_t * a); 53 | 54 | const char* CStr(const char* str); 55 | 56 | void StrPtr(std::string * str); 57 | 58 | void ConstRef(const int32_t & a); 59 | 60 | void VoidPtr(void* P){} 61 | 62 | int32_t IntArray[16]; 63 | 64 | static int StaticInt; 65 | 66 | static const float Ten; 67 | }; 68 | 69 | 70 | class AdvanceTestClass 71 | { 72 | public: 73 | AdvanceTestClass(int A); 74 | 75 | void JsObjectTest(puerts::Object Obj); 76 | 77 | void CallJsObjectTest(puerts::Function Func); 78 | 79 | void StdFunctionTest(std::function Func); 80 | }; 81 | 82 | -------------------------------------------------------------------------------- /puertstest/puerts/include/StdFunctionConverter.hpp: -------------------------------------------------------------------------------- 1 | template 2 | struct Converter> 3 | { 4 | static API::ValueType toScript(API::ContextType context, std::function value) 5 | { 6 | return API::GetUndefined(context); 7 | } 8 | 9 | static std::function toCpp(API::ContextType context, const API::ValueType value) 10 | { 11 | if (API::IsNullOrUndefined(context, value)) 12 | return nullptr; 13 | Function PF(context, value); 14 | return [=](Args... cppArgs) -> R { return PF.Func(cppArgs...); }; 15 | } 16 | 17 | static bool accept(API::ContextType context, const API::ValueType value) 18 | { 19 | return API::IsNullOrUndefined(context, value) || Converter::accept(context, value); 20 | } 21 | }; 22 | 23 | template 24 | struct Converter> 25 | { 26 | static API::ValueType toScript(API::ContextType context, std::function value) 27 | { 28 | return API::GetUndefined(context); 29 | } 30 | 31 | static std::function toCpp(API::ContextType context, const API::ValueType value) 32 | { 33 | if (API::IsNullOrUndefined(context, value)) 34 | return nullptr; 35 | Function PF(context, value); 36 | return [=](Args... cppArgs) -> void { PF.Action(cppArgs...); }; 37 | } 38 | 39 | static bool accept(API::ContextType context, const API::ValueType value) 40 | { 41 | return API::IsNullOrUndefined(context, value) || Converter::accept(context, value); 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /nodeaddon/hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Binding.hpp" 4 | #include "CppObjectMapper.h" 5 | 6 | class TestClass 7 | { 8 | public: 9 | TestClass(int p) { 10 | std::cout << "TestClass(" << p << ")" << std::endl; 11 | X = p; 12 | } 13 | 14 | static void Print(std::string msg) { 15 | std::cout << msg << std::endl; 16 | } 17 | 18 | int Add(int a, int b) 19 | { 20 | std::cout << "Add(" << a << "," << b << ")" << std::endl; 21 | return a + b; 22 | } 23 | 24 | int X; 25 | }; 26 | 27 | UsingCppType(TestClass); 28 | 29 | 30 | NODE_MODULE_INIT(/* exports, module, context */) { 31 | auto isolate = context->GetIsolate(); 32 | 33 | //TODO: 多addon有两个问题要解决,一个是目前注册JSClassRegister注册数据是放在静态变量,多addon每个addon一份并不共享,其次是FCppObjectMapper如何保持不冲突 34 | puerts::FCppObjectMapper *cppObjectMapper = new puerts::FCppObjectMapper(); 35 | cppObjectMapper->Initialize(isolate, context); 36 | isolate->SetData(MAPPER_ISOLATE_DATA_POS, static_cast(cppObjectMapper)); 37 | 38 | exports->Set(context, v8::String::NewFromUtf8(isolate, "loadCppType").ToLocalChecked(), v8::FunctionTemplate::New(isolate, [](const v8::FunctionCallbackInfo& info) 39 | { 40 | auto pom = static_cast((v8::Local::Cast(info.Data()))->Value()); 41 | pom->LoadCppType(info); 42 | }, v8::External::New(isolate, cppObjectMapper))->GetFunction(context).ToLocalChecked()).Check(); 43 | 44 | //这个初始化函数,前面都是固定的,从这开始和业务有关 45 | 46 | puerts::DefineClass() 47 | .Constructor() 48 | .Function("Print", MakeFunction(&TestClass::Print)) 49 | .Property("X", MakeProperty(&TestClass::X)) 50 | .Method("Add", MakeFunction(&TestClass::Add)) 51 | .Register(); 52 | } 53 | 54 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths: 7 | - puertstest/puerts/** 8 | - .github/workflows/ci.yml 9 | 10 | jobs: 11 | android: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Install NDK 17 | run: | 18 | cd ~ 19 | wget -O NDK -q https://dl.google.com/android/repository/android-ndk-r21b-linux-x86_64.zip 20 | sudo apt install unzip -y 21 | unzip -q NDK 22 | - name: Build 23 | run: | 24 | cd pesapitest/pesaddon 25 | chmod 777 make_android.sh 26 | ANDROID_NDK=~/android-ndk-r21b ./make_android.sh 27 | # ios: 28 | # runs-on: macos-10.15 29 | # 30 | # steps: 31 | # - uses: actions/checkout@v2 32 | # - name: Use Xcode 12.0 for x86 33 | # run: sudo xcode-select -switch "/Applications/Xcode_12.app" 34 | # - name: Build 35 | # run: | 36 | # cd pesapitest/pesaddon 37 | # sh ./make_ios.sh 38 | # - name: Upload 39 | # uses: actions/upload-artifact@v2 40 | # with: 41 | # path: ./unity/Assets/Plugins/**/* 42 | # name: Unity_Plugins_V8 43 | osx: 44 | runs-on: macos-14 45 | 46 | steps: 47 | - uses: actions/checkout@v2 48 | - name: Build 49 | run: | 50 | cd pesapitest/pesaddon 51 | sh ./make_osx.sh 52 | 53 | windows: 54 | runs-on: windows-2019 55 | 56 | steps: 57 | - uses: actions/checkout@v2 58 | - name: Build 59 | run: | 60 | cd pesapitest\pesaddon 61 | .\make_win64.bat 62 | 63 | linux64: 64 | runs-on: ubuntu-latest 65 | 66 | steps: 67 | - name: Install libc++-dev 68 | run: | 69 | sudo apt-get install clang 70 | sudo apt-get install libc++-dev 71 | sudo apt-get install libc++abi-dev 72 | - uses: actions/checkout@v2 73 | - name: Build 74 | run: | 75 | cd pesapitest/pesaddon 76 | mkdir build_linux64 77 | cd build_linux64 78 | cmake .. 79 | make 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # v8_embedding_test 2 | 3 | 《c++游戏服务器嵌入v8 js引擎胎教级教程》配套代码 4 | 5 | # !!! 注意:本示例库较老旧,正式生产使用,应到puerts官网取最新库代码: https://github.com/Tencent/puerts 6 | 7 | 测试环境:Ubuntu 8 | 9 | ## v8下载 10 | 11 | 下载puerts编译好的配套[v8库](https://github.com/puerts/backend-v8/releases/download/V8_9.4.146.24__241009/v8_bin_9.4.146.24.tgz) 12 | 13 | 解压到v8_embedding_test目录 14 | 15 | ## helloworld项目编译运行 16 | 17 | ~~~bash 18 | cd helloworld 19 | mkdir build 20 | cd build 21 | cmake .. 22 | make 23 | 24 | ./helloworld 25 | ~~~ 26 | 27 | ## puertstest项目编译运行 28 | 29 | ~~~bash 30 | cd puertstest 31 | mkdir build 32 | cd build 33 | cmake .. 34 | make 35 | 36 | ./helloworld 37 | ~~~ 38 | 39 | 40 | ## nodeaddon项目运行 41 | 42 | ~~~bash 43 | cd nodeaddon 44 | npm install . 45 | node hello.js 46 | ~~~ 47 | 48 | ## nodejstest项目运行 49 | 50 | 先编译libnode.so 51 | 52 | ~~~bash 53 | git clone git@github.com:nodejs/node.git 54 | cd node 55 | ./configure --shared 56 | make -j4 57 | ~~~ 58 | 59 | 拷贝nodejstest到node目录,拷贝puertstest/puerts目录到node/nodejstest目录 60 | 61 | ~~~bash 62 | cd nodejstest 63 | mkdir build 64 | cd build 65 | cmake .. 66 | make 67 | 68 | ./embedtest 69 | ~~~ 70 | 71 | ## pesapitest 72 | 73 | 由于动态库加载仅实现了window版本(见([PesapiAddonLoad.cpp]pesapitest/pesapiv8impl/src/PesapiAddonLoad.cpp)),所以只能在window下运行 74 | 75 | 编译 76 | ~~~bash 77 | cd pesapitest\pesv8app 78 | make_win64.bat 79 | ~~~ 80 | 81 | ~~~bash 82 | cd pesapitest\pesaddon 83 | make_win64.bat 84 | ~~~ 85 | 86 | 运行 87 | ~~~bash 88 | cd pesapitest\pesv8app 89 | build64_v8\Release\helloworld.exe 90 | ~~~ 91 | 92 | 输出 93 | ~~~bash 94 | wrap by hand begin 95 | Inc1024 96 | wrap by hand end 97 | Inc2048 98 | ~~~ 99 | 100 | ### 说明 101 | 102 | * pesapitest\pesaddon是一个pesapi的扩展(动态库),理论上可以在任意实现了pesapi的环境运行,可以仅依赖于纯c的头文件pesapi.h以根据该头文件生成的pesapi_adpt.c文件。如果需要用c++模板绑定,则依赖puerts相关头文件。 103 | 104 | * pesv8app是个可执行程序,其嵌入了v8,并基于v8实现了pesapi(见[PesapiV8Impl.cpp]pesapitest/pesapiv8impl/src/PesapiV8Impl.cpp)) 105 | 106 | * pesv8app通过pesapi_load_addon加载了dll,然后就可以通过loadCppType加载注册的类 107 | 108 | 109 | -------------------------------------------------------------------------------- /puertstest/puerts/include/CppObjectMapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #pragma warning(push, 0) 12 | #include "v8.h" 13 | #pragma warning(pop) 14 | 15 | #include 16 | #include "JSClassRegister.h" 17 | #include "ObjectCacheNode.h" 18 | #include "ObjectMapper.h" 19 | 20 | namespace puerts 21 | { 22 | class FCppObjectMapper final : public ICppObjectMapper 23 | { 24 | public: 25 | void Initialize(v8::Isolate* InIsolate, v8::Local InContext); 26 | 27 | void LoadCppType(const v8::FunctionCallbackInfo& Info); 28 | 29 | virtual bool IsInstanceOfCppObject(const void* TypeId, v8::Local JsObject) override; 30 | 31 | virtual std::weak_ptr GetJsEnvLifeCycleTracker() override; 32 | 33 | virtual v8::Local FindOrAddCppObject( 34 | v8::Isolate* Isolate, v8::Local& Context, const void* TypeId, void* Ptr, bool PassByPointer) override; 35 | 36 | virtual void UnBindCppObject(JSClassDefinition* ClassDefinition, void* Ptr) override; 37 | 38 | virtual void BindCppObject(v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr, v8::Local JSObject, 39 | bool PassByPointer) override; 40 | 41 | void UnInitialize(v8::Isolate* InIsolate); 42 | 43 | v8::Local GetTemplateOfClass(v8::Isolate* Isolate, const JSClassDefinition* ClassDefinition); 44 | 45 | private: 46 | std::map CDataCache; 47 | 48 | std::map> CDataNameToTemplateMap; 49 | 50 | v8::UniquePersistent PointerConstructor; 51 | 52 | std::map CDataFinalizeMap; 53 | 54 | std::shared_ptr Ref = std::make_shared(0); 55 | }; 56 | 57 | } // namespace puerts -------------------------------------------------------------------------------- /pesapitest/pesaddon/src/TestClass.cc: -------------------------------------------------------------------------------- 1 | #include "TestClass.h" 2 | #include "Object.hpp" 3 | 4 | void BaseClass::Foo(int p) 5 | { 6 | } 7 | 8 | TestClass::TestClass() 9 | { 10 | X = 0; 11 | Y = 0; 12 | } 13 | 14 | TestClass::TestClass(int32_t InX, int32_t InY) 15 | { 16 | X = InX; 17 | Y = InY; 18 | } 19 | 20 | int32_t TestClass::Add(int32_t a, int32_t b) 21 | { 22 | return a + b; 23 | } 24 | 25 | void TestClass::Overload() 26 | { 27 | } 28 | 29 | void TestClass::Overload(int32_t a) 30 | { 31 | } 32 | 33 | void TestClass::Overload(int32_t a, int32_t b) 34 | { 35 | } 36 | 37 | void TestClass::Overload(std::string a, int32_t b) 38 | { 39 | } 40 | 41 | 42 | int32_t TestClass::OverloadMethod() 43 | { 44 | return 0; 45 | } 46 | 47 | int32_t TestClass::OverloadMethod(int32_t a) 48 | { 49 | return 1; 50 | } 51 | 52 | uint32_t TestClass::OverloadMethod(uint32_t a) 53 | { 54 | return a; 55 | } 56 | 57 | int64_t TestClass::OverloadMethod(int64_t a) 58 | { 59 | return a; 60 | } 61 | 62 | TestClass * TestClass::GetSelf() 63 | { 64 | return this; 65 | } 66 | 67 | void TestClass::PrintInfo(TestClass * tc) 68 | { 69 | } 70 | 71 | 72 | int TestClass::Ref(int32_t & a) 73 | { 74 | ++a; 75 | return a + 1; 76 | } 77 | 78 | void TestClass::StrRef(std::string & str) 79 | { 80 | str += " append by c++"; 81 | } 82 | 83 | int TestClass::Ptr(int32_t * a) 84 | { 85 | ++(*a); 86 | return *a + 1; 87 | } 88 | 89 | const char* TestClass::CStr(const char* str) 90 | { 91 | return "hehe.."; 92 | } 93 | 94 | void TestClass::StrPtr(std::string * str) 95 | { 96 | *str += " append by c++"; 97 | } 98 | 99 | void TestClass::ConstRef(const int32_t & a) 100 | { 101 | } 102 | 103 | int TestClass::StaticInt = 0; 104 | 105 | const float TestClass::Ten = 10; 106 | 107 | 108 | AdvanceTestClass::AdvanceTestClass(int A) 109 | { 110 | } 111 | 112 | void AdvanceTestClass::JsObjectTest(puerts::Object Obj) 113 | { 114 | auto P = Obj.Get("p"); 115 | Obj.Set("q", "john"); 116 | } 117 | 118 | void AdvanceTestClass::CallJsObjectTest(puerts::Function Func) 119 | { 120 | auto Ret = Func.Func(1024, "che"); 121 | } 122 | 123 | void AdvanceTestClass::StdFunctionTest(std::function Func) 124 | { 125 | int Ret = Func(88, 99); 126 | } 127 | -------------------------------------------------------------------------------- /puertstest/puerts/include/Object.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #if BUILDING_PES_EXTENSION 12 | #include "PesapiObject.hpp" 13 | #else 14 | #include "V8Object.hpp" 15 | #endif 16 | 17 | namespace puerts 18 | { 19 | namespace internal 20 | { 21 | constexpr std::size_t NumDigits(std::size_t n) 22 | { 23 | return n < 10 ? 1 : NumDigits(n / 10) + 1; 24 | } 25 | 26 | template 27 | struct CharList 28 | { 29 | const char Str[sizeof...(Chars)] = {Chars...}; 30 | }; 31 | 32 | template 33 | struct SI2A 34 | { 35 | using type = typename SI2A::type; 36 | }; 37 | 38 | template 39 | struct SI2A<1, N, Chars...> 40 | { 41 | using type = CharList<'0' + N, Chars..., '\0'>; 42 | }; 43 | 44 | template 45 | using SI2A_T = typename SI2A::type; 46 | 47 | template 48 | struct ParamsDecl 49 | { 50 | }; 51 | 52 | template 53 | struct ParamsDecl 54 | { 55 | static constexpr auto Get() 56 | { 57 | return ParamsDecl::Get() + Literal(", ") + ParamsDecl::Get(); 58 | } 59 | }; 60 | 61 | template 62 | struct ParamsDecl 63 | { 64 | static constexpr auto Get() 65 | { 66 | return Literal("p") + Literal(SI2A_T().Str) + Literal(":") + ScriptTypeNameWithNamespace::value(); 67 | } 68 | }; 69 | 70 | template 71 | struct ParamsDecl 72 | { 73 | static constexpr auto Get() 74 | { 75 | return Literal(""); 76 | } 77 | }; 78 | 79 | } // namespace internal 80 | 81 | template 82 | struct ScriptTypeName> 83 | { 84 | static constexpr auto value() 85 | { 86 | return internal::Literal("(") + internal::ParamsDecl<0, Args...>::Get() + internal::Literal(") => ") + 87 | ScriptTypeNameWithNamespace::value(); 88 | } 89 | }; 90 | 91 | } // namespace puerts 92 | -------------------------------------------------------------------------------- /snapshottest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD" CACHE STRING "") 4 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MDd" CACHE STRING "") 5 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD" CACHE STRING "") 6 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd" CACHE STRING "") 7 | 8 | 9 | project(SnapshotTest) 10 | 11 | set (CMAKE_CXX_STANDARD 14) 12 | 13 | 14 | set(JS_ENGINE_ROOT ${CMAKE_SOURCE_DIR}/../v8) 15 | 16 | include_directories( 17 | ${JS_ENGINE_ROOT}/Inc 18 | ) 19 | 20 | set ( SRC hello-world.cc) 21 | 22 | add_executable(snapshottest ${SRC}) 23 | 24 | set (LIB_NAME wee8) 25 | 26 | if ( ANDROID ) 27 | find_library(log-lib log ) 28 | 29 | if( ANDROID_ABI STREQUAL "armeabi-v7a") 30 | target_link_libraries(snapshottest 31 | ${JS_ENGINE_ROOT}/Lib/Android/armv7/lib${LIB_NAME}.a 32 | ${log-lib} 33 | ) 34 | target_compile_definitions (snapshottest PRIVATE PLATFORM_ANDROID_ARM) 35 | else ( ) 36 | target_link_libraries(snapshottest 37 | ${JS_ENGINE_ROOT}/Lib/Android/arm64/lib${LIB_NAME}.a 38 | ${log-lib} 39 | ) 40 | target_compile_definitions (snapshottest PRIVATE PLATFORM_ANDROID_ARM64) 41 | endif ( ) 42 | elseif ( APPLE ) 43 | if (IOS) 44 | target_link_libraries(snapshottest 45 | ${JS_ENGINE_ROOT}/Lib/iOS/lib${LIB_NAME}.a 46 | ) 47 | target_compile_definitions (snapshottest PRIVATE PLATFORM_IOS) 48 | else () 49 | target_link_libraries(snapshottest 50 | ${JS_ENGINE_ROOT}/Lib/macOS/lib${LIB_NAME}.a 51 | ) 52 | target_compile_definitions (snapshottest PRIVATE PLATFORM_MAC) 53 | endif ( ) 54 | elseif (UNIX) 55 | target_link_libraries(snapshottest 56 | ${JS_ENGINE_ROOT}/Lib/Linux/lib${LIB_NAME}.a 57 | pthread 58 | ) 59 | target_compile_definitions (snapshottest PRIVATE PLATFORM_LINUX) 60 | set(CMAKE_CXX_COMPILER "clang++") 61 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 62 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi") 63 | else () 64 | if ( JS_ENGINE STREQUAL "v8") 65 | set(LIBS_NEEDED winmm.lib dbghelp.lib shlwapi.lib) 66 | endif() 67 | if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") 68 | target_link_libraries(snapshottest 69 | ${JS_ENGINE_ROOT}/Lib/Win32/${LIB_NAME}.lib 70 | ${LIBS_NEEDED} 71 | ) 72 | else () 73 | target_link_libraries(snapshottest 74 | ${JS_ENGINE_ROOT}/Lib/Win64/${LIB_NAME}.lib 75 | ${LIBS_NEEDED} 76 | ) 77 | endif () 78 | target_compile_definitions (snapshottest PRIVATE PLATFORM_WINDOWS) 79 | endif ( ) 80 | -------------------------------------------------------------------------------- /helloworld/hello-world.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "libplatform/libplatform.h" 14 | #include "v8.h" 15 | 16 | static void Print(const v8::FunctionCallbackInfo& info) { 17 | v8::Isolate* isolate = info.GetIsolate(); 18 | v8::Local context = isolate->GetCurrentContext(); 19 | 20 | std::string msg = *(v8::String::Utf8Value(isolate, info[0]->ToString(context).ToLocalChecked())); 21 | std::cout << msg << std::endl; 22 | } 23 | 24 | int main(int argc, char* argv[]) { 25 | // Initialize V8. 26 | std::unique_ptr platform = v8::platform::NewDefaultPlatform(); 27 | v8::V8::InitializePlatform(platform.get()); 28 | v8::V8::Initialize(); 29 | 30 | // Create a new Isolate and make it the current one. 31 | v8::Isolate::CreateParams create_params; 32 | create_params.array_buffer_allocator = 33 | v8::ArrayBuffer::Allocator::NewDefaultAllocator(); 34 | v8::Isolate* isolate = v8::Isolate::New(create_params); 35 | { 36 | v8::Isolate::Scope isolate_scope(isolate); 37 | 38 | // Create a stack-allocated handle scope. 39 | v8::HandleScope handle_scope(isolate); 40 | 41 | // Create a new context. 42 | v8::Local context = v8::Context::New(isolate); 43 | 44 | // Enter the context for compiling and running the hello world script. 45 | v8::Context::Scope context_scope(context); 46 | 47 | context->Global()->Set(context, v8::String::NewFromUtf8(isolate, "Print").ToLocalChecked(), 48 | v8::FunctionTemplate::New(isolate, Print)->GetFunction(context).ToLocalChecked()) 49 | .Check(); 50 | 51 | 52 | { 53 | const char* csource = R"( 54 | Print('hello world'); 55 | )"; 56 | 57 | // Create a string containing the JavaScript source code. 58 | v8::Local source = 59 | v8::String::NewFromUtf8(isolate, csource) 60 | .ToLocalChecked(); 61 | 62 | // Compile the source code. 63 | v8::Local script = 64 | v8::Script::Compile(context, source).ToLocalChecked(); 65 | 66 | // Run the script 67 | auto _unused = script->Run(context); 68 | } 69 | 70 | } 71 | 72 | // Dispose the isolate and tear down V8. 73 | isolate->Dispose(); 74 | v8::V8::Dispose(); 75 | v8::V8::ShutdownPlatform(); 76 | delete create_params.array_buffer_allocator; 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /puertstest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | if ( WIN32 AND NOT CYGWIN AND NOT ( CMAKE_SYSTEM_NAME STREQUAL "WindowsStore" ) AND NOT ANDROID) 4 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT" CACHE STRING "") 5 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd" CACHE STRING "") 6 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT" CACHE STRING "") 7 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd" CACHE STRING "") 8 | endif () 9 | 10 | project(Helloworld) 11 | 12 | set (CMAKE_CXX_STANDARD 14) 13 | 14 | 15 | set(JS_ENGINE_ROOT ${CMAKE_SOURCE_DIR}/../v8) 16 | 17 | include_directories( 18 | ${JS_ENGINE_ROOT}/Inc 19 | puerts/include 20 | ) 21 | 22 | set ( SRC hello-world.cc 23 | puerts/src/CppObjectMapper.cpp 24 | puerts/src/DataTransfer.cpp 25 | puerts/src/JSClassRegister.cpp 26 | ) 27 | 28 | add_executable(helloworld ${SRC}) 29 | 30 | set (LIB_NAME wee8) 31 | 32 | if ( ANDROID ) 33 | find_library(log-lib log ) 34 | 35 | if( ANDROID_ABI STREQUAL "armeabi-v7a") 36 | target_link_libraries(helloworld 37 | ${JS_ENGINE_ROOT}/Lib/Android/armv7/lib${LIB_NAME}.a 38 | ${log-lib} 39 | ) 40 | target_compile_definitions (helloworld PRIVATE PLATFORM_ANDROID_ARM) 41 | else ( ) 42 | target_link_libraries(helloworld 43 | ${JS_ENGINE_ROOT}/Lib/Android/arm64/lib${LIB_NAME}.a 44 | ${log-lib} 45 | ) 46 | target_compile_definitions (helloworld PRIVATE PLATFORM_ANDROID_ARM64) 47 | endif ( ) 48 | elseif ( APPLE ) 49 | if (IOS) 50 | target_link_libraries(helloworld 51 | ${JS_ENGINE_ROOT}/Lib/iOS/lib${LIB_NAME}.a 52 | ) 53 | target_compile_definitions (helloworld PRIVATE PLATFORM_IOS) 54 | else () 55 | target_link_libraries(helloworld 56 | ${JS_ENGINE_ROOT}/Lib/macOS/lib${LIB_NAME}.a 57 | ) 58 | target_compile_definitions (helloworld PRIVATE PLATFORM_MAC) 59 | endif ( ) 60 | elseif (UNIX) 61 | target_link_libraries(helloworld 62 | ${JS_ENGINE_ROOT}/Lib/Linux/lib${LIB_NAME}.a 63 | pthread 64 | ) 65 | target_compile_definitions (helloworld PRIVATE PLATFORM_LINUX) 66 | set(CMAKE_CXX_COMPILER "clang++") 67 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 68 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi") 69 | else () 70 | if ( JS_ENGINE STREQUAL "v8") 71 | set(LIBS_NEEDED winmm.lib dbghelp.lib shlwapi.lib) 72 | endif() 73 | if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") 74 | target_link_libraries(hello-world 75 | ${JS_ENGINE_ROOT}/Lib/Win32/${LIB_NAME}.lib 76 | ${LIBS_NEEDED} 77 | ) 78 | else () 79 | target_link_libraries(helloworld 80 | ${JS_ENGINE_ROOT}/Lib/Win64/${LIB_NAME}.lib 81 | ${LIBS_NEEDED} 82 | ) 83 | endif () 84 | target_compile_definitions (helloworld PRIVATE PLATFORM_WINDOWS) 85 | endif ( ) 86 | -------------------------------------------------------------------------------- /helloworld/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | if ( WIN32 AND NOT CYGWIN AND NOT ( CMAKE_SYSTEM_NAME STREQUAL "WindowsStore" ) AND NOT ANDROID) 4 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT" CACHE STRING "") 5 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd" CACHE STRING "") 6 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT" CACHE STRING "") 7 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd" CACHE STRING "") 8 | endif () 9 | 10 | project(Helloworld) 11 | 12 | set (CMAKE_CXX_STANDARD 14) 13 | 14 | if ( NOT DEFINED JS_ENGINE ) 15 | set(JS_ENGINE v8) 16 | endif() 17 | 18 | set(JS_ENGINE_ROOT ${CMAKE_SOURCE_DIR}/../${JS_ENGINE}) 19 | 20 | include_directories( 21 | ${JS_ENGINE_ROOT}/Inc 22 | ) 23 | 24 | set ( SRC hello-world.cc) 25 | 26 | add_executable(helloworld ${SRC}) 27 | 28 | if ( JS_ENGINE STREQUAL "v8") 29 | set (LIB_NAME wee8) 30 | elseif ( JS_ENGINE STREQUAL "quickjs") 31 | set (LIB_NAME quickjs) 32 | endif () 33 | 34 | if ( ANDROID ) 35 | find_library(log-lib log ) 36 | 37 | if( ANDROID_ABI STREQUAL "armeabi-v7a") 38 | target_link_libraries(helloworld 39 | ${JS_ENGINE_ROOT}/Lib/Android/armv7/lib${LIB_NAME}.a 40 | ${log-lib} 41 | ) 42 | target_compile_definitions (helloworld PRIVATE PLATFORM_ANDROID_ARM) 43 | else ( ) 44 | target_link_libraries(helloworld 45 | ${JS_ENGINE_ROOT}/Lib/Android/arm64/lib${LIB_NAME}.a 46 | ${log-lib} 47 | ) 48 | target_compile_definitions (helloworld PRIVATE PLATFORM_ANDROID_ARM64) 49 | endif ( ) 50 | elseif ( APPLE ) 51 | if (IOS) 52 | target_link_libraries(helloworld 53 | ${JS_ENGINE_ROOT}/Lib/iOS/lib${LIB_NAME}.a 54 | ) 55 | target_compile_definitions (helloworld PRIVATE PLATFORM_IOS) 56 | else () 57 | target_link_libraries(helloworld 58 | ${JS_ENGINE_ROOT}/Lib/macOS/lib${LIB_NAME}.a 59 | ) 60 | target_compile_definitions (helloworld PRIVATE PLATFORM_MAC) 61 | endif ( ) 62 | elseif (UNIX) 63 | target_link_libraries(helloworld 64 | ${JS_ENGINE_ROOT}/Lib/Linux/lib${LIB_NAME}.a 65 | pthread 66 | ) 67 | target_compile_definitions (helloworld PRIVATE PLATFORM_LINUX) 68 | set(CMAKE_CXX_COMPILER "clang++") 69 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 70 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi") 71 | else () 72 | if ( JS_ENGINE STREQUAL "v8") 73 | set(LIBS_NEEDED winmm.lib dbghelp.lib shlwapi.lib) 74 | endif() 75 | if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") 76 | target_link_libraries(hello-world 77 | ${JS_ENGINE_ROOT}/Lib/Win32/${LIB_NAME}.lib 78 | ${LIBS_NEEDED} 79 | ) 80 | else () 81 | target_link_libraries(helloworld 82 | ${JS_ENGINE_ROOT}/Lib/Win64/${LIB_NAME}.lib 83 | ${LIBS_NEEDED} 84 | ) 85 | endif () 86 | target_compile_definitions (helloworld PRIVATE PLATFORM_WINDOWS) 87 | endif ( ) 88 | -------------------------------------------------------------------------------- /puertstest/puerts/src/DataTransfer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #include "DataTransfer.h" 10 | #include "ObjectMapper.h" 11 | #if USING_IN_UNREAL_ENGINE 12 | #include "V8Utils.h" 13 | #endif 14 | 15 | namespace puerts 16 | { 17 | v8::Local DataTransfer::FindOrAddCData( 18 | v8::Isolate* Isolate, v8::Local Context, const void* TypeId, const void* Ptr, bool PassByPointer) 19 | { 20 | return IsolateData(Isolate)->FindOrAddCppObject( 21 | Isolate, Context, TypeId, const_cast(Ptr), PassByPointer); 22 | } 23 | 24 | bool DataTransfer::IsInstanceOf(v8::Isolate* Isolate, const void* TypeId, v8::Local JsObject) 25 | { 26 | return IsolateData(Isolate)->IsInstanceOfCppObject(TypeId, JsObject); 27 | } 28 | 29 | v8::Local DataTransfer::UnRef(v8::Isolate* Isolate, const v8::Local& Value) 30 | { 31 | v8::Local Context = Isolate->GetCurrentContext(); 32 | v8::Local ReturnValue = Value->ToObject(Context).ToLocalChecked()->Get(Context, 0).ToLocalChecked(); 33 | 34 | return ReturnValue; 35 | } 36 | 37 | void DataTransfer::UpdateRef(v8::Isolate* Isolate, v8::Local Outer, const v8::Local& Value) 38 | { 39 | v8::Local Context = Isolate->GetCurrentContext(); 40 | 41 | auto Ret = Outer->ToObject(Context).ToLocalChecked()->Set(Context, 0, Value); 42 | } 43 | 44 | std::weak_ptr DataTransfer::GetJsEnvLifeCycleTracker(v8::Isolate* Isolate) 45 | { 46 | return IsolateData(Isolate)->GetJsEnvLifeCycleTracker(); 47 | } 48 | 49 | #if USING_IN_UNREAL_ENGINE 50 | FString DataTransfer::ToFString(v8::Isolate* Isolate, v8::Local Value) 51 | { 52 | return FV8Utils::ToFString(Isolate, Value); 53 | } 54 | 55 | v8::Local DataTransfer::FindOrAddObject( 56 | v8::Isolate* Isolate, v8::Local& Context, UClass* Class, UObject* UEObject) 57 | { 58 | return FV8Utils::IsolateData(Isolate)->FindOrAdd(Isolate, Context, Class, UEObject); 59 | } 60 | 61 | v8::Local DataTransfer::FindOrAddStruct( 62 | v8::Isolate* Isolate, v8::Local Context, UScriptStruct* ScriptStruct, void* Ptr, bool PassByPointer) 63 | { 64 | return FV8Utils::IsolateData(Isolate)->FindOrAddStruct(Isolate, Context, ScriptStruct, Ptr, PassByPointer); 65 | } 66 | 67 | bool DataTransfer::IsInstanceOf(v8::Isolate* Isolate, UStruct* Struct, v8::Local JsObject) 68 | { 69 | return FV8Utils::IsolateData(Isolate)->IsInstanceOf(Struct, JsObject); 70 | } 71 | 72 | void DataTransfer::ThrowException(v8::Isolate* Isolate, const char* Message) 73 | { 74 | FV8Utils::ThrowException(Isolate, Message); 75 | } 76 | #endif 77 | } // namespace puerts 78 | -------------------------------------------------------------------------------- /pesapitest/pesv8app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | if ( WIN32 AND NOT CYGWIN AND NOT ( CMAKE_SYSTEM_NAME STREQUAL "WindowsStore" ) AND NOT ANDROID) 4 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT" CACHE STRING "") 5 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd" CACHE STRING "") 6 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT" CACHE STRING "") 7 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd" CACHE STRING "") 8 | endif () 9 | 10 | project(Helloworld) 11 | 12 | set (CMAKE_CXX_STANDARD 14) 13 | 14 | 15 | set(JS_ENGINE_ROOT ${CMAKE_SOURCE_DIR}/../../v8) 16 | 17 | set(PUERTS_LIB_ROOT ../../puertstest/puerts) 18 | set(PUERTS_INCLUDE ${PUERTS_LIB_ROOT}/include) 19 | set(PUERTS_SRC 20 | ${PUERTS_LIB_ROOT}/src/CppObjectMapper.cpp 21 | ${PUERTS_LIB_ROOT}/src/DataTransfer.cpp 22 | ${PUERTS_LIB_ROOT}/src/JSClassRegister.cpp 23 | ) 24 | 25 | set(PESAPI_ROOT ../pesapiv8impl) 26 | 27 | set(PESAPI_INCLUDE ${PESAPI_ROOT}/include) 28 | set(PESAPI_SRC 29 | ${PESAPI_ROOT}/src/PesapiV8Impl.cpp 30 | ${PESAPI_ROOT}/src/PesapiAddonLoad.cpp 31 | ) 32 | 33 | include_directories( 34 | ${JS_ENGINE_ROOT}/Inc 35 | ${PUERTS_INCLUDE} 36 | ${PESAPI_INCLUDE} 37 | ) 38 | 39 | set ( SRC hello-world.cc ${PUERTS_SRC} ${PESAPI_SRC}) 40 | 41 | add_executable(helloworld ${SRC}) 42 | 43 | set (LIB_NAME wee8) 44 | 45 | if ( ANDROID ) 46 | find_library(log-lib log ) 47 | 48 | if( ANDROID_ABI STREQUAL "armeabi-v7a") 49 | target_link_libraries(helloworld 50 | ${JS_ENGINE_ROOT}/Lib/Android/armv7/lib${LIB_NAME}.a 51 | ${log-lib} 52 | ) 53 | target_compile_definitions (helloworld PRIVATE PLATFORM_ANDROID_ARM) 54 | else ( ) 55 | target_link_libraries(helloworld 56 | ${JS_ENGINE_ROOT}/Lib/Android/arm64/lib${LIB_NAME}.a 57 | ${log-lib} 58 | ) 59 | target_compile_definitions (helloworld PRIVATE PLATFORM_ANDROID_ARM64) 60 | endif ( ) 61 | elseif ( APPLE ) 62 | if (IOS) 63 | target_link_libraries(helloworld 64 | ${JS_ENGINE_ROOT}/Lib/iOS/lib${LIB_NAME}.a 65 | ) 66 | target_compile_definitions (helloworld PRIVATE PLATFORM_IOS) 67 | else () 68 | target_link_libraries(helloworld 69 | ${JS_ENGINE_ROOT}/Lib/macOS/lib${LIB_NAME}.a 70 | ) 71 | target_compile_definitions (helloworld PRIVATE PLATFORM_MAC) 72 | endif ( ) 73 | elseif (UNIX) 74 | target_link_libraries(helloworld 75 | ${JS_ENGINE_ROOT}/Lib/Linux/lib${LIB_NAME}.a 76 | pthread 77 | ) 78 | target_compile_definitions (helloworld PRIVATE PLATFORM_LINUX) 79 | set(CMAKE_CXX_COMPILER "clang++") 80 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 81 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi") 82 | else () 83 | if ( JS_ENGINE STREQUAL "v8") 84 | set(LIBS_NEEDED winmm.lib dbghelp.lib shlwapi.lib) 85 | endif() 86 | if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") 87 | target_link_libraries(hello-world 88 | ${JS_ENGINE_ROOT}/Lib/Win32/${LIB_NAME}.lib 89 | ${LIBS_NEEDED} 90 | ) 91 | else () 92 | target_link_libraries(helloworld 93 | ${JS_ENGINE_ROOT}/Lib/Win64/${LIB_NAME}.lib 94 | ${LIBS_NEEDED} 95 | ) 96 | endif () 97 | target_compile_definitions (helloworld PRIVATE PLATFORM_WINDOWS) 98 | endif ( ) 99 | -------------------------------------------------------------------------------- /pesapitest/pesv8app/hello-world.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include "DataTransfer.h" 15 | #include "CppObjectMapper.h" 16 | 17 | #include "libplatform/libplatform.h" 18 | #include "v8.h" 19 | 20 | int main(int argc, char* argv[]) { 21 | // Initialize V8. 22 | std::unique_ptr platform = v8::platform::NewDefaultPlatform(); 23 | v8::V8::InitializePlatform(platform.get()); 24 | v8::V8::Initialize(); 25 | 26 | // Create a new Isolate and make it the current one. 27 | v8::Isolate::CreateParams create_params; 28 | create_params.array_buffer_allocator = 29 | v8::ArrayBuffer::Allocator::NewDefaultAllocator(); 30 | v8::Isolate* isolate = v8::Isolate::New(create_params); 31 | 32 | puerts::FCppObjectMapper cppObjectMapper; 33 | { 34 | v8::Isolate::Scope isolate_scope(isolate); 35 | 36 | // Create a stack-allocated handle scope. 37 | v8::HandleScope handle_scope(isolate); 38 | 39 | // Create a new context. 40 | v8::Local context = v8::Context::New(isolate); 41 | 42 | // Enter the context for compiling and running the hello world script. 43 | v8::Context::Scope context_scope(context); 44 | 45 | cppObjectMapper.Initialize(isolate, context); 46 | isolate->SetData(MAPPER_ISOLATE_DATA_POS, static_cast(&cppObjectMapper)); 47 | 48 | context->Global()->Set(context, v8::String::NewFromUtf8(isolate, "loadCppType").ToLocalChecked(), v8::FunctionTemplate::New(isolate, [](const v8::FunctionCallbackInfo& info) 49 | { 50 | auto pom = static_cast((v8::Local::Cast(info.Data()))->Value()); 51 | pom->LoadCppType(info); 52 | }, v8::External::New(isolate, &cppObjectMapper))->GetFunction(context).ToLocalChecked()).Check(); 53 | 54 | #if defined(PLATFORM_WINDOWS) 55 | pesapi_load_addon("..\\pesaddon\\build64\\Release\\hello.dll", "hello"); 56 | #endif 57 | { 58 | const char* csource = R"( 59 | const TestClass11 = loadCppType('TestClass11'); 60 | const TestClass22 = loadCppType('TestClass22'); 61 | 62 | TestClass11.Inc(1024); 63 | TestClass22.Inc(2048); 64 | )"; 65 | 66 | // Create a string containing the JavaScript source code. 67 | v8::Local source = 68 | v8::String::NewFromUtf8(isolate, csource) 69 | .ToLocalChecked(); 70 | 71 | // Compile the source code. 72 | v8::Local script = 73 | v8::Script::Compile(context, source).ToLocalChecked(); 74 | 75 | // Run the script 76 | auto _unused = script->Run(context); 77 | } 78 | 79 | cppObjectMapper.UnInitialize(isolate); 80 | 81 | } 82 | 83 | // Dispose the isolate and tear down V8. 84 | isolate->Dispose(); 85 | v8::V8::Dispose(); 86 | v8::V8::ShutdownPlatform(); 87 | delete create_params.array_buffer_allocator; 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /puertstest/puerts/include/ObjectCacheNode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #pragma warning(push, 0) 12 | #include "v8.h" 13 | #pragma warning(pop) 14 | 15 | namespace puerts 16 | { 17 | class FObjectCacheNode 18 | { 19 | public: 20 | V8_INLINE FObjectCacheNode(const void* TypeId_) : TypeId(TypeId_), Next(nullptr) 21 | { 22 | } 23 | 24 | V8_INLINE FObjectCacheNode(const void* TypeId_, FObjectCacheNode* Next_) : TypeId(TypeId_), Next(Next_) 25 | { 26 | } 27 | 28 | V8_INLINE FObjectCacheNode(FObjectCacheNode&& other) noexcept 29 | : TypeId(other.TypeId), Next(other.Next), Value(std::move(other.Value)) 30 | { 31 | other.TypeId = nullptr; 32 | other.Next = nullptr; 33 | } 34 | 35 | V8_INLINE FObjectCacheNode& operator=(FObjectCacheNode&& rhs) noexcept 36 | { 37 | TypeId = rhs.TypeId; 38 | Next = rhs.Next; 39 | Value = std::move(rhs.Value); 40 | rhs.TypeId = nullptr; 41 | rhs.Next = nullptr; 42 | return *this; 43 | } 44 | 45 | V8_INLINE ~FObjectCacheNode() 46 | { 47 | if (Next) 48 | delete Next; 49 | } 50 | 51 | V8_INLINE FObjectCacheNode* Find(const void* TypeId_) 52 | { 53 | if (TypeId_ == TypeId) 54 | { 55 | return this; 56 | } 57 | if (Next) 58 | { 59 | return Next->Find(TypeId_); 60 | } 61 | return nullptr; 62 | } 63 | 64 | V8_INLINE FObjectCacheNode* Remove(const void* TypeId_, bool IsHead) 65 | { 66 | if (TypeId_ == TypeId) 67 | { 68 | if (IsHead) 69 | { 70 | if (Next) 71 | { 72 | auto PreNext = Next; 73 | *this = std::move(*Next); 74 | delete PreNext; 75 | } 76 | else 77 | { 78 | TypeId = nullptr; 79 | Next = nullptr; 80 | Value.Reset(); 81 | } 82 | } 83 | return this; 84 | } 85 | if (Next) 86 | { 87 | auto Removed = Next->Remove(TypeId_, false); 88 | if (Removed && Removed == Next) // detach & delete by prev node 89 | { 90 | Next = Removed->Next; 91 | Removed->Next = nullptr; 92 | delete Removed; 93 | } 94 | return Removed; 95 | } 96 | return nullptr; 97 | } 98 | 99 | V8_INLINE FObjectCacheNode* Add(const void* TypeId_) 100 | { 101 | Next = new FObjectCacheNode(TypeId_, Next); 102 | return Next; 103 | } 104 | 105 | const void* TypeId; 106 | 107 | FObjectCacheNode* Next; 108 | 109 | v8::UniquePersistent Value; 110 | 111 | FObjectCacheNode(const FObjectCacheNode&) = delete; 112 | void operator=(const FObjectCacheNode&) = delete; 113 | }; 114 | 115 | } // namespace puerts 116 | -------------------------------------------------------------------------------- /puertstest/puerts/include/JSClassRegister.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "functional" 12 | 13 | #if USING_IN_UNREAL_ENGINE 14 | #include "CoreMinimal.h" 15 | #else 16 | #define JSENV_API 17 | #define FORCEINLINE V8_INLINE 18 | #define UPTRINT uintptr_t 19 | #endif 20 | 21 | #include 22 | 23 | #pragma warning(push, 0) 24 | #include "v8.h" 25 | #pragma warning(pop) 26 | 27 | #include "TypeInfo.hpp" 28 | 29 | namespace puerts 30 | { 31 | struct JSENV_API JSFunctionInfo 32 | { 33 | const char* Name; 34 | v8::FunctionCallback Callback; 35 | void* Data = nullptr; 36 | const CFunctionInfo* ReflectionInfo = nullptr; 37 | }; 38 | 39 | struct JSENV_API JSPropertyInfo 40 | { 41 | const char* Name; 42 | v8::FunctionCallback Getter; 43 | v8::FunctionCallback Setter; 44 | void* Data = nullptr; 45 | }; 46 | 47 | typedef void (*FinalizeFunc)(void* Ptr); 48 | 49 | typedef void* (*InitializeFunc)(const v8::FunctionCallbackInfo& Info); 50 | 51 | struct NamedFunctionInfo 52 | { 53 | const char* Name; 54 | const CFunctionInfo* Type; 55 | }; 56 | 57 | struct NamedPropertyInfo 58 | { 59 | const char* Name; 60 | const CTypeInfo* Type; 61 | }; 62 | 63 | struct JSENV_API JSClassDefinition 64 | { 65 | const void* TypeId; 66 | const void* SuperTypeId; 67 | const char* ScriptName; 68 | const char* UETypeName; 69 | InitializeFunc Initialize; 70 | JSFunctionInfo* Methods; //成员方法 71 | JSFunctionInfo* Functions; //静态方法 72 | JSPropertyInfo* Properties; //成员属性 73 | JSPropertyInfo* Variables; //静态属性 74 | FinalizeFunc Finalize; 75 | // int InternalFieldCount; 76 | NamedFunctionInfo* ConstructorInfos; 77 | NamedFunctionInfo* MethodInfos; 78 | NamedFunctionInfo* FunctionInfos; 79 | NamedPropertyInfo* PropertyInfos; 80 | NamedPropertyInfo* VariableInfos; 81 | void* Data = nullptr; 82 | }; 83 | 84 | #define JSClassEmptyDefinition \ 85 | { \ 86 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ 87 | } 88 | 89 | void JSENV_API RegisterJSClass(const JSClassDefinition& ClassDefinition); 90 | 91 | void JSENV_API ForeachRegisterClass(std::function); 92 | 93 | JSENV_API const JSClassDefinition* FindClassByID(const void* TypeId); 94 | 95 | const JSClassDefinition* FindCppTypeClassByName(const std::string& Name); 96 | 97 | typedef void (*AddonRegisterFunc)(v8::Local Context, v8::Local Exports); 98 | 99 | AddonRegisterFunc FindAddonRegisterFunc(const std::string& Name); 100 | 101 | void RegisterAddon(const char* Name, AddonRegisterFunc RegisterFunc); 102 | 103 | #if USING_IN_UNREAL_ENGINE 104 | JSENV_API const JSClassDefinition* FindClassByType(UStruct* Type); 105 | #endif 106 | 107 | } // namespace puerts 108 | 109 | #define PUERTS_MODULE(Name, RegFunc) \ 110 | static struct FAutoRegisterFor##Name \ 111 | { \ 112 | FAutoRegisterFor##Name() \ 113 | { \ 114 | puerts::RegisterAddon(#Name, (RegFunc)); \ 115 | } \ 116 | } _AutoRegisterFor##Name 117 | -------------------------------------------------------------------------------- /puertstest/hello-world.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Binding.hpp" 14 | #include "CppObjectMapper.h" 15 | 16 | #include "libplatform/libplatform.h" 17 | #include "v8.h" 18 | 19 | class TestClass 20 | { 21 | public: 22 | TestClass(int p) { 23 | std::cout << "TestClass(" << p << ")" << std::endl; 24 | X = p; 25 | } 26 | 27 | static void Print(std::string msg) { 28 | std::cout << msg << std::endl; 29 | } 30 | 31 | int Add(int a, int b) 32 | { 33 | std::cout << "Add(" << a << "," << b << ")" << std::endl; 34 | return a + b; 35 | } 36 | 37 | int X; 38 | }; 39 | 40 | UsingCppType(TestClass); 41 | 42 | 43 | int main(int argc, char* argv[]) { 44 | // Initialize V8. 45 | std::unique_ptr platform = v8::platform::NewDefaultPlatform(); 46 | v8::V8::InitializePlatform(platform.get()); 47 | v8::V8::Initialize(); 48 | 49 | // Create a new Isolate and make it the current one. 50 | v8::Isolate::CreateParams create_params; 51 | create_params.array_buffer_allocator = 52 | v8::ArrayBuffer::Allocator::NewDefaultAllocator(); 53 | v8::Isolate* isolate = v8::Isolate::New(create_params); 54 | 55 | puerts::FCppObjectMapper cppObjectMapper; 56 | { 57 | v8::Isolate::Scope isolate_scope(isolate); 58 | 59 | // Create a stack-allocated handle scope. 60 | v8::HandleScope handle_scope(isolate); 61 | 62 | // Create a new context. 63 | v8::Local context = v8::Context::New(isolate); 64 | 65 | // Enter the context for compiling and running the hello world script. 66 | v8::Context::Scope context_scope(context); 67 | 68 | cppObjectMapper.Initialize(isolate, context); 69 | isolate->SetData(MAPPER_ISOLATE_DATA_POS, static_cast(&cppObjectMapper)); 70 | 71 | context->Global()->Set(context, v8::String::NewFromUtf8(isolate, "loadCppType").ToLocalChecked(), v8::FunctionTemplate::New(isolate, [](const v8::FunctionCallbackInfo& info) 72 | { 73 | auto pom = static_cast((v8::Local::Cast(info.Data()))->Value()); 74 | pom->LoadCppType(info); 75 | }, v8::External::New(isolate, &cppObjectMapper))->GetFunction(context).ToLocalChecked()).Check(); 76 | 77 | 78 | //注册 79 | puerts::DefineClass() 80 | .Constructor() 81 | .Function("Print", MakeFunction(&TestClass::Print)) 82 | .Property("X", MakeProperty(&TestClass::X)) 83 | .Method("Add", MakeFunction(&TestClass::Add)) 84 | .Register(); 85 | 86 | { 87 | const char* csource = R"( 88 | const TestClass = loadCppType('TestClass'); 89 | TestClass.Print('hello world'); 90 | let obj = new TestClass(123); 91 | 92 | TestClass.Print(obj.X); 93 | obj.X = 99; 94 | TestClass.Print(obj.X); 95 | 96 | TestClass.Print('ret = ' + obj.Add(1, 3)); 97 | )"; 98 | 99 | // Create a string containing the JavaScript source code. 100 | v8::Local source = 101 | v8::String::NewFromUtf8(isolate, csource) 102 | .ToLocalChecked(); 103 | 104 | // Compile the source code. 105 | v8::Local script = 106 | v8::Script::Compile(context, source).ToLocalChecked(); 107 | 108 | // Run the script 109 | auto _unused = script->Run(context); 110 | } 111 | 112 | cppObjectMapper.UnInitialize(isolate); 113 | 114 | } 115 | 116 | // Dispose the isolate and tear down V8. 117 | isolate->Dispose(); 118 | v8::V8::Dispose(); 119 | v8::V8::ShutdownPlatform(); 120 | delete create_params.array_buffer_allocator; 121 | return 0; 122 | } 123 | -------------------------------------------------------------------------------- /pesapitest/pesaddon/src/hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "TestClass.h" 5 | 6 | //cpp lib 7 | class TestClass22 { 8 | public: 9 | TestClass22(){ 10 | std::cout << "TestClass22 " << this << std::endl; 11 | c = 0; 12 | } 13 | 14 | static int32_t Inc(int32_t p) { 15 | std::cout << "Inc " << p << std::endl; 16 | return p + 1; 17 | } 18 | 19 | int32_t Cpp() { 20 | std::cout << "Cpp " << c << std::endl; 21 | return c++; 22 | } 23 | 24 | ~TestClass22(){ 25 | std::cout << "~TestClass22 " << this << std::endl; 26 | } 27 | 28 | int c; 29 | }; 30 | 31 | //only depend on pesapi.h 32 | void Inc(pesapi_callback_info info) { 33 | std::cout << "wrap by hand begin" << std::endl; 34 | pesapi_env env = pesapi_get_env(info); 35 | int32_t i = pesapi_get_value_int32(env, pesapi_get_arg(info, 0)); 36 | pesapi_add_return(info, pesapi_create_int32(env, TestClass22::Inc(i))); 37 | std::cout << "wrap by hand end" << std::endl; 38 | } 39 | 40 | void Init1() { 41 | pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(1); 42 | pesapi_set_method_info(properties, 0, "Inc", true, Inc, nullptr, nullptr); 43 | pesapi_define_class("TestClass11", nullptr, "TestClass11", nullptr, nullptr, 1, properties, nullptr); 44 | } 45 | 46 | //cpp template 47 | UsingCppType(TestClass22); 48 | UsingCppType(BaseClass); 49 | UsingCppType(TestClass); 50 | UsingCppType(AdvanceTestClass); 51 | 52 | void Init2() { 53 | puerts::DefineClass() 54 | .Constructor() 55 | .Function("Inc", MakeFunction(&TestClass22::Inc)) 56 | .Method("Cpp", MakeFunction(&TestClass22::Cpp)) 57 | .Register(); 58 | 59 | puerts::DefineClass() 60 | .Method("Foo", MakeFunction(&BaseClass::Foo)) 61 | .Register(); 62 | 63 | puerts::DefineClass() 64 | .Extends() 65 | //.Constructor() //if only one Constructor 66 | .Constructor(CombineConstructors( 67 | MakeConstructor(TestClass, int32_t, int32_t), 68 | MakeConstructor(TestClass) 69 | )) 70 | .Property("X", MakeProperty(&TestClass::X)) 71 | .Property("Y", MakeProperty(&TestClass::Y)) 72 | .Variable("StaticInt", MakeVariable(&TestClass::StaticInt)) 73 | .Variable("Ten", MakeReadonlyVariable(&TestClass::Ten)) 74 | .Variable("IntArray", MakeReadonlyVariable(&TestClass::IntArray)) 75 | .Function("Add", MakeFunction(&TestClass::Add)) 76 | .Function("PrintInfo", MakeFunction(&TestClass::PrintInfo)) 77 | .Method("GetSelf", MakeFunction(&TestClass::GetSelf)) 78 | .Method("Ref", MakeFunction(&TestClass::Ref)) 79 | .Method("StrRef", MakeFunction(&TestClass::StrRef)) 80 | .Method("Ptr", MakeFunction(&TestClass::Ptr)) 81 | .Method("CStr", MakeFunction(&TestClass::CStr)) 82 | .Method("StrPtr", MakeFunction(&TestClass::StrPtr)) 83 | .Method("ConstRef", MakeFunction(&TestClass::ConstRef)) 84 | .Method("VoidPtr", MakeFunction(&TestClass::VoidPtr)) 85 | .Function("Overload", CombineOverloads( 86 | MakeOverload(void(*)(), &TestClass::Overload), 87 | MakeOverload(void(*)(int32_t), &TestClass::Overload), 88 | MakeOverload(void(*)(int32_t, int32_t), &TestClass::Overload), 89 | MakeOverload(void(*)(std::string, int32_t), &TestClass::Overload) 90 | )) 91 | .Method("OverloadMethod", CombineOverloads( 92 | MakeOverload(int32_t(TestClass::*)(), &TestClass::OverloadMethod), 93 | MakeOverload(int32_t(TestClass::*)(int32_t), &TestClass::OverloadMethod), 94 | MakeOverload(uint32_t(TestClass::*)(uint32_t), &TestClass::OverloadMethod), 95 | MakeOverload(int64_t(TestClass::*)(int64_t), &TestClass::OverloadMethod) 96 | )) 97 | .Register(); 98 | 99 | puerts::DefineClass() 100 | .Constructor() //if only one Constructor 101 | .Method("JsObjectTest", MakeFunction(&AdvanceTestClass::JsObjectTest)) 102 | .Method("CallJsObjectTest", MakeFunction(&AdvanceTestClass::CallJsObjectTest)) 103 | .Method("StdFunctionTest", MakeFunction(&AdvanceTestClass::StdFunctionTest)) 104 | .Register(); 105 | } 106 | 107 | void Init() { 108 | Init1(); 109 | Init2(); 110 | } 111 | 112 | PESAPI_MODULE(hello, Init) 113 | -------------------------------------------------------------------------------- /puertstest/puerts/include/ObjectMapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #if USING_IN_UNREAL_ENGINE 12 | #include "CoreMinimal.h" 13 | #include "PropertyTranslator.h" 14 | #include "StructWrapper.h" 15 | #endif 16 | #include "JSClassRegister.h" 17 | 18 | #pragma warning(push, 0) 19 | #include "v8.h" 20 | #pragma warning(pop) 21 | 22 | #include 23 | 24 | namespace puerts 25 | { 26 | class ICppObjectMapper 27 | { 28 | public: 29 | virtual void BindCppObject(v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr, v8::Local JSObject, 30 | bool PassByPointer) = 0; 31 | 32 | virtual void UnBindCppObject(JSClassDefinition* ClassDefinition, void* Ptr) = 0; 33 | 34 | virtual v8::Local FindOrAddCppObject( 35 | v8::Isolate* Isolate, v8::Local& Context, const void* TypeId, void* Ptr, bool PassByPointer) = 0; 36 | 37 | virtual bool IsInstanceOfCppObject(const void* TypeId, v8::Local JsObject) = 0; 38 | 39 | virtual std::weak_ptr GetJsEnvLifeCycleTracker() = 0; 40 | 41 | virtual ~ICppObjectMapper() 42 | { 43 | } 44 | }; 45 | 46 | #if USING_IN_UNREAL_ENGINE 47 | class IObjectMapper : public ICppObjectMapper 48 | { 49 | public: 50 | virtual void Bind(FClassWrapper* ClassWrapper, UObject* UEObject, v8::Local JSObject) = 0; 51 | 52 | virtual void UnBind(UClass* Class, UObject* UEObject) = 0; 53 | 54 | virtual v8::Local FindOrAdd( 55 | v8::Isolate* Isolate, v8::Local& Context, UClass* Class, UObject* UEObject) = 0; 56 | 57 | virtual void BindStruct( 58 | FScriptStructWrapper* ScriptStructWrapper, void* Ptr, v8::Local JSObject, bool PassByPointer) = 0; 59 | 60 | virtual void UnBindStruct(FScriptStructWrapper* ScriptStructWrapper, void* Ptr) = 0; 61 | 62 | // PassByPointer为false代表需要在js对象释放时,free相应的内存 63 | // 相关信息见该issue:https://github.com/Tencent/puerts/issues/693 64 | virtual v8::Local FindOrAddStruct( 65 | v8::Isolate* Isolate, v8::Local& Context, UScriptStruct* ScriptStruct, void* Ptr, bool PassByPointer) = 0; 66 | 67 | virtual void Merge( 68 | v8::Isolate* Isolate, v8::Local Context, v8::Local Src, UStruct* DesType, void* Des) = 0; 69 | 70 | virtual void BindContainer( 71 | void* Ptr, v8::Local JSObject, void (*Callback)(const v8::WeakCallbackInfo& data)) = 0; 72 | 73 | virtual void UnBindContainer(void* Ptr) = 0; 74 | 75 | virtual v8::Local FindOrAddContainer( 76 | v8::Isolate* Isolate, v8::Local& Context, PropertyMacro* Property, FScriptArray* Ptr, bool PassByPointer) = 0; 77 | 78 | virtual v8::Local FindOrAddContainer( 79 | v8::Isolate* Isolate, v8::Local& Context, PropertyMacro* Property, FScriptSet* Ptr, bool PassByPointer) = 0; 80 | 81 | virtual v8::Local FindOrAddContainer(v8::Isolate* Isolate, v8::Local& Context, 82 | PropertyMacro* KeyProperty, PropertyMacro* ValueProperty, FScriptMap* Ptr, bool PassByPointer) = 0; 83 | 84 | virtual v8::Local FindOrAddDelegate(v8::Isolate* Isolate, v8::Local& Context, UObject* Owner, 85 | PropertyMacro* Property, void* DelegatePtr, bool PassByPointer) = 0; 86 | 87 | virtual bool AddToDelegate( 88 | v8::Isolate* Isolate, v8::Local& Context, void* DelegatePtr, v8::Local JsFunction) = 0; 89 | 90 | virtual PropertyMacro* FindDelegateProperty(void* DelegatePtr) = 0; 91 | 92 | virtual FScriptDelegate NewDelegate(v8::Isolate* Isolate, v8::Local& Context, UObject* Owner, 93 | v8::Local JsFunction, UFunction* SignatureFunction) = 0; 94 | 95 | virtual bool RemoveFromDelegate( 96 | v8::Isolate* Isolate, v8::Local& Context, void* DelegatePtr, v8::Local JsFunction) = 0; 97 | 98 | virtual bool ClearDelegate(v8::Isolate* Isolate, v8::Local& Context, void* DelegatePtr) = 0; 99 | 100 | virtual void ExecuteDelegate(v8::Isolate* Isolate, v8::Local& Context, 101 | const v8::FunctionCallbackInfo& Info, void* DelegatePtr) = 0; 102 | 103 | virtual v8::Local CreateArray( 104 | v8::Isolate* Isolate, v8::Local& Context, FPropertyTranslator* Property, void* ArrayPtr) = 0; 105 | 106 | virtual bool IsInstanceOf(UStruct* Struct, v8::Local JsObject) = 0; 107 | 108 | virtual v8::Local AddSoftObjectPtr( 109 | v8::Isolate* Isolate, v8::Local Context, FSoftObjectPtr* SoftObjectPtr, UClass* Class, bool IsSoftClass) = 0; 110 | }; 111 | #endif 112 | 113 | } // namespace puerts 114 | -------------------------------------------------------------------------------- /nodejstest/embedtest.cc: -------------------------------------------------------------------------------- 1 | #include "node.h" 2 | #include "uv.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Binding.hpp" 8 | #include "CppObjectMapper.h" 9 | 10 | // Note: This file is being referred to from doc/api/embedding.md, and excerpts 11 | // from it are included in the documentation. Try to keep these in sync. 12 | 13 | using node::CommonEnvironmentSetup; 14 | using node::Environment; 15 | using node::MultiIsolatePlatform; 16 | using v8::Context; 17 | using v8::HandleScope; 18 | using v8::Isolate; 19 | using v8::Locker; 20 | using v8::MaybeLocal; 21 | using v8::V8; 22 | using v8::Value; 23 | 24 | 25 | class TestClass 26 | { 27 | public: 28 | TestClass(int p) { 29 | std::cout << "TestClass(" << p << ")" << std::endl; 30 | X = p; 31 | } 32 | 33 | static void Print(std::string msg) { 34 | std::cout << msg << std::endl; 35 | } 36 | 37 | int Add(int a, int b) 38 | { 39 | std::cout << "Add(" << a << "," << b << ")" << std::endl; 40 | return a + b; 41 | } 42 | 43 | int X; 44 | }; 45 | 46 | UsingCppType(TestClass); 47 | 48 | static int RunNodeInstance(MultiIsolatePlatform* platform, 49 | const std::vector& args, 50 | const std::vector& exec_args); 51 | 52 | int main(int argc, char** argv) { 53 | argv = uv_setup_args(argc, argv); 54 | std::vector args(argv, argv + argc); 55 | std::vector exec_args; 56 | std::vector errors; 57 | int exit_code = node::InitializeNodeWithArgs(&args, &exec_args, &errors); 58 | for (const std::string& error : errors) 59 | fprintf(stderr, "%s: %s\n", args[0].c_str(), error.c_str()); 60 | if (exit_code != 0) { 61 | return exit_code; 62 | } 63 | 64 | std::unique_ptr platform = 65 | MultiIsolatePlatform::Create(4); 66 | V8::InitializePlatform(platform.get()); 67 | V8::Initialize(); 68 | 69 | int ret = RunNodeInstance(platform.get(), args, exec_args); 70 | 71 | V8::Dispose(); 72 | V8::ShutdownPlatform(); 73 | return ret; 74 | } 75 | 76 | int RunNodeInstance(MultiIsolatePlatform* platform, 77 | const std::vector& args, 78 | const std::vector& exec_args) { 79 | int exit_code = 0; 80 | 81 | std::vector errors; 82 | std::unique_ptr setup = 83 | CommonEnvironmentSetup::Create(platform, &errors, args, exec_args); 84 | if (!setup) { 85 | for (const std::string& err : errors) 86 | fprintf(stderr, "%s: %s\n", args[0].c_str(), err.c_str()); 87 | return 1; 88 | } 89 | 90 | Isolate* isolate = setup->isolate(); 91 | Environment* env = setup->env(); 92 | 93 | { 94 | Locker locker(isolate); 95 | Isolate::Scope isolate_scope(isolate); 96 | HandleScope handle_scope(isolate); 97 | Context::Scope context_scope(setup->context()); 98 | 99 | MaybeLocal loadenv_ret = node::LoadEnvironment( 100 | env, 101 | "const publicRequire =" 102 | " require('module').createRequire(process.cwd() + '/');" 103 | "globalThis.require = publicRequire;" 104 | "globalThis.embedVars = { nön_ascıı: '🏳️‍🌈' };" 105 | "require('vm').runInThisContext(process.argv[1]);"); 106 | 107 | if (loadenv_ret.IsEmpty()) // There has been a JS exception. 108 | return 1; 109 | 110 | exit_code = node::SpinEventLoop(env).FromMaybe(1); 111 | 112 | auto context = setup->context(); 113 | puerts::FCppObjectMapper cppObjectMapper; 114 | cppObjectMapper.Initialize(isolate, context); 115 | isolate->SetData(MAPPER_ISOLATE_DATA_POS, static_cast(&cppObjectMapper)); 116 | 117 | context->Global()->Set(context, v8::String::NewFromUtf8(isolate, "loadCppType").ToLocalChecked(), v8::FunctionTemplate::New(isolate, [](const v8::FunctionCallbackInfo& info) 118 | { 119 | auto pom = static_cast((v8::Local::Cast(info.Data()))->Value()); 120 | pom->LoadCppType(info); 121 | }, v8::External::New(isolate, &cppObjectMapper))->GetFunction(context).ToLocalChecked()).Check(); 122 | 123 | //注册 124 | puerts::DefineClass() 125 | .Constructor() 126 | .Function("Print", MakeFunction(&TestClass::Print)) 127 | .Property("X", MakeProperty(&TestClass::X)) 128 | .Method("Add", MakeFunction(&TestClass::Add)) 129 | .Register(); 130 | 131 | { 132 | const char* csource = R"( 133 | const TestClass = loadCppType('TestClass'); 134 | TestClass.Print('hello world'); 135 | let obj = new TestClass(123); 136 | 137 | TestClass.Print(obj.X); 138 | obj.X = 99; 139 | TestClass.Print(obj.X); 140 | 141 | TestClass.Print('ret = ' + obj.Add(1, 3)); 142 | 143 | const fs = require('fs'); 144 | let info = fs.readdirSync('.'); 145 | console.log(info); 146 | )"; 147 | 148 | // Create a string containing the JavaScript source code. 149 | v8::Local source = 150 | v8::String::NewFromUtf8(isolate, csource) 151 | .ToLocalChecked(); 152 | 153 | // Compile the source code. 154 | v8::Local script = 155 | v8::Script::Compile(context, source).ToLocalChecked(); 156 | 157 | // Run the script 158 | auto _unused = script->Run(context); 159 | } 160 | 161 | cppObjectMapper.UnInitialize(isolate); 162 | 163 | node::Stop(env); 164 | } 165 | 166 | return exit_code; 167 | } 168 | -------------------------------------------------------------------------------- /pesapitest/pesapiv8impl/src/PesapiAddonLoad.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #include "pesapi.h" 10 | #if defined(PLATFORM_WINDOWS) 11 | #include 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define STRINGIFY_(x) #x 20 | #define STRINGIFY(x) STRINGIFY_(x) 21 | 22 | #ifndef MSVC_PRAGMA 23 | #if !defined(__clang__) && defined(_MSC_VER) 24 | #define MSVC_PRAGMA(Pragma) __pragma(Pragma) 25 | #else 26 | #define MSVC_PRAGMA(...) 27 | #endif 28 | #endif 29 | 30 | static std::map GHandlers; 31 | 32 | MSVC_PRAGMA(warning(push)) 33 | MSVC_PRAGMA(warning(disable : 4191)) 34 | static pesapi_func_ptr funcs[] = {(pesapi_func_ptr) &pesapi_create_null, (pesapi_func_ptr) &pesapi_create_undefined, 35 | (pesapi_func_ptr) &pesapi_create_boolean, (pesapi_func_ptr) &pesapi_create_int32, (pesapi_func_ptr) &pesapi_create_uint32, 36 | (pesapi_func_ptr) &pesapi_create_int64, (pesapi_func_ptr) &pesapi_create_uint64, (pesapi_func_ptr) &pesapi_create_double, 37 | (pesapi_func_ptr) &pesapi_create_string_utf8, (pesapi_func_ptr) &pesapi_create_binary, (pesapi_func_ptr) &pesapi_get_value_bool, 38 | (pesapi_func_ptr) &pesapi_get_value_int32, (pesapi_func_ptr) &pesapi_get_value_uint32, 39 | (pesapi_func_ptr) &pesapi_get_value_int64, (pesapi_func_ptr) &pesapi_get_value_uint64, 40 | (pesapi_func_ptr) &pesapi_get_value_double, (pesapi_func_ptr) &pesapi_get_value_string_utf8, 41 | (pesapi_func_ptr) &pesapi_get_value_binary, (pesapi_func_ptr) &pesapi_is_null, (pesapi_func_ptr) &pesapi_is_undefined, 42 | (pesapi_func_ptr) &pesapi_is_boolean, (pesapi_func_ptr) &pesapi_is_int32, (pesapi_func_ptr) &pesapi_is_uint32, 43 | (pesapi_func_ptr) &pesapi_is_int64, (pesapi_func_ptr) &pesapi_is_uint64, (pesapi_func_ptr) &pesapi_is_double, 44 | (pesapi_func_ptr) &pesapi_is_string, (pesapi_func_ptr) &pesapi_is_object, (pesapi_func_ptr) &pesapi_is_function, 45 | (pesapi_func_ptr) &pesapi_is_binary, (pesapi_func_ptr) &pesapi_create_native_object, 46 | (pesapi_func_ptr) &pesapi_get_native_object_ptr, (pesapi_func_ptr) &pesapi_get_native_object_typeid, 47 | (pesapi_func_ptr) &pesapi_is_native_object, (pesapi_func_ptr) &pesapi_create_ref, (pesapi_func_ptr) &pesapi_get_value_ref, 48 | (pesapi_func_ptr) &pesapi_update_value_ref, (pesapi_func_ptr) &pesapi_is_ref, (pesapi_func_ptr) &pesapi_get_args_len, 49 | (pesapi_func_ptr) &pesapi_get_arg, (pesapi_func_ptr) &pesapi_get_env, (pesapi_func_ptr) &pesapi_get_this, 50 | (pesapi_func_ptr) &pesapi_get_holder, (pesapi_func_ptr) &pesapi_get_userdata, 51 | (pesapi_func_ptr) &pesapi_get_constructor_userdata, (pesapi_func_ptr) &pesapi_add_return, 52 | (pesapi_func_ptr) &pesapi_throw_by_string, (pesapi_func_ptr) &pesapi_hold_env, (pesapi_func_ptr) &pesapi_get_env_from_holder, 53 | (pesapi_func_ptr) &pesapi_duplicate_env_holder, (pesapi_func_ptr) &pesapi_release_env_holder, 54 | (pesapi_func_ptr) &pesapi_open_scope, (pesapi_func_ptr) &pesapi_has_caught, (pesapi_func_ptr) &pesapi_get_exception_as_string, 55 | (pesapi_func_ptr) &pesapi_close_scope, (pesapi_func_ptr) &pesapi_hold_value, (pesapi_func_ptr) &pesapi_duplicate_value_holder, 56 | (pesapi_func_ptr) &pesapi_release_value_holder, (pesapi_func_ptr) &pesapi_get_value_from_holder, 57 | (pesapi_func_ptr) &pesapi_get_property, (pesapi_func_ptr) &pesapi_set_property, (pesapi_func_ptr) &pesapi_get_property_uint32, 58 | (pesapi_func_ptr) &pesapi_set_property_uint32, (pesapi_func_ptr) &pesapi_call_function, (pesapi_func_ptr) &pesapi_eval, 59 | (pesapi_func_ptr) &pesapi_alloc_type_infos, (pesapi_func_ptr) &pesapi_set_type_info, 60 | (pesapi_func_ptr) &pesapi_create_signature_info, (pesapi_func_ptr) &pesapi_alloc_property_descriptors, 61 | (pesapi_func_ptr) &pesapi_set_method_info, (pesapi_func_ptr) &pesapi_set_property_info, (pesapi_func_ptr) &pesapi_define_class}; 62 | MSVC_PRAGMA(warning(pop)) 63 | 64 | static int LoadAddon(const char* path, const char* module_name) 65 | { 66 | if (GHandlers.find(path) != GHandlers.end()) 67 | { 68 | // UE_LOG(LogTemp, Warning, TEXT("Try load addon already loaded: %s"), UTF8_TO_TCHAR(path)); 69 | return 0; 70 | } 71 | 72 | HINSTANCE hinstLib; 73 | 74 | hinstLib = LoadLibrary(path); 75 | 76 | if (hinstLib != NULL) 77 | { 78 | /* 79 | std::string EntryName = STRINGIFY(PESAPI_MODULE_INITIALIZER(___magic_module_name_xx___)); 80 | EntryName = std::regex_replace(EntryName, std::regex("___magic_module_name_xx___"), module_name); 81 | 82 | auto Init = (void (*)(pesapi_func_ptr*))(uintptr_t)GetProcAddress(hinstLib, EntryName.c_str()); 83 | 84 | if (Init) 85 | { 86 | Init(funcs); 87 | GHandlers[path] = hinstLib; 88 | return 0; 89 | } 90 | */ 91 | std::string EntryName = STRINGIFY(PESAPI_MODULE_INITIALIZER(dynamic)); 92 | 93 | auto Init = (const char* (*)(pesapi_func_ptr*))(uintptr_t)GetProcAddress(hinstLib, EntryName.c_str()); 94 | 95 | if (Init) 96 | { 97 | const char* mn = Init(funcs); 98 | std::cout << "load " << mn << " success!" << std::endl; 99 | GHandlers[path] = hinstLib; 100 | return 0; 101 | } 102 | std::cout << "can find symbol " << EntryName << " in " << path << "!" << std::endl; 103 | FreeLibrary(hinstLib); 104 | } 105 | else 106 | { 107 | std::cout << "load " << path << " fail!" << std::endl; 108 | } 109 | 110 | return -1; 111 | } 112 | 113 | EXTERN_C_START 114 | int pesapi_load_addon(const char* path, const char* module_name) 115 | { 116 | return LoadAddon(path, module_name); 117 | } 118 | EXTERN_C_END 119 | 120 | -------------------------------------------------------------------------------- /puertstest/puerts/include/V8FastCall.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #pragma warning(push, 0) 12 | #include 13 | #pragma warning(pop) 14 | #include "DataTransfer.h" 15 | 16 | namespace puerts 17 | { 18 | template 19 | struct FastCallArgument 20 | { 21 | }; 22 | 23 | template 24 | struct FastCallArgument::value && !std::is_same::value && 25 | !std::is_enum::type>::value && 26 | !std::is_integral::type>::value && 27 | !std::is_floating_point::type>::value>::type> 28 | { 29 | using DeclType = v8::Local; 30 | 31 | static T Get(v8::Local v) 32 | { 33 | if (V8_LIKELY(v->IsObject())) 34 | { 35 | // return static_cast(v.As()->GetAlignedPointerFromInternalField(1)); 36 | return static_cast(DataTransfer::GetPointerFast(v.As())); 37 | } 38 | return nullptr; 39 | } 40 | }; 41 | 42 | template <> 43 | struct FastCallArgument 44 | { 45 | }; 46 | 47 | template 48 | struct FastCallArgument::value>::type> 49 | { 50 | using DeclType = int; 51 | 52 | static T Get(int i) 53 | { 54 | return static_cast(i); 55 | } 56 | }; 57 | 58 | template 59 | struct FastCallArgument::value || std::is_floating_point::value>::type> 60 | { 61 | using DeclType = typename std::decay::type; 62 | 63 | static T Get(typename std::decay::type i) 64 | { 65 | return i; 66 | } 67 | }; 68 | 69 | template <> 70 | struct FastCallArgument 71 | { 72 | using DeclType = bool; 73 | 74 | static bool Get(bool i) 75 | { 76 | return i; 77 | } 78 | }; 79 | 80 | namespace internal 81 | { 82 | namespace fastcallutil 83 | { 84 | template 85 | struct _Conjunction 86 | { // handle false trait or last trait 87 | using type = _First; 88 | }; 89 | 90 | template 91 | struct _Conjunction 92 | { // the first trait is true, try the next one 93 | using type = typename _Conjunction<_Next::value, _Next, _Rest...>::type; 94 | }; 95 | 96 | template 97 | struct Conjunction : std::true_type 98 | { 99 | }; // If _Traits is empty, true_type 100 | 101 | template 102 | struct Conjunction<_First, _Rest...> : _Conjunction<_First::value, _First, _Rest...>::type 103 | { 104 | // the first false trait in _Traits, or the last trait if none are false 105 | }; 106 | 107 | template 108 | using Void_t = void; 109 | } // namespace fastcallutil 110 | } // namespace internal 111 | 112 | template 113 | struct IsArgSupportedHelper : std::false_type 114 | { 115 | }; 116 | 117 | template 118 | struct IsArgSupportedHelper::Get)>> : std::true_type 119 | { 120 | }; 121 | 122 | template 123 | struct IsArgsSupportedHelper : std::false_type 124 | { 125 | }; 126 | 127 | template 128 | struct IsArgsSupportedHelper, 129 | typename std::enable_if...>::value>::type> : std::true_type 130 | { 131 | }; 132 | 133 | template 134 | struct IsReturnSupportedHelper : std::false_type 135 | { 136 | }; 137 | 138 | template 139 | struct IsReturnSupportedHelper::value && !std::is_pointer::value && !std::is_integral::value>::type> 141 | : std::true_type 142 | { 143 | }; 144 | 145 | template 146 | struct IsReturnSupportedHelper::value && sizeof(T) < 8>::type> : std::true_type 147 | { 148 | }; 149 | 150 | template <> 151 | struct IsReturnSupportedHelper : std::true_type 152 | { 153 | }; 154 | 155 | template 156 | struct V8FastCall 157 | { 158 | static const v8::CFunction* info() 159 | { 160 | return nullptr; 161 | } 162 | }; 163 | 164 | template 165 | struct V8FastCall::value && IsArgsSupportedHelper>::value && 167 | (sizeof...(Args) > 0)>::type> 168 | { 169 | static Ret Wrap(typename FastCallArgument::DeclType... args) 170 | { 171 | return func(FastCallArgument::Get(args)...); 172 | } 173 | 174 | static const v8::CFunction* info() 175 | { 176 | static v8::CFunction _info = v8::CFunction::Make(Wrap); 177 | return &_info; 178 | } 179 | }; 180 | 181 | template 182 | struct V8FastCall::value && IsArgsSupportedHelper>::value>::type> 184 | { 185 | static Ret Wrap(v8::Local receiver_obj, typename FastCallArgument::DeclType... args) 186 | { 187 | auto self = FastCallArgument::Get(receiver_obj); 188 | return (self->*func)(FastCallArgument::Get(args)...); 189 | } 190 | 191 | static const v8::CFunction* info() 192 | { 193 | static v8::CFunction _info = v8::CFunction::Make(Wrap); 194 | return &_info; 195 | } 196 | }; 197 | 198 | template 199 | struct V8FastCall::value && IsArgsSupportedHelper>::value>::type> 201 | { 202 | static Ret Wrap(v8::Local receiver_obj, typename FastCallArgument::DeclType... args) 203 | { 204 | auto self = FastCallArgument::Get(receiver_obj); 205 | return (self->*func)(FastCallArgument::Get(args)...); 206 | } 207 | 208 | static const v8::CFunction* info() 209 | { 210 | static v8::CFunction _info = v8::CFunction::Make(Wrap); 211 | return &_info; 212 | } 213 | }; 214 | 215 | } // namespace puerts 216 | -------------------------------------------------------------------------------- /puertstest/puerts/include/PesapiObject.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "Binding.hpp" 12 | #include "pesapi.h" 13 | #include 14 | 15 | namespace puerts 16 | { 17 | namespace internal 18 | { 19 | class AutoValueScope 20 | { 21 | public: 22 | AutoValueScope(pesapi_env_holder env_holder) 23 | { 24 | scope = pesapi_open_scope(env_holder); 25 | } 26 | 27 | ~AutoValueScope() 28 | { 29 | pesapi_close_scope(scope); 30 | } 31 | 32 | pesapi_scope scope; 33 | }; 34 | } // namespace internal 35 | namespace pesapi_impl 36 | { 37 | static void REPORT_EXCEPTION(const char* MSG) 38 | { 39 | std::cout << "call function throw: " << MSG << std::endl; 40 | } 41 | 42 | class Object 43 | { 44 | public: 45 | Object(pesapi_env env, pesapi_value value) 46 | { 47 | env_holder = pesapi_hold_env(env); 48 | value_holder = pesapi_hold_value(env, value); 49 | } 50 | 51 | Object(const Object& InOther) 52 | { 53 | env_holder = pesapi_duplicate_env_holder(InOther.env_holder); 54 | value_holder = pesapi_duplicate_value_holder(InOther.value_holder); 55 | } 56 | 57 | ~Object() 58 | { 59 | pesapi_release_value_holder(value_holder); 60 | pesapi_release_env_holder(env_holder); 61 | } 62 | 63 | template 64 | T Get(const char* key) const 65 | { 66 | internal::AutoValueScope ValueScope(env_holder); 67 | auto env = pesapi_get_env_from_holder(env_holder); 68 | auto object = pesapi_get_value_from_holder(env, value_holder); 69 | 70 | auto value = pesapi_get_property(env, object, key); 71 | if (!pesapi_is_undefined(env, value)) 72 | { 73 | return puerts::pesapi_impl::Converter::toCpp(env, value); 74 | } 75 | return {}; 76 | } 77 | 78 | template 79 | void Set(const char* key, T val) const 80 | { 81 | internal::AutoValueScope ValueScope(env_holder); 82 | auto env = pesapi_get_env_from_holder(env_holder); 83 | auto object = pesapi_get_value_from_holder(env, value_holder); 84 | 85 | pesapi_set_property(env, object, key, puerts::pesapi_impl::Converter::toScript(env, val)); 86 | } 87 | 88 | bool IsValid() const 89 | { 90 | internal::AutoValueScope ValueScope(env_holder); 91 | auto env = pesapi_get_env_from_holder(env_holder); 92 | auto val = pesapi_get_value_from_holder(env, value_holder); 93 | return val && pesapi_is_object(env, val); 94 | } 95 | 96 | void operator=(const Object& obj) 97 | { 98 | env_holder = pesapi_duplicate_env_holder(obj.env_holder); 99 | value_holder = pesapi_duplicate_value_holder(obj.value_holder); 100 | } 101 | 102 | pesapi_env_holder env_holder; 103 | pesapi_value_holder value_holder; 104 | 105 | friend struct puerts::pesapi_impl::Converter; 106 | }; 107 | 108 | class Function : public Object 109 | { 110 | public: 111 | Function(pesapi_env env, pesapi_value value) : Object(env, value) 112 | { 113 | } 114 | 115 | template 116 | void Action(Args... cppArgs) const 117 | { 118 | internal::AutoValueScope ValueScope(env_holder); 119 | auto env = pesapi_get_env_from_holder(env_holder); 120 | auto object = pesapi_get_value_from_holder(env, value_holder); 121 | 122 | auto _un_used = invokeHelper(env, object, cppArgs...); 123 | 124 | if (pesapi_has_caught(ValueScope.scope)) 125 | { 126 | REPORT_EXCEPTION(pesapi_get_exception_as_string(ValueScope.scope, true)); 127 | } 128 | } 129 | 130 | template 131 | Ret Func(Args... cppArgs) const 132 | { 133 | internal::AutoValueScope ValueScope(env_holder); 134 | auto env = pesapi_get_env_from_holder(env_holder); 135 | auto object = pesapi_get_value_from_holder(env, value_holder); 136 | 137 | auto ret = invokeHelper(env, object, cppArgs...); 138 | 139 | if (pesapi_has_caught(ValueScope.scope)) 140 | { 141 | REPORT_EXCEPTION(pesapi_get_exception_as_string(ValueScope.scope, true)); 142 | return {}; 143 | } 144 | else 145 | { 146 | return pesapi_impl::Converter::toCpp(env, ret); 147 | } 148 | } 149 | 150 | bool IsValid() const 151 | { 152 | internal::AutoValueScope ValueScope(env_holder); 153 | auto env = pesapi_get_env_from_holder(env_holder); 154 | auto val = pesapi_get_value_from_holder(env, value_holder); 155 | return val && pesapi_is_function(env, val); 156 | } 157 | 158 | private: 159 | template 160 | auto invokeHelper(pesapi_env env, pesapi_value func, Args... CppArgs) const 161 | { 162 | pesapi_value argv[sizeof...(Args)]{puerts::pesapi_impl::Converter::toScript(env, CppArgs)...}; 163 | return pesapi_call_function(env, func, nullptr, sizeof...(Args), argv); 164 | } 165 | 166 | auto invokeHelper(pesapi_env env, pesapi_value func) const 167 | { 168 | return pesapi_call_function(env, func, nullptr, 0, nullptr); 169 | } 170 | 171 | friend struct puerts::pesapi_impl::Converter; 172 | }; 173 | 174 | } // namespace pesapi_impl 175 | 176 | template <> 177 | struct ScriptTypeName 178 | { 179 | static constexpr auto value() 180 | { 181 | return internal::Literal("object"); 182 | } 183 | }; 184 | 185 | template <> 186 | struct ScriptTypeName 187 | { 188 | static constexpr auto value() 189 | { 190 | return internal::Literal("Function"); 191 | } 192 | }; 193 | 194 | namespace pesapi_impl 195 | { 196 | template <> 197 | struct Converter 198 | { 199 | static pesapi_value toScript(pesapi_env env, Object value) 200 | { 201 | return pesapi_get_value_from_holder(env, value.value_holder); 202 | } 203 | 204 | static Object toCpp(pesapi_env env, pesapi_value value) 205 | { 206 | return Object(env, value); 207 | } 208 | 209 | static bool accept(pesapi_env env, pesapi_value value) 210 | { 211 | return pesapi_is_object(env, value); 212 | } 213 | }; 214 | 215 | template <> 216 | struct Converter 217 | { 218 | static pesapi_value toScript(pesapi_env env, Function value) 219 | { 220 | return pesapi_get_value_from_holder(env, value.value_holder); 221 | } 222 | 223 | static Function toCpp(pesapi_env env, pesapi_value value) 224 | { 225 | return Function(env, value); 226 | } 227 | 228 | static bool accept(pesapi_env env, pesapi_value value) 229 | { 230 | return pesapi_is_function(env, value); 231 | } 232 | }; 233 | 234 | #include "StdFunctionConverter.hpp" 235 | } // namespace pesapi_impl 236 | 237 | } // namespace puerts 238 | -------------------------------------------------------------------------------- /puertstest/puerts/src/JSClassRegister.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #include "JSClassRegister.h" 10 | #if USING_IN_UNREAL_ENGINE 11 | #include "UObject/Class.h" 12 | #endif 13 | #include 14 | 15 | namespace puerts 16 | { 17 | template 18 | static T* PropertyInfoDuplicate(T* Arr) 19 | { 20 | if (Arr == nullptr) 21 | return nullptr; 22 | int Count = 0; 23 | ; 24 | while (true) 25 | { 26 | if (Arr[Count++].Name == nullptr) 27 | break; 28 | } 29 | T* Ret = new T[Count]; 30 | ::memcpy(Ret, Arr, sizeof(T) * Count); 31 | return Ret; 32 | } 33 | 34 | JSClassDefinition* JSClassDefinitionDuplicate(const JSClassDefinition* ClassDefinition) 35 | { 36 | auto Ret = new JSClassDefinition; 37 | ::memcpy(Ret, ClassDefinition, sizeof(JSClassDefinition)); 38 | Ret->Methods = PropertyInfoDuplicate(ClassDefinition->Methods); 39 | Ret->Functions = PropertyInfoDuplicate(ClassDefinition->Functions); 40 | Ret->Properties = PropertyInfoDuplicate(ClassDefinition->Properties); 41 | Ret->Variables = PropertyInfoDuplicate(ClassDefinition->Variables); 42 | Ret->ConstructorInfos = PropertyInfoDuplicate(ClassDefinition->ConstructorInfos); 43 | Ret->MethodInfos = PropertyInfoDuplicate(ClassDefinition->MethodInfos); 44 | Ret->FunctionInfos = PropertyInfoDuplicate(ClassDefinition->FunctionInfos); 45 | Ret->PropertyInfos = PropertyInfoDuplicate(ClassDefinition->PropertyInfos); 46 | Ret->VariableInfos = PropertyInfoDuplicate(ClassDefinition->VariableInfos); 47 | return Ret; 48 | } 49 | 50 | void JSClassDefinitionDelete(JSClassDefinition* ClassDefinition) 51 | { 52 | delete[] ClassDefinition->Methods; 53 | delete[] ClassDefinition->Functions; 54 | delete[] ClassDefinition->Properties; 55 | delete[] ClassDefinition->Variables; 56 | delete[] ClassDefinition->ConstructorInfos; 57 | delete[] ClassDefinition->MethodInfos; 58 | delete[] ClassDefinition->FunctionInfos; 59 | delete[] ClassDefinition->PropertyInfos; 60 | delete[] ClassDefinition->VariableInfos; 61 | delete ClassDefinition; 62 | } 63 | 64 | class JSClassRegister 65 | { 66 | public: 67 | JSClassRegister(); 68 | ~JSClassRegister(); 69 | 70 | void RegisterClass(const JSClassDefinition& ClassDefinition); 71 | 72 | void ForeachRegisterClass(std::function); 73 | 74 | const JSClassDefinition* FindClassByID(const void* TypeId); 75 | 76 | const JSClassDefinition* FindCppTypeClassByName(const std::string& Name); 77 | 78 | void RegisterAddon(const std::string& Name, AddonRegisterFunc RegisterFunc); 79 | 80 | AddonRegisterFunc FindAddonRegisterFunc(const std::string& Name); 81 | 82 | #if USING_IN_UNREAL_ENGINE 83 | const JSClassDefinition* FindClassByType(UStruct* Type); 84 | #endif 85 | 86 | private: 87 | std::map CDataIdToClassDefinition; 88 | std::map CDataNameToClassDefinition; 89 | std::map AddonRegisterInfos; 90 | #if USING_IN_UNREAL_ENGINE 91 | std::map StructNameToClassDefinition; 92 | #endif 93 | }; 94 | 95 | JSClassRegister::JSClassRegister() 96 | { 97 | } 98 | 99 | JSClassRegister::~JSClassRegister() 100 | { 101 | for (auto& KV : CDataIdToClassDefinition) 102 | { 103 | JSClassDefinitionDelete(KV.second); 104 | } 105 | CDataIdToClassDefinition.clear(); 106 | #if USING_IN_UNREAL_ENGINE 107 | for (auto& KV : StructNameToClassDefinition) 108 | { 109 | JSClassDefinitionDelete(KV.second); 110 | } 111 | StructNameToClassDefinition.clear(); 112 | #endif 113 | } 114 | 115 | void JSClassRegister::RegisterClass(const JSClassDefinition& ClassDefinition) 116 | { 117 | if (ClassDefinition.TypeId && ClassDefinition.ScriptName) 118 | { 119 | auto cd_iter = CDataIdToClassDefinition.find(ClassDefinition.TypeId); 120 | if (cd_iter != CDataIdToClassDefinition.end()) 121 | { 122 | JSClassDefinitionDelete(cd_iter->second); 123 | } 124 | CDataIdToClassDefinition[ClassDefinition.TypeId] = JSClassDefinitionDuplicate(&ClassDefinition); 125 | std::string SN = ClassDefinition.ScriptName; 126 | CDataNameToClassDefinition[SN] = CDataIdToClassDefinition[ClassDefinition.TypeId]; 127 | } 128 | #if USING_IN_UNREAL_ENGINE 129 | else if (ClassDefinition.UETypeName) 130 | { 131 | FString SN = UTF8_TO_TCHAR(ClassDefinition.UETypeName); 132 | auto ud_iter = StructNameToClassDefinition.find(SN); 133 | if (ud_iter != StructNameToClassDefinition.end()) 134 | { 135 | JSClassDefinitionDelete(ud_iter->second); 136 | } 137 | StructNameToClassDefinition[SN] = JSClassDefinitionDuplicate(&ClassDefinition); 138 | } 139 | #endif 140 | } 141 | 142 | const JSClassDefinition* JSClassRegister::FindClassByID(const void* TypeId) 143 | { 144 | auto Iter = CDataIdToClassDefinition.find(TypeId); 145 | if (Iter == CDataIdToClassDefinition.end()) 146 | { 147 | return nullptr; 148 | } 149 | else 150 | { 151 | return Iter->second; 152 | } 153 | } 154 | 155 | const JSClassDefinition* JSClassRegister::FindCppTypeClassByName(const std::string& Name) 156 | { 157 | auto Iter = CDataNameToClassDefinition.find(Name); 158 | if (Iter == CDataNameToClassDefinition.end()) 159 | { 160 | return nullptr; 161 | } 162 | else 163 | { 164 | return Iter->second; 165 | } 166 | } 167 | 168 | void JSClassRegister::RegisterAddon(const std::string& Name, AddonRegisterFunc RegisterFunc) 169 | { 170 | AddonRegisterInfos[Name] = RegisterFunc; 171 | } 172 | 173 | AddonRegisterFunc JSClassRegister::FindAddonRegisterFunc(const std::string& Name) 174 | { 175 | auto Iter = AddonRegisterInfos.find(Name); 176 | if (Iter == AddonRegisterInfos.end()) 177 | { 178 | return nullptr; 179 | } 180 | else 181 | { 182 | return Iter->second; 183 | } 184 | } 185 | 186 | #if USING_IN_UNREAL_ENGINE 187 | const JSClassDefinition* JSClassRegister::FindClassByType(UStruct* Type) 188 | { 189 | auto Iter = StructNameToClassDefinition.find(Type->GetName()); 190 | if (Iter == StructNameToClassDefinition.end()) 191 | { 192 | return nullptr; 193 | } 194 | else 195 | { 196 | return Iter->second; 197 | } 198 | } 199 | #endif 200 | 201 | void JSClassRegister::ForeachRegisterClass(std::function Callback) 202 | { 203 | for (auto& KV : CDataNameToClassDefinition) 204 | { 205 | Callback(KV.second); 206 | } 207 | #if USING_IN_UNREAL_ENGINE 208 | for (auto& KV : StructNameToClassDefinition) 209 | { 210 | Callback(KV.second); 211 | } 212 | #endif 213 | } 214 | 215 | JSClassRegister* GetJSClassRegister() 216 | { 217 | static JSClassRegister S_JSClassRegister; 218 | return &S_JSClassRegister; 219 | } 220 | 221 | void RegisterJSClass(const JSClassDefinition& ClassDefinition) 222 | { 223 | GetJSClassRegister()->RegisterClass(ClassDefinition); 224 | } 225 | 226 | void ForeachRegisterClass(std::function Callback) 227 | { 228 | GetJSClassRegister()->ForeachRegisterClass(Callback); 229 | } 230 | 231 | const JSClassDefinition* FindClassByID(const void* TypeId) 232 | { 233 | return GetJSClassRegister()->FindClassByID(TypeId); 234 | } 235 | 236 | const JSClassDefinition* FindCppTypeClassByName(const std::string& Name) 237 | { 238 | return GetJSClassRegister()->FindCppTypeClassByName(Name); 239 | } 240 | 241 | void RegisterAddon(const char* Name, AddonRegisterFunc RegisterFunc) 242 | { 243 | GetJSClassRegister()->RegisterAddon(Name, RegisterFunc); 244 | } 245 | 246 | AddonRegisterFunc FindAddonRegisterFunc(const std::string& Name) 247 | { 248 | return GetJSClassRegister()->FindAddonRegisterFunc(Name); 249 | } 250 | 251 | #if USING_IN_UNREAL_ENGINE 252 | const JSClassDefinition* FindClassByType(UStruct* Type) 253 | { 254 | return GetJSClassRegister()->FindClassByType(Type); 255 | } 256 | #endif 257 | 258 | } // namespace puerts 259 | -------------------------------------------------------------------------------- /puertstest/puerts/include/ScriptBackend.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | #if defined(BUILDING_PES_EXTENSION) 11 | #include "PesapiBackend.hpp" 12 | #else 13 | #include "V8Backend.hpp" 14 | #endif 15 | #include "Object.hpp" 16 | 17 | #ifndef PUERTS_BINDING_IMPL 18 | #if defined(BUILDING_PES_EXTENSION) 19 | #define PUERTS_BINDING_IMPL pesapi_impl 20 | #else 21 | #define PUERTS_BINDING_IMPL v8_impl 22 | #endif 23 | #endif 24 | 25 | #define MakeConstructor(T, ...) ::puerts::template ConstructorWrapper 26 | #define MakeGetter(M) &(::puerts::PropertyWrapper::getter) 27 | #define MakeSetter(M) &(::puerts::PropertyWrapper::setter) 28 | #define MakeProperty(M) \ 29 | &(::puerts::PropertyWrapper::getter), \ 30 | &(::puerts::PropertyWrapper::setter), \ 31 | ::puerts::PropertyWrapper::info() 32 | #define MakeReadonlyProperty(M) \ 33 | &(::puerts::PropertyWrapper::getter), nullptr, \ 34 | ::puerts::PropertyWrapper::info() 35 | #define MakeVariable(M) MakeProperty(M) 36 | #define MakeReadonlyVariable(M) MakeReadonlyProperty(M) 37 | #define MakeFunction(M, ...) \ 38 | [](::puerts::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \ 39 | { ::puerts::FuncCallWrapper::callWithDefaultValues(info, ##__VA_ARGS__); }, \ 40 | ::puerts::FuncCallWrapper::info(puerts::Count(__VA_ARGS__)) 41 | #define MakeExtension(M, ...) \ 42 | [](::puerts::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \ 43 | { \ 44 | ::puerts::FuncCallWrapper::callExtensionWithDefaultValues( \ 45 | info, ##__VA_ARGS__); \ 46 | }, \ 47 | ::puerts::FuncCallWrapper::extensionInfo(puerts::Count(__VA_ARGS__)) 48 | #define SelectFunction(SIGNATURE, M, ...) \ 49 | [](::puerts::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \ 50 | { ::puerts::FuncCallWrapper::callWithDefaultValues(info, ##__VA_ARGS__); }, \ 51 | ::puerts::FuncCallWrapper::info(puerts::Count(__VA_ARGS__)) 52 | #define SelectFunction_PtrRet(SIGNATURE, M, ...) \ 53 | [](::puerts::PUERTS_BINDING_IMPL::API::CallbackInfoType info) { \ 54 | ::puerts::FuncCallWrapper::callWithDefaultValues( \ 55 | info, ##__VA_ARGS__); \ 56 | }, \ 57 | ::puerts::FuncCallWrapper::info(puerts::Count(__VA_ARGS__)) 58 | #define MakeCheckFunction(M) \ 59 | &(::puerts::FuncCallWrapper::checkedCall), \ 60 | ::puerts::FuncCallWrapper::info() 61 | #define MakeOverload(SIGNATURE, M) puerts::FuncCallWrapper 62 | #define CombineOverloads(...) \ 63 | &::puerts::OverloadsCombiner::call, \ 64 | ::puerts::OverloadsCombiner::length, \ 65 | ::puerts::OverloadsCombiner::infos() 66 | #define CombineConstructors(...) \ 67 | &::puerts::ConstructorsCombiner::call, \ 68 | ::puerts::ConstructorsCombiner::length, \ 69 | ::puerts::ConstructorsCombiner::infos() 70 | 71 | #define DeclOverloads(Name) \ 72 | template \ 73 | struct Name##PuertsOverloads \ 74 | { \ 75 | }; 76 | 77 | #define DeclOverload(Name, SIGNATURE, M, ...) \ 78 | template <> \ 79 | struct Name##PuertsOverloads \ 80 | { \ 81 | static bool overloadCall(::puerts::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \ 82 | { \ 83 | return ::puerts::FuncCallWrapper::overloadCallWithDefaultValues(info, ##__VA_ARGS__); \ 84 | } \ 85 | static const ::puerts::CFunctionInfo* info() \ 86 | { \ 87 | return ::puerts::FuncCallWrapper::info(puerts::Count(__VA_ARGS__)); \ 88 | } \ 89 | }; 90 | 91 | #define SelectOverload(Name, SIGNATURE) Name##PuertsOverloads 92 | 93 | #define __DefObjectType_HELPER1(CLS, Suffix) __DefObjectType_##Suffix(CLS) 94 | #define __DefObjectType_HELPER2(CLS, Suffix) __DefObjectType_HELPER1(CLS, Suffix) 95 | #define __DefCDataPointerConverter_HELPER1(CLS, Suffix) __DefCDataPointerConverter_##Suffix(CLS) 96 | #define __DefCDataPointerConverter_HELPER2(CLS, Suffix) __DefCDataPointerConverter_HELPER1(CLS, Suffix) 97 | #define __DefObjectType(CLS) __DefObjectType_HELPER2(CLS, PUERTS_BINDING_IMPL) 98 | #define __DefCDataPointerConverter(CLS) __DefCDataPointerConverter_HELPER2(CLS, PUERTS_BINDING_IMPL) 99 | #define UsingNamedCppType(CLS, NAME) __DefScriptTTypeName(NAME, CLS) __DefObjectType(CLS) __DefCDataPointerConverter(CLS) 100 | 101 | #define UsingCppType(CLS) UsingNamedCppType(CLS, CLS) 102 | 103 | namespace puerts 104 | { 105 | template 106 | class ClassDefineBuilder; 107 | 108 | template 109 | ClassDefineBuilder DefineClass() 110 | { 111 | static auto NameLiteral = ScriptTypeName::value(); 112 | return ClassDefineBuilder(NameLiteral.Data()); 113 | } 114 | 115 | using Object = PUERTS_BINDING_IMPL::Object; 116 | 117 | using Function = PUERTS_BINDING_IMPL::Function; 118 | } // namespace puerts -------------------------------------------------------------------------------- /puertstest/puerts/include/V8Object.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "Binding.hpp" 12 | #include 13 | 14 | #ifdef USING_IN_UNREAL_ENGINE 15 | #include "JSLogger.h" 16 | #include "V8Utils.h" 17 | #else 18 | #include 19 | #endif 20 | 21 | namespace puerts 22 | { 23 | namespace v8_impl 24 | { 25 | static void REPORT_EXCEPTION(v8::Isolate* Isolate, v8::TryCatch* TC) 26 | { 27 | #ifdef USING_IN_UNREAL_ENGINE 28 | UE_LOG(Puerts, Error, TEXT("call function throw: %s"), *puerts::FV8Utils::TryCatchToString(Isolate, TC)); 29 | #else 30 | std::cout << "call function throw: " << *v8::String::Utf8Value(Isolate, TC->Exception()) << std::endl; 31 | #endif 32 | } 33 | 34 | class Object 35 | { 36 | public: 37 | Object() 38 | { 39 | } 40 | 41 | Object(v8::Local context, v8::Local object) 42 | { 43 | Isolate = context->GetIsolate(); 44 | GContext.Reset(Isolate, context); 45 | GObject.Reset(Isolate, object.As()); 46 | JsEnvLifeCycleTracker = DataTransfer::GetJsEnvLifeCycleTracker(Isolate); 47 | } 48 | 49 | Object(const Object& InOther) 50 | { 51 | Isolate = InOther.Isolate; 52 | v8::Isolate::Scope IsolateScope(Isolate); 53 | v8::HandleScope HandleScope(Isolate); 54 | GContext.Reset(Isolate, InOther.GContext.Get(Isolate)); 55 | GObject.Reset(Isolate, InOther.GObject.Get(Isolate)); 56 | JsEnvLifeCycleTracker = DataTransfer::GetJsEnvLifeCycleTracker(Isolate); 57 | } 58 | 59 | Object& operator=(const Object& InOther) 60 | { 61 | Isolate = InOther.Isolate; 62 | v8::Isolate::Scope IsolateScope(Isolate); 63 | v8::HandleScope HandleScope(Isolate); 64 | GContext.Reset(Isolate, InOther.GContext.Get(Isolate)); 65 | GObject.Reset(Isolate, InOther.GObject.Get(Isolate)); 66 | JsEnvLifeCycleTracker = DataTransfer::GetJsEnvLifeCycleTracker(Isolate); 67 | return *this; 68 | } 69 | 70 | ~Object() 71 | { 72 | if (JsEnvLifeCycleTracker.expired()) 73 | { 74 | GObject.Empty(); 75 | GContext.Empty(); 76 | } 77 | } 78 | 79 | template 80 | T Get(const char* key) const 81 | { 82 | if (JsEnvLifeCycleTracker.expired()) 83 | { 84 | return {}; 85 | } 86 | v8::Isolate::Scope IsolateScope(Isolate); 87 | v8::HandleScope HandleScope(Isolate); 88 | auto Context = GContext.Get(Isolate); 89 | v8::Context::Scope ContextScope(Context); 90 | auto Object = GObject.Get(Isolate); 91 | 92 | auto MaybeValue = Object->Get(Context, puerts::v8_impl::Converter::toScript(Context, key)); 93 | v8::Local Val; 94 | if (MaybeValue.ToLocal(&Val)) 95 | { 96 | return puerts::v8_impl::Converter::toCpp(Context, Val); 97 | } 98 | return {}; 99 | } 100 | 101 | template 102 | void Set(const char* key, T val) const 103 | { 104 | if (JsEnvLifeCycleTracker.expired()) 105 | { 106 | return; 107 | } 108 | v8::Isolate::Scope IsolateScope(Isolate); 109 | v8::HandleScope HandleScope(Isolate); 110 | auto Context = GContext.Get(Isolate); 111 | v8::Context::Scope ContextScope(Context); 112 | auto Object = GObject.Get(Isolate); 113 | 114 | auto _UnUsed = Object->Set(Context, puerts::v8_impl::Converter::toScript(Context, key), 115 | puerts::v8_impl::Converter::toScript(Context, val)); 116 | } 117 | 118 | bool IsValid() const 119 | { 120 | if (JsEnvLifeCycleTracker.expired() || !Isolate || GContext.IsEmpty() || GObject.IsEmpty()) 121 | return false; 122 | v8::Isolate::Scope IsolateScope(Isolate); 123 | v8::HandleScope HandleScope(Isolate); 124 | auto Context = GContext.Get(Isolate); 125 | v8::Context::Scope ContextScope(Context); 126 | auto Object = GObject.Get(Isolate); 127 | return !Object.IsEmpty() && Object->IsObject(); 128 | } 129 | 130 | v8::Isolate* Isolate; 131 | v8::Global GContext; 132 | v8::Global GObject; 133 | 134 | std::weak_ptr JsEnvLifeCycleTracker; 135 | 136 | friend struct puerts::v8_impl::Converter; 137 | }; 138 | 139 | class Function : public Object 140 | { 141 | public: 142 | Function() 143 | { 144 | } 145 | 146 | Function(v8::Local context, v8::Local object) : Object(context, object) 147 | { 148 | } 149 | 150 | template 151 | void Action(Args... cppArgs) const 152 | { 153 | if (JsEnvLifeCycleTracker.expired()) 154 | { 155 | return; 156 | } 157 | v8::Isolate::Scope IsolateScope(Isolate); 158 | v8::HandleScope HandleScope(Isolate); 159 | auto Context = GContext.Get(Isolate); 160 | v8::Context::Scope ContextScope(Context); 161 | 162 | auto Object = GObject.Get(Isolate); 163 | 164 | v8::TryCatch TryCatch(Isolate); 165 | 166 | auto _UnUsed = InvokeHelper(Context, Object, cppArgs...); 167 | 168 | if (TryCatch.HasCaught()) 169 | { 170 | REPORT_EXCEPTION(Isolate, &TryCatch); 171 | } 172 | } 173 | 174 | template 175 | Ret Func(Args... cppArgs) const 176 | { 177 | if (JsEnvLifeCycleTracker.expired()) 178 | { 179 | return {}; 180 | } 181 | v8::Isolate::Scope IsolateScope(Isolate); 182 | v8::HandleScope HandleScope(Isolate); 183 | auto Context = GContext.Get(Isolate); 184 | v8::Context::Scope ContextScope(Context); 185 | 186 | auto Object = GObject.Get(Isolate); 187 | 188 | v8::TryCatch TryCatch(Isolate); 189 | 190 | auto MaybeRet = InvokeHelper(Context, Object, cppArgs...); 191 | 192 | if (TryCatch.HasCaught()) 193 | { 194 | REPORT_EXCEPTION(Isolate, &TryCatch); 195 | } 196 | 197 | if (!MaybeRet.IsEmpty()) 198 | { 199 | return puerts::v8_impl::Converter::toCpp(Context, MaybeRet.ToLocalChecked()); 200 | } 201 | return {}; 202 | } 203 | 204 | bool IsValid() const 205 | { 206 | if (JsEnvLifeCycleTracker.expired() || !Isolate || GContext.IsEmpty() || GObject.IsEmpty()) 207 | return false; 208 | v8::Isolate::Scope IsolateScope(Isolate); 209 | v8::HandleScope HandleScope(Isolate); 210 | auto Context = GContext.Get(Isolate); 211 | v8::Context::Scope ContextScope(Context); 212 | auto Object = GObject.Get(Isolate); 213 | return !Object.IsEmpty() && Object->IsFunction(); 214 | } 215 | 216 | private: 217 | template 218 | auto InvokeHelper(v8::Local& Context, v8::Local& Object, Args... CppArgs) const 219 | { 220 | v8::Local Argv[sizeof...(Args)]{puerts::v8_impl::Converter::toScript(Context, CppArgs)...}; 221 | return Object.As()->Call(Context, v8::Undefined(Isolate), sizeof...(Args), Argv); 222 | } 223 | 224 | auto InvokeHelper(v8::Local& Context, v8::Local& Object) const 225 | { 226 | return Object.As()->Call(Context, v8::Undefined(Isolate), 0, nullptr); 227 | } 228 | 229 | friend struct puerts::v8_impl::Converter; 230 | }; 231 | 232 | } // namespace v8_impl 233 | 234 | template <> 235 | struct ScriptTypeName 236 | { 237 | static constexpr auto value() 238 | { 239 | return internal::Literal("object"); 240 | } 241 | }; 242 | 243 | template <> 244 | struct ScriptTypeName 245 | { 246 | static constexpr auto value() 247 | { 248 | return internal::Literal("()=>void"); 249 | } 250 | }; 251 | 252 | namespace v8_impl 253 | { 254 | template <> 255 | struct Converter 256 | { 257 | static v8::Local toScript(v8::Local context, Object value) 258 | { 259 | return value.GObject.Get(context->GetIsolate()); 260 | } 261 | 262 | static Object toCpp(v8::Local context, const v8::Local& value) 263 | { 264 | return Object(context, value.As()); 265 | } 266 | 267 | static bool accept(v8::Local context, const v8::Local& value) 268 | { 269 | return value->IsObject(); 270 | } 271 | }; 272 | 273 | template <> 274 | struct Converter 275 | { 276 | static v8::Local toScript(v8::Local context, Function value) 277 | { 278 | return value.GObject.Get(context->GetIsolate()); 279 | } 280 | 281 | static Function toCpp(v8::Local context, const v8::Local& value) 282 | { 283 | return Function(context, value.As()); 284 | } 285 | 286 | static bool accept(v8::Local context, const v8::Local& value) 287 | { 288 | return value->IsFunction(); 289 | } 290 | }; 291 | 292 | #include "StdFunctionConverter.hpp" 293 | } // namespace v8_impl 294 | 295 | } // namespace puerts 296 | -------------------------------------------------------------------------------- /puertstest/puerts/include/DataTransfer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #if USING_IN_UNREAL_ENGINE 12 | #include "CoreMinimal.h" 13 | #include "UObject/Package.h" 14 | #else 15 | #include "JSClassRegister.h" 16 | #endif 17 | 18 | #pragma warning(push, 0) 19 | #include "v8.h" 20 | #pragma warning(pop) 21 | 22 | #if !defined(MAPPER_ISOLATE_DATA_POS) 23 | #define MAPPER_ISOLATE_DATA_POS 0 24 | #endif 25 | 26 | #define RELEASED_UOBJECT ((UObject*) 12) 27 | #define RELEASED_UOBJECT_MEMBER ((void*) 12) 28 | 29 | namespace puerts 30 | { 31 | template 32 | struct TOuterLinker 33 | { 34 | V8_INLINE static void Link(v8::Local Context, v8::Local Outer, v8::Local Inner) 35 | { 36 | } 37 | }; 38 | 39 | V8_INLINE void LinkOuterImpl(v8::Local Context, v8::Local Outer, v8::Local Inner) 40 | { 41 | #ifdef WITH_OUTER_LINK 42 | Inner.As()->Set(Context, 0, Outer); 43 | #endif 44 | } 45 | 46 | #if USING_IN_UNREAL_ENGINE 47 | FORCEINLINE UScriptStruct* GetScriptStructInCoreUObject(const TCHAR* Name) 48 | { 49 | static UPackage* CoreUObjectPkg = FindObjectChecked(nullptr, TEXT("/Script/CoreUObject")); 50 | return FindObjectChecked(CoreUObjectPkg, Name); 51 | } 52 | 53 | template 54 | struct TScriptStructTraits 55 | { 56 | }; 57 | 58 | template <> 59 | struct TScriptStructTraits 60 | { 61 | static UScriptStruct* Get() 62 | { 63 | return TBaseStructure::Get(); 64 | } 65 | }; 66 | 67 | template <> 68 | struct TScriptStructTraits 69 | { 70 | static UScriptStruct* Get() 71 | { 72 | return TBaseStructure::Get(); 73 | } 74 | }; 75 | 76 | template <> 77 | struct TScriptStructTraits 78 | { 79 | static UScriptStruct* Get() 80 | { 81 | return TBaseStructure::Get(); 82 | } 83 | }; 84 | 85 | template <> 86 | struct TScriptStructTraits 87 | { 88 | static UScriptStruct* Get() 89 | { 90 | return TBaseStructure::Get(); 91 | } 92 | }; 93 | 94 | template <> 95 | struct TScriptStructTraits 96 | { 97 | static UScriptStruct* Get() 98 | { 99 | return TBaseStructure::Get(); 100 | } 101 | }; 102 | 103 | template <> 104 | struct TScriptStructTraits 105 | { 106 | static UScriptStruct* Get() 107 | { 108 | return TBaseStructure::Get(); 109 | } 110 | }; 111 | 112 | template <> 113 | struct TScriptStructTraits 114 | { 115 | static UScriptStruct* Get() 116 | { 117 | return TBaseStructure::Get(); 118 | } 119 | }; 120 | 121 | template <> 122 | struct TScriptStructTraits 123 | { 124 | static UScriptStruct* Get() 125 | { 126 | return TBaseStructure::Get(); 127 | } 128 | }; 129 | 130 | template <> 131 | struct TScriptStructTraits 132 | { 133 | static UScriptStruct* Get() 134 | { 135 | return TBaseStructure::Get(); 136 | } 137 | }; 138 | 139 | template <> 140 | struct TScriptStructTraits 141 | { 142 | static UScriptStruct* Get() 143 | { 144 | return TBaseStructure::Get(); 145 | } 146 | }; 147 | 148 | template <> 149 | struct TScriptStructTraits 150 | { 151 | static UScriptStruct* Get() 152 | { 153 | return GetScriptStructInCoreUObject(TEXT("IntPoint")); 154 | } 155 | }; 156 | 157 | template <> 158 | struct TScriptStructTraits 159 | { 160 | static UScriptStruct* Get() 161 | { 162 | return GetScriptStructInCoreUObject(TEXT("IntVector")); 163 | } 164 | }; 165 | 166 | template <> 167 | struct TScriptStructTraits 168 | { 169 | static UScriptStruct* Get() 170 | { 171 | return GetScriptStructInCoreUObject(TEXT("Plane")); 172 | } 173 | }; 174 | 175 | template 176 | using ToVoid = void; 177 | 178 | template 179 | struct HasStaticStructHelper : std::false_type 180 | { 181 | }; 182 | 183 | template 184 | struct HasStaticStructHelper> : std::true_type 185 | { 186 | }; 187 | 188 | template 189 | struct TScriptStructTraits::value>::type> 190 | { 191 | static UScriptStruct* Get() 192 | { 193 | return T::StaticStruct(); 194 | } 195 | }; 196 | 197 | template 198 | struct TOuterLinker::Get)>> 199 | { 200 | V8_INLINE static void Link(v8::Local Context, v8::Local Outer, v8::Local Inner) 201 | { 202 | LinkOuterImpl(Context, Outer, Inner); 203 | } 204 | }; 205 | #endif 206 | 207 | class JSENV_API DataTransfer 208 | { 209 | public: 210 | FORCEINLINE static void* MakeAddressWithHighPartOfTwo(void* Address1, void* Address2) 211 | { 212 | UPTRINT High = reinterpret_cast(Address1) & (((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //清除低位 213 | UPTRINT Low = (reinterpret_cast(Address2) >> (sizeof(UPTRINT) / 2)) & 214 | ~(((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //右移,然后清除高位 215 | return reinterpret_cast(High | Low); 216 | } 217 | 218 | FORCEINLINE static void SplitAddressToHighPartOfTwo(const void* Address, UPTRINT& High, UPTRINT& Low) 219 | { 220 | High = reinterpret_cast(Address) & (((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //清除低位 221 | Low = reinterpret_cast(Address) << (sizeof(UPTRINT) / 2); 222 | } 223 | 224 | template 225 | FORCEINLINE static T* GetPointerFast(v8::Local Object, int Index) 226 | { 227 | int P1 = Index << 1; 228 | int P2 = P1 + 1; 229 | if (V8_LIKELY(Object->InternalFieldCount() > P2)) 230 | { 231 | return static_cast(MakeAddressWithHighPartOfTwo( 232 | Object->GetAlignedPointerFromInternalField(P1), Object->GetAlignedPointerFromInternalField(P2))); 233 | } 234 | return nullptr; 235 | } 236 | 237 | template 238 | FORCEINLINE static T* GetPointerFast(v8::Local Object) 239 | { 240 | if (V8_LIKELY(Object->InternalFieldCount() > 1)) 241 | { 242 | return static_cast(MakeAddressWithHighPartOfTwo( 243 | Object->GetAlignedPointerFromInternalField(0), Object->GetAlignedPointerFromInternalField(1))); 244 | } 245 | return nullptr; 246 | } 247 | 248 | //替代 Object->SetAlignedPointerInInternalField(Index, Ptr); 249 | FORCEINLINE static void SetPointer(v8::Isolate* Isolate, v8::Local Object, const void* Ptr, int Index) 250 | { 251 | // Object->SetInternalField(Index, v8::External::New(Isolate, Ptr)); 252 | // Object->SetAlignedPointerInInternalField(Index, Ptr); 253 | UPTRINT High; 254 | UPTRINT Low; 255 | SplitAddressToHighPartOfTwo(Ptr, High, Low); 256 | Object->SetAlignedPointerInInternalField(Index * 2, reinterpret_cast(High)); 257 | Object->SetAlignedPointerInInternalField(Index * 2 + 1, reinterpret_cast(Low)); 258 | } 259 | 260 | template 261 | FORCEINLINE static T* IsolateData(v8::Isolate* Isolate) 262 | { 263 | return static_cast(Isolate->GetData(MAPPER_ISOLATE_DATA_POS)); 264 | } 265 | 266 | static v8::Local FindOrAddCData( 267 | v8::Isolate* Isolate, v8::Local Context, const void* TypeId, const void* Ptr, bool PassByPointer); 268 | 269 | static bool IsInstanceOf(v8::Isolate* Isolate, const void* TypeId, v8::Local JsObject); 270 | 271 | static v8::Local UnRef(v8::Isolate* Isolate, const v8::Local& Value); 272 | 273 | static void UpdateRef(v8::Isolate* Isolate, v8::Local Outer, const v8::Local& Value); 274 | 275 | static std::weak_ptr GetJsEnvLifeCycleTracker(v8::Isolate* Isolate); 276 | 277 | #if USING_IN_UNREAL_ENGINE 278 | template 279 | static v8::Local FindOrAddObject(v8::Isolate* Isolate, v8::Local& Context, T* UEObject) 280 | { 281 | return FindOrAddObject(Isolate, Context, UEObject == nullptr ? T::StaticClass() : UEObject->GetClass(), UEObject); 282 | } 283 | 284 | static v8::Local FindOrAddObject( 285 | v8::Isolate* Isolate, v8::Local& Context, UClass* Class, UObject* UEObject); 286 | 287 | template 288 | static v8::Local FindOrAddStruct(v8::Isolate* Isolate, v8::Local Context, void* Ptr, bool PassByPointer) 289 | { 290 | return FindOrAddStruct(Isolate, Context, TScriptStructTraits::Get(), Ptr, PassByPointer); 291 | } 292 | 293 | static v8::Local FindOrAddStruct( 294 | v8::Isolate* Isolate, v8::Local Context, UScriptStruct* ScriptStruct, void* Ptr, bool PassByPointer); 295 | 296 | template 297 | static bool IsInstanceOf(v8::Isolate* Isolate, v8::Local JsObject) 298 | { 299 | return IsInstanceOf(Isolate, TScriptStructTraits::Get(), JsObject); 300 | } 301 | 302 | static bool IsInstanceOf(v8::Isolate* Isolate, UStruct* Struct, v8::Local JsObject); 303 | 304 | static FString ToFString(v8::Isolate* Isolate, v8::Local Value); 305 | 306 | static void ThrowException(v8::Isolate* Isolate, const char* Message); 307 | #endif 308 | 309 | template 310 | FORCEINLINE static void LinkOuter(v8::Local Context, v8::Local Outer, v8::Local Inner) 311 | { 312 | TOuterLinker::Link(Context, Outer, Inner); 313 | } 314 | }; 315 | } // namespace puerts 316 | -------------------------------------------------------------------------------- /pesapitest/pesapiv8impl/include/pesapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #ifndef PS_API_H_ 10 | #define PS_API_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | // Portable Embedded Scripting API 17 | 18 | #define PESAPI_VERSION 6 19 | 20 | #define PESAPI_EXTERN 21 | 22 | #if defined(__APPLE__) && defined(BUILDING_PES_EXTENSION) && !defined(PESAPI_ADPT_C) 23 | #include "TargetConditionals.h" 24 | #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR 25 | #define USING_OBJC_REFLECTION 26 | #endif 27 | #endif 28 | 29 | #ifdef USING_OBJC_REFLECTION 30 | #import 31 | #endif 32 | 33 | #ifdef _WIN32 34 | #define PESAPI_MODULE_EXPORT __declspec(dllexport) 35 | #else 36 | #define PESAPI_MODULE_EXPORT __attribute__((visibility("default"))) 37 | #endif 38 | 39 | #if defined(__GNUC__) 40 | #define PESAPI_NO_RETURN __attribute__((noreturn)) 41 | #elif defined(_WIN32) 42 | #define PESAPI_NO_RETURN __declspec(noreturn) 43 | #else 44 | #define PESAPI_NO_RETURN 45 | #endif 46 | 47 | #ifdef __cplusplus 48 | #define EXTERN_C_START \ 49 | extern "C" \ 50 | { 51 | #define EXTERN_C_END } 52 | #else 53 | #define EXTERN_C_START 54 | #define EXTERN_C_END 55 | #endif 56 | 57 | #define PESAPI_MODULE_INITIALIZER_X(base, module, version) PESAPI_MODULE_INITIALIZER_X_HELPER(base, module, version) 58 | 59 | #define PESAPI_MODULE_INITIALIZER_X_HELPER(base, module, version) base##module##_v##version 60 | 61 | #define PESAPI_MODULE_INITIALIZER_BASE pesapi_register_ 62 | 63 | #define PESAPI_MODULE_INITIALIZER(modname) PESAPI_MODULE_INITIALIZER_X(PESAPI_MODULE_INITIALIZER_BASE, modname, PESAPI_VERSION) 64 | 65 | #ifdef USING_OBJC_REFLECTION 66 | 67 | #define PESAPI_MODULE(modname, initfunc) \ 68 | @interface PESAPI_MODULE_INITIALIZER (modname) : NSObject \ 69 | @end \ 70 | @implementation PESAPI_MODULE_INITIALIZER (modname) \ 71 | +(void) initlib : (pesapi_func_ptr*) func_ptr_array \ 72 | { \ 73 | pesapi_init(func_ptr_array); \ 74 | initfunc(); \ 75 | } \ 76 | @end 77 | 78 | #else 79 | 80 | #define PESAPI_MODULE(modname, initfunc) \ 81 | EXTERN_C_START \ 82 | PESAPI_MODULE_EXPORT void PESAPI_MODULE_INITIALIZER(modname)(pesapi_func_ptr * func_ptr_array); \ 83 | PESAPI_MODULE_EXPORT const char* PESAPI_MODULE_INITIALIZER(dynamic)(pesapi_func_ptr * func_ptr_array); \ 84 | EXTERN_C_END \ 85 | PESAPI_MODULE_EXPORT void PESAPI_MODULE_INITIALIZER(modname)(pesapi_func_ptr * func_ptr_array) \ 86 | { \ 87 | pesapi_init(func_ptr_array); \ 88 | initfunc(); \ 89 | } \ 90 | PESAPI_MODULE_EXPORT const char* PESAPI_MODULE_INITIALIZER(dynamic)(pesapi_func_ptr * func_ptr_array) \ 91 | { \ 92 | if (func_ptr_array) \ 93 | { \ 94 | pesapi_init(func_ptr_array); \ 95 | initfunc(); \ 96 | } \ 97 | return #modname; \ 98 | } 99 | 100 | #endif 101 | 102 | EXTERN_C_START 103 | 104 | typedef struct pesapi_env__* pesapi_env; 105 | typedef struct pesapi_env_holder__* pesapi_env_holder; 106 | typedef struct pesapi_value__* pesapi_value; 107 | typedef struct pesapi_value_holder__* pesapi_value_holder; 108 | typedef struct pesapi_callback_info__* pesapi_callback_info; 109 | typedef struct pesapi_scope__* pesapi_scope; 110 | typedef struct pesapi_type_info__* pesapi_type_info; 111 | typedef struct pesapi_signature_info__* pesapi_signature_info; 112 | typedef struct pesapi_property_descriptor__* pesapi_property_descriptor; 113 | 114 | typedef void (*pesapi_callback)(pesapi_callback_info info); 115 | typedef void* (*pesapi_constructor)(pesapi_callback_info info); 116 | typedef void (*pesapi_finalize)(void* Ptr); 117 | typedef void (*pesapi_func_ptr)(void); 118 | 119 | #ifdef BUILDING_PES_EXTENSION 120 | PESAPI_EXTERN void pesapi_init(pesapi_func_ptr* func_array); 121 | #else 122 | PESAPI_MODULE_EXPORT int pesapi_load_addon(const char* path, const char* module_name); 123 | #endif 124 | 125 | // value process 126 | PESAPI_EXTERN pesapi_value pesapi_create_null(pesapi_env env); 127 | PESAPI_EXTERN pesapi_value pesapi_create_undefined(pesapi_env env); 128 | PESAPI_EXTERN pesapi_value pesapi_create_boolean(pesapi_env env, bool value); 129 | PESAPI_EXTERN pesapi_value pesapi_create_int32(pesapi_env env, int32_t value); 130 | PESAPI_EXTERN pesapi_value pesapi_create_uint32(pesapi_env env, uint32_t value); 131 | PESAPI_EXTERN pesapi_value pesapi_create_int64(pesapi_env env, int64_t value); 132 | PESAPI_EXTERN pesapi_value pesapi_create_uint64(pesapi_env env, uint64_t value); 133 | PESAPI_EXTERN pesapi_value pesapi_create_double(pesapi_env env, double value); 134 | PESAPI_EXTERN pesapi_value pesapi_create_string_utf8(pesapi_env env, const char* str, size_t length); 135 | PESAPI_EXTERN pesapi_value pesapi_create_binary(pesapi_env env, void* str, size_t length); 136 | 137 | PESAPI_EXTERN bool pesapi_get_value_bool(pesapi_env env, pesapi_value value); 138 | PESAPI_EXTERN int32_t pesapi_get_value_int32(pesapi_env env, pesapi_value value); 139 | PESAPI_EXTERN uint32_t pesapi_get_value_uint32(pesapi_env env, pesapi_value value); 140 | PESAPI_EXTERN int64_t pesapi_get_value_int64(pesapi_env env, pesapi_value value); 141 | PESAPI_EXTERN uint64_t pesapi_get_value_uint64(pesapi_env env, pesapi_value value); 142 | PESAPI_EXTERN double pesapi_get_value_double(pesapi_env env, pesapi_value value); 143 | PESAPI_EXTERN const char* pesapi_get_value_string_utf8(pesapi_env env, pesapi_value value, char* buf, size_t* bufsize); 144 | PESAPI_EXTERN void* pesapi_get_value_binary(pesapi_env env, pesapi_value pvalue, size_t* bufsize); 145 | 146 | PESAPI_EXTERN bool pesapi_is_null(pesapi_env env, pesapi_value value); 147 | PESAPI_EXTERN bool pesapi_is_undefined(pesapi_env env, pesapi_value value); 148 | PESAPI_EXTERN bool pesapi_is_boolean(pesapi_env env, pesapi_value value); 149 | PESAPI_EXTERN bool pesapi_is_int32(pesapi_env env, pesapi_value value); 150 | PESAPI_EXTERN bool pesapi_is_uint32(pesapi_env env, pesapi_value value); 151 | PESAPI_EXTERN bool pesapi_is_int64(pesapi_env env, pesapi_value value); 152 | PESAPI_EXTERN bool pesapi_is_uint64(pesapi_env env, pesapi_value value); 153 | PESAPI_EXTERN bool pesapi_is_double(pesapi_env env, pesapi_value value); 154 | PESAPI_EXTERN bool pesapi_is_string(pesapi_env env, pesapi_value value); 155 | PESAPI_EXTERN bool pesapi_is_object(pesapi_env env, pesapi_value value); 156 | PESAPI_EXTERN bool pesapi_is_function(pesapi_env env, pesapi_value value); 157 | PESAPI_EXTERN bool pesapi_is_binary(pesapi_env env, pesapi_value value); 158 | 159 | PESAPI_EXTERN pesapi_value pesapi_create_native_object(pesapi_env env, const void* class_id, void* object_ptr, bool copy); 160 | PESAPI_EXTERN void* pesapi_get_native_object_ptr(pesapi_env env, pesapi_value value); 161 | PESAPI_EXTERN const void* pesapi_get_native_object_typeid(pesapi_env env, pesapi_value value); 162 | PESAPI_EXTERN bool pesapi_is_native_object(pesapi_env env, const void* class_id, pesapi_value value); 163 | 164 | PESAPI_EXTERN pesapi_value pesapi_create_ref(pesapi_env env, pesapi_value value); 165 | PESAPI_EXTERN pesapi_value pesapi_get_value_ref(pesapi_env env, pesapi_value value); 166 | PESAPI_EXTERN void pesapi_update_value_ref(pesapi_env env, pesapi_value ref, pesapi_value value); 167 | PESAPI_EXTERN bool pesapi_is_ref(pesapi_env env, pesapi_value value); 168 | 169 | PESAPI_EXTERN int pesapi_get_args_len(pesapi_callback_info info); 170 | PESAPI_EXTERN pesapi_value pesapi_get_arg(pesapi_callback_info info, int index); 171 | PESAPI_EXTERN pesapi_env pesapi_get_env(pesapi_callback_info info); 172 | PESAPI_EXTERN pesapi_value pesapi_get_this(pesapi_callback_info info); 173 | PESAPI_EXTERN pesapi_value pesapi_get_holder(pesapi_callback_info info); 174 | PESAPI_EXTERN void* pesapi_get_userdata(pesapi_callback_info info); 175 | PESAPI_EXTERN void* pesapi_get_constructor_userdata(pesapi_callback_info info); 176 | PESAPI_EXTERN void pesapi_add_return(pesapi_callback_info info, pesapi_value value); 177 | PESAPI_EXTERN void pesapi_throw_by_string(pesapi_callback_info pinfo, const char* msg); 178 | 179 | PESAPI_EXTERN pesapi_env_holder pesapi_hold_env(pesapi_env env); 180 | PESAPI_EXTERN pesapi_env pesapi_get_env_from_holder(pesapi_env_holder env_holder); 181 | PESAPI_EXTERN pesapi_env_holder pesapi_duplicate_env_holder(pesapi_env_holder env_holder); 182 | PESAPI_EXTERN void pesapi_release_env_holder(pesapi_env_holder env_holder); 183 | 184 | PESAPI_EXTERN pesapi_scope pesapi_open_scope(pesapi_env_holder env_holder); 185 | PESAPI_EXTERN bool pesapi_has_caught(pesapi_scope scope); 186 | PESAPI_EXTERN const char* pesapi_get_exception_as_string(pesapi_scope scope, bool with_stack); 187 | PESAPI_EXTERN void pesapi_close_scope(pesapi_scope scope); 188 | 189 | PESAPI_EXTERN pesapi_value_holder pesapi_hold_value(pesapi_env env, pesapi_value value); 190 | PESAPI_EXTERN pesapi_value_holder pesapi_duplicate_value_holder(pesapi_value_holder value_holder); 191 | PESAPI_EXTERN void pesapi_release_value_holder(pesapi_value_holder value_holder); 192 | PESAPI_EXTERN pesapi_value pesapi_get_value_from_holder(pesapi_env env, pesapi_value_holder value_holder); 193 | 194 | PESAPI_EXTERN pesapi_value pesapi_get_property(pesapi_env env, pesapi_value object, const char* key); 195 | PESAPI_EXTERN void pesapi_set_property(pesapi_env env, pesapi_value object, const char* key, pesapi_value value); 196 | 197 | PESAPI_EXTERN pesapi_value pesapi_get_property_uint32(pesapi_env env, pesapi_value object, uint32_t key); 198 | PESAPI_EXTERN void pesapi_set_property_uint32(pesapi_env env, pesapi_value object, uint32_t key, pesapi_value value); 199 | 200 | PESAPI_EXTERN pesapi_value pesapi_call_function( 201 | pesapi_env env, pesapi_value func, pesapi_value this_object, int argc, const pesapi_value argv[]); 202 | 203 | PESAPI_EXTERN pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size, const char* path); 204 | 205 | PESAPI_EXTERN pesapi_type_info pesapi_alloc_type_infos(size_t count); 206 | 207 | PESAPI_EXTERN void pesapi_set_type_info( 208 | pesapi_type_info type_infos, size_t index, const char* name, bool is_pointer, bool is_const, bool is_ref, bool is_primitive); 209 | 210 | PESAPI_EXTERN pesapi_signature_info pesapi_create_signature_info( 211 | pesapi_type_info return_type, size_t parameter_count, pesapi_type_info parameter_types); 212 | 213 | PESAPI_EXTERN pesapi_property_descriptor pesapi_alloc_property_descriptors(size_t count); 214 | 215 | // using pesapi_get_userdata obtain userdata in callback 216 | PESAPI_EXTERN void pesapi_set_method_info(pesapi_property_descriptor properties, size_t index, const char* name, bool is_static, 217 | pesapi_callback method, void* userdata, pesapi_signature_info signature_info); 218 | 219 | PESAPI_EXTERN void pesapi_set_property_info(pesapi_property_descriptor properties, size_t index, const char* name, bool is_static, 220 | pesapi_callback getter, pesapi_callback setter, void* userdata, pesapi_type_info type_info); 221 | 222 | PESAPI_EXTERN void pesapi_define_class(const void* type_id, const void* super_type_id, const char* type_name, 223 | pesapi_constructor constructor, pesapi_finalize finalize, size_t property_count, pesapi_property_descriptor properties, 224 | void* userdata); 225 | 226 | EXTERN_C_END 227 | 228 | #endif 229 | -------------------------------------------------------------------------------- /puertstest/puerts/src/CppObjectMapper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #include "CppObjectMapper.h" 10 | #include "DataTransfer.h" 11 | 12 | namespace puerts 13 | { 14 | template 15 | inline void __USE(T&&) 16 | { 17 | } 18 | 19 | static void ThrowException(v8::Isolate* Isolate, const char* Message) 20 | { 21 | auto ExceptionStr = v8::String::NewFromUtf8(Isolate, Message, v8::NewStringType::kNormal).ToLocalChecked(); 22 | Isolate->ThrowException(v8::Exception::Error(ExceptionStr)); 23 | } 24 | 25 | void FCppObjectMapper::LoadCppType(const v8::FunctionCallbackInfo& Info) 26 | { 27 | v8::Isolate* Isolate = Info.GetIsolate(); 28 | v8::Isolate::Scope IsolateScope(Isolate); 29 | v8::HandleScope HandleScope(Isolate); 30 | v8::Local Context = Isolate->GetCurrentContext(); 31 | v8::Context::Scope ContextScope(Context); 32 | 33 | if (!Info[0]->IsString()) 34 | { 35 | ThrowException(Isolate, "#0 argument expect a string"); 36 | return; 37 | } 38 | 39 | std::string TypeName = *(v8::String::Utf8Value(Isolate, Info[0])); 40 | 41 | auto ClassDef = FindCppTypeClassByName(TypeName); 42 | if (ClassDef) 43 | { 44 | Info.GetReturnValue().Set(GetTemplateOfClass(Isolate, ClassDef)->GetFunction(Context).ToLocalChecked()); 45 | } 46 | else 47 | { 48 | const std::string ErrMsg = "can not find type: " + TypeName; 49 | ThrowException(Isolate, ErrMsg.c_str()); 50 | } 51 | } 52 | 53 | static void PointerNew(const v8::FunctionCallbackInfo& Info) 54 | { 55 | // do nothing 56 | } 57 | 58 | void FCppObjectMapper::Initialize(v8::Isolate* InIsolate, v8::Local InContext) 59 | { 60 | auto LocalTemplate = v8::FunctionTemplate::New(InIsolate, PointerNew); 61 | LocalTemplate->InstanceTemplate()->SetInternalFieldCount(4); // 0 Ptr, 1, CDataName 62 | PointerConstructor = v8::UniquePersistent(InIsolate, LocalTemplate->GetFunction(InContext).ToLocalChecked()); 63 | } 64 | 65 | v8::Local FCppObjectMapper::FindOrAddCppObject( 66 | v8::Isolate* Isolate, v8::Local& Context, const void* TypeId, void* Ptr, bool PassByPointer) 67 | { 68 | if (Ptr == nullptr) 69 | { 70 | return v8::Undefined(Isolate); 71 | } 72 | 73 | if (PassByPointer) 74 | { 75 | auto Iter = CDataCache.find(Ptr); 76 | if (Iter != CDataCache.end()) 77 | { 78 | auto CacheNodePtr = Iter->second.Find(TypeId); 79 | if (CacheNodePtr) 80 | { 81 | return CacheNodePtr->Value.Get(Isolate); 82 | } 83 | } 84 | } 85 | 86 | // create and link 87 | auto BindTo = v8::External::New(Context->GetIsolate(), Ptr); 88 | v8::Handle Args[] = {BindTo, v8::Boolean::New(Isolate, PassByPointer)}; 89 | auto ClassDefinition = FindClassByID(TypeId); 90 | if (ClassDefinition) 91 | { 92 | return GetTemplateOfClass(Isolate, ClassDefinition) 93 | ->GetFunction(Context) 94 | .ToLocalChecked() 95 | ->NewInstance(Context, 2, Args) 96 | .ToLocalChecked(); 97 | } 98 | else 99 | { 100 | auto Result = PointerConstructor.Get(Isolate)->NewInstance(Context, 0, nullptr).ToLocalChecked(); 101 | DataTransfer::SetPointer(Isolate, Result, Ptr, 0); 102 | DataTransfer::SetPointer(Isolate, Result, TypeId, 1); 103 | return Result; 104 | } 105 | } 106 | 107 | bool FCppObjectMapper::IsInstanceOfCppObject(const void* TypeId, v8::Local JsObject) 108 | { 109 | return DataTransfer::GetPointerFast(JsObject, 1) == TypeId; 110 | } 111 | 112 | std::weak_ptr FCppObjectMapper::GetJsEnvLifeCycleTracker() 113 | { 114 | return std::weak_ptr(Ref); 115 | } 116 | 117 | static void CDataNew(const v8::FunctionCallbackInfo& Info) 118 | { 119 | v8::Isolate* Isolate = Info.GetIsolate(); 120 | v8::Isolate::Scope IsolateScope(Isolate); 121 | v8::HandleScope HandleScope(Isolate); 122 | v8::Local Context = Isolate->GetCurrentContext(); 123 | v8::Context::Scope ContextScope(Context); 124 | 125 | if (Info.IsConstructCall()) 126 | { 127 | auto Self = Info.This(); 128 | JSClassDefinition* ClassDefinition = 129 | reinterpret_cast((v8::Local::Cast(Info.Data()))->Value()); 130 | void* Ptr = nullptr; 131 | bool PassByPointer = false; 132 | 133 | if (Info.Length() == 2 && Info[0]->IsExternal()) // Call by Native 134 | { 135 | Ptr = v8::Local::Cast(Info[0])->Value(); 136 | PassByPointer = Info[1]->BooleanValue(Isolate); 137 | } 138 | else // Call by js new 139 | { 140 | if (ClassDefinition->Initialize) 141 | Ptr = ClassDefinition->Initialize(Info); 142 | if (Ptr == nullptr) 143 | return; 144 | } 145 | DataTransfer::IsolateData(Isolate)->BindCppObject(Isolate, ClassDefinition, Ptr, Self, PassByPointer); 146 | } 147 | else 148 | { 149 | ThrowException(Isolate, "only call as Construct is supported!"); 150 | } 151 | } 152 | 153 | v8::Local FCppObjectMapper::GetTemplateOfClass(v8::Isolate* Isolate, const JSClassDefinition* ClassDefinition) 154 | { 155 | auto Iter = CDataNameToTemplateMap.find(ClassDefinition->TypeId); 156 | if (Iter == CDataNameToTemplateMap.end()) 157 | { 158 | auto Template = v8::FunctionTemplate::New( 159 | Isolate, CDataNew, v8::External::New(Isolate, const_cast(reinterpret_cast(ClassDefinition)))); 160 | Template->InstanceTemplate()->SetInternalFieldCount(4); 161 | 162 | JSPropertyInfo* PropertyInfo = ClassDefinition->Properties; 163 | while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Getter) 164 | { 165 | v8::PropertyAttribute PropertyAttribute = v8::DontDelete; 166 | if (!PropertyInfo->Setter) 167 | PropertyAttribute = (v8::PropertyAttribute)(PropertyAttribute | v8::ReadOnly); 168 | auto Data = PropertyInfo->Data ? static_cast>(v8::External::New(Isolate, PropertyInfo->Data)) 169 | : v8::Local(); 170 | Template->PrototypeTemplate()->SetAccessorProperty( 171 | v8::String::NewFromUtf8(Isolate, PropertyInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(), 172 | v8::FunctionTemplate::New(Isolate, PropertyInfo->Getter, Data), 173 | v8::FunctionTemplate::New(Isolate, PropertyInfo->Setter, Data), PropertyAttribute); 174 | ++PropertyInfo; 175 | } 176 | 177 | PropertyInfo = ClassDefinition->Variables; 178 | while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Getter) 179 | { 180 | v8::PropertyAttribute PropertyAttribute = v8::DontDelete; 181 | if (!PropertyInfo->Setter) 182 | PropertyAttribute = (v8::PropertyAttribute)(PropertyAttribute | v8::ReadOnly); 183 | auto Data = PropertyInfo->Data ? static_cast>(v8::External::New(Isolate, PropertyInfo->Data)) 184 | : v8::Local(); 185 | Template->SetAccessorProperty( 186 | v8::String::NewFromUtf8(Isolate, PropertyInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(), 187 | v8::FunctionTemplate::New(Isolate, PropertyInfo->Getter, Data), 188 | v8::FunctionTemplate::New(Isolate, PropertyInfo->Setter, Data), PropertyAttribute); 189 | ++PropertyInfo; 190 | } 191 | 192 | JSFunctionInfo* FunctionInfo = ClassDefinition->Methods; 193 | while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) 194 | { 195 | Template->PrototypeTemplate()->Set( 196 | v8::String::NewFromUtf8(Isolate, FunctionInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(), 197 | v8::FunctionTemplate::New(Isolate, FunctionInfo->Callback, 198 | FunctionInfo->Data ? static_cast>(v8::External::New(Isolate, FunctionInfo->Data)) 199 | : v8::Local())); 200 | ++FunctionInfo; 201 | } 202 | FunctionInfo = ClassDefinition->Functions; 203 | while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) 204 | { 205 | Template->Set(v8::String::NewFromUtf8(Isolate, FunctionInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(), 206 | v8::FunctionTemplate::New(Isolate, FunctionInfo->Callback, 207 | FunctionInfo->Data ? static_cast>(v8::External::New(Isolate, FunctionInfo->Data)) 208 | : v8::Local())); 209 | ++FunctionInfo; 210 | } 211 | 212 | if (ClassDefinition->SuperTypeId) 213 | { 214 | if (auto SuperDefinition = FindClassByID(ClassDefinition->SuperTypeId)) 215 | { 216 | Template->Inherit(GetTemplateOfClass(Isolate, SuperDefinition)); 217 | } 218 | } 219 | 220 | CDataNameToTemplateMap[ClassDefinition->TypeId] = v8::UniquePersistent(Isolate, Template); 221 | 222 | return Template; 223 | } 224 | else 225 | { 226 | return v8::Local::New(Isolate, Iter->second); 227 | } 228 | } 229 | 230 | static void CDataGarbageCollectedWithFree(const v8::WeakCallbackInfo& Data) 231 | { 232 | JSClassDefinition* ClassDefinition = Data.GetParameter(); 233 | void* Ptr = DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1)); 234 | if (ClassDefinition->Finalize) 235 | ClassDefinition->Finalize(Ptr); 236 | DataTransfer::IsolateData(Data.GetIsolate())->UnBindCppObject(ClassDefinition, Ptr); 237 | } 238 | 239 | static void CDataGarbageCollectedWithoutFree(const v8::WeakCallbackInfo& Data) 240 | { 241 | JSClassDefinition* ClassDefinition = Data.GetParameter(); 242 | void* Ptr = DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1)); 243 | DataTransfer::IsolateData(Data.GetIsolate())->UnBindCppObject(ClassDefinition, Ptr); 244 | } 245 | 246 | void FCppObjectMapper::BindCppObject( 247 | v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr, v8::Local JSObject, bool PassByPointer) 248 | { 249 | DataTransfer::SetPointer(Isolate, JSObject, Ptr, 0); 250 | DataTransfer::SetPointer(Isolate, JSObject, ClassDefinition->TypeId, 1); 251 | 252 | auto Iter = CDataCache.find(Ptr); 253 | FObjectCacheNode* CacheNodePtr; 254 | if (Iter != CDataCache.end()) 255 | { 256 | CacheNodePtr = Iter->second.Add(ClassDefinition->TypeId); 257 | } 258 | else 259 | { 260 | auto Ret = CDataCache.insert({Ptr, FObjectCacheNode(ClassDefinition->TypeId)}); 261 | CacheNodePtr = &Ret.first->second; 262 | } 263 | CacheNodePtr->Value.Reset(Isolate, JSObject); 264 | 265 | if (!PassByPointer) 266 | { 267 | CDataFinalizeMap[Ptr] = ClassDefinition->Finalize; 268 | CacheNodePtr->Value.SetWeak( 269 | ClassDefinition, CDataGarbageCollectedWithFree, v8::WeakCallbackType::kInternalFields); 270 | } 271 | else 272 | { 273 | CacheNodePtr->Value.SetWeak( 274 | ClassDefinition, CDataGarbageCollectedWithoutFree, v8::WeakCallbackType::kInternalFields); 275 | } 276 | } 277 | 278 | void FCppObjectMapper::UnBindCppObject(JSClassDefinition* ClassDefinition, void* Ptr) 279 | { 280 | CDataFinalizeMap.erase(Ptr); 281 | auto Iter = CDataCache.find(Ptr); 282 | if (Iter != CDataCache.end()) 283 | { 284 | auto Removed = Iter->second.Remove(ClassDefinition->TypeId, true); 285 | if (!Iter->second.TypeId) // last one 286 | { 287 | CDataCache.erase(Ptr); 288 | } 289 | } 290 | } 291 | 292 | void FCppObjectMapper::UnInitialize(v8::Isolate* InIsolate) 293 | { 294 | for (auto Iter = CDataFinalizeMap.begin(); Iter != CDataFinalizeMap.end(); Iter++) 295 | { 296 | if (Iter->second) 297 | Iter->second(Iter->first); 298 | } 299 | CDataCache.clear(); 300 | CDataFinalizeMap.clear(); 301 | CDataNameToTemplateMap.clear(); 302 | PointerConstructor.Reset(); 303 | } 304 | 305 | } // namespace puerts 306 | -------------------------------------------------------------------------------- /snapshottest/hello-world.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "libplatform/libplatform.h" 14 | #include "v8.h" 15 | 16 | static void Print1(const v8::FunctionCallbackInfo& info) { 17 | v8::Isolate* isolate = info.GetIsolate(); 18 | v8::Local context = isolate->GetCurrentContext(); 19 | 20 | int *p = (int*)v8::Local::Cast(info.Data())->Value(); 21 | if (p) { 22 | std::cout << "p=[" << p[0] << ", " << p[1] << ", " << p[2] << "]" << std::endl; 23 | } else { 24 | std::cout << "p=null" << std::endl; 25 | } 26 | 27 | std::string msg = *(v8::String::Utf8Value(isolate, info[0]->ToString(context).ToLocalChecked())); 28 | std::cout << "Print1:" << msg << std::endl; 29 | } 30 | 31 | static void Print2(const v8::FunctionCallbackInfo& info) { 32 | v8::Isolate* isolate = info.GetIsolate(); 33 | v8::Local context = isolate->GetCurrentContext(); 34 | 35 | int *p = (int*)v8::Local::Cast(info.Data())->Value(); 36 | if (p) { 37 | std::cout << "p=[" << p[0] << ", " << p[1] << ", " << p[2] << "]" << std::endl; 38 | } else { 39 | std::cout << "p=null" << std::endl; 40 | } 41 | 42 | std::string msg = *(v8::String::Utf8Value(isolate, info[0]->ToString(context).ToLocalChecked())); 43 | std::cout << "Print2:" << msg << std::endl; 44 | } 45 | 46 | v8::StartupData SerializeInternalFields(v8::Local holder, 47 | int index, 48 | void* data) { 49 | std::vector* s = static_cast*>(holder->GetAlignedPointerFromInternalField(index)); 50 | if (s) { 51 | std::cout << "SerializeInternalFields index: " << index 52 | << ", ver[0]: " << (*s)[0] << std::endl; 53 | 54 | 55 | int* payload = new int[s->size() + 1]; 56 | int arr_size = s->size() * sizeof(int); 57 | int size = (s->size() + 1) * sizeof(int); 58 | payload[0] = (int)s->size(); 59 | memcpy(payload + 1, s->data(), arr_size); 60 | std::cout << "SerializeInternalFields payload size: " << size << std::endl; 61 | std::cout << "ptr of InternalField:" << s << std::endl; 62 | return {(char*)payload, size}; 63 | //return {nullptr, 0}; // 不会调用DeserializeInternalFields,但GetAlignedPointerFromInternalField会返回非空值,返回的是之前指针“值” 64 | } else { 65 | void* p = (*((void**)*holder)); 66 | 67 | if (!holder->IsArrayBufferView() && !holder->IsArrayBuffer()) { 68 | std::cout << "no data, SerializeInternalFields index: " << index << ",ptr=" << p << std::endl; 69 | } 70 | 71 | //一个Int8Array会有两个对象,一个是ArrayBufferView,一个是ArrayBuffer,每个都有两个InternalFields 72 | //如果是js中new的,不用管,会自动序列化过去 73 | if (holder->IsArrayBufferView()) { 74 | std::cout << "ArrayBufferView index: " << index << ",ptr=" << p << std::endl; 75 | } 76 | if (holder->IsArrayBuffer()) { 77 | std::cout << "ArrayBuffer index: " << index << ",ptr=" << p << std::endl; 78 | } 79 | return {nullptr, 0}; 80 | } 81 | } 82 | 83 | void DeserializeInternalFields(v8::Local holder, 84 | int index, 85 | v8::StartupData payload, 86 | void* data) { 87 | std::cout << "DeserializeInternalFields payload size: " << payload.raw_size << '\n'; 88 | std::vector* s = new std::vector(); 89 | int* buffer = (int*)payload.data; 90 | int size = buffer[1]; 91 | s->insert(s->end(), buffer + 1, buffer + 1 + buffer[1]); 92 | 93 | std::cout << "DeserializeInternalFields vec.size: " << s->size() << ", ver[0]: " << (*s)[0] << '\n'; 94 | holder->SetAlignedPointerInInternalField(index, s); 95 | } 96 | 97 | int main(int argc, char* argv[]) { 98 | 99 | std::unique_ptr platform = v8::platform::NewDefaultPlatform(); 100 | v8::V8::InitializePlatform(platform.get()); 101 | v8::V8::Initialize(); 102 | size_t context_index; 103 | v8::StartupData cross_data; 104 | 105 | v8::SerializeInternalFieldsCallback si_cb = v8::SerializeInternalFieldsCallback( 106 | SerializeInternalFields, nullptr); 107 | 108 | { 109 | v8::Isolate* isolate = v8::Isolate::Allocate(); 110 | 111 | { 112 | std::vector external_refs; 113 | external_refs.reserve(100); //make external_refs.data do not change 114 | external_refs.push_back(reinterpret_cast(Print2)); 115 | external_refs.push_back(reinterpret_cast(Print1)); 116 | //看v8的处理,external_refs以nullptr作为结尾 117 | 118 | v8::SnapshotCreator snapshot_creator(isolate, external_refs.data(), &SnapshotBlob); 119 | std::cout << "external_refs.data()=" << external_refs.data() << std::endl; 120 | std::vector s; 121 | s.push_back(1); 122 | { 123 | 124 | v8::Isolate::Scope isolate_scope(isolate); 125 | 126 | // Create a stack-allocated handle scope. 127 | v8::HandleScope handle_scope(isolate); 128 | 129 | // Create a new context. 130 | v8::Local context = v8::Context::New(isolate); 131 | 132 | 133 | // Enter the context for compiling and running the hello world script. 134 | v8::Context::Scope context_scope(context); 135 | 136 | int * p = new int[] {1, 2, 3}; 137 | external_refs.push_back(reinterpret_cast(p)); 138 | std::cout << "external_refs.data()=" << external_refs.data() << std::endl; 139 | 140 | context->Global()->Set(context, v8::String::NewFromUtf8Literal(isolate, "Print"), 141 | v8::FunctionTemplate::New(isolate, Print1, v8::External::New(isolate, p))->GetFunction(context).ToLocalChecked()) 142 | .Check(); 143 | 144 | uint8_t * buff = new uint8_t[3] {6, 7, 8}; 145 | 146 | auto backing = v8::ArrayBuffer::NewBackingStore( 147 | buff, 3, 148 | [](void* Data, size_t Length, void* DeleterData) 149 | { 150 | uint8_t * b = (uint8_t *)Data; 151 | std::cout << "delete " << (void*)b << std::endl; 152 | delete b; 153 | }, nullptr); 154 | 155 | auto ab = v8::ArrayBuffer::New(isolate, std::move(backing)); 156 | 157 | void* abp = (*((void**)*ab)); 158 | std::cout << "abp:" << abp << std::endl; 159 | 160 | context->Global()->Set(context, v8::String::NewFromUtf8Literal(isolate, "ab"), ab) 161 | .Check(); 162 | 163 | //int * p2 = new int[] {1, 2, 3}; 164 | //如果External p2, 会报Unknown external reference,也就是同一个外部指针可以用多次 165 | context->Global()->Set(context, v8::String::NewFromUtf8Literal(isolate, "Print2"), 166 | v8::FunctionTemplate::New(isolate, Print2, v8::External::New(isolate, p))->GetFunction(context).ToLocalChecked()) 167 | .Check(); 168 | 169 | { 170 | const char* csource = R"( 171 | Print('hello world'); 172 | int8arr = new Int8Array(2); 173 | int8arr[0] = 10; 174 | int8arr[1] = 42; 175 | 176 | (function(){ 177 | const aba = new Int8Array(ab); 178 | Print(`aba.length=${aba.length}, aba[0,1]=[${aba[0]}, ${aba[1]}]`); 179 | })(); 180 | )"; 181 | 182 | // Create a string containing the JavaScript source code. 183 | v8::Local source = 184 | v8::String::NewFromUtf8(isolate, csource) 185 | .ToLocalChecked(); 186 | 187 | // Compile the source code. 188 | v8::Local script = 189 | v8::Script::Compile(context, source).ToLocalChecked(); 190 | 191 | // Run the script 192 | auto _unused = script->Run(context); 193 | } 194 | 195 | auto objTemplate = v8::ObjectTemplate::New(isolate); 196 | objTemplate->SetInternalFieldCount(1); 197 | auto obj = objTemplate->NewInstance(context).ToLocalChecked(); 198 | //std::vector s; //放这里局部变量析构了,序列化时就是无效内存了,说明序列化操作是在CreateBlob时操作的,而不是AddContext 199 | //s.push_back(1); 200 | obj->SetAlignedPointerInInternalField(0, static_cast(&s)); 201 | context->Global()->Set(context, v8::String::NewFromUtf8Literal(isolate, "something"), obj).Check(); 202 | 203 | // SetDefaultContext mush be call 204 | //snapshot_creator.SetDefaultContext(v8::Context::New(isolate)); //cross_data.raw_size=58486 205 | //context_index = snapshot_creator.AddContext(context, si_cb); //对应v8::Context::FromSnapshot 206 | 207 | snapshot_creator.SetDefaultContext(context, si_cb);// 对应v8::Context::New 208 | } 209 | 210 | std::cout << "create blob...." << std::endl; 211 | // Must be out of HandleScope 212 | cross_data = snapshot_creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep); 213 | std::cout << "cross_data.raw_size=" << cross_data.raw_size << ", context_index=" << context_index << std::endl; 214 | } 215 | 216 | // Dispose will crash, managed by SnapshotCreator 217 | //isolate->Dispose(); 218 | 219 | } 220 | 221 | v8::DeserializeInternalFieldsCallback di_cb = v8::DeserializeInternalFieldsCallback( 222 | DeserializeInternalFields, nullptr); 223 | 224 | { 225 | std::vector external_refs; 226 | external_refs.push_back(reinterpret_cast(Print1)); 227 | external_refs.push_back(reinterpret_cast(Print2)); 228 | int * p = new int[] {1, 2, 3}; 229 | external_refs.push_back(reinterpret_cast(p)); // 假如不给值,Data获取到的是空,个人推测是直接获取external_refs.data()[1],因为本来就没给长度,这样会越界读,毕竟危险 230 | 231 | v8::Isolate* isolate = v8::Isolate::Allocate(); 232 | 233 | v8::SnapshotCreator snapshot_creator(isolate, external_refs.data(), &cross_data); 234 | 235 | v8::Isolate::Scope isolate_scope(isolate); 236 | 237 | // Create a stack-allocated handle scope. 238 | v8::HandleScope handle_scope(isolate); 239 | 240 | // Create a new context. 241 | //v8::Local context = v8::Context::FromSnapshot(isolate, context_index, di_cb).ToLocalChecked(); 242 | v8::Local context = v8::Context::New(isolate, nullptr, v8::MaybeLocal(), v8::MaybeLocal(), di_cb); 243 | 244 | 245 | // Enter the context for compiling and running the hello world script. 246 | v8::Context::Scope context_scope(context); 247 | 248 | 249 | { 250 | v8::TryCatch try_catch(isolate); 251 | const char* csource = R"( 252 | Print('hello world'); 253 | Print(`int8arr.length=${int8arr.length}, int8arr[0,1]=[${int8arr[0]}, ${int8arr[1]}]`); 254 | 255 | (function() { 256 | const aba = new Int8Array(ab); 257 | Print(`aba.length=${aba.length}, aba[0,1]=[${aba[0]}, ${aba[1]}]`); 258 | })(); 259 | )"; 260 | 261 | // Create a string containing the JavaScript source code. 262 | v8::Local source = 263 | v8::String::NewFromUtf8(isolate, csource) 264 | .ToLocalChecked(); 265 | 266 | // Compile the source code. 267 | v8::Local script = 268 | v8::Script::Compile(context, source).ToLocalChecked(); 269 | 270 | 271 | // Run the script 272 | auto _unused = script->Run(context); 273 | std::cout << "try_catch.HasCaught():" << try_catch.HasCaught() << std::endl; 274 | } 275 | 276 | auto val = context->Global()->Get(context, v8::String::NewFromUtf8Literal(isolate, "something")).ToLocalChecked(); 277 | 278 | auto obj = v8::Local::Cast(val); 279 | 280 | std::cout << "obj->InternalFieldCount(): " << obj->InternalFieldCount() << std::endl; 281 | 282 | std::vector* ptr = static_cast*>(obj->GetAlignedPointerFromInternalField(0)); 283 | if (ptr) { 284 | std::cout << "ptr of InternalField:" << ptr << std::endl; 285 | std::cout << "InternalField vec.size: " << ptr->size() << ", ver[0]: " << (*ptr)[0] << '\n'; 286 | } else { 287 | std::cout << "InternalField is null" << std::endl; 288 | } 289 | 290 | } 291 | 292 | v8::V8::Dispose(); 293 | v8::V8::ShutdownPlatform(); 294 | return 0; 295 | } 296 | -------------------------------------------------------------------------------- /puertstest/puerts/include/TypeInfo.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #ifdef WITH_V8_FAST_CALL 13 | #include "V8FastCall.hpp" 14 | #endif 15 | 16 | #define __DefScriptTTypeName(CLSNAME, CLS) \ 17 | namespace puerts \ 18 | { \ 19 | template <> \ 20 | struct ScriptTypeName \ 21 | { \ 22 | static constexpr auto value() \ 23 | { \ 24 | return internal::Literal(#CLSNAME); \ 25 | } \ 26 | }; \ 27 | } 28 | 29 | namespace puerts 30 | { 31 | namespace internal 32 | { 33 | template 34 | class StringLiteral 35 | { 36 | public: 37 | template 38 | constexpr StringLiteral(Characters... characters) : m_value{characters..., '\0'} 39 | { 40 | } 41 | 42 | template 43 | constexpr StringLiteral(const char (&value)[N + 1], std::index_sequence dummy) : StringLiteral(value[Indexes]...) 44 | { 45 | } 46 | 47 | constexpr StringLiteral(const char (&value)[N + 1]) : StringLiteral(value, std::make_index_sequence{}) 48 | { 49 | } 50 | 51 | constexpr char operator[](const std::size_t index) const 52 | { 53 | return m_value[index]; 54 | } 55 | 56 | constexpr const char* Data() const 57 | { 58 | return m_value; 59 | } 60 | 61 | template 62 | constexpr StringLiteral Sub(std::index_sequence dummy) const 63 | { 64 | return StringLiteral(m_value[Start + Index]...); 65 | } 66 | 67 | template 68 | constexpr StringLiteral Sub() const 69 | { 70 | return Sub(std::make_index_sequence()); 71 | } 72 | 73 | private: 74 | const char m_value[N + 1]; 75 | }; 76 | 77 | template 78 | constexpr StringLiteral ConcatStrings( 79 | const Left& lhs, const Right& rhs, std::index_sequence dummy1, std::index_sequence dummy2) 80 | { 81 | return StringLiteral(lhs[IndexesLeft]..., rhs[IndexesRight]...); 82 | } 83 | 84 | template 85 | constexpr StringLiteral operator+(const StringLiteral& lhs, const StringLiteral& rhs) 86 | { 87 | return ConcatStrings(lhs, rhs, std::make_index_sequence(), std::make_index_sequence()); 88 | } 89 | 90 | template 91 | constexpr auto Literal(const char (&value)[N]) 92 | { 93 | return StringLiteral(value, typename std::make_index_sequence{}); 94 | } 95 | 96 | } // namespace internal 97 | 98 | template 99 | struct ScriptTypeName 100 | { 101 | }; 102 | 103 | template 104 | struct ScriptTypeNameWithNamespace 105 | { 106 | static constexpr auto value() 107 | { 108 | return ScriptTypeName::value(); 109 | } 110 | }; 111 | 112 | template 113 | struct ScriptTypeName 114 | { 115 | static constexpr auto value() 116 | { 117 | return ScriptTypeName::type>::value(); 118 | } 119 | }; 120 | 121 | template 122 | struct ScriptTypeName 123 | { 124 | static constexpr auto value() 125 | { 126 | return ScriptTypeName::type>::value(); 127 | } 128 | }; 129 | 130 | template 131 | struct ScriptTypeName 132 | { 133 | static constexpr auto value() 134 | { 135 | return ScriptTypeName::type>::value(); 136 | } 137 | }; 138 | 139 | template 140 | struct ScriptTypeName::value && sizeof(T) == 8>::type> 141 | { 142 | static constexpr auto value() 143 | { 144 | return internal::Literal("bigint"); 145 | } 146 | }; 147 | 148 | template 149 | struct ScriptTypeName::value>::type> 150 | { 151 | static constexpr auto value() 152 | { 153 | return internal::Literal("number"); 154 | } 155 | }; 156 | 157 | template 158 | struct ScriptTypeName::value || (std::is_integral::value && sizeof(T) < 8)>::type> 160 | { 161 | static constexpr auto value() 162 | { 163 | return internal::Literal("number"); 164 | } 165 | }; 166 | 167 | template <> 168 | struct ScriptTypeName 169 | { 170 | static constexpr auto value() 171 | { 172 | return internal::Literal("string"); 173 | } 174 | }; 175 | 176 | template <> 177 | struct ScriptTypeName 178 | { 179 | static constexpr auto value() 180 | { 181 | return internal::Literal("cstring"); 182 | } 183 | }; 184 | 185 | template <> 186 | struct ScriptTypeName 187 | { 188 | static constexpr auto value() 189 | { 190 | return internal::Literal("boolean"); 191 | } 192 | }; 193 | 194 | template <> 195 | struct ScriptTypeName 196 | { 197 | static constexpr auto value() 198 | { 199 | return internal::Literal("void"); 200 | } 201 | }; 202 | 203 | template 204 | struct StaticTypeId 205 | { 206 | static void* get() 207 | { 208 | static T* dummy = nullptr; 209 | return &dummy; 210 | } 211 | }; 212 | 213 | template 214 | struct DynamicTypeId 215 | { 216 | static void* get(T* Obj) 217 | { 218 | return StaticTypeId::get(); 219 | } 220 | }; 221 | 222 | template 223 | struct is_uetype : std::false_type 224 | { 225 | }; 226 | 227 | template 228 | struct is_objecttype : std::false_type 229 | { 230 | }; 231 | 232 | template 233 | struct is_script_type : std::false_type 234 | { 235 | }; 236 | 237 | template 238 | struct is_script_type::value && !std::is_same::value>::type> 239 | : std::true_type 240 | { 241 | }; 242 | 243 | template <> 244 | struct is_script_type : std::true_type 245 | { 246 | }; 247 | 248 | template 249 | struct ScriptTypeName::value && !std::is_const::value>::type> 250 | { 251 | static constexpr auto value() 252 | { 253 | return internal::Literal("ArrayBuffer"); 254 | } 255 | }; 256 | 257 | template <> 258 | struct ScriptTypeName 259 | { 260 | static constexpr auto value() 261 | { 262 | return internal::Literal("any"); 263 | } 264 | }; 265 | 266 | template <> 267 | struct ScriptTypeName 268 | { 269 | static constexpr auto value() 270 | { 271 | return internal::Literal("any"); 272 | } 273 | }; 274 | 275 | class CTypeInfo 276 | { 277 | public: 278 | virtual const char* Name() const = 0; 279 | virtual bool IsPointer() const = 0; 280 | virtual bool IsRef() const = 0; 281 | virtual bool IsConst() const = 0; 282 | virtual bool IsUEType() const = 0; 283 | virtual bool IsObjectType() const = 0; 284 | }; 285 | 286 | class CFunctionInfo 287 | { 288 | public: 289 | virtual const CTypeInfo* Return() const = 0; 290 | virtual unsigned int ArgumentCount() const = 0; 291 | virtual unsigned int DefaultCount() const = 0; 292 | virtual const CTypeInfo* Argument(unsigned int index) const = 0; 293 | virtual const char* CustomSignature() const = 0; 294 | #ifdef WITH_V8_FAST_CALL 295 | virtual const class v8::CFunction* FastCallInfo() const = 0; 296 | #endif 297 | }; 298 | 299 | template 300 | class CTypeInfoImpl : CTypeInfo 301 | { 302 | public: 303 | virtual const char* Name() const override 304 | { 305 | static auto NameLiteral = ScriptTypeName::value(); 306 | return NameLiteral.Data(); 307 | } 308 | virtual bool IsPointer() const override 309 | { 310 | return std::is_pointer::value && !ScriptTypePtrAsRef; 311 | }; 312 | virtual bool IsRef() const override 313 | { 314 | return (std::is_reference::value && !std::is_const::type>::value) || 315 | (std::is_pointer::value && 316 | !std::is_same::type>::type>::value && 317 | ScriptTypePtrAsRef && !IsConst() && !IsUEType() && !IsObjectType()); 318 | }; 319 | virtual bool IsConst() const override 320 | { 321 | return std::is_const::type>::type>::value; 322 | }; 323 | virtual bool IsUEType() const override 324 | { 325 | return is_uetype::type>::type>::type>::value; 326 | }; 327 | virtual bool IsObjectType() const override 328 | { 329 | return is_objecttype< 330 | typename std::remove_const::type>::type>::type>::value; 331 | }; 332 | 333 | static const CTypeInfo* get() 334 | { 335 | static CTypeInfoImpl instance; 336 | return &instance; 337 | } 338 | }; 339 | 340 | template 341 | class CFunctionInfoImpl : public CFunctionInfo 342 | { 343 | protected: 344 | const CTypeInfo* return_; 345 | const unsigned int argCount_; 346 | const CTypeInfo* arguments_[sizeof...(Args) + 1]; 347 | unsigned int defaultCount_; 348 | 349 | CFunctionInfoImpl() 350 | : return_(CTypeInfoImpl::get()) 351 | , argCount_(sizeof...(Args)) 352 | , arguments_{CTypeInfoImpl::get()...} 353 | , defaultCount_(0) 354 | { 355 | } 356 | 357 | virtual ~CFunctionInfoImpl() 358 | { 359 | } 360 | 361 | public: 362 | virtual const CTypeInfo* Return() const override 363 | { 364 | return return_; 365 | } 366 | virtual unsigned int ArgumentCount() const override 367 | { 368 | return argCount_ - StartParameter; 369 | } 370 | virtual unsigned int DefaultCount() const override 371 | { 372 | return defaultCount_; 373 | } 374 | virtual const CTypeInfo* Argument(unsigned int index) const override 375 | { 376 | return arguments_[index + StartParameter]; 377 | } 378 | virtual const char* CustomSignature() const override 379 | { 380 | return nullptr; 381 | } 382 | #ifdef WITH_V8_FAST_CALL 383 | virtual const class v8::CFunction* FastCallInfo() const override 384 | { 385 | return nullptr; 386 | }; 387 | #endif 388 | 389 | static const CFunctionInfo* get(unsigned int defaultCount) 390 | { 391 | static CFunctionInfoImpl instance{}; 392 | instance.defaultCount_ = defaultCount; 393 | return &instance; 394 | } 395 | }; 396 | 397 | template 398 | class CFunctionInfoByPtrImpl 399 | { 400 | }; 401 | 402 | template 403 | class CFunctionInfoByPtrImpl 404 | : public CFunctionInfoImpl 405 | { 406 | public: 407 | virtual ~CFunctionInfoByPtrImpl() 408 | { 409 | } 410 | #ifdef WITH_V8_FAST_CALL 411 | virtual const class v8::CFunction* FastCallInfo() const override 412 | { 413 | return V8FastCall::info(); 414 | }; 415 | #endif 416 | 417 | static const CFunctionInfo* get(unsigned int defaultCount) 418 | { 419 | static CFunctionInfoByPtrImpl instance{}; 420 | instance.defaultCount_ = defaultCount; 421 | return &instance; 422 | } 423 | }; 424 | 425 | template 426 | class CFunctionInfoByPtrImpl 427 | : public CFunctionInfoImpl 428 | { 429 | public: 430 | virtual ~CFunctionInfoByPtrImpl() 431 | { 432 | } 433 | #ifdef WITH_V8_FAST_CALL 434 | virtual const class v8::CFunction* FastCallInfo() const override 435 | { 436 | return V8FastCall::info(); 437 | }; 438 | #endif 439 | 440 | static const CFunctionInfo* get(unsigned int defaultCount) 441 | { 442 | static CFunctionInfoByPtrImpl instance{}; 443 | instance.defaultCount_ = defaultCount; 444 | return &instance; 445 | } 446 | }; 447 | 448 | template 449 | class CFunctionInfoByPtrImpl 450 | : public CFunctionInfoImpl 451 | { 452 | public: 453 | virtual ~CFunctionInfoByPtrImpl() 454 | { 455 | } 456 | #ifdef WITH_V8_FAST_CALL 457 | virtual const class v8::CFunction* FastCallInfo() const override 458 | { 459 | return V8FastCall::info(); 460 | }; 461 | #endif 462 | 463 | static const CFunctionInfo* get(unsigned int defaultCount) 464 | { 465 | static CFunctionInfoByPtrImpl instance{}; 466 | instance.defaultCount_ = defaultCount; 467 | return &instance; 468 | } 469 | }; 470 | 471 | class CFunctionInfoWithCustomSignature : public CFunctionInfo 472 | { 473 | const char* _signature; 474 | 475 | public: 476 | CFunctionInfoWithCustomSignature(const char* signature) : _signature(signature) 477 | { 478 | } 479 | 480 | virtual ~CFunctionInfoWithCustomSignature() 481 | { 482 | } 483 | 484 | virtual const CTypeInfo* Return() const override 485 | { 486 | return nullptr; 487 | } 488 | virtual unsigned int ArgumentCount() const override 489 | { 490 | return 0; 491 | } 492 | virtual unsigned int DefaultCount() const override 493 | { 494 | return 0; 495 | } 496 | virtual const CTypeInfo* Argument(unsigned int index) const override 497 | { 498 | return nullptr; 499 | } 500 | virtual const char* CustomSignature() const override 501 | { 502 | return _signature; 503 | } 504 | }; 505 | 506 | } // namespace puerts 507 | -------------------------------------------------------------------------------- /puertstest/puerts/include/PesapiBackend.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Puerts available. 3 | * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. 4 | * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may 5 | * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', 6 | * which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "TypeInfo.hpp" 18 | 19 | #define __DefObjectType_pesapi_impl(CLS) \ 20 | namespace puerts \ 21 | { \ 22 | template <> \ 23 | struct is_objecttype : public std::true_type \ 24 | { \ 25 | }; \ 26 | } 27 | 28 | #define __DefCDataPointerConverter_pesapi_impl(CLS) \ 29 | namespace puerts \ 30 | { \ 31 | namespace pesapi_impl \ 32 | { \ 33 | template <> \ 34 | struct Converter \ 35 | { \ 36 | static pesapi_value toScript(pesapi_env env, CLS* value) \ 37 | { \ 38 | return pesapi_create_native_object(env, puerts::DynamicTypeId::get(value), value, false); \ 39 | } \ 40 | static CLS* toCpp(pesapi_env env, pesapi_value value) \ 41 | { \ 42 | return static_cast(pesapi_get_native_object_ptr(env, value)); \ 43 | } \ 44 | static bool accept(pesapi_env env, pesapi_value value) \ 45 | { \ 46 | return pesapi_is_native_object(env, puerts::StaticTypeId::get(), value); \ 47 | } \ 48 | }; \ 49 | } \ 50 | } 51 | 52 | namespace puerts 53 | { 54 | namespace pesapi_impl 55 | { 56 | template 57 | struct Converter; 58 | 59 | template 60 | struct CustomArgumentBufferType 61 | { 62 | static constexpr bool enable = false; 63 | }; 64 | 65 | struct API 66 | { 67 | typedef pesapi_callback_info CallbackInfoType; 68 | typedef pesapi_env ContextType; 69 | typedef pesapi_value ValueType; 70 | typedef void (*FunctionCallbackType)(pesapi_callback_info info); 71 | typedef void* (*InitializeFuncType)(pesapi_callback_info Info); 72 | struct GeneralFunctionInfo 73 | { 74 | const char* Name; 75 | FunctionCallbackType Callback; 76 | void* Data = nullptr; 77 | const CFunctionInfo* ReflectionInfo = nullptr; 78 | }; 79 | 80 | struct GeneralPropertyInfo 81 | { 82 | const char* Name; 83 | FunctionCallbackType Getter; 84 | FunctionCallbackType Setter; 85 | void* Data = nullptr; 86 | }; 87 | 88 | struct GeneralFunctionReflectionInfo 89 | { 90 | const char* Name; 91 | const CFunctionInfo* Type; 92 | }; 93 | 94 | struct GeneralPropertyReflectionInfo 95 | { 96 | const char* Name; 97 | const CTypeInfo* Type; 98 | }; 99 | 100 | inline static int GetArgsLen(pesapi_callback_info info) 101 | { 102 | return pesapi_get_args_len(info); 103 | } 104 | 105 | inline static pesapi_value GetArg(pesapi_callback_info info, int index) 106 | { 107 | return pesapi_get_arg(info, index); 108 | } 109 | 110 | inline static pesapi_env GetContext(pesapi_callback_info info) 111 | { 112 | return pesapi_get_env(info); 113 | } 114 | inline static pesapi_value GetThis(pesapi_callback_info info) 115 | { 116 | return pesapi_get_this(info); 117 | } 118 | 119 | inline static pesapi_value GetHolder(pesapi_callback_info info) 120 | { 121 | return pesapi_get_holder(info); 122 | } 123 | 124 | inline static void ThrowException(pesapi_callback_info info, const char* msg) 125 | { 126 | pesapi_throw_by_string(info, msg); 127 | } 128 | 129 | inline static void SetReturn(pesapi_callback_info info, pesapi_value value) 130 | { 131 | pesapi_add_return(info, value); 132 | } 133 | 134 | template 135 | inline static void LinkOuter(pesapi_env env, pesapi_value outer, pesapi_value inner) 136 | { 137 | pesapi_set_property_uint32(env, inner, 0, outer); 138 | } 139 | 140 | inline static void UpdateRefValue(pesapi_env env, pesapi_value holder, pesapi_value value) 141 | { 142 | if (pesapi_is_object(env, holder)) 143 | { 144 | pesapi_update_value_ref(env, holder, value); 145 | } 146 | } 147 | 148 | template 149 | inline static T* FastGetNativeObjectPointer(pesapi_env env, pesapi_value value) 150 | { 151 | return static_cast(pesapi_get_native_object_ptr(env, value)); 152 | } 153 | 154 | inline static pesapi_value GetUndefined(pesapi_env env) 155 | { 156 | return pesapi_create_undefined(env); 157 | } 158 | 159 | inline static bool IsNullOrUndefined(pesapi_env env, pesapi_value val) 160 | { 161 | return pesapi_is_null(env, val) || pesapi_is_undefined(env, val); 162 | } 163 | 164 | typedef void (*FinalizeFuncType)(void* Ptr); 165 | 166 | template 167 | static void Register(FinalizeFuncType Finalize, const CDB& Cdb) 168 | { 169 | size_t properties_count = Cdb.functions_.size() + Cdb.methods_.size() + Cdb.properties_.size() + Cdb.variables_.size(); 170 | auto properties = pesapi_alloc_property_descriptors(properties_count); 171 | size_t pos = 0; 172 | for (const auto& func : Cdb.functions_) 173 | { 174 | pesapi_set_method_info(properties, pos++, func.Name, true, func.Callback, nullptr, nullptr); 175 | } 176 | 177 | for (const auto& method : Cdb.methods_) 178 | { 179 | pesapi_set_method_info(properties, pos++, method.Name, false, method.Callback, nullptr, nullptr); 180 | } 181 | 182 | for (const auto& prop : Cdb.properties_) 183 | { 184 | pesapi_set_property_info(properties, pos++, prop.Name, false, prop.Getter, prop.Setter, nullptr, nullptr); 185 | } 186 | 187 | for (const auto& prop : Cdb.variables_) 188 | { 189 | pesapi_set_property_info(properties, pos++, prop.Name, true, prop.Getter, prop.Setter, nullptr, nullptr); 190 | } 191 | 192 | pesapi_finalize finalize = Finalize; 193 | pesapi_define_class(StaticTypeId::get(), Cdb.superTypeId_, Cdb.className_, Cdb.constructor_, finalize, properties_count, 194 | properties, nullptr); 195 | } 196 | 197 | template 198 | using Converter = Converter; 199 | 200 | template 201 | using CustomArgumentBufferType = CustomArgumentBufferType; 202 | }; 203 | 204 | class StringHolder 205 | { 206 | public: 207 | StringHolder(pesapi_env env, pesapi_value value) 208 | { 209 | if (!value) 210 | return; 211 | if (pesapi_is_binary(env, value)) 212 | { 213 | needFree_ = false; 214 | size_t length = 0; 215 | str_ = (char*) pesapi_get_value_binary(env, value, &length); 216 | } 217 | else 218 | { 219 | size_t length = 0; 220 | str_ = (char*) pesapi_get_value_string_utf8(env, value, nullptr, &length); 221 | needFree_ = false; 222 | if (!str_) 223 | { 224 | str_ = new char[length + 1]; 225 | pesapi_get_value_string_utf8(env, value, str_, &length); 226 | needFree_ = true; 227 | } 228 | } 229 | } 230 | 231 | // Disallow copying and assigning. 232 | StringHolder(const StringHolder&) = delete; 233 | void operator=(const StringHolder&) = delete; 234 | 235 | ~StringHolder() 236 | { 237 | if (needFree_ && str_) 238 | { 239 | delete[] str_; 240 | } 241 | } 242 | 243 | const char* Data() const 244 | { 245 | return str_; 246 | } 247 | 248 | private: 249 | char* str_; 250 | 251 | bool needFree_; 252 | }; 253 | 254 | template <> 255 | struct CustomArgumentBufferType 256 | { 257 | using type = StringHolder; 258 | static constexpr bool enable = true; 259 | }; 260 | 261 | template 262 | struct Converter::value && sizeof(T) == 8 && std::is_signed::value>::type> 263 | { 264 | static pesapi_value toScript(pesapi_env env, T value) 265 | { 266 | return pesapi_create_int64(env, value); 267 | } 268 | 269 | static T toCpp(pesapi_env env, pesapi_value value) 270 | { 271 | return static_cast(pesapi_get_value_int64(env, value)); 272 | } 273 | 274 | static bool accept(pesapi_env env, pesapi_value value) 275 | { 276 | return pesapi_is_int64(env, value); 277 | } 278 | }; 279 | 280 | template 281 | struct Converter::value && sizeof(T) == 8 && !std::is_signed::value>::type> 282 | { 283 | static pesapi_value toScript(pesapi_env env, T value) 284 | { 285 | return pesapi_create_uint64(env, value); 286 | } 287 | 288 | static T toCpp(pesapi_env env, pesapi_value value) 289 | { 290 | return static_cast(pesapi_get_value_uint64(env, value)); 291 | } 292 | 293 | static bool accept(pesapi_env env, pesapi_value value) 294 | { 295 | return pesapi_is_uint64(env, value); 296 | } 297 | }; 298 | 299 | template 300 | struct Converter::value && sizeof(T) < 8 && std::is_signed::value>::type> 301 | { 302 | static pesapi_value toScript(pesapi_env env, T value) 303 | { 304 | return pesapi_create_int32(env, value); 305 | } 306 | 307 | static T toCpp(pesapi_env env, pesapi_value value) 308 | { 309 | return static_cast(pesapi_get_value_int32(env, value)); 310 | } 311 | 312 | static bool accept(pesapi_env env, pesapi_value value) 313 | { 314 | return pesapi_is_int32(env, value); 315 | } 316 | }; 317 | 318 | template 319 | struct Converter::value && sizeof(T) < 8 && !std::is_signed::value>::type> 320 | { 321 | static pesapi_value toScript(pesapi_env env, T value) 322 | { 323 | return pesapi_create_uint32(env, value); 324 | } 325 | 326 | static T toCpp(pesapi_env env, pesapi_value value) 327 | { 328 | return static_cast(pesapi_get_value_uint32(env, value)); 329 | } 330 | 331 | static bool accept(pesapi_env env, pesapi_value value) 332 | { 333 | return pesapi_is_uint32(env, value); 334 | } 335 | }; 336 | 337 | template 338 | struct Converter::value>::type> 339 | { 340 | static pesapi_value toScript(pesapi_env env, T value) 341 | { 342 | return pesapi_create_int32(env, static_cast(value)); 343 | } 344 | 345 | static T toCpp(pesapi_env env, pesapi_value value) 346 | { 347 | return static_cast(pesapi_get_value_int32(env, value)); 348 | } 349 | 350 | static bool accept(pesapi_env env, pesapi_value value) 351 | { 352 | return pesapi_is_int32(env, value); 353 | } 354 | }; 355 | 356 | template 357 | struct Converter::value>::type> 358 | { 359 | static pesapi_value toScript(pesapi_env env, T value) 360 | { 361 | return pesapi_create_double(env, value); 362 | } 363 | 364 | static T toCpp(pesapi_env env, pesapi_value value) 365 | { 366 | return static_cast(pesapi_get_value_double(env, value)); 367 | } 368 | 369 | static bool accept(pesapi_env env, pesapi_value value) 370 | { 371 | return pesapi_is_double(env, value); 372 | } 373 | }; 374 | 375 | template <> 376 | struct Converter 377 | { 378 | static pesapi_value toScript(pesapi_env env, std::string value) 379 | { 380 | return pesapi_create_string_utf8(env, value.c_str(), value.size()); 381 | } 382 | 383 | static std::string toCpp(pesapi_env env, pesapi_value value) 384 | { 385 | size_t bufSize = 0; 386 | const char* str = pesapi_get_value_string_utf8(env, value, nullptr, &bufSize); 387 | if (str) 388 | { 389 | return std::string(str); 390 | } 391 | else 392 | { 393 | std::vector buffer(bufSize + 1); 394 | str = pesapi_get_value_string_utf8(env, value, buffer.data(), &bufSize); 395 | return std::string(str); 396 | } 397 | } 398 | 399 | static bool accept(pesapi_env env, pesapi_value value) 400 | { 401 | return pesapi_is_string(env, value); 402 | } 403 | }; 404 | 405 | template <> 406 | struct Converter 407 | { 408 | static pesapi_value toScript(pesapi_env env, const char* value) 409 | { 410 | return pesapi_create_string_utf8(env, value, strlen(value)); 411 | } 412 | 413 | static bool accept(pesapi_env env, pesapi_value value) 414 | { 415 | return pesapi_is_string(env, value); 416 | } 417 | }; 418 | 419 | template <> 420 | struct Converter 421 | { 422 | static pesapi_value toScript(pesapi_env env, void* value) 423 | { 424 | return pesapi_create_binary(env, value, 0); 425 | } 426 | 427 | static void* toCpp(pesapi_env env, pesapi_value value) 428 | { 429 | size_t bufsize; 430 | return pesapi_get_value_binary(env, value, &bufsize); 431 | } 432 | 433 | static bool accept(pesapi_env env, pesapi_value value) 434 | { 435 | return pesapi_is_binary(env, value); 436 | } 437 | }; 438 | 439 | template <> 440 | struct Converter 441 | { 442 | static pesapi_value toScript(pesapi_env env, bool value) 443 | { 444 | return pesapi_create_boolean(env, value); 445 | } 446 | 447 | static bool toCpp(pesapi_env env, pesapi_value value) 448 | { 449 | return pesapi_get_value_bool(env, value); 450 | } 451 | 452 | static bool accept(pesapi_env env, pesapi_value value) 453 | { 454 | return pesapi_is_boolean(env, value); 455 | } 456 | }; 457 | 458 | template 459 | struct Converter, typename std::enable_if::value>::type> 460 | { 461 | static pesapi_value toScript(pesapi_env env, const T& value) 462 | { 463 | return pesapi_create_ref(env, Converter::toScript(env, value)); 464 | } 465 | 466 | static T toCpp(pesapi_env env, pesapi_value value) 467 | { 468 | return Converter::toCpp(env, pesapi_get_value_ref(env, value)); 469 | } 470 | 471 | static bool accept(pesapi_env env, pesapi_value value) 472 | { 473 | return pesapi_is_ref(env, value); // do not checked inner 474 | } 475 | }; 476 | 477 | template 478 | struct Converter, typename std::enable_if::value>::type> 479 | { 480 | static pesapi_value toScript(pesapi_env env, const T& value) 481 | { 482 | return pesapi_create_ref(env, Converter::toScript(env, value)); 483 | } 484 | 485 | static T* toCpp(pesapi_env env, pesapi_value value) 486 | { 487 | if (pesapi_is_object(env, value)) 488 | { 489 | return Converter::toCpp(env, pesapi_get_value_ref(env, value)); 490 | } 491 | return nullptr; 492 | } 493 | 494 | static bool accept(pesapi_env env, pesapi_value value) 495 | { 496 | return pesapi_is_ref(env, value); // do not checked inner 497 | } 498 | }; 499 | 500 | template 501 | struct Converter::type>::value && !std::is_array::value && 503 | !std::is_const::type>::value && std::is_pointer::value>::type> 504 | { 505 | static pesapi_value toScript(pesapi_env env, T value) 506 | { 507 | return pesapi_create_binary(env, value, 0); 508 | } 509 | 510 | static T toCpp(pesapi_env env, pesapi_value value) 511 | { 512 | size_t bufsize; 513 | return static_cast(pesapi_get_value_binary(env, value, &bufsize)); 514 | } 515 | 516 | static bool accept(pesapi_env env, pesapi_value value) 517 | { 518 | return pesapi_is_binary(env, value); 519 | } 520 | }; 521 | 522 | template 523 | struct Converter::value && !std::is_const::value>::type> 524 | { 525 | static pesapi_value toScript(pesapi_env env, T value[Size]) 526 | { 527 | return pesapi_create_binary(env, value, sizeof(T) * Size); 528 | } 529 | 530 | static bool accept(pesapi_env env, pesapi_value value) 531 | { 532 | return pesapi_is_binary(env, value); 533 | } 534 | }; 535 | 536 | template 537 | struct Converter::value && std::is_constructible::value && 538 | is_objecttype::value && !is_uetype::value>::type> 539 | { 540 | static pesapi_value toScript(pesapi_env env, T value) 541 | { 542 | return pesapi_create_native_object(env, puerts::DynamicTypeId::get(&value), new T(value), true); 543 | } 544 | static T toCpp(pesapi_env env, pesapi_value value) 545 | { 546 | T* ptr = (static_cast(pesapi_get_native_object_ptr(env, value))); 547 | return ptr ? *ptr : T{}; 548 | } 549 | static bool accept(pesapi_env env, pesapi_value value) 550 | { 551 | return pesapi_is_native_object(env, puerts::StaticTypeId::get(), value); 552 | } 553 | }; 554 | 555 | } // namespace pesapi_impl 556 | } // namespace puerts 557 | --------------------------------------------------------------------------------