diff --git a/cmake/CommonTesting.cmake b/cmake/CommonTesting.cmake index 1d0f7b1934577ea57d199d064d1156bf4b01dda0..406ba5a280a02fd0e3eaebba208649b90f34af78 100644 --- a/cmake/CommonTesting.cmake +++ b/cmake/CommonTesting.cmake @@ -20,9 +20,9 @@ function(common_add_gtest) endif() set(prefix ARG) - set(noValues CONTAINS_MAIN NO_CORES RAPIDCHECK_ON) - set(singleValues NAME OUTPUT_DIRECTORY TSAN_EXTRA_OPTIONS PANDA_STD_LIB ARK_BOOTCLASSPATH CUSTOM_PRERUN_ENVIRONMENT TEST_RUN_DIR) - set(multiValues SOURCES INCLUDE_DIRS LIBRARIES SANITIZERS DEPS_TARGETS) + set(noValues CONTAINS_MAIN NO_CORES RAPIDCHECK_ON NO_EXECUTABLE) + set(singleValues NAME OUTPUT_DIRECTORY TSAN_EXTRA_OPTIONS PANDA_STD_LIB ARK_BOOTCLASSPATH TEST_RUN_DIR) + set(multiValues SOURCES INCLUDE_DIRS LIBRARIES SANITIZERS DEPS_TARGETS CUSTOM_PRERUN_ENVIRONMENT LAUNCHER) set(TIMEOUT_SIGNAL USR1) cmake_parse_arguments(${prefix} @@ -46,13 +46,17 @@ function(common_add_gtest) endif() if (ARG_RAPIDCHECK_ON) - panda_add_executable(${ARG_NAME} RAPIDCHECK_ON ${ARG_SOURCES}) + if(NOT ARG_NO_EXECUTABLE) + panda_add_executable(${ARG_NAME} RAPIDCHECK_ON ${ARG_SOURCES}) + endif() set_target_properties(${ARG_NAME} PROPERTIES LINK_FLAGS "-fno-rtti -fexceptions") target_compile_definitions(${ARG_NAME} PRIVATE PANDA_RAPIDCHECK) target_compile_options(${ARG_NAME} PRIVATE "-fno-rtti" "-fexceptions" "-fPIC") target_compile_definitions(${ARG_NAME} PUBLIC PANDA_RAPIDCHECK) else() - panda_add_executable(${ARG_NAME} ${ARG_SOURCES}) + if(NOT ARG_NO_EXECUTABLE) + panda_add_executable(${ARG_NAME} ${ARG_SOURCES}) + endif() endif() set(ARG_USE_GTESTS ON) @@ -143,21 +147,20 @@ function(common_add_gtest) set(ARK_BOOTCLASSPATH "ARK_BOOTCLASSPATH=${ARG_ARK_BOOTCLASSPATH}") endif() - set(CUSTOM_PRERUN_ENVIRONMENT "") - if(DEFINED ARG_CUSTOM_PRERUN_ENVIRONMENT) - set(CUSTOM_PRERUN_ENVIRONMENT ${ARG_CUSTOM_PRERUN_ENVIRONMENT}) - endif() - set(TEST_RUN_DIR ${CMAKE_CURRENT_BINARY_DIR}) if(DEFINED ARG_TEST_RUN_DIR) set(TEST_RUN_DIR ${ARG_TEST_RUN_DIR}) endif() + if(NOT DEFINED ARG_LAUNCHER) + set(ARG_LAUNCHER "${ARG_OUTPUT_DIRECTORY}/${ARG_NAME}") + endif() + set(output_file "${ARG_OUTPUT_DIRECTORY}/${ARG_NAME}_gtest_output.txt") add_custom_target(${ARG_NAME}_gtests - COMMAND ${PANDA_STD_LIB} ${ARK_BOOTCLASSPATH} ${CUSTOM_PRERUN_ENVIRONMENT} + COMMAND ${PANDA_STD_LIB} ${ARK_BOOTCLASSPATH} ${ARG_CUSTOM_PRERUN_ENVIRONMENT} ${tsan_options} ${prlimit_prefix} ${timeout_prefix} - ${PANDA_RUN_PREFIX} "${ARG_OUTPUT_DIRECTORY}/${ARG_NAME}" + ${PANDA_RUN_PREFIX} ${ARG_LAUNCHER} --gtest_shuffle --gtest_death_test_style=threadsafe --gtest_brief=0 >${output_file} 2>&1 diff --git a/plugins/ets/CMakeLists.txt b/plugins/ets/CMakeLists.txt index 5f32c76fea39bddd6fbc61284ef2272aab035217..01247272c69ec4f0bfb7fe3c5be2fca35ae8eb67 100644 --- a/plugins/ets/CMakeLists.txt +++ b/plugins/ets/CMakeLists.txt @@ -16,6 +16,8 @@ project(plugin_ets) message(STATUS "eTS plugin is found") +include(cmake/import.cmake) + if(PANDA_WITH_RUNTIME) add_subdirectory(runtime) endif() diff --git a/plugins/ets/cmake/ets_package.cmake b/plugins/ets/cmake/ets_package.cmake new file mode 100644 index 0000000000000000000000000000000000000000..cd7e8b7c70b0e9bed5fd88bd1a584545c9c4f6fd --- /dev/null +++ b/plugins/ets/cmake/ets_package.cmake @@ -0,0 +1,124 @@ +# Copyright (c) 2021-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + + +# Helped method for creating xx package +# +# Example usage: +# do_panda_ets_package(package_name +# ETS_SOURCES +# path/to/file0.ets +# path/to/file1.ets +# OUTPUT_DIRECTORY +# path/to/output_director +# ) +function(do_panda_ets_package TARGET) + # Parse arguments + cmake_parse_arguments( + ARG + "" + "OUTPUT_DIRECTORY" + "ETS_SOURCES" + ${ARGN} + ) + + # Check arguments + if(NOT DEFINED ARG_OUTPUT_DIRECTORY) + message(FATAL_ERROR "OUTPUT_DIRECTORY is not set") + endif() + + if(NOT DEFINED ARG_ETS_SOURCES) + message(FATAL_ERROR "ETS_SOURCES is not set") + endif() + + list(LENGTH ARG_ETS_SOURCES NB_ETS_SOURCES) + if(NOT ${NB_ETS_SOURCES} STREQUAL "1") + message(FATAL_ERROR "Currenly we only support one ets file") + endif() + + # Set variables + set(ETS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_ETS_SOURCES}) + set(ES2PANDA_ARGUMENTS + --opt-level=0 + --thread=0 + --extension=ets + ) + set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}) + + # Convert *.ets -> classes.abc + set(OUTPUT_ABC ${BUILD_DIR}/src/classes.abc) + add_custom_command( + OUTPUT ${OUTPUT_ABC} + COMMENT "${TARGET}: Convert ets files to ${OUTPUT_ABC}" + COMMAND rm -rf ${BUILD_DIR}/src + COMMAND mkdir -p ${BUILD_DIR}/src + COMMAND ${es2panda_bin} ${ES2PANDA_ARGUMENTS} --output=${OUTPUT_ABC} ${ETS_FILE} + DEPENDS etsstdlib ${es2panda_target} ${ETS_FILE} + ) + + # Pack classes.abc to .zip archive + set(OUTPUT_ZIP ${BUILD_DIR}/out/${TARGET}.zip) + add_custom_command( + OUTPUT ${OUTPUT_ZIP} + COMMENT "Create ${OUTPUT_ZIP}" + COMMAND rm -rf ${BUILD_DIR}/out + COMMAND mkdir ${BUILD_DIR}/out + COMMAND cd ${BUILD_DIR}/src + COMMAND zip -r -0 ${OUTPUT_ZIP} * + DEPENDS ${OUTPUT_ABC} + ) + + # Copy .zip to / + set(RELEASE_ZIP ${PANDA_BINARY_ROOT}/${ARG_OUTPUT_DIRECTORY}/${TARGET}.zip) + add_custom_command( + OUTPUT ${RELEASE_ZIP} + COMMENT "Copy ${OUTPUT_ZIP} to ${RELEASE_ZIP}" + COMMAND cp ${OUTPUT_ZIP} ${RELEASE_ZIP} + DEPENDS ${OUTPUT_ZIP} + ) + add_custom_target(${TARGET} + DEPENDS ${RELEASE_ZIP} + ) +endfunction(do_panda_ets_package) + + +# Create ets package +# +# Example usage: +# panda_ets_package(package_name +# ETS_SOURCES +# path/to/file0.ets +# path/to/file1.ets +# ) +function(panda_ets_package) + do_panda_ets_package( + ${ARGV} + OUTPUT_DIRECTORY abc + ) +endfunction(panda_ets_package) + + +# Create ets package for tests +# +# Example usage: +# panda_ets_package_gtest(package_name +# ETS_SOURCES +# path/to/file0.ets +# path/to/file1.ets +# ) +function(panda_ets_package_gtest) + do_panda_ets_package( + ${ARGV} + OUTPUT_DIRECTORY abc-gtests + ) +endfunction(panda_ets_package_gtest) diff --git a/plugins/ets/cmake/import.cmake b/plugins/ets/cmake/import.cmake new file mode 100644 index 0000000000000000000000000000000000000000..c158e727df3e5391422f3437f6d1436416280399 --- /dev/null +++ b/plugins/ets/cmake/import.cmake @@ -0,0 +1,19 @@ +# Copyright (c) 2021-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + + +include(cmake/ets_package.cmake) + +if(PANDA_ETS_INTEROP_JS) + include(cmake/interop_js_plugin.cmake) +endif() diff --git a/plugins/ets/cmake/interop_js_plugin.cmake b/plugins/ets/cmake/interop_js_plugin.cmake new file mode 100644 index 0000000000000000000000000000000000000000..cd1f886d2c9ab785b716271e4377ba82c559b63e --- /dev/null +++ b/plugins/ets/cmake/interop_js_plugin.cmake @@ -0,0 +1,64 @@ +# Copyright (c) 2021-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + + +# Create js plugin +# +# Example usage: +# panda_ets_interop_js_plugin(plugin_name +# SOURCES +# path/to/file0.cpp +# path/to/file1.cpp +# LIBRARIES +# lib_name0 +# lib_name1 +# LIBRARY_OUTPUT_DIRECTORY +# ) +function(panda_ets_interop_js_plugin TARGET) + # Parse arguments + cmake_parse_arguments( + ARG + "" + "LIBRARY_OUTPUT_DIRECTORY" + "SOURCES;LIBRARIES" + ${ARGN} + ) + + if(NOT DEFINED ARG_LIBRARY_OUTPUT_DIRECTORY) + # Set default value + set(ARG_LIBRARY_OUTPUT_DIRECTORY ${PANDA_BINARY_ROOT}/lib/module) + endif() + + add_library(${TARGET} SHARED ${ARG_SOURCES}) + target_link_libraries(${TARGET} ${ARG_LIBRARIES}) + + if(PANDA_TARGET_OHOS) + target_link_libraries(${TARGET} ace_napi.z) + else() + if(NAPI_HEADERS_PATH) + target_include_directories(${TARGET} PRIVATE ${NAPI_HEADERS_PATH}) + else() + message(FATAL_ERROR "NAPI_HEADERS_PATH is not set") + endif() + set_target_properties(${TARGET} + PROPERTIES + # Set module name + PREFIX "" + OUTPUT_NAME "${TARGET}" + SUFFIX ".node" + + # Set output direcory + LIBRARY_OUTPUT_DIRECTORY ${ARG_LIBRARY_OUTPUT_DIRECTORY} + ) + endif() +endfunction(panda_ets_interop_js_plugin) diff --git a/plugins/ets/runtime/CMakeLists.txt b/plugins/ets/runtime/CMakeLists.txt index 8d037fca76dad4f8ba2b5388a1594896f7eec19d..d732714bd6d048aa9f40586f2980a426982a504c 100644 --- a/plugins/ets/runtime/CMakeLists.txt +++ b/plugins/ets/runtime/CMakeLists.txt @@ -47,14 +47,6 @@ set(ETS_RUNTIME_SOURCES ${ETS_EXT_SOURCES}/ets_vm_api.cpp ) -if (PANDA_WITH_OHOS_NAPI) - list(APPEND ETS_RUNTIME_SOURCES - ${ETS_EXT_SOURCES}/ts2ets/ts2ets_common.cpp - ${ETS_EXT_SOURCES}/ts2ets/ts2ets_copy.cpp - ${ETS_EXT_SOURCES}/ts2ets/ts2ets_proxy.cpp - ) -endif() - get_directory_property(CURRENT_DEFS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) if (PANDA_TARGET_ARM32_ABI_SOFT OR PANDA_TARGET_ARM32_ABI_SOFTFP) @@ -76,3 +68,7 @@ target_include_directories(arkruntime_static PUBLIC target_compile_definitions(arkruntime_static PRIVATE ${CURRENT_DEFS}) add_dependencies(arkruntime_static cross_values) + +if (PANDA_ETS_INTEROP_JS) + add_subdirectory(interop_js) +endif() diff --git a/plugins/ets/runtime/ets_vm.cpp b/plugins/ets/runtime/ets_vm.cpp index 935eb195e795afc3b045af59c4da95cf3288e9cc..426ca0789cd4fcf2dddb1915c8c5684fc4cc7c8a 100644 --- a/plugins/ets/runtime/ets_vm.cpp +++ b/plugins/ets/runtime/ets_vm.cpp @@ -576,15 +576,3 @@ void PandaEtsVM::Abort(const char *message /* = nullptr */) } } // namespace panda::ets - -#ifdef PANDA_WITH_OHOS_NAPI -// to prevent linker from removing symbols -#include "plugins/ets/runtime/ts2ets/ts2ets_copy.h" -[[maybe_unused]] auto g_dummy_InvokeEtsMethodImpl = - reinterpret_cast(&panda::ets::ts2ets::InvokeEtsMethodImpl); -#include "plugins/ets/runtime/ts2ets/ts2ets_proxy.h" -[[maybe_unused]] auto g_dummy_RegisterETSClassImpl = - reinterpret_cast(&panda::ets::ts2ets::RegisterETSClassImpl); -[[maybe_unused]] auto g_dummy_RegisterETSFunctionImpl = - reinterpret_cast(&panda::ets::ts2ets::RegisterETSFunctionImpl); -#endif diff --git a/plugins/ets/runtime/ets_vm_api.cpp b/plugins/ets/runtime/ets_vm_api.cpp index 7721e466dcf6e1a7815401d6ead7e451f4ec1218..aa28eda61711e9e7ac0b166135ec1027baeccb9d 100644 --- a/plugins/ets/runtime/ets_vm_api.cpp +++ b/plugins/ets/runtime/ets_vm_api.cpp @@ -13,55 +13,44 @@ * limitations under the License. */ -#ifdef PANDA_WITH_OHOS_NAPI -#include -#endif - #include "ets_vm_api.h" #include "ets_vm.h" #include "generated/base_options.h" -namespace panda::ets { - -#ifdef PANDA_WITH_OHOS_NAPI +// WORKAROUND: +// We delete PANDA_TARGET_OHOS macros because CI doesn't have header. +// We should remove this workaround when CI will be fixed. +#undef PANDA_TARGET_OHOS -#define OHOS_LOG_INFO(msg, ...) OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "ArkEtsVm", msg, __VA_ARGS__) -#define OHOS_LOG_ERROR(msg, ...) OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "ArkEtsVm", msg, __VA_ARGS__) -#define OHOS_LOG_DEBUG(msg, ...) OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xFF00, "ArkEtsVm", msg, __VA_ARGS__) -#define OHOS_LOG_WARN(msg, ...) OH_LOG_Print(LOG_APP, LOG_WARN, 0xFF00, "ArkEtsVm", msg, __VA_ARGS__) -#define OHOS_LOG_FATAL(msg, ...) OH_LOG_Print(LOG_APP, LOG_FATAL, 0xFF00, "ArkEtsVm", msg, __VA_ARGS__) +#ifdef PANDA_TARGET_OHOS +#include static void LogPrint([[maybe_unused]] int id, int level, const char *component, [[maybe_unused]] const char *fmt, const char *msg) { switch (level) { case panda::Logger::PandaLog2MobileLog::DEBUG: - OHOS_LOG_DEBUG("%s: %s", component, msg); + OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xFF00, "ArkEtsVm", "%s: %s", component, msg); break; case panda::Logger::PandaLog2MobileLog::INFO: - OHOS_LOG_INFO("%s: %s", component, msg); + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "ArkEtsVm", "%s: %s", component, msg); break; case panda::Logger::PandaLog2MobileLog::ERROR: - OHOS_LOG_ERROR("%s: %s", component, msg); + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "ArkEtsVm", "%s: %s", component, msg); break; case panda::Logger::PandaLog2MobileLog::FATAL: - OHOS_LOG_FATAL("%s: %s", component, msg); + OH_LOG_Print(LOG_APP, LOG_FATAL, 0xFF00, "ArkEtsVm", "%s: %s", component, msg); break; case panda::Logger::PandaLog2MobileLog::WARN: - OHOS_LOG_WARN("%s: %s", component, msg); + OH_LOG_Print(LOG_APP, LOG_WARN, 0xFF00, "ArkEtsVm", "%s: %s", component, msg); break; default: UNREACHABLE(); } } +#endif // PANDA_TARGET_OHOS -#undef OHOS_LOG_INFO -#undef OHOS_LOG_ERROR -#undef OHOS_LOG_DEBUG -#undef OHOS_LOG_WARN -#undef OHOS_LOG_FATAL - -#endif +namespace panda::ets { // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) static std::string G_RESOURCES_PATH; @@ -86,7 +75,7 @@ bool CreateRuntime(const std::string &stdlib_abc, const std::string &path_abc, c runtime_options.SetLoadRuntimes({"ets"}); runtime_options.SetBootPandaFiles({stdlib_abc, path_abc}); runtime_options.SetPandaFiles({path_abc}); -#ifdef PANDA_WITH_OHOS_NAPI +#ifdef PANDA_TARGET_OHOS runtime_options.SetMobileLog(reinterpret_cast(LogPrint)); #endif runtime_options.SetGcTriggerType("heap-trigger"); diff --git a/plugins/ets/runtime/interop_js/CMakeLists.txt b/plugins/ets/runtime/interop_js/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..86dc6c00d03e3635edb00d346fb6d0398fd4fe9d --- /dev/null +++ b/plugins/ets/runtime/interop_js/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) 2021-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + + +panda_ets_interop_js_plugin(ets_vm_plugin + SOURCES + ets_vm_plugin.cpp + ts2ets_common.cpp + ts2ets_copy.cpp + ts2ets_proxy.cpp + LIBRARIES + arkruntime +) diff --git a/plugins/ets/runtime/ts2ets/ets_type_visitor-inl.h b/plugins/ets/runtime/interop_js/ets_type_visitor-inl.h similarity index 100% rename from plugins/ets/runtime/ts2ets/ets_type_visitor-inl.h rename to plugins/ets/runtime/interop_js/ets_type_visitor-inl.h diff --git a/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp b/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..547abc077f560c085f1ad20d27a1bc99a7fa09db --- /dev/null +++ b/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include "runtime/include/runtime.h" +#include "plugins/ets/runtime/ets_vm_api.h" +#include "plugins/ets/runtime/interop_js/ts2ets_copy.h" + +namespace panda::ets::napi_addon { + +static napi_value Version(napi_env env, [[maybe_unused]] napi_callback_info info) +{ + const char msg[] = "0.1"; + + napi_value result; + napi_status status = napi_create_string_utf8(env, msg, sizeof(msg), &result); + assert(status == napi_ok); + + return result; +} + +static bool CreateEtsVM() +{ + const char *gtest_abc_path = std::getenv("ARK_ETS_INTEROP_JS_GTEST_ABC_PATH"); + if (gtest_abc_path == nullptr) { + std::cerr << "ARK_ETS_INTEROP_JS_GTEST_ABC_PATH is not set" << std::endl; + std::abort(); + } + + const char *ets_stdlib_path = std::getenv("ARK_ETS_STDLIB_PATH"); + if (ets_stdlib_path == nullptr) { + std::cerr << "ARK_ETS_STDLIB_PATH is not set" << std::endl; + std::abort(); + } + + bool use_jit = false; + bool use_aot = false; + return panda::ets::CreateRuntime(ets_stdlib_path, gtest_abc_path, use_jit, use_aot); +} + +static napi_value Call(napi_env env, napi_callback_info info) +{ + size_t argc = 0; + napi_status status; + status = napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr); + assert(status == napi_ok); + + auto argv = std::make_unique(argc); + napi_value this_arg; + void *data; + status = napi_get_cb_info(env, info, &argc, argv.get(), &this_arg, &data); + assert(status == napi_ok); + + return ts2ets::InvokeEtsMethodImpl(env, argv.get(), argc, false); +} + +static napi_value Init(napi_env env, napi_value exports) +{ + bool ret = CreateEtsVM(); + if (!ret) { + std::cerr << "Cannot create ETS VM" << std::endl; + std::abort(); + } + + const std::array desc = { + napi_property_descriptor {"version", 0, Version, 0, 0, 0, napi_enumerable, 0}, + napi_property_descriptor {"call", 0, Call, 0, 0, 0, napi_enumerable, 0}, + }; + + napi_status status; + status = napi_define_properties(env, exports, desc.size(), desc.data()); + assert(status == napi_ok); + + return exports; +} + +} // namespace panda::ets::napi_addon + +NAPI_MODULE(ETS_VM_PLUGIN, panda::ets::napi_addon::Init) diff --git a/plugins/ets/runtime/interop_js/ets_vm_plugin.d.ts b/plugins/ets/runtime/interop_js/ets_vm_plugin.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5e4d2eaf2200cec70db9f343e6105389c177e7b --- /dev/null +++ b/plugins/ets/runtime/interop_js/ets_vm_plugin.d.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +export function version(): string; +export function call(methodName: string, ...args: any): any; diff --git a/plugins/ets/runtime/ts2ets/ts2ets_common.cpp b/plugins/ets/runtime/interop_js/ts2ets_common.cpp similarity index 97% rename from plugins/ets/runtime/ts2ets/ts2ets_common.cpp rename to plugins/ets/runtime/interop_js/ts2ets_common.cpp index 38752d969641d40ee5be668feec83da8f3c4fe6f..750dba083033bf69e62b41e0b1e75c0621be4ffb 100644 --- a/plugins/ets/runtime/ts2ets/ts2ets_common.cpp +++ b/plugins/ets/runtime/interop_js/ts2ets_common.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "plugins/ets/runtime/ts2ets/ts2ets_common.h" +#include "plugins/ets/runtime/interop_js/ts2ets_common.h" namespace panda::ets::ts2ets { diff --git a/plugins/ets/runtime/ts2ets/ts2ets_common.h b/plugins/ets/runtime/interop_js/ts2ets_common.h similarity index 75% rename from plugins/ets/runtime/ts2ets/ts2ets_common.h rename to plugins/ets/runtime/interop_js/ts2ets_common.h index a33f1eb3d204c3f6a80c15012572a51f0b042b92..a08aab4b3b9b78cb72cd80c22de42ac9300943a2 100644 --- a/plugins/ets/runtime/ts2ets/ts2ets_common.h +++ b/plugins/ets/runtime/interop_js/ts2ets_common.h @@ -16,21 +16,50 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_COMMON_H_ #define PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_COMMON_H_ -#ifdef PANDA_WITH_OHOS_NAPI - -#include "plugins/ets/runtime/ts2ets/ets_type_visitor-inl.h" +#include "plugins/ets/runtime/interop_js/ets_type_visitor-inl.h" #include "runtime/include/thread_scopes.h" #include -#include -namespace panda::ets::ts2ets { +#ifdef PANDA_TARGET_OHOS +#include #define OH_TS2ETS_LOG_INFO(msg) OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "ts2ets", msg) #define OH_TS2ETS_LOG_INFO_A(msg, ...) OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "ts2ets", msg, __VA_ARGS__) #define OH_TS2ETS_LOG_ERROR(msg) OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "ts2ets", msg) #define OH_TS2ETS_LOG_ERROR_A(msg, ...) OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "ts2ets", msg, __VA_ARGS__) +#else + +static inline const char *EtsLogMakeString(char *buf, size_t buf_size, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int n = vsnprintf(buf, buf_size, fmt, ap); + if (n < 0) { + LOG(FATAL, ETS) << "ts2ets: Cannot convert message to log buffer"; + UNREACHABLE(); + } + va_end(ap); + n = n < int(buf_size) ? n : buf_size; + buf[n] = '\0'; + return buf; +} + +#define TS2ETS_LOGGER(level, ...) \ + do { \ + char buf[256]; \ + LOG(level, ETS) << "ts2ets: " << EtsLogMakeString(buf, sizeof(buf), __VA_ARGS__); \ + } while (0) + +#define OH_TS2ETS_LOG_INFO(msg) TS2ETS_LOGGER(INFO, msg) +#define OH_TS2ETS_LOG_INFO_A(msg, ...) TS2ETS_LOGGER(INFO, msg, __VA_ARGS__) +#define OH_TS2ETS_LOG_ERROR(msg) TS2ETS_LOGGER(INFO, msg) +#define OH_TS2ETS_LOG_ERROR_A(msg, ...) TS2ETS_LOGGER(INFO, msg, __VA_ARGS__) +#endif + +namespace panda::ets::ts2ets { + [[noreturn]] void __attribute__((noinline)) ts2ets_fatal(char const *message); #define NAPI_FATAL_IF(expr) \ @@ -121,6 +150,4 @@ private: } // namespace panda::ets::ts2ets -#endif - #endif // !PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_COMMON_H_ diff --git a/plugins/ets/runtime/ts2ets/ts2ets_copy.cpp b/plugins/ets/runtime/interop_js/ts2ets_copy.cpp similarity index 98% rename from plugins/ets/runtime/ts2ets/ts2ets_copy.cpp rename to plugins/ets/runtime/interop_js/ts2ets_copy.cpp index b4b5f784de64570b435e93d3cf5b845885be3341..128ee913acad2279bf46dc0e81fa5f6eb18aab71 100644 --- a/plugins/ets/runtime/ts2ets/ts2ets_copy.cpp +++ b/plugins/ets/runtime/interop_js/ts2ets_copy.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "plugins/ets/runtime/ts2ets/ts2ets_common.h" +#include "plugins/ets/runtime/interop_js/ts2ets_common.h" #include "runtime/include/panda_vm.h" #include "runtime/handle_scope-inl.h" @@ -646,8 +646,8 @@ napi_value InvokeEtsMethodImpl(napi_env env, napi_value *jsargv, uint32_t jsargc } args = js2ets.GetResult(); auto end = std::chrono::steady_clock::now(); - OH_TS2ETS_LOG_INFO_A("InvokeEtsMethod: js2ets elapsed time %lld us", - std::chrono::duration_cast(end - begin).count()); + long long int t = std::chrono::duration_cast(end - begin).count(); + OH_TS2ETS_LOG_INFO_A("InvokeEtsMethod: js2ets elapsed time %lld us", t); } panda::Value ets_res = method->Invoke(thread, args.data()); @@ -686,8 +686,8 @@ napi_value InvokeEtsMethodImpl(napi_env env, napi_value *jsargv, uint32_t jsargc } js_res = ets2js.GetResult(); auto end = std::chrono::steady_clock::now(); - OH_TS2ETS_LOG_INFO_A("InvokeEtsMethod: ets2js elapsed time %lld us", - std::chrono::duration_cast(end - begin).count()); + long long int t = std::chrono::duration_cast(end - begin).count(); + OH_TS2ETS_LOG_INFO_A("InvokeEtsMethod: ets2js elapsed time %ldd us", t); js_handle_scope.Escape(js_res); } diff --git a/plugins/ets/runtime/ts2ets/ts2ets_copy.h b/plugins/ets/runtime/interop_js/ts2ets_copy.h similarity index 96% rename from plugins/ets/runtime/ts2ets/ts2ets_copy.h rename to plugins/ets/runtime/interop_js/ts2ets_copy.h index 39dce7e2bcce3a387d7366406fee3cfc4a202075..78f020606888ab5ad3d589c631beca4398925706 100644 --- a/plugins/ets/runtime/ts2ets/ts2ets_copy.h +++ b/plugins/ets/runtime/interop_js/ts2ets_copy.h @@ -16,8 +16,6 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_COPY_H_ #define PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_COPY_H_ -#ifdef PANDA_WITH_OHOS_NAPI - #include namespace panda::ets::ts2ets { @@ -26,6 +24,4 @@ napi_value InvokeEtsMethodImpl(napi_env env, napi_value *jsargv, uint32_t jsargc } // namespace panda::ets::ts2ets -#endif - #endif // !PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_COPY_H_ diff --git a/plugins/ets/runtime/ts2ets/ts2ets_proxy.cpp b/plugins/ets/runtime/interop_js/ts2ets_proxy.cpp similarity index 99% rename from plugins/ets/runtime/ts2ets/ts2ets_proxy.cpp rename to plugins/ets/runtime/interop_js/ts2ets_proxy.cpp index 22386904ee13dc4637a6a48e897fc8616c2855d9..d60e49cb5993706e74884dac1a8ad7af5d228073 100644 --- a/plugins/ets/runtime/ts2ets/ts2ets_proxy.cpp +++ b/plugins/ets/runtime/interop_js/ts2ets_proxy.cpp @@ -13,13 +13,15 @@ * limitations under the License. */ -#include "plugins/ets/runtime/ts2ets/ts2ets_common.h" -#include "plugins/ets/runtime/ts2ets/ts2ets_proxy.h" +#include "plugins/ets/runtime/interop_js/ts2ets_common.h" +#include "plugins/ets/runtime/interop_js/ts2ets_proxy.h" #include "runtime/handle_scope-inl.h" #include "plugins/ets/runtime/ets_utils.h" #include "runtime/mem/refstorage/global_object_storage.h" +#include + namespace panda::ets::ts2ets { #ifndef NDEBUG @@ -163,7 +165,7 @@ public: ASSERT(Lookup(klass) == nullptr); auto [it, found] = cache_.emplace(std::piecewise_construct, std::forward_as_tuple(klass), std::forward_as_tuple()); - ASSERT(it.second); + ASSERT(found); auto &res = it->second; @@ -266,7 +268,7 @@ public: ASSERT(Lookup(method) == nullptr); auto [it, found] = cache_.emplace(std::piecewise_construct, std::forward_as_tuple(method), std::forward_as_tuple()); - ASSERT(it.second); + ASSERT(found); auto &res = it->second; PROXY_DLOG_A("WrapperMethodCache: inserted: %p -> %p", (void *)method, (void *)&res); return &res; @@ -523,7 +525,7 @@ TS2ETS_WRAPPER_UNWRAP(F32, float) ets_val = val; return true; } -TS2ETS_WRAPPER_FIELD_ACCESSOR_PRIMITIVE(F32, float); +TS2ETS_WRAPPER_FIELD_ACCESSOR_PRIMITIVE(F32, float) TS2ETS_WRAPPER_WRAP(I32, int32_t) { @@ -545,7 +547,7 @@ TS2ETS_WRAPPER_UNWRAP(I32, int32_t) ets_val = val; return true; } -TS2ETS_WRAPPER_FIELD_ACCESSOR_PRIMITIVE(I32, int32_t); +TS2ETS_WRAPPER_FIELD_ACCESSOR_PRIMITIVE(I32, int32_t) TS2ETS_WRAPPER_WRAP(I64, int64_t) { @@ -567,7 +569,7 @@ TS2ETS_WRAPPER_UNWRAP(I64, int64_t) ets_val = val; return true; } -TS2ETS_WRAPPER_FIELD_ACCESSOR_PRIMITIVE(I64, int64_t); +TS2ETS_WRAPPER_FIELD_ACCESSOR_PRIMITIVE(I64, int64_t) TS2ETS_WRAPPER_WRAP(OBJ, panda::ObjectHeader *) { @@ -832,15 +834,11 @@ private: { auto name = reinterpret_cast(method->GetName().data); - napi_property_attributes attr; napi_callback impl; - if (method->IsStatic()) { impl = CallWrapperMethod; - attr = static_method_attr; } else { impl = CallWrapperMethod; - attr = method_attr; } wclass_->wmethods.push_back(WrapperMethodLink(method)); // lazy diff --git a/plugins/ets/runtime/ts2ets/ts2ets_proxy.h b/plugins/ets/runtime/interop_js/ts2ets_proxy.h similarity index 97% rename from plugins/ets/runtime/ts2ets/ts2ets_proxy.h rename to plugins/ets/runtime/interop_js/ts2ets_proxy.h index 96d637d9ce55f6d14a23e0545f5c5d8b94bbfed9..9a8b1b03e35f4e540b70171aeb8113a225899f35 100644 --- a/plugins/ets/runtime/ts2ets/ts2ets_proxy.h +++ b/plugins/ets/runtime/interop_js/ts2ets_proxy.h @@ -16,8 +16,6 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_PROXY_H_ #define PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_PROXY_H_ -//#ifdef PANDA_WITH_OHOS_NAPI - #include namespace panda::ets::ts2ets { @@ -42,6 +40,4 @@ napi_value RegisterETSFunctionImpl(napi_env env, napi_value *jsargv, uint32_t js } // namespace panda::ets::ts2ets -//#endif - #endif // !PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_PROXY_H_ diff --git a/plugins/ets/subproject_sources.gn b/plugins/ets/subproject_sources.gn index 99eddb80dd1ec151405aefe7000750b79e64b027..6a543e3b9b70e753ea7bc37a9c522d49c998e969 100644 --- a/plugins/ets/subproject_sources.gn +++ b/plugins/ets/subproject_sources.gn @@ -67,9 +67,9 @@ srcs_runtime = [ if (ark_with_ohos_napi) { srcs_runtime += [ - "runtime/ts2ets/ts2ets_common.cpp", - "runtime/ts2ets/ts2ets_copy.cpp", - "runtime/ts2ets/ts2ets_proxy.cpp", + "runtime/interop_js/ts2ets_common.cpp", + "runtime/interop_js/ts2ets_copy.cpp", + "runtime/interop_js/ts2ets_proxy.cpp", ] } diff --git a/plugins/ets/tests/CMakeLists.txt b/plugins/ets/tests/CMakeLists.txt index 6e1ca6f2fed7f17b3c14dc502ad1489cf44895bd..96d6b8de2a70943950f40e04f948d07d0bf2872d 100644 --- a/plugins/ets/tests/CMakeLists.txt +++ b/plugins/ets/tests/CMakeLists.txt @@ -315,3 +315,8 @@ endfunction() add_custom_target(ets_common_gtests) add_dependencies(ets_gtests ets_common_gtests) add_subdirectory(mock) + + +if (PANDA_ETS_INTEROP_JS) + add_subdirectory(interop_js) +endif() diff --git a/plugins/ets/tests/interop_js/CMakeLists.txt b/plugins/ets/tests/interop_js/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ef6854334f94205fef817f37439161fb9ed6e16 --- /dev/null +++ b/plugins/ets/tests/interop_js/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (c) 2021-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + +include(cmake/import.cmake) + +add_subdirectory(gtest_plugin) +add_subdirectory(tests) diff --git a/plugins/ets/tests/interop_js/cmake/import.cmake b/plugins/ets/tests/interop_js/cmake/import.cmake new file mode 100644 index 0000000000000000000000000000000000000000..d0494a8735e1ed03361038e5d0de479d3bc68375 --- /dev/null +++ b/plugins/ets/tests/interop_js/cmake/import.cmake @@ -0,0 +1,14 @@ +# Copyright (c) 2021-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + +include(cmake/interop_js_tests.cmake) diff --git a/plugins/ets/tests/interop_js/cmake/interop_js_tests.cmake b/plugins/ets/tests/interop_js/cmake/interop_js_tests.cmake new file mode 100644 index 0000000000000000000000000000000000000000..dc71aa8accd7788968c0ca1a5335c0ae16d82905 --- /dev/null +++ b/plugins/ets/tests/interop_js/cmake/interop_js_tests.cmake @@ -0,0 +1,68 @@ +# Copyright (c) 2021-2022 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + + +add_custom_target(ets_interop_js_gtests COMMENT "Runing ets_interop_js tests") +add_dependencies(ets_gtests ets_interop_js_gtests) + + +# Add Googletest-based tests to ets_interop_js_gtests target. +# +# Example usage: +# panda_ets_interop_js_gtest(test_name +# CPP_SOURCES +# tests/unit1_test.cpp +# tests/unit2_test.cpp +# ETS_SOURCES +# tests/unit1_test.ets +# tests/unit2_test.ets +# ) +function(panda_ets_interop_js_gtest TARGET) + # Parse arguments + cmake_parse_arguments( + ARG + "" + "" + "CPP_SOURCES;ETS_SOURCES" + ${ARGN} + ) + + set(INTEROP_TESTS_DIR "${PANDA_BINARY_ROOT}/tests/ets_interop_js") + panda_ets_interop_js_plugin(${TARGET} + SOURCES ${ARG_CPP_SOURCES} + LIBRARIES ets_interop_js_gtest + LIBRARY_OUTPUT_DIRECTORY "${INTEROP_TESTS_DIR}/lib/module" + ) + + set(TARGET_GTEST_PACKAGE ${TARGET}_gtest_pacage) + panda_ets_package_gtest(${TARGET_GTEST_PACKAGE} + ETS_SOURCES ${ARG_ETS_SOURCES} + ) + add_dependencies(${TARGET} ${TARGET_GTEST_PACKAGE}) + + # Add launcher <${TARGET}_gtests> target + common_add_gtest( + NAME ${TARGET} + NO_EXECUTABLE + NO_CORES + CUSTOM_PRERUN_ENVIRONMENT + "ARK_ETS_STDLIB_PATH=${PANDA_BINARY_ROOT}/plugins/ets/etsstdlib.abc" + "ARK_ETS_INTEROP_JS_GTEST_ABC_PATH=${PANDA_BINARY_ROOT}/abc-gtests/${TARGET_GTEST_PACKAGE}.zip" + LAUNCHER node gtest_launcher.js ${TARGET} + DEPS_TARGETS ${TARGET} ets_interop_js_gtest_launcher + TEST_RUN_DIR ${INTEROP_TESTS_DIR} + OUTPUT_DIRECTORY ${INTEROP_TESTS_DIR} + ) + + add_dependencies(ets_interop_js_gtests ${TARGET}_gtests) +endfunction(panda_ets_interop_js_gtest) diff --git a/plugins/ets/tests/interop_js/gtest_plugin/CMakeLists.txt b/plugins/ets/tests/interop_js/gtest_plugin/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bbc501ca91831dd42f99944bcbc5afbe080dd978 --- /dev/null +++ b/plugins/ets/tests/interop_js/gtest_plugin/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (c) 2021-2022 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + + +# Create ets_interop_js_gtest plugin +add_library(ets_interop_js_gtest STATIC ets_interop_js_gtest.cpp) +target_link_libraries(ets_interop_js_gtest gtest) +set_target_properties(ets_interop_js_gtest PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_include_directories(ets_interop_js_gtest + PUBLIC ${PANDA_ETS_PLUGIN_SOURCE}/tests/interop_js/gtest_plugin +) +if(PANDA_TARGET_OHOS) + target_link_libraries(ets_interop_js_gtest ace_napi.z) +else() + if(NAPI_HEADERS_PATH) + target_include_directories(ets_interop_js_gtest PRIVATE ${NAPI_HEADERS_PATH}) + else() + message(FATAL_ERROR "NAPI_HEADERS_PATH is not set") + endif() +endif() + + +# Copy gtest_launcher.js to /tests/ets_interop_js/ +set(GTEST_LAUNCHER_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/gtest_launcher.js") +set(GTEST_LAUNCHER "${PANDA_BINARY_ROOT}/tests/ets_interop_js/gtest_launcher.js") +add_custom_command( + OUTPUT ${GTEST_LAUNCHER} + COMMENT "Copy ${GTEST_LAUNCHER_SOURCE} to ${GTEST_LAUNCHER}" + COMMAND cp ${GTEST_LAUNCHER_SOURCE} ${GTEST_LAUNCHER} + DEPENDS ${GTEST_LAUNCHER_SOURCE} +) +add_custom_target(ets_interop_js_gtest_launcher + DEPENDS ${GTEST_LAUNCHER} ets_vm_plugin +) diff --git a/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.cpp b/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a706b1146312b384c55a6d36f0a2de9ef56ccac6 --- /dev/null +++ b/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.cpp @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include +#include "ets_interop_js_gtest.h" + +#define ETS_PLUGIN_FATAL(msg) \ + do { \ + std::cerr << "ETS_INTEROP_GTEST_PLUGIN: " << msg << std::endl; \ + std::abort(); \ + } while (0) + +namespace panda::ets::interop::js::testing { + +napi_env EtsInteropTest::js_env_ = {}; + +class JsEnvAccessor { +public: + static void SetJsEnv(napi_env env) + { + EtsInteropTest::js_env_ = env; + } + + static void ResetJsEnv() + { + EtsInteropTest::js_env_ = {}; + } +}; + +static napi_value Main(napi_env env, napi_callback_info info) +{ + size_t js_argc = 0; + napi_status status; + status = napi_get_cb_info(env, info, &js_argc, nullptr, nullptr, nullptr); + assert(status == napi_ok); + + if (js_argc != 1) { + ETS_PLUGIN_FATAL("Incorrect argc, argc=" << js_argc); + } + + auto js_argv = std::make_unique(js_argc); + napi_value this_arg; + void *data; + status = napi_get_cb_info(env, info, &js_argc, js_argv.get(), &this_arg, &data); + assert(status == napi_ok); + + napi_value js_array = js_argv[0]; + uint32_t js_array_length; + status = napi_get_array_length(env, js_array, &js_array_length); + assert(status == napi_ok); + + auto argv = std::make_unique(js_array_length); + std::vector> holder_args; + for (uint32_t i = 0; i < js_array_length; ++i) { + napi_value js_array_element; + status = napi_get_element(env, js_array, i, &js_array_element); + assert(status == napi_ok); + + size_t str_length; + status = napi_get_value_string_utf8(env, js_array_element, nullptr, 0, &str_length); + assert(status == napi_ok); + + auto utf8_str = std::make_unique(str_length + 1); + size_t copied; + status = napi_get_value_string_utf8(env, js_array_element, utf8_str.get(), str_length + 1, &copied); + assert(status == napi_ok); + utf8_str[copied] = '\0'; + + holder_args.push_back(std::move(utf8_str)); + argv[i] = holder_args[i].get(); + } + + int argc = js_array_length; + ::testing::InitGoogleTest(&argc, argv.get()); + + // Run tests + JsEnvAccessor::SetJsEnv(env); + int ret_value = RUN_ALL_TESTS(); + JsEnvAccessor::ResetJsEnv(); + + napi_value js_ret_value; + status = napi_create_int32(env, ret_value, &js_ret_value); + assert(status == napi_ok); + return js_ret_value; +} + +static napi_value Init(napi_env env, napi_value exports) +{ + const std::array desc = { + napi_property_descriptor {"main", 0, Main, 0, 0, 0, napi_enumerable, 0}, + }; + + napi_status status; + status = napi_define_properties(env, exports, desc.size(), desc.data()); + assert(status == napi_ok); + + return exports; +} + +} // namespace panda::ets::interop::js::testing + +NAPI_MODULE(GTEST_ADDON, panda::ets::interop::js::testing::Init) diff --git a/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h b/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h new file mode 100644 index 0000000000000000000000000000000000000000..de04cffff89555e109da53ca680aff0f0b820c7a --- /dev/null +++ b/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h @@ -0,0 +1,223 @@ +/** + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#ifndef PANDA_PLUGINS_ETS_INTEROP_JS_GTEST_H_ +#define PANDA_PLUGINS_ETS_INTEROP_JS_GTEST_H_ + +#include +#include + +namespace panda::ets::interop::js::testing { + +class EtsInteropTest : public ::testing::Test { +public: + static void SetUpTestSuite() + { + runJsScript(R"( + // load ets_vm_plugin to globalThis.gtest.etsVm + gtest.etsVm = gtest.require("ets_vm_plugin"); + )"); + } + + static void runJsScript(const std::string &script) + { + doRunJsScript(js_env_, script); + } + + template + static R callEtsMethod(std::string_view fn_name, Args... args) + { + return doCallEtsMethod(fn_name, js_env_, args...); + } + + static napi_env getJsEnv() + { + return js_env_; + } + +private: + static void doRunJsScript(napi_env env, const std::string &script) + { + napi_status status; + napi_value js_script; + status = napi_create_string_utf8(env, script.c_str(), script.length(), &js_script); + assert(status == napi_ok); + + napi_value js_result; + status = napi_run_script(env, js_script, &js_result); + if (status == napi_generic_failure) { + napi_value fatal_exception; + status = napi_get_and_clear_last_exception(env, &fatal_exception); + assert(status == napi_ok); + + status = napi_fatal_exception(env, fatal_exception); + assert(status == napi_ok); + + // Unreachable code + std::abort(); + } + ASSERT_EQ(status, napi_ok); + } + + template + static T getRetValue([[maybe_unused]] napi_env env, napi_value js_value) + { + if constexpr (std::is_same_v) { + double v; + napi_status status = napi_get_value_double(env, js_value, &v); + assert(status == napi_ok); + return v; + } else if constexpr (std::is_same_v) { + int32_t v; + napi_status status = napi_get_value_int32(env, js_value, &v); + assert(status == napi_ok); + return v; + } else if constexpr (std::is_same_v) { + uint32_t v; + napi_status status = napi_get_value_uint32(env, js_value, &v); + assert(status == napi_ok); + return v; + } else if constexpr (std::is_same_v) { + int64_t v; + napi_status status = napi_get_value_int64(env, js_value, &v); + assert(status == napi_ok); + return v; + } else if constexpr (std::is_same_v) { + napi_status status; + size_t length; + status = napi_get_value_string_utf8(env, js_value, nullptr, 0, &length); + assert(status == napi_ok); + std::string v(length, '\0'); + size_t copied; + status = napi_get_value_string_utf8(env, js_value, v.data(), length + 1, &copied); + assert(status == napi_ok); + assert(length == copied); + return v; + } else if constexpr (std::is_same_v) { + return js_value; + } else { + enum { INCORRECT_TEMPLATE_TYPE = false }; + static_assert(INCORRECT_TEMPLATE_TYPE, "Incorrect template type"); + } + } + + static napi_value makeJsArg(napi_env env, double arg) + { + napi_value v; + napi_status status = napi_create_double(env, arg, &v); + assert(status == napi_ok); + return v; + } + + static napi_value makeJsArg(napi_env env, int32_t arg) + { + napi_value v; + napi_status status = napi_create_int32(env, arg, &v); + assert(status == napi_ok); + return v; + } + + static napi_value makeJsArg(napi_env env, uint32_t arg) + { + napi_value v; + napi_status status = napi_create_uint32(env, arg, &v); + assert(status == napi_ok); + return v; + } + + static napi_value makeJsArg(napi_env env, int64_t arg) + { + napi_value v; + napi_status status = napi_create_int64(env, arg, &v); + assert(status == napi_ok); + return v; + } + + static napi_value makeJsArg(napi_env env, std::string_view arg) + { + napi_value v; + napi_status status = napi_create_string_utf8(env, arg.data(), arg.length(), &v); + assert(status == napi_ok); + return v; + } + + static napi_value makeJsArg([[maybe_unused]] napi_env env, napi_value arg) + { + return arg; + } + + static napi_value getJsGtestObject(napi_env env) + { + napi_status status; + + // Get globalThis + napi_value js_global_object; + status = napi_get_global(env, &js_global_object); + assert(status == napi_ok); + + // Get globalThis.gtest + napi_value js_gtest_object; + status = napi_get_named_property(env, js_global_object, "gtest", &js_gtest_object); + assert(status == napi_ok); + + return js_gtest_object; + } + + template + static R doCallEtsMethod(std::string_view fn_name, napi_env env, Args... args) + { + napi_status status; + + // Get globalThis.gtest + napi_value js_gtest_object = getJsGtestObject(env); + + // Set globalThis.gtest.functionName + napi_value js_function_name; + status = napi_create_string_utf8(env, fn_name.data(), fn_name.length(), &js_function_name); + assert(status == napi_ok); + status = napi_set_named_property(env, js_gtest_object, "functionName", js_function_name); + assert(status == napi_ok); + + // Set globalThis.gtest.args + std::initializer_list napi_args = {makeJsArg(env, args)...}; + napi_value js_args; + status = napi_create_array_with_length(env, napi_args.size(), &js_args); + assert(status == napi_ok); + uint32_t i = 0; + for (auto arg : napi_args) { + status = napi_set_element(env, js_args, i++, arg); + assert(status == napi_ok); + } + status = napi_set_named_property(env, js_gtest_object, "args", js_args); + assert(status == napi_ok); + + // Call ETS method via JS + runJsScript(R"( + gtest.ret = gtest.etsVm.call(gtest.functionName, ...gtest.args); + )"); + + // Get globalThis.gtest.ret + napi_value js_ret_value {}; + status = napi_get_named_property(env, js_gtest_object, "ret", &js_ret_value); + return getRetValue(env, js_ret_value); + } + + friend class JsEnvAccessor; + static napi_env js_env_; +}; + +} // namespace panda::ets::interop::js::testing + +#endif // !PANDA_PLUGINS_ETS_INTEROP_JS_GTEST_H_ diff --git a/plugins/ets/tests/interop_js/gtest_plugin/gtest_launcher.js b/plugins/ets/tests/interop_js/gtest_plugin/gtest_launcher.js new file mode 100644 index 0000000000000000000000000000000000000000..06f3f2dfa7914f9b5d99a93cc5006334ce559f57 --- /dev/null +++ b/plugins/ets/tests/interop_js/gtest_plugin/gtest_launcher.js @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + + +function main() { + // Init 'gtestRootPath' + let gtestRootPath = (() => { + let path = process.env.ETS_GTEST_ROOT_PATH; + if (path == undefined) { + return __dirname + "/../.."; + } + return path; + })(); + + // Add 'gtest' object to global space. + // This object is used by gtests as storage to save and restore variables + gtest = {} + + // 'gtest.require' is used by gtests to load the node modules. + gtest.require = (modulePath) => { + let fullPath = gtestRootPath + "/lib/module/" + modulePath; + + console.log("fullPath=" + fullPath); + return require(fullPath); + } + + let gtestName = process.argv[2]; + if (gtestName == undefined) { + console.error(`Usage: ${process.argv[0]} ${process.argv[1]} `); + return 1; + } + + // Run gtest + console.log(`Run ets_interop_js_gtest module: ${gtestName}`) + var ets_gtest = require(`./lib/module/${gtestName}`); + let args = process.argv.slice(2); + let ret = ets_gtest.main(args); + return ret; +} + +process.exit(main()) diff --git a/plugins/ets/tests/interop_js/tests/CMakeLists.txt b/plugins/ets/tests/interop_js/tests/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a2fe2266426a81cbe4bb75c16a8f4c2e7b7c5767 --- /dev/null +++ b/plugins/ets/tests/interop_js/tests/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (c) 2021-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + +panda_ets_interop_js_gtest(ets_interop_js_test__sample + CPP_SOURCES sample/test_sample.cpp + ETS_SOURCES sample/test_sample.ets +) diff --git a/plugins/ets/tests/interop_js/tests/sample/test_sample.cpp b/plugins/ets/tests/interop_js/tests/sample/test_sample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f907223ad71dc3724e65ef9efd966140802e34a --- /dev/null +++ b/plugins/ets/tests/interop_js/tests/sample/test_sample.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include "ets_interop_js_gtest.h" + +namespace panda::ets::interop::js::testing { + +class EtsInteropJsSampleTest : public EtsInteropTest {}; + +TEST_F(EtsInteropJsSampleTest, ets_return_int_arg0) +{ + int32_t ret = callEtsMethod("ets_return_int_arg0", 253); + ASSERT_EQ(ret, 253); +} + +TEST_F(EtsInteropJsSampleTest, ets_sum_double) +{ + double ret = callEtsMethod("ets_sum_double", 5.2, 9.3); + ASSERT_EQ(ret, 5.2 + 9.3); +} + +TEST_F(EtsInteropJsSampleTest, ets_sum_any_types) +{ + std::string ret = callEtsMethod("ets_sum_any_types", 934, "_input_string_", 9.435); + ASSERT_STREQ(ret.c_str(), "934_input_string_9.435"); +} + +TEST_F(EtsInteropJsSampleTest, ets_use_napi) +{ + napi_value ret = callEtsMethod("ets_use_napi", 73, 2.35); + + napi_env env = getJsEnv(); + napi_status status; + + napi_value v0_js; + status = napi_get_named_property(env, ret, "v0", &v0_js); + ASSERT_EQ(status, napi_ok); + int32_t v0; + status = napi_get_value_int32(env, v0_js, &v0); + ASSERT_EQ(status, napi_ok); + + napi_value v1_js; + status = napi_get_named_property(env, ret, "v1", &v1_js); + ASSERT_EQ(status, napi_ok); + double v1; + status = napi_get_value_double(env, v1_js, &v1); + ASSERT_EQ(status, napi_ok); + + ASSERT_EQ(v0, 73); + ASSERT_EQ(v1, 2.35); +} + +} // namespace panda::ets::interop::js::testing diff --git a/plugins/ets/tests/interop_js/tests/sample/test_sample.ets b/plugins/ets/tests/interop_js/tests/sample/test_sample.ets new file mode 100644 index 0000000000000000000000000000000000000000..8d5c9bd42a4ead465310ed5b1d02fa8866ccdb36 --- /dev/null +++ b/plugins/ets/tests/interop_js/tests/sample/test_sample.ets @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + + +function ets_return_int_arg0(v0: int): int { + return v0; +} + +function ets_sum_double(v0: double, v1: double): double { + return v0 + v1; +} + +function ets_sum_any_types(v0: int, v1: String, v2: double): String { + return v0 + v1 + v2; +} + +class TmpDict { + constructor(v0: int, v1: double) { + this.v0 = v0; + this.v1 = v1; + } + + v0: int; + v1: double +} + +function ets_use_napi(v0: int, v1: double): TmpDict { + return new TmpDict(v0, v1); +} diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index e47db6e8db2d4284a965abfcb5913a19a2a921c9..977d4efaf0ad16113387f4a808cc17c1c05fd99b 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -474,11 +474,6 @@ if (NOT PANDA_TARGET_OHOS) target_link_libraries(arkruntime_static atomic) endif() -if (PANDA_WITH_OHOS_NAPI) - target_compile_definitions(arkruntime_static PUBLIC -DPANDA_WITH_OHOS_NAPI) - target_link_libraries(arkruntime_static ace_napi.z) -endif() - set(CSA_TESTS_ARKRUNTIME_PATH ${GEN_INCLUDE_DIR}/debug_test_interpreter-inl_gen.cpp) add_library(csa_tests_arkruntime_interpreter_impl OBJECT EXCLUDE_FROM_ALL ${CSA_TESTS_ARKRUNTIME_PATH}) target_include_directories(csa_tests_arkruntime_interpreter_impl diff --git a/scripts/sdk/build_sdk.sh b/scripts/sdk/build_sdk.sh index aeff70a9c58bce09040621efafb1e2d3d6a2725c..ea25b96360aba4a921bab9efad947faadd9f2bf4 100755 --- a/scripts/sdk/build_sdk.sh +++ b/scripts/sdk/build_sdk.sh @@ -93,7 +93,7 @@ TARGET_CMAKE_ARGS=" \ -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/cross-ohos-musl-aarch64.cmake \ -DTOOLCHAIN_SYSROOT=$OHOS_SDK/sysroot \ -DTOOLCHAIN_CLANG_ROOT=$OHOS_SDK/llvm \ - -DPANDA_WITH_OHOS_NAPI=ON \ + -DPANDA_ETS_INTEROP_JS=ON \ -DPANDA_WITH_ECMASCRIPT=OFF" build_panda "$TARGET_BUILD_DIR" "$TARGET_CMAKE_ARGS" "arkruntime arkassembler" copy_into_sdk "$TARGET_BUILD_DIR" "$TARGET_SDK_DIR" "$SCRIPT_DIR"/ohos_arm64.txt