@@ -106,6 +106,8 @@ Persistent<String> domain_symbol;
106106// declared in node_internals.h
107107Persistent<Object> process;
108108
109+ static Persistent<Array> domains_stack;
110+
109111static Persistent<Function> process_tickFromSpinner;
110112static Persistent<Function> process_tickCallback;
111113
@@ -127,6 +129,8 @@ static Persistent<String> exit_symbol;
127129static Persistent<String> disposed_symbol;
128130
129131static Persistent<String> emitting_toplevel_domain_error_symbol;
132+ static Persistent<String> _events_symbol;
133+ static Persistent<String> error_symbol;
130134
131135static bool print_eval = false ;
132136static bool force_repl = false ;
@@ -905,25 +909,77 @@ Handle<Value> FromConstructorTemplate(Persistent<FunctionTemplate> t,
905909 return scope.Close (t->GetFunction ()->NewInstance (argc, argv));
906910}
907911
908- static bool IsDomainActive () {
909- if (domain_symbol.IsEmpty ())
910- domain_symbol = NODE_PSYMBOL (" domain" );
912+ static bool DomainHasErrorHandler (const Local<Object>& domain) {
913+ HandleScope scope;
914+
915+ if (_events_symbol.IsEmpty ())
916+ _events_symbol = NODE_PSYMBOL (" _events" );
917+
918+ Local<Value> domain_event_listeners_v = domain->Get (_events_symbol);
919+ if (!domain_event_listeners_v->IsObject ())
920+ return false ;
921+
922+ Local<Object> domain_event_listeners_o =
923+ domain_event_listeners_v.As <Object>();
924+
925+ if (error_symbol.IsEmpty ())
926+ error_symbol = NODE_PSYMBOL (" error" );
927+
928+ Local<Value> domain_error_listeners_v =
929+ domain_event_listeners_o->Get (error_symbol);
930+
931+ if (domain_error_listeners_v->IsFunction () ||
932+ (domain_error_listeners_v->IsArray () &&
933+ domain_error_listeners_v.As <Array>()->Length () > 0 ))
934+ return true ;
935+
936+ return false ;
937+ }
938+
939+ static bool TopDomainHasErrorHandler () {
940+ HandleScope scope;
941+
942+ if (!using_domains)
943+ return false ;
911944
912- Local<Value> domain_v = process->Get (domain_symbol);
945+ Local<Array> domains_stack_array = Local<Array>::New (domains_stack);
946+ if (domains_stack_array->Length () == 0 )
947+ return false ;
913948
914- return domain_v->IsObject ();
949+ uint32_t domains_stack_length = domains_stack_array->Length ();
950+ if (domains_stack_length == 0 )
951+ return false ;
952+
953+ Local<Value> domain_v = domains_stack_array->Get (domains_stack_length - 1 );
954+ if (!domain_v->IsObject ())
955+ return false ;
956+
957+ Local<Object> domain = domain_v.As <Object>();
958+ if (DomainHasErrorHandler (domain))
959+ return true ;
960+
961+ return false ;
915962}
916963
917964bool ShouldAbortOnUncaughtException () {
918965 Local<Value> emitting_toplevel_domain_error_v =
919966 process->Get (emitting_toplevel_domain_error_symbol);
920- return !IsDomainActive () || emitting_toplevel_domain_error_v->BooleanValue ();
967+
968+ return emitting_toplevel_domain_error_v->BooleanValue () ||
969+ !TopDomainHasErrorHandler ();
921970}
922971
923972Handle<Value> UsingDomains (const Arguments& args) {
924973 HandleScope scope;
974+
925975 if (using_domains)
926976 return scope.Close (Undefined ());
977+
978+ if (!args[0 ]->IsArray ()) {
979+ fprintf (stderr, " domains stack must be an array\n " );
980+ abort ();
981+ }
982+
927983 using_domains = true ;
928984 Local<Value> tdc_v = process->Get (String::New (" _tickDomainCallback" ));
929985 Local<Value> ndt_v = process->Get (String::New (" _nextDomainTick" ));
@@ -935,6 +991,9 @@ Handle<Value> UsingDomains(const Arguments& args) {
935991 fprintf (stderr, " process._nextDomainTick assigned to non-function\n " );
936992 abort ();
937993 }
994+
995+ domains_stack = Persistent<Array>::New (args[0 ].As <Array>());
996+
938997 Local<Function> tdc = tdc_v.As <Function>();
939998 Local<Function> ndt = ndt_v.As <Function>();
940999 process->Set (String::New (" _tickCallback" ), tdc);
@@ -2460,7 +2519,10 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
24602519 process->Set (String::NewSymbol (" _tickInfoBox" ), info_box);
24612520
24622521 // pre-set _events object for faster emit checks
2463- process->Set (String::NewSymbol (" _events" ), Object::New ());
2522+ if (_events_symbol.IsEmpty ())
2523+ _events_symbol = NODE_PSYMBOL (" _events" );
2524+
2525+ process->Set (_events_symbol, Object::New ());
24642526
24652527 if (emitting_toplevel_domain_error_symbol.IsEmpty ())
24662528 emitting_toplevel_domain_error_symbol =
0 commit comments