@@ -158,6 +158,7 @@ using v8::SealHandleScope;
158
158
using v8::String;
159
159
using v8::TryCatch;
160
160
using v8::Uint32Array;
161
+ using v8::Undefined;
161
162
using v8::V8;
162
163
using v8::Value;
163
164
@@ -1344,85 +1345,153 @@ void AddPromiseHook(v8::Isolate* isolate, promise_hook_func fn, void* arg) {
1344
1345
env->AddPromiseHook (fn, arg);
1345
1346
}
1346
1347
1348
+ class InternalCallbackScope {
1349
+ public:
1350
+ InternalCallbackScope (Environment* env,
1351
+ Local<Object> object,
1352
+ const async_context& asyncContext);
1353
+ ~InternalCallbackScope ();
1354
+ void Close ();
1355
+
1356
+ inline bool Failed () const { return failed_; }
1357
+ inline void MarkAsFailed () { failed_ = true ; }
1358
+ inline bool IsInnerMakeCallback () const {
1359
+ return callback_scope_.in_makecallback ();
1360
+ }
1361
+
1362
+ private:
1363
+ Environment* env_;
1364
+ async_context async_context_;
1365
+ v8::Local<v8::Object> object_;
1366
+ Environment::AsyncCallbackScope callback_scope_;
1367
+ bool failed_ = false ;
1368
+ bool pushed_ids_ = false ;
1369
+ bool closed_ = false ;
1370
+ };
1371
+
1372
+ CallbackScope::CallbackScope (Isolate* isolate,
1373
+ Local<Object> object,
1374
+ async_context asyncContext)
1375
+ : private_(new InternalCallbackScope(Environment::GetCurrent(isolate),
1376
+ object,
1377
+ asyncContext)),
1378
+ try_catch_ (isolate) {
1379
+ try_catch_.SetVerbose (true );
1380
+ }
1381
+
1382
+ CallbackScope::~CallbackScope () {
1383
+ if (try_catch_.HasCaught ())
1384
+ private_->MarkAsFailed ();
1385
+ delete private_;
1386
+ }
1387
+
1388
+ InternalCallbackScope::InternalCallbackScope (Environment* env,
1389
+ Local<Object> object,
1390
+ const async_context& asyncContext)
1391
+ : env_(env),
1392
+ async_context_ (asyncContext),
1393
+ object_(object),
1394
+ callback_scope_(env) {
1395
+ CHECK (!object.IsEmpty ());
1347
1396
1348
- MaybeLocal<Value> MakeCallback (Environment* env,
1349
- Local<Value> recv,
1350
- const Local<Function> callback,
1351
- int argc,
1352
- Local<Value> argv[],
1353
- async_context asyncContext) {
1354
1397
// If you hit this assertion, you forgot to enter the v8::Context first.
1355
1398
CHECK_EQ (env->context (), env->isolate ()->GetCurrentContext ());
1356
1399
1357
- Local<Object> object;
1358
-
1359
- Environment::AsyncCallbackScope callback_scope (env);
1360
- bool disposed_domain = false ;
1361
-
1362
- if (recv->IsObject ()) {
1363
- object = recv.As <Object>();
1400
+ if (env->using_domains ()) {
1401
+ failed_ = DomainEnter (env, object_);
1402
+ if (failed_)
1403
+ return ;
1364
1404
}
1365
1405
1366
- if (env-> using_domains () ) {
1367
- CHECK (recv-> IsObject ());
1368
- disposed_domain = DomainEnter (env, object);
1369
- if (disposed_domain) return Undefined ( env-> isolate () );
1406
+ if (asyncContext. async_id != 0 ) {
1407
+ // No need to check a return value because the application will exit if
1408
+ // an exception occurs.
1409
+ AsyncWrap::EmitBefore ( env, asyncContext. async_id );
1370
1410
}
1371
1411
1372
- MaybeLocal<Value> ret;
1412
+ env->async_hooks ()->push_ids (async_context_.async_id ,
1413
+ async_context_.trigger_async_id );
1414
+ pushed_ids_ = true ;
1415
+ }
1373
1416
1374
- {
1375
- AsyncHooks::ExecScope exec_scope (env, asyncContext. async_id ,
1376
- asyncContext. trigger_async_id );
1417
+ InternalCallbackScope::~InternalCallbackScope () {
1418
+ Close ();
1419
+ }
1377
1420
1378
- if (asyncContext.async_id != 0 ) {
1379
- // No need to check a return value because the application will exit if
1380
- // an exception occurs.
1381
- AsyncWrap::EmitBefore (env, asyncContext.async_id );
1382
- }
1421
+ void InternalCallbackScope::Close () {
1422
+ if (closed_) return ;
1423
+ closed_ = true ;
1383
1424
1384
- ret = callback->Call (env->context (), recv, argc, argv);
1425
+ if (pushed_ids_)
1426
+ env_->async_hooks ()->pop_ids (async_context_.async_id );
1385
1427
1386
- if (ret.IsEmpty ()) {
1387
- // NOTE: For backwards compatibility with public API we return Undefined()
1388
- // if the top level call threw.
1389
- return callback_scope.in_makecallback () ?
1390
- ret : Undefined (env->isolate ());
1391
- }
1428
+ if (failed_) return ;
1392
1429
1393
- if (asyncContext.async_id != 0 ) {
1394
- AsyncWrap::EmitAfter (env, asyncContext.async_id );
1395
- }
1430
+ if (async_context_.async_id != 0 ) {
1431
+ AsyncWrap::EmitAfter (env_, async_context_.async_id );
1396
1432
}
1397
1433
1398
- if (env ->using_domains ()) {
1399
- disposed_domain = DomainExit (env, object );
1400
- if (disposed_domain ) return Undefined (env-> isolate ()) ;
1434
+ if (env_ ->using_domains ()) {
1435
+ failed_ = DomainExit (env_, object_ );
1436
+ if (failed_ ) return ;
1401
1437
}
1402
1438
1403
- if (callback_scope. in_makecallback ()) {
1404
- return ret ;
1439
+ if (IsInnerMakeCallback ()) {
1440
+ return ;
1405
1441
}
1406
1442
1407
- Environment::TickInfo* tick_info = env ->tick_info ();
1443
+ Environment::TickInfo* tick_info = env_ ->tick_info ();
1408
1444
1409
1445
if (tick_info->length () == 0 ) {
1410
- env ->isolate ()->RunMicrotasks ();
1446
+ env_ ->isolate ()->RunMicrotasks ();
1411
1447
}
1412
1448
1413
1449
// Make sure the stack unwound properly. If there are nested MakeCallback's
1414
1450
// then it should return early and not reach this code.
1415
- CHECK_EQ (env ->current_async_id (), asyncContext. async_id );
1416
- CHECK_EQ (env ->trigger_id (), asyncContext. trigger_async_id );
1451
+ CHECK_EQ (env_ ->current_async_id (), 0 );
1452
+ CHECK_EQ (env_ ->trigger_id (), 0 );
1417
1453
1418
- Local<Object> process = env ->process_object ();
1454
+ Local<Object> process = env_ ->process_object ();
1419
1455
1420
1456
if (tick_info->length () == 0 ) {
1421
1457
tick_info->set_index (0 );
1422
- return ret;
1458
+ return ;
1459
+ }
1460
+
1461
+ CHECK_EQ (env_->current_async_id (), 0 );
1462
+ CHECK_EQ (env_->trigger_id (), 0 );
1463
+
1464
+ if (env_->tick_callback_function ()->Call (process, 0 , nullptr ).IsEmpty ()) {
1465
+ failed_ = true ;
1466
+ }
1467
+ }
1468
+
1469
+ MaybeLocal<Value> InternalMakeCallback (Environment* env,
1470
+ Local<Object> recv,
1471
+ const Local<Function> callback,
1472
+ int argc,
1473
+ Local<Value> argv[],
1474
+ async_context asyncContext) {
1475
+ InternalCallbackScope scope (env, recv, asyncContext);
1476
+ if (scope.Failed ()) {
1477
+ return Undefined (env->isolate ());
1478
+ }
1479
+
1480
+ MaybeLocal<Value> ret;
1481
+
1482
+ {
1483
+ ret = callback->Call (env->context (), recv, argc, argv);
1484
+
1485
+ if (ret.IsEmpty ()) {
1486
+ // NOTE: For backwards compatibility with public API we return Undefined()
1487
+ // if the top level call threw.
1488
+ scope.MarkAsFailed ();
1489
+ return scope.IsInnerMakeCallback () ? ret : Undefined (env->isolate ());
1490
+ }
1423
1491
}
1424
1492
1425
- if (env->tick_callback_function ()->Call (process, 0 , nullptr ).IsEmpty ()) {
1493
+ scope.Close ();
1494
+ if (scope.Failed ()) {
1426
1495
return Undefined (env->isolate ());
1427
1496
}
1428
1497
@@ -1475,8 +1544,8 @@ MaybeLocal<Value> MakeCallback(Isolate* isolate,
1475
1544
// the two contexts need not be the same.
1476
1545
Environment* env = Environment::GetCurrent (callback->CreationContext ());
1477
1546
Context::Scope context_scope (env->context ());
1478
- return MakeCallback (env, recv. As <Value>() , callback, argc, argv ,
1479
- asyncContext);
1547
+ return InternalMakeCallback (env, recv, callback,
1548
+ argc, argv, asyncContext);
1480
1549
}
1481
1550
1482
1551
0 commit comments