Skip to content

Add N-API compliance tests - #116

Open
matthargett wants to merge 41 commits into
BabylonJS:mainfrom
rebeckerspecialties:napi-tests
Open

Add N-API compliance tests#116
matthargett wants to merge 41 commits into
BabylonJS:mainfrom
rebeckerspecialties:napi-tests

Conversation

@matthargett

@matthargettmatthargett commented Oct 12, 2025

Copy link
Copy Markdown

Pulled from @vmoroz 's awesome hermes-windows work that is being upstreamed into Hermes, this pull request runs his now-portable test suite here in JsRuntimeHost. It actually found one bug so far!

The bug was JSC-specific: our JavaScriptCore wrapper previously passed nullptr to JSObjectCallAsFunction when the receiver was undefined, so the VM forcibly substituted the global object even in strict mode. The new implementation always routes through Function.prototype.call, preserving the exact thisArg.

New tests run on macOS (JavaScriptCore) and the Android simulator (V8). On Android the app sandbox can't fork/exec, so the suite runs in-process and dlopen's each conformance addon as a standalone .node — which needs napi built as a shared library there. That shared-library change is up in isolation as #183: please merge #183 first, then this PR rebases and the duplicate drops out. We can wire the suite into CI in a separate PR unless you'd prefer otherwise.

Note:

  1. Right now, there is no good way to package up the test suite, this is something Vlad, myself, and other collaborators have been discussing with the broader NodeJS community. Feels a little gross to duplicate the files, but the collaborators I worked with on N-API stuff in 2026 have a pre-release repo of the portable conformance test suite that we can leverage in a separate PR.

  2. We now have a safety net for bumping NAPI_VERSION to 6 (and beyond) to drive parity and congruence with hermes-windows (and React Native [Windows] itself). Our (rbckr.co) app will need these expanded NAPI capabilities so that we can run the code currently running in web workers in our BabylonJS WebXR app in separate JS domains/worklets that communicate with the main BabylonJS thread.


Landing sequence

Inter-related N-API PRs; intended order (✅ done / ⏳ pending):

  1. Fix Windows/UWP CI build (MSVC C4875 + JSI include path) #185 — Fix Windows/UWP CI build (MSVC C4875 + JSI include path). Independent build/toolchain fix; lands first so CI is green under everything below. (fork twin build: fix pre-existing Windows/UWP CI build failures (MSVC C4875 + JSI include path) rebeckerspecialties/JsRuntimeHost#5 — 22/22 green)
  2. Build napi as a shared library on Android #183 — Build napi as a shared library on Android (so in-process addons resolve napi_*).
  3. Add N-API compliance tests #116 — N-API compliance tests (the Android addons resolve napi_* via the shared libnapi.so from the step above). ← this PR
  4. N-API v7 across runtimes (V8 / JSC / Chakra)N-API v7 across runtimes (V8 / JavaScriptCore / Chakra) #189 (draft) — fork CI twin N-API v7 across runtimes (V8 / JavaScriptCore / Chakra) rebeckerspecialties/JsRuntimeHost#4, 22/22 green.

Motivating RFCs: rebeckerspecialties#6 (jsc-android → maintained JSC) · rebeckerspecialties#7 (WebWorker via N-API → Factotum into BabylonNative).

@matthargettmatthargett changed the title Add N-API compliant testsAdd N-API compliance testsOct 12, 2025
CopilotAI review requested due to automatic review settings June 5, 2026 04:21

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR integrates the Node-API conformance test suite into the repo’s test infrastructure (including Android instrumentation), adds a NodeLite harness + native addon build plumbing, and fixes a shutdown/finalization edge case in the JavaScriptCore Node-API implementation.

Changes:

  • Add Node-API test harness (gtest) and bring in a large set of Node-API JS/native conformance tests + build files.
  • Wire Android unit test host to provide AssetManager + writable base dir for running Node-API tests in-process; add optional ASan wrapping and updated Android build settings.
  • Fix JavaScriptCore Node-API reference finalization during environment shutdown and adjust function-calling implementation.

Reviewed changes

