| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 5c7a9c8 commit c705b73
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -30,6 +30,7 @@ | |||
| 30 | 30 | #include <iostream> | |
| 31 | 31 | #include <limits> | |
| 32 | 32 | #include <memory> | |
| 33 | + #include <optional> | ||
| 33 | 34 | #include <unordered_map> | |
| 34 | 35 | ||
| 35 | 36 | namespace node { | |
@@ -55,13 +56,16 @@ using v8::Number; | |||
| 55 | 56 | using v8::Object; | |
| 56 | 57 | using v8::ObjectTemplate; | |
| 57 | 58 | using v8::Private; | |
| 59 | + using v8::Promise; | ||
| 60 | + using v8::PromiseHookType; | ||
| 58 | 61 | using v8::Script; | |
| 59 | 62 | using v8::SnapshotCreator; | |
| 60 | 63 | using v8::StackTrace; | |
| 61 | 64 | using v8::String; | |
| 62 | 65 | using v8::Symbol; | |
| 63 | 66 | using v8::TracingController; | |
| 64 | 67 | using v8::TryCatch; | |
| 68 | + using v8::Uint32; | ||
| 65 | 69 | using v8::Undefined; | |
| 66 | 70 | using v8::Value; | |
| 67 | 71 | using v8::WrapperDescriptor; | |
@@ -1839,6 +1843,60 @@ void Environment::BuildEmbedderGraph(Isolate* isolate, | |||
| 1839 | 1843 | tracker.Track(env); | |
| 1840 | 1844 | } | |
| 1841 | 1845 | ||
| 1846 | + std::optional<uint32_t> GetPromiseId(Environment* env, Local<Promise> promise) { | ||
| 1847 | + Local<Value> id_val; | ||
| 1848 | + if (!promise->GetPrivate(env->context(), env->promise_trace_id()) | ||
| 1849 | + .ToLocal(&id_val) || | ||
| 1850 | + !id_val->IsUint32()) { | ||
| 1851 | + return std::nullopt; | ||
| 1852 | + } | ||
| 1853 | + return id_val.As<Uint32>()->Value(); | ||
| 1854 | + } | ||
| 1855 | + | ||
| 1856 | + void Environment::TracePromises(PromiseHookType type, | ||
| 1857 | + Local<Promise> promise, | ||
| 1858 | + Local<Value> parent) { | ||
| 1859 | + // We don't care about the execution of promises, just the | ||
| 1860 | + // creation/resolution. | ||
| 1861 | + if (type == PromiseHookType::kBefore || type == PromiseHookType::kAfter) { | ||
| 1862 | + return; | ||
| 1863 | + } | ||
| 1864 | + Isolate* isolate = Isolate::GetCurrent(); | ||
| 1865 | + Local<Context> context = isolate->GetCurrentContext(); | ||
| 1866 | + Environment* env = Environment::GetCurrent(context); | ||
| 1867 | + if (env == nullptr) return; | ||
| 1868 | + | ||
| 1869 | + std::optional<uint32_t> parent_id; | ||
| 1870 | + if (!parent.IsEmpty() && parent->IsPromise()) { | ||
| 1871 | + parent_id = GetPromiseId(env, parent.As<Promise>()); | ||
| 1872 | + } | ||
| 1873 | + | ||
| 1874 | + uint32_t id = 0; | ||
| 1875 | + std::string action; | ||
| 1876 | + if (type == PromiseHookType::kInit) { | ||
| 1877 | + id = env->trace_promise_id_counter_++; | ||
| 1878 | + promise->SetPrivate( | ||
| 1879 | + context, env->promise_trace_id(), Uint32::New(isolate, id)); | ||
| 1880 | + action = "created"; | ||
| 1881 | + } else if (type == PromiseHookType::kResolve) { | ||
| 1882 | + auto opt = GetPromiseId(env, promise); | ||
| 1883 | + if (!opt.has_value()) return; | ||
| 1884 | + id = opt.value(); | ||
| 1885 | + action = "resolved"; | ||
| 1886 | + } else { | ||
| 1887 | + UNREACHABLE(); | ||
| 1888 | + } | ||
| 1889 | + | ||
| 1890 | + FPrintF(stderr, "[--trace-promises] "); | ||
| 1891 | + if (parent_id.has_value()) { | ||
| 1892 | + FPrintF(stderr, "promise #%d ", parent_id.value()); | ||
| 1893 | + } | ||
| 1894 | + FPrintF(stderr, "%s promise #%d\n", action, id); | ||
| 1895 | + // TODO(joyeecheung): we can dump the native stack trace too if the | ||
| 1896 | + // JS stack trace is empty i.e. it may be resolved on the native side. | ||
| 1897 | + PrintCurrentStackTrace(isolate); | ||
| 1898 | + } | ||
| 1899 | + | ||
| 1842 | 1900 | size_t Environment::NearHeapLimitCallback(void* data, | |
| 1843 | 1901 | size_t current_heap_limit, | |
| 1844 | 1902 | size_t initial_heap_limit) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -934,6 +934,9 @@ class Environment : public MemoryRetainer { | |||
| 934 | 934 | inline void RemoveCleanupHook(CleanupQueue::Callback cb, void* arg); | |
| 935 | 935 | void RunCleanup(); | |
| 936 | 936 | ||
| 937 | + static void TracePromises(v8::PromiseHookType type, | ||
| 938 | + v8::Local<v8::Promise> promise, | ||
| 939 | + v8::Local<v8::Value> parent); | ||
| 937 | 940 | static size_t NearHeapLimitCallback(void* data, | |
| 938 | 941 | size_t current_heap_limit, | |
| 939 | 942 | size_t initial_heap_limit); | |
@@ -1094,6 +1097,7 @@ class Environment : public MemoryRetainer { | |||
| 1094 | 1097 | uint32_t module_id_counter_ = 0; | |
| 1095 | 1098 | uint32_t script_id_counter_ = 0; | |
| 1096 | 1099 | uint32_t function_id_counter_ = 0; | |
| 1100 | + uint32_t trace_promise_id_counter_ = 0; | ||
| 1097 | 1101 | ||
| 1098 | 1102 | AliasedInt32Array exit_info_; | |
| 1099 | 1103 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -26,6 +26,7 @@ | |||
| 26 | 26 | V(napi_wrapper, "node:napi:wrapper") \ | |
| 27 | 27 | V(untransferable_object_private_symbol, "node:untransferableObject") \ | |
| 28 | 28 | V(exit_info_private_symbol, "node:exit_info_private_symbol") \ | |
| 29 | + V(promise_trace_id, "node:promise_trace_id") \ | ||
| 29 | 30 | V(require_private_symbol, "node:require_private_symbol") | |
| 30 | 31 | ||
| 31 | 32 | // Symbols are per-isolate primitives but Environment proxies them | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -264,6 +264,9 @@ void Environment::InitializeDiagnostics() { | |||
| 264 | 264 | env->isolate()->SetAtomicsWaitCallback(nullptr, nullptr); | |
| 265 | 265 | }, this); | |
| 266 | 266 | } | |
| 267 | + if (options_->trace_promises) { | ||
| 268 | + isolate_->SetPromiseHook(TracePromises); | ||
| 269 | + } | ||
| 267 | 270 | } | |
| 268 | 271 | ||
| 269 | 272 | static | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -291,6 +291,13 @@ void PrintStackTrace(Isolate* isolate, | |||
| 291 | 291 | PrintToStderrAndFlush(FormatStackTrace(isolate, stack, prefix)); | |
| 292 | 292 | } | |
| 293 | 293 | ||
| 294 | + void PrintCurrentStackTrace(Isolate* isolate, StackTracePrefix prefix) { | ||
| 295 | + Local<StackTrace> stack; | ||
| 296 | + if (GetCurrentStackTrace(isolate).ToLocal(&stack)) { | ||
| 297 | + PrintStackTrace(isolate, stack, prefix); | ||
| 298 | + } | ||
| 299 | + } | ||
| 300 | + | ||
| 294 | 301 | std::string FormatCaughtException(Isolate* isolate, | |
| 295 | 302 | Local<Context> context, | |
| 296 | 303 | Local<Value> err, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -87,6 +87,8 @@ enum class StackTracePrefix { | |||
| 87 | 87 | kAt, // " at " | |
| 88 | 88 | kNumber | |
| 89 | 89 | }; | |
| 90 | + void PrintCurrentStackTrace(v8::Isolate* isolate, | ||
| 91 | + StackTracePrefix prefix = StackTracePrefix::kAt); | ||
| 90 | 92 | void PrintStackTrace(v8::Isolate* isolate, | |
| 91 | 93 | v8::Local<v8::StackTrace> stack, | |
| 92 | 94 | StackTracePrefix prefix = StackTracePrefix::kAt); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -667,6 +667,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { | |||
| 667 | 667 | "show stack traces on process warnings", | |
| 668 | 668 | &EnvironmentOptions::trace_warnings, | |
| 669 | 669 | kAllowedInEnvvar); | |
| 670 | + AddOption("--trace-promises", | ||
| 671 | + "show stack traces on promise initialization and resolution", | ||
| 672 | + &EnvironmentOptions::trace_promises, | ||
| 673 | + kAllowedInEnvvar); | ||
| 670 | 674 | AddOption("--experimental-default-type", | |
| 671 | 675 | "set module system to use by default", | |
| 672 | 676 | &EnvironmentOptions::type, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -178,6 +178,7 @@ class EnvironmentOptions : public Options { | |||
| 178 | 178 | bool trace_tls = false; | |
| 179 | 179 | bool trace_uncaught = false; | |
| 180 | 180 | bool trace_warnings = false; | |
| 181 | + bool trace_promises = false; | ||
| 181 | 182 | bool extra_info_on_fatal_exception = true; | |
| 182 | 183 | std::string unhandled_rejections; | |
| 183 | 184 | std::vector<std::string> userland_loaders; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -106,6 +106,8 @@ assert(undocumented.delete('--no-node-snapshot')); | |||
| 106 | 106 | assert(undocumented.delete('--loader')); | |
| 107 | 107 | assert(undocumented.delete('--verify-base-objects')); | |
| 108 | 108 | assert(undocumented.delete('--no-verify-base-objects')); | |
| 109 | + assert(undocumented.delete('--trace-promises')); | ||
| 110 | + assert(undocumented.delete('--no-trace-promises')); | ||
| 109 | 111 | ||
| 110 | 112 | // Remove negated versions of the flags. | |
| 111 | 113 | for (const flag of undocumented) { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments