diff --git a/doc/contributing/adding-v8-fast-api.md b/doc/contributing/adding-v8-fast-api.md index 1869c12731f7f3..e26bc841121e66 100644 --- a/doc/contributing/adding-v8-fast-api.md +++ b/doc/contributing/adding-v8-fast-api.md @@ -26,15 +26,8 @@ for example, they may not trigger garbage collection. in a snapshot (either the built-in or a user-land one). Please refer to the [binding functions documentation](../../src/README.md#binding-functions) for more information. -* To test fast APIs, make sure to run the tests in a loop with a decent - iterations count to trigger relevant optimizations that prefer the fast API - over the slow one. -* In debug mode (`--debug` or `--debug-node` flags), the fast API calls can be - tracked using the `TRACK_V8_FAST_API_CALL("key")` macro. This can be used to - count how many times fast paths are taken during tests. The key is a global - identifier and should be unique across the codebase. - Use `"binding_name.function_name"` or `"binding_name.function_name.suffix"` to - ensure uniqueness. +* Fast API functions must be tested following the example in + [Test with Fast API path](#test-with-fast-api-path). * The fast callback must be idempotent up to the point where error and fallback conditions are checked, because otherwise executing the slow callback might produce visible side effects twice. @@ -175,40 +168,47 @@ A typical function that communicates between JavaScript and C++ is as follows. v8::FastApiCallbackOptions& options); ``` -* In the unit tests: - - Since the fast API function uses `TRACK_V8_FAST_API_CALL`, we can ensure that - the fast paths are taken and test them by writing tests that force - V8 optimizations and check the counters. - - ```js - // Flags: --expose-internals --no-warnings --allow-natives-syntax - 'use strict'; - const common = require('../common'); - - const { internalBinding } = require('internal/test/binding'); - // We could also require a function that uses the internal binding internally. - const { divide } = internalBinding('custom_namespace'); - - // The function that will be optimized. It has to be a function written in - // JavaScript. Since `divide` comes from the C++ side, we need to wrap it. - function testFastPath(a, b) { - return divide(a, b); - } - - eval('%PrepareFunctionForOptimization(testFastPath)'); - // This call will let V8 know about the argument types that the function expects. - assert.strictEqual(testFastPath(6, 3), 2); - - eval('%OptimizeFunctionOnNextCall(testFastPath)'); - assert.strictEqual(testFastPath(8, 2), 4); - assert.throws(() => testFastPath(1, 0), { - code: 'ERR_INVALID_STATE', - }); - - if (common.isDebug) { - const { getV8FastApiCallCount } = internalBinding('debug'); - assert.strictEqual(getV8FastApiCallCount('custom_namespace.divide.ok'), 1); - assert.strictEqual(getV8FastApiCallCount('custom_namespace.divide.error'), 1); - } - ``` +### Test with Fast API path + +In debug mode (`./configure --debug` or `./configure --debug-node` flags), the +fast API calls can be tracked using the `TRACK_V8_FAST_API_CALL("key")` macro. +This can be used to count how many times fast paths are taken during tests. The +key is a global identifier and should be unique across the codebase. +Use `"binding_name.function_name"` or `"binding_name.function_name.suffix"` to +ensure uniqueness. + +In the unit tests, since the fast API function uses `TRACK_V8_FAST_API_CALL`, +we can ensure that the fast paths are taken and test them by writing tests that +force V8 optimizations and check the counters. + +```js +// Flags: --expose-internals --no-warnings --allow-natives-syntax +'use strict'; +const common = require('../common'); + +const { internalBinding } = require('internal/test/binding'); +// We could also require a function that uses the internal binding internally. +const { divide } = internalBinding('custom_namespace'); + +// The function that will be optimized. It has to be a function written in +// JavaScript. Since `divide` comes from the C++ side, we need to wrap it. +function testFastPath(a, b) { + return divide(a, b); +} + +eval('%PrepareFunctionForOptimization(testFastPath)'); +// This call will let V8 know about the argument types that the function expects. +assert.strictEqual(testFastPath(6, 3), 2); + +eval('%OptimizeFunctionOnNextCall(testFastPath)'); +assert.strictEqual(testFastPath(8, 2), 4); +assert.throws(() => testFastPath(1, 0), { + code: 'ERR_INVALID_STATE', +}); + +if (common.isDebug) { + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('custom_namespace.divide.ok'), 1); + assert.strictEqual(getV8FastApiCallCount('custom_namespace.divide.error'), 1); +} +```