Skip to content

Commit d441c7f

Browse files
trevnorrisaddaleax
authored andcommitted
async_wrap: unroll unnecessarily DRY code
* Because Emit{Before,After}() will always exit the process if there's an exception there's no need to check a return value. This simplifies the conditions and makes {Pre,Post}CallbackExecution() unnecessary. They have been removed and relevant code has been moved to the respective call sites. Which are: * PromiseHook() never needs to run domains, and without a return value to check place the calls to Emit{Before,After}() on location. * The logic in MakeCallback() is simplified by moving the single calls to Emit{Before,After}() then doing a simpler conditional to check if the domain has been disposed. * Change Domain{Enter,Exit}() to return true if the instance has been disposed. Makes the conditional check in MakeCallback() simpler to reason about. * Add UNREACHABLE() after FatalException() to make sure all error handlers have been cleared and the process really does exit. PR-URL: #14722 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Refael Ackermann <[email protected]>
1 parent 94369d8 commit d441c7f

File tree

3 files changed

+50
-65
lines changed

3 files changed

+50
-65
lines changed

src/async-wrap.cc

Lines changed: 43 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ static void DestroyIdsCb(uv_timer_t* handle) {
165165
if (ret.IsEmpty()) {
166166
ClearFatalExceptionHandlers(env);
167167
FatalException(env->isolate(), try_catch);
168+
UNREACHABLE();
168169
}
169170
}
170171
} while (!env->destroy_ids_list()->empty());
@@ -218,69 +219,43 @@ bool DomainExit(Environment* env, v8::Local<v8::Object> object) {
218219
}
219220

220221

