mirror of
https://github.com/zebrajr/node.git
synced 2025-12-07 00:20:38 +01:00
src: migrate to new V8 ArrayBuffer API
ArrayBuffer without BackingStore will soon be deprecated. Fixes:https://github.com/nodejs/node/issues/30529 PR-URL: https://github.com/nodejs/node/pull/30782 Fixes: https://github.com/nodejs/node/issues/30529 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
parent
2dff8ddafb
commit
4f523c2c1a
|
|
@ -983,10 +983,20 @@ inline v8::MaybeLocal<v8::Object> AllocatedBuffer::ToBuffer() {
|
||||||
inline v8::Local<v8::ArrayBuffer> AllocatedBuffer::ToArrayBuffer() {
|
inline v8::Local<v8::ArrayBuffer> AllocatedBuffer::ToArrayBuffer() {
|
||||||
CHECK_NOT_NULL(env_);
|
CHECK_NOT_NULL(env_);
|
||||||
uv_buf_t buf = release();
|
uv_buf_t buf = release();
|
||||||
|
auto callback = [](void* data, size_t length, void* deleter_data){
|
||||||
|
CHECK_NOT_NULL(deleter_data);
|
||||||
|
|
||||||
|
static_cast<v8::ArrayBuffer::Allocator*>(deleter_data)
|
||||||
|
->Free(data, length);
|
||||||
|
};
|
||||||
|
std::unique_ptr<v8::BackingStore> backing =
|
||||||
|
v8::ArrayBuffer::NewBackingStore(buf.base,
|
||||||
|
buf.len,
|
||||||
|
callback,
|
||||||
|
env_->isolate()
|
||||||
|
->GetArrayBufferAllocator());
|
||||||
return v8::ArrayBuffer::New(env_->isolate(),
|
return v8::ArrayBuffer::New(env_->isolate(),
|
||||||
buf.base,
|
std::move(backing));
|
||||||
buf.len,
|
|
||||||
v8::ArrayBufferCreationMode::kInternalized);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Environment::ThrowError(const char* errmsg) {
|
inline void Environment::ThrowError(const char* errmsg) {
|
||||||
|
|
|
||||||
|
|
@ -2612,8 +2612,18 @@ napi_status napi_create_external_arraybuffer(napi_env env,
|
||||||
CHECK_ARG(env, result);
|
CHECK_ARG(env, result);
|
||||||
|
|
||||||
v8::Isolate* isolate = env->isolate;
|
v8::Isolate* isolate = env->isolate;
|
||||||
|
// The buffer will be freed with v8impl::ArrayBufferReference::New()
|
||||||
|
// below, hence this BackingStore does not need to free the buffer.
|
||||||
|
std::unique_ptr<v8::BackingStore> backing =
|
||||||
|
v8::ArrayBuffer::NewBackingStore(external_data,
|
||||||
|
byte_length,
|
||||||
|
[](void*, size_t, void*){},
|
||||||
|
nullptr);
|
||||||
v8::Local<v8::ArrayBuffer> buffer =
|
v8::Local<v8::ArrayBuffer> buffer =
|
||||||
v8::ArrayBuffer::New(isolate, external_data, byte_length);
|
v8::ArrayBuffer::New(isolate, std::move(backing));
|
||||||
|
// TODO(thangktran): drop this check when V8 is pumped to 8.0 .
|
||||||
|
if (!buffer->IsExternal())
|
||||||
|
buffer->Externalize(buffer->GetBackingStore());
|
||||||
v8::Maybe<bool> marked = env->mark_arraybuffer_as_untransferable(buffer);
|
v8::Maybe<bool> marked = env->mark_arraybuffer_as_untransferable(buffer);
|
||||||
CHECK_MAYBE_NOTHING(env, marked, napi_generic_failure);
|
CHECK_MAYBE_NOTHING(env, marked, napi_generic_failure);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ namespace node {
|
||||||
namespace Buffer {
|
namespace Buffer {
|
||||||
|
|
||||||
using v8::ArrayBuffer;
|
using v8::ArrayBuffer;
|
||||||
using v8::ArrayBufferCreationMode;
|
|
||||||
using v8::ArrayBufferView;
|
using v8::ArrayBufferView;
|
||||||
|
using v8::BackingStore;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::EscapableHandleScope;
|
using v8::EscapableHandleScope;
|
||||||
using v8::FunctionCallbackInfo;
|
using v8::FunctionCallbackInfo;
|
||||||
|
|
@ -127,8 +127,8 @@ CallbackInfo::CallbackInfo(Environment* env,
|
||||||
data_(data),
|
data_(data),
|
||||||
hint_(hint),
|
hint_(hint),
|
||||||
env_(env) {
|
env_(env) {
|
||||||
ArrayBuffer::Contents obj_c = object->GetContents();
|
std::shared_ptr<BackingStore> obj_backing = object->GetBackingStore();
|
||||||
CHECK_EQ(data_, static_cast<char*>(obj_c.Data()));
|
CHECK_EQ(data_, static_cast<char*>(obj_backing->Data()));
|
||||||
if (object->ByteLength() != 0)
|
if (object->ByteLength() != 0)
|
||||||
CHECK_NOT_NULL(data_);
|
CHECK_NOT_NULL(data_);
|
||||||
|
|
||||||
|
|
@ -406,7 +406,19 @@ MaybeLocal<Object> New(Environment* env,
|
||||||
return Local<Object>();
|
return Local<Object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), data, length);
|
|
||||||
|
// The buffer will be released by a CallbackInfo::New() below,
|
||||||
|
// hence this BackingStore callback is empty.
|
||||||
|
std::unique_ptr<BackingStore> backing =
|
||||||
|
ArrayBuffer::NewBackingStore(data,
|
||||||
|
length,
|
||||||
|
[](void*, size_t, void*){},
|
||||||
|
nullptr);
|
||||||
|
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(),
|
||||||
|
std::move(backing));
|
||||||
|
// TODO(thangktran): drop this check when V8 is pumped to 8.0 .
|
||||||
|
if (!ab->IsExternal())
|
||||||
|
ab->Externalize(ab->GetBackingStore());
|
||||||
if (ab->SetPrivate(env->context(),
|
if (ab->SetPrivate(env->context(),
|
||||||
env->arraybuffer_untransferable_private_symbol(),
|
env->arraybuffer_untransferable_private_symbol(),
|
||||||
True(env->isolate())).IsNothing()) {
|
True(env->isolate())).IsNothing()) {
|
||||||
|
|
@ -465,11 +477,21 @@ MaybeLocal<Object> New(Environment* env,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<ArrayBuffer> ab =
|
auto callback = [](void* data, size_t length, void* deleter_data){
|
||||||
ArrayBuffer::New(env->isolate(),
|
CHECK_NOT_NULL(deleter_data);
|
||||||
data,
|
|
||||||
length,
|
static_cast<v8::ArrayBuffer::Allocator*>(deleter_data)
|
||||||
ArrayBufferCreationMode::kInternalized);
|
->Free(data, length);
|
||||||
|
};
|
||||||
|
std::unique_ptr<v8::BackingStore> backing =
|
||||||
|
v8::ArrayBuffer::NewBackingStore(data,
|
||||||
|
length,
|
||||||
|
callback,
|
||||||
|
env->isolate()
|
||||||
|
->GetArrayBufferAllocator());
|
||||||
|
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(),
|
||||||
|
std::move(backing));
|
||||||
|
|
||||||
return Buffer::New(env, ab, 0, length).FromMaybe(Local<Object>());
|
return Buffer::New(env, ab, 0, length).FromMaybe(Local<Object>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1181,8 +1203,16 @@ void Initialize(Local<Object> target,
|
||||||
if (NodeArrayBufferAllocator* allocator =
|
if (NodeArrayBufferAllocator* allocator =
|
||||||
env->isolate_data()->node_allocator()) {
|
env->isolate_data()->node_allocator()) {
|
||||||
uint32_t* zero_fill_field = allocator->zero_fill_field();
|
uint32_t* zero_fill_field = allocator->zero_fill_field();
|
||||||
Local<ArrayBuffer> array_buffer = ArrayBuffer::New(
|
std::unique_ptr<BackingStore> backing =
|
||||||
env->isolate(), zero_fill_field, sizeof(*zero_fill_field));
|
ArrayBuffer::NewBackingStore(zero_fill_field,
|
||||||
|
sizeof(*zero_fill_field),
|
||||||
|
[](void*, size_t, void*){},
|
||||||
|
nullptr);
|
||||||
|
Local<ArrayBuffer> array_buffer =
|
||||||
|
ArrayBuffer::New(env->isolate(), std::move(backing));
|
||||||
|
// TODO(thangktran): drop this check when V8 is pumped to 8.0 .
|
||||||
|
if (!array_buffer->IsExternal())
|
||||||
|
array_buffer->Externalize(array_buffer->GetBackingStore());
|
||||||
CHECK(target
|
CHECK(target
|
||||||
->Set(env->context(),
|
->Set(env->context(),
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(), "zeroFill"),
|
FIXED_ONE_BYTE_STRING(env->isolate(), "zeroFill"),
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ namespace node {
|
||||||
|
|
||||||
using v8::ArrayBuffer;
|
using v8::ArrayBuffer;
|
||||||
using v8::ArrayBufferView;
|
using v8::ArrayBufferView;
|
||||||
|
using v8::BackingStore;
|
||||||
using v8::Boolean;
|
using v8::Boolean;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::Float64Array;
|
using v8::Float64Array;
|
||||||
|
|
@ -566,10 +567,18 @@ Http2Session::Http2Session(Environment* env,
|
||||||
|
|
||||||
{
|
{
|
||||||
// Make the js_fields_ property accessible to JS land.
|
// Make the js_fields_ property accessible to JS land.
|
||||||
|
std::unique_ptr<BackingStore> backing =
|
||||||
|
ArrayBuffer::NewBackingStore(
|
||||||
|
reinterpret_cast<uint8_t*>(&js_fields_),
|
||||||
|
kSessionUint8FieldCount,
|
||||||
|
[](void*, size_t, void*){},
|
||||||
|
nullptr);
|
||||||
Local<ArrayBuffer> ab =
|
Local<ArrayBuffer> ab =
|
||||||
ArrayBuffer::New(env->isolate(),
|
ArrayBuffer::New(env->isolate(), std::move(backing));
|
||||||
reinterpret_cast<uint8_t*>(&js_fields_),
|
// TODO(thangktran): drop this check when V8 is pumped to 8.0 .
|
||||||
kSessionUint8FieldCount);
|
if (!ab->IsExternal())
|
||||||
|
ab->Externalize(ab->GetBackingStore());
|
||||||
|
js_fields_ab_.Reset(env->isolate(), ab);
|
||||||
Local<Uint8Array> uint8_arr =
|
Local<Uint8Array> uint8_arr =
|
||||||
Uint8Array::New(ab, 0, kSessionUint8FieldCount);
|
Uint8Array::New(ab, 0, kSessionUint8FieldCount);
|
||||||
USE(wrap->Set(env->context(), env->fields_string(), uint8_arr));
|
USE(wrap->Set(env->context(), env->fields_string(), uint8_arr));
|
||||||
|
|
@ -581,6 +590,14 @@ Http2Session::~Http2Session() {
|
||||||
Debug(this, "freeing nghttp2 session");
|
Debug(this, "freeing nghttp2 session");
|
||||||
nghttp2_session_del(session_);
|
nghttp2_session_del(session_);
|
||||||
CHECK_EQ(current_nghttp2_memory_, 0);
|
CHECK_EQ(current_nghttp2_memory_, 0);
|
||||||
|
HandleScope handle_scope(env()->isolate());
|
||||||
|
// Detach js_fields_ab_ to avoid having problem when new Http2Session
|
||||||
|
// instances are created on the same location of previous
|
||||||
|
// instances. This in turn will call ArrayBuffer::NewBackingStore()
|
||||||
|
// multiple times with the same buffer address and causing error.
|
||||||
|
// Ref: https://github.com/nodejs/node/pull/30782
|
||||||
|
Local<ArrayBuffer> ab = js_fields_ab_.Get(env()->isolate());
|
||||||
|
ab->Detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Http2Session::diagnostic_name() const {
|
std::string Http2Session::diagnostic_name() const {
|
||||||
|
|
|
||||||
|
|
@ -989,6 +989,7 @@ class Http2Session : public AsyncWrap,
|
||||||
|
|
||||||
// JS-accessible numeric fields, as indexed by SessionUint8Fields.
|
// JS-accessible numeric fields, as indexed by SessionUint8Fields.
|
||||||
SessionJSFields js_fields_ = {};
|
SessionJSFields js_fields_ = {};
|
||||||
|
v8::Global<v8::ArrayBuffer> js_fields_ab_;
|
||||||
|
|
||||||
// The session type: client or server
|
// The session type: client or server
|
||||||
nghttp2_session_type session_type_;
|
nghttp2_session_type session_type_;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ namespace node {
|
||||||
|
|
||||||
using v8::Array;
|
using v8::Array;
|
||||||
using v8::ArrayBuffer;
|
using v8::ArrayBuffer;
|
||||||
|
using v8::BackingStore;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::FunctionCallbackInfo;
|
using v8::FunctionCallbackInfo;
|
||||||
using v8::HeapCodeStatistics;
|
using v8::HeapCodeStatistics;
|
||||||
|
|
@ -162,12 +163,22 @@ void Initialize(Local<Object> target,
|
||||||
const size_t heap_statistics_buffer_byte_length =
|
const size_t heap_statistics_buffer_byte_length =
|
||||||
sizeof(*env->heap_statistics_buffer()) * kHeapStatisticsPropertiesCount;
|
sizeof(*env->heap_statistics_buffer()) * kHeapStatisticsPropertiesCount;
|
||||||
|
|
||||||
|
std::unique_ptr<BackingStore> heap_statistics_backing =
|
||||||
|
ArrayBuffer::NewBackingStore(env->heap_statistics_buffer(),
|
||||||
|
heap_statistics_buffer_byte_length,
|
||||||
|
[](void*, size_t, void*){},
|
||||||
|
nullptr);
|
||||||
|
Local<ArrayBuffer> heap_statistics_ab =
|
||||||
|
ArrayBuffer::New(env->isolate(),
|
||||||
|
std::move(heap_statistics_backing));
|
||||||
|
// TODO(thangktran): drop this check when V8 is pumped to 8.0 .
|
||||||
|
if (!heap_statistics_ab->IsExternal())
|
||||||
|
heap_statistics_ab->Externalize(
|
||||||
|
heap_statistics_ab->GetBackingStore());
|
||||||
target->Set(env->context(),
|
target->Set(env->context(),
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(),
|
FIXED_ONE_BYTE_STRING(env->isolate(),
|
||||||
"heapStatisticsArrayBuffer"),
|
"heapStatisticsArrayBuffer"),
|
||||||
ArrayBuffer::New(env->isolate(),
|
heap_statistics_ab).Check();
|
||||||
env->heap_statistics_buffer(),
|
|
||||||
heap_statistics_buffer_byte_length)).Check();
|
|
||||||
|
|
||||||
#define V(i, _, name) \
|
#define V(i, _, name) \
|
||||||
target->Set(env->context(), \
|
target->Set(env->context(), \
|
||||||
|
|
@ -189,12 +200,22 @@ void Initialize(Local<Object> target,
|
||||||
sizeof(*env->heap_code_statistics_buffer())
|
sizeof(*env->heap_code_statistics_buffer())
|
||||||
* kHeapCodeStatisticsPropertiesCount;
|
* kHeapCodeStatisticsPropertiesCount;
|
||||||
|
|
||||||
|
std::unique_ptr<BackingStore> heap_code_statistics_backing =
|
||||||
|
ArrayBuffer::NewBackingStore(env->heap_code_statistics_buffer(),
|
||||||
|
heap_code_statistics_buffer_byte_length,
|
||||||
|
[](void*, size_t, void*){},
|
||||||
|
nullptr);
|
||||||
|
Local<ArrayBuffer> heap_code_statistics_ab =
|
||||||
|
ArrayBuffer::New(env->isolate(),
|
||||||
|
std::move(heap_code_statistics_backing));
|
||||||
|
// TODO(thangktran): drop this check when V8 is pumped to 8.0 .
|
||||||
|
if (!heap_code_statistics_ab->IsExternal())
|
||||||
|
heap_code_statistics_ab->Externalize(
|
||||||
|
heap_code_statistics_ab->GetBackingStore());
|
||||||
target->Set(env->context(),
|
target->Set(env->context(),
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(),
|
FIXED_ONE_BYTE_STRING(env->isolate(),
|
||||||
"heapCodeStatisticsArrayBuffer"),
|
"heapCodeStatisticsArrayBuffer"),
|
||||||
ArrayBuffer::New(env->isolate(),
|
heap_code_statistics_ab)
|
||||||
env->heap_code_statistics_buffer(),
|
|
||||||
heap_code_statistics_buffer_byte_length))
|
|
||||||
.Check();
|
.Check();
|
||||||
|
|
||||||
#define V(i, _, name) \
|
#define V(i, _, name) \
|
||||||
|
|
@ -244,12 +265,22 @@ void Initialize(Local<Object> target,
|
||||||
kHeapSpaceStatisticsPropertiesCount *
|
kHeapSpaceStatisticsPropertiesCount *
|
||||||
number_of_heap_spaces;
|
number_of_heap_spaces;
|
||||||
|
|
||||||
|
std::unique_ptr<BackingStore> heap_space_statistics_backing =
|
||||||
|
ArrayBuffer::NewBackingStore(env->heap_space_statistics_buffer(),
|
||||||
|
heap_space_statistics_buffer_byte_length,
|
||||||
|
[](void*, size_t, void*){},
|
||||||
|
nullptr);
|
||||||
|
Local<ArrayBuffer> heap_space_statistics_ab =
|
||||||
|
ArrayBuffer::New(env->isolate(),
|
||||||
|
std::move(heap_space_statistics_backing));
|
||||||
|
// TODO(thangktran): drop this check when V8 is pumped to 8.0 .
|
||||||
|
if (!heap_space_statistics_ab->IsExternal())
|
||||||
|
heap_space_statistics_ab->Externalize(
|
||||||
|
heap_space_statistics_ab->GetBackingStore());
|
||||||
target->Set(env->context(),
|
target->Set(env->context(),
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(),
|
FIXED_ONE_BYTE_STRING(env->isolate(),
|
||||||
"heapSpaceStatisticsArrayBuffer"),
|
"heapSpaceStatisticsArrayBuffer"),
|
||||||
ArrayBuffer::New(env->isolate(),
|
heap_space_statistics_ab)
|
||||||
env->heap_space_statistics_buffer(),
|
|
||||||
heap_space_statistics_buffer_byte_length))
|
|
||||||
.Check();
|
.Check();
|
||||||
|
|
||||||
#define V(i, _, name) \
|
#define V(i, _, name) \
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
using node::kDisallowedInEnvironment;
|
using node::kDisallowedInEnvironment;
|
||||||
using v8::Array;
|
using v8::Array;
|
||||||
using v8::ArrayBuffer;
|
using v8::ArrayBuffer;
|
||||||
|
using v8::BackingStore;
|
||||||
using v8::Boolean;
|
using v8::Boolean;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::Float64Array;
|
using v8::Float64Array;
|
||||||
|
|
@ -622,6 +623,7 @@ void Worker::GetResourceLimits(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
Local<Float64Array> Worker::GetResourceLimits(Isolate* isolate) const {
|
Local<Float64Array> Worker::GetResourceLimits(Isolate* isolate) const {
|
||||||
Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, sizeof(resource_limits_));
|
Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, sizeof(resource_limits_));
|
||||||
|
|
||||||
memcpy(ab->GetBackingStore()->Data(),
|
memcpy(ab->GetBackingStore()->Data(),
|
||||||
resource_limits_,
|
resource_limits_,
|
||||||
sizeof(resource_limits_));
|
sizeof(resource_limits_));
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ using v8::Object;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
uint32_t free_call_count = 0;
|
uint32_t free_call_count = 0;
|
||||||
char data[] = "hello";
|
|
||||||
|
|
||||||
void GetFreeCallCount(const FunctionCallbackInfo<Value>& args) {
|
void GetFreeCallCount(const FunctionCallbackInfo<Value>& args) {
|
||||||
args.GetReturnValue().Set(free_call_count);
|
args.GetReturnValue().Set(free_call_count);
|
||||||
|
|
@ -21,6 +20,9 @@ void Initialize(Local<Object> exports,
|
||||||
Local<Context> context) {
|
Local<Context> context) {
|
||||||
Isolate* isolate = context->GetIsolate();
|
Isolate* isolate = context->GetIsolate();
|
||||||
NODE_SET_METHOD(exports, "getFreeCallCount", GetFreeCallCount);
|
NODE_SET_METHOD(exports, "getFreeCallCount", GetFreeCallCount);
|
||||||
|
|
||||||
|
char* data = new char;
|
||||||
|
|
||||||
exports->Set(context,
|
exports->Set(context,
|
||||||
v8::String::NewFromUtf8(
|
v8::String::NewFromUtf8(
|
||||||
isolate, "buffer", v8::NewStringType::kNormal)
|
isolate, "buffer", v8::NewStringType::kNormal)
|
||||||
|
|
@ -30,6 +32,7 @@ void Initialize(Local<Object> exports,
|
||||||
data,
|
data,
|
||||||
sizeof(data),
|
sizeof(data),
|
||||||
[](char* data, void* hint) {
|
[](char* data, void* hint) {
|
||||||
|
delete data;
|
||||||
free_call_count++;
|
free_call_count++;
|
||||||
},
|
},
|
||||||
nullptr).ToLocalChecked()).Check();
|
nullptr).ToLocalChecked()).Check();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#define NAPI_EXPERIMENTAL
|
#define NAPI_EXPERIMENTAL
|
||||||
#include <js_native_api.h>
|
#include <js_native_api.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "../common.h"
|
#include "../common.h"
|
||||||
|
|
||||||
static napi_value Multiply(napi_env env, napi_callback_info info) {
|
static napi_value Multiply(napi_env env, napi_callback_info info) {
|
||||||
|
|
@ -74,22 +75,33 @@ static napi_value Multiply(napi_env env, napi_callback_info info) {
|
||||||
return output_array;
|
return output_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FinalizeCallback(napi_env env,
|
||||||
|
void* finalize_data,
|
||||||
|
void* finalize_hint)
|
||||||
|
{
|
||||||
|
free(finalize_data);
|
||||||
|
}
|
||||||
|
|
||||||
static napi_value External(napi_env env, napi_callback_info info) {
|
static napi_value External(napi_env env, napi_callback_info info) {
|
||||||
static int8_t externalData[] = {0, 1, 2};
|
const uint8_t nElem = 3;
|
||||||
|
int8_t* externalData = malloc(nElem*sizeof(int8_t));
|
||||||
|
externalData[0] = 0;
|
||||||
|
externalData[1] = 1;
|
||||||
|
externalData[2] = 2;
|
||||||
|
|
||||||
napi_value output_buffer;
|
napi_value output_buffer;
|
||||||
NAPI_CALL(env, napi_create_external_arraybuffer(
|
NAPI_CALL(env, napi_create_external_arraybuffer(
|
||||||
env,
|
env,
|
||||||
externalData,
|
externalData,
|
||||||
sizeof(externalData),
|
nElem*sizeof(int8_t),
|
||||||
NULL, // finalize_callback
|
FinalizeCallback,
|
||||||
NULL, // finalize_hint
|
NULL, // finalize_hint
|
||||||
&output_buffer));
|
&output_buffer));
|
||||||
|
|
||||||
napi_value output_array;
|
napi_value output_array;
|
||||||
NAPI_CALL(env, napi_create_typedarray(env,
|
NAPI_CALL(env, napi_create_typedarray(env,
|
||||||
napi_int8_array,
|
napi_int8_array,
|
||||||
sizeof(externalData) / sizeof(int8_t),
|
nElem,
|
||||||
output_buffer,
|
output_buffer,
|
||||||
0,
|
0,
|
||||||
&output_array));
|
&output_array));
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <node_api.h>
|
#include <node_api.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "../../js-native-api/common.h"
|
#include "../../js-native-api/common.h"
|
||||||
|
|
||||||
uint32_t free_call_count = 0;
|
uint32_t free_call_count = 0;
|
||||||
char data[] = "hello";
|
|
||||||
|
|
||||||
napi_value GetFreeCallCount(napi_env env, napi_callback_info info) {
|
napi_value GetFreeCallCount(napi_env env, napi_callback_info info) {
|
||||||
napi_value value;
|
napi_value value;
|
||||||
|
|
@ -13,7 +13,7 @@ napi_value GetFreeCallCount(napi_env env, napi_callback_info info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finalize_cb(napi_env env, void* finalize_data, void* hint) {
|
static void finalize_cb(napi_env env, void* finalize_data, void* hint) {
|
||||||
assert(finalize_data == data);
|
free(finalize_data);
|
||||||
free_call_count++;
|
free_call_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,6 +29,9 @@ NAPI_MODULE_INIT() {
|
||||||
// rather than a Node.js Buffer, since testing the latter would only test
|
// rather than a Node.js Buffer, since testing the latter would only test
|
||||||
// the same code paths and not the ones specific to N-API.
|
// the same code paths and not the ones specific to N-API.
|
||||||
napi_value buffer;
|
napi_value buffer;
|
||||||
|
|
||||||
|
char* data = malloc(sizeof(char));
|
||||||
|
|
||||||
NAPI_CALL(env, napi_create_external_arraybuffer(
|
NAPI_CALL(env, napi_create_external_arraybuffer(
|
||||||
env,
|
env,
|
||||||
data,
|
data,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user