-
Notifications
You must be signed in to change notification settings - Fork 29.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
doc: add v8 fast api contribution guidelines
- Loading branch information
Showing
1 changed file
with
128 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<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`](/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); | ||
``` |