From 7acea0d0e878c8271616f687e828dc53479d46b0 Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Thu, 6 Apr 2023 20:52:23 +0300 Subject: [PATCH 1/3] assembler: Update ASSERT() Signed-off-by: Vyacheslav Cherkashin --- assembler/assembly-emitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assembler/assembly-emitter.cpp b/assembler/assembly-emitter.cpp index d3ab1b8ea..22b475c83 100644 --- a/assembler/assembly-emitter.cpp +++ b/assembler/assembly-emitter.cpp @@ -713,7 +713,7 @@ static void AddBytecodeIndexDependencies(MethodItem *method, const Ins &insn, for (const auto &id : insn.ids) { auto it = items.find(id); - ASSERT(it != items.cend()); + ASSERT_PRINT(it != items.cend(), "Symbol '" << id << " not found"); auto *item = it->second; ASSERT(item->GetIndexType() != panda_file::IndexType::NONE); -- Gitee From 9f10a61d09d140c2fd41e6a021ab119736f6f1af Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Wed, 29 Mar 2023 14:59:52 +0300 Subject: [PATCH 2/3] Map panda::ets::interop::js::JSValue to std.interop.js.JSValue List of changes: * Add std.interop.js.JSValue and std.interop.js.JSRuntime to etsstdlib * Use panda::ets::interop::js namespace for interop_js plugin * Separate GlobalCtx and EtsJSNapiEnvScope classes from common code * Map panda::ets::interop::js::JSValue to std.interop.js.JSValue Signed-off-by: Vyacheslav Cherkashin --- plugins/ets/cmake/interop_js_plugin.cmake | 11 +- plugins/ets/ets_plugin_options.yaml | 2 +- plugins/ets/intrinsics.cmake | 4 + plugins/ets/runtime/CMakeLists.txt | 11 + plugins/ets/runtime/ets_vm.h | 16 ++ plugins/ets/runtime/interop_js/CMakeLists.txt | 3 + .../runtime/interop_js/ets_type_visitor-inl.h | 7 +- .../ets/runtime/interop_js/ets_vm_plugin.cpp | 10 +- .../ets/runtime/interop_js/ets_vm_plugin.h | 80 +++++++ .../ets/runtime/interop_js/global_context.cpp | 47 ++++ .../ets/runtime/interop_js/global_context.h | 75 +++++++ .../intrinsics/std_js_jsruntime.cpp | 87 ++++++++ .../interop_js/intrinsics/std_js_jsruntime.h | 27 +++ .../intrinsics/std_js_jsruntime.yaml | 71 ++++++ .../ets/runtime/interop_js/intrinsics_api.h | 36 +++ .../interop_js/intrinsics_api_impl.cpp | 64 ++++++ .../runtime/interop_js/intrinsics_api_impl.h | 27 +++ .../interop_js/intrinsics_declaration.h | 25 +++ plugins/ets/runtime/interop_js/js_plugin.h | 80 +++++++ plugins/ets/runtime/interop_js/js_value.cpp | 95 ++++++++ plugins/ets/runtime/interop_js/js_value.h | 140 ++++++++++++ .../ets/runtime/interop_js/napi_env_scope.h | 55 +++++ .../ets/runtime/interop_js/ts2ets_common.cpp | 20 +- .../ets/runtime/interop_js/ts2ets_common.h | 75 +------ .../ets/runtime/interop_js/ts2ets_copy.cpp | 72 +++--- plugins/ets/runtime/interop_js/ts2ets_copy.h | 4 +- .../ets/runtime/interop_js/ts2ets_jsvalue.cpp | 17 +- .../ets/runtime/interop_js/ts2ets_jsvalue.h | 51 +---- .../interop_js/ts2ets_jsvalue_exports.h | 4 +- .../ets/runtime/interop_js/ts2ets_proxy.cpp | 9 +- plugins/ets/runtime/interop_js/ts2ets_proxy.h | 4 +- .../ets/runtime/interop_js/ts2ets_tstype.cpp | 17 +- plugins/ets/runtime/intrinsics_declaration.h | 25 +++ .../ets/stdlib/std/interop/js/JSException.ets | 30 +++ .../ets/stdlib/std/interop/js/JSRuntime.ets | 206 ++++++++++++++++++ plugins/ets/stdlib/std/interop/js/JSValue.ets | 21 ++ .../interop_js/cmake/interop_js_tests.cmake | 7 +- .../gtest_plugin/ets_interop_js_gtest.h | 4 +- .../ets/tests/interop_js/tests/CMakeLists.txt | 13 +- .../tests/bouncing_pandas/bouncing_pandas.cpp | 5 +- .../tests/js_value/test_js_value.cpp | 130 +++++++++++ .../tests/js_value/test_js_value.ets | 34 +++ .../test_map_mirror_classes.cpp | 66 ++++++ .../test_map_mirror_classes.ets | 2 + .../interop_js/tests/sample/test_sample.cpp | 5 +- 45 files changed, 1584 insertions(+), 210 deletions(-) create mode 100644 plugins/ets/runtime/interop_js/ets_vm_plugin.h create mode 100644 plugins/ets/runtime/interop_js/global_context.cpp create mode 100644 plugins/ets/runtime/interop_js/global_context.h create mode 100644 plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.cpp create mode 100644 plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.h create mode 100644 plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.yaml create mode 100644 plugins/ets/runtime/interop_js/intrinsics_api.h create mode 100644 plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp create mode 100644 plugins/ets/runtime/interop_js/intrinsics_api_impl.h create mode 100644 plugins/ets/runtime/interop_js/intrinsics_declaration.h create mode 100644 plugins/ets/runtime/interop_js/js_plugin.h create mode 100644 plugins/ets/runtime/interop_js/js_value.cpp create mode 100644 plugins/ets/runtime/interop_js/js_value.h create mode 100644 plugins/ets/runtime/interop_js/napi_env_scope.h create mode 100644 plugins/ets/runtime/intrinsics_declaration.h create mode 100644 plugins/ets/stdlib/std/interop/js/JSException.ets create mode 100644 plugins/ets/stdlib/std/interop/js/JSRuntime.ets create mode 100644 plugins/ets/stdlib/std/interop/js/JSValue.ets create mode 100644 plugins/ets/tests/interop_js/tests/js_value/test_js_value.cpp create mode 100644 plugins/ets/tests/interop_js/tests/js_value/test_js_value.ets create mode 100644 plugins/ets/tests/interop_js/tests/map_mirror_classes/test_map_mirror_classes.cpp create mode 100644 plugins/ets/tests/interop_js/tests/map_mirror_classes/test_map_mirror_classes.ets diff --git a/plugins/ets/cmake/interop_js_plugin.cmake b/plugins/ets/cmake/interop_js_plugin.cmake index 68333492d..6c2e13847 100644 --- a/plugins/ets/cmake/interop_js_plugin.cmake +++ b/plugins/ets/cmake/interop_js_plugin.cmake @@ -12,6 +12,15 @@ # limitations under the License. +function(panda_ets_interop_js_napi_include_directories TARGET) + if(NAPI_HEADERS_PATH) + target_include_directories(${TARGET} PRIVATE ${NAPI_HEADERS_PATH}) + else() + message(FATAL_ERROR "NAPI_HEADERS_PATH is not set") + endif() +endfunction(panda_ets_interop_js_napi_include_directories) + + # Create js plugin # # Example usage: @@ -45,7 +54,7 @@ function(panda_ets_interop_js_plugin TARGET) if(PANDA_TARGET_OHOS) target_link_libraries(${TARGET} ace_napi.z) else() - target_include_directories(${TARGET} PRIVATE ${NAPI_HEADERS_PATH}) + panda_ets_interop_js_napi_include_directories(${TARGET}) set_target_properties(${TARGET} PROPERTIES # Set module name diff --git a/plugins/ets/ets_plugin_options.yaml b/plugins/ets/ets_plugin_options.yaml index 6438e5a16..b542589c6 100644 --- a/plugins/ets/ets_plugin_options.yaml +++ b/plugins/ets/ets_plugin_options.yaml @@ -27,7 +27,7 @@ string_class_descriptor: Lstd/core/String; Intrinsics: - header: plugins/ets/runtime/types/ets_array.h + header: plugins/ets/runtime/intrinsics_declaration.h Disasm: language_interface_path: plugins/ets/disassembler/disasm_ets_plugin.inc diff --git a/plugins/ets/intrinsics.cmake b/plugins/ets/intrinsics.cmake index 81e113d83..6e01426f8 100644 --- a/plugins/ets/intrinsics.cmake +++ b/plugins/ets/intrinsics.cmake @@ -1 +1,5 @@ set(ETS_RUNTIME_YAML ${PANDA_ETS_PLUGIN_SOURCE}/runtime/ets_libbase_runtime.yaml) + +if (PANDA_ETS_INTEROP_JS) + list(APPEND ETS_RUNTIME_YAML ${PANDA_ETS_PLUGIN_SOURCE}/runtime/interop_js/intrinsics/std_js_jsruntime.yaml) +endif() diff --git a/plugins/ets/runtime/CMakeLists.txt b/plugins/ets/runtime/CMakeLists.txt index 71c7fd558..31946fa6c 100644 --- a/plugins/ets/runtime/CMakeLists.txt +++ b/plugins/ets/runtime/CMakeLists.txt @@ -84,4 +84,15 @@ endif() if (PANDA_ETS_INTEROP_JS) add_subdirectory(interop_js) + + # NOTE: + # For the following targets, we should to set PANDA_ETS_INTEROP_JS define + # because they use the plugins/ets/runtime/intrinsics_declaration.h file + target_compile_definitions(arkruntime_interpreter_impl PRIVATE -DPANDA_ETS_INTEROP_JS) + target_compile_definitions(arkruntime_static PUBLIC -DPANDA_ETS_INTEROP_JS) + + # NOTE: + # Implementation of intrinsics should be built in 'arkruntime_static' target + target_sources(arkruntime_static PRIVATE ${ETS_EXT_SOURCES}/interop_js/intrinsics/std_js_jsruntime.cpp) + panda_ets_interop_js_napi_include_directories(arkruntime_static) endif() diff --git a/plugins/ets/runtime/ets_vm.h b/plugins/ets/runtime/ets_vm.h index b43d2fa1d..6ed36fc24 100644 --- a/plugins/ets/runtime/ets_vm.h +++ b/plugins/ets/runtime/ets_vm.h @@ -226,6 +226,20 @@ public: [[noreturn]] static void Abort(const char *message = nullptr); + void *GetInteropData() + { + return interop_data_.data(); + } + + static PandaEtsVM *FromInteropData(void *interop_data) + { + ASSERT(interop_data != nullptr); + constexpr size_t INTEROP_DATA_OFFSET = MEMBER_OFFSET(PandaEtsVM, interop_data_); + return reinterpret_cast(reinterpret_cast(interop_data) - INTEROP_DATA_OFFSET); + } + + using InteropData = std::array; + protected: bool CheckEntrypointSignature(Method *entrypoint) override; Expected InvokeEntrypointImpl(Method *entrypoint, @@ -251,6 +265,8 @@ private: os::memory::Mutex finalization_queue_lock_; PandaList registered_finalization_queue_instances_ GUARDED_BY(finalization_queue_lock_); + InteropData interop_data_; + NO_MOVE_SEMANTIC(PandaEtsVM); NO_COPY_SEMANTIC(PandaEtsVM); diff --git a/plugins/ets/runtime/interop_js/CMakeLists.txt b/plugins/ets/runtime/interop_js/CMakeLists.txt index 1b3fe53c5..5cd758c65 100644 --- a/plugins/ets/runtime/interop_js/CMakeLists.txt +++ b/plugins/ets/runtime/interop_js/CMakeLists.txt @@ -27,7 +27,10 @@ endif() panda_ets_interop_js_plugin(ets_interop_js_napi SOURCES + global_context.cpp ets_vm_plugin.cpp + intrinsics_api_impl.cpp + js_value.cpp ts2ets_common.cpp ts2ets_copy.cpp ts2ets_jsvalue.cpp diff --git a/plugins/ets/runtime/interop_js/ets_type_visitor-inl.h b/plugins/ets/runtime/interop_js/ets_type_visitor-inl.h index 7843824a2..a9a50734c 100644 --- a/plugins/ets/runtime/interop_js/ets_type_visitor-inl.h +++ b/plugins/ets/runtime/interop_js/ets_type_visitor-inl.h @@ -19,8 +19,9 @@ #include "libpandabase/macros.h" #include "runtime/include/runtime.h" #include "runtime/mem/heap_manager.h" +#include "plugins/ets/runtime/interop_js/global_context.h" -namespace panda::ets::utils { +namespace panda::ets::interop::js { // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define TYPEVIS_PRIM_TYPES_LIST(V) \ @@ -293,7 +294,7 @@ private: USlot() { - memset(this, 0, sizeof(USlot)); + memset(reinterpret_cast(this), 0, sizeof(USlot)); } }; @@ -301,6 +302,6 @@ private: bool is_field_ = false; }; -} // namespace panda::ets::utils +} // namespace panda::ets::interop::js #endif // !PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_ETS_TYPE_VISITOR_H_ diff --git a/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp b/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp index c69ed762c..f8233950b 100644 --- a/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp +++ b/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp @@ -18,7 +18,7 @@ #include "plugins/ets/runtime/ets_vm_api.h" #include "plugins/ets/runtime/interop_js/ts2ets_copy.h" -namespace panda::ets::napi_addon { +namespace panda::ets::interop::js { static napi_value Version(napi_env env, [[maybe_unused]] napi_callback_info info) { @@ -47,7 +47,7 @@ static bool CreateEtsVM() bool use_jit = false; bool use_aot = false; - return panda::ets::CreateRuntime(ets_stdlib_path, gtest_abc_path, use_jit, use_aot); + return ets::CreateRuntime(ets_stdlib_path, gtest_abc_path, use_jit, use_aot); } static napi_value Call(napi_env env, napi_callback_info info) @@ -63,7 +63,7 @@ static napi_value Call(napi_env env, napi_callback_info info) status = napi_get_cb_info(env, info, &argc, argv.data(), &this_arg, &data); assert(status == napi_ok); - return ts2ets::InvokeEtsMethodImpl(env, argv.data(), argc, false); + return InvokeEtsMethodImpl(env, argv.data(), argc, false); } static napi_value Init(napi_env env, napi_value exports) @@ -86,6 +86,6 @@ static napi_value Init(napi_env env, napi_value exports) return exports; } -} // namespace panda::ets::napi_addon +} // namespace panda::ets::interop::js -NAPI_MODULE(ETS_INTEROP_JS_NAPI, panda::ets::napi_addon::Init) +NAPI_MODULE(ETS_INTEROP_JS_NAPI, panda::ets::interop::js::Init) diff --git a/plugins/ets/runtime/interop_js/ets_vm_plugin.h b/plugins/ets/runtime/interop_js/ets_vm_plugin.h new file mode 100644 index 000000000..8fdb026dd --- /dev/null +++ b/plugins/ets/runtime/interop_js/ets_vm_plugin.h @@ -0,0 +1,80 @@ +/** + * Copyright (c) 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_RUNTIME_INTEROP_JS_JS_PLUGIN_H_ +#define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_PLUGIN_H_ + +#include "libpandabase/macros.h" +#include "plugins/ets/runtime/ets_vm.h" +#include "plugins/ets/runtime/interop_js/global_context.h" +#include "plugins/ets/runtime/interop_js/intrinsics_api_impl.h" +#include "plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.h" + +namespace panda::ets::interop::js { + +class JsPlugin { +public: + void Init() + { + JSRuntimeIntrinsicsSetIntrinsicsAPI(GetIntrinsicsAPI()); + ctx_.Init(); + } + + ALWAYS_INLINE GlobalCtx *GetContext() + { + return &ctx_; + } + + void ThrowException(std::string_view msg) + { + // TODO: Remove the fatal log when exception handling is implemented + LOG(FATAL, ETS) << "ThrowException: msg" << msg; + + EtsCoroutine *cor = EtsCoroutine::GetCurrent(); + LanguageContext lang_ctx = cor->GetLanguageContext(); + const uint8_t *class_descriptor = utf::CStringAsMutf8("Lstd/interop/js/JSException;"); + panda::ThrowException(lang_ctx, cor, class_descriptor, utf::CStringAsMutf8(msg.data())); + } + + static ALWAYS_INLINE JsPlugin *GetCurrent(PandaEtsVM *ets_vm) + { + static_assert(sizeof(PandaEtsVM::InteropData) >= sizeof(JsPlugin), + "JsPlugin doesn't fit into the PandaEtsVM::InteropData"); + + return reinterpret_cast(ets_vm->GetInteropData()); + } + + static ALWAYS_INLINE JsPlugin *GetCurrent(EtsCoroutine *cor) + { + return JsPlugin::GetCurrent(cor->GetPandaVM()); + } + + static ALWAYS_INLINE JsPlugin *GetCurrent() + { + return JsPlugin::GetCurrent(EtsCoroutine::GetCurrent()); + } + + ALWAYS_INLINE PandaEtsVM *GetPandaEtsVM() + { + return PandaEtsVM::FromInteropData(reinterpret_cast(this)); + } + +private: + GlobalCtx ctx_; +}; + +} // namespace panda::ets::interop::js + +#endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_PLUGIN_H_ diff --git a/plugins/ets/runtime/interop_js/global_context.cpp b/plugins/ets/runtime/interop_js/global_context.cpp new file mode 100644 index 000000000..10fa507e6 --- /dev/null +++ b/plugins/ets/runtime/interop_js/global_context.cpp @@ -0,0 +1,47 @@ +/** + * Copyright (c) 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 "plugins/ets/runtime/ets_utils.h" +#include "plugins/ets/runtime/interop_js/global_context.h" +#include "plugins/ets/runtime/interop_js/ets_vm_plugin.h" +#include "plugins/ets/runtime/interop_js/ts2ets_common.h" +#include "runtime/include/runtime.h" + +namespace panda::ets::interop::js { + +void GlobalCtx::Init() +{ + auto ctx = Current(); + + ASSERT(ctx->refstor_ == nullptr); + ASSERT(ctx->linker_ctx_ == nullptr); + ASSERT(ctx->jsvalue_class_ == nullptr); + + ctx->refstor_ = ManagedThread::GetCurrent()->GetVM()->GetGlobalObjectStorage(); + ctx->linker_ctx_ = ets::utils::GetClassLinkerExtension()->GetBootContext(); + ctx->jsvalue_class_ = ResolveEtsClassByName(Runtime::GetCurrent(), "std/interop/js/JSValue"); + + ASSERT(ctx->refstor_ != nullptr); + ASSERT(ctx->linker_ctx_ != nullptr); + ASSERT(ctx->jsvalue_class_ != nullptr); +} + +/*static*/ +GlobalCtx *GlobalCtx::Current() +{ + return JsPlugin::GetCurrent()->GetContext(); +} + +} // namespace panda::ets::interop::js diff --git a/plugins/ets/runtime/interop_js/global_context.h b/plugins/ets/runtime/interop_js/global_context.h new file mode 100644 index 000000000..4012e70a6 --- /dev/null +++ b/plugins/ets/runtime/interop_js/global_context.h @@ -0,0 +1,75 @@ +/** + * Copyright (c) 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_RUNTIME_INTEROP_JS_GLOBAL_CONTEXT_H_ +#define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_GLOBAL_CONTEXT_H_ + +#include "libpandabase/macros.h" +#include + +namespace panda { + +class Class; +class ClassLinkerContext; + +namespace mem { +class GlobalObjectStorage; +} // namespace mem + +} // namespace panda + +namespace panda::ets::interop::js { + +// TODO: +// We should move all field of this class to JsPlugin and delete it after refactoring +class GlobalCtx { +public: + static void Init(); + static GlobalCtx *Current(); + + mem::GlobalObjectStorage *Refstor() + { + return refstor_; + } + + napi_env &JSEnv() + { + return js_env_; + } + + Class *JSValueClass() + { + return jsvalue_class_; + } + + ClassLinkerContext *LinkerCtx() + { + return linker_ctx_; + }; + +private: + GlobalCtx() = default; + + mem::GlobalObjectStorage *refstor_ {}; + ClassLinkerContext *linker_ctx_ {}; + Class *jsvalue_class_ {}; + napi_env js_env_ {}; + + friend struct EtsJSNapiEnvScope; +}; + +} // namespace panda::ets::interop::js + +#endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_GLOBAL_CONTEXT_H_ diff --git a/plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.cpp b/plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.cpp new file mode 100644 index 000000000..95f9e5632 --- /dev/null +++ b/plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 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 "intrinsics.h" +#include "plugins/ets/runtime/interop_js/intrinsics_api.h" + +namespace panda::ets::interop::js { + +static void NotImplemented(const char *method_name) +{ + LOG(FATAL, ETS) << "Intrinsic 'JSRuntime" << method_name << "Intrinsic' is not set"; + UNREACHABLE(); +} + +static JSValue *NewJSValueDouble(double) +{ + NotImplemented(__func__); + return nullptr; +} + +static double GetValueDouble(JSValue *) +{ + NotImplemented(__func__); + return 0; +} + +static JSValue *GetPropertyJSValue(JSValue *, EtsString *) +{ + NotImplemented(__func__); + return nullptr; +} + +static void SetPropertyDouble(JSValue *, EtsString *, double) +{ + NotImplemented(__func__); +} + +static const IntrinsicsAPI S_INTRINSICS_API_NOT_IMPLEMENTED = { + NewJSValueDouble, + GetValueDouble, + GetPropertyJSValue, + SetPropertyDouble, +}; + +static const IntrinsicsAPI *s_intrinsics_api = &S_INTRINSICS_API_NOT_IMPLEMENTED; + +void JSRuntimeIntrinsicsSetIntrinsicsAPI(const IntrinsicsAPI *intrinsics_api) +{ + s_intrinsics_api = intrinsics_api; +} + +namespace intrinsics { + +JSValue *JSRuntimeNewJSValueDoubleIntrinsic(double v) +{ + return s_intrinsics_api->JSRuntimeNewJSValueDouble(v); +} + +double JSRuntimeGetValueDoubleIntrinsic(JSValue *ets_js_value) +{ + return s_intrinsics_api->JSRuntimeGetValueDouble(ets_js_value); +} + +JSValue *JSRuntimeGetPropertyJSValueIntrinsic(JSValue *ets_js_value, EtsString *ets_prop_name) +{ + return s_intrinsics_api->JSRuntimeGetPropertyJSValue(ets_js_value, ets_prop_name); +} + +void JSRuntimeSetPropertyDoubleIntrinsic(JSValue *ets_js_value, EtsString *ets_prop_name, double value) +{ + s_intrinsics_api->JSRuntimeSetPropertyDouble(ets_js_value, ets_prop_name, value); +} + +} // namespace intrinsics +} // namespace panda::ets::interop::js diff --git a/plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.h b/plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.h new file mode 100644 index 000000000..9e550717c --- /dev/null +++ b/plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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_RUNTIME_INTEROP_JS_INTRINSICS_STD_JS_JSRUNTIME_H_ +#define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_STD_JS_JSRUNTIME_H_ + +namespace panda::ets::interop::js { + +struct IntrinsicsAPI; + +void JSRuntimeIntrinsicsSetIntrinsicsAPI(const IntrinsicsAPI *intrinsics_api); + +} // namespace panda::ets::interop::js + +#endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_STD_JS_JSRUNTIME_H_ diff --git a/plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.yaml b/plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.yaml new file mode 100644 index 000000000..a8655d40d --- /dev/null +++ b/plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.yaml @@ -0,0 +1,71 @@ +# Copyright (c) 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. + +coretypes: +- managed_class: std.core.String + mirror_class: panda::ets::EtsString + +- managed_class: std.interop.js.JSValue + mirror_class: panda::ets::interop::js::JSValue + + +intrinsics_namespace: panda::ets::interop::js::intrinsics + + +#################### +# std.js.JSRuntime # +#################### +intrinsics: + - name: JSRuntimeNewJSValueDouble + space: ets + class_name: std.interop.js.JSRuntime + method_name: newJSValueDouble + static: true + signature: + ret: std.interop.js.JSValue + args: [ f64 ] + impl: panda::ets::interop::js::intrinsics::JSRuntimeNewJSValueDoubleIntrinsic + clear_flags: [ ] + + - name: JSRuntimeGetValueDouble + space: ets + class_name: std.interop.js.JSRuntime + method_name: getValueDouble + static: true + signature: + ret: f64 + args: [ std.interop.js.JSValue ] + impl: panda::ets::interop::js::intrinsics::JSRuntimeGetValueDoubleIntrinsic + clear_flags: [ ] + + - name: JSRuntimeGetPropertyJSValue + space: ets + class_name: std.interop.js.JSRuntime + method_name: getPropertyJSValue + static: true + signature: + ret: std.interop.js.JSValue + args: [ std.interop.js.JSValue, std.core.String ] + impl: panda::ets::interop::js::intrinsics::JSRuntimeGetPropertyJSValueIntrinsic + clear_flags: [ ] + + - name: JSRuntimeSetPropertyDouble + space: ets + class_name: std.interop.js.JSRuntime + method_name: setPropertyDouble + static: true + signature: + ret: void + args: [ std.interop.js.JSValue, std.core.String, f64 ] + impl: panda::ets::interop::js::intrinsics::JSRuntimeSetPropertyDoubleIntrinsic + clear_flags: [ ] diff --git a/plugins/ets/runtime/interop_js/intrinsics_api.h b/plugins/ets/runtime/interop_js/intrinsics_api.h new file mode 100644 index 000000000..5c4bb460b --- /dev/null +++ b/plugins/ets/runtime/interop_js/intrinsics_api.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 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_RUNTIME_INTEROP_JS_INTRINSICS_API_H_ +#define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_API_H_ + +namespace panda::ets { +class EtsString; +} // namespace panda::ets + +namespace panda::ets::interop::js { + +class JSValue; + +struct IntrinsicsAPI { + JSValue *(*JSRuntimeNewJSValueDouble)(double v); + double (*JSRuntimeGetValueDouble)(JSValue *ets_js_value); + JSValue *(*JSRuntimeGetPropertyJSValue)(JSValue *ets_js_value, EtsString *ets_prop_name); + void (*JSRuntimeSetPropertyDouble)(JSValue *ets_js_value, EtsString *ets_prop_name, double value); +}; + +} // namespace panda::ets::interop::js + +#endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_API_H_ diff --git a/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp b/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp new file mode 100644 index 000000000..0dc82bc50 --- /dev/null +++ b/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 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 "plugins/ets/runtime/interop_js/intrinsics_api.h" +#include "plugins/ets/runtime/interop_js/intrinsics_api_impl.h" +#include "plugins/ets/runtime/interop_js/js_value.h" +#include "plugins/ets/runtime/interop_js/napi_env_scope.h" +#include "plugins/ets/runtime/types/ets_string.h" + +namespace panda::ets::interop::js { + +static JSValue *JSRuntimeNewJSValueDouble(double v) +{ + return JSValue::CreateDouble(v); +} + +static double JSRuntimeGetValueDouble(JSValue *ets_js_value) +{ + return ets_js_value->GetDouble(); +} + +static JSValue *JSRuntimeGetPropertyJSValue(JSValue *ets_js_value, EtsString *ets_prop_name) +{ + ASSERT(ets_js_value->GetType() == JSValue::Type::OBJECT); + + napi_env env = EtsJSNapiEnvScope::Get(); + PandaString prop_name = ets_prop_name->GetMutf8(); + + return ets_js_value->GetProperty(env, prop_name.c_str()); +} + +static void JSRuntimeSetPropertyDouble(JSValue *ets_js_value, EtsString *ets_prop_name, double value) +{ + napi_env env = EtsJSNapiEnvScope::Get(); + PandaString prop_name = ets_prop_name->GetMutf8(); + + ets_js_value->SetPropertyDouble(env, prop_name.c_str(), value); +} + +const IntrinsicsAPI G_INTRINSICS_API = { + JSRuntimeNewJSValueDouble, + JSRuntimeGetValueDouble, + JSRuntimeGetPropertyJSValue, + JSRuntimeSetPropertyDouble, +}; + +const IntrinsicsAPI *GetIntrinsicsAPI() +{ + return &G_INTRINSICS_API; +} + +} // namespace panda::ets::interop::js diff --git a/plugins/ets/runtime/interop_js/intrinsics_api_impl.h b/plugins/ets/runtime/interop_js/intrinsics_api_impl.h new file mode 100644 index 000000000..882869e57 --- /dev/null +++ b/plugins/ets/runtime/interop_js/intrinsics_api_impl.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 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_RUNTIME_INTEROP_JS_INTRINSICS_API_IMPL_H_ +#define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_API_IMPL_H_ + +namespace panda::ets::interop::js { + +struct IntrinsicsAPI; + +const IntrinsicsAPI *GetIntrinsicsAPI(); + +} // namespace panda::ets::interop::js + +#endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_API_IMPL_H_ diff --git a/plugins/ets/runtime/interop_js/intrinsics_declaration.h b/plugins/ets/runtime/interop_js/intrinsics_declaration.h new file mode 100644 index 000000000..0bcb4cc65 --- /dev/null +++ b/plugins/ets/runtime/interop_js/intrinsics_declaration.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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_RUNTIME_INTEROP_JS_INTRINSICS_DECLARATION_H_ +#define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_DECLARATION_H_ + +namespace panda::ets::interop::js { + +class JSValue; + +} // namespace panda::ets::interop::js + +#endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_DECLARATION_H_ diff --git a/plugins/ets/runtime/interop_js/js_plugin.h b/plugins/ets/runtime/interop_js/js_plugin.h new file mode 100644 index 000000000..ad3231693 --- /dev/null +++ b/plugins/ets/runtime/interop_js/js_plugin.h @@ -0,0 +1,80 @@ +/** + * Copyright (c) 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_RUNTIME_INTEROP_JS_JS_PLUGIN_H_ +#define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_PLUGIN_H_ + +#include "libpandabase/macros.h" +#include "plugins/ets/runtime/ets_vm.h" +#include "plugins/ets/runtime/interop_js/global_context.h" +#include "plugins/ets/runtime/interop_js/intrinsics_api_impl.h" +#include "plugins/ets/runtime/interop_js/intrinsics/std_js_jsruntime.h" + +namespace panda::ets::interop::js { + +class JsPlugin { +public: + void Init() + { + JSRuntimeIntrinsicsSetIntrinsicsAPI(GetIntrinsicsAPI()); + ctx_.Init(); + } + + ALWAYS_INLINE GlobalCtx *GetContext() + { + return &ctx_; + } + + void ThrowException(std::string_view msg) + { + LOG(FATAL, ETS) << "ThrowException: msg" << msg; + // PandaEtsVM *ets_vm = GetPandaEtsVM(); + + EtsCoroutine *cor = EtsCoroutine::GetCurrent(); + LanguageContext lang_ctx = cor->GetLanguageContext(); + const uint8_t *class_descriptor = utf::CStringAsMutf8("Lstd/interop/js/JSException;"); + panda::ThrowException(lang_ctx, cor, class_descriptor, utf::CStringAsMutf8(msg.data())); + } + + static ALWAYS_INLINE JsPlugin *GetCurrent(PandaEtsVM *ets_vm) + { + static_assert(sizeof(PandaEtsVM::InteropData) >= sizeof(JsPlugin), + "JsPlugin doesn't fit into the PandaEtsVM::InteropData"); + + return reinterpret_cast(ets_vm->GetInteropData()); + } + + static ALWAYS_INLINE JsPlugin *GetCurrent(EtsCoroutine *cor) + { + return JsPlugin::GetCurrent(cor->GetPandaVM()); + } + + static ALWAYS_INLINE JsPlugin *GetCurrent() + { + return JsPlugin::GetCurrent(EtsCoroutine::GetCurrent()); + } + + ALWAYS_INLINE PandaEtsVM *GetPandaEtsVM() + { + return PandaEtsVM::FromInteropData(reinterpret_cast(this)); + } + +private: + GlobalCtx ctx_; +}; + +} // namespace panda::ets::interop::js + +#endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_PLUGIN_H_ diff --git a/plugins/ets/runtime/interop_js/js_value.cpp b/plugins/ets/runtime/interop_js/js_value.cpp new file mode 100644 index 000000000..7246052d9 --- /dev/null +++ b/plugins/ets/runtime/interop_js/js_value.cpp @@ -0,0 +1,95 @@ +/** + * 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 "plugins/ets/runtime/interop_js/js_value.h" +#include "plugins/ets/runtime/interop_js/ets_vm_plugin.h" +#include "plugins/ets/runtime/interop_js/ts2ets_common.h" + +namespace panda::ets::interop::js { + +/* static */ +JSValue *JSValue::CreateByNapiValue(napi_env env, napi_value js_value) +{ + napi_valuetype js_type; + NAPI_CHECK_FATAL(napi_typeof(env, js_value, &js_type)); + + switch (js_type) { + case napi_number: { + double v; + NAPI_CHECK_FATAL(napi_get_value_double(env, js_value, &v)); + return JSValue::CreateDouble(v); + } + case napi_object: { + napi_ref ref; + NAPI_CHECK_FATAL(napi_create_reference(env, js_value, 1, &ref)); + return JSValue::CreateObject(ref); + } + default: { + // Do nothing + } + } + + JsPlugin::GetCurrent()->ThrowException("Unsupported NAPI type: " + std::to_string(js_type)); + return nullptr; +} + +napi_value JSValue::CreateNapiValue(napi_env env) +{ + napi_value js_value {}; + + Type type = GetType(); + switch (type) { + case JSValue::Type::DOUBLE: { + NAPI_CHECK_FATAL(napi_create_double(env, GetDouble(), &js_value)); + break; + } + default: { + uint32_t t = helpers::ToUnderlying(type); + JsPlugin::GetCurrent()->ThrowException("Unsupported JSValue.Type: " + std::to_string(t)); + break; + } + } + + return js_value; +} + +JSValue *JSValue::GetProperty(napi_env env, const char *prop_name) +{ + ASSERT(GetType() == JSValue::Type::OBJECT); + + napi_ref ref = GetRef(); + napi_value js_object {}; + NAPI_CHECK_FATAL(napi_get_reference_value(env, ref, &js_object)); + + napi_value js_prop {}; + NAPI_CHECK_FATAL(napi_get_named_property(env, js_object, prop_name, &js_prop)); + + return JSValue::CreateByNapiValue(env, js_prop); +} + +void JSValue::SetPropertyDouble(napi_env env, const char *prop_name, double prop_value) +{ + ASSERT(GetType() == JSValue::Type::OBJECT); + + napi_ref ref = GetRef(); + napi_value js_object {}; + NAPI_CHECK_FATAL(napi_get_reference_value(env, ref, &js_object)); + + napi_value js_prop_value {}; + NAPI_CHECK_FATAL(napi_create_double(env, prop_value, &js_prop_value)); + NAPI_CHECK_FATAL(napi_set_named_property(env, js_object, prop_name, js_prop_value)); +} + +} // namespace panda::ets::interop::js diff --git a/plugins/ets/runtime/interop_js/js_value.h b/plugins/ets/runtime/interop_js/js_value.h new file mode 100644 index 000000000..913af2214 --- /dev/null +++ b/plugins/ets/runtime/interop_js/js_value.h @@ -0,0 +1,140 @@ +/** + * Copyright (c) 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_RUNTIME_INTEROP_JS_JSVALUE_H_ +#define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JSVALUE_H_ + +#include "plugins/ets/runtime/interop_js/global_context.h" +#include "plugins/ets/runtime/types/ets_object.h" +#include "runtime/include/coretypes/class.h" +#include + +namespace panda::ets::interop::js { + +namespace testing { +class JSValueOffsets; +} // namespace testing + +struct JSValueMemberOffsets; + +class JSValue : private EtsObject { +public: + enum class Type : uint64_t { + UNDEFINED, + BOOLEAN, + BYTE, + CHAR, + SHORT, + INT, + LONG, + FLOAT, + DOUBLE, + OBJECT, + + LAST_VALUE, + }; + static_assert(helpers::ToUnderlying(Type::UNDEFINED) == 0, "Type::UNDEFINED must be equal to 0"); + + static JSValue *CreateUndefinded() + { + EtsClass *ets_class = EtsClass::FromRuntimeClass(GlobalCtx::Current()->JSValueClass()); + JSValue *js_value = FromEtsType(EtsObject::Create(ets_class)); + ASSERT(js_value->type_ == helpers::ToUnderlying(Type::UNDEFINED)); + return js_value; + } + + static JSValue *CreateDouble(double value) + { + JSValue *js_value = CreateUndefinded(); + js_value->SetDouble(value); + return js_value; + } + + static JSValue *CreateObject(napi_ref ref) + { + JSValue *js_value = CreateUndefinded(); + js_value->SetRef(ref); + return js_value; + } + + static JSValue *CreateByNapiValue(napi_env env, napi_value js_value); + napi_value CreateNapiValue(napi_env env); + JSValue *GetProperty(napi_env env, const char *prop_name); + void SetPropertyDouble(napi_env env, const char *prop_name, double prop_value); + + static JSValue *FromEtsType(EtsObject *ets_object) + { + ASSERT(ets_object->GetClass() == EtsClass::FromRuntimeClass(GlobalCtx::Current()->JSValueClass())); + return static_cast(ets_object); + } + + EtsObject *GetEtsType() + { + return this; + } + + ALWAYS_INLINE inline void SetRef(napi_ref ref) + { + type_ = helpers::ToUnderlying(Type::OBJECT); + data_ = reinterpret_cast(ref); + } + + ALWAYS_INLINE inline napi_ref GetRef() const + { + ASSERT(GetType() == Type::OBJECT); + return reinterpret_cast(data_); + } + + ALWAYS_INLINE inline Type GetType() const + { + ASSERT(type_ < helpers::ToUnderlying(Type::LAST_VALUE)); + return static_cast(type_); + } + + ALWAYS_INLINE inline void SetDouble(double value) + { + type_ = helpers::ToUnderlying(Type::DOUBLE); + data_ = bit_cast(value); + } + + ALWAYS_INLINE inline double GetDouble() const + { + ASSERT(GetType() == Type::DOUBLE); + return bit_cast(data_); + } + + static constexpr uint32_t GetTypeOffset() + { + return MEMBER_OFFSET(JSValue, type_); + } + +private: + JSValue() = delete; + + FIELD_UNUSED uint64_t type_; + FIELD_UNUSED uint64_t data_; + + friend class testing::JSValueOffsets; + + static_assert(sizeof(type_) == sizeof(Type)); + static_assert(sizeof(data_) == sizeof(double)); + static_assert(sizeof(data_) >= sizeof(napi_ref)); +}; + +static_assert(JSValue::GetTypeOffset() == sizeof(ObjectHeader)); + +} // namespace panda::ets::interop::js + +#endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JSVALUE_H_ diff --git a/plugins/ets/runtime/interop_js/napi_env_scope.h b/plugins/ets/runtime/interop_js/napi_env_scope.h new file mode 100644 index 000000000..b8177cbe8 --- /dev/null +++ b/plugins/ets/runtime/interop_js/napi_env_scope.h @@ -0,0 +1,55 @@ +/** + * 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. + */ + +#ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_NAPI_ENV_SCOPE_H_ +#define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_NAPI_ENV_SCOPE_H_ + +#include "libpandabase/macros.h" +#include "plugins/ets/runtime/interop_js/global_context.h" +#include + +namespace panda::ets::interop::js { + +class EtsJSNapiEnvScope { +public: + EtsJSNapiEnvScope(napi_env new_env) + { + saved_ = CurrentNapiEnv(); + CurrentNapiEnv() = new_env; + } + + ~EtsJSNapiEnvScope() + { + CurrentNapiEnv() = saved_; + } + + static ALWAYS_INLINE napi_env Get() + { + ASSERT(CurrentNapiEnv() != nullptr); + return CurrentNapiEnv(); + } + +private: + static ALWAYS_INLINE napi_env &CurrentNapiEnv() + { + return GlobalCtx::Current()->JSEnv(); + } + + napi_env saved_ {}; +}; + +} // namespace panda::ets::interop::js + +#endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_NAPI_ENV_SCOPE_H_ diff --git a/plugins/ets/runtime/interop_js/ts2ets_common.cpp b/plugins/ets/runtime/interop_js/ts2ets_common.cpp index 5338693c2..e6857ea84 100644 --- a/plugins/ets/runtime/interop_js/ts2ets_common.cpp +++ b/plugins/ets/runtime/interop_js/ts2ets_common.cpp @@ -13,10 +13,11 @@ * limitations under the License. */ +#include "plugins/ets/runtime/interop_js/global_context.h" #include "plugins/ets/runtime/interop_js/ts2ets_common.h" #include "plugins/ets/runtime/ets_utils.h" -namespace panda::ets::ts2ets { +namespace panda::ets::interop::js { [[noreturn]] void __attribute__((noinline)) ts2ets_fatal(char const *message) { @@ -73,21 +74,6 @@ extern "C" __attribute__((weak)) napi_status napi_object_seal([[maybe_unused]] n return napi_ok; } -thread_local GlobalCtx GlobalCtx::tls_ctx_ {}; - -void GlobalCtx::Init() -{ - auto ctx = Current(); - if (LIKELY(ctx->initialized_)) { - return; - } - ctx->initialized_ = true; - - ctx->refstor_ = panda::ManagedThread::GetCurrent()->GetVM()->GetGlobalObjectStorage(); - ctx->linker_ctx_ = panda::ets::utils::GetClassLinkerExtension()->GetBootContext(); - ctx->jsvalue_klass_ = ResolveEtsClassByName(panda::Runtime::GetCurrent(), "jsvalue"); -} - panda::Class *ResolveEtsClassByName(panda::Runtime *runtime, char const *str) { auto class_linker = runtime->GetClassLinker(); @@ -98,4 +84,4 @@ panda::Class *ResolveEtsClassByName(panda::Runtime *runtime, char const *str) return klass; } -} // namespace panda::ets::ts2ets +} // namespace panda::ets::interop::js diff --git a/plugins/ets/runtime/interop_js/ts2ets_common.h b/plugins/ets/runtime/interop_js/ts2ets_common.h index fcc01b71a..30c0e9695 100644 --- a/plugins/ets/runtime/interop_js/ts2ets_common.h +++ b/plugins/ets/runtime/interop_js/ts2ets_common.h @@ -71,7 +71,7 @@ static inline std::string EtsLogMakeString(const char *fmt, ...) #define OH_TS2ETS_LOG_ERROR_A(msg, ...) TS2ETS_LOGGER(INFO, msg, __VA_ARGS__) #endif -namespace panda::ets::ts2ets { +namespace panda::ets::interop::js { [[noreturn]] void __attribute__((noinline)) ts2ets_fatal(char const *message); @@ -169,77 +169,6 @@ private: bool switched_ = false; }; -struct GlobalCtx { - static void Init(); - static ALWAYS_INLINE GlobalCtx *Current() - { - return &tls_ctx_; - } - - panda::mem::GlobalObjectStorage *Refstor() - { - return refstor_; - } - - napi_env &JSEnv() - { - return js_env_; - } - - panda::ClassLinkerContext *LinkerCtx() - { - return linker_ctx_; - }; - - panda::Class *JSValueKlass() - { - return jsvalue_klass_; - }; - -private: - GlobalCtx() = default; - friend struct EtsJSNapiEnvScope; - - panda::mem::GlobalObjectStorage *refstor_ {}; - panda::ClassLinkerContext *linker_ctx_ {}; - panda::Class *jsvalue_klass_ {}; - - napi_env js_env_ {}; - - bool initialized_ {false}; - static thread_local GlobalCtx tls_ctx_; -}; - -struct EtsJSNapiEnvScope { - explicit EtsJSNapiEnvScope(napi_env new_env) - { - saved_ = TLSEnv(); - TLSEnv() = new_env; - } - - ~EtsJSNapiEnvScope() - { - TLSEnv() = saved_; - } - - static ALWAYS_INLINE napi_env Get() - { - ASSERT(TLSEnv() != nullptr); - return TLSEnv(); - } - - NO_COPY_SEMANTIC(EtsJSNapiEnvScope); - NO_MOVE_SEMANTIC(EtsJSNapiEnvScope); - -private: - static ALWAYS_INLINE napi_env &TLSEnv() - { - return GlobalCtx::tls_ctx_.JSEnv(); - } - - napi_env saved_ {}; -}; - panda::Class *ResolveEtsClassByName(panda::Runtime *runtime, char const *str); static ALWAYS_INLINE inline bool IsUndefined(napi_env env, napi_value val) @@ -249,6 +178,6 @@ static ALWAYS_INLINE inline bool IsUndefined(napi_env env, napi_value val) return vtype == napi_undefined; } -} // namespace panda::ets::ts2ets +} // namespace panda::ets::interop::js #endif // !PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_COMMON_H_ diff --git a/plugins/ets/runtime/interop_js/ts2ets_copy.cpp b/plugins/ets/runtime/interop_js/ts2ets_copy.cpp index 53252d63a..a0424f13d 100644 --- a/plugins/ets/runtime/interop_js/ts2ets_copy.cpp +++ b/plugins/ets/runtime/interop_js/ts2ets_copy.cpp @@ -13,23 +13,21 @@ * limitations under the License. */ +#include "plugins/ets/runtime/interop_js/js_value.h" +#include "plugins/ets/runtime/interop_js/napi_env_scope.h" #include "plugins/ets/runtime/interop_js/ts2ets_common.h" #include "runtime/include/panda_vm.h" #include "runtime/handle_scope-inl.h" -namespace panda::ets::ts2ets { - -using panda::ets::utils::EtsConvertorRef; -using panda::ets::utils::EtsMethodVisitor; -using panda::ets::utils::EtsTypeVisitor; +namespace panda::ets::interop::js { static inline EtsConvertorRef::ObjRoot ToObjRoot(uintptr_t ptr) { return reinterpret_cast(ptr); } -class JsToEtsConvertor final : public panda::ets::utils::EtsTypeVisitor { - using Base = panda::ets::utils::EtsTypeVisitor; +class JsToEtsConvertor final : public EtsTypeVisitor { + using Base = EtsTypeVisitor; public: JsToEtsConvertor(napi_env env, napi_value js_value, EtsConvertorRef::ValVariant *data_ptr) @@ -180,21 +178,12 @@ public: void VisitObject(panda::Class *klass) override { - { - napi_valuetype type; - TYPEVIS_NAPI_CHECK(napi_typeof(env_, js_value_, &type)); - TYPEVIS_CHECK_ERROR(type == napi_object, "object expected"); - } - auto thread = panda::ManagedThread::GetCurrent(); - - NapiScope js_handle_scope(env_); - { - auto ets_obj = panda::ObjectHeader::Create(klass); - owner_ = ToObjRoot(panda::VMHandle(thread, ets_obj).GetAddress()); - } + ASSERT(klass == GlobalCtx::Current()->JSValueClass()); - panda::HandleScope ets_handle_scope(thread); - Base::VisitObject(klass); + JSValue *ets_js_value = JSValue::CreateByNapiValue(env_, js_value_); + ObjectHeader *object_header = ets_js_value->GetEtsType()->GetCoreType(); + ManagedThread *thread = ManagedThread::GetCurrent(); + owner_ = ToObjRoot(VMHandle(thread, object_header).GetAddress()); TYPEVIS_ABRUPT_ON_ERROR(); loc_.StoreReference(owner_); } @@ -316,18 +305,13 @@ public: void VisitObject(panda::Class *klass) override { - auto thread = panda::ManagedThread::GetCurrent(); + ASSERT(klass == GlobalCtx::Current()->JSValueClass()); - panda::HandleScope ets_handle_scope(thread); - { - auto ets_obj = loc_.LoadReference(); - owner_ = ToObjRoot(panda::VMHandle(thread, ets_obj).GetAddress()); - } - - TYPEVIS_NAPI_CHECK(napi_create_object(env_, &js_value_)); - - NapiScope js_handle_scope(env_); - Base::VisitObject(klass); + ObjectHeader *ets_obj = loc_.LoadReference(); + JSValue *ets_js_value = JSValue::FromEtsType(EtsObject::FromCoreType(ets_obj)); + js_value_ = ets_js_value->CreateNapiValue(env_); + auto thread = panda::ManagedThread::GetCurrent(); + owner_ = ToObjRoot(panda::VMHandle(thread, ets_obj).GetAddress()); } napi_value GetResult() @@ -359,7 +343,9 @@ public: if (std::holds_alternative(e)) { res.emplace_back(std::get(e)); } else { - res.emplace_back(*std::get(e)); + auto obj = std::get(e); + auto v = obj == nullptr ? nullptr : *obj; + res.emplace_back(v); } } return res; @@ -441,7 +427,7 @@ class EtsClassesRecursionChecker final : public EtsTypeVisitor { using Base = EtsTypeVisitor; struct DFSData { - explicit DFSData(panda::Class *klass) : klass(klass) {} + explicit DFSData(panda::Class *cls) : klass(cls) {} // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) panda::Class *klass = nullptr; @@ -565,6 +551,11 @@ public: private: void VisitReturn(panda::panda_file::Type type) override { + if (type.GetId() == panda_file::Type::TypeId::VOID) { + // Skip 'void' type because it doesn't require conversion + return; + } + EtsToJsConvertor conv(env_, &ret_); conv.VisitPrimitive(type); TYPEVIS_CHECK_FORWARD_ERROR(conv.Error()); @@ -593,7 +584,7 @@ private: napi_value InvokeEtsMethodImpl(napi_env env, napi_value *jsargv, uint32_t jsargc, bool do_clscheck) { - [[maybe_unused]] panda::ets::ts2ets::EtsJSNapiEnvScope scope(env); + [[maybe_unused]] EtsJSNapiEnvScope scope(env); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) OH_TS2ETS_LOG_INFO("InvokeEtsMethod: enter"); @@ -700,9 +691,16 @@ napi_value InvokeEtsMethodImpl(napi_env env, napi_value *jsargv, uint32_t jsargc // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) OH_TS2ETS_LOG_INFO_A("InvokeEtsMethod: ets2js elapsed time %s us", std::to_string(t).c_str()); - js_handle_scope.Escape(js_res); + // Check that the method has a return value + panda_file::Type ret_type = method->GetProto().GetReturnType(); + if (ret_type.GetId() != panda_file::Type::TypeId::VOID) { + ASSERT(js_res != nullptr); + js_handle_scope.Escape(js_res); + } else { + ASSERT(js_res == nullptr); + } } return js_res; } -} // namespace panda::ets::ts2ets +} // namespace panda::ets::interop::js diff --git a/plugins/ets/runtime/interop_js/ts2ets_copy.h b/plugins/ets/runtime/interop_js/ts2ets_copy.h index 78f020606..d73b24284 100644 --- a/plugins/ets/runtime/interop_js/ts2ets_copy.h +++ b/plugins/ets/runtime/interop_js/ts2ets_copy.h @@ -18,10 +18,10 @@ #include -namespace panda::ets::ts2ets { +namespace panda::ets::interop::js { napi_value InvokeEtsMethodImpl(napi_env env, napi_value *jsargv, uint32_t jsargc, bool do_clscheck); -} // namespace panda::ets::ts2ets +} // namespace panda::ets::interop::js #endif // !PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_COPY_H_ diff --git a/plugins/ets/runtime/interop_js/ts2ets_jsvalue.cpp b/plugins/ets/runtime/interop_js/ts2ets_jsvalue.cpp index e4cdc252a..c93f8cf0a 100644 --- a/plugins/ets/runtime/interop_js/ts2ets_jsvalue.cpp +++ b/plugins/ets/runtime/interop_js/ts2ets_jsvalue.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "plugins/ets/runtime/interop_js/napi_env_scope.h" #include "plugins/ets/runtime/interop_js/ts2ets_jsvalue.h" #include @@ -27,7 +28,7 @@ #define JSVALUE_DLOG_A(msg, ...) #endif -namespace panda::ets::ts2ets { +namespace panda::ets::interop::js { template static void WalkQualifiedName(std::string_view name, F const &f) @@ -115,8 +116,8 @@ static ALWAYS_INLINE uint64_t JSValueJSCallImpl(Method *method, uint8_t *args, u case panda::panda_file::Type::TypeId::REFERENCE: { auto value = arg_reader.Read(); auto klass = resolve_ref_cls(ref_arg_idx++); - if (klass == ctx->JSValueKlass()) { - js_val = JSConvertJSValue::Wrap(env, static_cast(value)); + if (klass == ctx->JSValueClass()) { + js_val = JSConvertJSValue::Wrap(env, JSValue::FromEtsType(EtsObject::FromCoreType((value)))); break; } if (klass->IsStringClass()) { @@ -150,7 +151,7 @@ static ALWAYS_INLINE uint64_t JSValueJSCallImpl(Method *method, uint8_t *args, u panda::Value ets_ret; if constexpr (IS_NEWCALL) { - NAPI_FATAL_IF(resolve_ref_cls(0) != ctx->JSValueKlass()); + NAPI_FATAL_IF(resolve_ref_cls(0) != ctx->JSValueClass()); JSValue *value; if (!JSConvertJSValue::Unwrap(env, js_ret, value)) { ts2ets_fatal("unwrap failed"); @@ -172,7 +173,7 @@ static ALWAYS_INLINE uint64_t JSValueJSCallImpl(Method *method, uint8_t *args, u } case panda::panda_file::Type::TypeId::REFERENCE: { [[maybe_unused]] auto klass = resolve_ref_cls(0); - if (klass == ctx->JSValueKlass()) { + if (klass == ctx->JSValueClass()) { JSValue *value; if (!JSConvertJSValue::Unwrap(env, js_ret, value)) { ts2ets_fatal("unwrap failed"); @@ -227,9 +228,9 @@ static void InitJSCallSignatures([[maybe_unused]] panda::Method *method, panda:: } void *method_ep; if constexpr (IS_NEWCALL) { - method_ep = reinterpret_cast(panda::ets::ts2ets::JSValueJSNewBridge); + method_ep = reinterpret_cast(JSValueJSNewBridge); } else { - method_ep = reinterpret_cast(panda::ets::ts2ets::JSValueJSCallBridge); + method_ep = reinterpret_cast(JSValueJSCallBridge); } call_method.SetCompiledEntryPoint(method_ep); call_method.SetNativePointer(nullptr); @@ -326,4 +327,4 @@ void InitJSValueExports() panda::ets::BindNative("LETSGLOBAL;", "__init_jsnew", reinterpret_cast(InitJSCallSignatures)); } -} // namespace panda::ets::ts2ets +} // namespace panda::ets::interop::js diff --git a/plugins/ets/runtime/interop_js/ts2ets_jsvalue.h b/plugins/ets/runtime/interop_js/ts2ets_jsvalue.h index 7fa1f3641..062e55861 100644 --- a/plugins/ets/runtime/interop_js/ts2ets_jsvalue.h +++ b/plugins/ets/runtime/interop_js/ts2ets_jsvalue.h @@ -20,41 +20,11 @@ #include "plugins/ets/runtime/ets_utils.h" #include "plugins/ets/runtime/interop_js/ts2ets_jsvalue_exports.h" #include "plugins/ets/runtime/interop_js/ts2ets_common.h" +#include "plugins/ets/runtime/interop_js/js_value.h" #include "runtime/handle_scope-inl.h" #include "runtime/include/coretypes/class.h" -namespace panda::ets::ts2ets { - -class JSValue : public ObjectHeader { -public: - JSValue() = delete; - - static constexpr uint32_t GetDataOffset() - { - return MEMBER_OFFSET(JSValue, data_); - } - - ALWAYS_INLINE inline void SetData(napi_ref data) - { - SetFieldPrimitive(GetDataOffset(), reinterpret_cast(data)); - } - - ALWAYS_INLINE inline napi_ref GetData() const - { - return reinterpret_cast(GetFieldPrimitive(GetDataOffset())); - } - -private: - uint64_t data_ FIELD_UNUSED; -}; -static_assert(JSValue::GetDataOffset() == sizeof(ObjectHeader)); - -static_assert(sizeof(napi_ref) <= sizeof(uint64_t)); - -static inline JSValue *JSValueCreate() -{ - return static_cast(panda::ObjectHeader::Create(GlobalCtx::Current()->JSValueKlass())); -} +namespace panda::ets::interop::js { static inline void JSConvertTypeCheckFailed([[maybe_unused]] char const *type_name) { @@ -136,13 +106,14 @@ TS2ETS_WRAPPER_UNWRAP(String) return true; } -static ALWAYS_INLINE inline bool JSValueClassUnwrap(panda::Class *klass, napi_env env, napi_value js_val, - JSValue *&ets_val) +static ALWAYS_INLINE inline bool JSValueClassUnwrap(Class *klass, napi_env env, napi_value js_val, JSValue *&ets_val) { + ASSERT(klass == GlobalCtx::Current()->JSValueClass()); + napi_ref js_ref; NAPI_CHECK_FATAL(napi_create_reference(env, js_val, 0, &js_ref)); - ets_val = static_cast(panda::ObjectHeader::Create(klass)); - ets_val->SetData(js_ref); + ets_val = JSValue::CreateUndefinded(); + ets_val->SetRef(js_ref); return true; } @@ -150,13 +121,13 @@ TS2ETS_WRAPPER_TYPE(JSValue, JSValue *) TS2ETS_WRAPPER_WRAP(JSValue) { napi_value js_val; - auto js_ref = ets_val->GetData(); + auto js_ref = ets_val->GetRef(); NAPI_CHECK_FATAL(napi_get_reference_value(env, js_ref, &js_val)); return js_val; } TS2ETS_WRAPPER_UNWRAP(JSValue) { - return JSValueClassUnwrap(GlobalCtx::Current()->JSValueKlass(), env, js_val, ets_val); + return JSValueClassUnwrap(GlobalCtx::Current()->JSValueClass(), env, js_val, ets_val); } #undef TS2ETS_WRAPPER_TYPE @@ -169,7 +140,7 @@ static ALWAYS_INLINE inline typename T::cpptype JSValueGetByName(JSValue *jsvalu napi_env env = EtsJSNapiEnvScope::Get(); NapiScope js_handle_scope(env); - auto js_ref = jsvalue->GetData(); + auto js_ref = jsvalue->GetRef(); napi_value js_val; NAPI_CHECK_FATAL(napi_get_reference_value(env, js_ref, &js_val)); NAPI_CHECK_FATAL(napi_get_named_property(env, js_val, name, &js_val)); @@ -179,6 +150,6 @@ static ALWAYS_INLINE inline typename T::cpptype JSValueGetByName(JSValue *jsvalu return ets_val; } -} // namespace panda::ets::ts2ets +} // namespace panda::ets::interop::js #endif // !PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_JSVALUE_H_ diff --git a/plugins/ets/runtime/interop_js/ts2ets_jsvalue_exports.h b/plugins/ets/runtime/interop_js/ts2ets_jsvalue_exports.h index 8f611f4b8..1ccc49385 100644 --- a/plugins/ets/runtime/interop_js/ts2ets_jsvalue_exports.h +++ b/plugins/ets/runtime/interop_js/ts2ets_jsvalue_exports.h @@ -18,7 +18,7 @@ #include -namespace panda::ets::ts2ets { +namespace panda::ets::interop::js { /* * Initializes jsvalue/jscall apis @@ -29,6 +29,6 @@ void InitJSValueExports(); */ void InitTSTypeExports(); -} // namespace panda::ets::ts2ets +} // namespace panda::ets::interop::js #endif // !PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_JSVALUE_EXPORTS_H_ diff --git a/plugins/ets/runtime/interop_js/ts2ets_proxy.cpp b/plugins/ets/runtime/interop_js/ts2ets_proxy.cpp index ff40693a7..5973db87b 100644 --- a/plugins/ets/runtime/interop_js/ts2ets_proxy.cpp +++ b/plugins/ets/runtime/interop_js/ts2ets_proxy.cpp @@ -13,11 +13,13 @@ * limitations under the License. */ +#include "plugins/ets/runtime/interop_js/global_context.h" +#include "plugins/ets/runtime/interop_js/napi_env_scope.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" -namespace panda::ets::ts2ets { +namespace panda::ets::interop::js { #ifndef NDEBUG // Debug log @@ -731,9 +733,6 @@ static napi_value WrapperCtor(napi_env env, napi_callback_info cinfo) return athis; } -using panda::ets::utils::EtsMethodVisitor; -using panda::ets::utils::EtsTypeVisitor; - template napi_value CallWrapperMethod(napi_env env, napi_callback_info cinfo); @@ -1397,4 +1396,4 @@ napi_value RegisterETSFunctionImpl(napi_env env, napi_value *jsargv, uint32_t js return js_func; } -} // namespace panda::ets::ts2ets +} // namespace panda::ets::interop::js diff --git a/plugins/ets/runtime/interop_js/ts2ets_proxy.h b/plugins/ets/runtime/interop_js/ts2ets_proxy.h index 9a8b1b03e..b6268676f 100644 --- a/plugins/ets/runtime/interop_js/ts2ets_proxy.h +++ b/plugins/ets/runtime/interop_js/ts2ets_proxy.h @@ -18,7 +18,7 @@ #include -namespace panda::ets::ts2ets { +namespace panda::ets::interop::js { /* * Resolve ETS class by "name" and return something that appears like js class @@ -38,6 +38,6 @@ napi_value RegisterETSClassImpl(napi_env env, napi_value *jsargv, uint32_t jsarg */ napi_value RegisterETSFunctionImpl(napi_env env, napi_value *jsargv, uint32_t jsargc); -} // namespace panda::ets::ts2ets +} // namespace panda::ets::interop::js #endif // !PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_TS2ETS_PROXY_H_ diff --git a/plugins/ets/runtime/interop_js/ts2ets_tstype.cpp b/plugins/ets/runtime/interop_js/ts2ets_tstype.cpp index 486fdacb0..82b839743 100644 --- a/plugins/ets/runtime/interop_js/ts2ets_tstype.cpp +++ b/plugins/ets/runtime/interop_js/ts2ets_tstype.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "plugins/ets/runtime/interop_js/napi_env_scope.h" #include "plugins/ets/runtime/interop_js/ts2ets_jsvalue.h" #include @@ -27,7 +28,7 @@ #define TSTYPE_DLOG_A(msg, ...) #endif -namespace panda::ets::ts2ets { +namespace panda::ets::interop::js { template ALWAYS_INLINE uint64_t TSTypeCall(Method *method, uint8_t *args, uint8_t *in_stack_args); @@ -253,7 +254,7 @@ ALWAYS_INLINE uint64_t TSTypeCall(Method *method, uint8_t *args, uint8_t *in_sta panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId()); auto class_linker = panda::Runtime::GetCurrent()->GetClassLinker(); - auto resolve_ref_cls = [&](uint32_t idx) { + auto resolve_ref_cls = [&](uint32_t idx) -> Class * { auto klass = class_linker->GetClass(*pf, pda.GetReferenceType(idx), ctx->LinkerCtx()); NAPI_FATAL_IF(klass == nullptr); return klass; @@ -276,8 +277,8 @@ ALWAYS_INLINE uint64_t TSTypeCall(Method *method, uint8_t *args, uint8_t *in_sta } else { auto value = arg_reader.Read(); auto klass = method->GetClass(); - NAPI_FATAL_IF(klass->GetBase() != ctx->JSValueKlass()); - js_this = JSConvertJSValue::Wrap(env, static_cast(value)); + NAPI_FATAL_IF(klass->GetBase() != ctx->JSValueClass()); + js_this = JSConvertJSValue::Wrap(env, JSValue::FromEtsType(EtsObject::FromCoreType(value))); ++it; // this } @@ -297,8 +298,8 @@ ALWAYS_INLINE uint64_t TSTypeCall(Method *method, uint8_t *args, uint8_t *in_sta js_val = JSConvertString::Wrap(env, static_cast(value)); break; } - if (klass == ctx->JSValueKlass() || klass->GetBase() == ctx->JSValueKlass()) { - js_val = JSConvertJSValue::Wrap(env, static_cast(value)); + if (klass == ctx->JSValueClass() || klass->GetBase() == ctx->JSValueClass()) { + js_val = JSConvertJSValue::Wrap(env, JSValue::FromEtsType(EtsObject::FromCoreType(value))); break; } ts2ets_fatal("unsupported reftype"); @@ -346,7 +347,7 @@ ALWAYS_INLINE uint64_t TSTypeCall(Method *method, uint8_t *args, uint8_t *in_sta ets_ret = panda::Value(ToUintPtr(value)); break; } - if (klass == ctx->JSValueKlass() || klass->GetBase() == ctx->JSValueKlass()) { + if (klass == ctx->JSValueClass() || klass->GetBase() == ctx->JSValueClass()) { if (UNLIKELY(!klass->IsInitialized())) { class_linker->InitializeClass(thread, klass); } @@ -417,4 +418,4 @@ void InitTSTypeExports() panda::ets::BindNative("LETSGLOBAL;", "__tstype_cctor", reinterpret_cast(TSTypeCCtor)); } -} // namespace panda::ets::ts2ets +} // namespace panda::ets::interop::js diff --git a/plugins/ets/runtime/intrinsics_declaration.h b/plugins/ets/runtime/intrinsics_declaration.h new file mode 100644 index 000000000..7d5fd97c9 --- /dev/null +++ b/plugins/ets/runtime/intrinsics_declaration.h @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#ifndef PANDA_PLUGINS_ETS_RUNTIME_INTRINSICS_DECLARATION_H_ +#define PANDA_PLUGINS_ETS_RUNTIME_INTRINSICS_DECLARATION_H_ + +#include "plugins/ets/runtime/types/ets_array.h" + +#ifdef PANDA_ETS_INTEROP_JS +#include "plugins/ets/runtime/interop_js/intrinsics_declaration.h" +#endif // PANDA_ETS_INTEROP_JS + +#endif // !PANDA_PLUGINS_ETS_RUNTIME_INTRINSICS_DECLARATION_H_ diff --git a/plugins/ets/stdlib/std/interop/js/JSException.ets b/plugins/ets/stdlib/std/interop/js/JSException.ets new file mode 100644 index 000000000..497e057ba --- /dev/null +++ b/plugins/ets/stdlib/std/interop/js/JSException.ets @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package std.interop.js; + +class JSException extends Exception { + constructor() { + super(); + } + + constructor(msg: String) { + super(msg); + } + + constructor(msg: String, cause: Object) { + super(msg, cause); + } +} diff --git a/plugins/ets/stdlib/std/interop/js/JSRuntime.ets b/plugins/ets/stdlib/std/interop/js/JSRuntime.ets new file mode 100644 index 000000000..d37509f0d --- /dev/null +++ b/plugins/ets/stdlib/std/interop/js/JSRuntime.ets @@ -0,0 +1,206 @@ +/* + * 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. + */ + +package std.interop.js; + +export class JSRuntime { + // ================== + // newJSValue() + // ================== + public static newJSValueBoolean(value: boolean): JSValue + { + JSRuntime.checkIntrinsicMethod(); + } + + public static newJSValueByte(value: byte): JSValue + { + JSRuntime.checkIntrinsicMethod(); + } + + public static newJSValueChar(value: char): JSValue + { + JSRuntime.checkIntrinsicMethod(); + } + + public static newJSValueShort(value: short): JSValue + { + JSRuntime.checkIntrinsicMethod(); + } + + public static newJSValueInt(value: int): JSValue + { + JSRuntime.checkIntrinsicMethod(); + } + + public static newJSValueLong(value: long): JSValue + { + JSRuntime.checkIntrinsicMethod(); + } + + public static newJSValueFloat(value: float): JSValue + { + JSRuntime.checkIntrinsicMethod(); + } + + public static newJSValueDouble(value: double): JSValue + { + JSRuntime.checkIntrinsicMethod(); + } + + // ================ + // getValue() + // ================ + public static getValueBoolean(value: JSValue): boolean + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getValueByte(value: JSValue): byte + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getValueChar(value: JSValue): char + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getValueShort(value: JSValue): short + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getValueInt(value: JSValue): int + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getValueLong(value: JSValue): long + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getValueFloat(value: JSValue): float + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getValueDouble(value: JSValue): double + { + JSRuntime.checkIntrinsicMethod(); + } + + // =================== + // getProperty() + // =================== + public static getPropertyBoolean(object: JSValue, name: String): boolean + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getPropertyByte(object: JSValue, name: String): byte + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getPropertyChar(object: JSValue, name: String): char + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getPropertyShort(object: JSValue, name: String): short + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getPropertyInt(object: JSValue, name: String): int + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getPropertyLong(object: JSValue, name: String): long + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getPropertyFloat(object: JSValue, name: String): float + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getPropertyDouble(object: JSValue, name: String): double + { + JSRuntime.checkIntrinsicMethod(); + } + + public static getPropertyJSValue(object: JSValue, name: String): JSValue + { + JSRuntime.checkIntrinsicMethod(); + } + + // =================== + // setProperty() + // =================== + public static setPropertyBoolean(object: JSValue, name: String, value: boolean): void + { + JSRuntime.checkIntrinsicMethod(); + } + + public static setPropertyByte(object: JSValue, name: String, value: byte): void + { + JSRuntime.checkIntrinsicMethod(); + } + + public static setPropertyChar(object: JSValue, name: String, value: char): void + { + JSRuntime.checkIntrinsicMethod(); + } + + public static setPropertyShort(object: JSValue, name: String, value: short): void + { + JSRuntime.checkIntrinsicMethod(); + } + + public static setPropertyInt(object: JSValue, name: String, value: int): void + { + JSRuntime.checkIntrinsicMethod(); + } + + public static setPropertyLong(object: JSValue, name: String, value: long): void + { + JSRuntime.checkIntrinsicMethod(); + } + + public static setPropertyFloat(object: JSValue, name: String, value: float): void + { + JSRuntime.checkIntrinsicMethod(); + } + + public static setPropertyDouble(object: JSValue, name: String, value: double): void + { + JSRuntime.checkIntrinsicMethod(); + } + public static setPropertyJSValue(object: JSValue, name: String, value: JSValue): void + { + JSRuntime.checkIntrinsicMethod(); + } + + private static checkIntrinsicMethod(): void { + let e = new Exception("This method must not be called"); + // TODO: Remove log when exception handling is implemented + Console.print("ERROR: " + e.toString() + "\n"); + throw e; + } +} diff --git a/plugins/ets/stdlib/std/interop/js/JSValue.ets b/plugins/ets/stdlib/std/interop/js/JSValue.ets new file mode 100644 index 000000000..f3a954786 --- /dev/null +++ b/plugins/ets/stdlib/std/interop/js/JSValue.ets @@ -0,0 +1,21 @@ +/* + * 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. + */ + +package std.interop.js; + +export class JSValue { + __internal_field_0: long; + __internal_field_1: long; +} diff --git a/plugins/ets/tests/interop_js/cmake/interop_js_tests.cmake b/plugins/ets/tests/interop_js/cmake/interop_js_tests.cmake index 059ed34a4..1a5c0c809 100644 --- a/plugins/ets/tests/interop_js/cmake/interop_js_tests.cmake +++ b/plugins/ets/tests/interop_js/cmake/interop_js_tests.cmake @@ -26,6 +26,9 @@ add_dependencies(ets_gtests ets_interop_js_gtests) # ETS_SOURCES # tests/unit1_test.ets # tests/unit2_test.ets +# LIBRARIES +# lib_target1 +# lib_target2 # ) function(panda_ets_interop_js_gtest TARGET) # Parse arguments @@ -33,14 +36,14 @@ function(panda_ets_interop_js_gtest TARGET) ARG "" "" - "CPP_SOURCES;ETS_SOURCES" + "CPP_SOURCES;ETS_SOURCES;LIBRARIES" ${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 + LIBRARIES ets_interop_js_gtest ${ARG_LIBRARIES} LIBRARY_OUTPUT_DIRECTORY "${INTEROP_TESTS_DIR}/lib/module" ) 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 index ff892e7de..cc1506ae7 100644 --- 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 @@ -107,7 +107,7 @@ private: } template - static T GetRetValue([[maybe_unused]] napi_env env, napi_value js_value) + static T GetRetValue([[maybe_unused]] napi_env env, [[maybe_unused]] napi_value js_value) { if constexpr (std::is_same_v) { double v; @@ -142,6 +142,8 @@ private: return v; } else if constexpr (std::is_same_v) { return js_value; + } else if constexpr (std::is_same_v) { + // do nothing } else { enum { INCORRECT_TEMPLATE_TYPE = false }; static_assert(INCORRECT_TEMPLATE_TYPE, "Incorrect template type"); diff --git a/plugins/ets/tests/interop_js/tests/CMakeLists.txt b/plugins/ets/tests/interop_js/tests/CMakeLists.txt index bfd0ebad2..38db661c9 100644 --- a/plugins/ets/tests/interop_js/tests/CMakeLists.txt +++ b/plugins/ets/tests/interop_js/tests/CMakeLists.txt @@ -17,7 +17,18 @@ panda_ets_interop_js_gtest(ets_interop_js_test__sample ETS_SOURCES ${INTEROP_JS_TESTS_SOURCE_DIR}/sample/test_sample.ets ) +panda_ets_interop_js_gtest(ets_interop_js_test__map_mirror_classes + CPP_SOURCES ${INTEROP_JS_TESTS_SOURCE_DIR}/map_mirror_classes/test_map_mirror_classes.cpp + ETS_SOURCES ${INTEROP_JS_TESTS_SOURCE_DIR}/map_mirror_classes/test_map_mirror_classes.ets + LIBRARIES arkruntime +) + +panda_ets_interop_js_gtest(ets_interop_js_test__js_value + CPP_SOURCES ${INTEROP_JS_TESTS_SOURCE_DIR}/js_value/test_js_value.cpp + ETS_SOURCES ${INTEROP_JS_TESTS_SOURCE_DIR}/js_value/test_js_value.ets +) + panda_ets_interop_js_gtest(ets_interop_js_test_bouncing_pandas CPP_SOURCES ${INTEROP_JS_TESTS_SOURCE_DIR}/bouncing_pandas/bouncing_pandas.cpp ETS_SOURCES ${PANDA_ETS_PLUGIN_SOURCE}/tests/common/bouncing_pandas/bouncing_pandas.ets -) \ No newline at end of file +) diff --git a/plugins/ets/tests/interop_js/tests/bouncing_pandas/bouncing_pandas.cpp b/plugins/ets/tests/interop_js/tests/bouncing_pandas/bouncing_pandas.cpp index bbfec0760..1c45b2748 100644 --- a/plugins/ets/tests/interop_js/tests/bouncing_pandas/bouncing_pandas.cpp +++ b/plugins/ets/tests/interop_js/tests/bouncing_pandas/bouncing_pandas.cpp @@ -20,7 +20,10 @@ namespace panda::ets::interop::js::testing { class EtsInteropJsBouncingPandasTest : public EtsInteropTest {}; -TEST_F(EtsInteropJsBouncingPandasTest, BouncingPandasTest) +// FIX: +// We will not support API that uses in plugins/ets/tests/common/bouncing_pandas/bouncing_pandas.ets, +// Therefore, we need to fix this test, according to the approved the Interop JS API +TEST_F(EtsInteropJsBouncingPandasTest, DISABLED_BouncingPandasTest) { // NOLINTNEXTLINE(modernize-use-auto) uint32_t ret = RunJsScriptByPath("bouncing_pandas/bouncing_pandas.js"); diff --git a/plugins/ets/tests/interop_js/tests/js_value/test_js_value.cpp b/plugins/ets/tests/interop_js/tests/js_value/test_js_value.cpp new file mode 100644 index 000000000..8fcb8f0e2 --- /dev/null +++ b/plugins/ets/tests/interop_js/tests/js_value/test_js_value.cpp @@ -0,0 +1,130 @@ +/** + * 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 EtsInteropJsJSValue : public EtsInteropTest {}; + +TEST_F(EtsInteropJsJSValue, double2jsvalue) +{ + const double TEST_VALUE = 3.6; + + // Call ets method + napi_value ret = CallEtsMethod("double2jsvalue", TEST_VALUE); + + // Get double from napi_value + double v; + napi_status status = napi_get_value_double(GetJsEnv(), ret, &v); + ASSERT_EQ(status, napi_ok); + + // Check result + ASSERT_EQ(v, TEST_VALUE); +} + +TEST_F(EtsInteropJsJSValue, jsvalue2double) +{ + const double TEST_VALUE = 53.23; + + // Create napi_value from double + napi_value js_value; + ASSERT_EQ(napi_ok, napi_create_double(GetJsEnv(), TEST_VALUE, &js_value)); + + // Call ets method + double ret = CallEtsMethod("jsvalue2double", js_value); + + // Check result + ASSERT_EQ(ret, TEST_VALUE); +} + +TEST_F(EtsInteropJsJSValue, get_property_from_jsvalue) +{ + napi_env env = GetJsEnv(); + + const double TEST_VALUE = 67.78; + // Create js object: + // { + // .prop = 67.78 + // } + napi_value js_obj; + napi_value js_value; + ASSERT_EQ(napi_ok, napi_create_object(env, &js_obj)); + ASSERT_EQ(napi_ok, napi_create_double(env, TEST_VALUE, &js_value)); + ASSERT_EQ(napi_ok, napi_set_named_property(env, js_obj, "prop", js_value)); + + // Call ets method + double ret = CallEtsMethod("get_property_from_jsvalue", js_obj); + + // Check result + ASSERT_EQ(ret, TEST_VALUE); +} + +TEST_F(EtsInteropJsJSValue, get_property_from_jsvalue2) +{ + napi_env env = GetJsEnv(); + + const double TEST_VALUE = 674.6; + // Create js object: + // { + // .prop_1 = { + // .prop_2 = 674.6 + // } + // } + napi_value js_obj {}; + napi_value js_prop_1 {}; + napi_value js_prop_2 {}; + ASSERT_EQ(napi_ok, napi_create_object(env, &js_obj)); + ASSERT_EQ(napi_ok, napi_create_object(env, &js_prop_1)); + ASSERT_EQ(napi_ok, napi_create_double(env, TEST_VALUE, &js_prop_2)); + ASSERT_EQ(napi_ok, napi_set_named_property(env, js_obj, "prop_1", js_prop_1)); + ASSERT_EQ(napi_ok, napi_set_named_property(env, js_prop_1, "prop_2", js_prop_2)); + + // Call ets method + double ret = CallEtsMethod("get_property_from_jsvalue2", js_obj); + + // Check result + ASSERT_EQ(ret, TEST_VALUE); +} + +TEST_F(EtsInteropJsJSValue, set_property_to_jsvalue) +{ + napi_env env = GetJsEnv(); + + const double TEST_VALUE = 54.064; + // Create js object: + // { + // } + napi_value js_obj {}; + ASSERT_EQ(napi_ok, napi_create_object(env, &js_obj)); + + // Call ets method + CallEtsMethod("set_property_to_jsvalue", js_obj, TEST_VALUE); + + // Return js object: + // { + // .prop = 54.064 + // } + napi_value js_prop {}; + double val {}; + ASSERT_EQ(napi_ok, napi_get_named_property(env, js_obj, "prop", &js_prop)); + ASSERT_EQ(napi_ok, napi_get_value_double(env, js_prop, &val)); + + // Check result + ASSERT_EQ(val, TEST_VALUE); +} + +} // namespace panda::ets::interop::js::testing diff --git a/plugins/ets/tests/interop_js/tests/js_value/test_js_value.ets b/plugins/ets/tests/interop_js/tests/js_value/test_js_value.ets new file mode 100644 index 000000000..7935a4b63 --- /dev/null +++ b/plugins/ets/tests/interop_js/tests/js_value/test_js_value.ets @@ -0,0 +1,34 @@ +/** + * 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 double2jsvalue(v: double): JSValue { + return v; +} + +function jsvalue2double(v: JSValue): double { + return v; +} + +function get_property_from_jsvalue(obj: JSValue): double { + return obj.prop; +} + +function get_property_from_jsvalue2(obj: JSValue): double { + return obj.prop_1.prop_2; +} + +function set_property_to_jsvalue(obj: JSValue, v: double): void { + obj.prop = v; +} diff --git a/plugins/ets/tests/interop_js/tests/map_mirror_classes/test_map_mirror_classes.cpp b/plugins/ets/tests/interop_js/tests/map_mirror_classes/test_map_mirror_classes.cpp new file mode 100644 index 000000000..cc9b82699 --- /dev/null +++ b/plugins/ets/tests/interop_js/tests/map_mirror_classes/test_map_mirror_classes.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (c) 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 "ets_interop_js_gtest.h" +#include "plugins/ets/runtime/interop_js/js_value.h" +#include "plugins/ets/runtime/ets_vm.h" +#include "plugins/ets/runtime/ets_utils.h" +#include "runtime/include/thread_scopes.h" + +namespace panda::ets::interop::js::testing { + +class EtsInteropJsClassLinkerTest : public EtsInteropTest {}; + +struct MemberInfo { + uint32_t offset; + const char *name; +}; + +static void CheckOffsetOfFields(const char *class_name, const std::vector &members_list) +{ + ScopedManagedCodeThread scoped(ManagedThread::GetCurrent()); + + ClassLinker *ets_class_linker = PandaEtsVM::GetCurrent()->GetClassLinker(); + auto boot_context = ets::utils::GetClassLinkerExtension()->GetBootContext(); + Class *core_class = ets_class_linker->GetClass(utf::CStringAsMutf8(class_name), false, boot_context); + EtsClass *klass = EtsClass::FromRuntimeClass(core_class); + ASSERT_NE(klass, nullptr); + ASSERT_EQ(klass->GetInstanceFieldsNumber(), members_list.size()); + + for (const auto &member_info : members_list) { + EtsField *field = klass->GetFieldIDByOffset(member_info.offset); + ASSERT_NE(field, nullptr); + EXPECT_STREQ(field->GetName(), member_info.name); + } +} + +class JSValueOffsets { +public: + static std::vector GetMembersInfo() + { + return std::vector { + MemberInfo {MEMBER_OFFSET(JSValue, type_), "__internal_field_0"}, // long + MemberInfo {MEMBER_OFFSET(JSValue, data_), "__internal_field_1"}, // long + }; + } +}; + +TEST_F(EtsInteropJsClassLinkerTest, Filed_std_interop_js_JSValue) +{ + CheckOffsetOfFields("Lstd/interop/js/JSValue;", JSValueOffsets::GetMembersInfo()); +} + +} // namespace panda::ets::interop::js::testing diff --git a/plugins/ets/tests/interop_js/tests/map_mirror_classes/test_map_mirror_classes.ets b/plugins/ets/tests/interop_js/tests/map_mirror_classes/test_map_mirror_classes.ets new file mode 100644 index 000000000..bcbd46b02 --- /dev/null +++ b/plugins/ets/tests/interop_js/tests/map_mirror_classes/test_map_mirror_classes.ets @@ -0,0 +1,2 @@ +// NOTE: +// We have to add this file, because it is necessary to panda_ets_interop_js_gtest() diff --git a/plugins/ets/tests/interop_js/tests/sample/test_sample.cpp b/plugins/ets/tests/interop_js/tests/sample/test_sample.cpp index 9e8633b8b..21f8bc946 100644 --- a/plugins/ets/tests/interop_js/tests/sample/test_sample.cpp +++ b/plugins/ets/tests/interop_js/tests/sample/test_sample.cpp @@ -49,7 +49,10 @@ TEST_F(EtsInteropJsSampleTest, ets_sum_any_types) ASSERT_STREQ(ret.data(), RES.data()); } -TEST_F(EtsInteropJsSampleTest, ets_use_napi) +// FIX: +// We will not support API that uses in plugins/ets/tests/interop_js/tests/sample/test_sample.ets +// Therefore, we need to fix this test, according to the approved the Interop JS API +TEST_F(EtsInteropJsSampleTest, DISABLED_ets_use_napi) { constexpr int ARG0 = 73; constexpr double ARG1 = 2.35; -- Gitee From bf00445e464b1e93ebd5f9bd0bd36f88f73e2c12 Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Fri, 21 Apr 2023 21:37:32 +0300 Subject: [PATCH 3/3] [TMP] Init JsPlugin --- plugins/ets/runtime/interop_js/ets_vm_plugin.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp b/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp index f8233950b..117071f1a 100644 --- a/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp +++ b/plugins/ets/runtime/interop_js/ets_vm_plugin.cpp @@ -15,7 +15,9 @@ #include #include "runtime/include/runtime.h" +#include "runtime/include/thread_scopes.h" #include "plugins/ets/runtime/ets_vm_api.h" +#include "plugins/ets/runtime/interop_js/ets_vm_plugin.h" #include "plugins/ets/runtime/interop_js/ts2ets_copy.h" namespace panda::ets::interop::js { @@ -74,6 +76,11 @@ static napi_value Init(napi_env env, napi_value exports) std::abort(); } + { + ScopedManagedCodeThread scoped(ManagedThread::GetCurrent()); + JsPlugin::GetCurrent()->Init(); + } + 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}, -- Gitee