| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 6f81b27 commit 4ffa756
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -26,15 +26,8 @@ for example, they may not trigger garbage collection. | |||
| 26 | 26 | in a snapshot (either the built-in or a user-land one). Please refer to the | |
| 27 | 27 | [binding functions documentation](../../src/README.md#binding-functions) for more | |
| 28 | 28 | information. | |
| 29 | - * To test fast APIs, make sure to run the tests in a loop with a decent | ||
| 30 | - iterations count to trigger relevant optimizations that prefer the fast API | ||
| 31 | - over the slow one. | ||
| 32 | - * In debug mode (`--debug` or `--debug-node` flags), the fast API calls can be | ||
| 33 | - tracked using the `TRACK_V8_FAST_API_CALL("key")` macro. This can be used to | ||
| 34 | - count how many times fast paths are taken during tests. The key is a global | ||
| 35 | - identifier and should be unique across the codebase. | ||
| 36 | - Use `"binding_name.function_name"` or `"binding_name.function_name.suffix"` to | ||
| 37 | - ensure uniqueness. | ||
| 29 | + * Fast API functions must be tested following the example in | ||
| 30 | + [Test with Fast API path](#test-with-fast-api-path). | ||
| 38 | 31 | * The fast callback must be idempotent up to the point where error and fallback | |
| 39 | 32 | conditions are checked, because otherwise executing the slow callback might | |
| 40 | 33 | produce visible side effects twice. | |
@@ -175,40 +168,47 @@ A typical function that communicates between JavaScript and C++ is as follows. | |||
| 175 | 168 | v8::FastApiCallbackOptions& options); | |
| 176 | 169 | ``` | |
| 177 | 170 | ||
| 178 | - * In the unit tests: | ||
| 179 | - | ||
| 180 | - Since the fast API function uses `TRACK_V8_FAST_API_CALL`, we can ensure that | ||
| 181 | - the fast paths are taken and test them by writing tests that force | ||
| 182 | - V8 optimizations and check the counters. | ||
| 183 | - | ||
| 184 | - ```js | ||
| 185 | - // Flags: --expose-internals --no-warnings --allow-natives-syntax | ||
| 186 | - 'use strict'; | ||
| 187 | - const common = require('../common'); | ||
| 188 | - | ||
| 189 | - const { internalBinding } = require('internal/test/binding'); | ||
| 190 | - // We could also require a function that uses the internal binding internally. | ||
| 191 | - const { divide } = internalBinding('custom_namespace'); | ||
| 192 | - | ||
| 193 | - // The function that will be optimized. It has to be a function written in | ||
| 194 | - // JavaScript. Since `divide` comes from the C++ side, we need to wrap it. | ||
| 195 | - function testFastPath(a, b) { | ||
| 196 | - return divide(a, b); | ||
| 197 | - } | ||
| 198 | - | ||
| 199 | - eval('%PrepareFunctionForOptimization(testFastPath)'); | ||
| 200 | - // This call will let V8 know about the argument types that the function expects. | ||
| 201 | - assert.strictEqual(testFastPath(6, 3), 2); | ||
| 202 | - | ||
| 203 | - eval('%OptimizeFunctionOnNextCall(testFastPath)'); | ||
| 204 | - assert.strictEqual(testFastPath(8, 2), 4); | ||
| 205 | - assert.throws(() => testFastPath(1, 0), { | ||
| 206 | - code: 'ERR_INVALID_STATE', | ||
| 207 | - }); | ||
| 208 | - | ||
| 209 | - if (common.isDebug) { | ||
| 210 | - const { getV8FastApiCallCount } = internalBinding('debug'); | ||
| 211 | - assert.strictEqual(getV8FastApiCallCount('custom_namespace.divide.ok'), 1); | ||
| 212 | - assert.strictEqual(getV8FastApiCallCount('custom_namespace.divide.error'), 1); | ||
| 213 | - } | ||
| 214 | - ``` | ||
| 171 | + ### Test with Fast API path | ||
| 172 | + | ||
| 173 | + In debug mode (`./configure --debug` or `./configure --debug-node` flags), the | ||
| 174 | + fast API calls can be tracked using the `TRACK_V8_FAST_API_CALL("key")` macro. | ||
| 175 | + This can be used to count how many times fast paths are taken during tests. The | ||
| 176 | + key is a global identifier and should be unique across the codebase. | ||
| 177 | + Use `"binding_name.function_name"` or `"binding_name.function_name.suffix"` to | ||
| 178 | + ensure uniqueness. | ||
| 179 | + | ||
| 180 | + In the unit tests, since the fast API function uses `TRACK_V8_FAST_API_CALL`, | ||
| 181 | + we can ensure that the fast paths are taken and test them by writing tests that | ||
| 182 | + force V8 optimizations and check the counters. | ||
| 183 | + | ||
| 184 | + ```js | ||
| 185 | + // Flags: --expose-internals --no-warnings --allow-natives-syntax | ||
| 186 | + 'use strict'; | ||
| 187 | + const common = require('../common'); | ||
| 188 | + | ||
| 189 | + const { internalBinding } = require('internal/test/binding'); | ||
| 190 | + // We could also require a function that uses the internal binding internally. | ||
| 191 | + const { divide } = internalBinding('custom_namespace'); | ||
| 192 | + | ||
| 193 | + // The function that will be optimized. It has to be a function written in | ||
| 194 | + // JavaScript. Since `divide` comes from the C++ side, we need to wrap it. | ||
| 195 | + function testFastPath(a, b) { | ||
| 196 | + return divide(a, b); | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + eval('%PrepareFunctionForOptimization(testFastPath)'); | ||
| 200 | + // This call will let V8 know about the argument types that the function expects. | ||
| 201 | + assert.strictEqual(testFastPath(6, 3), 2); | ||
| 202 | + | ||
| 203 | + eval('%OptimizeFunctionOnNextCall(testFastPath)'); | ||
| 204 | + assert.strictEqual(testFastPath(8, 2), 4); | ||
| 205 | + assert.throws(() => testFastPath(1, 0), { | ||
| 206 | + code: 'ERR_INVALID_STATE', | ||
| 207 | + }); | ||
| 208 | + | ||
| 209 | + if (common.isDebug) { | ||
| 210 | + const { getV8FastApiCallCount } = internalBinding('debug'); | ||
| 211 | + assert.strictEqual(getV8FastApiCallCount('custom_namespace.divide.ok'), 1); | ||
| 212 | + assert.strictEqual(getV8FastApiCallCount('custom_namespace.divide.error'), 1); | ||
| 213 | + } | ||
| 214 | + ``` | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments