diff --git a/packages/bun-types/globals.d.ts b/packages/bun-types/globals.d.ts index ebbb36aefa..bec0a10704 100644 --- a/packages/bun-types/globals.d.ts +++ b/packages/bun-types/globals.d.ts @@ -744,6 +744,14 @@ interface Process { constrainedMemory(): number | undefined; send(data: any): void; + + report: { + getReport(): Object; + /** + * @TODO This is not implemented yet + */ + writeReport(fileName?: string): void; + }; } interface MemoryUsageObject { diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index 7fcb35a827..d600f26060 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -15,12 +15,16 @@ #include #include #include +#include "wtf-bindings.h" #ifndef WIN32 #include #include #include #include +#include +#include +#include #else #include #include @@ -30,6 +34,10 @@ #include "ProcessBindingUV.h" #include "ProcessBindingNatives.h" +#if OS(LINUX) +#include +#endif + #pragma mark - Node.js Process #if defined(__APPLE__) @@ -91,6 +99,97 @@ extern "C" const char* Bun__githubURL; extern "C" JSC_DECLARE_HOST_FUNCTION(Bun__Process__send); extern "C" JSC_DECLARE_HOST_FUNCTION(Bun__Process__disconnect); +static JSValue constructArch(VM& vm, JSObject* processObject) +{ +#if CPU(X86_64) + return JSC::jsString(vm, makeAtomString("x64")); +#elif CPU(ARM64) + return JSC::jsString(vm, makeAtomString("arm64")); +#else +#error "Unknown architecture" +#endif +} + +static JSValue constructPlatform(VM& vm, JSObject* processObject) +{ +#if defined(__APPLE__) + return JSC::jsString(vm, makeAtomString("darwin")); +#elif defined(__linux__) + return JSC::jsString(vm, makeAtomString("linux")); +#elif OS(WINDOWS) + return JSC::jsString(vm, makeAtomString("win32")); +#else +#error "Unknown platform" +#endif +} + +static JSValue constructVersions(VM& vm, JSObject* processObject) +{ + auto* globalObject = processObject->globalObject(); + JSC::JSObject* object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 19); + + object->putDirect(vm, JSC::Identifier::fromString(vm, "node"_s), + JSC::JSValue(JSC::jsOwnedString(vm, makeAtomString(REPORTED_NODE_VERSION)))); + object->putDirect( + vm, JSC::Identifier::fromString(vm, "bun"_s), + JSC::JSValue(JSC::jsOwnedString(vm, makeAtomString(Bun__version + 1 /* remove "v" prefix */)))); + object->putDirect(vm, JSC::Identifier::fromString(vm, "webkit"_s), + JSC::JSValue(JSC::jsOwnedString(vm, makeAtomString(BUN_WEBKIT_VERSION)))); + object->putDirect(vm, JSC::Identifier::fromString(vm, "boringssl"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_boringssl))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "libarchive"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_libarchive))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "mimalloc"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_mimalloc))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "picohttpparser"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_picohttpparser))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "uwebsockets"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_uws))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "webkit"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_webkit))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "zig"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_zig))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "zlib"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_zlib))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "tinycc"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_tinycc))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "lolhtml"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_lolhtml))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "ares"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_c_ares))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "usockets"_s), + JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_usockets))), 0); + + object->putDirect(vm, JSC::Identifier::fromString(vm, "v8"_s), JSValue(JSC::jsString(vm, makeString("11.3.244.8-node.15"_s))), 0); +#if OS(WINDOWS) + object->putDirect(vm, JSC::Identifier::fromString(vm, "uv"_s), JSValue(JSC::jsString(vm, makeString(uv_version_string()))), 0); +#else + object->putDirect(vm, JSC::Identifier::fromString(vm, "uv"_s), JSValue(JSC::jsString(vm, makeString("1.46.0"_s))), 0); +#endif + object->putDirect(vm, JSC::Identifier::fromString(vm, "napi"_s), JSValue(JSC::jsString(vm, makeString("9"_s))), 0); + + object->putDirect(vm, JSC::Identifier::fromString(vm, "modules"_s), + JSC::JSValue(JSC::jsString(vm, makeAtomString("115")))); + + return object; +} + +static JSValue constructProcessReleaseObject(VM& vm, JSObject* processObject) +{ + auto* globalObject = processObject->globalObject(); + auto* release = JSC::constructEmptyObject(globalObject); + + // SvelteKit compatibility hack + release->putDirect(vm, Identifier::fromString(vm, "name"_s), jsString(vm, WTF::String("node"_s)), 0); + + release->putDirect(vm, Identifier::fromString(vm, "lts"_s), jsBoolean(false), 0); + release->putDirect(vm, Identifier::fromString(vm, "sourceUrl"_s), jsString(vm, WTF::String(Bun__githubURL, strlen(Bun__githubURL))), 0); + release->putDirect(vm, Identifier::fromString(vm, "headersUrl"_s), jsEmptyString(vm), 0); + release->putDirect(vm, Identifier::fromString(vm, "libUrl"_s), jsEmptyString(vm), 0); + + return release; +} + static void dispatchExitInternal(JSC::JSGlobalObject* globalObject, Process* process, int exitCode) { @@ -837,55 +936,613 @@ JSC_DEFINE_CUSTOM_SETTER(setProcessConnected, (JSC::JSGlobalObject * lexicalGlob return false; } -static JSValue constructVersions(VM& vm, JSObject* processObject) +static JSValue constructReportObjectComplete(VM& vm, Zig::GlobalObject* globalObject, const String& fileName) +{ + + // macOS output: + // { + // header: { + // reportVersion: 3, + // event: 'JavaScript API', + // trigger: 'GetReport', + // filename: null, + // dumpEventTime: '2023-11-16T17:56:55Z', + // dumpEventTimeStamp: '1700186215013', + // processId: 18234, + // threadId: 0, + // cwd: '/Users/jarred/Code/bun', + // commandLine: [ 'node' ], + // nodejsVersion: 'v20.8.0', + // wordSize: 64, + // arch: 'arm64', + // platform: 'darwin', + // componentVersions: process.versions, + // release: { + // name: 'node', + // headersUrl: 'https://nodejs.org/download/release/v20.8.0/node-v20.8.0-headers.tar.gz', + // sourceUrl: 'https://nodejs.org/download/release/v20.8.0/node-v20.8.0.tar.gz' + // }, + // osName: 'Darwin', + // osRelease: '22.6.0', + // osVersion: 'Darwin Kernel Version 22.6.0: Wed Jul 5 22:22:05 PDT 2023; root:xnu-8796.141.3~6/RELEASE_ARM64_T6000', + // osMachine: 'arm64', + // cpus: [], + // networkInterfaces: [], + // host: 'macbook.local' + // }, + // javascriptStack: { + // message: 'Error [ERR_SYNTHETIC]: JavaScript Callstack', + // stack: [ + // 'at new NodeError (node:internal/errors:406:5)', + // 'at Object.getReport (node:internal/process/report:36:13)', + // 'at REPL68:1:16', + // 'at Script.runInThisContext (node:vm:122:12)', + // 'at REPLServer.defaultEval (node:repl:594:29)', + // 'at bound (node:domain:432:15)', + // 'at REPLServer.runBound [as eval] (node:domain:443:12)', + // 'at REPLServer.onLine (node:repl:924:10)', + // 'at REPLServer.emit (node:events:526:35)' + // ], + // errorProperties: { code: 'ERR_SYNTHETIC' } + // }, + // javascriptHeap: { + // totalMemory: 5734400, + // executableMemory: 524288, + // totalCommittedMemory: 4931584, + // availableMemory: 4341838112, + // totalGlobalHandlesMemory: 8192, + // usedGlobalHandlesMemory: 8000, + // usedMemory: 4304384, + // memoryLimit: 4345298944, + // mallocedMemory: 147560, + // externalMemory: 2152593, + // peakMallocedMemory: 892416, + // nativeContextCount: 1, + // detachedContextCount: 0, + // doesZapGarbage: 0, + // heapSpaces: { + // read_only_space: [Object], + // new_space: [Object], + // old_space: [Object], + // code_space: [Object], + // shared_space: [Object], + // new_large_object_space: [Object], + // large_object_space: [Object], + // code_large_object_space: [Object], + // shared_large_object_space: [Object] + // } + // }, + // nativeStack: [ + // { + // pc: '0x0000000105293a44', + // symbol: 'node::GetNodeReport(node::Environment*, char const*, char const*, v8::Local, std::__1::basic_ostream>&) [/opt/homebrew/Cellar/node/20.8.0/bin/node]' + // }, + // ], + // resourceUsage: { + // free_memory: 14188216320, + // total_memory: 68719476736, + // rss: 40009728, + // available_memory: 14188216320, + // userCpuSeconds: 0.244133, + // kernelCpuSeconds: 0.058853, + // cpuConsumptionPercent: 1.16533, + // userCpuConsumptionPercent: 0.938973, + // kernelCpuConsumptionPercent: 0.226358, + // maxRss: 41697280, + // pageFaults: { IORequired: 1465, IONotRequired: 1689 }, + // fsActivity: { reads: 0, writes: 0 } + // }, + // libuv: [], + // workers: [], + // environmentVariables: { + // PATH: '', + // }, + // userLimits: { + // core_file_size_blocks: { soft: 0, hard: 'unlimited' }, + // data_seg_size_kbytes: { soft: 'unlimited', hard: 'unlimited' }, + // file_size_blocks: { soft: 'unlimited', hard: 'unlimited' }, + // max_locked_memory_bytes: { soft: 'unlimited', hard: 'unlimited' }, + // max_memory_size_kbytes: { soft: 'unlimited', hard: 'unlimited' }, + // open_files: { soft: 2147483646, hard: 2147483646 }, + // stack_size_bytes: { soft: 8372224, hard: 67092480 }, + // cpu_time_seconds: { soft: 'unlimited', hard: 'unlimited' }, + // max_user_processes: { soft: 10666, hard: 16000 }, + // virtual_memory_kbytes: { soft: 'unlimited', hard: 'unlimited' } + // }, + // sharedObjects: [ + // '/opt/homebrew/Cellar/node/20.8.0/bin/node', + // ] + + // linux: + // { + // header: { + // reportVersion: 3, + // event: 'JavaScript API', + // trigger: 'GetReport', + // filename: null, + // dumpEventTime: '2023-11-16T18:41:38Z', + // dumpEventTimeStamp: '1700188898941', + // processId: 1621753, + // threadId: 0, + // cwd: '/home/jarred', + // commandLine: [ 'node' ], + // nodejsVersion: 'v20.5.0', + // glibcVersionRuntime: '2.35', + // glibcVersionCompiler: '2.28', + // wordSize: 64, + // arch: 'x64', + // platform: 'linux', + // componentVersions: { + // acorn: '8.10.0', + // ada: '2.5.1', + // ares: '1.19.1', + // base64: '0.5.0', + // brotli: '1.0.9', + // cjs_module_lexer: '1.2.2', + // cldr: '43.1', + // icu: '73.2', + // llhttp: '8.1.1', + // modules: '115', + // napi: '9', + // nghttp2: '1.55.1', + // nghttp3: '0.7.0', + // ngtcp2: '0.8.1', + // node: '20.5.0', + // openssl: '3.0.9+quic', + // simdutf: '3.2.14', + // tz: '2023c', + // undici: '5.22.1', + // unicode: '15.0', + // uv: '1.46.0', + // uvwasi: '0.0.18', + // v8: '11.3.244.8-node.10', + // zlib: '1.2.13.1-motley' + // }, + // release: { + // name: 'node', + // headersUrl: 'https://nodejs.org/download/release/v20.5.0/node-v20.5.0-headers.tar.gz', + // sourceUrl: 'https://nodejs.org/download/release/v20.5.0/node-v20.5.0.tar.gz' + // }, + // osName: 'Linux', + // osRelease: '5.17.0-1016-oem', + // osVersion: '#17-Ubuntu SMP PREEMPT Mon Aug 22 11:31:08 UTC 2022', + // osMachine: 'x86_64', + // cpus: [ + // ], + // networkInterfaces: [ + + // ], + // host: 'jarred-desktop' + // }, + // javascriptStack: { + // message: 'Error [ERR_SYNTHETIC]: JavaScript Callstack', + // stack: [ + // 'at new NodeError (node:internal/errors:405:5)', + // 'at Object.getReport (node:internal/process/report:36:13)', + // 'at REPL18:1:16', + // 'at Script.runInThisContext (node:vm:122:12)', + // 'at REPLServer.defaultEval (node:repl:593:29)', + // 'at bound (node:domain:433:15)', + // 'at REPLServer.runBound [as eval] (node:domain:444:12)', + // 'at REPLServer.onLine (node:repl:923:10)', + // 'at REPLServer.emit (node:events:526:35)' + // ], + // errorProperties: { code: 'ERR_SYNTHETIC' } + // }, + // javascriptHeap: { + // totalMemory: 6696960, + // executableMemory: 262144, + // totalCommittedMemory: 6811648, + // availableMemory: 4339915016, + // totalGlobalHandlesMemory: 8192, + // usedGlobalHandlesMemory: 4416, + // usedMemory: 5251032, + // memoryLimit: 4345298944, + // mallocedMemory: 262312, + // externalMemory: 2120511, + // peakMallocedMemory: 521312, + // nativeContextCount: 2, + // detachedContextCount: 0, + // doesZapGarbage: 0, + // heapSpaces: { + // read_only_space: [Object], + // new_space: [Object], + // old_space: [Object], + // code_space: [Object], + // shared_space: [Object], + // new_large_object_space: [Object], + // large_object_space: [Object], + // code_large_object_space: [Object], + // shared_large_object_space: [Object] + // } + // }, + // nativeStack: [ + + // ], + // resourceUsage: { + // free_memory: 64445558784, + // total_memory: 67358441472, + // rss: 52109312, + // constrained_memory: 18446744073709552000, + // available_memory: 18446744073657442000, + // userCpuSeconds: 0.105635, + // kernelCpuSeconds: 0.033611, + // cpuConsumptionPercent: 4.64153, + // userCpuConsumptionPercent: 3.52117, + // kernelCpuConsumptionPercent: 1.12037, + // maxRss: 52150272, + // pageFaults: { IORequired: 26, IONotRequired: 3917 }, + // fsActivity: { reads: 3536, writes: 24 } + // }, + // uvthreadResourceUsage: { + // userCpuSeconds: 0.088644, + // kernelCpuSeconds: 0.005214, + // cpuConsumptionPercent: 3.1286, + // userCpuConsumptionPercent: 2.9548, + // kernelCpuConsumptionPercent: 0.1738, + // fsActivity: { reads: 3512, writes: 0 } + // }, + // libuv: [ + + // ], + // workers: [], + // environmentVariables: { + // }, + // userLimits: { + // core_file_size_blocks: { soft: 'unlimited', hard: 'unlimited' }, + // data_seg_size_kbytes: { soft: 'unlimited', hard: 'unlimited' }, + // file_size_blocks: { soft: 'unlimited', hard: 'unlimited' }, + // max_locked_memory_bytes: { soft: 8419803136, hard: 8419803136 }, + // max_memory_size_kbytes: { soft: 'unlimited', hard: 'unlimited' }, + // open_files: { soft: 1048576, hard: 1048576 }, + // stack_size_bytes: { soft: 8388608, hard: 'unlimited' }, + // cpu_time_seconds: { soft: 'unlimited', hard: 'unlimited' }, + // max_user_processes: { soft: 256637, hard: 256637 }, + // virtual_memory_kbytes: { soft: 'unlimited', hard: 'unlimited' } + // }, + // sharedObjects: [ + // + // ] + // } + auto constructUserLimits = [&]() -> JSValue { + JSC::JSObject* userLimits = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 11); + + rusage usage; + + static constexpr int resourceLimits[] = { + RLIMIT_CORE, + RLIMIT_DATA, + RLIMIT_FSIZE, + RLIMIT_MEMLOCK, + RLIMIT_RSS, + RLIMIT_NOFILE, + RLIMIT_STACK, + RLIMIT_CPU, + RLIMIT_NPROC, + RLIMIT_AS, + }; + + static constexpr ASCIILiteral labels[] = { + "core_file_size_blocks"_s, + "data_seg_size_kbytes"_s, + "file_size_blocks"_s, + "max_locked_memory_bytes"_s, + "max_memory_size_kbytes"_s, + "open_files"_s, + "stack_size_bytes"_s, + "cpu_time_seconds"_s, + "max_user_processes"_s, + "virtual_memory_kbytes"_s, + }; + + for (size_t i = 0; i < std::size(resourceLimits); i++) { + JSC::JSObject* limitObject = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 2); + struct rlimit limit; + getrlimit(resourceLimits[i], &limit); + + JSValue soft = limit.rlim_cur == RLIM_INFINITY ? JSC::jsString(vm, String("unlimited"_s)) : limit.rlim_cur > INT32_MAX ? JSC::jsNumber(limit.rlim_cur) + : JSC::jsDoubleNumber(static_cast(limit.rlim_cur)); + + JSValue hard = limit.rlim_max == RLIM_INFINITY ? JSC::jsString(vm, String("unlimited"_s)) : limit.rlim_max > INT32_MAX ? JSC::jsNumber(limit.rlim_max) + : JSC::jsDoubleNumber(static_cast(limit.rlim_max)); + + limitObject->putDirect(vm, JSC::Identifier::fromString(vm, "soft"_s), soft, 0); + limitObject->putDirect(vm, JSC::Identifier::fromString(vm, "hard"_s), hard, 0); + + userLimits->putDirect(vm, JSC::Identifier::fromString(vm, labels[i]), limitObject, 0); + } + + return userLimits; + }; + + auto constructResourceUsage = [&]() -> JSC::JSValue { + JSC::JSObject* resourceUsage = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 11); + + rusage usage; + + getrusage(RUSAGE_SELF, &usage); + + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "free_memory"_s), JSC::jsNumber(usage.ru_maxrss), 0); + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "total_memory"_s), JSC::jsNumber(usage.ru_maxrss), 0); + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "rss"_s), JSC::jsNumber(usage.ru_maxrss), 0); + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "available_memory"_s), JSC::jsNumber(usage.ru_maxrss), 0); + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "userCpuSeconds"_s), JSC::jsNumber(usage.ru_utime.tv_sec), 0); + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "kernelCpuSeconds"_s), JSC::jsNumber(usage.ru_stime.tv_sec), 0); + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "cpuConsumptionPercent"_s), JSC::jsNumber(usage.ru_utime.tv_sec), 0); + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "userCpuConsumptionPercent"_s), JSC::jsNumber(usage.ru_utime.tv_sec), 0); + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "kernelCpuConsumptionPercent"_s), JSC::jsNumber(usage.ru_utime.tv_sec), 0); + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "maxRss"_s), JSC::jsNumber(usage.ru_maxrss), 0); + + JSC::JSObject* pageFaults = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 2); + pageFaults->putDirect(vm, JSC::Identifier::fromString(vm, "IORequired"_s), JSC::jsNumber(usage.ru_majflt), 0); + pageFaults->putDirect(vm, JSC::Identifier::fromString(vm, "IONotRequired"_s), JSC::jsNumber(usage.ru_minflt), 0); + + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "pageFaults"_s), pageFaults, 0); + + JSC::JSObject* fsActivity = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 2); + fsActivity->putDirect(vm, JSC::Identifier::fromString(vm, "reads"_s), JSC::jsNumber(usage.ru_inblock), 0); + fsActivity->putDirect(vm, JSC::Identifier::fromString(vm, "writes"_s), JSC::jsNumber(usage.ru_oublock), 0); + + resourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "fsActivity"_s), fsActivity, 0); + + return resourceUsage; + }; + + auto constructHeader = [&]() -> JSC::JSValue { + JSC::JSObject* header = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype()); + + header->putDirect(vm, JSC::Identifier::fromString(vm, "reportVersion"_s), JSC::jsNumber(3), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "event"_s), JSC::jsString(vm, String("JavaScript API"_s)), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "trigger"_s), JSC::jsString(vm, String("GetReport"_s)), 0); + if (fileName.isEmpty()) { + header->putDirect(vm, JSC::Identifier::fromString(vm, "filename"_s), JSC::jsNull(), 0); + } else { + header->putDirect(vm, JSC::Identifier::fromString(vm, "filename"_s), JSC::jsString(vm, fileName), 0); + } + + double time = WTF::jsCurrentTime(); + char timeBuf[64] = { 0 }; + Bun::toISOString(vm, time, timeBuf); + auto timeStamp = WTF::String::fromLatin1(timeBuf); + + header->putDirect(vm, JSC::Identifier::fromString(vm, "dumpEventTime"_s), JSC::numberToString(vm, time, 10), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "dumpEventTimeStamp"_s), JSC::jsString(vm, timeStamp, 0)); + header->putDirect(vm, JSC::Identifier::fromString(vm, "processId"_s), JSC::jsNumber(getpid()), 0); + // TODO: + header->putDirect(vm, JSC::Identifier::fromString(vm, "threadId"_s), JSC::jsNumber(0), 0); + + { + char cwd[PATH_MAX] = { 0 }; + getcwd(cwd, PATH_MAX); + + header->putDirect(vm, JSC::Identifier::fromString(vm, "cwd"_s), JSC::jsString(vm, String::fromUTF8ReplacingInvalidSequences(reinterpret_cast(cwd), strlen(cwd))), 0); + } + + header->putDirect(vm, JSC::Identifier::fromString(vm, "commandLine"_s), JSValue::decode(Bun__Process__getExecArgv(globalObject)), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "nodejsVersion"_s), JSC::jsString(vm, String::fromLatin1(REPORTED_NODE_VERSION)), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "wordSize"_s), JSC::jsNumber(64), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "arch"_s), constructArch(vm, header), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "platform"_s), constructPlatform(vm, header), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "componentVersions"_s), constructVersions(vm, header), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "release"_s), constructProcessReleaseObject(vm, header), 0); + + { + // uname + struct utsname buf; + uname(&buf); + + header->putDirect(vm, JSC::Identifier::fromString(vm, "osName"_s), JSC::jsString(vm, String::fromUTF8ReplacingInvalidSequences(reinterpret_cast(buf.sysname), strlen(buf.sysname))), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "osRelease"_s), JSC::jsString(vm, String::fromUTF8ReplacingInvalidSequences(reinterpret_cast(buf.release), strlen(buf.release))), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "osVersion"_s), JSC::jsString(vm, String::fromUTF8ReplacingInvalidSequences(reinterpret_cast(buf.version), strlen(buf.version))), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "osMachine"_s), JSC::jsString(vm, String::fromUTF8ReplacingInvalidSequences(reinterpret_cast(buf.machine), strlen(buf.machine))), 0); + } + + // host + { + // TODO: use HOSTNAME_MAX + char host[1024] = { 0 }; + gethostname(host, 1024); + + header->putDirect(vm, JSC::Identifier::fromString(vm, "host"_s), JSC::jsString(vm, String::fromUTF8ReplacingInvalidSequences(reinterpret_cast(host), strlen(host))), 0); + } + +#if OS(LINUX) + header->putDirect(vm, JSC::Identifier::fromString(vm, "glibcVersionCompiler"_s), JSC::jsString(vm, makeString(__GLIBC__, '.', __GLIBC_MINOR__)), 0); + header->putDirect(vm, JSC::Identifier::fromString(vm, "glibcVersionRuntime"_s), JSC::jsString(vm, String::fromUTF8(reinterpret_cast(gnu_get_libc_version())), 0)); +#endif + + header->putDirect(vm, Identifier::fromString(vm, "cpus"_s), JSC::constructEmptyArray(globalObject, nullptr), 0); + header->putDirect(vm, Identifier::fromString(vm, "networkInterfaces"_s), JSC::constructEmptyArray(globalObject, nullptr), 0); + + return header; + }; + + auto constructJavaScriptHeap = [&]() -> JSC::JSValue { + JSC::JSObject* heap = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 16); + + JSC::JSObject* heapSpaces = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 9); + heapSpaces->putDirect(vm, JSC::Identifier::fromString(vm, "read_only_space"_s), JSC::constructEmptyObject(globalObject), 0); + heapSpaces->putDirect(vm, JSC::Identifier::fromString(vm, "new_space"_s), JSC::constructEmptyObject(globalObject), 0); + heapSpaces->putDirect(vm, JSC::Identifier::fromString(vm, "old_space"_s), JSC::constructEmptyObject(globalObject), 0); + heapSpaces->putDirect(vm, JSC::Identifier::fromString(vm, "code_space"_s), JSC::constructEmptyObject(globalObject), 0); + heapSpaces->putDirect(vm, JSC::Identifier::fromString(vm, "shared_space"_s), JSC::constructEmptyObject(globalObject), 0); + heapSpaces->putDirect(vm, JSC::Identifier::fromString(vm, "new_large_object_space"_s), JSC::constructEmptyObject(globalObject), 0); + heapSpaces->putDirect(vm, JSC::Identifier::fromString(vm, "large_object_space"_s), JSC::constructEmptyObject(globalObject), 0); + heapSpaces->putDirect(vm, JSC::Identifier::fromString(vm, "code_large_object_space"_s), JSC::constructEmptyObject(globalObject), 0); + heapSpaces->putDirect(vm, JSC::Identifier::fromString(vm, "shared_large_object_space"_s), JSC::constructEmptyObject(globalObject), 0); + + heap->putDirect(vm, JSC::Identifier::fromString(vm, "totalMemory"_s), JSC::jsDoubleNumber(static_cast(WTF::ramSize())), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "executableMemory"_s), jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "totalCommittedMemory"_s), jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "availableMemory"_s), jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "totalGlobalHandlesMemory"_s), jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "usedGlobalHandlesMemory"_s), jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "usedMemory"_s), jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "memoryLimit"_s), jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "mallocedMemory"_s), jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "externalMemory"_s), JSC::jsDoubleNumber(static_cast(vm.heap.externalMemorySize())), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "peakMallocedMemory"_s), jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "nativeContextCount"_s), JSC::jsNumber(1), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "detachedContextCount"_s), JSC::jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "doesZapGarbage"_s), JSC::jsNumber(0), 0); + heap->putDirect(vm, JSC::Identifier::fromString(vm, "heapSpaces"_s), heapSpaces, 0); + + return heap; + }; + + auto constructUVThreadResourceUsage = [&]() -> JSC::JSValue { + JSC::JSObject* uvthreadResourceUsage = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 6); + + uvthreadResourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "userCpuSeconds"_s), JSC::jsNumber(0), 0); + uvthreadResourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "kernelCpuSeconds"_s), JSC::jsNumber(0), 0); + uvthreadResourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "cpuConsumptionPercent"_s), JSC::jsNumber(0), 0); + uvthreadResourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "userCpuConsumptionPercent"_s), JSC::jsNumber(0), 0); + uvthreadResourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "kernelCpuConsumptionPercent"_s), JSC::jsNumber(0), 0); + + JSC::JSObject* fsActivity = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 2); + fsActivity->putDirect(vm, JSC::Identifier::fromString(vm, "reads"_s), JSC::jsNumber(0), 0); + fsActivity->putDirect(vm, JSC::Identifier::fromString(vm, "writes"_s), JSC::jsNumber(0), 0); + + uvthreadResourceUsage->putDirect(vm, JSC::Identifier::fromString(vm, "fsActivity"_s), fsActivity, 0); + + return uvthreadResourceUsage; + }; + + auto constructJavaScriptStack = [&]() -> JSC::JSValue { + JSC::JSObject* javascriptStack = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 3); + + javascriptStack->putDirect(vm, JSC::Identifier::fromString(vm, "message"_s), JSC::jsString(vm, String("Error [ERR_SYNTHETIC]: JavaScript Callstack"_s)), 0); + + // TODO: allow errors as an argument + { + WTF::Vector stackFrames; + vm.interpreter.getStackTrace(javascriptStack, stackFrames, 1); + String name = "Error"_s; + String message = "JavaScript Callstack"_s; + unsigned int line = 0; + unsigned int column = 0; + WTF::String sourceURL; + WTF::String stackProperty = Bun::formatStackTrace(vm, globalObject, name, message, line, column, sourceURL, stackFrames, nullptr); + WTF::String stack; + // first line after "Error:" + size_t firstLine = stackProperty.find('\n'); + if (firstLine != WTF::notFound) { + stack = stackProperty.substring(firstLine + 1); + } + + JSC::JSArray* stackArray = JSC::constructEmptyArray(globalObject, nullptr); + + stack.split('\n', [&](WTF::StringView line) { + stackArray->push(globalObject, JSC::jsString(vm, line.toString().trim(isASCIIWhitespace))); + }); + + javascriptStack->putDirect(vm, JSC::Identifier::fromString(vm, "stack"_s), stackArray, 0); + } + + JSC::JSObject* errorProperties = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1); + errorProperties->putDirect(vm, JSC::Identifier::fromString(vm, "code"_s), JSC::jsString(vm, String("ERR_SYNTHETIC"_s)), 0); + javascriptStack->putDirect(vm, JSC::Identifier::fromString(vm, "errorProperties"_s), errorProperties, 0); + return javascriptStack; + }; + + auto constructSharedObjects = [&]() -> JSC::JSValue { + JSC::JSObject* sharedObjects = JSC::constructEmptyArray(globalObject, nullptr); + + // TODO: + + return sharedObjects; + }; + + auto constructLibUV = [&]() -> JSC::JSValue { + JSC::JSObject* libuv = JSC::constructEmptyArray(globalObject, nullptr); + + // TODO: + + return libuv; + }; + + auto constructWorkers = [&]() -> JSC::JSValue { + JSC::JSObject* workers = JSC::constructEmptyArray(globalObject, nullptr); + + // TODO: + + return workers; + }; + + auto constructEnvironmentVariables = [&]() -> JSC::JSValue { + return globalObject->processEnvObject(); + }; + + auto constructCpus = [&]() -> JSC::JSValue { + JSC::JSObject* cpus = JSC::constructEmptyArray(globalObject, nullptr); + + // TODO: + + return cpus; + }; + + auto constructNetworkInterfaces = [&]() -> JSC::JSValue { + JSC::JSObject* networkInterfaces = JSC::constructEmptyArray(globalObject, nullptr); + + // TODO: + + return networkInterfaces; + }; + + auto constructNativeStack = [&]() -> JSC::JSValue { + JSC::JSObject* nativeStack = JSC::constructEmptyArray(globalObject, nullptr); + + // TODO: + + return nativeStack; + }; + + { + JSC::JSObject* report = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 19); + + report->putDirect(vm, JSC::Identifier::fromString(vm, "header"_s), constructHeader(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "javascriptStack"_s), constructJavaScriptStack(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "javascriptHeap"_s), constructJavaScriptHeap(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "nativeStack"_s), constructNativeStack(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "resourceUsage"_s), constructResourceUsage(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "uvthreadResourceUsage"_s), constructUVThreadResourceUsage(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "libuv"_s), constructLibUV(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "workers"_s), constructWorkers(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "environmentVariables"_s), constructEnvironmentVariables(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "userLimits"_s), constructUserLimits(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "sharedObjects"_s), constructSharedObjects(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "cpus"_s), constructCpus(), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "networkInterfaces"_s), constructNetworkInterfaces(), 0); + + return report; + } +} + +JSC_DEFINE_HOST_FUNCTION(Process_functionGetReport, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + // TODO: node:vm + return JSValue::encode(constructReportObjectComplete(vm, jsCast(globalObject), String())); +} + +JSC_DEFINE_HOST_FUNCTION(Process_functionWriteReport, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + // TODO: + return JSValue::encode(callFrame->argument(0)); +} + +static JSValue constructProcessReportObject(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); - JSC::JSObject* object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 19); - - object->putDirect(vm, JSC::Identifier::fromString(vm, "node"_s), - JSC::JSValue(JSC::jsOwnedString(vm, makeAtomString(REPORTED_NODE_VERSION)))); - object->putDirect( - vm, JSC::Identifier::fromString(vm, "bun"_s), - JSC::JSValue(JSC::jsOwnedString(vm, makeAtomString(Bun__version + 1 /* remove "v" prefix */)))); - object->putDirect(vm, JSC::Identifier::fromString(vm, "webkit"_s), - JSC::JSValue(JSC::jsOwnedString(vm, makeAtomString(BUN_WEBKIT_VERSION)))); - object->putDirect(vm, JSC::Identifier::fromString(vm, "boringssl"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_boringssl))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "libarchive"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_libarchive))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "mimalloc"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_mimalloc))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "picohttpparser"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_picohttpparser))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "uwebsockets"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_uws))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "webkit"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_webkit))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "zig"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_zig))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "zlib"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_zlib))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "tinycc"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_tinycc))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "lolhtml"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_lolhtml))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "ares"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_c_ares))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "usockets"_s), - JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_usockets))), 0); - - object->putDirect(vm, JSC::Identifier::fromString(vm, "v8"_s), JSValue(JSC::jsString(vm, makeString("11.3.244.8-node.15"_s))), 0); -#if OS(WINDOWS) - object->putDirect(vm, JSC::Identifier::fromString(vm, "uv"_s), JSValue(JSC::jsString(vm, makeString(uv_version_string()))), 0); -#else - object->putDirect(vm, JSC::Identifier::fromString(vm, "uv"_s), JSValue(JSC::jsString(vm, makeString("1.46.0"_s))), 0); -#endif - object->putDirect(vm, JSC::Identifier::fromString(vm, "napi"_s), JSValue(JSC::jsString(vm, makeString("9"_s))), 0); - - object->putDirect(vm, JSC::Identifier::fromString(vm, "modules"_s), - JSC::JSValue(JSC::jsString(vm, makeAtomString("115")))); - - return object; + auto* report = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 4); + report->putDirect(vm, JSC::Identifier::fromString(vm, "getReport"_s), JSC::JSFunction::create(vm, globalObject, 0, String("getReport"_s), Process_functionGetReport, ImplementationVisibility::Public), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "directory"_s), JSC::jsEmptyString(vm), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "filename"_s), JSC::jsEmptyString(vm), 0); + report->putDirect(vm, JSC::Identifier::fromString(vm, "writeReport"_s), JSC::JSFunction::create(vm, globalObject, 1, String("writeReport"_s), Process_functionWriteReport, ImplementationVisibility::Public), 0); + return report; } static JSValue constructProcessConfigObject(VM& vm, JSObject* processObject) @@ -924,22 +1581,6 @@ static JSValue constructProcessConfigObject(VM& vm, JSObject* processObject) return config; } -static JSValue constructProcessReleaseObject(VM& vm, JSObject* processObject) -{ - auto* globalObject = processObject->globalObject(); - auto* release = JSC::constructEmptyObject(globalObject); - - // SvelteKit compatibility hack - release->putDirect(vm, Identifier::fromString(vm, "name"_s), jsString(vm, WTF::String("node"_s)), 0); - - release->putDirect(vm, Identifier::fromString(vm, "lts"_s), jsBoolean(false), 0); - release->putDirect(vm, Identifier::fromString(vm, "sourceUrl"_s), jsString(vm, WTF::String(Bun__githubURL, strlen(Bun__githubURL))), 0); - release->putDirect(vm, Identifier::fromString(vm, "headersUrl"_s), jsEmptyString(vm), 0); - release->putDirect(vm, Identifier::fromString(vm, "libUrl"_s), jsEmptyString(vm), 0); - - return release; -} - static JSValue constructProcessHrtimeObject(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); @@ -1080,30 +1721,6 @@ static JSValue constructArgv(VM& vm, JSObject* processObject) return JSValue::decode(Bun__Process__getArgv(globalObject)); } -static JSValue constructArch(VM& vm, JSObject* processObject) -{ -#if CPU(X86_64) - return JSC::jsString(vm, makeAtomString("x64")); -#elif CPU(ARM64) - return JSC::jsString(vm, makeAtomString("arm64")); -#else -#error "Unknown architecture" -#endif -} - -static JSValue constructPlatform(VM& vm, JSObject* processObject) -{ -#if defined(__APPLE__) - return JSC::jsString(vm, makeAtomString("darwin")); -#elif defined(__linux__) - return JSC::jsString(vm, makeAtomString("linux")); -#elif OS(WINDOWS) - return JSC::jsString(vm, makeAtomString("win32")); -#else -#error "Unknown platform" -#endif -} - static JSValue constructBrowser(VM& vm, JSObject* processObject) { return jsBoolean(false); @@ -2056,6 +2673,7 @@ extern "C" void Process__emitDisconnectEvent(Zig::GlobalObject* global) ppid constructPpid PropertyCallback reallyExit Process_functionReallyExit Function 1 release constructProcessReleaseObject PropertyCallback + report constructProcessReportObject PropertyCallback revision constructRevision PropertyCallback setSourceMapsEnabled Process_stubEmptyFunction Function 1 send constructProcessSend PropertyCallback diff --git a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp index 9e65b18548..abf794786c 100644 --- a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp +++ b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp @@ -105,8 +105,9 @@ JSC_DEFINE_CUSTOM_SETTER(jsTimeZoneEnvironmentVariableSetter, (JSGlobalObject * auto privateName = builtinNames->dataPrivateName(); object->putDirect(vm, privateName, JSValue::decode(value), 0); + // TODO: this is an assertion failure // Recreate this because the property visibility needs to be set correctly - object->putDirectCustomAccessor(vm, propertyName, JSC::CustomGetterSetter::create(vm, jsTimeZoneEnvironmentVariableGetter, jsTimeZoneEnvironmentVariableSetter), JSC::PropertyAttribute::CustomAccessor | 0); + // object->putDirectWithoutTransition(vm, propertyName, JSC::CustomGetterSetter::create(vm, jsTimeZoneEnvironmentVariableGetter, jsTimeZoneEnvironmentVariableSetter), JSC::PropertyAttribute::CustomAccessor | 0); return true; } diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 7adaed4add..61ae6fec6f 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -317,21 +317,8 @@ extern "C" Zig::GlobalObject* Bun__getDefaultGlobal(); // TODO: thread_local for workers static bool skipNextComputeErrorInfo = false; -// error.stack calls this function -static String computeErrorInfoWithoutPrepareStackTrace(JSC::VM& vm, Vector& stackTrace, unsigned& line, unsigned& column, String& sourceURL, JSObject* errorInstance) +WTF::String Bun::formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* globalObject, const WTF::String& name, const WTF::String& message, unsigned& line, unsigned& column, WTF::String& sourceURL, Vector& stackTrace, JSC::JSObject* errorInstance) { - GCDeferralContext context(vm); - auto* lexicalGlobalObject = errorInstance->globalObject(); - Zig::GlobalObject* globalObject = jsDynamicCast(lexicalGlobalObject); - - WTF::String name = "Error"_s; - WTF::String message; - - // Note that we are not allowed to allocate memory in here. It's called inside a finalizer. - if (auto* instance = jsDynamicCast(errorInstance)) { - name = instance->sanitizedNameString(lexicalGlobalObject); - message = instance->sanitizedMessageString(lexicalGlobalObject); - } WTF::StringBuilder sb; @@ -346,9 +333,10 @@ static String computeErrorInfoWithoutPrepareStackTrace(JSC::VM& vm, VectorputDirect(vm, Identifier::fromString(vm, "originalLine"_s), jsNumber(thisLine), 0); - errorInstance->putDirect(vm, Identifier::fromString(vm, "originalColumn"_s), jsNumber(thisColumn), 0); + if (errorInstance) { + errorInstance->putDirect(vm, Identifier::fromString(vm, "originalLine"_s), jsNumber(thisLine), 0); + errorInstance->putDirect(vm, Identifier::fromString(vm, "originalColumn"_s), jsNumber(thisColumn), 0); + } } } @@ -436,6 +426,24 @@ static String computeErrorInfoWithoutPrepareStackTrace(JSC::VM& vm, Vector& stackTrace, unsigned& line, unsigned& column, String& sourceURL, JSObject* errorInstance) +{ + auto* lexicalGlobalObject = errorInstance->globalObject(); + Zig::GlobalObject* globalObject = jsDynamicCast(lexicalGlobalObject); + + WTF::String name = "Error"_s; + WTF::String message; + + // Note that we are not allowed to allocate memory in here. It's called inside a finalizer. + if (auto* instance = jsDynamicCast(errorInstance)) { + name = instance->sanitizedNameString(lexicalGlobalObject); + message = instance->sanitizedMessageString(lexicalGlobalObject); + } + + return Bun::formatStackTrace(vm, globalObject, name, message, line, column, sourceURL, stackTrace, errorInstance); +} + static String computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, Vector& stackFrames, unsigned& line, unsigned& column, String& sourceURL, JSObject* errorObject, JSObject* prepareStackTrace) { auto scope = DECLARE_THROW_SCOPE(vm); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 2962a134e6..aa55015582 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -537,6 +537,13 @@ private: } // namespace Zig +// TODO: move this +namespace Bun { + +String formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* globalObject, const WTF::String& name, const WTF::String& message, unsigned& line, unsigned& column, WTF::String& sourceURL, Vector& stackTrace, JSC::JSObject* errorInstance); + +} + #ifndef RENAMED_JSDOM_GLOBAL_OBJECT #define RENAMED_JSDOM_GLOBAL_OBJECT namespace WebCore { diff --git a/src/bun.js/bindings/wtf-bindings.cpp b/src/bun.js/bindings/wtf-bindings.cpp index f9d3aa37f2..cf049c709f 100644 --- a/src/bun.js/bindings/wtf-bindings.cpp +++ b/src/bun.js/bindings/wtf-bindings.cpp @@ -273,4 +273,37 @@ String base64URLEncodeToString(Vector data) RELEASE_ASSERT(result.length() == encodedLength); return result; } + +// https://github.com/oven-sh/WebKit/blob/b7bc2ba65db9774d201018f2e1a0a891d6365c13/Source/JavaScriptCore/runtime/DatePrototype.cpp#L323-L345 +size_t toISOString(JSC::VM& vm, double date, char in[64]) +{ + if (!std::isfinite(date)) + return 0; + + GregorianDateTime gregorianDateTime; + vm.dateCache.msToGregorianDateTime(date, WTF::TimeType::UTCTime, gregorianDateTime); + + // Maximum amount of space we need in buffer: 7 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds) + // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination. + char buffer[28]; + // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1). + int ms = static_cast(fmod(date, msPerSecond)); + if (ms < 0) + ms += msPerSecond; + + int charactersWritten; + if (gregorianDateTime.year() > 9999 || gregorianDateTime.year() < 0) + charactersWritten = snprintf(buffer, sizeof(buffer), "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime.year(), gregorianDateTime.month() + 1, gregorianDateTime.monthDay(), gregorianDateTime.hour(), gregorianDateTime.minute(), gregorianDateTime.second(), ms); + else + charactersWritten = snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime.year(), gregorianDateTime.month() + 1, gregorianDateTime.monthDay(), gregorianDateTime.hour(), gregorianDateTime.minute(), gregorianDateTime.second(), ms); + + ASSERT(charactersWritten > 0 && static_cast(charactersWritten) < sizeof(buffer)); + + memcpy(in, buffer, charactersWritten + 1); + if (static_cast(charactersWritten) >= sizeof(buffer)) + return 0; + + return charactersWritten; +} + } diff --git a/src/bun.js/bindings/wtf-bindings.h b/src/bun.js/bindings/wtf-bindings.h index 0a15464721..6b96ac070d 100644 --- a/src/bun.js/bindings/wtf-bindings.h +++ b/src/bun.js/bindings/wtf-bindings.h @@ -5,6 +5,11 @@ extern "C" void WTF__copyLCharsFromUCharSource(LChar* destination, const UChar* source, size_t length); +namespace JSC { +class VM; +} + namespace Bun { String base64URLEncodeToString(Vector data); +size_t toISOString(JSC::VM& vm, double date, char buffer[64]); } \ No newline at end of file diff --git a/test/js/node/process/process.test.js b/test/js/node/process/process.test.js index fd91fdef5d..8964c5c4c2 100644 --- a/test/js/node/process/process.test.js +++ b/test/js/node/process/process.test.js @@ -508,3 +508,8 @@ it("process.constrainedMemory()", () => { expect(process.constrainedMemory()).toBeUndefined(); } }); + +it("process.report", () => { + // TODO: write better tests + JSON.stringify(process.report.getReport(), null, 2); +});