diff options
author | Bert Belder <bertbelder@gmail.com> | 2019-04-28 21:31:10 +0200 |
---|---|---|
committer | Bert Belder <bertbelder@gmail.com> | 2019-05-01 21:11:09 +0200 |
commit | 41c7e96f1a81ea416ebb3ba45f2815e0202d6b75 (patch) | |
tree | 5fcb15b8664d7579cf4db76d16754c8efa7c4667 /core/libdeno/deno.h | |
parent | abdb98a2516a9d6ec313805dffbc2107d38f8ed4 (diff) |
Refactor zero-copy buffers for performance and to prevent memory leaks
* In order to prevent ArrayBuffers from getting garbage collected by V8,
we used to store a v8::Persistent<ArrayBuffer> in a map. This patch
introduces a custom ArrayBuffer allocator which doesn't use Persistent
handles, but instead stores a pointer to the actual ArrayBuffer data
alongside with a reference count. Since creating Persistent handles
has quite a bit of overhead, this change significantly increases
performance. Various HTTP server benchmarks report about 5-10% more
requests per second than before.
* Previously the Persistent handle that prevented garbage collection had
to be released manually, and this wasn't always done, which was
causing memory leaks. This has been resolved by introducing a new
`PinnedBuf` type in both Rust and C++ that automatically re-enables
garbage collection when it goes out of scope.
* Zero-copy buffers are now correctly wrapped in an Option if there is a
possibility that they're not present. This clears up a correctness
issue where we were creating zero-length slices from a null pointer,
which is against the rules.
Diffstat (limited to 'core/libdeno/deno.h')
-rw-r--r-- | core/libdeno/deno.h | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/core/libdeno/deno.h b/core/libdeno/deno.h index 8054090ed..f83f00834 100644 --- a/core/libdeno/deno.h +++ b/core/libdeno/deno.h @@ -1,21 +1,26 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. #ifndef DENO_H_ #define DENO_H_ + #include <stddef.h> #include <stdint.h> + +#include "buffer.h" + // Neither Rust nor Go support calling directly into C++ functions, therefore // the public interface to libdeno is done in C. #ifdef __cplusplus extern "C" { #endif +typedef deno::PinnedBuf::Raw deno_pinned_buf; + // Data that gets transmitted. typedef struct { - uint8_t* alloc_ptr; // Start of memory allocation (returned from `malloc()`). + uint8_t* alloc_ptr; // Start of memory allocation (from `new uint8_t[len]`). size_t alloc_len; // Length of the memory allocation. uint8_t* data_ptr; // Start of logical contents (within the allocation). size_t data_len; // Length of logical contents. - size_t zero_copy_id; // 0 = normal, 1 = must call deno_zero_copy_release. } deno_buf; typedef struct { @@ -29,7 +34,7 @@ typedef struct deno_s Deno; // control_buf is valid for only for the lifetime of this callback. // data_buf is valid until deno_respond() is called. typedef void (*deno_recv_cb)(void* user_data, deno_buf control_buf, - deno_buf zerop_copy_buf); + deno_pinned_buf zero_copy_buf); void deno_init(); const char* deno_v8_version(); @@ -84,9 +89,7 @@ void deno_execute(Deno* d, void* user_data, const char* js_filename, void deno_respond(Deno* d, void* user_data, deno_buf buf); // consumes zero_copy -// Calling this function more than once with the same zero_copy_id will result -// in an error. -void deno_zero_copy_release(Deno* d, size_t zero_copy_id); +void deno_pinned_buf_delete(deno_pinned_buf* buf); void deno_check_promise_errors(Deno* d); |