From 177f200151b95f8ea60204572e90d8bef5c0bc84 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Fri, 13 Jan 2023 09:03:49 -0500 Subject: [PATCH] doc: add v8 fast api contribution guidelines --- doc/contributing/adding-v8-fast-api.md | 128 +++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 doc/contributing/adding-v8-fast-api.md diff --git a/doc/contributing/adding-v8-fast-api.md b/doc/contributing/adding-v8-fast-api.md new file mode 100644 index 00000000000000..a5b195767b10fd --- /dev/null +++ b/doc/contributing/adding-v8-fast-api.md @@ -0,0 +1,128 @@ +# Adding V8 Fast API + +Node.js uses [V8](https://github.com/v8/v8) as the JavaScript engine. +In order to provide fast paths for functions that are called quite often, +V8 proposes the usage of `fast api calls` that does not use any of the V8 +internals, but uses internal C functions. + +## Limitations + +* Fast api calls can not use `V8` internals inside the fast path. +* Not all parameter and return types are supported in fast api calls. + For a full list, please look into +* [`v8-fast-api-calls.h`](/deps/v8/include/v8-fast-api-calls.h) file. + +## Requirements + +* Each unique fast path function signature should be defined inside + [`node_external_reference.h`](/src/node_external_reference.h) file. +* In order to test fast paths, make sure to run the tests in a loop + with more than 1000 iterations to force V8 to optimize and prefer the + fast api over slow path. + +## Fallback to slow path + +Fast apis support fallback to slow path (implementation that uses V8 internals) +in case logically it is wise to do so, for example when providing a more +detailed error. Fallback mechanism can be enabled, and changed from both caller +JavaScript function or from the fast api function declaration. + +Every fast api function accessible from JavaScript side, can pass an object +consisting of fallback key, with a boolean value as the last parameter +(or the first parameter, if no parameters of the function exist). + +In V8 the options fallback is defined as `FastApiCallbackOptions` inside +[`v8-fast-api-calls.h`](/deps/v8/include/v8-fast-api-calls.h) file. + +* JavaScript land + +Example of a JavaScript: + +```javascript +// Let calculateX be a function that provides fast api calls. +const { calculateX } = internalBinding('custom_namespace'); + +function conditionallyGetX(useSlowPath) { + return calculateX({ fallback: useSlowPath }) +} +``` + +* C++ land + +Example of a conditional fast path on C++ + +```c++ +// Anywhere in the execution flow, you can set fallback and stop the execution. +static void FastCalculateX(const v8::FastApiCallbackOptions& options) { + if (true) { + options.fallback = true; + } +} +``` + +## Example + +A typical function that communicates between JavaScript and C++ is as follows. + +* On the JavaScript side: + +```javascript +const { calculateX } = internalBinding('custom_namespace'); +``` + +* On the C++ side: + +```c++ +namespace node { +namespace custom_namespace { + +#define PREFER_FALLBACK = false; + +static void CalculateX(const FunctionCallbackInfo& args) { + int calculated_x = 5; + args.GetReturnValue().Set(calculated_x); +} + +static int FastCalculateX(const v8::FastApiCallbackOptions& options) { + if (PREFER_FALLBACK) { + options.fallback = true; + return; + } + return 5; +} + +CFunction fast_calculate_x_(CFunction::Make(FastCalculateX)); + +static void Initialize(Local target, + Local unused, + Local context, + void* priv) { + SetFastMethod(context, target, "calculateX", CalculateX, &calculate_x_); +} + +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(CalculateX); + registry->Register(FastCalculateX); + registry->Register(fast_calculate_x_.GetTypeInfo()); +} + +} // namespace custom_namespace +} // namespace node + +NODE_BINDING_CONTEXT_AWARE_INTERNAL(custom_namespace, + node::custom_namespace::Initialize); +NODE_BINDING_EXTERNAL_REFERENCE( + custom_namespace, + node::custom_namespace::RegisterExternalReferences); +``` + +* Update external references ([`node_external_reference.h`](/src/node_external_reference.h)) + +Since our implementation used `int(const v8::FastApiCallbackOptions& options)` signature, +we need to add it to external references. + +Example declaration: + +```c++ +using CFunctionCallbackReturningInt = int (*)(const v8::FastApiCallbackOptions& options); +```