3737#include " req-wrap.h"
3838#include " req-wrap-inl.h"
3939#include " string_bytes.h"
40+ #include " track-promise.h"
4041#include " util.h"
4142#include " uv.h"
4243#include " libplatform/libplatform.h"
@@ -104,6 +105,7 @@ using v8::Array;
104105using v8::ArrayBuffer;
105106using v8::Boolean;
106107using v8::Context;
108+ using v8::Debug;
107109using v8::EscapableHandleScope;
108110using v8::Exception;
109111using v8::Function;
@@ -118,6 +120,7 @@ using v8::Locker;
118120using v8::MaybeLocal;
119121using v8::Message;
120122using v8::Name;
123+ using v8::NativeWeakMap;
121124using v8::Null;
122125using v8::Number;
123126using v8::Object;
@@ -127,6 +130,7 @@ using v8::PromiseRejectMessage;
127130using v8::PropertyCallbackInfo;
128131using v8::ScriptOrigin;
129132using v8::SealHandleScope;
133+ using v8::Set;
130134using v8::String;
131135using v8::TryCatch;
132136using v8::Uint32;
@@ -1136,14 +1140,77 @@ void PromiseRejectCallback(PromiseRejectMessage message) {
11361140 callback->Call (process, arraysize (args), args);
11371141}
11381142
1143+ Local<Value> GetPromiseReason (Environment* env, Local<Value> promise) {
1144+ Local<Function> fn = env->promise_unhandled_rejection ();
1145+
1146+ Local<Value> internalProps =
1147+ Debug::GetInternalProperties (env->isolate (),
1148+ promise).ToLocalChecked ().As <Value>();
1149+
1150+ // If fn is empty we'll almost certainly have to panic anyways
1151+ return fn->Call (env->context (), Null (env->isolate ()), 1 ,
1152+ &internalProps).ToLocalChecked ();
1153+ }
1154+
1155+ void OnPromiseGC (const FunctionCallbackInfo<Value>& args) {
1156+ Environment* env = Environment::GetCurrent (args);
1157+
1158+ CHECK (args[0 ]->IsObject ());
1159+ Local<Object> promise = args[0 ].As <Object>();
1160+
1161+ TrackPromise::New (env->isolate (), promise);
1162+
1163+ Local<Value> err = GetPromiseReason (env, promise);
1164+ Local<NativeWeakMap> unhandled_reject_map =
1165+ env->promise_unhandled_reject_map ();
1166+ Local<Set> unhandled_reject_keys =
1167+ env->promise_unhandled_reject_keys ();
1168+
1169+ if (unhandled_reject_keys->AsArray ()->Length () > 1000 ) {
1170+ return ;
1171+ }
1172+
1173+ if (!unhandled_reject_map->Has (err) && !err->IsUndefined ()) {
1174+ unhandled_reject_map->Set (err, promise);
1175+ CHECK (!unhandled_reject_keys->Add (env->context (), err).IsEmpty ());
1176+ }
1177+ }
1178+
1179+ void UntrackPromise (const FunctionCallbackInfo<Value>& args) {
1180+ Environment* env = Environment::GetCurrent (args);
1181+
1182+ CHECK (args[0 ]->IsObject ());
1183+ Local<Value> promise = args[0 ].As <Value>();
1184+
1185+ Local<Value> err = GetPromiseReason (env, promise);
1186+ Local<NativeWeakMap> unhandled_reject_map =
1187+ env->promise_unhandled_reject_map ();
1188+ Local<Set> unhandled_reject_keys =
1189+ env->promise_unhandled_reject_keys ();
1190+
1191+ if (unhandled_reject_keys->Has (env->context (), err).IsJust ()) {
1192+ CHECK (unhandled_reject_keys->Delete (env->context (), err).IsJust ());
1193+ unhandled_reject_map->Delete (err);
1194+ }
1195+ }
1196+
11391197void SetupPromises (const FunctionCallbackInfo<Value>& args) {
11401198 Environment* env = Environment::GetCurrent (args);
11411199 Isolate* isolate = env->isolate ();
11421200
1201+ env->set_promise_unhandled_reject_map (NativeWeakMap::New (isolate));
1202+ env->set_promise_unhandled_reject_keys (Set::New (isolate));\
1203+
11431204 CHECK (args[0 ]->IsFunction ());
1205+ CHECK (args[1 ]->IsFunction ());
1206+ CHECK (args[2 ]->IsObject ());
11441207
11451208 isolate->SetPromiseRejectCallback (PromiseRejectCallback);
11461209 env->set_promise_reject_function (args[0 ].As <Function>());
1210+ env->set_promise_unhandled_rejection (args[1 ].As <Function>());
1211+
1212+ env->SetMethod (args[2 ].As <Object>(), " onPromiseGC" , OnPromiseGC);
1213+ env->SetMethod (args[2 ].As <Object>(), " untrackPromise" , UntrackPromise);
11471214
11481215 env->process_object ()->Delete (
11491216 env->context (),
@@ -1572,10 +1639,17 @@ void AppendExceptionLine(Environment* env,
15721639 PrintErrorString (" \n %s" , arrow);
15731640}
15741641
1642+ void ReportPromiseRejection (Isolate* isolate, Local<Value> promise) {
1643+ Environment* env = Environment::GetCurrent (isolate);
1644+
1645+ Local<Value> err = GetPromiseReason (env, promise);
1646+
1647+ ReportException (env, err, Exception::CreateMessage (isolate, err));
1648+ }
15751649
1576- static void ReportException (Environment* env,
1577- Local<Value> er,
1578- Local<Message> message) {
1650+ void ReportException (Environment* env,
1651+ Local<Value> er,
1652+ Local<Message> message) {
15791653 HandleScope scope (env->isolate ());
15801654
15811655 AppendExceptionLine (env, er, message);
@@ -3307,6 +3381,11 @@ void LoadEnvironment(Environment* env) {
33073381 // Add a reference to the global object
33083382 Local<Object> global = env->context ()->Global ();
33093383
3384+ Local<Object> JSArray = global->Get (env->array_class_string ()).As <Object>();
3385+ Local<Function> JSFrom =
3386+ JSArray->Get (env->array_from_string ()).As <Function>();
3387+ env->set_array_from (JSFrom);
3388+
33103389#if defined HAVE_DTRACE || defined HAVE_ETW
33113390 InitDTrace (env, global);
33123391#endif
@@ -4322,6 +4401,26 @@ static void StartNodeInstance(void* arg) {
43224401 } while (more == true );
43234402 }
43244403
4404+ Local<Value> promise_keys_set =
4405+ env->promise_unhandled_reject_keys ().As <Value>();
4406+ Local<Function> convert = env->array_from ();
4407+ Local<Value> ret = convert->Call (env->context (),
4408+ Null (env->isolate ()), 1 , &promise_keys_set).ToLocalChecked ();
4409+ Local<Array> promise_keys = ret.As <Array>();
4410+ uint32_t key_count = promise_keys->Length ();
4411+ Local<NativeWeakMap> unhandled_reject_map =
4412+ env->promise_unhandled_reject_map ();
4413+
4414+ for (uint32_t key_iter = 0 ; key_iter < key_count; key_iter++) {
4415+ Local<Value> key = promise_keys->Get (env->context (),
4416+ key_iter).ToLocalChecked ();
4417+
4418+ if (unhandled_reject_map->Has (key)) {
4419+ ReportPromiseRejection (isolate, unhandled_reject_map->Get (key));
4420+ exit (1 );
4421+ }
4422+ }
4423+
43254424 env->set_trace_sync_io (false );
43264425
43274426 int exit_code = EmitExit (env);
0 commit comments