Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Add Node-API to Hermes #1377

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

vmoroz
Copy link
Contributor

@vmoroz vmoroz commented Apr 18, 2024

Summary

This is an initial implementation of Node-API for Hermes.
The code is taken from the hermes-windows repo.

Node-API is an ABI-safe that is originally implemented for Node.js addons, and then adopted by all major JS runtimes.

This is a draft PR. Before removing the draft status I would like to ask a few questons:

  • What must be the library that exposes the Node-API? In hermes-windows we expose it for the hermes.dll. It is the libhermes for Windows. In this repo libhermes is not a shared library.
  • Please advise on the source file names and their locations.
  • What must be file headers?
  • I am going to add the test files after figuring out what must be the library that exposes Node-API.

Test Plan

Unit tests for Node-API are to be added.

@facebook-github-bot facebook-github-bot added the CLA Signed Do not delete this pull request or issue due to inactivity. label Apr 18, 2024
@tmikov
Copy link
Contributor

tmikov commented Apr 18, 2024

Thanks for doing this @vmoroz!!!

@facebook-github-bot
Copy link
Contributor

@tmikov has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@shirakaba
Copy link

Thanks so much, @vmoroz! Really excited to play with this.

@NathanWalker
Copy link

Huge effort @vmoroz thank you ❤️

@neildhar
Copy link
Contributor

Hey @vmoroz, thanks for putting this together!

Two high level requests:

  1. Could you move all the new code into the node-api directory? It can produce a static library that we link into libhermes, but I think keeping the implementation of this API separate makes more sense (similar to how the hermes_abi implementation is separate).
  2. As a first step, could we just include the implementations of the actual NAPI APIs? That is, we should exclude the extensions for providing things like CDP integration and access to Hermes specific functionality. We want to support these things eventually, but we haven't decided on what the ABI boundary should look like.

@vmoroz
Copy link
Contributor Author

vmoroz commented Jun 14, 2024

Hey @vmoroz, thanks for putting this together!

Two high level requests:

  1. Could you move all the new code into the node-api directory? It can produce a static library that we link into libhermes, but I think keeping the implementation of this API separate makes more sense (similar to how the hermes_abi implementation is separate).
  2. As a first step, could we just include the implementations of the actual NAPI APIs? That is, we should exclude the extensions for providing things like CDP integration and access to Hermes specific functionality. We want to support these things eventually, but we haven't decided on what the ABI boundary should look like.

@neildhar , thank you for the feedback and suggestions!
Extracting the Node API related code into the node-api folder similar to the hermes_abi code makes perfect sense. I will do that.

@wcandillon
Copy link

wcandillon commented Jul 11, 2024

Is this the main place to follow work on this topic? Is there still some appetite to support NAPI in React Native?
We are eyeing at some node modules that we would love to use out of the box in React Native.

@shirakaba
Copy link

shirakaba commented Jul 11, 2024

I'm still very interested in it and have even submitted conference talk proposals on the topic so would love it to become a reality!

I have some native Node addons that I've written for Electron, and it's a shame that I can use them in React Native Windows (as it supports Node-API) yet can't use them in any other flavour of React Native currently.

Let me know if there's any way I could help!

@vmoroz
Copy link
Contributor Author

vmoroz commented Jul 11, 2024

Is this the main place to follow work on this topic? Is there still some appetite to support NAPI in React Native? We are eyeing at some node modules that we would love to use out of the box in React Native.

One of the Discord RN channels or a discussion topic in one of the Meta's or Microsoft's related repo could be a better place to discuss all the details, but we can start it here.

The goal of supporting Node-API for Hermes, V8, and RN was to provide the industry standard ABI-safe API. It should enable versioning support for modules, support for multiple programming languages, and reuse of native code written for Node.js.

I wonder what is your scenario in terms of tergeting platforms (Windows, Mac, Android, etc.) and if you own the code that uses Node-API? It may be not possible to reuse binary Node.js modules, but reusing the majority of the code and recompiling it for the RN is a more achievable scenario.

@wcandillon
Copy link

wcandillon commented Jul 11, 2024 via email

@vmoroz
Copy link
Contributor Author

vmoroz commented Jul 11, 2024

