From ba251cc01ce51f94260fca2d386e2bc46be1ed36 Mon Sep 17 00:00:00 2001 From: Robert Gerdisch Date: Mon, 12 Jul 2021 17:26:10 -0700 Subject: [PATCH 1/9] Working NAPI-JSI --- Apps/Playground/UWP/App.cpp | 7 + Apps/Playground/UWP/App.h | 2 + Apps/Playground/UWP/Package.appxmanifest | 1 + Apps/Playground/Win32/App.cpp | 2 +- Core/AppRuntime/CMakeLists.txt | 57 +-- Core/AppRuntime/Source/AppRuntimeJSI.cpp | 47 ++ Dependencies/CMakeExtensions/CMakeLists.txt | 16 + Dependencies/napi/CMakeLists.txt | 2 + .../OnLinkedAsDependency.cmake | 24 +- Dependencies/napi/napi-direct/CMakeLists.txt | 34 +- .../napi/napi-direct/include/napi/napi-inl.h | 18 + .../napi/napi-direct/include/napi/napi.h | 1 + Dependencies/napi/napi-direct/nuget.config | 13 + Dependencies/napi/napi-jsi/CMakeLists.txt | 54 +- .../napi-jsi/include/napi/js_native_api.h | 419 +++++++++++++++ .../include/napi/js_native_api_types.h | 149 ++++++ .../napi/napi-jsi/include/napi/napi-inl.h | 2 +- .../napi/napi-jsi/include/napi/napi.h | 37 +- Dependencies/napi/napi-jsi/nuget.config | 13 + Dependencies/napi/napi-jsi/packages.config | 5 + Dependencies/napi/napi-jsi/source/jsi.cpp | 484 ++++++++++++++++++ Plugins/ChromeDevTools/CMakeLists.txt | 17 +- .../Source/ChromeDevToolsJSI.cpp | 76 +++ Plugins/NativeCamera/Source/NativeCamera.cpp | 27 +- Polyfills/Console/Source/Console.cpp | 12 +- Polyfills/Console/Source/Console.h | 2 +- 26 files changed, 1398 insertions(+), 123 deletions(-) create mode 100644 Core/AppRuntime/Source/AppRuntimeJSI.cpp rename Dependencies/napi/{napi-direct => }/OnLinkedAsDependency.cmake (55%) create mode 100644 Dependencies/napi/napi-direct/nuget.config create mode 100644 Dependencies/napi/napi-jsi/include/napi/js_native_api.h create mode 100644 Dependencies/napi/napi-jsi/include/napi/js_native_api_types.h create mode 100644 Dependencies/napi/napi-jsi/nuget.config create mode 100644 Dependencies/napi/napi-jsi/packages.config create mode 100644 Dependencies/napi/napi-jsi/source/jsi.cpp create mode 100644 Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp diff --git a/Apps/Playground/UWP/App.cpp b/Apps/Playground/UWP/App.cpp index 61aaceb1c..72f27bd66 100644 --- a/Apps/Playground/UWP/App.cpp +++ b/Apps/Playground/UWP/App.cpp @@ -124,6 +124,7 @@ void App::Uninitialize() m_graphics->FinishRenderingCurrentFrame(); } + m_chromeDevTools.reset(); m_inputBuffer.reset(); m_runtime.reset(); m_graphics.reset(); @@ -291,6 +292,12 @@ void App::RestartRuntime(Windows::Foundation::Rect bounds) Babylon::Plugins::NativeXr::Initialize(env); InputManager::Initialize(env, *m_inputBuffer); + + m_chromeDevTools = std::make_unique(Babylon::Plugins::ChromeDevTools::Initialize(env)); + if (m_chromeDevTools->SupportsInspector()) + { + m_chromeDevTools->StartInspector(4653, "BabylonNative Playground"); + } }); Babylon::ScriptLoader loader{*m_runtime}; diff --git a/Apps/Playground/UWP/App.h b/Apps/Playground/UWP/App.h index aefc85a0d..a8b82cbe1 100644 --- a/Apps/Playground/UWP/App.h +++ b/Apps/Playground/UWP/App.h @@ -3,6 +3,7 @@ #include #include #include +#include // Main entry point for our app. Connects the app with the Windows shell and handles application lifecycle events. ref class App sealed : public Windows::ApplicationModel::Core::IFrameworkView @@ -42,6 +43,7 @@ ref class App sealed : public Windows::ApplicationModel::Core::IFrameworkView std::unique_ptr m_graphics{}; std::unique_ptr m_runtime{}; std::unique_ptr::InputBuffer> m_inputBuffer{}; + std::unique_ptr m_chromeDevTools{}; Windows::Foundation::Collections::IVectorView^ m_files; bool m_windowClosed; bool m_windowVisible; diff --git a/Apps/Playground/UWP/Package.appxmanifest b/Apps/Playground/UWP/Package.appxmanifest index 67ffde841..d64ab75fd 100644 --- a/Apps/Playground/UWP/Package.appxmanifest +++ b/Apps/Playground/UWP/Package.appxmanifest @@ -36,5 +36,6 @@ + \ No newline at end of file diff --git a/Apps/Playground/Win32/App.cpp b/Apps/Playground/Win32/App.cpp index c90989131..45323599d 100644 --- a/Apps/Playground/Win32/App.cpp +++ b/Apps/Playground/Win32/App.cpp @@ -140,7 +140,7 @@ namespace chromeDevTools = std::make_unique(Babylon::Plugins::ChromeDevTools::Initialize(env)); if (chromeDevTools->SupportsInspector()) { - chromeDevTools->StartInspector(5643, "BabylonNative Playground"); + chromeDevTools->StartInspector(4653, "BabylonNative Playground"); } }); diff --git a/Core/AppRuntime/CMakeLists.txt b/Core/AppRuntime/CMakeLists.txt index 801833367..45d322e8b 100644 --- a/Core/AppRuntime/CMakeLists.txt +++ b/Core/AppRuntime/CMakeLists.txt @@ -1,37 +1,34 @@ -if(NOT NAPI_JAVASCRIPT_ENGINE STREQUAL "JSI") - - set(SOURCES - "Include/Babylon/AppRuntime.h" - "Source/AppRuntime.cpp" - "Source/AppRuntime${NAPI_JAVASCRIPT_ENGINE}.cpp" - "Source/WorkQueue.cpp" - "Source/WorkQueue.h") - - if(APPLE) - set(SOURCES ${SOURCES} "Source/AppRuntime${BABYLON_NATIVE_PLATFORM}.mm") - else() - set(SOURCES ${SOURCES} "Source/AppRuntime${BABYLON_NATIVE_PLATFORM}.cpp") - endif() +set(SOURCES + "Include/Babylon/AppRuntime.h" + "Source/AppRuntime.cpp" + "Source/AppRuntime${NAPI_JAVASCRIPT_ENGINE}.cpp" + "Source/WorkQueue.cpp" + "Source/WorkQueue.h") + +if(APPLE) + set(SOURCES ${SOURCES} "Source/AppRuntime${BABYLON_NATIVE_PLATFORM}.mm") +else() + set(SOURCES ${SOURCES} "Source/AppRuntime${BABYLON_NATIVE_PLATFORM}.cpp") +endif() - add_library(AppRuntime ${SOURCES}) - warnings_as_errors(AppRuntime) +add_library(AppRuntime ${SOURCES}) +warnings_as_errors(AppRuntime) - target_include_directories(AppRuntime - PRIVATE "Include/Babylon" - INTERFACE "Include") +target_include_directories(AppRuntime + PRIVATE "Include/Babylon" + INTERFACE "Include") - if(UNIX AND NOT APPLE AND NOT ANDROID) - target_include_directories(AppRuntime INTERFACE "/usr/include/webkitgtk-4.0/") - endif() +if(UNIX AND NOT APPLE AND NOT ANDROID) + target_include_directories(AppRuntime INTERFACE "/usr/include/webkitgtk-4.0/") +endif() - target_link_to_dependencies(AppRuntime - PRIVATE arcana - PUBLIC JsRuntime) +target_link_to_dependencies(AppRuntime + PRIVATE arcana + PUBLIC JsRuntime) - target_compile_definitions(AppRuntime - PRIVATE NOMINMAX) +target_compile_definitions(AppRuntime + PRIVATE NOMINMAX) - set_property(TARGET AppRuntime PROPERTY FOLDER Core) - source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) +set_property(TARGET AppRuntime PROPERTY FOLDER Core) +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) -endif() diff --git a/Core/AppRuntime/Source/AppRuntimeJSI.cpp b/Core/AppRuntime/Source/AppRuntimeJSI.cpp new file mode 100644 index 000000000..38c38efa2 --- /dev/null +++ b/Core/AppRuntime/Source/AppRuntimeJSI.cpp @@ -0,0 +1,47 @@ +#include "AppRuntime.h" +#include "WorkQueue.h" + +#include +#include +#include + +namespace Babylon +{ + class TaskRunnerAdapter : public v8runtime::JSITaskRunner + { + public: + TaskRunnerAdapter(WorkQueue& workQueue) + : m_workQueue(workQueue) + { } + + void postTask(std::unique_ptr task) override + { + std::shared_ptr shared_task(task.release()); + m_workQueue.Append([shared_task2 = std::move(shared_task)](Napi::Env) { + shared_task2->run(); + }); + } + + private: + TaskRunnerAdapter(const TaskRunnerAdapter&) = delete; + TaskRunnerAdapter& operator=(const TaskRunnerAdapter&) = delete; + + WorkQueue& m_workQueue; + }; + + void AppRuntime::RunEnvironmentTier(const char*) + { + v8runtime::V8RuntimeArgs args{}; + args.inspectorPort = 4653; + args.foreground_task_runner = std::make_shared(*m_workQueue); + + const auto runtime = v8runtime::makeV8Runtime(std::move(args)); + Napi::Env env = Napi::Attach(*runtime); + Dispatch([&runtime](Napi::Env env) { + JsRuntime::NativeObject::GetFromJavaScript(env) + .Set("_JSIRuntime", Napi::External::New(env, runtime.get())); + }); + Run(env); + Napi::Detach(env); + } +} diff --git a/Dependencies/CMakeExtensions/CMakeLists.txt b/Dependencies/CMakeExtensions/CMakeLists.txt index 0630b422f..3aa5c6c05 100644 --- a/Dependencies/CMakeExtensions/CMakeLists.txt +++ b/Dependencies/CMakeExtensions/CMakeLists.txt @@ -123,4 +123,20 @@ function(set_win32_arch) else() message(FATAL_ERROR "Unrecognized compiler: ${CMAKE_CXX_COMPILER}") endif() +endfunction() + +# Uses the nuget.config and packages.config files in the current directory to download packages from NuGet. +# NUGET_PATH will be set to the directory where the packages are installed. +function (nuget_download) + set(NUGET_PATH "${CMAKE_BINARY_DIR}/NuGet") + set(NUGET_PATH "${NUGET_PATH}" PARENT_SCOPE) + set(NUGET_EXE "${NUGET_PATH}/nuget.exe") + if(NOT EXISTS ${NUGET_EXE}) + file(DOWNLOAD "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" ${NUGET_EXE}) + endif() + file(COPY "nuget.config" DESTINATION ${NUGET_PATH}) + file(COPY "packages.config" DESTINATION ${NUGET_PATH}) + + execute_process(COMMAND ${NUGET_EXE} restore WORKING_DIRECTORY ${NUGET_PATH}) + execute_process(COMMAND ${NUGET_EXE} install WORKING_DIRECTORY ${NUGET_PATH}) endfunction() \ No newline at end of file diff --git a/Dependencies/napi/CMakeLists.txt b/Dependencies/napi/CMakeLists.txt index 7e6039746..973b717af 100644 --- a/Dependencies/napi/CMakeLists.txt +++ b/Dependencies/napi/CMakeLists.txt @@ -26,3 +26,5 @@ if(NAPI_JAVASCRIPT_ENGINE STREQUAL "JSI") else() add_subdirectory(napi-direct) endif() + +add_on_linked_as_dependency_cmake_file(napi "${CMAKE_CURRENT_SOURCE_DIR}/OnLinkedAsDependency.cmake") \ No newline at end of file diff --git a/Dependencies/napi/napi-direct/OnLinkedAsDependency.cmake b/Dependencies/napi/OnLinkedAsDependency.cmake similarity index 55% rename from Dependencies/napi/napi-direct/OnLinkedAsDependency.cmake rename to Dependencies/napi/OnLinkedAsDependency.cmake index 51b1d9761..4a62bd088 100644 --- a/Dependencies/napi/napi-direct/OnLinkedAsDependency.cmake +++ b/Dependencies/napi/OnLinkedAsDependency.cmake @@ -1,27 +1,31 @@ # Callback to perform custom behavior -- in this case, copying runtime output artifacts like DLLs -- when # linked from an executable target as a library. function(on_linked_as_dependency target) - # We only have to do anything if the JavaScript engine is V8. - if (NAPI_JAVASCRIPT_ENGINE STREQUAL "V8") - - # Propagate this file to the target so that it will be transitively available to targets that - # link to that one, too. - propagate_on_linked_as_dependency_cmake_file(napi ${target}) - + # Propagate this file to the target so that it will be transitively available to targets that + # link to that one, too. + propagate_on_linked_as_dependency_cmake_file(napi ${target}) + if (DEFINED NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS) # We only need to actually copy files if we're being linked from an executable. get_target_property(type ${target} TYPE) if(${type} STREQUAL "EXECUTABLE") if (WINDOWS_STORE) # WINDOWS_STORE allows us to use the VS_DEPLOYMENT_CONTENT property. target_sources(${target} PRIVATE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS}) - set_property(SOURCE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS} PROPERTY VS_DEPLOYMENT_CONTENT 1) + + if ((DEFINED NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_DEBUG) AND (DEFINED NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_RELEASE)) + set_property(SOURCE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_DEBUG} PROPERTY VS_DEPLOYMENT_CONTENT $) + set_property(SOURCE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_RELEASE} PROPERTY VS_DEPLOYMENT_CONTENT $>) + else() + set_property(SOURCE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS} PROPERTY VS_DEPLOYMENT_CONTENT 1) + endif() + set_property(SOURCE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS} PROPERTY VS_DEPLOYMENT_LOCATION ".") else() # Without the VS_DEPLOYMENT_CONTENT property, create custom rules to copy the artifacts. foreach(artifact ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS}) add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${artifact} $) - endforeach(artifact) + endforeach() endif() endif() endif() -endfunction() +endfunction() \ No newline at end of file diff --git a/Dependencies/napi/napi-direct/CMakeLists.txt b/Dependencies/napi/napi-direct/CMakeLists.txt index 6c9ba6288..505cd3d04 100644 --- a/Dependencies/napi/napi-direct/CMakeLists.txt +++ b/Dependencies/napi/napi-direct/CMakeLists.txt @@ -28,36 +28,32 @@ target_include_directories(napi PUBLIC "include") # Install v8 SDK from NuGet function (install_v8_nuget V8_VERSION ARCH VS_PLAT_TOOLSET) - set(NUGET_PATH "${CMAKE_BINARY_DIR}/NuGet") - set(NUGET_EXE "${NUGET_PATH}/nuget.exe") - if(NOT EXISTS ${NUGET_EXE}) - file(DOWNLOAD "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" ${NUGET_EXE}) - endif() - file(COPY "packages.config" DESTINATION ${NUGET_PATH}) - execute_process(COMMAND ${NUGET_EXE} install WORKING_DIRECTORY ${NUGET_PATH}) + nuget_download() + set(V8_PACKAGE_PATH "${NUGET_PATH}/packages/v8-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}") + set(V8_REDIST_PACKAGE_PATH "${NUGET_PATH}/packages/v8.redist-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}") + add_library(v8_libbase SHARED IMPORTED) - set_target_properties(v8_libbase PROPERTIES IMPORTED_IMPLIB "${NUGET_PATH}/v8-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/lib/Release/v8_libbase.dll.lib") + set_target_properties(v8_libbase PROPERTIES IMPORTED_IMPLIB "${V8_PACKAGE_PATH}/lib/Release/v8_libbase.dll.lib") add_library(v8_libplatform SHARED IMPORTED) - set_target_properties(v8_libplatform PROPERTIES IMPORTED_IMPLIB "${NUGET_PATH}/v8-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/lib/Release/v8_libplatform.dll.lib") + set_target_properties(v8_libplatform PROPERTIES IMPORTED_IMPLIB "${V8_PACKAGE_PATH}/lib/Release/v8_libplatform.dll.lib") add_library(v8 SHARED IMPORTED) - set_target_properties(v8 PROPERTIES IMPORTED_IMPLIB "${NUGET_PATH}/v8-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/lib/Release/v8.dll.lib") + set_target_properties(v8 PROPERTIES IMPORTED_IMPLIB "${V8_PACKAGE_PATH}/lib/Release/v8.dll.lib") target_link_libraries(v8 INTERFACE v8_libbase INTERFACE v8_libplatform) - target_include_directories(v8 INTERFACE "${NUGET_PATH}/v8-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/include") + target_include_directories(v8 INTERFACE "${V8_PACKAGE_PATH}/include") set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS - "${NUGET_PATH}/v8.redist-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/lib/Release/icudtl.dat" - "${NUGET_PATH}/v8.redist-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/lib/Release/icui18n.dll" - "${NUGET_PATH}/v8.redist-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/lib/Release/icuuc.dll" - "${NUGET_PATH}/v8.redist-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/lib/Release/v8.dll" - "${NUGET_PATH}/v8.redist-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/lib/Release/v8_libbase.dll" - "${NUGET_PATH}/v8.redist-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/lib/Release/v8_libplatform.dll" - "${NUGET_PATH}/v8.redist-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}/lib/Release/zlib.dll" + "${V8_REDIST_PACKAGE_PATH}/lib/Release/icudtl.dat" + "${V8_REDIST_PACKAGE_PATH}/lib/Release/icui18n.dll" + "${V8_REDIST_PACKAGE_PATH}/lib/Release/icuuc.dll" + "${V8_REDIST_PACKAGE_PATH}/lib/Release/v8.dll" + "${V8_REDIST_PACKAGE_PATH}/lib/Release/v8_libbase.dll" + "${V8_REDIST_PACKAGE_PATH}/lib/Release/v8_libplatform.dll" + "${V8_REDIST_PACKAGE_PATH}/lib/Release/zlib.dll" CACHE STRING "N-API runtime output artifacts") endfunction() if(NOT TARGET javascript_engine) add_library(javascript_engine INTERFACE) - add_on_linked_as_dependency_cmake_file(napi "${CMAKE_CURRENT_SOURCE_DIR}/OnLinkedAsDependency.cmake") if(NAPI_JAVASCRIPT_ENGINE STREQUAL "V8") if(WIN32) set_win32_arch() diff --git a/Dependencies/napi/napi-direct/include/napi/napi-inl.h b/Dependencies/napi/napi-direct/include/napi/napi-inl.h index 03f6c525c..075f417c4 100644 --- a/Dependencies/napi/napi-direct/include/napi/napi-inl.h +++ b/Dependencies/napi/napi-direct/include/napi/napi-inl.h @@ -1781,6 +1781,24 @@ inline Value Function::Call(napi_value recv, const std::vector& args return Call(recv, args.size(), args.data()); } +inline Value Function::Call(napi_value recv, size_t argc, const Napi::Value* args) const { + napi_value stackArgs[6]; + std::vector heapArgs; + napi_value* argv; + if (argc <= std::size(stackArgs)) { + argv = stackArgs; + } else { + heapArgs.resize(argc); + argv = heapArgs.data(); + } + + for (size_t i = 0; i < argc; ++i) { + argv[i] = args[i]; + } + + return Call(recv, argc, argv); +} + inline Value Function::Call(napi_value recv, size_t argc, const napi_value* args) const { napi_value result; napi_status status = napi_call_function( diff --git a/Dependencies/napi/napi-direct/include/napi/napi.h b/Dependencies/napi/napi-direct/include/napi/napi.h index 1284e2cc0..aa767f40d 100644 --- a/Dependencies/napi/napi-direct/include/napi/napi.h +++ b/Dependencies/napi/napi-direct/include/napi/napi.h @@ -1013,6 +1013,7 @@ namespace Napi { Value Call(size_t argc, const napi_value* args) const; Value Call(napi_value recv, const std::initializer_list& args) const; Value Call(napi_value recv, const std::vector& args) const; + Value Call(napi_value recv, size_t argc, const Napi::Value* args) const; Value Call(napi_value recv, size_t argc, const napi_value* args) const; #ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC diff --git a/Dependencies/napi/napi-direct/nuget.config b/Dependencies/napi/napi-direct/nuget.config new file mode 100644 index 000000000..db7d8b6cc --- /dev/null +++ b/Dependencies/napi/napi-direct/nuget.config @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Dependencies/napi/napi-jsi/CMakeLists.txt b/Dependencies/napi/napi-jsi/CMakeLists.txt index 2d36ae64e..d142f8164 100644 --- a/Dependencies/napi/napi-jsi/CMakeLists.txt +++ b/Dependencies/napi/napi-jsi/CMakeLists.txt @@ -1,16 +1,60 @@ -if(NOT TARGET jsi) - message(FATAL_ERROR "jsi target is required") -endif() - set(SOURCES "include/napi/env.h" "include/napi/napi.h" "include/napi/napi-inl.h" + "include/napi/js_native_api_types.h" + "include/napi/js_native_api.h" "source/env.cc") +if(NOT TARGET jsi) + if(WIN32) + nuget_download() + set_win32_arch() + set(V8JSI_VERSION "0.64.16") + if (WINDOWS_STORE) + set(V8JSI_PACKAGE_PATH "${NUGET_PATH}/packages/ReactNative.V8Jsi.Windows.UWP.${V8JSI_VERSION}") + set(PLATFORM_FOLDER "uwp") + else() + set(V8JSI_PACKAGE_PATH "${NUGET_PATH}/packages/ReactNative.V8Jsi.Windows.${V8JSI_VERSION}") + set(PLATFORM_FOLDER "win32") + endif() + + # TODO: Pull in v8jsi symbols once they're packaged with the debug build. + set(V8JSI_LIB_PATH_DEBUG "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/Debug/${WIN32_ARCH}/v8jsi.dll.lib") + set(V8JSI_LIB_PATH_RELEASE "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/Release/${WIN32_ARCH}/v8jsi.dll.lib") + set(V8JSI_DLL_PATH "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/$,Debug,Release>/${WIN32_ARCH}/v8jsi.dll") + set(V8JSI_DLL_PATH_DEBUG "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/Debug/${WIN32_ARCH}/v8jsi.dll") + set(V8JSI_DLL_PATH_RELEASE "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/Release/${WIN32_ARCH}/v8jsi.dll") + + add_library(jsi SHARED IMPORTED) + set_target_properties(jsi PROPERTIES + IMPORTED_IMPLIB_DEBUG ${V8JSI_LIB_PATH_DEBUG} + IMPORTED_IMPLIB_RELEASE ${V8JSI_LIB_PATH_RELEASE} + IMPORTED_IMPLIB_MINSIZEREL ${V8JSI_LIB_PATH_RELEASE} + IMPORTED_IMPLIB_RELWITHDEBINFO ${V8JSI_LIB_PATH_RELEASE}) + + target_include_directories(jsi INTERFACE "${V8JSI_PACKAGE_PATH}/build/native/include") + target_include_directories(jsi INTERFACE "${V8JSI_PACKAGE_PATH}/build/native/jsi") + set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_DEBUG ${V8JSI_DLL_PATH_DEBUG} CACHE STRING "N-API runtime output artifacts (debug)") + set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_RELEASE ${V8JSI_DLL_PATH_RELEASE} CACHE STRING "N-API runtime output artifacts (release)") + set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS ${V8JSI_DLL_PATH} CACHE STRING "N-API runtime output artifacts") + target_compile_definitions(jsi INTERFACE V8JSI_ENABLE_INSPECTOR) + + set(SOURCES ${SOURCES} "source/jsi.cpp") + else() + message(FATAL_ERROR "jsi target is required") + endif() +endif() + add_library(napi ${SOURCES}) -target_include_directories(napi +if (DEFINED V8JSI_PACKAGE_PATH) + target_include_directories(napi + PUBLIC "${V8JSI_PACKAGE_PATH}/build/native/include" + PUBLIC "${V8JSI_PACKAGE_PATH}/build/native/jsi") +endif() + +target_include_directories(napi PUBLIC "include") target_link_to_dependencies(napi diff --git a/Dependencies/napi/napi-jsi/include/napi/js_native_api.h b/Dependencies/napi/napi-jsi/include/napi/js_native_api.h new file mode 100644 index 000000000..885542e41 --- /dev/null +++ b/Dependencies/napi/napi-jsi/include/napi/js_native_api.h @@ -0,0 +1,419 @@ +#ifndef SRC_JS_NATIVE_API_H_ +#define SRC_JS_NATIVE_API_H_ + +// This file needs to be compatible with C compilers. +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) + +// Use INT_MAX, this should only be consumed by the pre-processor anyway. +#define NAPI_VERSION_EXPERIMENTAL 2147483647 +#ifndef NAPI_VERSION +#ifdef NAPI_EXPERIMENTAL +#define NAPI_VERSION NAPI_VERSION_EXPERIMENTAL +#else +// The baseline version for N-API. +// The NAPI_VERSION controls which version will be used by default when +// compilling a native addon. If the addon developer specifically wants to use +// functions available in a new version of N-API that is not yet ported in all +// LTS versions, they can set NAPI_VERSION knowing that they have specifically +// depended on that version. +#define NAPI_VERSION 8 +#endif +#endif + +#include "js_native_api_types.h" + +// If you need __declspec(dllimport), either include instead, or +// define NAPI_EXTERN as __declspec(dllimport) on the compiler's command line. +#ifndef NAPI_EXTERN +#ifdef _WIN32 +#define NAPI_EXTERN __declspec(dllexport) +#elif defined(__wasm32__) +#define NAPI_EXTERN __attribute__((visibility("default"))) __attribute__((__import_module__("napi"))) +#else +#define NAPI_EXTERN __attribute__((visibility("default"))) +#endif +#endif + +#define NAPI_AUTO_LENGTH SIZE_MAX + +#ifdef __cplusplus +#define EXTERN_C_START extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_START +#define EXTERN_C_END +#endif + +EXTERN_C_START + +NAPI_EXTERN napi_status __cdecl napi_get_last_error_info(napi_env env, const napi_extended_error_info **result); + +// Getters for defined singletons +NAPI_EXTERN napi_status __cdecl napi_get_undefined(napi_env env, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_get_null(napi_env env, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_get_global(napi_env env, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_get_boolean(napi_env env, bool value, napi_value *result); + +// Methods to create Primitive types/Objects +NAPI_EXTERN napi_status __cdecl napi_create_object(napi_env env, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_array(napi_env env, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_array_with_length(napi_env env, size_t length, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_double(napi_env env, double value, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_int32(napi_env env, int32_t value, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_uint32(napi_env env, uint32_t value, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_int64(napi_env env, int64_t value, napi_value *result); +NAPI_EXTERN +napi_status __cdecl napi_create_string_latin1(napi_env env, const char *str, size_t length, napi_value *result); +NAPI_EXTERN +napi_status __cdecl napi_create_string_utf8(napi_env env, const char *str, size_t length, napi_value *result); +NAPI_EXTERN +napi_status __cdecl napi_create_string_utf16(napi_env env, const char16_t *str, size_t length, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_symbol(napi_env env, napi_value description, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_function( + napi_env env, + const char *utf8name, + size_t length, + napi_callback cb, + void *data, + napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_error(napi_env env, napi_value code, napi_value msg, napi_value *result); +NAPI_EXTERN +napi_status __cdecl napi_create_type_error(napi_env env, napi_value code, napi_value msg, napi_value *result); +NAPI_EXTERN +napi_status __cdecl napi_create_range_error(napi_env env, napi_value code, napi_value msg, napi_value *result); + +// Methods to get the native napi_value from Primitive type +NAPI_EXTERN napi_status __cdecl napi_typeof(napi_env env, napi_value value, napi_valuetype *result); +NAPI_EXTERN napi_status __cdecl napi_get_value_double(napi_env env, napi_value value, double *result); +NAPI_EXTERN napi_status __cdecl napi_get_value_int32(napi_env env, napi_value value, int32_t *result); +NAPI_EXTERN napi_status __cdecl napi_get_value_uint32(napi_env env, napi_value value, uint32_t *result); +NAPI_EXTERN napi_status __cdecl napi_get_value_int64(napi_env env, napi_value value, int64_t *result); +NAPI_EXTERN napi_status __cdecl napi_get_value_bool(napi_env env, napi_value value, bool *result); + +// Copies LATIN-1 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status __cdecl napi_get_value_string_latin1( + napi_env env, + napi_value value, + char *buf, + size_t bufsize, + size_t *result); + +// Copies UTF-8 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status __cdecl napi_get_value_string_utf8( + napi_env env, + napi_value value, + char *buf, + size_t bufsize, + size_t *result); + +// Copies UTF-16 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status __cdecl napi_get_value_string_utf16( + napi_env env, + napi_value value, + char16_t *buf, + size_t bufsize, + size_t *result); + +// Methods to coerce values +// These APIs may execute user scripts +NAPI_EXTERN napi_status __cdecl napi_coerce_to_bool(napi_env env, napi_value value, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_coerce_to_number(napi_env env, napi_value value, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_coerce_to_object(napi_env env, napi_value value, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_coerce_to_string(napi_env env, napi_value value, napi_value *result); + +// Methods to work with Objects +NAPI_EXTERN napi_status __cdecl napi_get_prototype(napi_env env, napi_value object, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_get_property_names(napi_env env, napi_value object, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_set_property(napi_env env, napi_value object, napi_value key, napi_value value); +NAPI_EXTERN napi_status __cdecl napi_has_property(napi_env env, napi_value object, napi_value key, bool *result); +NAPI_EXTERN napi_status __cdecl napi_get_property(napi_env env, napi_value object, napi_value key, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_delete_property(napi_env env, napi_value object, napi_value key, bool *result); +NAPI_EXTERN napi_status __cdecl napi_has_own_property(napi_env env, napi_value object, napi_value key, bool *result); +NAPI_EXTERN napi_status __cdecl napi_set_named_property( + napi_env env, + napi_value object, + const char *utf8name, + napi_value value); +NAPI_EXTERN +napi_status __cdecl napi_has_named_property(napi_env env, napi_value object, const char *utf8name, bool *result); +NAPI_EXTERN napi_status __cdecl napi_get_named_property( + napi_env env, + napi_value object, + const char *utf8name, + napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_set_element(napi_env env, napi_value object, uint32_t index, napi_value value); +NAPI_EXTERN napi_status __cdecl napi_has_element(napi_env env, napi_value object, uint32_t index, bool *result); +NAPI_EXTERN napi_status __cdecl napi_get_element(napi_env env, napi_value object, uint32_t index, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_delete_element(napi_env env, napi_value object, uint32_t index, bool *result); +NAPI_EXTERN napi_status __cdecl napi_define_properties( + napi_env env, + napi_value object, + size_t property_count, + const napi_property_descriptor *properties); + +// Methods to work with Arrays +NAPI_EXTERN napi_status __cdecl napi_is_array(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status __cdecl napi_get_array_length(napi_env env, napi_value value, uint32_t *result); + +// Methods to compare values +NAPI_EXTERN napi_status __cdecl napi_strict_equals(napi_env env, napi_value lhs, napi_value rhs, bool *result); + +// Methods to work with Functions +NAPI_EXTERN napi_status __cdecl napi_call_function( + napi_env env, + napi_value recv, + napi_value func, + size_t argc, + const napi_value *argv, + napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_new_instance( + napi_env env, + napi_value constructor, + size_t argc, + const napi_value *argv, + napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_instanceof(napi_env env, napi_value object, napi_value constructor, bool *result); + +// Methods to work with napi_callbacks + +// Gets all callback info in a single call. (Ugly, but faster.) +NAPI_EXTERN napi_status __cdecl napi_get_cb_info( + napi_env env, // [in] NAPI environment handle + napi_callback_info cbinfo, // [in] Opaque callback-info handle + size_t *argc, // [in-out] Specifies the size of the provided argv array + // and receives the actual count of args. + napi_value *argv, // [out] Array of values + napi_value *this_arg, // [out] Receives the JS 'this' arg for the call + void **data); // [out] Receives the data pointer for the callback. + +NAPI_EXTERN napi_status __cdecl napi_get_new_target(napi_env env, napi_callback_info cbinfo, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_define_class( + napi_env env, + const char *utf8name, + size_t length, + napi_callback constructor, + void *data, + size_t property_count, + const napi_property_descriptor *properties, + napi_value *result); + +// Methods to work with external data objects +NAPI_EXTERN napi_status __cdecl napi_wrap( + napi_env env, + napi_value js_object, + void *native_object, + napi_finalize finalize_cb, + void *finalize_hint, + napi_ref *result); +NAPI_EXTERN napi_status __cdecl napi_unwrap(napi_env env, napi_value js_object, void **result); +NAPI_EXTERN napi_status __cdecl napi_remove_wrap(napi_env env, napi_value js_object, void **result); +NAPI_EXTERN napi_status __cdecl napi_create_external( + napi_env env, + void *data, + napi_finalize finalize_cb, + void *finalize_hint, + napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_get_value_external(napi_env env, napi_value value, void **result); + +// Methods to control object lifespan + +// Set initial_refcount to 0 for a weak reference, >0 for a strong reference. +NAPI_EXTERN napi_status __cdecl napi_create_reference( + napi_env env, + napi_value value, + uint32_t initial_refcount, + napi_ref *result); + +// Deletes a reference. The referenced value is released, and may +// be GC'd unless there are other references to it. +NAPI_EXTERN napi_status __cdecl napi_delete_reference(napi_env env, napi_ref ref); + +// Increments the reference count, optionally returning the resulting count. +// After this call the reference will be a strong reference because its +// refcount is >0, and the referenced object is effectively "pinned". +// Calling this when the refcount is 0 and the object is unavailable +// results in an error. +NAPI_EXTERN napi_status __cdecl napi_reference_ref(napi_env env, napi_ref ref, uint32_t *result); + +// Decrements the reference count, optionally returning the resulting count. +// If the result is 0 the reference is now weak and the object may be GC'd +// at any time if there are no other references. Calling this when the +// refcount is already 0 results in an error. +NAPI_EXTERN napi_status __cdecl napi_reference_unref(napi_env env, napi_ref ref, uint32_t *result); + +// Attempts to get a referenced value. If the reference is weak, +// the value might no longer be available, in that case the call +// is still successful but the result is NULL. +NAPI_EXTERN napi_status __cdecl napi_get_reference_value(napi_env env, napi_ref ref, napi_value *result); + +NAPI_EXTERN napi_status __cdecl napi_open_handle_scope(napi_env env, napi_handle_scope *result); +NAPI_EXTERN napi_status __cdecl napi_close_handle_scope(napi_env env, napi_handle_scope scope); +NAPI_EXTERN napi_status __cdecl napi_open_escapable_handle_scope(napi_env env, napi_escapable_handle_scope *result); +NAPI_EXTERN napi_status __cdecl napi_close_escapable_handle_scope(napi_env env, napi_escapable_handle_scope scope); + +NAPI_EXTERN napi_status __cdecl napi_escape_handle( + napi_env env, + napi_escapable_handle_scope scope, + napi_value escapee, + napi_value *result); + +// Methods to support error handling +NAPI_EXTERN napi_status __cdecl napi_throw(napi_env env, napi_value error); +NAPI_EXTERN napi_status __cdecl napi_throw_error(napi_env env, const char *code, const char *msg); +NAPI_EXTERN napi_status __cdecl napi_throw_type_error(napi_env env, const char *code, const char *msg); +NAPI_EXTERN napi_status __cdecl napi_throw_range_error(napi_env env, const char *code, const char *msg); +NAPI_EXTERN napi_status __cdecl napi_is_error(napi_env env, napi_value value, bool *result); + +// Methods to support catching exceptions +NAPI_EXTERN napi_status __cdecl napi_is_exception_pending(napi_env env, bool *result); +NAPI_EXTERN napi_status __cdecl napi_get_and_clear_last_exception(napi_env env, napi_value *result); + +// Methods to work with array buffers and typed arrays +NAPI_EXTERN napi_status __cdecl napi_is_arraybuffer(napi_env env, napi_value value, bool *result); +NAPI_EXTERN +napi_status __cdecl napi_create_arraybuffer(napi_env env, size_t byte_length, void **data, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_external_arraybuffer( + napi_env env, + void *external_data, + size_t byte_length, + napi_finalize finalize_cb, + void *finalize_hint, + napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_get_arraybuffer_info( + napi_env env, + napi_value arraybuffer, + void **data, + size_t *byte_length); +NAPI_EXTERN napi_status __cdecl napi_is_typedarray(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status __cdecl napi_create_typedarray( + napi_env env, + napi_typedarray_type type, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_get_typedarray_info( + napi_env env, + napi_value typedarray, + napi_typedarray_type *type, + size_t *length, + void **data, + napi_value *arraybuffer, + size_t *byte_offset); + +NAPI_EXTERN napi_status __cdecl napi_create_dataview( + napi_env env, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_is_dataview(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status __cdecl napi_get_dataview_info( + napi_env env, + napi_value dataview, + size_t *bytelength, + void **data, + napi_value *arraybuffer, + size_t *byte_offset); + +// version management +NAPI_EXTERN napi_status __cdecl napi_get_version(napi_env env, uint32_t *result); + +// Promises +NAPI_EXTERN napi_status __cdecl napi_create_promise(napi_env env, napi_deferred *deferred, napi_value *promise); +NAPI_EXTERN napi_status __cdecl napi_resolve_deferred(napi_env env, napi_deferred deferred, napi_value resolution); +NAPI_EXTERN napi_status __cdecl napi_reject_deferred(napi_env env, napi_deferred deferred, napi_value rejection); +NAPI_EXTERN napi_status __cdecl napi_is_promise(napi_env env, napi_value value, bool *is_promise); + +// Running a script +NAPI_EXTERN napi_status __cdecl napi_run_script(napi_env env, napi_value script, napi_value *result); + +// Memory management +NAPI_EXTERN +napi_status __cdecl napi_adjust_external_memory(napi_env env, int64_t change_in_bytes, int64_t *adjusted_value); + +#if NAPI_VERSION >= 5 + +// Dates +NAPI_EXTERN napi_status __cdecl napi_create_date(napi_env env, double time, napi_value *result); + +NAPI_EXTERN napi_status __cdecl napi_is_date(napi_env env, napi_value value, bool *is_date); + +NAPI_EXTERN napi_status __cdecl napi_get_date_value(napi_env env, napi_value value, double *result); + +// Add finalizer for pointer +NAPI_EXTERN napi_status __cdecl napi_add_finalizer( + napi_env env, + napi_value js_object, + void *native_object, + napi_finalize finalize_cb, + void *finalize_hint, + napi_ref *result); + +#endif // NAPI_VERSION >= 5 + +#if NAPI_VERSION >= 6 + +// BigInt +NAPI_EXTERN napi_status __cdecl napi_create_bigint_int64(napi_env env, int64_t value, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_bigint_uint64(napi_env env, uint64_t value, napi_value *result); +NAPI_EXTERN napi_status __cdecl napi_create_bigint_words( + napi_env env, + int sign_bit, + size_t word_count, + const uint64_t *words, + napi_value *result); +NAPI_EXTERN +napi_status __cdecl napi_get_value_bigint_int64(napi_env env, napi_value value, int64_t *result, bool *lossless); +NAPI_EXTERN +napi_status __cdecl napi_get_value_bigint_uint64(napi_env env, napi_value value, uint64_t *result, bool *lossless); +NAPI_EXTERN napi_status __cdecl napi_get_value_bigint_words( + napi_env env, + napi_value value, + int *sign_bit, + size_t *word_count, + uint64_t *words); + +// Object +NAPI_EXTERN napi_status __cdecl napi_get_all_property_names( + napi_env env, + napi_value object, + napi_key_collection_mode key_mode, + napi_key_filter key_filter, + napi_key_conversion key_conversion, + napi_value *result); + +// Instance data +NAPI_EXTERN napi_status __cdecl napi_set_instance_data( + napi_env env, + void *data, + napi_finalize finalize_cb, + void *finalize_hint); + +NAPI_EXTERN napi_status __cdecl napi_get_instance_data(napi_env env, void **data); +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 7 +// ArrayBuffer detaching +NAPI_EXTERN napi_status __cdecl napi_detach_arraybuffer(napi_env env, napi_value arraybuffer); + +NAPI_EXTERN napi_status __cdecl napi_is_detached_arraybuffer(napi_env env, napi_value value, bool *result); +#endif // NAPI_VERSION >= 7 + +#if NAPI_VERSION >= 8 +// Type tagging +NAPI_EXTERN napi_status __cdecl napi_type_tag_object(napi_env env, napi_value value, const napi_type_tag *type_tag); + +NAPI_EXTERN napi_status __cdecl napi_check_object_type_tag( + napi_env env, + napi_value value, + const napi_type_tag *type_tag, + bool *result); +NAPI_EXTERN napi_status __cdecl napi_object_freeze(napi_env env, napi_value object); +NAPI_EXTERN napi_status __cdecl napi_object_seal(napi_env env, napi_value object); +#endif // NAPI_VERSION >= 8 + +EXTERN_C_END + +#endif // SRC_JS_NATIVE_API_H_ diff --git a/Dependencies/napi/napi-jsi/include/napi/js_native_api_types.h b/Dependencies/napi/napi-jsi/include/napi/js_native_api_types.h new file mode 100644 index 000000000..1d881c930 --- /dev/null +++ b/Dependencies/napi/napi-jsi/include/napi/js_native_api_types.h @@ -0,0 +1,149 @@ +#ifndef SRC_JS_NATIVE_API_TYPES_H_ +#define SRC_JS_NATIVE_API_TYPES_H_ + +// This file needs to be compatible with C compilers. +// This is a public include file, and these includes have essentially +// became part of it's API. +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) + +#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) +typedef uint16_t char16_t; +#endif + +// JSVM API types are all opaque pointers for ABI stability +// typedef undefined structs instead of void* for compile time type safety +typedef struct napi_env__ *napi_env; +typedef struct napi_value__ *napi_value; +typedef struct napi_ref__ *napi_ref; +typedef struct napi_handle_scope__ *napi_handle_scope; +typedef struct napi_escapable_handle_scope__ *napi_escapable_handle_scope; +typedef struct napi_callback_info__ *napi_callback_info; +typedef struct napi_deferred__ *napi_deferred; + +typedef enum { + napi_default = 0, + napi_writable = 1 << 0, + napi_enumerable = 1 << 1, + napi_configurable = 1 << 2, + + // Used with napi_define_class to distinguish static properties + // from instance properties. Ignored by napi_define_properties. + napi_static = 1 << 10, + +#if NAPI_VERSION >= 8 + // Default for class methods. + napi_default_method = napi_writable | napi_configurable, + + // Default for object properties, like in JS obj[prop]. + napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable, +#endif // NAPI_VERSION >= 8 +} napi_property_attributes; + +typedef enum { + // ES6 types (corresponds to typeof) + napi_undefined, + napi_null, + napi_boolean, + napi_number, + napi_string, + napi_symbol, + napi_object, + napi_function, + napi_external, + napi_bigint, +} napi_valuetype; + +typedef enum { + napi_int8_array, + napi_uint8_array, + napi_uint8_clamped_array, + napi_int16_array, + napi_uint16_array, + napi_int32_array, + napi_uint32_array, + napi_float32_array, + napi_float64_array, + napi_bigint64_array, + napi_biguint64_array, +} napi_typedarray_type; + +typedef enum { + napi_ok, + napi_invalid_arg, + napi_object_expected, + napi_string_expected, + napi_name_expected, + napi_function_expected, + napi_number_expected, + napi_boolean_expected, + napi_array_expected, + napi_generic_failure, + napi_pending_exception, + napi_cancelled, + napi_escape_called_twice, + napi_handle_scope_mismatch, + napi_callback_scope_mismatch, + napi_queue_full, + napi_closing, + napi_bigint_expected, + napi_date_expected, + napi_arraybuffer_expected, + napi_detachable_arraybuffer_expected, + napi_would_deadlock // unused +} napi_status; +// Note: when adding a new enum value to `napi_status`, please also update +// * `const int last_status` in the definition of `napi_get_last_error_info()' +// in file js_native_api_v8.cc. +// * `const char* error_messages[]` in file js_native_api_v8.cc with a brief +// message explaining the error. +// * the definition of `napi_status` in doc/api/n-api.md to reflect the newly +// added value(s). + +typedef napi_value (*napi_callback)(napi_env env, napi_callback_info info); +typedef void (*napi_finalize)(napi_env env, void *finalize_data, void *finalize_hint); + +typedef struct { + // One of utf8name or name should be NULL. + const char *utf8name; + napi_value name; + + napi_callback method; + napi_callback getter; + napi_callback setter; + napi_value value; + + napi_property_attributes attributes; + void *data; +} napi_property_descriptor; + +typedef struct { + const char *error_message; + void *engine_reserved; + uint32_t engine_error_code; + napi_status error_code; +} napi_extended_error_info; + +#if NAPI_VERSION >= 6 +typedef enum { napi_key_include_prototypes, napi_key_own_only } napi_key_collection_mode; + +typedef enum { + napi_key_all_properties = 0, + napi_key_writable = 1, + napi_key_enumerable = 1 << 1, + napi_key_configurable = 1 << 2, + napi_key_skip_strings = 1 << 3, + napi_key_skip_symbols = 1 << 4 +} napi_key_filter; + +typedef enum { napi_key_keep_numbers, napi_key_numbers_to_strings } napi_key_conversion; +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 8 +typedef struct { + uint64_t lower; + uint64_t upper; +} napi_type_tag; +#endif // NAPI_VERSION >= 8 + +#endif // SRC_JS_NATIVE_API_TYPES_H_ diff --git a/Dependencies/napi/napi-jsi/include/napi/napi-inl.h b/Dependencies/napi/napi-jsi/include/napi/napi-inl.h index ac00c891c..454458027 100644 --- a/Dependencies/napi/napi-jsi/include/napi/napi-inl.h +++ b/Dependencies/napi/napi-jsi/include/napi/napi-inl.h @@ -1222,7 +1222,7 @@ namespace details struct Function { static inline jsi::Value Callback(napi_env env, const jsi::Value& thisVal, const jsi::Value* args, size_t count, void* data, Callable cb) { CallbackInfo callbackInfo{env, thisVal, args, count, {}, data}; - return {env->rt, cb(callbackInfo)}; + return jsi::Value(env->rt, cb(std::move(callbackInfo))); } }; diff --git a/Dependencies/napi/napi-jsi/include/napi/napi.h b/Dependencies/napi/napi-jsi/include/napi/napi.h index 5b7eeb741..b4b90fb6b 100644 --- a/Dependencies/napi/napi-jsi/include/napi/napi.h +++ b/Dependencies/napi/napi-jsi/include/napi/napi.h @@ -1,5 +1,7 @@ #pragma once +#include "js_native_api.h" +#include "js_native_api_types.h" #include #include #include @@ -8,39 +10,6 @@ #include #include -// Copied from js_native_api.h -typedef enum { - napi_default = 0, - napi_writable = 1 << 0, - napi_enumerable = 1 << 1, - napi_configurable = 1 << 2, -} napi_property_attributes; - -typedef enum { - // ES6 types (corresponds to typeof) - napi_undefined, - napi_null, - napi_boolean, - napi_number, - napi_string, - napi_symbol, - napi_object, - napi_function, - napi_external, -} napi_valuetype; - -typedef enum { - napi_int8_array, - napi_uint8_array, - napi_uint8_clamped_array, - napi_int16_array, - napi_uint16_array, - napi_int32_array, - napi_uint32_array, - napi_float32_array, - napi_float64_array, -} napi_typedarray_type; - struct napi_env__ { napi_env__(facebook::jsi::Runtime& rt) : rt{rt} @@ -1161,6 +1130,8 @@ namespace Napi { CallbackInfo(napi_env env, const jsi::Value& thisVal, const jsi::Value* args, size_t argc, const jsi::Value& newTarget, void* data); ~CallbackInfo(); + CallbackInfo(CallbackInfo &&) = default; + // Disallow copying to prevent multiple free of _dynamicArgs CallbackInfo(CallbackInfo const &) = delete; void operator=(CallbackInfo const &) = delete; diff --git a/Dependencies/napi/napi-jsi/nuget.config b/Dependencies/napi/napi-jsi/nuget.config new file mode 100644 index 000000000..c681fdbd5 --- /dev/null +++ b/Dependencies/napi/napi-jsi/nuget.config @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Dependencies/napi/napi-jsi/packages.config b/Dependencies/napi/napi-jsi/packages.config new file mode 100644 index 000000000..f91b6758a --- /dev/null +++ b/Dependencies/napi/napi-jsi/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Dependencies/napi/napi-jsi/source/jsi.cpp b/Dependencies/napi/napi-jsi/source/jsi.cpp new file mode 100644 index 000000000..e4a7e431f --- /dev/null +++ b/Dependencies/napi/napi-jsi/source/jsi.cpp @@ -0,0 +1,484 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include +#include + +namespace facebook { +namespace jsi { + +namespace { + +// This is used for generating short exception strings. +std::string kindToString(const Value& v, Runtime* rt = nullptr) { + if (v.isUndefined()) { + return "undefined"; + } else if (v.isNull()) { + return "null"; + } else if (v.isBool()) { + return v.getBool() ? "true" : "false"; + } else if (v.isNumber()) { + return "a number"; + } else if (v.isString()) { + return "a string"; + } else { + assert(v.isObject() && "Expecting object."); + return rt != nullptr && v.getObject(*rt).isFunction(*rt) ? "a function" + : "an object"; + } +} + +// getPropertyAsFunction() will try to create a JSError. If the +// failure is in building a JSError, this will lead to infinite +// recursion. This function is used in place of getPropertyAsFunction +// when building JSError, to avoid that infinite recursion. +Value callGlobalFunction(Runtime& runtime, const char* name, const Value& arg) { + Value v = runtime.global().getProperty(runtime, name); + if (!v.isObject()) { + throw JSINativeException( + std::string("callGlobalFunction: JS global property '") + name + + "' is " + kindToString(v, &runtime) + ", expected a Function"); + } + Object o = v.getObject(runtime); + if (!o.isFunction(runtime)) { + throw JSINativeException( + std::string("callGlobalFunction: JS global property '") + name + + "' is a non-callable Object, expected a Function"); + } + Function f = std::move(o).getFunction(runtime); + return f.call(runtime, arg); +} + +} // namespace + +namespace detail { + +void throwJSError(Runtime& rt, const char* msg) { + throw JSError(rt, msg); +} + +} // namespace detail + +Buffer::~Buffer() = default; + +PreparedJavaScript::~PreparedJavaScript() = default; + +Value HostObject::get(Runtime&, const PropNameID&) { + return Value(); +} + +void HostObject::set(Runtime& rt, const PropNameID& name, const Value&) { + std::string msg("TypeError: Cannot assign to property '"); + msg += name.utf8(rt); + msg += "' on HostObject with default setter"; + throw JSError(rt, msg); +} + +HostObject::~HostObject() {} + +Runtime::~Runtime() {} + +Instrumentation& Runtime::instrumentation() { + class NoInstrumentation : public Instrumentation { + std::string getRecordedGCStats() override { + return ""; + } + + std::unordered_map getHeapInfo(bool) override { + return std::unordered_map{}; + } + + void collectGarbage() override {} + + void startTrackingHeapObjectStackTraces() override {} + void stopTrackingHeapObjectStackTraces() override {} + + void createSnapshotToFile(const std::string&) override { + throw JSINativeException( + "Default instrumentation cannot create a heap snapshot"); + } + + void createSnapshotToStream(std::ostream&) override { + throw JSINativeException( + "Default instrumentation cannot create a heap snapshot"); + } + + std::string flushAndDisableBridgeTrafficTrace() override { + std::abort(); + } + + void writeBasicBlockProfileTraceToFile(const std::string&) const override { + std::abort(); + } + + void dumpProfilerSymbolsToFile(const std::string&) const override { + std::abort(); + } + }; + + static NoInstrumentation sharedInstance; + return sharedInstance; +} + +Value Runtime::createValueFromJsonUtf8(const uint8_t* json, size_t length) { + Function parseJson = global() + .getPropertyAsObject(*this, "JSON") + .getPropertyAsFunction(*this, "parse"); + return parseJson.call(*this, String::createFromUtf8(*this, json, length)); +} + +Pointer& Pointer::operator=(Pointer&& other) { + if (ptr_) { + ptr_->invalidate(); + } + ptr_ = other.ptr_; + other.ptr_ = nullptr; + return *this; +} + +Object Object::getPropertyAsObject(Runtime& runtime, const char* name) const { + Value v = getProperty(runtime, name); + + if (!v.isObject()) { + throw JSError( + runtime, + std::string("getPropertyAsObject: property '") + name + "' is " + + kindToString(v, &runtime) + ", expected an Object"); + } + + return v.getObject(runtime); +} + +Function Object::getPropertyAsFunction(Runtime& runtime, const char* name) + const { + Object obj = getPropertyAsObject(runtime, name); + if (!obj.isFunction(runtime)) { + throw JSError( + runtime, + std::string("getPropertyAsFunction: property '") + name + "' is " + + kindToString(std::move(obj), &runtime) + ", expected a Function"); + }; + + return std::move(obj).getFunction(runtime); +} + +Array Object::asArray(Runtime& runtime) const& { + if (!isArray(runtime)) { + throw JSError( + runtime, + "Object is " + kindToString(Value(runtime, *this), &runtime) + + ", expected an array"); + } + return getArray(runtime); +} + +Array Object::asArray(Runtime& runtime) && { + if (!isArray(runtime)) { + throw JSError( + runtime, + "Object is " + kindToString(Value(runtime, *this), &runtime) + + ", expected an array"); + } + return std::move(*this).getArray(runtime); +} + +Function Object::asFunction(Runtime& runtime) const& { + if (!isFunction(runtime)) { + throw JSError( + runtime, + "Object is " + kindToString(Value(runtime, *this), &runtime) + + ", expected a function"); + } + return getFunction(runtime); +} + +Function Object::asFunction(Runtime& runtime) && { + if (!isFunction(runtime)) { + throw JSError( + runtime, + "Object is " + kindToString(Value(runtime, *this), &runtime) + + ", expected a function"); + } + return std::move(*this).getFunction(runtime); +} + +Value::Value(Value&& other) : Value(other.kind_) { + if (kind_ == BooleanKind) { + data_.boolean = other.data_.boolean; + } else if (kind_ == NumberKind) { + data_.number = other.data_.number; + } else if (kind_ >= PointerKind) { + new (&data_.pointer) Pointer(std::move(other.data_.pointer)); + } + // when the other's dtor runs, nothing will happen. + other.kind_ = UndefinedKind; +} + +Value::Value(Runtime& runtime, const Value& other) : Value(other.kind_) { + // data_ is uninitialized, so use placement new to create non-POD + // types in it. Any other kind of initialization will call a dtor + // first, which is incorrect. + if (kind_ == BooleanKind) { + data_.boolean = other.data_.boolean; + } else if (kind_ == NumberKind) { + data_.number = other.data_.number; + } else if (kind_ == SymbolKind) { + new (&data_.pointer) Pointer(runtime.cloneSymbol(other.data_.pointer.ptr_)); + } else if (kind_ == StringKind) { + new (&data_.pointer) Pointer(runtime.cloneString(other.data_.pointer.ptr_)); + } else if (kind_ >= ObjectKind) { + new (&data_.pointer) Pointer(runtime.cloneObject(other.data_.pointer.ptr_)); + } +} + +Value::~Value() { + if (kind_ >= PointerKind) { + data_.pointer.~Pointer(); + } +} + +bool Value::strictEquals(Runtime& runtime, const Value& a, const Value& b) { + if (a.kind_ != b.kind_) { + return false; + } + switch (a.kind_) { + case UndefinedKind: + case NullKind: + return true; + case BooleanKind: + return a.data_.boolean == b.data_.boolean; + case NumberKind: + return a.data_.number == b.data_.number; + case SymbolKind: + return runtime.strictEquals( + static_cast(a.data_.pointer), + static_cast(b.data_.pointer)); + case StringKind: + return runtime.strictEquals( + static_cast(a.data_.pointer), + static_cast(b.data_.pointer)); + case ObjectKind: + return runtime.strictEquals( + static_cast(a.data_.pointer), + static_cast(b.data_.pointer)); + } + return false; +} + +double Value::asNumber() const { + if (!isNumber()) { + throw JSINativeException( + "Value is " + kindToString(*this) + ", expected a number"); + } + + return getNumber(); +} + +Object Value::asObject(Runtime& rt) const& { + if (!isObject()) { + throw JSError( + rt, "Value is " + kindToString(*this, &rt) + ", expected an Object"); + } + + return getObject(rt); +} + +Object Value::asObject(Runtime& rt) && { + if (!isObject()) { + throw JSError( + rt, "Value is " + kindToString(*this, &rt) + ", expected an Object"); + } + auto ptr = data_.pointer.ptr_; + data_.pointer.ptr_ = nullptr; + return static_cast(ptr); +} + +Symbol Value::asSymbol(Runtime& rt) const& { + if (!isSymbol()) { + throw JSError( + rt, "Value is " + kindToString(*this, &rt) + ", expected a Symbol"); + } + + return getSymbol(rt); +} + +Symbol Value::asSymbol(Runtime& rt) && { + if (!isSymbol()) { + throw JSError( + rt, "Value is " + kindToString(*this, &rt) + ", expected a Symbol"); + } + + return std::move(*this).getSymbol(rt); +} + +String Value::asString(Runtime& rt) const& { + if (!isString()) { + throw JSError( + rt, "Value is " + kindToString(*this, &rt) + ", expected a String"); + } + + return getString(rt); +} + +String Value::asString(Runtime& rt) && { + if (!isString()) { + throw JSError( + rt, "Value is " + kindToString(*this, &rt) + ", expected a String"); + } + + return std::move(*this).getString(rt); +} + +String Value::toString(Runtime& runtime) const { + Function toString = runtime.global().getPropertyAsFunction(runtime, "String"); + return toString.call(runtime, *this).getString(runtime); +} + +Array Array::createWithElements( + Runtime& rt, + std::initializer_list elements) { + Array result(rt, elements.size()); + size_t index = 0; + for (const auto& element : elements) { + result.setValueAtIndex(rt, index++, element); + } + return result; +} + +std::vector HostObject::getPropertyNames(Runtime&) { + return {}; +} + +Runtime::ScopeState* Runtime::pushScope() { + return nullptr; +} + +void Runtime::popScope(ScopeState*) {} + +JSError::JSError(Runtime& rt, Value&& value) { + setValue(rt, std::move(value)); +} + +JSError::JSError(Runtime& rt, std::string msg) : message_(std::move(msg)) { + try { + setValue( + rt, + callGlobalFunction(rt, "Error", String::createFromUtf8(rt, message_))); + } catch (const std::exception& ex) { + message_ = std::string(ex.what()) + " (while raising " + message_ + ")"; + setValue(rt, String::createFromUtf8(rt, message_)); + } catch (...) { + setValue(rt, Value()); + } +} + +JSError::JSError(Runtime& rt, std::string msg, std::string stack) + : message_(std::move(msg)), stack_(std::move(stack)) { + try { + Object e(rt); + e.setProperty(rt, "message", String::createFromUtf8(rt, message_)); + e.setProperty(rt, "stack", String::createFromUtf8(rt, stack_)); + setValue(rt, std::move(e)); + } catch (const std::exception& ex) { + setValue(rt, String::createFromUtf8(rt, ex.what())); + } catch (...) { + setValue(rt, Value()); + } +} + +JSError::JSError(std::string what, Runtime& rt, Value&& value) + : JSIException(std::move(what)) { + setValue(rt, std::move(value)); +} + +void JSError::setValue(Runtime& rt, Value&& value) { + value_ = std::make_shared(std::move(value)); + + try { + if ((message_.empty() || stack_.empty()) && value_->isObject()) { + auto obj = value_->getObject(rt); + + if (message_.empty()) { + try { + Value message = obj.getProperty(rt, "message"); + if (!message.isUndefined() && !message.isString()) { + message = callGlobalFunction(rt, "String", message); + } + if (message.isString()) { + message_ = message.getString(rt).utf8(rt); + } else if (!message.isUndefined()) { + message_ = "String(e.message) is a " + kindToString(message, &rt); + } + } catch (const std::exception& ex) { + message_ = std::string("[Exception while creating message string: ") + + ex.what() + "]"; + } + } + + if (stack_.empty()) { + try { + Value stack = obj.getProperty(rt, "stack"); + if (!stack.isUndefined() && !stack.isString()) { + stack = callGlobalFunction(rt, "String", stack); + } + if (stack.isString()) { + stack_ = stack.getString(rt).utf8(rt); + } else if (!stack.isUndefined()) { + stack_ = "String(e.stack) is a " + kindToString(stack, &rt); + } + } catch (const std::exception& ex) { + message_ = std::string("[Exception while creating stack string: ") + + ex.what() + "]"; + } + } + } + + if (message_.empty()) { + try { + if (value_->isString()) { + message_ = value_->getString(rt).utf8(rt); + } else { + Value message = callGlobalFunction(rt, "String", *value_); + if (message.isString()) { + message_ = message.getString(rt).utf8(rt); + } else { + message_ = "String(e) is a " + kindToString(message, &rt); + } + } + } catch (const std::exception& ex) { + message_ = std::string("[Exception while creating message string: ") + + ex.what() + "]"; + } + } + + if (stack_.empty()) { + stack_ = "no stack"; + } + + if (what_.empty()) { + what_ = message_ + "\n\n" + stack_; + } + } catch (...) { + message_ = "[Exception caught creating message string]"; + stack_ = "[Exception caught creating stack string]"; + what_ = "[Exception caught getting value fields]"; + } +} + +JSIException::~JSIException() {} + +JSINativeException::~JSINativeException() {} + +JSError::~JSError() {} + +} // namespace jsi +} // namespace facebook diff --git a/Plugins/ChromeDevTools/CMakeLists.txt b/Plugins/ChromeDevTools/CMakeLists.txt index 2b00bbf94..0c25df9b5 100644 --- a/Plugins/ChromeDevTools/CMakeLists.txt +++ b/Plugins/ChromeDevTools/CMakeLists.txt @@ -1,9 +1,14 @@ set(SOURCES "Include/Babylon/Plugins/ChromeDevTools.h") -set(CHROME_DEVTOOLS_SUPPORTED_ENGINES "V8") +if (WIN32) + set(CHROME_DEVTOOLS_SUPPORTED_ENGINES ${CHROME_DEVTOOLS_SUPPORTED_ENGINES} "JSI") + if (NOT WINDOWS_STORE) + set(CHROME_DEVTOOLS_SUPPORTED_ENGINES ${CHROME_DEVTOOLS_SUPPORTED_ENGINES} "V8") + endif() +endif() -if (NAPI_JAVASCRIPT_ENGINE IN_LIST CHROME_DEVTOOLS_SUPPORTED_ENGINES AND WIN32) +if (NAPI_JAVASCRIPT_ENGINE IN_LIST CHROME_DEVTOOLS_SUPPORTED_ENGINES) set(SOURCES ${SOURCES} "Source/ChromeDevTools${NAPI_JAVASCRIPT_ENGINE}.cpp") else() set(SOURCES ${SOURCES} "Source/ChromeDevToolsNull.cpp") @@ -12,14 +17,14 @@ endif() add_library(ChromeDevTools ${SOURCES}) warnings_as_errors(ChromeDevTools) +if (NAPI_JAVASCRIPT_ENGINE IN_LIST CHROME_DEVTOOLS_SUPPORTED_ENGINES AND NAPI_JAVASCRIPT_ENGINE STREQUAL "V8") + target_link_to_dependencies(ChromeDevTools PRIVATE v8inspector) +endif() + target_include_directories(ChromeDevTools INTERFACE "Include") target_include_directories(ChromeDevTools PRIVATE "Include/Babylon/Plugins") target_link_to_dependencies(ChromeDevTools PUBLIC JsRuntime) -if (NAPI_JAVASCRIPT_ENGINE STREQUAL "V8" AND WIN32) - target_link_to_dependencies(ChromeDevTools PRIVATE v8inspector) -endif() - set_property(TARGET ChromeDevTools PROPERTY FOLDER Plugins) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) diff --git a/Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp b/Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp new file mode 100644 index 000000000..654166fa8 --- /dev/null +++ b/Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp @@ -0,0 +1,76 @@ +#include "ChromeDevTools.h" + +#include +#include + +namespace Babylon::Plugins +{ + class ChromeDevTools::Impl final : public std::enable_shared_from_this + { + public: + explicit Impl(Napi::Env env) + : m_env(env) + { + JsRuntime::GetFromJavaScript(env).Dispatch([this](Napi::Env env) { + m_runtime = JsRuntime::NativeObject::GetFromJavaScript(env).Get("_JSIRuntime").As>().Data(); + }); + } + + ~Impl() + { + } + + bool SupportsInspector() + { + return true; + } + + void StartInspector(const unsigned short, const std::string&) + { + JsRuntime::GetFromJavaScript(m_env).Dispatch([this](Napi::Env) { + if (m_runtime != nullptr) + { + v8runtime::openInspector(*m_runtime); + } + }); + } + + void StopInspector() + { + } + + private: + facebook::jsi::Runtime* m_runtime; + Napi::Env m_env; + }; + + ChromeDevTools ChromeDevTools::Initialize(Napi::Env env) + { + return {std::make_shared(env)}; + } + + ChromeDevTools::ChromeDevTools(std::shared_ptr impl) + : m_impl{std::move(impl)} + { + } + + bool ChromeDevTools::SupportsInspector() const + { + return m_impl->SupportsInspector(); + } + + /* + Note: V8JSI doesn't currently support setting the port or appName at runtime. + For now the port is set to 4653 in AppRuntimeJSI.cpp. + */ + void ChromeDevTools::StartInspector(const unsigned short port, const std::string& appName) const + { + m_impl->StartInspector(port, appName); + } + + /* Note: V8JSI doesn't currently have a method for stopping the inspector at runtime. */ + void ChromeDevTools::StopInspector() const + { + m_impl->StopInspector(); + } +} diff --git a/Plugins/NativeCamera/Source/NativeCamera.cpp b/Plugins/NativeCamera/Source/NativeCamera.cpp index 65a3e4f42..1c437463f 100644 --- a/Plugins/NativeCamera/Source/NativeCamera.cpp +++ b/Plugins/NativeCamera/Source/NativeCamera.cpp @@ -66,18 +66,7 @@ namespace Babylon // append media devices to navigator Napi::Object mediaDevices = Napi::Object::New(env); - mediaDevices.Set("getUserMedia", Napi::Function::New(env, [](const Napi::CallbackInfo& info) { - auto env = info.Env(); - auto deferred{ Napi::Promise::Deferred::New(env) }; - auto promise{ deferred.Promise() }; - - auto& jsRuntime{ JsRuntime::GetFromJavaScript(env) }; - jsRuntime.Dispatch([deferred{ std::move(deferred) }](Napi::Env env) { - deferred.Resolve(env.Null()); - }); - - return promise; - })); + mediaDevices.Set("getUserMedia", Napi::Function::New(env, &NativeCamera::GetUserMedia, "getUserMedia")); navigator.Set("mediaDevices", mediaDevices); } @@ -120,6 +109,20 @@ namespace Babylon videoObject->UpdateTexture(texture->Handle); } + + static Napi::Value GetUserMedia(const Napi::CallbackInfo& info) + { + auto env = info.Env(); + auto deferred{Napi::Promise::Deferred::New(env)}; + auto promise{deferred.Promise()}; + + auto& jsRuntime{JsRuntime::GetFromJavaScript(env)}; + jsRuntime.Dispatch([deferred{std::move(deferred)}](Napi::Env env) { + deferred.Resolve(env.Null()); + }); + + return promise; + } }; Camera::Camera(std::shared_ptr impl) diff --git a/Polyfills/Console/Source/Console.cpp b/Polyfills/Console/Source/Console.cpp index 6a90a7569..57f5aee23 100644 --- a/Polyfills/Console/Source/Console.cpp +++ b/Polyfills/Console/Source/Console.cpp @@ -5,9 +5,9 @@ namespace { - std::vector GetCallbackInfoArgs(const Napi::CallbackInfo& info) + std::vector GetCallbackInfoArgs(const Napi::CallbackInfo& info) { - auto args = std::vector(); + auto args = std::vector(); for (unsigned int index = 0; index < info.Length(); index++) args.push_back(info[index]); return args; @@ -34,7 +34,7 @@ namespace Babylon::Polyfills::Internal const auto existingConsole = env.Global().Get(JS_INSTANCE_NAME); if (!existingConsole.IsUndefined()) { - Console::Unwrap(console)->m_engineConsole = std::make_unique(Napi::Persistent(existingConsole.As())); + Console::Unwrap(console)->m_engineConsole = std::make_unique(Napi::Persistent(existingConsole.As())); } env.Global().Set(JS_INSTANCE_NAME, console); } @@ -83,8 +83,10 @@ namespace Babylon::Polyfills::Internal if (m_engineConsole != nullptr) { const auto engineConsoleFunc = m_engineConsole->Value().Get(functionName).As(); - if (!engineConsoleFunc.IsUndefined()) - engineConsoleFunc.As().Call(m_engineConsole->Value(), GetCallbackInfoArgs(info)); + if (!engineConsoleFunc.IsUndefined()) { + const auto args = GetCallbackInfoArgs(info); + engineConsoleFunc.As().Call(m_engineConsole->Value(), args.size(), args.data()); + } } } } diff --git a/Polyfills/Console/Source/Console.h b/Polyfills/Console/Source/Console.h index 210a82eb2..eb2b50916 100644 --- a/Polyfills/Console/Source/Console.h +++ b/Polyfills/Console/Source/Console.h @@ -22,7 +22,7 @@ namespace Babylon::Polyfills::Internal void InvokeCallback(const Napi::CallbackInfo& info, Babylon::Polyfills::Console::LogLevel logLevel) const; void InvokeEngineCallback(const std::string functionName, const Napi::CallbackInfo& info); - std::unique_ptr m_engineConsole{}; + std::unique_ptr m_engineConsole{}; Babylon::Polyfills::Console::CallbackT m_callback{}; }; } From b41356cc6b43b6029a31c4e699b7bb03b1452eca Mon Sep 17 00:00:00 2001 From: Robert Gerdisch Date: Fri, 23 Jul 2021 10:52:16 -0700 Subject: [PATCH 2/9] Use original port --- Apps/Playground/UWP/App.cpp | 2 +- Apps/Playground/Win32/App.cpp | 2 +- Core/AppRuntime/Source/AppRuntimeJSI.cpp | 4 ++-- Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Apps/Playground/UWP/App.cpp b/Apps/Playground/UWP/App.cpp index 72f27bd66..328063ec1 100644 --- a/Apps/Playground/UWP/App.cpp +++ b/Apps/Playground/UWP/App.cpp @@ -296,7 +296,7 @@ void App::RestartRuntime(Windows::Foundation::Rect bounds) m_chromeDevTools = std::make_unique(Babylon::Plugins::ChromeDevTools::Initialize(env)); if (m_chromeDevTools->SupportsInspector()) { - m_chromeDevTools->StartInspector(4653, "BabylonNative Playground"); + m_chromeDevTools->StartInspector(5643, "BabylonNative Playground"); } }); diff --git a/Apps/Playground/Win32/App.cpp b/Apps/Playground/Win32/App.cpp index 45323599d..c90989131 100644 --- a/Apps/Playground/Win32/App.cpp +++ b/Apps/Playground/Win32/App.cpp @@ -140,7 +140,7 @@ namespace chromeDevTools = std::make_unique(Babylon::Plugins::ChromeDevTools::Initialize(env)); if (chromeDevTools->SupportsInspector()) { - chromeDevTools->StartInspector(4653, "BabylonNative Playground"); + chromeDevTools->StartInspector(5643, "BabylonNative Playground"); } }); diff --git a/Core/AppRuntime/Source/AppRuntimeJSI.cpp b/Core/AppRuntime/Source/AppRuntimeJSI.cpp index 38c38efa2..6fd233291 100644 --- a/Core/AppRuntime/Source/AppRuntimeJSI.cpp +++ b/Core/AppRuntime/Source/AppRuntimeJSI.cpp @@ -30,9 +30,9 @@ namespace Babylon }; void AppRuntime::RunEnvironmentTier(const char*) - { + { v8runtime::V8RuntimeArgs args{}; - args.inspectorPort = 4653; + args.inspectorPort = 5643; args.foreground_task_runner = std::make_shared(*m_workQueue); const auto runtime = v8runtime::makeV8Runtime(std::move(args)); diff --git a/Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp b/Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp index 654166fa8..ef5827aab 100644 --- a/Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp +++ b/Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp @@ -61,7 +61,7 @@ namespace Babylon::Plugins /* Note: V8JSI doesn't currently support setting the port or appName at runtime. - For now the port is set to 4653 in AppRuntimeJSI.cpp. + For now the port is set to 5643 in AppRuntimeJSI.cpp. */ void ChromeDevTools::StartInspector(const unsigned short port, const std::string& appName) const { From 9b57f897fc7f2e38ec0a860ecff85c7dd19feb59 Mon Sep 17 00:00:00 2001 From: Robert Gerdisch Date: Fri, 23 Jul 2021 11:02:45 -0700 Subject: [PATCH 3/9] Cleanup --- Core/AppRuntime/Source/AppRuntimeJSI.cpp | 16 ++++++++++------ Dependencies/CMakeExtensions/CMakeLists.txt | 2 +- Dependencies/napi/OnLinkedAsDependency.cmake | 2 +- Dependencies/napi/napi-direct/CMakeLists.txt | 2 +- Dependencies/napi/napi-jsi/CMakeLists.txt | 2 +- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Core/AppRuntime/Source/AppRuntimeJSI.cpp b/Core/AppRuntime/Source/AppRuntimeJSI.cpp index 6fd233291..97f188c65 100644 --- a/Core/AppRuntime/Source/AppRuntimeJSI.cpp +++ b/Core/AppRuntime/Source/AppRuntimeJSI.cpp @@ -5,14 +5,15 @@ #include #include -namespace Babylon +namespace { class TaskRunnerAdapter : public v8runtime::JSITaskRunner { public: - TaskRunnerAdapter(WorkQueue& workQueue) + TaskRunnerAdapter(Babylon::WorkQueue& workQueue) : m_workQueue(workQueue) - { } + { + } void postTask(std::unique_ptr task) override { @@ -26,17 +27,20 @@ namespace Babylon TaskRunnerAdapter(const TaskRunnerAdapter&) = delete; TaskRunnerAdapter& operator=(const TaskRunnerAdapter&) = delete; - WorkQueue& m_workQueue; + Babylon::WorkQueue& m_workQueue; }; +} +namespace Babylon +{ void AppRuntime::RunEnvironmentTier(const char*) { v8runtime::V8RuntimeArgs args{}; args.inspectorPort = 5643; args.foreground_task_runner = std::make_shared(*m_workQueue); - const auto runtime = v8runtime::makeV8Runtime(std::move(args)); - Napi::Env env = Napi::Attach(*runtime); + const auto runtime{v8runtime::makeV8Runtime(std::move(args))}; + const auto env{Napi::Attach(*runtime)}; Dispatch([&runtime](Napi::Env env) { JsRuntime::NativeObject::GetFromJavaScript(env) .Set("_JSIRuntime", Napi::External::New(env, runtime.get())); diff --git a/Dependencies/CMakeExtensions/CMakeLists.txt b/Dependencies/CMakeExtensions/CMakeLists.txt index 3aa5c6c05..386157b9f 100644 --- a/Dependencies/CMakeExtensions/CMakeLists.txt +++ b/Dependencies/CMakeExtensions/CMakeLists.txt @@ -127,7 +127,7 @@ endfunction() # Uses the nuget.config and packages.config files in the current directory to download packages from NuGet. # NUGET_PATH will be set to the directory where the packages are installed. -function (nuget_download) +function (download_nuget) set(NUGET_PATH "${CMAKE_BINARY_DIR}/NuGet") set(NUGET_PATH "${NUGET_PATH}" PARENT_SCOPE) set(NUGET_EXE "${NUGET_PATH}/nuget.exe") diff --git a/Dependencies/napi/OnLinkedAsDependency.cmake b/Dependencies/napi/OnLinkedAsDependency.cmake index 4a62bd088..497402d6a 100644 --- a/Dependencies/napi/OnLinkedAsDependency.cmake +++ b/Dependencies/napi/OnLinkedAsDependency.cmake @@ -4,7 +4,7 @@ function(on_linked_as_dependency target) # Propagate this file to the target so that it will be transitively available to targets that # link to that one, too. propagate_on_linked_as_dependency_cmake_file(napi ${target}) - if (DEFINED NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS) + if (DEFINED NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS) # We only need to actually copy files if we're being linked from an executable. get_target_property(type ${target} TYPE) if(${type} STREQUAL "EXECUTABLE") diff --git a/Dependencies/napi/napi-direct/CMakeLists.txt b/Dependencies/napi/napi-direct/CMakeLists.txt index 505cd3d04..b0e3077eb 100644 --- a/Dependencies/napi/napi-direct/CMakeLists.txt +++ b/Dependencies/napi/napi-direct/CMakeLists.txt @@ -28,7 +28,7 @@ target_include_directories(napi PUBLIC "include") # Install v8 SDK from NuGet function (install_v8_nuget V8_VERSION ARCH VS_PLAT_TOOLSET) - nuget_download() + download_nuget() set(V8_PACKAGE_PATH "${NUGET_PATH}/packages/v8-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}") set(V8_REDIST_PACKAGE_PATH "${NUGET_PATH}/packages/v8.redist-${VS_PLAT_TOOLSET}-${ARCH}.${V8_VERSION}") diff --git a/Dependencies/napi/napi-jsi/CMakeLists.txt b/Dependencies/napi/napi-jsi/CMakeLists.txt index d142f8164..8b9c07145 100644 --- a/Dependencies/napi/napi-jsi/CMakeLists.txt +++ b/Dependencies/napi/napi-jsi/CMakeLists.txt @@ -8,7 +8,7 @@ set(SOURCES if(NOT TARGET jsi) if(WIN32) - nuget_download() + download_nuget() set_win32_arch() set(V8JSI_VERSION "0.64.16") if (WINDOWS_STORE) From ca6eefea648e9469d894ed13d0aab58c470d0843 Mon Sep 17 00:00:00 2001 From: Robert Gerdisch Date: Fri, 23 Jul 2021 11:08:00 -0700 Subject: [PATCH 4/9] Back out CallbackInfo change --- Dependencies/napi/napi-jsi/include/napi/napi-inl.h | 2 +- Dependencies/napi/napi-jsi/include/napi/napi.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Dependencies/napi/napi-jsi/include/napi/napi-inl.h b/Dependencies/napi/napi-jsi/include/napi/napi-inl.h index 454458027..ac00c891c 100644 --- a/Dependencies/napi/napi-jsi/include/napi/napi-inl.h +++ b/Dependencies/napi/napi-jsi/include/napi/napi-inl.h @@ -1222,7 +1222,7 @@ namespace details struct Function { static inline jsi::Value Callback(napi_env env, const jsi::Value& thisVal, const jsi::Value* args, size_t count, void* data, Callable cb) { CallbackInfo callbackInfo{env, thisVal, args, count, {}, data}; - return jsi::Value(env->rt, cb(std::move(callbackInfo))); + return {env->rt, cb(callbackInfo)}; } }; diff --git a/Dependencies/napi/napi-jsi/include/napi/napi.h b/Dependencies/napi/napi-jsi/include/napi/napi.h index b4b90fb6b..ff21c73a2 100644 --- a/Dependencies/napi/napi-jsi/include/napi/napi.h +++ b/Dependencies/napi/napi-jsi/include/napi/napi.h @@ -1130,8 +1130,6 @@ namespace Napi { CallbackInfo(napi_env env, const jsi::Value& thisVal, const jsi::Value* args, size_t argc, const jsi::Value& newTarget, void* data); ~CallbackInfo(); - CallbackInfo(CallbackInfo &&) = default; - // Disallow copying to prevent multiple free of _dynamicArgs CallbackInfo(CallbackInfo const &) = delete; void operator=(CallbackInfo const &) = delete; From d3b6cab2492ffdbf04f25de2394f9474fee1df1d Mon Sep 17 00:00:00 2001 From: Robert Gerdisch Date: Fri, 23 Jul 2021 11:16:45 -0700 Subject: [PATCH 5/9] Easier promise type fix --- Plugins/NativeCamera/Source/NativeCamera.cpp | 27 +++++++++----------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Plugins/NativeCamera/Source/NativeCamera.cpp b/Plugins/NativeCamera/Source/NativeCamera.cpp index 1c437463f..acc04906e 100644 --- a/Plugins/NativeCamera/Source/NativeCamera.cpp +++ b/Plugins/NativeCamera/Source/NativeCamera.cpp @@ -66,7 +66,18 @@ namespace Babylon // append media devices to navigator Napi::Object mediaDevices = Napi::Object::New(env); - mediaDevices.Set("getUserMedia", Napi::Function::New(env, &NativeCamera::GetUserMedia, "getUserMedia")); + mediaDevices.Set("getUserMedia", Napi::Function::New(env, [](const Napi::CallbackInfo& info) { + auto env = info.Env(); + auto deferred{Napi::Promise::Deferred::New(env)}; + auto promise{deferred.Promise()}; + + auto& jsRuntime{JsRuntime::GetFromJavaScript(env)}; + jsRuntime.Dispatch([deferred{std::move(deferred)}](Napi::Env env) { + deferred.Resolve(env.Null()); + }); + + return static_cast(promise); + })); navigator.Set("mediaDevices", mediaDevices); } @@ -109,20 +120,6 @@ namespace Babylon videoObject->UpdateTexture(texture->Handle); } - - static Napi::Value GetUserMedia(const Napi::CallbackInfo& info) - { - auto env = info.Env(); - auto deferred{Napi::Promise::Deferred::New(env)}; - auto promise{deferred.Promise()}; - - auto& jsRuntime{JsRuntime::GetFromJavaScript(env)}; - jsRuntime.Dispatch([deferred{std::move(deferred)}](Napi::Env env) { - deferred.Resolve(env.Null()); - }); - - return promise; - } }; Camera::Camera(std::shared_ptr impl) From 4fc8cfeab3c31e1d415758a6b55472dbebb9c931 Mon Sep 17 00:00:00 2001 From: Robert Gerdisch Date: Fri, 23 Jul 2021 11:20:56 -0700 Subject: [PATCH 6/9] Simpler NativeCamera function fix --- Plugins/NativeCamera/Source/NativeCamera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/NativeCamera/Source/NativeCamera.cpp b/Plugins/NativeCamera/Source/NativeCamera.cpp index acc04906e..f86a79cad 100644 --- a/Plugins/NativeCamera/Source/NativeCamera.cpp +++ b/Plugins/NativeCamera/Source/NativeCamera.cpp @@ -77,7 +77,7 @@ namespace Babylon }); return static_cast(promise); - })); + }, "getUserMedia")); navigator.Set("mediaDevices", mediaDevices); } From a809aebba7a3302c3c1933f6f14631a43ec201b7 Mon Sep 17 00:00:00 2001 From: Robert Gerdisch Date: Fri, 23 Jul 2021 12:09:32 -0700 Subject: [PATCH 7/9] Clean up all the napi imports --- Dependencies/napi/napi-jsi/CMakeLists.txt | 29 +- .../napi-jsi/include/napi/js_native_api.h | 419 --------------- .../include/napi/js_native_api_types.h | 149 ------ .../napi/napi-jsi/include/napi/napi.h | 37 +- Dependencies/napi/napi-jsi/source/jsi.cpp | 484 ------------------ 5 files changed, 48 insertions(+), 1070 deletions(-) delete mode 100644 Dependencies/napi/napi-jsi/include/napi/js_native_api.h delete mode 100644 Dependencies/napi/napi-jsi/include/napi/js_native_api_types.h delete mode 100644 Dependencies/napi/napi-jsi/source/jsi.cpp diff --git a/Dependencies/napi/napi-jsi/CMakeLists.txt b/Dependencies/napi/napi-jsi/CMakeLists.txt index 8b9c07145..71f3bbba0 100644 --- a/Dependencies/napi/napi-jsi/CMakeLists.txt +++ b/Dependencies/napi/napi-jsi/CMakeLists.txt @@ -2,10 +2,10 @@ set(SOURCES "include/napi/env.h" "include/napi/napi.h" "include/napi/napi-inl.h" - "include/napi/js_native_api_types.h" - "include/napi/js_native_api.h" "source/env.cc") +add_library(napi ${SOURCES}) + if(NOT TARGET jsi) if(WIN32) download_nuget() @@ -26,34 +26,31 @@ if(NOT TARGET jsi) set(V8JSI_DLL_PATH_DEBUG "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/Debug/${WIN32_ARCH}/v8jsi.dll") set(V8JSI_DLL_PATH_RELEASE "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/Release/${WIN32_ARCH}/v8jsi.dll") - add_library(jsi SHARED IMPORTED) - set_target_properties(jsi PROPERTIES + add_library(v8jsi SHARED IMPORTED) + set_target_properties(v8jsi PROPERTIES IMPORTED_IMPLIB_DEBUG ${V8JSI_LIB_PATH_DEBUG} IMPORTED_IMPLIB_RELEASE ${V8JSI_LIB_PATH_RELEASE} IMPORTED_IMPLIB_MINSIZEREL ${V8JSI_LIB_PATH_RELEASE} IMPORTED_IMPLIB_RELWITHDEBINFO ${V8JSI_LIB_PATH_RELEASE}) - target_include_directories(jsi INTERFACE "${V8JSI_PACKAGE_PATH}/build/native/include") - target_include_directories(jsi INTERFACE "${V8JSI_PACKAGE_PATH}/build/native/jsi") + target_include_directories(v8jsi INTERFACE "${V8JSI_PACKAGE_PATH}/build/native/include") + target_include_directories(v8jsi INTERFACE "${V8JSI_PACKAGE_PATH}/build/native/jsi") set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_DEBUG ${V8JSI_DLL_PATH_DEBUG} CACHE STRING "N-API runtime output artifacts (debug)") set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_RELEASE ${V8JSI_DLL_PATH_RELEASE} CACHE STRING "N-API runtime output artifacts (release)") set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS ${V8JSI_DLL_PATH} CACHE STRING "N-API runtime output artifacts") - target_compile_definitions(jsi INTERFACE V8JSI_ENABLE_INSPECTOR) + target_compile_definitions(v8jsi INTERFACE V8JSI_ENABLE_INSPECTOR) - set(SOURCES ${SOURCES} "source/jsi.cpp") + add_library(jsi "${V8JSI_PACKAGE_PATH}/build/native/jsi/jsi/jsi.cpp") + target_include_directories(jsi + PUBLIC "${V8JSI_PACKAGE_PATH}/build/native/include" + PUBLIC "${V8JSI_PACKAGE_PATH}/build/native/jsi") + target_link_libraries(jsi PUBLIC v8jsi) + set_property(TARGET jsi PROPERTY FOLDER Dependencies) else() message(FATAL_ERROR "jsi target is required") endif() endif() -add_library(napi ${SOURCES}) - -if (DEFINED V8JSI_PACKAGE_PATH) - target_include_directories(napi - PUBLIC "${V8JSI_PACKAGE_PATH}/build/native/include" - PUBLIC "${V8JSI_PACKAGE_PATH}/build/native/jsi") -endif() - target_include_directories(napi PUBLIC "include") diff --git a/Dependencies/napi/napi-jsi/include/napi/js_native_api.h b/Dependencies/napi/napi-jsi/include/napi/js_native_api.h deleted file mode 100644 index 885542e41..000000000 --- a/Dependencies/napi/napi-jsi/include/napi/js_native_api.h +++ /dev/null @@ -1,419 +0,0 @@ -#ifndef SRC_JS_NATIVE_API_H_ -#define SRC_JS_NATIVE_API_H_ - -// This file needs to be compatible with C compilers. -#include // NOLINT(modernize-deprecated-headers) -#include // NOLINT(modernize-deprecated-headers) - -// Use INT_MAX, this should only be consumed by the pre-processor anyway. -#define NAPI_VERSION_EXPERIMENTAL 2147483647 -#ifndef NAPI_VERSION -#ifdef NAPI_EXPERIMENTAL -#define NAPI_VERSION NAPI_VERSION_EXPERIMENTAL -#else -// The baseline version for N-API. -// The NAPI_VERSION controls which version will be used by default when -// compilling a native addon. If the addon developer specifically wants to use -// functions available in a new version of N-API that is not yet ported in all -// LTS versions, they can set NAPI_VERSION knowing that they have specifically -// depended on that version. -#define NAPI_VERSION 8 -#endif -#endif - -#include "js_native_api_types.h" - -// If you need __declspec(dllimport), either include instead, or -// define NAPI_EXTERN as __declspec(dllimport) on the compiler's command line. -#ifndef NAPI_EXTERN -#ifdef _WIN32 -#define NAPI_EXTERN __declspec(dllexport) -#elif defined(__wasm32__) -#define NAPI_EXTERN __attribute__((visibility("default"))) __attribute__((__import_module__("napi"))) -#else -#define NAPI_EXTERN __attribute__((visibility("default"))) -#endif -#endif - -#define NAPI_AUTO_LENGTH SIZE_MAX - -#ifdef __cplusplus -#define EXTERN_C_START extern "C" { -#define EXTERN_C_END } -#else -#define EXTERN_C_START -#define EXTERN_C_END -#endif - -EXTERN_C_START - -NAPI_EXTERN napi_status __cdecl napi_get_last_error_info(napi_env env, const napi_extended_error_info **result); - -// Getters for defined singletons -NAPI_EXTERN napi_status __cdecl napi_get_undefined(napi_env env, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_get_null(napi_env env, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_get_global(napi_env env, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_get_boolean(napi_env env, bool value, napi_value *result); - -// Methods to create Primitive types/Objects -NAPI_EXTERN napi_status __cdecl napi_create_object(napi_env env, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_array(napi_env env, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_array_with_length(napi_env env, size_t length, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_double(napi_env env, double value, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_int32(napi_env env, int32_t value, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_uint32(napi_env env, uint32_t value, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_int64(napi_env env, int64_t value, napi_value *result); -NAPI_EXTERN -napi_status __cdecl napi_create_string_latin1(napi_env env, const char *str, size_t length, napi_value *result); -NAPI_EXTERN -napi_status __cdecl napi_create_string_utf8(napi_env env, const char *str, size_t length, napi_value *result); -NAPI_EXTERN -napi_status __cdecl napi_create_string_utf16(napi_env env, const char16_t *str, size_t length, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_symbol(napi_env env, napi_value description, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_function( - napi_env env, - const char *utf8name, - size_t length, - napi_callback cb, - void *data, - napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_error(napi_env env, napi_value code, napi_value msg, napi_value *result); -NAPI_EXTERN -napi_status __cdecl napi_create_type_error(napi_env env, napi_value code, napi_value msg, napi_value *result); -NAPI_EXTERN -napi_status __cdecl napi_create_range_error(napi_env env, napi_value code, napi_value msg, napi_value *result); - -// Methods to get the native napi_value from Primitive type -NAPI_EXTERN napi_status __cdecl napi_typeof(napi_env env, napi_value value, napi_valuetype *result); -NAPI_EXTERN napi_status __cdecl napi_get_value_double(napi_env env, napi_value value, double *result); -NAPI_EXTERN napi_status __cdecl napi_get_value_int32(napi_env env, napi_value value, int32_t *result); -NAPI_EXTERN napi_status __cdecl napi_get_value_uint32(napi_env env, napi_value value, uint32_t *result); -NAPI_EXTERN napi_status __cdecl napi_get_value_int64(napi_env env, napi_value value, int64_t *result); -NAPI_EXTERN napi_status __cdecl napi_get_value_bool(napi_env env, napi_value value, bool *result); - -// Copies LATIN-1 encoded bytes from a string into a buffer. -NAPI_EXTERN napi_status __cdecl napi_get_value_string_latin1( - napi_env env, - napi_value value, - char *buf, - size_t bufsize, - size_t *result); - -// Copies UTF-8 encoded bytes from a string into a buffer. -NAPI_EXTERN napi_status __cdecl napi_get_value_string_utf8( - napi_env env, - napi_value value, - char *buf, - size_t bufsize, - size_t *result); - -// Copies UTF-16 encoded bytes from a string into a buffer. -NAPI_EXTERN napi_status __cdecl napi_get_value_string_utf16( - napi_env env, - napi_value value, - char16_t *buf, - size_t bufsize, - size_t *result); - -// Methods to coerce values -// These APIs may execute user scripts -NAPI_EXTERN napi_status __cdecl napi_coerce_to_bool(napi_env env, napi_value value, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_coerce_to_number(napi_env env, napi_value value, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_coerce_to_object(napi_env env, napi_value value, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_coerce_to_string(napi_env env, napi_value value, napi_value *result); - -// Methods to work with Objects -NAPI_EXTERN napi_status __cdecl napi_get_prototype(napi_env env, napi_value object, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_get_property_names(napi_env env, napi_value object, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_set_property(napi_env env, napi_value object, napi_value key, napi_value value); -NAPI_EXTERN napi_status __cdecl napi_has_property(napi_env env, napi_value object, napi_value key, bool *result); -NAPI_EXTERN napi_status __cdecl napi_get_property(napi_env env, napi_value object, napi_value key, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_delete_property(napi_env env, napi_value object, napi_value key, bool *result); -NAPI_EXTERN napi_status __cdecl napi_has_own_property(napi_env env, napi_value object, napi_value key, bool *result); -NAPI_EXTERN napi_status __cdecl napi_set_named_property( - napi_env env, - napi_value object, - const char *utf8name, - napi_value value); -NAPI_EXTERN -napi_status __cdecl napi_has_named_property(napi_env env, napi_value object, const char *utf8name, bool *result); -NAPI_EXTERN napi_status __cdecl napi_get_named_property( - napi_env env, - napi_value object, - const char *utf8name, - napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_set_element(napi_env env, napi_value object, uint32_t index, napi_value value); -NAPI_EXTERN napi_status __cdecl napi_has_element(napi_env env, napi_value object, uint32_t index, bool *result); -NAPI_EXTERN napi_status __cdecl napi_get_element(napi_env env, napi_value object, uint32_t index, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_delete_element(napi_env env, napi_value object, uint32_t index, bool *result); -NAPI_EXTERN napi_status __cdecl napi_define_properties( - napi_env env, - napi_value object, - size_t property_count, - const napi_property_descriptor *properties); - -// Methods to work with Arrays -NAPI_EXTERN napi_status __cdecl napi_is_array(napi_env env, napi_value value, bool *result); -NAPI_EXTERN napi_status __cdecl napi_get_array_length(napi_env env, napi_value value, uint32_t *result); - -// Methods to compare values -NAPI_EXTERN napi_status __cdecl napi_strict_equals(napi_env env, napi_value lhs, napi_value rhs, bool *result); - -// Methods to work with Functions -NAPI_EXTERN napi_status __cdecl napi_call_function( - napi_env env, - napi_value recv, - napi_value func, - size_t argc, - const napi_value *argv, - napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_new_instance( - napi_env env, - napi_value constructor, - size_t argc, - const napi_value *argv, - napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_instanceof(napi_env env, napi_value object, napi_value constructor, bool *result); - -// Methods to work with napi_callbacks - -// Gets all callback info in a single call. (Ugly, but faster.) -NAPI_EXTERN napi_status __cdecl napi_get_cb_info( - napi_env env, // [in] NAPI environment handle - napi_callback_info cbinfo, // [in] Opaque callback-info handle - size_t *argc, // [in-out] Specifies the size of the provided argv array - // and receives the actual count of args. - napi_value *argv, // [out] Array of values - napi_value *this_arg, // [out] Receives the JS 'this' arg for the call - void **data); // [out] Receives the data pointer for the callback. - -NAPI_EXTERN napi_status __cdecl napi_get_new_target(napi_env env, napi_callback_info cbinfo, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_define_class( - napi_env env, - const char *utf8name, - size_t length, - napi_callback constructor, - void *data, - size_t property_count, - const napi_property_descriptor *properties, - napi_value *result); - -// Methods to work with external data objects -NAPI_EXTERN napi_status __cdecl napi_wrap( - napi_env env, - napi_value js_object, - void *native_object, - napi_finalize finalize_cb, - void *finalize_hint, - napi_ref *result); -NAPI_EXTERN napi_status __cdecl napi_unwrap(napi_env env, napi_value js_object, void **result); -NAPI_EXTERN napi_status __cdecl napi_remove_wrap(napi_env env, napi_value js_object, void **result); -NAPI_EXTERN napi_status __cdecl napi_create_external( - napi_env env, - void *data, - napi_finalize finalize_cb, - void *finalize_hint, - napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_get_value_external(napi_env env, napi_value value, void **result); - -// Methods to control object lifespan - -// Set initial_refcount to 0 for a weak reference, >0 for a strong reference. -NAPI_EXTERN napi_status __cdecl napi_create_reference( - napi_env env, - napi_value value, - uint32_t initial_refcount, - napi_ref *result); - -// Deletes a reference. The referenced value is released, and may -// be GC'd unless there are other references to it. -NAPI_EXTERN napi_status __cdecl napi_delete_reference(napi_env env, napi_ref ref); - -// Increments the reference count, optionally returning the resulting count. -// After this call the reference will be a strong reference because its -// refcount is >0, and the referenced object is effectively "pinned". -// Calling this when the refcount is 0 and the object is unavailable -// results in an error. -NAPI_EXTERN napi_status __cdecl napi_reference_ref(napi_env env, napi_ref ref, uint32_t *result); - -// Decrements the reference count, optionally returning the resulting count. -// If the result is 0 the reference is now weak and the object may be GC'd -// at any time if there are no other references. Calling this when the -// refcount is already 0 results in an error. -NAPI_EXTERN napi_status __cdecl napi_reference_unref(napi_env env, napi_ref ref, uint32_t *result); - -// Attempts to get a referenced value. If the reference is weak, -// the value might no longer be available, in that case the call -// is still successful but the result is NULL. -NAPI_EXTERN napi_status __cdecl napi_get_reference_value(napi_env env, napi_ref ref, napi_value *result); - -NAPI_EXTERN napi_status __cdecl napi_open_handle_scope(napi_env env, napi_handle_scope *result); -NAPI_EXTERN napi_status __cdecl napi_close_handle_scope(napi_env env, napi_handle_scope scope); -NAPI_EXTERN napi_status __cdecl napi_open_escapable_handle_scope(napi_env env, napi_escapable_handle_scope *result); -NAPI_EXTERN napi_status __cdecl napi_close_escapable_handle_scope(napi_env env, napi_escapable_handle_scope scope); - -NAPI_EXTERN napi_status __cdecl napi_escape_handle( - napi_env env, - napi_escapable_handle_scope scope, - napi_value escapee, - napi_value *result); - -// Methods to support error handling -NAPI_EXTERN napi_status __cdecl napi_throw(napi_env env, napi_value error); -NAPI_EXTERN napi_status __cdecl napi_throw_error(napi_env env, const char *code, const char *msg); -NAPI_EXTERN napi_status __cdecl napi_throw_type_error(napi_env env, const char *code, const char *msg); -NAPI_EXTERN napi_status __cdecl napi_throw_range_error(napi_env env, const char *code, const char *msg); -NAPI_EXTERN napi_status __cdecl napi_is_error(napi_env env, napi_value value, bool *result); - -// Methods to support catching exceptions -NAPI_EXTERN napi_status __cdecl napi_is_exception_pending(napi_env env, bool *result); -NAPI_EXTERN napi_status __cdecl napi_get_and_clear_last_exception(napi_env env, napi_value *result); - -// Methods to work with array buffers and typed arrays -NAPI_EXTERN napi_status __cdecl napi_is_arraybuffer(napi_env env, napi_value value, bool *result); -NAPI_EXTERN -napi_status __cdecl napi_create_arraybuffer(napi_env env, size_t byte_length, void **data, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_external_arraybuffer( - napi_env env, - void *external_data, - size_t byte_length, - napi_finalize finalize_cb, - void *finalize_hint, - napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_get_arraybuffer_info( - napi_env env, - napi_value arraybuffer, - void **data, - size_t *byte_length); -NAPI_EXTERN napi_status __cdecl napi_is_typedarray(napi_env env, napi_value value, bool *result); -NAPI_EXTERN napi_status __cdecl napi_create_typedarray( - napi_env env, - napi_typedarray_type type, - size_t length, - napi_value arraybuffer, - size_t byte_offset, - napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_get_typedarray_info( - napi_env env, - napi_value typedarray, - napi_typedarray_type *type, - size_t *length, - void **data, - napi_value *arraybuffer, - size_t *byte_offset); - -NAPI_EXTERN napi_status __cdecl napi_create_dataview( - napi_env env, - size_t length, - napi_value arraybuffer, - size_t byte_offset, - napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_is_dataview(napi_env env, napi_value value, bool *result); -NAPI_EXTERN napi_status __cdecl napi_get_dataview_info( - napi_env env, - napi_value dataview, - size_t *bytelength, - void **data, - napi_value *arraybuffer, - size_t *byte_offset); - -// version management -NAPI_EXTERN napi_status __cdecl napi_get_version(napi_env env, uint32_t *result); - -// Promises -NAPI_EXTERN napi_status __cdecl napi_create_promise(napi_env env, napi_deferred *deferred, napi_value *promise); -NAPI_EXTERN napi_status __cdecl napi_resolve_deferred(napi_env env, napi_deferred deferred, napi_value resolution); -NAPI_EXTERN napi_status __cdecl napi_reject_deferred(napi_env env, napi_deferred deferred, napi_value rejection); -NAPI_EXTERN napi_status __cdecl napi_is_promise(napi_env env, napi_value value, bool *is_promise); - -// Running a script -NAPI_EXTERN napi_status __cdecl napi_run_script(napi_env env, napi_value script, napi_value *result); - -// Memory management -NAPI_EXTERN -napi_status __cdecl napi_adjust_external_memory(napi_env env, int64_t change_in_bytes, int64_t *adjusted_value); - -#if NAPI_VERSION >= 5 - -// Dates -NAPI_EXTERN napi_status __cdecl napi_create_date(napi_env env, double time, napi_value *result); - -NAPI_EXTERN napi_status __cdecl napi_is_date(napi_env env, napi_value value, bool *is_date); - -NAPI_EXTERN napi_status __cdecl napi_get_date_value(napi_env env, napi_value value, double *result); - -// Add finalizer for pointer -NAPI_EXTERN napi_status __cdecl napi_add_finalizer( - napi_env env, - napi_value js_object, - void *native_object, - napi_finalize finalize_cb, - void *finalize_hint, - napi_ref *result); - -#endif // NAPI_VERSION >= 5 - -#if NAPI_VERSION >= 6 - -// BigInt -NAPI_EXTERN napi_status __cdecl napi_create_bigint_int64(napi_env env, int64_t value, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_bigint_uint64(napi_env env, uint64_t value, napi_value *result); -NAPI_EXTERN napi_status __cdecl napi_create_bigint_words( - napi_env env, - int sign_bit, - size_t word_count, - const uint64_t *words, - napi_value *result); -NAPI_EXTERN -napi_status __cdecl napi_get_value_bigint_int64(napi_env env, napi_value value, int64_t *result, bool *lossless); -NAPI_EXTERN -napi_status __cdecl napi_get_value_bigint_uint64(napi_env env, napi_value value, uint64_t *result, bool *lossless); -NAPI_EXTERN napi_status __cdecl napi_get_value_bigint_words( - napi_env env, - napi_value value, - int *sign_bit, - size_t *word_count, - uint64_t *words); - -// Object -NAPI_EXTERN napi_status __cdecl napi_get_all_property_names( - napi_env env, - napi_value object, - napi_key_collection_mode key_mode, - napi_key_filter key_filter, - napi_key_conversion key_conversion, - napi_value *result); - -// Instance data -NAPI_EXTERN napi_status __cdecl napi_set_instance_data( - napi_env env, - void *data, - napi_finalize finalize_cb, - void *finalize_hint); - -NAPI_EXTERN napi_status __cdecl napi_get_instance_data(napi_env env, void **data); -#endif // NAPI_VERSION >= 6 - -#if NAPI_VERSION >= 7 -// ArrayBuffer detaching -NAPI_EXTERN napi_status __cdecl napi_detach_arraybuffer(napi_env env, napi_value arraybuffer); - -NAPI_EXTERN napi_status __cdecl napi_is_detached_arraybuffer(napi_env env, napi_value value, bool *result); -#endif // NAPI_VERSION >= 7 - -#if NAPI_VERSION >= 8 -// Type tagging -NAPI_EXTERN napi_status __cdecl napi_type_tag_object(napi_env env, napi_value value, const napi_type_tag *type_tag); - -NAPI_EXTERN napi_status __cdecl napi_check_object_type_tag( - napi_env env, - napi_value value, - const napi_type_tag *type_tag, - bool *result); -NAPI_EXTERN napi_status __cdecl napi_object_freeze(napi_env env, napi_value object); -NAPI_EXTERN napi_status __cdecl napi_object_seal(napi_env env, napi_value object); -#endif // NAPI_VERSION >= 8 - -EXTERN_C_END - -#endif // SRC_JS_NATIVE_API_H_ diff --git a/Dependencies/napi/napi-jsi/include/napi/js_native_api_types.h b/Dependencies/napi/napi-jsi/include/napi/js_native_api_types.h deleted file mode 100644 index 1d881c930..000000000 --- a/Dependencies/napi/napi-jsi/include/napi/js_native_api_types.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef SRC_JS_NATIVE_API_TYPES_H_ -#define SRC_JS_NATIVE_API_TYPES_H_ - -// This file needs to be compatible with C compilers. -// This is a public include file, and these includes have essentially -// became part of it's API. -#include // NOLINT(modernize-deprecated-headers) -#include // NOLINT(modernize-deprecated-headers) - -#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) -typedef uint16_t char16_t; -#endif - -// JSVM API types are all opaque pointers for ABI stability -// typedef undefined structs instead of void* for compile time type safety -typedef struct napi_env__ *napi_env; -typedef struct napi_value__ *napi_value; -typedef struct napi_ref__ *napi_ref; -typedef struct napi_handle_scope__ *napi_handle_scope; -typedef struct napi_escapable_handle_scope__ *napi_escapable_handle_scope; -typedef struct napi_callback_info__ *napi_callback_info; -typedef struct napi_deferred__ *napi_deferred; - -typedef enum { - napi_default = 0, - napi_writable = 1 << 0, - napi_enumerable = 1 << 1, - napi_configurable = 1 << 2, - - // Used with napi_define_class to distinguish static properties - // from instance properties. Ignored by napi_define_properties. - napi_static = 1 << 10, - -#if NAPI_VERSION >= 8 - // Default for class methods. - napi_default_method = napi_writable | napi_configurable, - - // Default for object properties, like in JS obj[prop]. - napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable, -#endif // NAPI_VERSION >= 8 -} napi_property_attributes; - -typedef enum { - // ES6 types (corresponds to typeof) - napi_undefined, - napi_null, - napi_boolean, - napi_number, - napi_string, - napi_symbol, - napi_object, - napi_function, - napi_external, - napi_bigint, -} napi_valuetype; - -typedef enum { - napi_int8_array, - napi_uint8_array, - napi_uint8_clamped_array, - napi_int16_array, - napi_uint16_array, - napi_int32_array, - napi_uint32_array, - napi_float32_array, - napi_float64_array, - napi_bigint64_array, - napi_biguint64_array, -} napi_typedarray_type; - -typedef enum { - napi_ok, - napi_invalid_arg, - napi_object_expected, - napi_string_expected, - napi_name_expected, - napi_function_expected, - napi_number_expected, - napi_boolean_expected, - napi_array_expected, - napi_generic_failure, - napi_pending_exception, - napi_cancelled, - napi_escape_called_twice, - napi_handle_scope_mismatch, - napi_callback_scope_mismatch, - napi_queue_full, - napi_closing, - napi_bigint_expected, - napi_date_expected, - napi_arraybuffer_expected, - napi_detachable_arraybuffer_expected, - napi_would_deadlock // unused -} napi_status; -// Note: when adding a new enum value to `napi_status`, please also update -// * `const int last_status` in the definition of `napi_get_last_error_info()' -// in file js_native_api_v8.cc. -// * `const char* error_messages[]` in file js_native_api_v8.cc with a brief -// message explaining the error. -// * the definition of `napi_status` in doc/api/n-api.md to reflect the newly -// added value(s). - -typedef napi_value (*napi_callback)(napi_env env, napi_callback_info info); -typedef void (*napi_finalize)(napi_env env, void *finalize_data, void *finalize_hint); - -typedef struct { - // One of utf8name or name should be NULL. - const char *utf8name; - napi_value name; - - napi_callback method; - napi_callback getter; - napi_callback setter; - napi_value value; - - napi_property_attributes attributes; - void *data; -} napi_property_descriptor; - -typedef struct { - const char *error_message; - void *engine_reserved; - uint32_t engine_error_code; - napi_status error_code; -} napi_extended_error_info; - -#if NAPI_VERSION >= 6 -typedef enum { napi_key_include_prototypes, napi_key_own_only } napi_key_collection_mode; - -typedef enum { - napi_key_all_properties = 0, - napi_key_writable = 1, - napi_key_enumerable = 1 << 1, - napi_key_configurable = 1 << 2, - napi_key_skip_strings = 1 << 3, - napi_key_skip_symbols = 1 << 4 -} napi_key_filter; - -typedef enum { napi_key_keep_numbers, napi_key_numbers_to_strings } napi_key_conversion; -#endif // NAPI_VERSION >= 6 - -#if NAPI_VERSION >= 8 -typedef struct { - uint64_t lower; - uint64_t upper; -} napi_type_tag; -#endif // NAPI_VERSION >= 8 - -#endif // SRC_JS_NATIVE_API_TYPES_H_ diff --git a/Dependencies/napi/napi-jsi/include/napi/napi.h b/Dependencies/napi/napi-jsi/include/napi/napi.h index ff21c73a2..c360077c6 100644 --- a/Dependencies/napi/napi-jsi/include/napi/napi.h +++ b/Dependencies/napi/napi-jsi/include/napi/napi.h @@ -1,7 +1,5 @@ #pragma once -#include "js_native_api.h" -#include "js_native_api_types.h" #include #include #include @@ -10,6 +8,41 @@ #include #include +// Copied from js_native_api_types.h +typedef enum { + napi_default = 0, + napi_writable = 1 << 0, + napi_enumerable = 1 << 1, + napi_configurable = 1 << 2, +} napi_property_attributes; + +typedef enum { + // ES6 types (corresponds to typeof) + napi_undefined, + napi_null, + napi_boolean, + napi_number, + napi_string, + napi_symbol, + napi_object, + napi_function, + napi_external, +} napi_valuetype; + +typedef enum { + napi_int8_array, + napi_uint8_array, + napi_uint8_clamped_array, + napi_int16_array, + napi_uint16_array, + napi_int32_array, + napi_uint32_array, + napi_float32_array, + napi_float64_array, + napi_bigint64_array, + napi_biguint64_array, +} napi_typedarray_type; + struct napi_env__ { napi_env__(facebook::jsi::Runtime& rt) : rt{rt} diff --git a/Dependencies/napi/napi-jsi/source/jsi.cpp b/Dependencies/napi/napi-jsi/source/jsi.cpp deleted file mode 100644 index e4a7e431f..000000000 --- a/Dependencies/napi/napi-jsi/source/jsi.cpp +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -#include -#include - -namespace facebook { -namespace jsi { - -namespace { - -// This is used for generating short exception strings. -std::string kindToString(const Value& v, Runtime* rt = nullptr) { - if (v.isUndefined()) { - return "undefined"; - } else if (v.isNull()) { - return "null"; - } else if (v.isBool()) { - return v.getBool() ? "true" : "false"; - } else if (v.isNumber()) { - return "a number"; - } else if (v.isString()) { - return "a string"; - } else { - assert(v.isObject() && "Expecting object."); - return rt != nullptr && v.getObject(*rt).isFunction(*rt) ? "a function" - : "an object"; - } -} - -// getPropertyAsFunction() will try to create a JSError. If the -// failure is in building a JSError, this will lead to infinite -// recursion. This function is used in place of getPropertyAsFunction -// when building JSError, to avoid that infinite recursion. -Value callGlobalFunction(Runtime& runtime, const char* name, const Value& arg) { - Value v = runtime.global().getProperty(runtime, name); - if (!v.isObject()) { - throw JSINativeException( - std::string("callGlobalFunction: JS global property '") + name + - "' is " + kindToString(v, &runtime) + ", expected a Function"); - } - Object o = v.getObject(runtime); - if (!o.isFunction(runtime)) { - throw JSINativeException( - std::string("callGlobalFunction: JS global property '") + name + - "' is a non-callable Object, expected a Function"); - } - Function f = std::move(o).getFunction(runtime); - return f.call(runtime, arg); -} - -} // namespace - -namespace detail { - -void throwJSError(Runtime& rt, const char* msg) { - throw JSError(rt, msg); -} - -} // namespace detail - -Buffer::~Buffer() = default; - -PreparedJavaScript::~PreparedJavaScript() = default; - -Value HostObject::get(Runtime&, const PropNameID&) { - return Value(); -} - -void HostObject::set(Runtime& rt, const PropNameID& name, const Value&) { - std::string msg("TypeError: Cannot assign to property '"); - msg += name.utf8(rt); - msg += "' on HostObject with default setter"; - throw JSError(rt, msg); -} - -HostObject::~HostObject() {} - -Runtime::~Runtime() {} - -Instrumentation& Runtime::instrumentation() { - class NoInstrumentation : public Instrumentation { - std::string getRecordedGCStats() override { - return ""; - } - - std::unordered_map getHeapInfo(bool) override { - return std::unordered_map{}; - } - - void collectGarbage() override {} - - void startTrackingHeapObjectStackTraces() override {} - void stopTrackingHeapObjectStackTraces() override {} - - void createSnapshotToFile(const std::string&) override { - throw JSINativeException( - "Default instrumentation cannot create a heap snapshot"); - } - - void createSnapshotToStream(std::ostream&) override { - throw JSINativeException( - "Default instrumentation cannot create a heap snapshot"); - } - - std::string flushAndDisableBridgeTrafficTrace() override { - std::abort(); - } - - void writeBasicBlockProfileTraceToFile(const std::string&) const override { - std::abort(); - } - - void dumpProfilerSymbolsToFile(const std::string&) const override { - std::abort(); - } - }; - - static NoInstrumentation sharedInstance; - return sharedInstance; -} - -Value Runtime::createValueFromJsonUtf8(const uint8_t* json, size_t length) { - Function parseJson = global() - .getPropertyAsObject(*this, "JSON") - .getPropertyAsFunction(*this, "parse"); - return parseJson.call(*this, String::createFromUtf8(*this, json, length)); -} - -Pointer& Pointer::operator=(Pointer&& other) { - if (ptr_) { - ptr_->invalidate(); - } - ptr_ = other.ptr_; - other.ptr_ = nullptr; - return *this; -} - -Object Object::getPropertyAsObject(Runtime& runtime, const char* name) const { - Value v = getProperty(runtime, name); - - if (!v.isObject()) { - throw JSError( - runtime, - std::string("getPropertyAsObject: property '") + name + "' is " + - kindToString(v, &runtime) + ", expected an Object"); - } - - return v.getObject(runtime); -} - -Function Object::getPropertyAsFunction(Runtime& runtime, const char* name) - const { - Object obj = getPropertyAsObject(runtime, name); - if (!obj.isFunction(runtime)) { - throw JSError( - runtime, - std::string("getPropertyAsFunction: property '") + name + "' is " + - kindToString(std::move(obj), &runtime) + ", expected a Function"); - }; - - return std::move(obj).getFunction(runtime); -} - -Array Object::asArray(Runtime& runtime) const& { - if (!isArray(runtime)) { - throw JSError( - runtime, - "Object is " + kindToString(Value(runtime, *this), &runtime) + - ", expected an array"); - } - return getArray(runtime); -} - -Array Object::asArray(Runtime& runtime) && { - if (!isArray(runtime)) { - throw JSError( - runtime, - "Object is " + kindToString(Value(runtime, *this), &runtime) + - ", expected an array"); - } - return std::move(*this).getArray(runtime); -} - -Function Object::asFunction(Runtime& runtime) const& { - if (!isFunction(runtime)) { - throw JSError( - runtime, - "Object is " + kindToString(Value(runtime, *this), &runtime) + - ", expected a function"); - } - return getFunction(runtime); -} - -Function Object::asFunction(Runtime& runtime) && { - if (!isFunction(runtime)) { - throw JSError( - runtime, - "Object is " + kindToString(Value(runtime, *this), &runtime) + - ", expected a function"); - } - return std::move(*this).getFunction(runtime); -} - -Value::Value(Value&& other) : Value(other.kind_) { - if (kind_ == BooleanKind) { - data_.boolean = other.data_.boolean; - } else if (kind_ == NumberKind) { - data_.number = other.data_.number; - } else if (kind_ >= PointerKind) { - new (&data_.pointer) Pointer(std::move(other.data_.pointer)); - } - // when the other's dtor runs, nothing will happen. - other.kind_ = UndefinedKind; -} - -Value::Value(Runtime& runtime, const Value& other) : Value(other.kind_) { - // data_ is uninitialized, so use placement new to create non-POD - // types in it. Any other kind of initialization will call a dtor - // first, which is incorrect. - if (kind_ == BooleanKind) { - data_.boolean = other.data_.boolean; - } else if (kind_ == NumberKind) { - data_.number = other.data_.number; - } else if (kind_ == SymbolKind) { - new (&data_.pointer) Pointer(runtime.cloneSymbol(other.data_.pointer.ptr_)); - } else if (kind_ == StringKind) { - new (&data_.pointer) Pointer(runtime.cloneString(other.data_.pointer.ptr_)); - } else if (kind_ >= ObjectKind) { - new (&data_.pointer) Pointer(runtime.cloneObject(other.data_.pointer.ptr_)); - } -} - -Value::~Value() { - if (kind_ >= PointerKind) { - data_.pointer.~Pointer(); - } -} - -bool Value::strictEquals(Runtime& runtime, const Value& a, const Value& b) { - if (a.kind_ != b.kind_) { - return false; - } - switch (a.kind_) { - case UndefinedKind: - case NullKind: - return true; - case BooleanKind: - return a.data_.boolean == b.data_.boolean; - case NumberKind: - return a.data_.number == b.data_.number; - case SymbolKind: - return runtime.strictEquals( - static_cast(a.data_.pointer), - static_cast(b.data_.pointer)); - case StringKind: - return runtime.strictEquals( - static_cast(a.data_.pointer), - static_cast(b.data_.pointer)); - case ObjectKind: - return runtime.strictEquals( - static_cast(a.data_.pointer), - static_cast(b.data_.pointer)); - } - return false; -} - -double Value::asNumber() const { - if (!isNumber()) { - throw JSINativeException( - "Value is " + kindToString(*this) + ", expected a number"); - } - - return getNumber(); -} - -Object Value::asObject(Runtime& rt) const& { - if (!isObject()) { - throw JSError( - rt, "Value is " + kindToString(*this, &rt) + ", expected an Object"); - } - - return getObject(rt); -} - -Object Value::asObject(Runtime& rt) && { - if (!isObject()) { - throw JSError( - rt, "Value is " + kindToString(*this, &rt) + ", expected an Object"); - } - auto ptr = data_.pointer.ptr_; - data_.pointer.ptr_ = nullptr; - return static_cast(ptr); -} - -Symbol Value::asSymbol(Runtime& rt) const& { - if (!isSymbol()) { - throw JSError( - rt, "Value is " + kindToString(*this, &rt) + ", expected a Symbol"); - } - - return getSymbol(rt); -} - -Symbol Value::asSymbol(Runtime& rt) && { - if (!isSymbol()) { - throw JSError( - rt, "Value is " + kindToString(*this, &rt) + ", expected a Symbol"); - } - - return std::move(*this).getSymbol(rt); -} - -String Value::asString(Runtime& rt) const& { - if (!isString()) { - throw JSError( - rt, "Value is " + kindToString(*this, &rt) + ", expected a String"); - } - - return getString(rt); -} - -String Value::asString(Runtime& rt) && { - if (!isString()) { - throw JSError( - rt, "Value is " + kindToString(*this, &rt) + ", expected a String"); - } - - return std::move(*this).getString(rt); -} - -String Value::toString(Runtime& runtime) const { - Function toString = runtime.global().getPropertyAsFunction(runtime, "String"); - return toString.call(runtime, *this).getString(runtime); -} - -Array Array::createWithElements( - Runtime& rt, - std::initializer_list elements) { - Array result(rt, elements.size()); - size_t index = 0; - for (const auto& element : elements) { - result.setValueAtIndex(rt, index++, element); - } - return result; -} - -std::vector HostObject::getPropertyNames(Runtime&) { - return {}; -} - -Runtime::ScopeState* Runtime::pushScope() { - return nullptr; -} - -void Runtime::popScope(ScopeState*) {} - -JSError::JSError(Runtime& rt, Value&& value) { - setValue(rt, std::move(value)); -} - -JSError::JSError(Runtime& rt, std::string msg) : message_(std::move(msg)) { - try { - setValue( - rt, - callGlobalFunction(rt, "Error", String::createFromUtf8(rt, message_))); - } catch (const std::exception& ex) { - message_ = std::string(ex.what()) + " (while raising " + message_ + ")"; - setValue(rt, String::createFromUtf8(rt, message_)); - } catch (...) { - setValue(rt, Value()); - } -} - -JSError::JSError(Runtime& rt, std::string msg, std::string stack) - : message_(std::move(msg)), stack_(std::move(stack)) { - try { - Object e(rt); - e.setProperty(rt, "message", String::createFromUtf8(rt, message_)); - e.setProperty(rt, "stack", String::createFromUtf8(rt, stack_)); - setValue(rt, std::move(e)); - } catch (const std::exception& ex) { - setValue(rt, String::createFromUtf8(rt, ex.what())); - } catch (...) { - setValue(rt, Value()); - } -} - -JSError::JSError(std::string what, Runtime& rt, Value&& value) - : JSIException(std::move(what)) { - setValue(rt, std::move(value)); -} - -void JSError::setValue(Runtime& rt, Value&& value) { - value_ = std::make_shared(std::move(value)); - - try { - if ((message_.empty() || stack_.empty()) && value_->isObject()) { - auto obj = value_->getObject(rt); - - if (message_.empty()) { - try { - Value message = obj.getProperty(rt, "message"); - if (!message.isUndefined() && !message.isString()) { - message = callGlobalFunction(rt, "String", message); - } - if (message.isString()) { - message_ = message.getString(rt).utf8(rt); - } else if (!message.isUndefined()) { - message_ = "String(e.message) is a " + kindToString(message, &rt); - } - } catch (const std::exception& ex) { - message_ = std::string("[Exception while creating message string: ") + - ex.what() + "]"; - } - } - - if (stack_.empty()) { - try { - Value stack = obj.getProperty(rt, "stack"); - if (!stack.isUndefined() && !stack.isString()) { - stack = callGlobalFunction(rt, "String", stack); - } - if (stack.isString()) { - stack_ = stack.getString(rt).utf8(rt); - } else if (!stack.isUndefined()) { - stack_ = "String(e.stack) is a " + kindToString(stack, &rt); - } - } catch (const std::exception& ex) { - message_ = std::string("[Exception while creating stack string: ") + - ex.what() + "]"; - } - } - } - - if (message_.empty()) { - try { - if (value_->isString()) { - message_ = value_->getString(rt).utf8(rt); - } else { - Value message = callGlobalFunction(rt, "String", *value_); - if (message.isString()) { - message_ = message.getString(rt).utf8(rt); - } else { - message_ = "String(e) is a " + kindToString(message, &rt); - } - } - } catch (const std::exception& ex) { - message_ = std::string("[Exception while creating message string: ") + - ex.what() + "]"; - } - } - - if (stack_.empty()) { - stack_ = "no stack"; - } - - if (what_.empty()) { - what_ = message_ + "\n\n" + stack_; - } - } catch (...) { - message_ = "[Exception caught creating message string]"; - stack_ = "[Exception caught creating stack string]"; - what_ = "[Exception caught getting value fields]"; - } -} - -JSIException::~JSIException() {} - -JSINativeException::~JSINativeException() {} - -JSError::~JSError() {} - -} // namespace jsi -} // namespace facebook From f901c78102fa650a70eb0d7ef1ed988f0d50197f Mon Sep 17 00:00:00 2001 From: Robert Gerdisch Date: Fri, 23 Jul 2021 12:16:21 -0700 Subject: [PATCH 8/9] Add link to source --- Dependencies/napi/napi-jsi/include/napi/napi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dependencies/napi/napi-jsi/include/napi/napi.h b/Dependencies/napi/napi-jsi/include/napi/napi.h index c360077c6..b2dd454a9 100644 --- a/Dependencies/napi/napi-jsi/include/napi/napi.h +++ b/Dependencies/napi/napi-jsi/include/napi/napi.h @@ -8,7 +8,7 @@ #include #include -// Copied from js_native_api_types.h +// Copied from js_native_api_types.h (https://git.io/J8aI5) typedef enum { napi_default = 0, napi_writable = 1 << 0, From 537e4bccfe9c1921115351c60da14551b272e6e2 Mon Sep 17 00:00:00 2001 From: Robert Gerdisch Date: Fri, 23 Jul 2021 15:45:15 -0700 Subject: [PATCH 9/9] Final PR feedback --- .../napi/napi-direct/include/napi/napi-inl.h | 31 ++++++++++--------- .../napi/napi-jsi/include/napi/napi.h | 5 +-- NOTICE.md | 28 +++++++++++++++++ 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/Dependencies/napi/napi-direct/include/napi/napi-inl.h b/Dependencies/napi/napi-direct/include/napi/napi-inl.h index 075f417c4..a5308334c 100644 --- a/Dependencies/napi/napi-direct/include/napi/napi-inl.h +++ b/Dependencies/napi/napi-direct/include/napi/napi-inl.h @@ -1781,22 +1781,25 @@ inline Value Function::Call(napi_value recv, const std::vector& args return Call(recv, args.size(), args.data()); } -inline Value Function::Call(napi_value recv, size_t argc, const Napi::Value* args) const { - napi_value stackArgs[6]; - std::vector heapArgs; - napi_value* argv; - if (argc <= std::size(stackArgs)) { - argv = stackArgs; - } else { - heapArgs.resize(argc); - argv = heapArgs.data(); - } +inline Value Function::Call(napi_value recv, + size_t argc, + const Value* args) const { + const size_t stackArgsCount = 6; + napi_value stackArgs[stackArgsCount]; + std::vector heapArgs; + napi_value* argv; + if (argc <= stackArgsCount) { + argv = stackArgs; + } else { + heapArgs.resize(argc); + argv = heapArgs.data(); + } - for (size_t i = 0; i < argc; ++i) { - argv[i] = args[i]; - } + for (size_t index = 0; index < argc; index++) { + argv[index] = static_cast(args[index]); + } - return Call(recv, argc, argv); + return Call(recv, argc, argv); } inline Value Function::Call(napi_value recv, size_t argc, const napi_value* args) const { diff --git a/Dependencies/napi/napi-jsi/include/napi/napi.h b/Dependencies/napi/napi-jsi/include/napi/napi.h index b2dd454a9..56dd9f5c6 100644 --- a/Dependencies/napi/napi-jsi/include/napi/napi.h +++ b/Dependencies/napi/napi-jsi/include/napi/napi.h @@ -39,8 +39,9 @@ typedef enum { napi_uint32_array, napi_float32_array, napi_float64_array, - napi_bigint64_array, - napi_biguint64_array, + // JSI doesn't support bigint. + // napi_bigint64_array, + // napi_biguint64_array, } napi_typedarray_type; struct napi_env__ { diff --git a/NOTICE.md b/NOTICE.md index 381274b81..5268fe886 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -2197,3 +2197,31 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` + +# V8JSI + +``` +React Native V8 JSI adapter + +Copyright (c) Microsoft Corporation. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` \ No newline at end of file