Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
19dad19
deps: float 15d7e79 from openssl
tniessen Jul 21, 2019
e334c1f
src: fix type name in comment
bnoordhuis Jun 20, 2019
386d5d7
lib: support min/max values in validateInteger()
cjihrig Jul 22, 2019
2262526
module: implement "exports" proposal for CommonJS
hybrist Jul 19, 2019
d0b1fb3
doc: api/stream.md typo from writeable to writable
imcotton Jul 23, 2019
e0e7763
crypto: increase maxmem range from 32 to 53 bits
tniessen Jul 21, 2019
a38fecd
tools: update certdata.txt
sam-github Jul 22, 2019
86f4c68
crypto: update root certificates
sam-github Jul 22, 2019
c0a0448
doc: fix type in NSS update instructions
sam-github Jul 22, 2019
24b9d29
build: `uname -m` is amd64 on freebsd, not x86_64
bnoordhuis Jul 22, 2019
3c30456
src : elevate v8 namespaces
HarshithaKP Jul 22, 2019
0667d0c
doc: add documentation for response.flushHeaders()
lpinca Jul 22, 2019
95b87ce
doc: claim NODE_MODULE_VERSION=76 for Electron 8
MarshallOfSound Jul 22, 2019
ae56a23
deps: backport b107214 from upstream V8
addaleax Jul 24, 2019
727ffe4
domain: use strong reference to domain while active
addaleax Jun 20, 2019
881e345
doc: describe why new Buffer() is problematic
sam-github Jul 23, 2019
860c0d8
n-api: add APIs for per-instance state management
Jul 15, 2019
454e879
doc: fix incorrect name in report docs
cjihrig Jul 24, 2019
e0951c8
report: loop over uv_cpu_info() results
cjihrig Jul 23, 2019
d3426ee
assert: avoid potentially misleading reference to object identity
addaleax Jul 23, 2019
b7c6ad5
crypto: add outputLength option to crypto.createHash
tniessen Jul 19, 2019
3a62202
crypto: fix handling of malicious getters (scrypt)
tniessen Jul 23, 2019
5d5c89a
policy: add dependencies map for resources
bmeck Jul 18, 2019
ffc7a00
doc: add documentation for stream.destroyed
ronag Jul 23, 2019
e6b3bfe
n-api: refactor a previous commit
Jul 18, 2019
cf071a0
stream: resolve perf regression introduced by V8 7.3
mcollina Jul 24, 2019
82f263d
build,tools: support building with Visual Studio 2019
targos Jul 20, 2019
f6051f9
test: specialize OOM check for AIX
sam-github Jul 24, 2019
8db43b1
src: move relative uptime init
Jul 24, 2019
c9c7256
http: reset parser.incoming when server response is finished
addaleax Jul 11, 2019
24b8f20
deps: remove backup files
AdamMajer Jul 26, 2019
9e7c662
build: ignore backup files
AdamMajer Jul 26, 2019
a7ef102
crypto: add null check to outputLength logic
cjihrig Jul 26, 2019
0b6a84a
test,report: relax CPU match requirements
addaleax Jul 28, 2019
84efadf
test, util: refactor isObject in test-util
RamirezAlex Jul 27, 2019
5533d48
doc: correct import statement
himself65 Jul 27, 2019
085eb48
doc: fixup esm resolver spec formatting
guybedford Jul 28, 2019
406c50c
src: read break_node_first_line from the inspect options
MarshallOfSound Jun 19, 2019
2142b6d
test: improve test-async-hooks-http-parser-destroy
Flarna Jun 16, 2019
b282c85
vm: increase code coverage of source_text_module.js
kball Jun 21, 2019
9b02f36
deps: dlloads node static linked executable
lal12 Jun 4, 2019
9dfa636
dgram: changed 'var' to 'let' and 'const'
mgochoa Jun 21, 2019
1b0d67b
src: fix OpenBSD build
devnexen Jun 22, 2019
d0d3149
http2: add constant to already destructured constants
dnalborczyk Jun 11, 2019
fa82cbc
http2: destructure constants from require call
dnalborczyk Jun 11, 2019
a28db5f
doc: add example of event close for child_process
ltciro Jun 21, 2019
32cf344
src: readlink("/proc/self/exe") -> uv_exename()
bnoordhuis Jun 21, 2019
a0f89a2
test: refactor test using assert instead of try/catch
juansb827 Jun 21, 2019
9b47f77
test: udpate test comment description
Angelfire Jun 21, 2019
048db38
benchmark: swap var for let in url benchmarks
RamirezAlex Jul 24, 2019
f2c1f36
benchmark: swap var for let in util benchmarks
RamirezAlex Jul 24, 2019
bbcf9f0
benchmark: swap var for let in buffer benchmarks
RamirezAlex Jul 26, 2019
cce2087
src: export v8.GetHeapCodeAndMetadataStatistics()
May 30, 2019
fb57bc4
build: do not mix spaces and tabs in Makefile
lpinca Jul 28, 2019
31aa33b
test: fix race in test-http2-origin
mildsunrise Jul 30, 2019
19070e4
test: fix nits in test/fixtures/tls-connect.js
lpinca Jul 28, 2019
25aa222
build: generate openssl config for BSD-x86
bnoordhuis Jul 22, 2019
3d51d30
src: large pages fix FreeBSD fix region size
devnexen Jul 17, 2019
470db47
build: remove support for s390 (but not s390x)
bnoordhuis Jul 28, 2019
391fe46
benchmark, http: refactor for code consistency
RamirezAlex Jul 21, 2019
464136f
lib: replace var with let in loaders.js
mbj36 Jun 5, 2019
43acce1
worker: handle calling terminate when kHandler is null
elyalvarado Jun 21, 2019
3e63429
doc: add example about emitter.emit in events documentation
felipedc09 Jun 21, 2019
b6e174b
test: use assert.throws() in test-require-json.js
alejandronanez Jun 21, 2019
d72b682
inspector: report all workers
eugeneo Jul 26, 2019
5f07f49
doc: revoke DEP0089
cjihrig Jul 29, 2019
d9084d2
module: unify package exports test for CJS and ESM
hybrist Jul 24, 2019
d601a0a
src: allow generic C++ callables in SetImmediate()
addaleax Jul 15, 2019
7c80963
doc: include "exports" resolver specification
guybedford Dec 11, 2018
c93df0c
n-api: refactoring napi_create_function testing
Jul 28, 2019
c42eb5d
test: refactoring test_error testing
himself65 Jul 30, 2019
efe9b97
test: refactor test-beforeexit-event-exit using mustNotCall
himself65 Jul 30, 2019
dcef7b8
build: include stubs in shared library
jeroen Jul 29, 2019
2236aff
module: exports error as MODULE_NOT_FOUND
guybedford Jul 31, 2019
c389526
test: add tests for spaces in folder names
PaulBags Jul 23, 2019
0ac6d28
doc: writableFinished is true before 'finish'
ronag Jul 23, 2019
f4abf17
doc: remove legacy mode deprecation in assert
Trott Jul 31, 2019
7d9eb17
http2: destroy when settingsFn throws an error
himself65 Jul 31, 2019
57f5d50
doc: fix sorting nit in sections of http.md
vsemozhetbyt Aug 2, 2019
4b91e4d
report: include network interfaces in report
cjihrig Jul 23, 2019
0f8f552
test: refactor test-fs-stat.js
Trott Aug 1, 2019
bdd442f
doc: describe NODE_OPTIONS interop w/cmd line opts
reasonablytall Aug 1, 2019
4a747f6
Revert "src: remove trace_sync_io_ from env"
ChALkeR Aug 1, 2019
3c52dbe
net: shallow copy option when create Server
himself65 Aug 1, 2019
02a50c3
doc: remove use of you
mhdawson Aug 1, 2019
1f82929
path: improve normalization performance
mscdex Aug 3, 2019
11470d5
deps: upgrade npm to 6.10.2
isaacs Jul 25, 2019
77d8f0c
2019-08-06, Version 12.8.0 (Current)
BridgeAR Aug 6, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
src: allow generic C++ callables in SetImmediate()
Modify the native `SetImmediate()` functions to take generic C++
callables as arguments. This makes passing arguments to the callback
easier, and in particular, it allows passing `std::unique_ptr`s
directly, which in turn makes sure that the data they point to is
deleted if the `Environment` is torn down before the callback can run.