We are implementing WebGPU for React Native ( https://x.com/appjsconf/status/1806332497783058900) and right now we are virtually migrating a webgpu node module to JSI manually. So of course the thought or being able to use that node module directly is appealing to us.

This is awesome! In the video clip you say that you target first of all the mobile platforms: iOS and Android.
It means that you cannot use the precompiled binaries and targeting the Node-API is mostly the matter of the convenience of reusing the existing code. IMHO, it is an achievable goal and @shirakaba's team is already using the Hermes Node-API for their project. The only problem is that to use it we must modify the Hermes code to integrate with the jsi::Runtime.
This PR targets to eliminate this issue and to enable Node-API out of the main Hermes repo.

The current version of the Node-API for Hermes is in the hermes-windows repo: https://github.com/microsoft/hermes-windows/ . There we are starting to factor out the Node-API code into its own folder.

Yesterday we had a long informative face-to-face meeting with Hermes team.
The Hermes team seems to be still in the favor of supporting Node-API. There was an interesting discussion about the interoperability between Node-API and jsi::Runtine/AbiRuntime. There are a few issues to address there. Hopefully we can do it soon.

@tmikov
Copy link
Contributor

tmikov commented Jul 12, 2024

@wcandillon when you say that you are implementing WebGPU, do you literally mean the WebGPU spec, 1 to 1, with shader language, etc?

@wcandillon
Copy link

wcandillon commented Jul 12, 2024

We use Google Dawn for the native WebGPU implementation (Dawn is also a supported Skia backend), we code generate most of the bindings from its TS definition (which is itself generated from the W3C spec, we also match TS methods to C++ methods, Dawn provides a json model for that), and for the manual part of the work we just look at the node module and migrate it. This is why being able to use that node binding directly (which is already conformant to the official WebGPU testsuite) feels appealing.

@tmikov
Copy link
Contributor

tmikov commented Jul 12, 2024

May I emphatically object to using Discord channels, as they inherently make discussions exclusionary, unfriendly to different timezones, transient, difficult to search, and impossible to reference.

@SamuelScheit
Copy link

For anyone who wants to try out this PR with react-native use version 0.75.0-rc.5 (or newer).

@SamuelScheit
Copy link

I was able to link and run a react-native app with this hermes NodeAPI PR.

However after calling hermes_create_napi_env it fails with EXC_BAD_ACCESS and the following stacktrace:

hermes::CompactArray::Fixed<unsigned char>::get(char*, unsigned int) [inlined]
hermes::CompactArray::get(unsigned int) const [inlined]
hermes::CompactTable::isEmpty(unsigned int) const [inlined]
unsigned int hermes::vm::detail::IdentifierHashTable::lookupString<char>(llvh::ArrayRef<char>, unsigned int, bool) consthermes_node_api/lib/VM/detail/IdentifierHashTable.cpp:41
hermes::vm::SymbolID hermes::vm::IdentifierTable::registerLazyIdentifierImpl<char>(llvh::ArrayRef<char>, unsigned int)hermes_node_api/lib/VM/IdentifierTable.cpp:393
hermes::napi::NapiEnvironment::NapiEnvironment(hermes::vm::Runtime&, bool, std::__1::shared_ptr<facebook::jsi::PreparedScriptStore>, hermes::vm::RuntimeConfig const&)Users/user/Developer/respond/hermes/hermes_node_api/API/hermes/hermes_napi.cpp:3330
hermes::napi::NapiEnvironment::NapiEnvironment(hermes::vm::Runtime&, bool, std::__1::shared_ptr<facebook::jsi::PreparedScriptStore>, hermes::vm::RuntimeConfig const&) [inlined]
::hermes_create_napi_env(void *, napi_env *)

raw is a NULL pointer and therefore results in EXC_BAD_ACCESS

static uint32_t get(char *raw, uint32_t idx) {
return reinterpret_cast<T *>(raw)[idx];
}

uint32_t get(uint32_t idx) const {
assert(idx < size_);
switch (scale_) {
case UINT8:
return Fixed<uint8_t>::get(raw_, idx);

bool isEmpty(uint32_t idx) const {
return CompactArray::get(idx) == EMPTY;
}

if (table_.isEmpty(idx)) {

auto idx = hashTable_.lookupString(str, hash);

https://github.com/vmoroz/hermes-windows/blob/5d4656887af7397700006e1beec28dc9abd3333f/API/hermes/hermes_napi.cpp#L3327-L3331

so what I'm currently trying to figure out is: why is raw a null pointer and what is the source of this issue

Does anybody else tried to use the NAPI in an app and if yes were you successful or did you encounter errors?

@SamuelScheit
Copy link

After building hermes in debug mode I get a different error, however without any stacktrace:

libc++abi: terminating due to uncaught exception of type std::length_error: vector

and after retrying a few times a different error:

libc++abi: terminating due to uncaught exception of type std::bad_alloc

Does anyone know how I can get the stacktrace of these errors to find the cause??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Do not delete this pull request or issue due to inactivity.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants