Skip to content

Commit

Permalink
src: yield empty maybes for failed AsyncWrap::MakeCallback calls
Browse files Browse the repository at this point in the history
Use an empty `MaybeLocal<Value>` as the return value for
`AsyncWrap::MakeCallback()` if an exception occurred,
regardless of `MakeCallback` depth.

Unfortunately, the public API can not make this switch without
a breaking change (and possibly some kind of deprecation/renaming).

PR-URL: #22078
Backport-PR-URL: #22505
Reviewed-By: Michaël Zasso <targos@protonmail.com>
  • Loading branch information
addaleax authored and targos committed Sep 3, 2018
1 parent 02e3daa commit 198cf41
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 19 deletions.
5 changes: 3 additions & 2 deletions src/callback_scope.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ InternalCallbackScope::InternalCallbackScope(Environment* env,
AsyncWrap::EmitBefore(env, asyncContext.async_id);
}

if (!IsInnerMakeCallback()) {
CHECK_GE(env->makecallback_depth(), 1);
if (env->makecallback_depth() == 1) {
env->tick_info()->set_has_thrown(false);
}

Expand Down Expand Up @@ -91,7 +92,7 @@ void InternalCallbackScope::Close() {
AsyncWrap::EmitAfter(env_, async_context_.async_id);
}

if (IsInnerMakeCallback()) {
if (env_->makecallback_depth() > 1) {
return;
}

Expand Down
4 changes: 2 additions & 2 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ inline Environment::AsyncCallbackScope::~AsyncCallbackScope() {
env_->makecallback_cntr_--;
}

inline bool Environment::AsyncCallbackScope::in_makecallback() const {
return env_->makecallback_cntr_ > 1;
inline size_t Environment::makecallback_depth() const {
return makecallback_cntr_;
}

inline Environment::ImmediateInfo::ImmediateInfo(v8::Isolate* isolate)
Expand Down
3 changes: 2 additions & 1 deletion src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,14 +503,15 @@ class Environment {
AsyncCallbackScope() = delete;
explicit AsyncCallbackScope(Environment* env);
~AsyncCallbackScope();
inline bool in_makecallback() const;

private:
Environment* env_;

DISALLOW_COPY_AND_ASSIGN(AsyncCallbackScope);
};

inline size_t makecallback_depth() const;

class ImmediateInfo {
public:
inline AliasedBuffer<uint32_t, v8::Uint32Array>& fields();
Expand Down
18 changes: 11 additions & 7 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ MaybeLocal<Value> InternalMakeCallback(Environment* env,
CHECK(!recv.IsEmpty());
InternalCallbackScope scope(env, recv, asyncContext);
if (scope.Failed()) {
return Undefined(env->isolate());
return MaybeLocal<Value>();
}

Local<Function> domain_cb = env->domain_callback();
Expand All @@ -773,15 +773,13 @@ MaybeLocal<Value> InternalMakeCallback(Environment* env,
}

if (ret.IsEmpty()) {
// NOTE: For backwards compatibility with public API we return Undefined()
// if the top level call threw.
scope.MarkAsFailed();
return scope.IsInnerMakeCallback() ? ret : Undefined(env->isolate());
return MaybeLocal<Value>();
}

scope.Close();
if (scope.Failed()) {
return Undefined(env->isolate());
return MaybeLocal<Value>();
}

return ret;
Expand Down Expand Up @@ -833,8 +831,14 @@ MaybeLocal<Value> MakeCallback(Isolate* isolate,
// the two contexts need not be the same.
Environment* env = Environment::GetCurrent(callback->CreationContext());
Context::Scope context_scope(env->context());
return InternalMakeCallback(env, recv, callback,
argc, argv, asyncContext);
MaybeLocal<Value> ret = InternalMakeCallback(env, recv, callback,
argc, argv, asyncContext);
if (ret.IsEmpty() && env->makecallback_depth() == 0) {
// This is only for legacy compatiblity and we may want to look into
// removing/adjusting it.
return Undefined(env->isolate());
}
return ret;
}


Expand Down
3 changes: 0 additions & 3 deletions src/node_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,9 +543,6 @@ class InternalCallbackScope {

inline bool Failed() const { return failed_; }
inline void MarkAsFailed() { failed_ = true; }
inline bool IsInnerMakeCallback() const {
return callback_scope_.in_makecallback();
}

private:
Environment* env_;
Expand Down
8 changes: 4 additions & 4 deletions src/timer_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Integer;
using v8::Local;
using v8::MaybeLocal;
using v8::Object;
using v8::String;
using v8::Value;
Expand Down Expand Up @@ -138,13 +139,12 @@ class TimerWrap : public HandleWrap {
Environment* env = wrap->env();
HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context());
Local<Value> ret;
MaybeLocal<Value> ret;
Local<Value> args[1];
do {
args[0] = env->GetNow();
ret = wrap->MakeCallback(env->timers_callback_function(), 1, args)
.ToLocalChecked();
} while (ret->IsUndefined() &&
ret = wrap->MakeCallback(env->timers_callback_function(), 1, args);
} while ((ret.IsEmpty() || ret.ToLocalChecked()->IsUndefined()) &&
!env->tick_info()->has_thrown() &&
env->can_call_into_js() &&
wrap->object()->Get(env->context(),
Expand Down

0 comments on commit 198cf41

Please sign in to comment.