Copilot reviewed 224 out of 226 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
Tests/UnitTests/Shared/Shared.hAdd Android-only hook to provide Node-API test environment (AssetManager + base dir).
Tests/UnitTests/Android/tools/wrap.shAdd wrapper script to preload ASan runtime and set ASAN_OPTIONS.
Tests/UnitTests/Android/gradle.propertiesAdd JVM --add-opens flags for Gradle daemon.
Tests/UnitTests/Android/app/src/main/cpp/JNI.cppInitialize globals using application context/assets; pass environment to Node-API harness; improve log visibility.
Tests/UnitTests/Android/app/src/main/cpp/CMakeLists.txtLink NodeLite + Node-API test sources into UnitTestsJNI; add include paths and libraries.
Tests/UnitTests/Android/app/src/androidTest/java/com/jsruntimehost/unittests/Main.javaPass application context into native test entrypoint.
Tests/UnitTests/Android/app/build.gradleAdd Node-API assets generation/manifest; optional ASan packaging/runtime push tasks; bump NDK.
Tests/NodeApi/test_main.hAdd Node-API gtest configuration API and base fixture.
Tests/NodeApi/test_basics.cppAdd basic NodeLite script execution smoke tests.
Tests/NodeApi/test/package.jsonAdd JS tooling package for transforming/packaging Node-API test JS dependencies.
Tests/NodeApi/test/js-native-api/test_typedarray/test.jsAdd typedarray JS conformance tests.
Tests/NodeApi/test/js-native-api/test_typedarray/binding.gypAdd gyp build for typedarray addon.
Tests/NodeApi/test/js-native-api/test_typedarray/CMakeLists.txtAdd CMake build for typedarray addon.
Tests/NodeApi/test/js-native-api/test_symbol/test_symbol.cAdd native symbol addon for JS tests.
Tests/NodeApi/test/js-native-api/test_symbol/test3.jsAdd JS symbol conformance test.
Tests/NodeApi/test/js-native-api/test_symbol/test2.jsAdd JS symbol conformance test.
Tests/NodeApi/test/js-native-api/test_symbol/test1.jsAdd JS symbol conformance test.
Tests/NodeApi/test/js-native-api/test_symbol/binding.gypAdd gyp build for symbol addon.
Tests/NodeApi/test/js-native-api/test_symbol/CMakeLists.txtAdd CMake build for symbol addon.
Tests/NodeApi/test/js-native-api/test_string/test_null.jsAdd NULL-arg JS tests for string APIs.
Tests/NodeApi/test/js-native-api/test_string/test_null.hAdd header for string NULL tests.
Tests/NodeApi/test/js-native-api/test_string/test_null.cAdd native bindings for string NULL-arg tests.
Tests/NodeApi/test/js-native-api/test_string/test.jsAdd JS string API conformance tests.
Tests/NodeApi/test/js-native-api/test_string/binding.gypAdd gyp build for string addon (incl. NAPI_VERSION define).
Tests/NodeApi/test/js-native-api/test_string/CMakeLists.txtAdd CMake build for string addon (incl. NAPI_VERSION define).
Tests/NodeApi/test/js-native-api/test_reference_double_free/test_wrap.jsAdd JS repro for remove_wrap + delete_reference ordering.
Tests/NodeApi/test/js-native-api/test_reference_double_free/test_reference_double_free.cAdd native addon validating no double-free when removing wraps/references.
Tests/NodeApi/test/js-native-api/test_reference_double_free/test.jsAdd JS test for reference double-free scenario.
Tests/NodeApi/test/js-native-api/test_reference_double_free/binding.gypAdd gyp build for reference_double_free addon.
Tests/NodeApi/test/js-native-api/test_reference_double_free/CMakeLists.txtAdd CMake build for reference_double_free addon.
Tests/NodeApi/test/js-native-api/test_reference/test_finalizer.jsAdd JS test for JS-calling finalizers with uncaught exception policy.
Tests/NodeApi/test/js-native-api/test_reference/test_finalizer.cAdd native addon for JS-calling external finalizer test.
Tests/NodeApi/test/js-native-api/test_reference/binding.gypAdd gyp build for reference/finalizer addons.
Tests/NodeApi/test/js-native-api/test_reference/CMakeLists.txtAdd CMake build for reference/finalizer addons (incl. NAPI_VERSION).
Tests/NodeApi/test/js-native-api/test_properties/test_properties.cAdd native addon to validate property definition semantics.
Tests/NodeApi/test/js-native-api/test_properties/test.jsAdd JS property conformance tests.
Tests/NodeApi/test/js-native-api/test_properties/binding.gypAdd gyp build for properties addon.
Tests/NodeApi/test/js-native-api/test_properties/CMakeLists.txtAdd CMake build for properties addon (incl. NAPI_VERSION).
Tests/NodeApi/test/js-native-api/test_promise/test_promise.cAdd native promise API addon.
Tests/NodeApi/test/js-native-api/test_promise/test.jsAdd JS promise conformance tests.
Tests/NodeApi/test/js-native-api/test_promise/binding.gypAdd gyp build for promise addon.
Tests/NodeApi/test/js-native-api/test_promise/CMakeLists.txtAdd CMake build for promise addon.
Tests/NodeApi/test/js-native-api/test_object/test_null.jsAdd JS NULL-arg tests for object APIs.
Tests/NodeApi/test/js-native-api/test_object/test_null.hAdd header for object NULL tests.
Tests/NodeApi/test/js-native-api/test_object/test_exceptions.jsAdd JS tests ensuring object APIs surface pending exceptions.
Tests/NodeApi/test/js-native-api/test_object/test_exceptions.cAdd native addon for object exception propagation tests.
Tests/NodeApi/test/js-native-api/test_object/binding.gypAdd gyp build for object/exceptions addons.
Tests/NodeApi/test/js-native-api/test_object/CMakeLists.txtAdd CMake build for object/exceptions addons.
Tests/NodeApi/test/js-native-api/test_number/test_number.cAdd native number API addon (and NULL variants).
Tests/NodeApi/test/js-native-api/test_number/test_null.jsAdd JS NULL-arg tests for number APIs.
Tests/NodeApi/test/js-native-api/test_number/test_null.hAdd header for number NULL tests.
Tests/NodeApi/test/js-native-api/test_number/test_null.cAdd native bindings for number NULL-arg tests.
Tests/NodeApi/test/js-native-api/test_number/test.jsAdd JS number conformance tests.
Tests/NodeApi/test/js-native-api/test_number/binding.gypAdd gyp build for number addon.
Tests/NodeApi/test/js-native-api/test_number/CMakeLists.txtAdd CMake build for number addon.
Tests/NodeApi/test/js-native-api/test_new_target/test_new_target.cAdd native addon for napi_get_new_target semantics.
Tests/NodeApi/test/js-native-api/test_new_target/test.jsAdd JS tests for new.target behavior.
Tests/NodeApi/test/js-native-api/test_new_target/binding.gypAdd gyp build for new_target addon.
Tests/NodeApi/test/js-native-api/test_new_target/CMakeLists.txtAdd CMake build for new_target addon.
Tests/NodeApi/test/js-native-api/test_instance_data/test_instance_data.cAdd native addon for instance data API tests.
Tests/NodeApi/test/js-native-api/test_instance_data/test.jsAdd JS tests for instance data behavior (child/worker).
Tests/NodeApi/test/js-native-api/test_instance_data/binding.gypAdd gyp build for instance_data addon.
Tests/NodeApi/test/js-native-api/test_instance_data/CMakeLists.txtAdd CMake build for instance_data addon.
Tests/NodeApi/test/js-native-api/test_handle_scope/test_handle_scope.cAdd native addon for handle scope APIs.
Tests/NodeApi/test/js-native-api/test_handle_scope/test.jsAdd JS tests for handle scopes.
Tests/NodeApi/test/js-native-api/test_handle_scope/binding.gypAdd gyp build for handle_scope addon.
Tests/NodeApi/test/js-native-api/test_handle_scope/CMakeLists.txtAdd CMake build for handle_scope addon.
Tests/NodeApi/test/js-native-api/test_general/testV8Instanceof.jsImport V8 instanceof unit test for parity coverage.
Tests/NodeApi/test/js-native-api/test_general/testNapiStatus.jsAdd JS test verifying napi_status cleanup.
Tests/NodeApi/test/js-native-api/test_general/testNapiRun.jsAdd JS napi_run_script test.
Tests/NodeApi/test/js-native-api/test_general/testInstanceOf.jsAdd JS instanceof parity tests.
Tests/NodeApi/test/js-native-api/test_general/testGlobals.jsAdd JS tests for undefined/null getters.
Tests/NodeApi/test/js-native-api/test_general/testFinalizer.jsAdd JS tests for finalizer-only wrapping and GC behavior.
Tests/NodeApi/test/js-native-api/test_general/testEnvCleanup.jsAdd JS child-process test validating env cleanup finalizers.
Tests/NodeApi/test/js-native-api/test_general/test.jsAdd general Node-API conformance tests.
Tests/NodeApi/test/js-native-api/test_general/binding.gypAdd gyp build for general addon.
Tests/NodeApi/test/js-native-api/test_general/CMakeLists.txtAdd CMake build for general addon.
Tests/NodeApi/test/js-native-api/test_function/test.jsAdd JS tests for function APIs (incl. NULL param checks).
Tests/NodeApi/test/js-native-api/test_function/binding.gypAdd gyp build for function addon.
Tests/NodeApi/test/js-native-api/test_function/CMakeLists.txtAdd CMake build for function addon.
Tests/NodeApi/test/js-native-api/test_finalizer/test_fatal_finalize.jsAdd JS test validating fatal finalize behavior.
Tests/NodeApi/test/js-native-api/test_finalizer/test.jsAdd JS tests for basic vs JS-calling finalizers.
Tests/NodeApi/test/js-native-api/test_finalizer/binding.gypAdd gyp build for finalizer addon (NAPI_EXPERIMENTAL).
Tests/NodeApi/test/js-native-api/test_finalizer/CMakeLists.txtAdd CMake build for finalizer addon (NAPI_EXPERIMENTAL).
Tests/NodeApi/test/js-native-api/test_exception/test_exception.cAdd native addon that throws during Init and tests exception plumbing.
Tests/NodeApi/test/js-native-api/test_exception/testFinalizerException.jsAdd JS test validating exception from finalizer path.
Tests/NodeApi/test/js-native-api/test_exception/test.jsAdd JS tests for exception capture/pass-through behavior.
Tests/NodeApi/test/js-native-api/test_exception/binding.gypAdd gyp build for exception addon.
Tests/NodeApi/test/js-native-api/test_exception/CMakeLists.txtAdd CMake build for exception addon.
Tests/NodeApi/test/js-native-api/test_error/test.jsAdd JS tests for error creation/throw APIs.
Tests/NodeApi/test/js-native-api/test_error/binding.gypAdd gyp build for error addon.
Tests/NodeApi/test/js-native-api/test_error/CMakeLists.txtAdd CMake build for error addon (incl. NAPI_VERSION).
Tests/NodeApi/test/js-native-api/test_date/test_date.cAdd native date API addon.
Tests/NodeApi/test/js-native-api/test_date/test.jsAdd JS tests for date APIs.
Tests/NodeApi/test/js-native-api/test_date/binding.gypAdd gyp build for date addon.
Tests/NodeApi/test/js-native-api/test_date/CMakeLists.txtAdd CMake build for date addon.
Tests/NodeApi/test/js-native-api/test_dataview/test_dataview.cAdd native DataView addon.
Tests/NodeApi/test/js-native-api/test_dataview/test.jsAdd JS tests for DataView APIs.
Tests/NodeApi/test/js-native-api/test_dataview/binding.gypAdd gyp build for dataview addon.
Tests/NodeApi/test/js-native-api/test_dataview/CMakeLists.txtAdd CMake build for dataview addon.
Tests/NodeApi/test/js-native-api/test_conversions/test_null.hAdd header for conversions NULL tests.
Tests/NodeApi/test/js-native-api/test_conversions/test_null.cAdd native bindings for conversion NULL-arg tests.
Tests/NodeApi/test/js-native-api/test_conversions/binding.gypAdd gyp build for conversions addon.
Tests/NodeApi/test/js-native-api/test_conversions/CMakeLists.txtAdd CMake build for conversions addon.
Tests/NodeApi/test/js-native-api/test_constructor/test_null.jsAdd JS NULL-arg tests for define_class/constructors.
Tests/NodeApi/test/js-native-api/test_constructor/test_null.hAdd header for constructor NULL tests.
Tests/NodeApi/test/js-native-api/test_constructor/test_null.cAdd native bindings for constructor NULL tests.
Tests/NodeApi/test/js-native-api/test_constructor/test2.jsAdd JS test for constructor name.
Tests/NodeApi/test/js-native-api/test_constructor/test.jsAdd JS conformance tests for constructor behavior.
Tests/NodeApi/test/js-native-api/test_constructor/binding.gypAdd gyp build for constructor addon.
Tests/NodeApi/test/js-native-api/test_constructor/CMakeLists.txtAdd CMake build for constructor addon.
Tests/NodeApi/test/js-native-api/test_cannot_run_js/test_cannot_run_js.cAdd addon validating napi_cannot_run_js/pending_exception semantics in finalizers.
Tests/NodeApi/test/js-native-api/test_cannot_run_js/test.jsAdd JS tests covering cannot_run_js behavior by NAPI_VERSION.
Tests/NodeApi/test/js-native-api/test_cannot_run_js/binding.gypAdd gyp build for cannot_run_js + pending_exception variants.
Tests/NodeApi/test/js-native-api/test_cannot_run_js/CMakeLists.txtAdd CMake build for cannot_run_js + pending_exception variants.
Tests/NodeApi/test/js-native-api/test_bigint/test.jsAdd JS bigint API conformance tests.
Tests/NodeApi/test/js-native-api/test_bigint/binding.gypAdd gyp build for bigint addon.
Tests/NodeApi/test/js-native-api/test_bigint/CMakeLists.txtAdd CMake build for bigint addon.
Tests/NodeApi/test/js-native-api/test_array/test.jsAdd JS array API conformance tests.
Tests/NodeApi/test/js-native-api/test_array/binding.gypAdd gyp build for array addon.
Tests/NodeApi/test/js-native-api/test_array/CMakeLists.txtAdd CMake build for array addon.
Tests/NodeApi/test/js-native-api/entry_point.hAdd shared Node-API module entrypoint macro usage.
Tests/NodeApi/test/js-native-api/common.hAdd shared Node-API test macros/utilities.
Tests/NodeApi/test/js-native-api/common-inl.hAdd shared inline helpers for capturing N-API statuses.
Tests/NodeApi/test/js-native-api/CMakeLists.txtAdd driver CMake to build selected native test dirs.
Tests/NodeApi/test/js-native-api/8_passing_wrapped/test.jsAdd JS test for passing wrapped objects.
Tests/NodeApi/test/js-native-api/8_passing_wrapped/myobject.hAdd native wrapped object class for test.
Tests/NodeApi/test/js-native-api/8_passing_wrapped/myobject.ccAdd implementation for wrapped object test class.
Tests/NodeApi/test/js-native-api/8_passing_wrapped/binding.gypAdd gyp build for passing_wrapped addon.
Tests/NodeApi/test/js-native-api/8_passing_wrapped/CMakeLists.txtAdd CMake build for passing_wrapped addon.
Tests/NodeApi/test/js-native-api/8_passing_wrapped/8_passing_wrapped.ccAdd addon exports for passing_wrapped test.
Tests/NodeApi/test/js-native-api/7_factory_wrap/test.jsAdd JS test for factory wrap GC behavior.
Tests/NodeApi/test/js-native-api/7_factory_wrap/myobject.hAdd wrapped object class for factory wrap test.
Tests/NodeApi/test/js-native-api/7_factory_wrap/myobject.ccAdd implementation for factory wrap wrapped class.
Tests/NodeApi/test/js-native-api/7_factory_wrap/binding.gypAdd gyp build for factory_wrap addon.
Tests/NodeApi/test/js-native-api/7_factory_wrap/CMakeLists.txtAdd CMake build for factory_wrap addon.
Tests/NodeApi/test/js-native-api/7_factory_wrap/7_factory_wrap.ccAdd addon exports for factory_wrap test.
Tests/NodeApi/test/js-native-api/6_object_wrap/test.jsAdd JS tests for object_wrap behavior.
Tests/NodeApi/test/js-native-api/6_object_wrap/test-object-wrap-ref.jsAdd JS test for object wrap dangling references.
Tests/NodeApi/test/js-native-api/6_object_wrap/test-basic-finalizer.jsAdd JS test for basic-finalizer synchronous finalization.
Tests/NodeApi/test/js-native-api/6_object_wrap/nested_wrap.jsAdd JS test for nested wrap finalization ordering.
Tests/NodeApi/test/js-native-api/6_object_wrap/nested_wrap.hAdd native nested wrap class for finalization tests.
Tests/NodeApi/test/js-native-api/6_object_wrap/nested_wrap.ccAdd implementation for nested wrap test class.
Tests/NodeApi/test/js-native-api/6_object_wrap/myobject.hAdd object wrap class header.
Tests/NodeApi/test/js-native-api/6_object_wrap/binding.gypAdd gyp builds for myobject variants + nested_wrap.
Tests/NodeApi/test/js-native-api/6_object_wrap/CMakeLists.txtAdd CMake builds for myobject variants + nested_wrap.
Tests/NodeApi/test/js-native-api/5_function_factory/test.jsAdd JS tests for function factory addon.
Tests/NodeApi/test/js-native-api/5_function_factory/binding.gypAdd gyp build for function_factory addon.
Tests/NodeApi/test/js-native-api/5_function_factory/CMakeLists.txtAdd CMake build for function_factory addon.
Tests/NodeApi/test/js-native-api/5_function_factory/5_function_factory.cAdd native addon for creating functions.
Tests/NodeApi/test/js-native-api/4_object_factory/test.jsAdd JS tests for object factory addon.
Tests/NodeApi/test/js-native-api/4_object_factory/binding.gypAdd gyp build for object_factory addon.
Tests/NodeApi/test/js-native-api/4_object_factory/CMakeLists.txtAdd CMake build for object_factory addon.
Tests/NodeApi/test/js-native-api/4_object_factory/4_object_factory.cAdd native addon creating objects with properties.
Tests/NodeApi/test/js-native-api/3_callbacks/test.jsAdd JS tests for callback invocation (recv handling).
Tests/NodeApi/test/js-native-api/3_callbacks/binding.gypAdd gyp build for callbacks addon.
Tests/NodeApi/test/js-native-api/3_callbacks/CMakeLists.txtAdd CMake build for callbacks addon.
Tests/NodeApi/test/js-native-api/3_callbacks/3_callbacks.cAdd native addon for callback invocation tests.
Tests/NodeApi/test/js-native-api/2_function_arguments/test.jsAdd JS test for function arguments addon.
Tests/NodeApi/test/js-native-api/2_function_arguments/binding.gypAdd gyp build for function_arguments addon.
Tests/NodeApi/test/js-native-api/2_function_arguments/CMakeLists.txtAdd CMake build for function_arguments addon.
Tests/NodeApi/test/js-native-api/2_function_arguments/2_function_arguments.cAdd native addon for argument parsing and addition.
Tests/NodeApi/test/js-native-api/.gitignoreIgnore build outputs for native addon directories.
Tests/NodeApi/test/common/index.jsAdd Node-style common utilities wrapper (mustCall/gcUntil/etc).
Tests/NodeApi/test/common/gc.jsAdd GC retry helper used by JS tests.
Tests/NodeApi/test/basics/throw_string.jsAdd basic JS script that throws string.
Tests/NodeApi/test/basics/mustnotcall_success.jsAdd mustNotCall success script.
Tests/NodeApi/test/basics/mustnotcall_failure.jsAdd mustNotCall failure script.
Tests/NodeApi/test/basics/mustcall_success.jsAdd mustCall success script.
Tests/NodeApi/test/basics/mustcall_failure.jsAdd mustCall failure script.
Tests/NodeApi/test/basics/hello.jsAdd hello world script.
Tests/NodeApi/test/basics/async_resolved.jsAdd async resolved script.
Tests/NodeApi/test/basics/async_rejected.jsAdd async rejected script.
Tests/NodeApi/test/babel.config.jsAdd Babel config for transforming tests for Hermes.
Tests/NodeApi/test/CMakeLists.txtAdd JS tooling install + Babel transform pipeline; optionally build native addons.
Tests/NodeApi/test/.clang-formatAdd clang-format for NodeApi test sources.
Tests/NodeApi/string_utils.hAdd string helper declarations for NodeApi harness.
Tests/NodeApi/string_utils.cppAdd string helper implementations (format/replace).
Tests/NodeApi/node_lite_windows.cppAdd Windows-specific NodeLite dynamic loading implementation.
Tests/NodeApi/node_lite_posix.cppAdd POSIX NodeLite dynamic loading implementation (incl. Android API special cases).
Tests/NodeApi/node_lite_android.cppAdd Android NodeLite dynamic loading via soname + nativeLibraryDir.
Tests/NodeApi/main.cppAdd gtest runner executable for Node-API tests using NodeLite.
Tests/NodeApi/js_runtime_api.cppAdd runtime abstraction helpers (run script, collect GC, env scope handling).
Tests/NodeApi/include/node_api_types.hAdd minimal Node-API types shim header for tests.
Tests/NodeApi/include/node_api.hAdd minimal Node-API NAPI_MODULE macros/header for native addons.
Tests/NodeApi/compat.hAdd compat span shim for older C++ toolsets.
Tests/NodeApi/child_process_android.cppAdd Android stub for child_process SpawnSync.
Tests/NodeApi/child_process.hAdd child process abstraction used by test harness.
Tests/NodeApi/.clang-formatAdd clang-format for NodeApi sources.
Tests/CMakeLists.txtAdd NodeApi subdirectory to the test build.
Core/Node-API/Source/js_native_api_javascriptcore.hTrack shutdown state on env to prevent ref finalization work during teardown.
Core/Node-API/Source/js_native_api_javascriptcore.ccGuard ref finalizer work during shutdown; rework napi_call_function implementation.
Core/Node-API/CMakeLists.txtSwitch Linux JSC discovery to find_library; make napi SHARED by default on Android (configurable).
Core/Node-API-JSI/Include/napi/napi.hReplace locally-copied N-API enums with official js_native_api_types.h include.
CMakeLists.txtEnsure AndroidExtensions is added on Android builds.
Files not reviewed (1)
  • Tests/package-lock.json: Language not supported
