Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1411,9 +1411,19 @@ void Environment::RunAndClearInterrupts() {
}
}

bool Environment::HasNativeImmediates() const {
return native_immediates_.size() > 0 ||
native_immediates_threadsafe_.size() > 0 ||
native_immediates_interrupts_.size() > 0;
}

void Environment::RunAndClearNativeImmediates(bool only_refed) {
TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment),
"RunAndClearNativeImmediates");
if (!HasNativeImmediates()) {
return;
}

HandleScope handle_scope(isolate_);
// In case the Isolate is no longer accessible just use an empty Local. This
// is not an issue for InternalCallbackScope as this case is already handled
Expand Down Expand Up @@ -1586,6 +1596,9 @@ void Environment::CheckImmediate(uv_check_t* handle) {
Environment* env = Environment::from_immediate_check_handle(handle);
TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "CheckImmediate");

if (env->immediate_info()->count() == 0 && !env->HasNativeImmediates())
return;

HandleScope scope(env->isolate());
Context::Scope context_scope(env->context());

Expand Down
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,7 @@ class Environment final : public MemoryRetainer {

void RunAndClearNativeImmediates(bool only_refed = false);
void RunAndClearInterrupts();
bool HasNativeImmediates() const;

uv_buf_t allocate_managed_buffer(const size_t suggested_size);
std::unique_ptr<v8::BackingStore> release_managed_buffer(const uv_buf_t& buf);
Expand Down
63 changes: 63 additions & 0 deletions test/cctest/test_environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,69 @@ TEST_F(EnvironmentTest, SetImmediateCleanup) {
EXPECT_EQ(called_unref, 0);
}

TEST_F(EnvironmentTest, RunAndClearNativeImmediatesSkipsEmptyScope) {
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
Env env{handle_scope, argv};
v8::Local<v8::Context> context = env.context();

using IntVec = std::vector<int>;
IntVec callback_calls;
v8::Local<v8::Function> must_call =
v8::Function::New(
context,
[](const v8::FunctionCallbackInfo<v8::Value>& info) {
IntVec* callback_calls =
static_cast<IntVec*>(info.Data().As<v8::External>()->Value(
v8::kExternalPointerTypeTagDefault));
callback_calls->push_back(info[0].As<v8::Int32>()->Value());
},
v8::External::New(isolate_,
static_cast<void*>(&callback_calls),
v8::kExternalPointerTypeTagDefault))
.ToLocalChecked();
context->Global()
->Set(context,
v8::String::NewFromUtf8Literal(isolate_, "mustCall"),
must_call)
.Check();

v8::Local<v8::Function> eval_in_env =
node::LoadEnvironment(*env, "return eval;")
.ToLocalChecked()
.As<v8::Function>();

v8::Local<v8::Value> queue_microtask = v8::String::NewFromUtf8Literal(
isolate_, "Promise.resolve().then(() => mustCall(1));");
eval_in_env->Call(context, v8::Null(isolate_), 1, &queue_microtask)
.ToLocalChecked();
EXPECT_TRUE(callback_calls.empty());
(*env)->RunAndClearNativeImmediates();
EXPECT_TRUE(callback_calls.empty());

context->GetMicrotaskQueue()->PerformCheckpoint(isolate_);
EXPECT_EQ(callback_calls, (IntVec{1}));
callback_calls.clear();

queue_microtask = v8::String::NewFromUtf8Literal(
isolate_, "Promise.resolve().then(() => mustCall(2));");
eval_in_env->Call(context, v8::Null(isolate_), 1, &queue_microtask)
.ToLocalChecked();
EXPECT_TRUE(callback_calls.empty());

bool native_immediate_called = false;
(*env)->SetImmediate(
[&](node::Environment* env_arg) {
EXPECT_EQ(env_arg, *env);
native_immediate_called = true;
},
node::CallbackFlags::kRefed);

(*env)->RunAndClearNativeImmediates();
EXPECT_TRUE(native_immediate_called);
EXPECT_EQ(callback_calls, (IntVec{2}));
}

static char hello[] = "hello";

TEST_F(EnvironmentTest, BufferWithFreeCallbackIsDetached) {
Expand Down
Loading