@@ -161,6 +161,7 @@ using v8::SealHandleScope;
161161using v8::String;
162162using v8::TryCatch;
163163using v8::Uint32Array;
164+ using v8::Undefined;
164165using v8::V8;
165166using v8::Value;
166167
@@ -1311,85 +1312,153 @@ void AddPromiseHook(v8::Isolate* isolate, promise_hook_func fn, void* arg) {
13111312 env->AddPromiseHook (fn, arg);
13121313}
13131314
1315+ class InternalCallbackScope {
1316+ public:
1317+ InternalCallbackScope (Environment* env,
1318+ Local<Object> object,
1319+ const async_context& asyncContext);
1320+ ~InternalCallbackScope ();
1321+ void Close ();
1322+
1323+ inline bool Failed () const { return failed_; }
1324+ inline void MarkAsFailed () { failed_ = true ; }
1325+ inline bool IsInnerMakeCallback () const {
1326+ return callback_scope_.in_makecallback ();
1327+ }
1328+
1329+ private:
1330+ Environment* env_;
1331+ async_context async_context_;
1332+ v8::Local<v8::Object> object_;
1333+ Environment::AsyncCallbackScope callback_scope_;
1334+ bool failed_ = false ;
1335+ bool pushed_ids_ = false ;
1336+ bool closed_ = false ;
1337+ };
13141338
1315- MaybeLocal<Value> MakeCallback (Environment* env,
1316- Local<Value> recv,
1317- const Local<Function> callback,
1318- int argc,
1319- Local<Value> argv[],
1320- async_context asyncContext) {
1321- // If you hit this assertion, you forgot to enter the v8::Context first.
1322- CHECK_EQ (env->context (), env->isolate ()->GetCurrentContext ());
1339+ CallbackScope::CallbackScope (Isolate* isolate,
1340+ Local<Object> object,
1341+ async_context asyncContext)
1342+ : private_(new InternalCallbackScope(Environment::GetCurrent(isolate),
1343+ object,
1344+ asyncContext)),
1345+ try_catch_ (isolate) {
1346+ try_catch_.SetVerbose (true );
1347+ }
13231348
1324- Local<Object> object;
1349+ CallbackScope::~CallbackScope () {
1350+ if (try_catch_.HasCaught ())
1351+ private_->MarkAsFailed ();
1352+ delete private_;
1353+ }
13251354
1326- Environment::AsyncCallbackScope callback_scope (env);
1327- bool disposed_domain = false ;
1355+ InternalCallbackScope::InternalCallbackScope (Environment* env,
1356+ Local<Object> object,
1357+ const async_context& asyncContext)
1358+ : env_(env),
1359+ async_context_ (asyncContext),
1360+ object_(object),
1361+ callback_scope_(env) {
1362+ CHECK (!object.IsEmpty ());
13281363
1329- if (recv->IsObject ()) {
1330- object = recv.As <Object>();
1331- }
1364+ // If you hit this assertion, you forgot to enter the v8::Context first.
1365+ CHECK_EQ (env->context (), env->isolate ()->GetCurrentContext ());
13321366
13331367 if (env->using_domains ()) {
1334- CHECK (recv-> IsObject () );
1335- disposed_domain = DomainEnter (env, object);
1336- if (disposed_domain) return Undefined (env-> isolate ()) ;
1368+ failed_ = DomainEnter (env, object_ );
1369+ if (failed_)
1370+ return ;
13371371 }
13381372
1339- MaybeLocal<Value> ret;
1373+ if (asyncContext.async_id != 0 ) {
1374+ // No need to check a return value because the application will exit if
1375+ // an exception occurs.
1376+ AsyncWrap::EmitBefore (env, asyncContext.async_id );
1377+ }
13401378
1341- {
1342- AsyncHooks::ExecScope exec_scope (env, asyncContext.async_id ,
1343- asyncContext.trigger_async_id );
1379+ env->async_hooks ()->push_ids (async_context_.async_id ,
1380+ async_context_.trigger_async_id );
1381+ pushed_ids_ = true ;
1382+ }
13441383
1345- if (asyncContext.async_id != 0 ) {
1346- // No need to check a return value because the application will exit if
1347- // an exception occurs.
1348- AsyncWrap::EmitBefore (env, asyncContext.async_id );
1349- }
1384+ InternalCallbackScope::~InternalCallbackScope () {
1385+ Close ();
1386+ }
13501387
1351- ret = callback->Call (env->context (), recv, argc, argv);
1388+ void InternalCallbackScope::Close () {
1389+ if (closed_) return ;
1390+ closed_ = true ;
13521391
1353- if (ret.IsEmpty ()) {
1354- // NOTE: For backwards compatibility with public API we return Undefined()
1355- // if the top level call threw.
1356- return callback_scope.in_makecallback () ?
1357- ret : Undefined (env->isolate ());
1358- }
1392+ if (pushed_ids_)
1393+ env_->async_hooks ()->pop_ids (async_context_.async_id );
13591394
1360- if (asyncContext.async_id != 0 ) {
1361- AsyncWrap::EmitAfter (env, asyncContext.async_id );
1362- }
1395+ if (failed_) return ;
1396+
1397+ if (async_context_.async_id != 0 ) {
1398+ AsyncWrap::EmitAfter (env_, async_context_.async_id );
13631399 }
13641400
1365- if (env ->using_domains ()) {
1366- disposed_domain = DomainExit (env, object );
1367- if (disposed_domain ) return Undefined (env-> isolate ()) ;
1401+ if (env_ ->using_domains ()) {
1402+ failed_ = DomainExit (env_, object_ );
1403+ if (failed_ ) return ;
13681404 }
13691405
1370- if (callback_scope. in_makecallback ()) {
1371- return ret ;
1406+ if (IsInnerMakeCallback ()) {
1407+ return ;
13721408 }
13731409
1374- Environment::TickInfo* tick_info = env ->tick_info ();
1410+ Environment::TickInfo* tick_info = env_ ->tick_info ();
13751411
13761412 if (tick_info->length () == 0 ) {
1377- env ->isolate ()->RunMicrotasks ();
1413+ env_ ->isolate ()->RunMicrotasks ();
13781414 }
13791415
13801416 // Make sure the stack unwound properly. If there are nested MakeCallback's
13811417 // then it should return early and not reach this code.
1382- CHECK_EQ (env ->current_async_id (), asyncContext. async_id );
1383- CHECK_EQ (env ->trigger_id (), asyncContext. trigger_async_id );
1418+ CHECK_EQ (env_ ->current_async_id (), 0 );
1419+ CHECK_EQ (env_ ->trigger_id (), 0 );
13841420
1385- Local<Object> process = env ->process_object ();
1421+ Local<Object> process = env_ ->process_object ();
13861422
13871423 if (tick_info->length () == 0 ) {
13881424 tick_info->set_index (0 );
1389- return ret;
1425+ return ;
1426+ }
1427+
1428+ CHECK_EQ (env_->current_async_id (), 0 );
1429+ CHECK_EQ (env_->trigger_id (), 0 );
1430+
1431+ if (env_->tick_callback_function ()->Call (process, 0 , nullptr ).IsEmpty ()) {
1432+ failed_ = true ;
1433+ }
1434+ }
1435+
1436+ MaybeLocal<Value> InternalMakeCallback (Environment* env,
1437+ Local<Object> recv,
1438+ const Local<Function> callback,
1439+ int argc,
1440+ Local<Value> argv[],
1441+ async_context asyncContext) {
1442+ InternalCallbackScope scope (env, recv, asyncContext);
1443+ if (scope.Failed ()) {
1444+ return Undefined (env->isolate ());
1445+ }
1446+
1447+ MaybeLocal<Value> ret;
1448+
1449+ {
1450+ ret = callback->Call (env->context (), recv, argc, argv);
1451+
1452+ if (ret.IsEmpty ()) {
1453+ // NOTE: For backwards compatibility with public API we return Undefined()
1454+ // if the top level call threw.
1455+ scope.MarkAsFailed ();
1456+ return scope.IsInnerMakeCallback () ? ret : Undefined (env->isolate ());
1457+ }
13901458 }
13911459
1392- if (env->tick_callback_function ()->Call (process, 0 , nullptr ).IsEmpty ()) {
1460+ scope.Close ();
1461+ if (scope.Failed ()) {
13931462 return Undefined (env->isolate ());
13941463 }
13951464
@@ -1442,8 +1511,8 @@ MaybeLocal<Value> MakeCallback(Isolate* isolate,
14421511 // the two contexts need not be the same.
14431512 Environment* env = Environment::GetCurrent (callback->CreationContext ());
14441513 Context::Scope context_scope (env->context ());
1445- return MakeCallback (env, recv. As <Value>() , callback, argc, argv ,
1446- asyncContext);
1514+ return InternalMakeCallback (env, recv, callback,
1515+ argc, argv, asyncContext);
14471516}
14481517
14491518
0 commit comments