Comments suppressed due to low confidence (5)

Tests/NodeApi/test/common/index.js:1

  • Node’s built-in assert module does not export mustCall, mustCallAtLeast, or mustNotCall, and there is no standard "gc" module. As written, require('../common') will fail at runtime. Implement these helpers locally (as Node’s test common does) or import them from files you provide in this repo (e.g., ./must-call.js and ./gc.js), and keep gcUntil sourced from ./gc.js.
    Tests/NodeApi/test/package.json:1
  • The & backgrounds the tar command, so hasha can run before node_modules.tar is complete, producing an incorrect/unstable hash. Use a sequencing operator (e.g., &&) so hashing only occurs after the tarball is fully written.
    Tests/NodeApi/test/js-native-api/test_typedarray/test.js:1
  • This test block mixes buffer and externalResult: it creates a fresh buffer but asserts against externalResult (from an earlier call). If External() returns a new TypedArray instance, these assertions won’t be validating the detached object and can fail or miss regressions. Also, the console.log inside the RangeError assertion path adds noisy output to test runs and should be removed.
    Tests/NodeApi/test/js-native-api/test_typedarray/test.js:1
  • This test block mixes buffer and externalResult: it creates a fresh buffer but asserts against externalResult (from an earlier call). If External() returns a new TypedArray instance, these assertions won’t be validating the detached object and can fail or miss regressions. Also, the console.log inside the RangeError assertion path adds noisy output to test runs and should be removed.
    Tests/UnitTests/Android/app/build.gradle:1
  • eachFileRecurse traversal order is filesystem-dependent, which can make manifest.txt nondeterministic across machines/OSes and cause unnecessary rebuilds or hard-to-diff asset changes. Collect the relative paths into a list, sort it, then write the manifest deterministically.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadCore/Node-API/Source/js_native_api_javascriptcore.cc
