/* * Tencent is pleased to support the open source community by making Puerts available. * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', * which is part of this source code package. */ #pragma once #include "CoreMinimal.h" #include "wasm3.h" #include "m3_env.h" #include "WasmBindingTemplate.hpp" #include "WasmRuntime.h" #include "Wasm3ExportDef.h" class WASMCORE_API WasmFunction final { private: M3Function* _Function; public: WasmFunction(M3Function* Func) : _Function(Func) { } FORCEINLINE M3Function* GetFunction() const { return _Function; } private: template struct CallHelper { //不支持返回值是引用 static_assert(!std::is_reference::value, ""); template struct Functor; template struct Functor> { static bool InvokeNoReturn(WasmFunction* Outer, Args... args) { static_assert(wasm_is_all_support_type::value, ""); WasmRuntime* Runtime = Outer->GetRuntime(); WasmStackAllocCacheInfo Backup = Runtime->GetCurrentStackAllocInfo(); auto stack_params = std::make_tuple::translated_type...>( typename wasm_call_params_translator::translated_type()...); void* args_pointer[sizeof...(args)] = {Outer->InternalTranslatePointer( &std::get(stack_params), (typename wasm_remove_const_ref::type*) &args)...}; if (Outer->CallWithArgsNoReturn(sizeof...(args), (const void**) args_pointer)) { const WASM_PTR free_ptr_list[sizeof...(args)] = { Outer->InternalCopyback(args_pointer[Index], (typename wasm_remove_const_ref::type*) &args)...}; Runtime->RestoreCurrentStackAllocInfo(Backup); return true; } else { Runtime->RestoreCurrentStackAllocInfo(Backup); return false; } } //没有返回值 template static typename std::enable_if::value, void>::type InnerInvoke(WasmFunction* Outer, Args... args) { InvokeNoReturn(Outer, std::forward(args)...); } // 返回值是复杂类型 template static typename std::enable_if::value, T>::type InnerInvoke(WasmFunction* Outer, Args... args) { static_assert(wasm_is_all_support_type::value, ""); WasmRuntime* Runtime = Outer->GetRuntime(); WasmStackAllocCacheInfo Backup = Runtime->GetCurrentStackAllocInfo(); //复杂类型,栈的第一个是类型地址 WASM_PTR inner_ptr = Runtime->AllocStackParam(sizeof(T)).PtrInWasm; auto stack_params = std::make_tuple::translated_type...>( typename wasm_call_params_translator::translated_type()...); void* args_pointer[1 + sizeof...(args)] = { (void*) &inner_ptr, Outer->InternalTranslatePointer(&std::get(stack_params), (typename wasm_remove_const_ref::type*) &args)...}; if (Outer->CallWithArgsNoReturn(1 + sizeof...(args), (const void**) args_pointer)) { const WASM_PTR free_ptr_list[1 + sizeof...(args)] = {inner_ptr, Outer->InternalCopyback(args_pointer[Index], (typename wasm_remove_const_ref::type*) &args)...}; Ret* ret_ptr = (Ret*) Runtime->GetPlatformAddress(inner_ptr); Ret r = *ret_ptr; Runtime->RestoreCurrentStackAllocInfo(Backup); return r; } else { Runtime->RestoreCurrentStackAllocInfo(Backup); return T(); } } //返回值是简单类型 template static typename std::enable_if::value, T>::type InnerInvoke(WasmFunction* Outer, Args... args) { static_assert(wasm_is_all_support_type::value, ""); WasmRuntime* Runtime = Outer->GetRuntime(); WasmStackAllocCacheInfo Backup = Runtime->GetCurrentStackAllocInfo(); auto stack_params = std::make_tuple::translated_type...>( typename wasm_call_params_translator::translated_type()...); void* args_pointer[sizeof...(args)] = {Outer->InternalTranslatePointer( &std::get(stack_params), (typename wasm_remove_const_ref::type*) &args)...}; if (Outer->CallWithArgsNoReturn(sizeof...(args), (const void**) args_pointer)) { const WASM_PTR free_ptr_list[sizeof...(args)] = { Outer->InternalCopyback(args_pointer[Index], (typename wasm_remove_const_ref::type*) &args)...}; T r = Outer->GetReturnValue(); Runtime->RestoreCurrentStackAllocInfo(Backup); return r; } else { Runtime->RestoreCurrentStackAllocInfo(Backup); return T(); } } // 返回值是指针,等价于先返回一个wasm_ptr,再解析这个wasm_ptr template static typename std::enable_if::value, T>::type InnerInvoke( WasmFunction* Outer, Args... args) { using ptr_type_in_wasm = typename wasm_pointer_support_ptr_in_wasm::type; WASM_PTR ptr = InnerInvoke(Outer, std::forward(args)...); ptr_type_in_wasm* realPtr = (ptr_type_in_wasm*) Outer->GetRuntime()->GetPlatformAddress(ptr); return static_cast(*realPtr); } static Ret Invoke(WasmFunction* Outer, Args... args) { return InnerInvoke(Outer, std::forward(args)...); } }; }; public: //内部接口,谨慎调用 bool CallWithArgsNoReturn(int arg_count, const void** args) const { check(_Function); if (!Export_m3_Call(_Function, arg_count, args)) { UE_LOG(LogTemp, Error, TEXT("Error In Call Simple Function %s"), ANSI_TO_TCHAR(_Function->export_name)); return false; } return true; } //简单类型返回值 template typename std::enable_if::value, Ret>::type GetReturnValue() const { //不支持返回值是引用 static_assert(!std::is_reference::value, ""); Ret r; void* ret_ptrs[] = {&r}; if (!Export_m3_GetResults(_Function, 1, (const void**) ret_ptrs)) { UE_LOG(LogTemp, Error, TEXT("Error In GetReturnValue %s"), ANSI_TO_TCHAR(_Function->export_name)); } return r; } //并不支持复杂类型返回值使用这个接口,直接使用Call,因为复杂类型的返回值传参不太一样,这里只考虑指针和简单类型 template typename std::enable_if::value, Ret>::type GetReturnValue() const { //不支持返回值是引用 static_assert(!std::is_reference::value, ""); using ptr_type_in_wasm = typename wasm_pointer_support_ptr_in_wasm::type; WASM_PTR r; void* ret_ptrs[] = {&r}; if (!Export_m3_GetResults(_Function, 1, (const void**) ret_ptrs)) { UE_LOG(LogTemp, Error, TEXT("Error In GetReturnValue %s"), ANSI_TO_TCHAR(_Function->export_name)); } ptr_type_in_wasm* ptr = (ptr_type_in_wasm*) GetRuntime()->GetPlatformAddress(r); return static_cast(*ptr); } template bool CallNoReturn(Args... args) { // todo 看看是否需要把栈补一下,要不然可能会不平衡? return CallHelper::template Functor>::InvokeNoReturn( this, std::forward(args)...); } bool CallNoReturn() { return CallWithArgsNoReturn(0, nullptr); } template Ret Call(Args... args) { return CallHelper::template Functor>::Invoke( this, std::forward(args)...); } //简单类型或者指针类型 template typename std::enable_if::value || wasm_is_support_pointer_type::value, Ret>::type Call() { //不支持返回值是引用 static_assert(!std::is_reference::value, ""); if (CallWithArgsNoReturn(0, nullptr)) { return GetReturnValue(); } return Ret(); } //复杂类型 template typename std::enable_if::value, Ret>::type Call() { //不支持返回值是引用 static_assert(!std::is_reference::value, ""); WasmRuntime* Runtime = GetRuntime(); WasmStackAllocCacheInfo Backup = Runtime->GetCurrentStackAllocInfo(); WASM_PTR inner_ptr = Runtime->AllocStackParam(sizeof(Ret)).PtrInWasm; void* args_pointer[] = { &inner_ptr, }; if (CallWithArgsNoReturn(1, (const void**) args_pointer)) { Ret* ptr = (Ret*) Runtime->GetPlatformAddress(inner_ptr); Ret r = *ptr; Runtime->RestoreCurrentStackAllocInfo(Backup); return r; } else { Runtime->RestoreCurrentStackAllocInfo(Backup); } return Ret(); } private: // 简单类型,非引用 template ::translated_type, typename RT = typename wasm_remove_const_ref::type> typename std::enable_if::value && !std::is_reference::value, void*>::type InternalTranslatePointer( T_Translatedtype* stack_pointer, RT* src_pointer) { //非引用的,直接使用原来的地址就好了,因为本来就是传值的语义 return (void*) src_pointer; } // 简单类型的引用 template ::translated_type, typename RT = typename wasm_remove_const_ref::type> typename std::enable_if::value && std::is_reference::value, void*>::type InternalTranslatePointer( T_Translatedtype* stack_pointer, RT* src_pointer) { //引用被wasm当作指针来传递 WasmRuntime* Runtime = GetRuntime(); WasmStackAllocCacheInfo NewMalloc = Runtime->AllocStackParam(sizeof(T)); FMemory::Memcpy(NewMalloc.RealPtr, src_pointer, sizeof(T)); *((WASM_PTR*) stack_pointer) = NewMalloc.PtrInWasm; return stack_pointer; } // 复杂类型 template ::translated_type, typename RT = typename wasm_remove_const_ref::type> typename std::enable_if::value, void*>::type InternalTranslatePointer( void* stack_pointer, RT* src_pointer) { static_assert(std::is_same::value, ""); WasmRuntime* Runtime = GetRuntime(); WasmStackAllocCacheInfo NewMalloc = Runtime->AllocStackParam(sizeof(T)); FMemory::Memcpy(NewMalloc.RealPtr, src_pointer, sizeof(T)); *((WASM_PTR*) stack_pointer) = NewMalloc.PtrInWasm; return stack_pointer; } //指针 template ::translated_type, typename RT = typename wasm_remove_const_ref::type> typename std::enable_if::value, void*>::type InternalTranslatePointer( void* stack_pointer, RT* src_pointer) { WasmRuntime* Runtime = GetRuntime(); WasmStackAllocCacheInfo NewMalloc = Runtime->AllocStackParam(sizeof(void*)); T_Translatedtype value = static_cast(*src_pointer); *((T_Translatedtype*) (NewMalloc.RealPtr)) = value; *((WASM_PTR*) stack_pointer) = NewMalloc.PtrInWasm; return stack_pointer; } template ::translated_type, typename RT = typename wasm_remove_const_ref::type> typename std::enable_if::value, WASM_PTR>::type InternalCopyback( void* stack_pointer, RT* src_pointer) { // 指针也啥都不用干 return 0; } template ::translated_type, typename RT = typename wasm_remove_const_ref::type> typename std::enable_if::value && !std::is_reference::value, WASM_PTR>::type InternalCopyback( void* stack_pointer, RT* src_pointer) { // 非引用的简单类型,啥都不用干 return 0; } template ::translated_type, typename RT = typename wasm_remove_const_ref::type> typename std::enable_if::value && std::is_reference::value, WASM_PTR>::type InternalCopyback( void* stack_pointer, RT* src_pointer) { // 引用的简单类型,还要把值拷贝回去 WASM_PTR ptr = *((WASM_PTR*) stack_pointer); WasmRuntime* Runtime = GetRuntime(); if (std::is_reference::value && !std::is_const::type>::value) { void* real_ptr = Runtime->GetPlatformAddress(ptr); FMemory::Memcpy((void*) src_pointer, real_ptr, sizeof(T)); } return ptr; } template ::translated_type, typename RT = typename wasm_remove_const_ref::type> typename std::enable_if::value, WASM_PTR>::type InternalCopyback(void* stack_pointer, RT* src_pointer) { static_assert(std::is_same::value, ""); WASM_PTR ptr = *((WASM_PTR*) stack_pointer); WasmRuntime* Runtime = GetRuntime(); if (std::is_reference::value && !std::is_const::type>::value) { void* real_ptr = Runtime->GetPlatformAddress(ptr); FMemory::Memcpy((void*) src_pointer, real_ptr, sizeof(T)); } return ptr; } FORCEINLINE WasmRuntime* GetRuntime() const { return (WasmRuntime*) _Function->module->runtime->userdata; } };