| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent cb7a58a commit 01c0498
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2565,6 +2565,41 @@ object just created has been garbage collected. | |||
| 2565 | 2565 | JavaScript `ArrayBuffer`s are described in | |
| 2566 | 2566 | [Section ArrayBuffer objects][] of the ECMAScript Language Specification. | |
| 2567 | 2567 | ||
| 2568 | + #### `node_api_create_external_sharedarraybuffer` | ||
| 2569 | + | ||
| 2570 | + <!-- YAML | ||
| 2571 | + added: REPLACEME | ||
| 2572 | + --> | ||
| 2573 | + | ||
| 2574 | + ```c | ||
| 2575 | + napi_status | ||
| 2576 | + node_api_create_external_sharedarraybuffer(napi_env env, | ||
| 2577 | + void* external_data, | ||
| 2578 | + size_t byte_length, | ||
| 2579 | + node_api_noenv_finalize finalize_cb, | ||
| 2580 | + void* finalize_hint, | ||
| 2581 | + napi_value* result) | ||
| 2582 | + ``` | ||
| 2583 | + | ||
| 2584 | + * `[in] env`: The environment that the API is invoked under. | ||
| 2585 | + * `[in] external_data`: Pointer to the underlying byte buffer of the | ||
| 2586 | + `SharedArrayBuffer`. | ||
| 2587 | + * `[in] byte_length`: The length in bytes of the underlying buffer. | ||
| 2588 | + * `[in] finalize_cb`: Optional callback to call when the `SharedArrayBuffer` is | ||
| 2589 | + being collected. Called on an arbitrary thread. Because a `SharedArrayBuffer` | ||
| 2590 | + can outlive the environment it's created in, the callback does not receive a | ||
| 2591 | + reference to `env`. | ||
| 2592 | + * `[in] finalize_hint`: Optional hint to pass to the finalize callback during | ||
| 2593 | + collection. | ||
| 2594 | + * `[out] result`: A `napi_value` representing a JavaScript `SharedArrayBuffer`. | ||
| 2595 | + | ||
| 2596 | + Returns `napi_ok` if the API succeeded. | ||
| 2597 | + | ||
| 2598 | + Create a `SharedArrayBuffer` with externally managed memory. | ||
| 2599 | + | ||
| 2600 | + See the entry on [`napi_create_external_arraybuffer`][] for runtime | ||
| 2601 | + compatibility. | ||
| 2602 | + | ||
| 2568 | 2603 | #### `napi_create_external_buffer` | |
| 2569 | 2604 | ||
| 2570 | 2605 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -420,6 +420,16 @@ napi_create_external_arraybuffer(napi_env env, | |||
| 420 | 420 | node_api_basic_finalize finalize_cb, | |
| 421 | 421 | void* finalize_hint, | |
| 422 | 422 | napi_value* result); | |
| 423 | + #ifdef NAPI_EXPERIMENTAL | ||
| 424 | + #define NODE_API_EXPERIMENTAL_HAS_CREATE_EXTERNAL_SHAREDARRAYBUFFER | ||
| 425 | + NAPI_EXTERN napi_status NAPI_CDECL | ||
| 426 | + node_api_create_external_sharedarraybuffer(napi_env env, | ||
| 427 | + void* external_data, | ||
| 428 | + size_t byte_length, | ||
| 429 | + node_api_noenv_finalize finalize_cb, | ||
| 430 | + void* finalize_hint, | ||
| 431 | + napi_value* result); | ||
| 432 | + #endif // NAPI_EXPERIMENTAL | ||
| 423 | 433 | #endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED | |
| 424 | 434 | NAPI_EXTERN napi_status NAPI_CDECL napi_get_arraybuffer_info( | |
| 425 | 435 | napi_env env, napi_value arraybuffer, void** data, size_t* byte_length); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -174,6 +174,10 @@ typedef void(NAPI_CDECL* node_api_nogc_finalize)(node_api_nogc_env env, | |||
| 174 | 174 | #endif | |
| 175 | 175 | typedef node_api_nogc_finalize node_api_basic_finalize; | |
| 176 | 176 | ||
| 177 | + // A finalizer that can be called from any thread and at any time. | ||
| 178 | + typedef void(NAPI_CDECL* node_api_noenv_finalize)(void* finalize_data, | ||
| 179 | + void* finalize_hint); | ||
| 180 | + | ||
| 177 | 181 | typedef struct { | |
| 178 | 182 | // One of utf8name or name should be NULL. | |
| 179 | 183 | const char* utf8name; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3068,6 +3068,48 @@ napi_create_external_arraybuffer(napi_env env, | |||
| 3068 | 3068 | env, buffer, nullptr, nullptr, nullptr, result, nullptr); | |
| 3069 | 3069 | } | |
| 3070 | 3070 | ||
| 3071 | + napi_status NAPI_CDECL | ||
| 3072 | + node_api_create_external_sharedarraybuffer(napi_env env, | ||
| 3073 | + void* external_data, | ||
| 3074 | + size_t byte_length, | ||
| 3075 | + node_api_noenv_finalize finalize_cb, | ||
| 3076 | + void* finalize_hint, | ||
| 3077 | + napi_value* result) { | ||
| 3078 | + NAPI_PREAMBLE(env); | ||
| 3079 | + CHECK_ARG(env, result); | ||
| 3080 | + #ifdef V8_ENABLE_SANDBOX | ||
| 3081 | + return napi_set_last_error(env, napi_no_external_buffers_allowed); | ||
| 3082 | + #else | ||
| 3083 | + struct FinalizerData { | ||
| 3084 | + void (*cb)(void* external_data, void* finalize_hint); | ||
| 3085 | + void* hint; | ||
| 3086 | + }; | ||
| 3087 | + auto deleter = [](void* external_data, size_t length, void* deleter_data) { | ||
| 3088 | + if (auto fd = static_cast<FinalizerData*>(deleter_data)) { | ||
| 3089 | + fd->cb(external_data, fd->hint); | ||
| 3090 | + delete fd; | ||
| 3091 | + } | ||
| 3092 | + }; | ||
| 3093 | + FinalizerData* deleter_data = nullptr; | ||
| 3094 | + if (finalize_cb != nullptr) { | ||
| 3095 | + deleter_data = new FinalizerData{finalize_cb, finalize_hint}; | ||
| 3096 | + } | ||
| 3097 | + auto unique_backing_store = v8::SharedArrayBuffer::NewBackingStore( | ||
| 3098 | + external_data, | ||
| 3099 | + byte_length, | ||
| 3100 | + deleter, | ||
| 3101 | + reinterpret_cast<void*>(deleter_data)); | ||
| 3102 | + CHECK(!!unique_backing_store); // Cannot fail. | ||
| 3103 | + auto shared_backing_store = | ||
| 3104 | + std::shared_ptr<v8::BackingStore>(std::move(unique_backing_store)); | ||
| 3105 | + auto shared_array_buffer = | ||
| 3106 | + v8::SharedArrayBuffer::New(env->isolate, std::move(shared_backing_store)); | ||
| 3107 | + CHECK_MAYBE_EMPTY(env, shared_array_buffer, napi_generic_failure); | ||
| 3108 | + *result = v8impl::JsValueFromV8LocalValue(shared_array_buffer); | ||
| 3109 | + return napi_clear_last_error(env); | ||
| 3110 | + #endif // V8_ENABLE_SANDBOX | ||
| 3111 | + } | ||
| 3112 | + | ||
| 3071 | 3113 | napi_status NAPI_CDECL napi_get_arraybuffer_info(napi_env env, | |
| 3072 | 3114 | napi_value arraybuffer, | |
| 3073 | 3115 | void** data, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,7 +3,8 @@ | |||
| 3 | 3 | { | |
| 4 | 4 | "target_name": "test_buffer", | |
| 5 | 5 | "defines": [ | |
| 6 | - 'NAPI_VERSION=10' | ||
| 6 | + "NAPI_EXPERIMENTAL", | ||
| 7 | + "NODE_API_EXPERIMENTAL_NO_WARNING" | ||
| 7 | 8 | ], | |
| 8 | 9 | "sources": [ "test_buffer.c" ] | |
| 9 | 10 | }, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,7 +4,8 @@ | |||
| 4 | 4 | const common = require('../../common'); | |
| 5 | 5 | const binding = require(`./build/${common.buildType}/test_buffer`); | |
| 6 | 6 | const assert = require('assert'); | |
| 7 | - const tick = require('util').promisify(require('../../common/tick')); | ||
| 7 | + const util = require('util'); | ||
| 8 | + const tick = util.promisify(require('../../common/tick')); | ||
| 8 | 9 | ||
| 9 | 10 | (async function() { | |
| 10 | 11 | assert.strictEqual(binding.newBuffer().toString(), binding.theText); | |
@@ -26,6 +27,17 @@ const tick = require('util').promisify(require('../../common/tick')); | |||
| 26 | 27 | console.log('gc2'); | |
| 27 | 28 | assert.strictEqual(binding.getDeleterCallCount(), 2); | |
| 28 | 29 | ||
| 30 | + // Caveat emptor: it's indeterminate when the SharedArrayBuffer's backing | ||
| 31 | + // store is reclaimed; at least some of the time it happens even before | ||
| 32 | + // calling gc(). | ||
| 33 | + let sab = binding.newExternalSharedArrayBuffer(); | ||
| 34 | + assert(util.types.isSharedArrayBuffer(sab)); | ||
| 35 | + sab = null; | ||
| 36 | + global.gc(); | ||
| 37 | + await tick(10); | ||
| 38 | + console.log('gc3'); | ||
| 39 | + assert.strictEqual(binding.getDeleterCallCount(), 3); | ||
| 40 | + | ||
| 29 | 41 | // To test this doesn't crash | |
| 30 | 42 | binding.invalidObjectAsBuffer({}); | |
| 31 | 43 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -58,6 +58,30 @@ static napi_value newExternalBuffer(napi_env env, napi_callback_info info) { | |||
| 58 | 58 | return theBuffer; | |
| 59 | 59 | } | |
| 60 | 60 | ||
| 61 | + static char externalSharedArrayBufferData[1]; | ||
| 62 | + | ||
| 63 | + static void freeExternalSharedArrayBuffer(void* data, void* hint) { | ||
| 64 | + (void)hint; | ||
| 65 | + NODE_API_BASIC_ASSERT_RETURN_VOID( | ||
| 66 | + data == (void*)externalSharedArrayBufferData, | ||
| 67 | + "SharedArrayBuffer points to wrong data"); | ||
| 68 | + deleterCallCount++; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + static napi_value newExternalSharedArrayBuffer(napi_env env, | ||
| 72 | + napi_callback_info info) { | ||
| 73 | + napi_value sab; | ||
| 74 | + NODE_API_CALL( | ||
| 75 | + env, | ||
| 76 | + node_api_create_external_sharedarraybuffer(env, | ||
| 77 | + externalSharedArrayBufferData, | ||
| 78 | + 1, | ||
| 79 | + freeExternalSharedArrayBuffer, | ||
| 80 | + NULL, | ||
| 81 | + &sab)); | ||
| 82 | + return sab; | ||
| 83 | + } | ||
| 84 | + | ||
| 61 | 85 | static napi_value getDeleterCallCount(napi_env env, napi_callback_info info) { | |
| 62 | 86 | napi_value callCount; | |
| 63 | 87 | NODE_API_CALL(env, napi_create_int32(env, deleterCallCount, &callCount)); | |
@@ -171,6 +195,8 @@ static napi_value Init(napi_env env, napi_value exports) { | |||
| 171 | 195 | napi_property_descriptor methods[] = { | |
| 172 | 196 | DECLARE_NODE_API_PROPERTY("newBuffer", newBuffer), | |
| 173 | 197 | DECLARE_NODE_API_PROPERTY("newExternalBuffer", newExternalBuffer), | |
| 198 | + DECLARE_NODE_API_PROPERTY("newExternalSharedArrayBuffer", | ||
| 199 | + newExternalSharedArrayBuffer), | ||
| 174 | 200 | DECLARE_NODE_API_PROPERTY("getDeleterCallCount", getDeleterCallCount), | |
| 175 | 201 | DECLARE_NODE_API_PROPERTY("copyBuffer", copyBuffer), | |
| 176 | 202 | DECLARE_NODE_API_PROPERTY("bufferHasInstance", bufferHasInstance), | |
| Back | FazBrowse Home | New Git URL |
0 commit comments