PR-URL: #28704
Reviewed-By: James M Snell <[email protected]>
  • Loading branch information
addaleax authored and targos committed Aug 2, 2019
commit d601a0a9c0af2bf027d649360e9d0ed00b5de9ff
4 changes: 2 additions & 2 deletions src/async_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ struct AsyncWrapObject : public AsyncWrap {
SET_SELF_SIZE(AsyncWrapObject)
};

void AsyncWrap::DestroyAsyncIdsCallback(Environment* env, void* data) {
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env) {
Local<Function> fn = env->async_hooks_destroy_function();

TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
Expand Down Expand Up @@ -642,7 +642,7 @@ void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
}

if (env->destroy_async_id_list()->empty()) {
env->SetUnrefImmediate(DestroyAsyncIdsCallback, nullptr);
env->SetUnrefImmediate(&DestroyAsyncIdsCallback);
}

env->destroy_async_id_list()->push_back(async_id);
Expand Down
2 changes: 1 addition & 1 deletion src/async_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ class AsyncWrap : public BaseObject {
static void EmitTraceEventAfter(ProviderType type, double async_id);
void EmitTraceEventDestroy();

static void DestroyAsyncIdsCallback(Environment* env, void* data);
static void DestroyAsyncIdsCallback(Environment* env);

inline ProviderType provider_type() const;
inline ProviderType set_provider_type(ProviderType provider);
Expand Down
6 changes: 3 additions & 3 deletions src/cares_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -690,9 +690,9 @@ class QueryWrap : public AsyncWrap {
}

void QueueResponseCallback(int status) {
env()->SetImmediate([](Environment*, void* data) {
static_cast<QueryWrap*>(data)->AfterResponse();
}, this, object());
env()->SetImmediate([this](Environment*) {
AfterResponse();
}, object());

channel_->set_query_last_ok(status != ARES_ECONNREFUSED);
channel_->ModifyActivityQueryCount(-1);
Expand Down
67 changes: 50 additions & 17 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -753,33 +753,66 @@ inline void IsolateData::set_options(
options_ = std::move(options);
}

void Environment::CreateImmediate(native_immediate_callback cb,
void* data,
v8::Local<v8::Object> obj,
template <typename Fn>
void Environment::CreateImmediate(Fn&& cb,
v8::Local<v8::Object> keep_alive,
bool ref) {
native_immediate_callbacks_.push_back({
cb,
data,
v8::Global<v8::Object>(isolate_, obj),
ref
});
auto callback = std::make_unique<NativeImmediateCallbackImpl<Fn>>(
std::move(cb),
v8::Global<v8::Object>(isolate(), keep_alive),
ref);
NativeImmediateCallback* prev_tail = native_immediate_callbacks_tail_;

native_immediate_callbacks_tail_ = callback.get();
if (prev_tail != nullptr)
prev_tail->set_next(std::move(callback));
else
native_immediate_callbacks_head_ = std::move(callback);

immediate_info()->count_inc(1);
}

void Environment::SetImmediate(native_immediate_callback cb,
void* data,
v8::Local<v8::Object> obj) {
CreateImmediate(cb, data, obj, true);
template <typename Fn>
void Environment::SetImmediate(Fn&& cb, v8::Local<v8::Object> keep_alive) {
CreateImmediate(std::move(cb), keep_alive, true);

if (immediate_info()->ref_count() == 0)
ToggleImmediateRef(true);
immediate_info()->ref_count_inc(1);
}

void Environment::SetUnrefImmediate(native_immediate_callback cb,
void* data,
v8::Local<v8::Object> obj) {
CreateImmediate(cb, data, obj, false);
template <typename Fn>
void Environment::SetUnrefImmediate(Fn&& cb, v8::Local<v8::Object> keep_alive) {
CreateImmediate(std::move(cb), keep_alive, false);
}

Environment::NativeImmediateCallback::NativeImmediateCallback(bool refed)
: refed_(refed) {}

bool Environment::NativeImmediateCallback::is_refed() const {
return refed_;
}

std::unique_ptr<Environment::NativeImmediateCallback>
Environment::NativeImmediateCallback::get_next() {
return std::move(next_);
}

void Environment::NativeImmediateCallback::set_next(
std::unique_ptr<NativeImmediateCallback> next) {
next_ = std::move(next);
}

template <typename Fn>
Environment::NativeImmediateCallbackImpl<Fn>::NativeImmediateCallbackImpl(
Fn&& callback, v8::Global<v8::Object>&& keep_alive, bool refed)
: NativeImmediateCallback(refed),
callback_(std::move(callback)),
keep_alive_(std::move(keep_alive)) {}

template <typename Fn>
void Environment::NativeImmediateCallbackImpl<Fn>::Call(Environment* env) {
callback_(env);
}

inline bool Environment::can_call_into_js() const {
Expand Down
66 changes: 31 additions & 35 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ Environment::Environment(IsolateData* isolate_data,
[](void* arg) {
Environment* env = static_cast<Environment*>(arg);
if (!env->destroy_async_id_list()->empty())
AsyncWrap::DestroyAsyncIdsCallback(env, nullptr);
AsyncWrap::DestroyAsyncIdsCallback(env);
},
this);

Expand Down Expand Up @@ -642,42 +642,38 @@ void Environment::AtExit(void (*cb)(void* arg), void* arg) {
void Environment::RunAndClearNativeImmediates() {
TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
"RunAndClearNativeImmediates", this);
size_t count = native_immediate_callbacks_.size();
if (count > 0) {
size_t ref_count = 0;
std::vector<NativeImmediateCallback> list;
native_immediate_callbacks_.swap(list);
auto drain_list = [&]() {
TryCatchScope try_catch(this);
for (auto it = list.begin(); it != list.end(); ++it) {
DebugSealHandleScope seal_handle_scope(isolate());
it->cb_(this, it->data_);
if (it->refed_)
ref_count++;
if (UNLIKELY(try_catch.HasCaught())) {
if (!try_catch.HasTerminated())
errors::TriggerUncaughtException(isolate(), try_catch);

// We are done with the current callback. Increase the counter so that
// the steps below make everything *after* the current item part of
// the new list.
it++;

// Bail out, remove the already executed callbacks from list
// and set up a new TryCatch for the other pending callbacks.
std::move_backward(it, list.end(), list.begin() + (list.end() - it));
list.resize(list.end() - it);
return true;
}
size_t ref_count = 0;
size_t count = 0;
std::unique_ptr<NativeImmediateCallback> head;
head.swap(native_immediate_callbacks_head_);
native_immediate_callbacks_tail_ = nullptr;

auto drain_list = [&]() {
TryCatchScope try_catch(this);
for (; head; head = head->get_next()) {
DebugSealHandleScope seal_handle_scope(isolate());
count++;
if (head->is_refed())
ref_count++;

head->Call(this);
if (UNLIKELY(try_catch.HasCaught())) {
if (!try_catch.HasTerminated())
errors::TriggerUncaughtException(isolate(), try_catch);

// We are done with the current callback. Move one iteration along,
// as if we had completed successfully.
head = head->get_next();
return true;
}
return false;
};
while (drain_list()) {}
}
return false;
};
while (head && drain_list()) {}

DCHECK_GE(immediate_info()->count(), count);
immediate_info()->count_dec(count);
immediate_info()->ref_count_dec(ref_count);
}
DCHECK_GE(immediate_info()->count(), count);
immediate_info()->count_dec(count);
immediate_info()->ref_count_dec(ref_count);
}


Expand Down
59 changes: 42 additions & 17 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -1153,15 +1153,15 @@ class Environment : public MemoryRetainer {
return current_value;
}

typedef void (*native_immediate_callback)(Environment* env, void* data);
// cb will be called as cb(env, data) on the next event loop iteration.
// obj will be kept alive between now and after the callback has run.
inline void SetImmediate(native_immediate_callback cb,
void* data,
v8::Local<v8::Object> obj = v8::Local<v8::Object>());
inline void SetUnrefImmediate(native_immediate_callback cb,
void* data,
v8::Local<v8::Object> obj =
// cb will be called as cb(env) on the next event loop iteration.
// keep_alive will be kept alive between now and after the callback has run.
template <typename Fn>
inline void SetImmediate(Fn&& cb,
v8::Local<v8::Object> keep_alive =
v8::Local<v8::Object>());
template <typename Fn>
inline void SetUnrefImmediate(Fn&& cb,
v8::Local<v8::Object> keep_alive =
v8::Local<v8::Object>());
// This needs to be available for the JS-land setImmediate().
void ToggleImmediateRef(bool ref);
Expand Down Expand Up @@ -1226,9 +1226,9 @@ class Environment : public MemoryRetainer {
#endif // HAVE_INSPECTOR

private:
inline void CreateImmediate(native_immediate_callback cb,
void* data,
v8::Local<v8::Object> obj,
template <typename Fn>
inline void CreateImmediate(Fn&& cb,
v8::Local<v8::Object> keep_alive,
bool ref);

inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
Expand Down Expand Up @@ -1352,13 +1352,38 @@ class Environment : public MemoryRetainer {

std::list<ExitCallback> at_exit_functions_;

struct NativeImmediateCallback {
native_immediate_callback cb_;
void* data_;
v8::Global<v8::Object> keep_alive_;
class NativeImmediateCallback {
public:
explicit inline NativeImmediateCallback(bool refed);

virtual ~NativeImmediateCallback() = default;
virtual void Call(Environment* env) = 0;

inline bool is_refed() const;
inline std::unique_ptr<NativeImmediateCallback> get_next();
inline void set_next(std::unique_ptr<NativeImmediateCallback> next);

private:
bool refed_;
std::unique_ptr<NativeImmediateCallback> next_;
};

template <typename Fn>
class NativeImmediateCallbackImpl final : public NativeImmediateCallback {
public:
NativeImmediateCallbackImpl(Fn&& callback,
v8::Global<v8::Object>&& keep_alive,
bool refed);
void Call(Environment* env) override;

private:
Fn callback_;
v8::Global<v8::Object> keep_alive_;
};
std::vector<NativeImmediateCallback> native_immediate_callbacks_;

std::unique_ptr<NativeImmediateCallback> native_immediate_callbacks_head_;
NativeImmediateCallback* native_immediate_callbacks_tail_ = nullptr;

void RunAndClearNativeImmediates();
static void CheckImmediate(uv_check_t* handle);

Expand Down
42 changes: 24 additions & 18 deletions src/node_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,33 @@ class BufferFinalizer : private Finalizer {
public:
// node::Buffer::FreeCallback
static void FinalizeBufferCallback(char* data, void* hint) {
BufferFinalizer* finalizer = static_cast<BufferFinalizer*>(hint);
std::unique_ptr<BufferFinalizer, Deleter> finalizer{
static_cast<BufferFinalizer*>(hint)};
finalizer->_finalize_data = data;
static_cast<node_napi_env>(finalizer->_env)->node_env()
->SetImmediate([](node::Environment* env, void* hint) {
BufferFinalizer* finalizer = static_cast<BufferFinalizer*>(hint);

if (finalizer->_finalize_callback != nullptr) {
v8::HandleScope handle_scope(finalizer->_env->isolate);
v8::Context::Scope context_scope(finalizer->_env->context());

finalizer->_env->CallIntoModuleThrow([&](napi_env env) {
finalizer->_finalize_callback(
env,
finalizer->_finalize_data,
finalizer->_finalize_hint);
});
}

Delete(finalizer);
}, hint);
node::Environment* node_env =
static_cast<node_napi_env>(finalizer->_env)->node_env();
node_env->SetImmediate(
[finalizer = std::move(finalizer)](node::Environment* env) {
if (finalizer->_finalize_callback == nullptr) return;

v8::HandleScope handle_scope(finalizer->_env->isolate);
v8::Context::Scope context_scope(finalizer->_env->context());

finalizer->_env->CallIntoModuleThrow([&](napi_env env) {
finalizer->_finalize_callback(
env,
finalizer->_finalize_data,
finalizer->_finalize_hint);
});
});
}

struct Deleter {
void operator()(BufferFinalizer* finalizer) {
Finalizer::Delete(finalizer);
}
};
};

static inline napi_env NewEnv(v8::Local<v8::Context> context) {
Expand Down
18 changes: 8 additions & 10 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -170,35 +170,33 @@ inline void FileHandle::Close() {

struct err_detail { int ret; int fd; };

err_detail* detail = new err_detail { ret, fd_ };
err_detail detail { ret, fd_ };

if (ret < 0) {
// Do not unref this
env()->SetImmediate([](Environment* env, void* data) {
env()->SetImmediate([detail](Environment* env) {
char msg[70];
std::unique_ptr<err_detail> detail(static_cast<err_detail*>(data));
snprintf(msg, arraysize(msg),
"Closing file descriptor %d on garbage collection failed",
detail->fd);
detail.fd);
// This exception will end up being fatal for the process because
// it is being thrown from within the SetImmediate handler and
// there is no JS stack to bubble it to. In other words, tearing
// down the process is the only reasonable thing we can do here.
HandleScope handle_scope(env->isolate());
env->ThrowUVException(detail->ret, "close", msg);
}, detail);
env->ThrowUVException(detail.ret, "close", msg);
});
return;
}

// If the close was successful, we still want to emit a process warning
// to notify that the file descriptor was gc'd. We want to be noisy about
// this because not explicitly closing the FileHandle is a bug.
env()->SetUnrefImmediate([](Environment* env, void* data) {
std::unique_ptr<err_detail> detail(static_cast<err_detail*>(data));
env()->SetUnrefImmediate([detail](Environment* env) {
ProcessEmitWarning(env,
"Closing file descriptor %d on garbage collection",
detail->fd);
}, detail);
detail.fd);
});
}

void FileHandle::CloseReq::Resolve() {
Expand Down
Loading