Comment threadTests/NodeApi/child_process_android.cpp
Comment threadTests/NodeApi/node_lite_windows.cpp Outdated
matthargett added a commit to rebeckerspecialties/JsRuntimeHost that referenced this pull request Jun 5, 2026
…e, Windows error reporting)
- JSC napi_call_function: invoke through the canonical Function.prototype.call (captured once at env
init) rather than the target function's own, user-overridable "call" property -- so `func.call = ...`
cannot change native call behavior.
- child_process_android SpawnSync: return status 1 (was -1, which wrapped in the uint32_t status
field) for the unsupported path.
- node_lite_windows LoadFunction: format the narrow lib_path.string() with %s (path::c_str() is
wchar_t* on Windows -> UB) and report ::GetLastError() instead of errno for LoadLibraryA failures.
…ction when the receiver was undefined, so the VM forcibly substituted the global object even in strict mode. The new implementation always routes through Function.prototype.call, preserving the exact thisArg. This only affected JSC: Chakra already pushes recv onto the argv array before invoking JsCallFunction, and V8 hands the raw recv value to Function::Call. Neither engine coerces in strict mode, so no additional fixes were required.
…bug fix in strict mode was actually found by the suite! The failing behavior was exercised by Tests/NodeApi/test/js-native-api/3_callbacks/test.js. New cmake targets emit a node-lite binary and a NodeApiTests binary, all currently enabled tests for currently supported NAPI v5 pass on Mac. Next step is to enable them for running in Android simulator.
…x handles during instrumentation, causing crashes, and now route console output through the new NodeLiteRuntime::Callbacks. On Android we forward stdout/stderr to logcat via callbacks to work around this for now. Added Android-specific shims (node_lite_android.cpp, child_process_android.cpp) so native module loading uses dlopen and JS child_process.spawnSync safely reports “unsupported”. Extended the Node‑API harness to allow in-process execution: RunNodeLiteScript captures output, SetNodeApiTestEnvironment lets the JNI layer provide a base directory and asset manager, and the GTest registration path uses that configuration instead of shelling out to the node_lite executable
…-- a use-after-free. Will check sanitizers under Android next
Two build-restoration fixes (no behavior/impl or NAPI-version changes), needed
after rebasing onto upstream HEAD and building with the current Xcode/libc++:
- node_lite: NodeApi::CallFunction took std::span<napi_value> but is only ever
called with braced-init-lists ({a,b,c}). Newer libc++ correctly rejects
constructing a non-const std::span from an initializer_list (that ctor is
C++26). Switch the parameter to std::initializer_list<napi_value> (begin()
yields the const napi_value* napi_call_function wants).
- Tests/NodeApi: the POST_BUILD copy_directory of each .node runs as an Xcode
script phase BEFORE Xcode's implicit CodeSign phase signs the original, so the
copied addons that node_lite/NodeApiTests dlopen are unsigned on a clean build
and macOS refuses to load them. Ad-hoc sign the copies directly (APPLE only).
…mulator)
Build-restoration fixes for the Android in-process NodeApi harness after rebasing
onto upstream HEAD (no impl/NAPI-version changes). Each was a latent break in the
napi-tests Android integration, surfaced by a clean build on a current toolchain:
- CMakeLists.txt: drop the AndroidExtensions Globals.cpp 'patch' step. It file(COPY)'d
patches/AndroidExtensions/Globals.cpp, which was never committed in any ref (author's
local-only file). Upstream uses a newer AndroidExtensions pin and needs no patch.
- build.gradle: bump default ndkVersion 23.1.7779620 -> 28.2.13676358 (matches CI's
NDK_VERSION). NDK 23's libc++ can't compile googletest 1.17.0's <=> usage. Also map the
Android sanitizer flag JSR_ENABLE_ASAN -> ENABLE_SANITIZERS (the upstream option kept
during the rebase).
- Tests/NodeApi/CMakeLists.txt: use ${JsRuntimeHost_SOURCE_DIR} instead of
${CMAKE_SOURCE_DIR} for Core/Node-API include paths. On Android JsRuntimeHost is added
as a subdirectory of the app, so CMAKE_SOURCE_DIR was the app dir (headers not found);
the project-scoped var is correct in both standalone (macOS) and nested (Android) builds.
- Tests/NodeApi/CMakeLists.txt: allow the .node modules to link with unresolved napi_*
symbols on Android (-Wl,--unresolved-symbols=ignore-all), the ELF equivalent of Apple's
-undefined dynamic_lookup; they bind at dlopen time from the host (UnitTestsJNI).
- Shared.cpp: gate the Android NodeApi-harness block on NODE_API_AVAILABLE_NATIVE_TESTS
(defined only by UnitTestsJNI) so the standalone UnitTests target -- built but unused on
Android -- doesn't try to compile AndroidExtensions/NodeApi code it doesn't link.
The instrumented run aborted with 'use of deleted global reference': the harness fell
back to android::global::GetAppContext() (GetFilesDir -> GetObjectClass) whose JNI global
ref is not valid during the instrumented run. JNI.cpp now computes a writable base dir from
the still-valid instrumentation Context and passes it plus the native AAssetManager to
SetNodeApiTestEnvironment() before RunTests() -- the wiring the harness was designed for
(see e1fce6b) but which was never actually connected.
This removes the crash and lets ConfigureNodeApiTests run. NOTE: on-device execution of the
NodeApi conformance tests is still not achieved -- CopyAssetsRecursive relies on
AAssetManager subdirectory enumeration (AAssetDir_getNextFileName lists files only, not
dirs) so the nested test tree isn't copied, and the native .node modules are neither
packaged nor loadable from an app-writable dir on API 29+. Tracked as follow-up.
Before this, the instrumented run passed vacuously -- no NodeApi tests ran. Several
layered fixes get them executing on the emulator (macOS path unchanged: still 12/12):
#1 Asset enumeration: AAssetManager can't list subdirectories, so CopyAssetsRecursive
copied nothing. copyNodeApiTests now emits a file manifest (manifest.txt -- not a
dotfile, which aapt would drop) and Shared.cpp copies each listed file.
#2 Native module packaging/loading: build each addon as lib<name>.so on Android so AGP
packages it into lib/<abi>/ (nativeLibraryDir, the only dlopen-able location on API
29+); node_lite_android loads it by soname; ResolveModulePath resolves the (on-disk
absent) .node so LoadNativeModule runs.
V8 lifecycle (in-process node_lite shares the host's V8): reuse the host's already-
initialized V8 platform (fixes 'Wrong initialization order'); hold a Locker +
Isolate::Scope so multi-isolate access is locked (fixes 'Entering the V8 API without
proper locking').
KNOWN REMAINING (tracked): node_lite calls Node-API outside any napi callback during
NodeLiteRuntime::Initialize/script execution, which on V8 needs a live HandleScope +
current Context. v8::HandleScope/Context::Scope are stack-only (operator new is
private) so they can't be held across the holder; this needs a scope-wrapping rework
of node_lite's V8 entry points (or napi_open_handle_scope + context enter). Until then
the on-device native tests segfault in napi_create_object.
…eate_object segfault)
NodeApiEnvScope -> jsr_open_napi_env_scope was a no-op stub: it allocated a scope
struct but never entered the env's V8 isolate/context. On JSC that's fine (the env
carries its context explicitly), but on V8 node_lite then calls Node-API outside any
napi callback with no *current context*, so napi_create_object -> v8::Object::New(isolate)
segfaulted during NodeLiteRuntime::Initialize. Enter the env's context on open and exit
it on close (Android only). The in-process V8 runtime now initializes and runs tests.
… error
Step toward in-process error handling: ExitOnException was noexcept, but the in-process
runner installs a fatal handler that throws NodeLiteFatalError (rather than std::exit) so
the harness can turn a JS error into a ProcessResult. Throwing from the noexcept function
std::terminate'd the test process. Dropped noexcept so it propagates to RunNodeLiteScript.
(Partial: other noexcept teardown paths -- NodeApiHandleScope/NodeApiEnvScope dtors calling
NODE_LITE_CALL, and the env-holder dtor's onUnhandledError -> ExitWithJSError -- can still
throw during unwinding when a test errors. Full in-process error-path exception-safety is
the remaining Android item.)
NodeApiHandleScope/NodeApiEnvScope destructors used the throwing NODE_LITE_CALL, and the
JsRuntimeHostEnvHolder destructor's onUnhandledError can invoke the throwing in-process fatal
handler -- both std::terminate if they fire while a NodeLiteFatalError is unwinding. Make the
scope dtors ignore the close status and wrap onUnhandledError in try/catch.
Correct robustness fixes, but they do NOT yet resolve the remaining in-process failure: when a
test errors, a *second* NodeLiteFatalError is thrown during unwinding (double-exception ->
std::terminate). The escaping throw site isn't visible in the tombstone (stack already unwound)
and needs on-device lldb to pinpoint. macOS unaffected (12/12).
…winding
Don't re-throw NodeLiteFatalError from the in-process fatal handler when std::uncaught_exceptions()
> 0, to avoid a double-exception std::terminate. (Correct hardening, but the remaining in-process
abort is a *single* uncaught NodeLiteFatalError escaping RunNodeLiteScript's catch -- a scope-exit
destructor throw on a test that leaves a pending exception; needs on-device lldb to pinpoint.)
…(fixes terminate)
THE fix for the in-process abort. ExitWithJSError / ExitWithJSAssertError / ExitWithMessage
were declared noexcept. With the default fatal handler they call std::exit (never throw), but
the in-process runner installs a handler that *throws* NodeLiteFatalError (caught by
RunNodeLiteScript and turned into a ProcessResult). A throw crossing a noexcept boundary is an
immediate std::terminate -- so when any test errored (e.g. the expected-error basics tests
throw_string/mustcall_failure), the whole instrumented run aborted instead of reporting a
result. Removing noexcept lets the throw unwind to the catch. Confirmed on the emulator via a
temporary _Unwind_Backtrace probe (now removed): the throw stack was
HandleFatalError <- ExitWithMessage(noexcept!) <- ExitWithJSError <- RunTestScript <- RunNodeLiteScript.
Net effect: the in-process Android run no longer aborts; the js-native-api v5 tests (2-5) pass;
the remaining failures are the basics harness self-tests, run through the generic fixture rather
than the specialized test_basics.cpp path macOS uses. macOS unaffected (still 12/12).
… napi
The js-native-api conformance addons are dlopen'd in-process by the Android
harness and import napi_* from the host (libUnitTestsJNI.so). The host is
loaded RTLD_LOCAL by System.loadLibrary, and bionic's linker-namespace model
does not surface its statically-linked (but exported) napi_* symbols to a
dlopen'd module -- so the addon cannot bind them at load time. Post-hoc
RTLD_GLOBAL promotion of the host is a no-op on bionic (confirmed on device:
the module dlopen still returns NULL with the host re-opened RTLD_GLOBAL).
Making these tests runnable on Android requires building napi as a shared
library (libnapi.so) depended on by both the host and the addons -- a
packaging change affecting every Android consumer, deferred to a separate
change per the v5-suite-in-place scope. Until then, skip the in-process addon
tests on Android with a clear reason; macOS runs the full v5 addon suite
(12/12) as the reference.
This unblocks the Android suite: it now builds, the in-process harness runs
without aborting, and the suite passes (addon tests reported SKIPPED).
… in-process)
Dynamic .node loading is never shipped to the Play / Quest stores, and bionic won't resolve a
dlopen'd addon's napi_* imports against the System.loadLibrary-loaded host anyway (the addon carries
no DT_NEEDED for napi; RTLD_GLOBAL host promotion is a no-op on bionic). Rather than make napi a
shared library for every Android consumer (tracked separately, task #9), compile the conformance
addons directly into the host (UnitTestsJNI) and resolve them in-process.
To link several addons into one binary without symbol clashes:
- node_api.h: make NODE_API_MODULE_REGISTER_FUNCTION / _GET_API_VERSION_FUNCTION overridable.
- entry_point.h (JSR_NODE_API_STATIC_LINK): give Init internal linkage and emit a per-addon load-time
constructor that self-registers its uniquely-suffixed registrar/version functions with the host.
- The Android CMakeLists compiles each addon as an OBJECT library with per-module unique entry-point
names and links them into UnitTestsJNI.
- node_lite_android LoadFunction resolves entry points from the in-process static registry by module
name instead of dlopen+dlsym.
Removes the Android GTEST_SKIP. The 4 v5 js-native-api conformance tests now execute in-process and
PASS on Android (2_function_arguments, 3_callbacks, 4_object_factory, 5_function_factory). macOS is
unchanged (the desktop dynamic .node path uses the #else branches).
The conformance suite runs gtest in-process; its results (RUN/OK/FAILED and failure
file:line:message) went to stdout, which Android discards -- leaving only the JUnit "expected 0,
was 1" with no detail. Pump stdout/stderr to logcat (tag NodeApiTests) so test output and any
pre-crash native context are visible via `adb logcat -s NodeApiTests`.
…by static linking)
The conformance addons are statically linked into the in-process Android test host (f32130e), so the
standalone SHARED .so + -Wl,--unresolved-symbols=ignore-all + lib<name>.so naming that the old
dlopen-on-Android path needed are dead. add_node_api_module now early-returns on Android and is a
clean desktop-only MODULE .node helper. Also fixes a stale node_lite comment describing the
abandoned soname-dlopen path.
No functional change on desktop (MODULE .node, -undefined dynamic_lookup, POST_BUILD staging,
codesign all preserved); macOS still 12/12.
V8Platform::EnsureInitialized() became a no-op once we found the host AppRuntime already initializes
V8's process-global platform; the class and its unused init_flag_/platform_ members were left over
from the abandoned platform-init attempt. Fold the (still-important) "don't re-init the platform"
rationale into a comment at the isolate-creation site, and drop the dead class plus the now-unused
<mutex> / <libplatform> includes. No behavior change; Android still 4/4 js-native-api.
…d libnapi.so
Replaces the interim static-link-into-host approach with the dynamic .node model used by
nodejs/node-api-cts (add_node_api_cts_addon), so the Android suite and a future node-api-cts
migration share one addon model.
- Core/Node-API: build napi as a SHARED library (libnapi.so) on Android. It exports all 106 napi_*
(default visibility -- no global -fvisibility=hidden), and the host plus every addon depend on the
one libnapi.so via a real DT_NEEDED, so there is a single napi instance. Static elsewhere.
- The conformance addons are again standalone SHARED lib<name>.so (packaged into nativeLibraryDir),
now linking napi (DT_NEEDED libnapi.so) instead of -Wl,--unresolved-symbols=ignore-all.
- node_lite_android resolves entry points via dlopen(soname)+dlsym again; the addon's napi_* bind
from libnapi.so at load. Reverts the static-link infra (entry_point.h JSR_NODE_API_STATIC_LINK
branch, node_api.h overridable registrar macros, the host's per-addon OBJECT libraries).
Verified on device: lib2_function_arguments.so has DT_NEEDED [libnapi.so], its napi_* are imports,
libnapi.so exports the 106 napi_*, and all 4 v5 js-native-api tests pass in-process. macOS unchanged
(12/12; desktop keeps static napi + dlopen'd MODULE .node).
Replace the hand-rolled pipe+thread stdout pump (added while bringing up the in-process Node-API
harness) with android::StdoutLogger::Start()/Stop() from AndroidExtensions, which the rest of the
UnitTests host already uses. Same effect -- the in-process gtest output (incl. failure
file:line:message) is visible in logcat (tag StdoutLogger) -- with less bespoke code.
Verified on emulator: 8/8 UnitTests pass incl. 4/4 js_native_api, gtest output present in logcat.
Adds test_reference_double_free (js-native-api) to the enabled suite -- a real v5 reference/double-free
test, green on macOS (system JSC, including ASan) and Android (V8). Its test_wrap.js is quarantined via
a known-failing allow-list in test_main.cpp: JSC napi_remove_wrap on an unwrapped object returns
napi_invalid_arg (the consecutive remove_wrap+delete_reference path itself does not crash); tracked as a
separate JSC fix.
The rest of the reference/finalizer/wrap suite (test_reference, test_finalizer, 6_object_wrap) targets
newer Node-API -- node_api_symbol_for (v9), napi_get_instance_data (v6),
node_api_basic_env / node_api_post_finalizer (v9) -- and is documented for the staged NAPI_VERSION bump.
…e, Windows error reporting)
- JSC napi_call_function: invoke through the canonical Function.prototype.call (captured once at env
init) rather than the target function's own, user-overridable "call" property -- so `func.call = ...`
cannot change native call behavior.
- child_process_android SpawnSync: return status 1 (was -1, which wrapped in the uint32_t status
field) for the unsupported path.
- node_lite_windows LoadFunction: format the narrow lib_path.string() with %s (path::c_str() is
wchar_t* on Windows -> UB) and report ::GetLastError() instead of errno for LoadLibraryA failures.
An earlier commit in this branch deduplicated JSI's inlined napi type definitions by including the
shared <napi/js_native_api_types.h>. Upstream deliberately keeps Core/Node-API-JSI/Include/napi/napi.h
self-contained (it carries its own copy), and Core/Node-API-JSI is built *instead of* Core/Node-API
when the engine is JSI -- so the shared header is not on that target's include path and the JSI build
fails with C1083. Restore upstream's arrangement.
The harness picked the engine from the platform (__APPLE__ == JSC, __ANDROID__ == V8), which breaks any
non-default pairing: Android-JSC compiled the V8 path (#include <v8.h> -> not found) and Linux-V8 hit no
engine branch at all. Expose JSR_NAPI_ENGINE_<ENGINE> as a PUBLIC compile definition on the napi target
and branch on that instead. Fixes the Android_JSC + Ubuntu(V8) regressions; the #else is now a
compiling throw stub so Chakra/JSI builds still compile (they don't run node_lite in CI).
… at link
The .node addons referenced napi_* but never linked the napi library, so every Win32/UWP build failed
with unresolved external symbols (napi_create_function, napi_get_last_error_info, ...). MSVC binds DLL
imports at link time, so link napi directly (mirrors the Android branch). Fixes the pre-existing
Windows/UWP addon link failures.
node_lite and the js-native-api addons are written against the C napi_* API. Core/Node-API-JSI
implements only the C++ Napi:: wrapper over jsi (no C napi_* symbols), and its napi.h carries its own
copy of the napi types, which collides with the shared <napi/js_native_api_types.h> the harness
includes (C2365 redefinition in node_lite). Skip the harness for JSI.
…ootstrap)
This branch had replaced upstream's plain cached JAVASCRIPTCORE_LIBRARY path with find_library +
FATAL_ERROR. Upstream's Hermes support configures a *host* build of this same source tree to bootstrap
hermesc/shermes (-D NAPI_JAVASCRIPT_ENGINE=Hermes), and that configure runs the elseif(UNIX) branch on
CI runners that have no libwebkit2gtk installed -- so the fatal error aborts the bootstrap and
Android_Hermes fails. Restore upstream's non-fatal form; the engine isn't even JavaScriptCore there.
…d engines
The harness sources were compiled into UnitTestsJNI for every Android engine. Hermes supplies napi via
its own hermesNapi library, which does not export napi_create_external / napi_get_value_external, so
Android_Hermes failed to link; QuickJS has not been validated on-device. Gate the harness sources (and
the NODE_API_AVAILABLE_NATIVE_TESTS list that drives them) behind an engine allow-list of V8 and
JavaScriptCore, matching the desktop gating in Tests/NodeApi/CMakeLists.txt.
Hermes does not ship a js_native_api_hermes.cc -- its C napi_* functions live in the hermesNapi static
library. Building napi as a SHARED library therefore produces a libnapi.so that does not carry those
symbols, and everything linking it fails with undefined references (napi_wrap, napi_create_arraybuffer,
napi_create_external, ...). The shared-napi default exists so dlopen'd .node addons can resolve napi_*
at load; that harness is not built for Hermes, so keep napi static there.
matthargett added a commit to rebeckerspecialties/JsRuntimeHost that referenced this pull request Sep 1, 2026
…d at env init
Two independent problems in the same code, both about reaching JS intrinsics from
the C entry points.
1. Every BigInt entry point resolved its intrinsics on the live global object, once
per call: BigIntLow64 re-read `BigInt` and `BigInt.asIntN`/`asUintN`,
BigIntToString read `toString` off the boxed value (so through
BigInt.prototype), and the create path evaluated a `BigInt("...")` source
string. napi_detach_arraybuffer and napi_is_detached_arraybuffer did the same
with `transfer` and `detached`. All of those are reachable from script, so a
page could replace them and steer an addon's napi_*_bigint_* results -- the
invariant BabylonJS#116 established for napi_call_function with a cached
Function.prototype.call, not carried through to these.
Capture them once at env construction instead, before any user script can run:
the constructor, asIntN/asUintN, BigInt.prototype.toString, a `(v) => -v`
helper (StringToBigInt accepts a sign only on decimal literals, so the hex
words path cannot spell a negative value), ArrayBuffer.prototype.transfer, and
the `detached` getter out of its property descriptor. The create path now calls
the captured constructor rather than evaluating source, which also drops a
parse per BigInt created.
Capturing by property lookup doubles as the feature probe, replacing the eval
probe: on an engine without BigInt the lookups just fail. That matters because
a probe containing a `0n` literal is a SyntaxError -- not a false result -- on
jsc-android r250231.
NodeApi.BigIntIgnoresMonkeyPatchedIntrinsics covers this. Verified it fails
against the old lookup (returns the patched 1234, lossless false) and passes
with the fix, on both the C API and the fallback path.
2. The BigInt C API guards were wrong on two axes, verified by compiling against
each SDK rather than reading the annotations:
* `#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && >= 150000` is false on every
non-macOS Apple SDK, so the whole fast path was compiled out of iOS and
visionOS builds -- including iOS 18.3 and visionOS 26.1, where the API is
available. visionOS additionally reports __IPHONE_OS_VERSION_MAX_ALLOWED as
17.0, so it needs a clause of its own.
* `__builtin_available(macOS 15.0, *)` does not guard iOS or visionOS at all:
the `*` asserts availability on unlisted platforms. Had the `#if` been
"fixed" without this, an iOS 17 deployment would have called a null weak
symbol. clang confirms it -- the call still warns as unguarded under that
form at iOS 17 / visionOS 1.
Both are replaced by one JSR_JSC_HAS_BIGINT_C_API macro pair naming every
platform. Compiles clean and takes the intended path at macOS 13/15,
iOS 17/18.3, visionOS 1/26.1 and tvOS 18.
Also makes deinit_symbol null-safe: the intrinsics are null on an engine without
BigInt, and it unprotected unconditionally.
Verified: macOS JavaScriptCore 13/13 UnitTests and 15/16 conformance (1 quarantined),
on both the C API path and with it forced off; Android arm64 JavaScriptCore and V8
21 tests / 19 passed / 2 intentional skips each.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@matthargett