Skip to content

Commit

Permalink
doc: add v8 fast api contribution guidelines
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Jan 13, 2023
1 parent f5dc92c commit 5a5669f
Showing 1 changed file with 120 additions and 0 deletions.
120 changes: 120 additions & 0 deletions doc/contributing/adding-v8-fast-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# 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` file.

## Requirements
- Each unique fast path function signature should be defined inside
`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` 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<Value>& 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<Object> target, Local<Value> unused, Local<Context> 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`)
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);
```

0 comments on commit 5a5669f

Please sign in to comment.