221-
static bool PreCallbackExecution(AsyncWrap* wrap, bool run_domain_cbs) {
222-
if (wrap->env()->using_domains() && run_domain_cbs) {
223-
bool is_disposed = DomainEnter(wrap->env(), wrap->object());
224-
if (is_disposed)
225-
return false;
226-
}
227-
228-
return AsyncWrap::EmitBefore(wrap->env(), wrap->get_id());
229-
}
230-
231-
232-
bool AsyncWrap::EmitBefore(Environment* env, double async_id) {
222+
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
233223
AsyncHooks* async_hooks = env->async_hooks();
234224

235-
if (async_hooks->fields()[AsyncHooks::kBefore] > 0) {
236-
Local<Value> uid = Number::New(env->isolate(), async_id);
237-
Local<Function> fn = env->async_hooks_before_function();
238-
TryCatch try_catch(env->isolate());
239-
MaybeLocal<Value> ar = fn->Call(
240-
env->context(), Undefined(env->isolate()), 1, &uid);
241-
if (ar.IsEmpty()) {
242-
ClearFatalExceptionHandlers(env);
243-
FatalException(env->isolate(), try_catch);
244-
return false;
245-
}
246-
}
247-
248-
return true;
249-
}
250-
251-
252-
static bool PostCallbackExecution(AsyncWrap* wrap, bool run_domain_cbs) {
253-
if (!AsyncWrap::EmitAfter(wrap->env(), wrap->get_id()))
254-
return false;
225+
if (async_hooks->fields()[AsyncHooks::kBefore] == 0)
226+
return;
255227

256-
if (wrap->env()->using_domains() && run_domain_cbs) {
257-
bool is_disposed = DomainExit(wrap->env(), wrap->object());
258-
if (is_disposed)
259-
return false;
228+
Local<Value> uid = Number::New(env->isolate(), async_id);
229+
Local<Function> fn = env->async_hooks_before_function();
230+
TryCatch try_catch(env->isolate());
231+
MaybeLocal<Value> ar = fn->Call(
232+
env->context(), Undefined(env->isolate()), 1, &uid);
233+
if (ar.IsEmpty()) {
234+
ClearFatalExceptionHandlers(env);
235+
FatalException(env->isolate(), try_catch);
236+
UNREACHABLE();
260237
}
261-
262-
return true;
263238
}
264239

265-
bool AsyncWrap::EmitAfter(Environment* env, double async_id) {
240+
241+
void AsyncWrap::EmitAfter(Environment* env, double async_id) {
266242
AsyncHooks* async_hooks = env->async_hooks();
267243

268-
// If the callback failed then the after() hooks will be called at the end
269-
// of _fatalException().
270-
if (async_hooks->fields()[AsyncHooks::kAfter] > 0) {
271-
Local<Value> uid = Number::New(env->isolate(), async_id);
272-
Local<Function> fn = env->async_hooks_after_function();
273-
TryCatch try_catch(env->isolate());
274-
MaybeLocal<Value> ar = fn->Call(
275-
env->context(), Undefined(env->isolate()), 1, &uid);
276-
if (ar.IsEmpty()) {
277-
ClearFatalExceptionHandlers(env);
278-
FatalException(env->isolate(), try_catch);
279-
return false;
280-
}
281-
}
244+
if (async_hooks->fields()[AsyncHooks::kAfter] == 0)
245+
return;
282246

283-
return true;
247+
// If the user's callback failed then the after() hooks will be called at the
248+
// end of _fatalException().
249+
Local<Value> uid = Number::New(env->isolate(), async_id);
250+
Local<Function> fn = env->async_hooks_after_function();
251+
TryCatch try_catch(env->isolate());
252+
MaybeLocal<Value> ar = fn->Call(
253+
env->context(), Undefined(env->isolate()), 1, &uid);
254+
if (ar.IsEmpty()) {
255+
ClearFatalExceptionHandlers(env);
256+
FatalException(env->isolate(), try_catch);
257+
UNREACHABLE();
258+
}
284259
}
285260

286261
class PromiseWrap : public AsyncWrap {
@@ -373,9 +348,9 @@ static void PromiseHook(PromiseHookType type, Local<Promise> promise,
373348
CHECK_NE(wrap, nullptr);
374349
if (type == PromiseHookType::kBefore) {
375350
env->async_hooks()->push_ids(wrap->get_id(), wrap->get_trigger_id());
376-
PreCallbackExecution(wrap, false);
351+
AsyncWrap::EmitBefore(wrap->env(), wrap->get_id());
377352
} else if (type == PromiseHookType::kAfter) {
378-
PostCallbackExecution(wrap, false);
353+
AsyncWrap::EmitAfter(wrap->env(), wrap->get_id());
379354
if (env->current_async_id() == wrap->get_id()) {
380355
// This condition might not be true if async_hooks was enabled during
381356
// the promise callback execution.
@@ -687,18 +662,27 @@ MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
687662
get_id(),
688663
get_trigger_id());
689664

690-
if (!PreCallbackExecution(this, true)) {
665+
// Return v8::Undefined() because returning an empty handle will cause
666+
// ToLocalChecked() to abort.
667+
if (env()->using_domains() && DomainEnter(env(), object())) {
691668
return Undefined(env()->isolate());
692669
}
693670

694-
// Finally... Get to running the user's callback.
671+
// No need to check a return value because the application will exit if an
672+
// exception occurs.
673+
AsyncWrap::EmitBefore(env(), get_id());
674+
695675
MaybeLocal<Value> ret = cb->Call(env()->context(), object(), argc, argv);
696676

697677
if (ret.IsEmpty()) {
698678
return ret;
699679
}
700680

701-
if (!PostCallbackExecution(this, true)) {
681+
AsyncWrap::EmitAfter(env(), get_id());
682+
683+
// Return v8::Undefined() because returning an empty handle will cause
684+
// ToLocalChecked() to abort.
685+
if (env()->using_domains() && DomainExit(env(), object())) {
702686
return Undefined(env()->isolate());
703687
}
704688

src/async-wrap.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ class AsyncWrap : public BaseObject {
111111
double id,
112112
double trigger_id);
113113

114-
static bool EmitBefore(Environment* env, double id);
115-
static bool EmitAfter(Environment* env, double id);
114+
static void EmitBefore(Environment* env, double id);
115+
static void EmitAfter(Environment* env, double id);
116116

117117
inline ProviderType provider_type() const;
118118

@@ -146,6 +146,7 @@ class AsyncWrap : public BaseObject {
146146

147147
void LoadAsyncWrapperInfo(Environment* env);
148148

149+
// Return value is an indicator whether the domain was disposed.
149150
bool DomainEnter(Environment* env, v8::Local<v8::Object> object);
150151
bool DomainExit(Environment* env, v8::Local<v8::Object> object);
151152

src/node.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,8 +1328,9 @@ MaybeLocal<Value> MakeCallback(Environment* env,
13281328
asyncContext.trigger_async_id);
13291329

13301330
if (asyncContext.async_id != 0) {
1331-
if (!AsyncWrap::EmitBefore(env, asyncContext.async_id))
1332-
return Local<Value>();
1331+
// No need to check a return value because the application will exit if
1332+
// an exception occurs.
1333+
AsyncWrap::EmitBefore(env, asyncContext.async_id);
13331334
}
13341335

13351336
ret = callback->Call(env->context(), recv, argc, argv);
@@ -1342,8 +1343,7 @@ MaybeLocal<Value> MakeCallback(Environment* env,
13421343
}
13431344

13441345
if (asyncContext.async_id != 0) {
1345-
if (!AsyncWrap::EmitAfter(env, asyncContext.async_id))
1346-
return Local<Value>();
1346+
AsyncWrap::EmitAfter(env, asyncContext.async_id);
13471347
}
13481348
}
13491349

0 commit comments

Comments
 (0)