#include "BunProcess.h" #include #include #include #include #include "node_api.h" #include "ZigGlobalObject.h" #include "headers.h" #include "JSEnvironmentVariableMap.h" #include "ImportMetaObject.h" #include #include "ZigConsoleClient.h" #include #include #include #include #include #include "wtf-bindings.h" #ifndef WIN32 #include #include #include #include #include #include #include #else #include #include #include #endif #include "JSNextTickQueue.h" #include "ProcessBindingUV.h" #include "ProcessBindingNatives.h" #if OS(LINUX) #include #endif #pragma mark - Node.js Process #if defined(__APPLE__) #include #include #endif #if defined(__linux__) #include #include #include #include #endif #if !defined(_MSC_VER) #include // setuid, getuid #endif namespace Bun { using namespace JSC; #define REPORTED_NODE_VERSION "20.8.0" #define processObjectBindingCodeGenerator processObjectInternalsBindingCodeGenerator #define setProcessObjectInternalsMainModuleCodeGenerator processObjectInternalsSetMainModuleCodeGenerator #define setProcessObjectMainModuleCodeGenerator setMainModuleCodeGenerator #if !defined(BUN_WEBKIT_VERSION) #define BUN_WEBKIT_VERSION "unknown" #endif using JSGlobalObject = JSC::JSGlobalObject; using Exception = JSC::Exception; using JSValue = JSC::JSValue; using JSString = JSC::JSString; using JSModuleLoader = JSC::JSModuleLoader; using JSModuleRecord = JSC::JSModuleRecord; using Identifier = JSC::Identifier; using SourceOrigin = JSC::SourceOrigin; using JSObject = JSC::JSObject; using JSNonFinalObject = JSC::JSNonFinalObject; namespace JSCastingHelpers = JSC::JSCastingHelpers; JSC_DECLARE_CUSTOM_SETTER(Process_setTitle); JSC_DECLARE_CUSTOM_GETTER(Process_getArgv); JSC_DECLARE_CUSTOM_SETTER(Process_setArgv); JSC_DECLARE_CUSTOM_GETTER(Process_getTitle); JSC_DECLARE_CUSTOM_GETTER(Process_getPID); JSC_DECLARE_CUSTOM_GETTER(Process_getPPID); JSC_DECLARE_HOST_FUNCTION(Process_functionCwd); static bool processIsExiting = false; extern "C" uint8_t Bun__getExitCode(void*); extern "C" uint8_t Bun__setExitCode(void*, uint8_t); extern "C" void* Bun__getVM(); extern "C" Zig::GlobalObject* Bun__getDefaultGlobal(); extern "C" bool Bun__GlobalObject__hasIPC(JSGlobalObject*); 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) { if (processIsExiting) return; processIsExiting = true; auto& emitter = process->wrapped(); auto& vm = globalObject->vm(); if (vm.hasTerminationRequest() || vm.hasExceptionsAfterHandlingTraps()) return; auto event = Identifier::fromString(vm, "exit"_s); if (!emitter.hasEventListeners(event)) { return; } process->putDirect(vm, Identifier::fromString(vm, "_exiting"_s), jsBoolean(true), 0); MarkedArgumentBuffer arguments; arguments.append(jsNumber(exitCode)); emitter.emit(event, arguments); } JSC_DEFINE_CUSTOM_SETTER(Process_defaultSetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, JSC::PropertyName propertyName)) { JSC::VM& vm = globalObject->vm(); JSC::JSObject* thisObject = JSC::jsDynamicCast(JSValue::decode(thisValue)); if (value) thisObject->putDirect(vm, propertyName, JSValue::decode(value), 0); return true; } static bool getWindowSize(int fd, size_t* width, size_t* height) { #if OS(WINDOWS) CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE handle = INVALID_HANDLE_VALUE; switch (fd) { case 0: handle = GetStdHandle(STD_INPUT_HANDLE); break; case 1: handle = GetStdHandle(STD_OUTPUT_HANDLE); break; case 2: handle = GetStdHandle(STD_ERROR_HANDLE); break; default: break; } if (handle == INVALID_HANDLE_VALUE) return false; if (!GetConsoleScreenBufferInfo(handle, &csbi)) return false; *width = csbi.srWindow.Right - csbi.srWindow.Left + 1; *height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; return true; #else struct winsize ws; int err; do err = ioctl(fd, TIOCGWINSZ, &ws); while (err == -1 && errno == EINTR); if (err == -1) return false; *width = ws.ws_col; *height = ws.ws_row; return true; #endif } JSC_DEFINE_HOST_FUNCTION(Process_functionInternalGetWindowSize, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); auto argCount = callFrame->argumentCount(); auto throwScope = DECLARE_THROW_SCOPE(vm); if (argCount == 0) { JSC::throwTypeError(globalObject, throwScope, "getWindowSize requires 2 argument (a file descriptor)"_s); return JSC::JSValue::encode(JSC::JSValue {}); } int fd = callFrame->uncheckedArgument(0).toInt32(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); JSC::JSArray* array = jsDynamicCast(callFrame->uncheckedArgument(1)); if (!array || array->length() < 2) { JSC::throwTypeError(globalObject, throwScope, "getWindowSize requires 2 argument (an array)"_s); return JSC::JSValue::encode(JSC::JSValue {}); } size_t width, height; if (!getWindowSize(fd, &width, &height)) { return JSC::JSValue::encode(jsBoolean(false)); } array->putDirectIndex(globalObject, 0, jsNumber(width)); array->putDirectIndex(globalObject, 1, jsNumber(height)); return JSC::JSValue::encode(jsBoolean(true)); } JSC_DECLARE_HOST_FUNCTION(Process_functionDlopen); JSC_DEFINE_HOST_FUNCTION(Process_functionDlopen, (JSC::JSGlobalObject * globalObject_, JSC::CallFrame* callFrame)) { Zig::GlobalObject* globalObject = reinterpret_cast(globalObject_); auto callCountAtStart = globalObject->napiModuleRegisterCallCount; auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::VM& vm = globalObject->vm(); auto argCount = callFrame->argumentCount(); if (argCount < 2) { JSC::throwTypeError(globalObject, scope, "dlopen requires 2 arguments"_s); return JSC::JSValue::encode(JSC::JSValue {}); } JSC::JSValue moduleValue = callFrame->uncheckedArgument(0); JSC::JSObject* moduleObject = jsDynamicCast(moduleValue); if (UNLIKELY(!moduleObject)) { JSC::throwTypeError(globalObject, scope, "dlopen requires an object as first argument"_s); return JSC::JSValue::encode(JSC::JSValue {}); } JSValue exports = moduleObject->getIfPropertyExists(globalObject, builtinNames(vm).exportsPublicName()); RETURN_IF_EXCEPTION(scope, {}); if (UNLIKELY(!exports)) { JSC::throwTypeError(globalObject, scope, "dlopen requires an object with an exports property"_s); return JSC::JSValue::encode(JSC::JSValue {}); } globalObject->pendingNapiModule = exports; if (exports.isCell()) { vm.writeBarrier(globalObject, exports.asCell()); } WTF::String filename = callFrame->uncheckedArgument(1).toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, {}); #if OS(WINDOWS) CString utf8 = filename.utf8(); HMODULE handle = LoadLibraryA(utf8.data()); #else CString utf8 = filename.utf8(); void* handle = dlopen(utf8.data(), RTLD_LAZY); #endif if (!handle) { #if OS(WINDOWS) WTF::String msg = makeString("LoadLibraryA failed with error code: "_s, GetLastError()); #else WTF::String msg = WTF::String::fromUTF8(dlerror()); #endif JSC::throwTypeError(globalObject, scope, msg); return JSC::JSValue::encode(JSC::JSValue {}); } if (callCountAtStart != globalObject->napiModuleRegisterCallCount) { JSValue pendingModule = globalObject->pendingNapiModule; globalObject->pendingNapiModule = JSValue {}; globalObject->napiModuleRegisterCallCount = 0; if (pendingModule) { if (pendingModule.isCell() && pendingModule.getObject()->isErrorInstance()) { JSC::throwException(globalObject, scope, pendingModule); return JSC::JSValue::encode(JSC::JSValue {}); } return JSC::JSValue::encode(pendingModule); } } JSC::EncodedJSValue (*napi_register_module_v1)(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue exports); #if OS(WINDOWS) #define dlsym GetProcAddress #endif napi_register_module_v1 = reinterpret_cast( dlsym(handle, "napi_register_module_v1")); #if OS(WINDOWS) #undef dlsym #endif if (!napi_register_module_v1) { #if OS(WINDOWS) FreeLibrary(handle); #else dlclose(handle); #endif JSC::throwTypeError(globalObject, scope, "symbol 'napi_register_module_v1' not found in native module. Is this a Node API (napi) module?"_s); return JSC::JSValue::encode(JSC::JSValue {}); } return napi_register_module_v1(globalObject, JSC::JSValue::encode(exports)); } JSC_DEFINE_HOST_FUNCTION(Process_functionUmask, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { #if !OS(WINDOWS) if (callFrame->argumentCount() == 0 || callFrame->argument(0).isUndefined()) { mode_t currentMask = umask(0); umask(currentMask); return JSC::JSValue::encode(JSC::jsNumber(currentMask)); } auto& vm = globalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); JSValue numberValue = callFrame->argument(0); if (!numberValue.isNumber()) { throwTypeError(globalObject, throwScope, "The \"mask\" argument must be a number"_s); return JSValue::encode({}); } if (!numberValue.isAnyInt()) { throwRangeError(globalObject, throwScope, "The \"mask\" argument must be an integer"_s); return JSValue::encode({}); } double number = numberValue.toNumber(globalObject); int64_t newUmask = isInt52(number) ? tryConvertToInt52(number) : numberValue.toInt32(globalObject); RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::JSValue {})); if (newUmask < 0 || newUmask > 4294967295) { StringBuilder messageBuilder; messageBuilder.append("The \"mask\" value must be in range [0, 4294967295]. Received value: "_s); messageBuilder.append(int52ToString(vm, newUmask, 10)->getString(globalObject)); throwRangeError(globalObject, throwScope, messageBuilder.toString()); return JSValue::encode({}); } return JSC::JSValue::encode(JSC::jsNumber(umask(newUmask))); #else return JSC::JSValue::encode(JSC::jsNumber(0)); #endif } extern "C" uint64_t Bun__readOriginTimer(void*); extern "C" double Bun__readOriginTimerStart(void*); // https://github.com/nodejs/node/blob/1936160c31afc9780e4365de033789f39b7cbc0c/src/api/hooks.cc#L49 extern "C" void Process__dispatchOnBeforeExit(Zig::GlobalObject* globalObject, uint8_t exitCode) { if (!globalObject->hasProcessObject()) { return; } auto* process = jsCast(globalObject->processObject()); MarkedArgumentBuffer arguments; arguments.append(jsNumber(exitCode)); process->wrapped().emit(Identifier::fromString(globalObject->vm(), "beforeExit"_s), arguments); } extern "C" void Process__dispatchOnExit(Zig::GlobalObject* globalObject, uint8_t exitCode) { if (!globalObject->hasProcessObject()) { return; } auto* process = jsCast(globalObject->processObject()); dispatchExitInternal(globalObject, process, exitCode); } JSC_DEFINE_HOST_FUNCTION(Process_functionUptime, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { Zig::GlobalObject* globalObject_ = reinterpret_cast(globalObject); double now = static_cast(Bun__readOriginTimer(globalObject_->bunVM())); double result = (now / 1000000.0) / 1000.0; return JSC::JSValue::encode(JSC::jsNumber(result)); } JSC_DEFINE_HOST_FUNCTION(Process_functionExit, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm()); uint8_t exitCode = 0; JSValue arg0 = callFrame->argument(0); if (arg0.isNumber()) { if (!arg0.isInt32()) { throwRangeError(globalObject, throwScope, "The \"code\" argument must be an integer"_s); return JSC::JSValue::encode(JSC::JSValue {}); } int extiCode32 = arg0.toInt32(globalObject) % 256; RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::JSValue {})); exitCode = static_cast(extiCode32); } else if (!arg0.isUndefinedOrNull()) { throwTypeError(globalObject, throwScope, "The \"code\" argument must be an integer"_s); return JSC::JSValue::encode(JSC::JSValue {}); } else { exitCode = Bun__getExitCode(Bun__getVM()); } auto* zigGlobal = jsDynamicCast(globalObject); if (UNLIKELY(!zigGlobal)) { zigGlobal = Bun__getDefaultGlobal(); } Process__dispatchOnExit(zigGlobal, exitCode); Bun__Process__exit(zigGlobal, exitCode); return JSC::JSValue::encode(jsUndefined()); } extern "C" uint64_t Bun__readOriginTimer(void*); JSC_DEFINE_HOST_FUNCTION(Process_functionHRTime, (JSC::JSGlobalObject * globalObject_, JSC::CallFrame* callFrame)) { Zig::GlobalObject* globalObject = reinterpret_cast(globalObject_); auto& vm = globalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); uint64_t time = Bun__readOriginTimer(globalObject->bunVM()); int64_t seconds = static_cast(time / 1000000000); int64_t nanoseconds = time % 1000000000; if (callFrame->argumentCount() > 0) { JSC::JSValue arg0 = callFrame->uncheckedArgument(0); if (!arg0.isUndefinedOrNull()) { JSArray* relativeArray = JSC::jsDynamicCast(arg0); if ((!relativeArray && !arg0.isUndefinedOrNull()) || relativeArray->length() < 2) { JSC::throwTypeError(globalObject, throwScope, "hrtime() argument must be an array or undefined"_s); return JSC::JSValue::encode(JSC::JSValue {}); } JSValue relativeSecondsValue = relativeArray->getIndexQuickly(0); JSValue relativeNanosecondsValue = relativeArray->getIndexQuickly(1); if (!relativeSecondsValue.isNumber() || !relativeNanosecondsValue.isNumber()) { JSC::throwTypeError(globalObject, throwScope, "hrtime() argument must be an array of 2 integers"_s); return JSC::JSValue::encode(JSC::JSValue {}); } int64_t relativeSeconds = JSC__JSValue__toInt64(JSC::JSValue::encode(relativeSecondsValue)); int64_t relativeNanoseconds = JSC__JSValue__toInt64(JSC::JSValue::encode(relativeNanosecondsValue)); seconds -= relativeSeconds; nanoseconds -= relativeNanoseconds; if (nanoseconds < 0) { seconds--; nanoseconds += 1000000000; } } } JSC::JSArray* array = nullptr; { JSC::ObjectInitializationScope initializationScope(vm); if ((array = JSC::JSArray::tryCreateUninitializedRestricted( initializationScope, nullptr, globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous), 2))) { array->initializeIndex(initializationScope, 0, JSC::jsNumber(seconds)); array->initializeIndex(initializationScope, 1, JSC::jsNumber(nanoseconds)); } } if (UNLIKELY(!array)) { JSC::throwOutOfMemoryError(globalObject, throwScope); return JSC::JSValue::encode(JSC::JSValue {}); } RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(array)); } JSC_DEFINE_HOST_FUNCTION(Process_functionHRTimeBigInt, (JSC::JSGlobalObject * globalObject_, JSC::CallFrame* callFrame)) { Zig::GlobalObject* globalObject = reinterpret_cast(globalObject_); return JSC::JSValue::encode(JSValue(JSC::JSBigInt::createFrom(globalObject, Bun__readOriginTimer(globalObject->bunVM())))); } JSC_DEFINE_HOST_FUNCTION(Process_functionChdir, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); ZigString str = ZigString { nullptr, 0 }; if (callFrame->argumentCount() > 0) { str = Zig::toZigString(callFrame->uncheckedArgument(0).toWTFString(globalObject)); } JSC::JSValue result = JSC::JSValue::decode(Bun__Process__setCwd(globalObject, &str)); JSC::JSObject* obj = result.getObject(); if (UNLIKELY(obj != nullptr && obj->isErrorInstance())) { scope.throwException(globalObject, obj); return JSValue::encode(JSC::jsUndefined()); } scope.release(); return JSC::JSValue::encode(result); } #if !OS(WINDOWS) static HashMap* signalNameToNumberMap = nullptr; static HashMap* signalNumberToNameMap = nullptr; // signal number to array of script execution context ids that care about the signal static HashMap>* signalToContextIdsMap = nullptr; static Lock signalToContextIdsMapLock; static const NeverDestroyed signalNames[] = { MAKE_STATIC_STRING_IMPL("SIGHUP"), MAKE_STATIC_STRING_IMPL("SIGINT"), MAKE_STATIC_STRING_IMPL("SIGQUIT"), MAKE_STATIC_STRING_IMPL("SIGILL"), MAKE_STATIC_STRING_IMPL("SIGTRAP"), MAKE_STATIC_STRING_IMPL("SIGABRT"), MAKE_STATIC_STRING_IMPL("SIGIOT"), MAKE_STATIC_STRING_IMPL("SIGBUS"), MAKE_STATIC_STRING_IMPL("SIGFPE"), MAKE_STATIC_STRING_IMPL("SIGKILL"), MAKE_STATIC_STRING_IMPL("SIGUSR1"), MAKE_STATIC_STRING_IMPL("SIGSEGV"), MAKE_STATIC_STRING_IMPL("SIGUSR2"), MAKE_STATIC_STRING_IMPL("SIGPIPE"), MAKE_STATIC_STRING_IMPL("SIGALRM"), MAKE_STATIC_STRING_IMPL("SIGTERM"), MAKE_STATIC_STRING_IMPL("SIGCHLD"), MAKE_STATIC_STRING_IMPL("SIGCONT"), MAKE_STATIC_STRING_IMPL("SIGSTOP"), MAKE_STATIC_STRING_IMPL("SIGTSTP"), MAKE_STATIC_STRING_IMPL("SIGTTIN"), MAKE_STATIC_STRING_IMPL("SIGTTOU"), MAKE_STATIC_STRING_IMPL("SIGURG"), MAKE_STATIC_STRING_IMPL("SIGXCPU"), MAKE_STATIC_STRING_IMPL("SIGXFSZ"), MAKE_STATIC_STRING_IMPL("SIGVTALRM"), MAKE_STATIC_STRING_IMPL("SIGPROF"), MAKE_STATIC_STRING_IMPL("SIGWINCH"), MAKE_STATIC_STRING_IMPL("SIGIO"), MAKE_STATIC_STRING_IMPL("SIGINFO"), MAKE_STATIC_STRING_IMPL("SIGSYS"), }; static void loadSignalNumberMap() { static std::once_flag signalNameToNumberMapOnceFlag; std::call_once(signalNameToNumberMapOnceFlag, [] { signalNameToNumberMap = new HashMap(); signalNameToNumberMap->reserveInitialCapacity(31); signalNameToNumberMap->add(signalNames[0], SIGHUP); signalNameToNumberMap->add(signalNames[1], SIGINT); signalNameToNumberMap->add(signalNames[2], SIGQUIT); signalNameToNumberMap->add(signalNames[3], SIGILL); signalNameToNumberMap->add(signalNames[4], SIGTRAP); signalNameToNumberMap->add(signalNames[5], SIGABRT); signalNameToNumberMap->add(signalNames[6], SIGIOT); signalNameToNumberMap->add(signalNames[7], SIGBUS); signalNameToNumberMap->add(signalNames[8], SIGFPE); // signalNameToNumberMap->add(signalNames[9], SIGKILL); signalNameToNumberMap->add(signalNames[10], SIGUSR1); signalNameToNumberMap->add(signalNames[11], SIGSEGV); signalNameToNumberMap->add(signalNames[12], SIGUSR2); signalNameToNumberMap->add(signalNames[13], SIGPIPE); signalNameToNumberMap->add(signalNames[14], SIGALRM); signalNameToNumberMap->add(signalNames[15], SIGTERM); signalNameToNumberMap->add(signalNames[16], SIGCHLD); signalNameToNumberMap->add(signalNames[17], SIGCONT); // signalNameToNumberMap->add(signalNames[18], SIGSTOP); signalNameToNumberMap->add(signalNames[19], SIGTSTP); signalNameToNumberMap->add(signalNames[20], SIGTTIN); signalNameToNumberMap->add(signalNames[21], SIGTTOU); signalNameToNumberMap->add(signalNames[22], SIGURG); signalNameToNumberMap->add(signalNames[23], SIGXCPU); signalNameToNumberMap->add(signalNames[24], SIGXFSZ); signalNameToNumberMap->add(signalNames[25], SIGVTALRM); signalNameToNumberMap->add(signalNames[26], SIGPROF); signalNameToNumberMap->add(signalNames[27], SIGWINCH); signalNameToNumberMap->add(signalNames[28], SIGIO); #ifdef SIGINFO signalNameToNumberMap->add(signalNames[29], SIGINFO); #endif #ifndef SIGINFO signalNameToNumberMap->add(signalNames[29], 255); #endif signalNameToNumberMap->add(signalNames[30], SIGSYS); }); } static void onDidChangeListeners(EventEmitter& eventEmitter, const Identifier& eventName, bool isAdded) { if (eventName.string() == "message"_s) { if (isAdded) { if (Bun__GlobalObject__hasIPC(eventEmitter.scriptExecutionContext()->jsGlobalObject()) && eventEmitter.listenerCount(eventName) == 1) { eventEmitter.scriptExecutionContext()->refEventLoop(); eventEmitter.m_hasIPCRef = true; } } else { if (eventEmitter.listenerCount(eventName) == 0 && eventEmitter.m_hasIPCRef) { eventEmitter.scriptExecutionContext()->unrefEventLoop(); } } return; } loadSignalNumberMap(); static std::once_flag signalNumberToNameMapOnceFlag; std::call_once(signalNumberToNameMapOnceFlag, [] { signalNumberToNameMap = new HashMap(); signalNumberToNameMap->reserveInitialCapacity(31); signalNumberToNameMap->add(SIGHUP, signalNames[0]); signalNumberToNameMap->add(SIGINT, signalNames[1]); signalNumberToNameMap->add(SIGQUIT, signalNames[2]); signalNumberToNameMap->add(SIGILL, signalNames[3]); signalNumberToNameMap->add(SIGTRAP, signalNames[4]); signalNumberToNameMap->add(SIGABRT, signalNames[5]); signalNumberToNameMap->add(SIGIOT, signalNames[6]); signalNumberToNameMap->add(SIGBUS, signalNames[7]); signalNumberToNameMap->add(SIGFPE, signalNames[8]); // signalNumberToNameMap->add(SIGKILL, signalNames[9]); signalNumberToNameMap->add(SIGUSR1, signalNames[10]); signalNumberToNameMap->add(SIGSEGV, signalNames[11]); signalNumberToNameMap->add(SIGUSR2, signalNames[12]); signalNumberToNameMap->add(SIGPIPE, signalNames[13]); signalNumberToNameMap->add(SIGALRM, signalNames[14]); signalNumberToNameMap->add(SIGTERM, signalNames[15]); signalNumberToNameMap->add(SIGCHLD, signalNames[16]); signalNumberToNameMap->add(SIGCONT, signalNames[17]); // signalNumberToNameMap->add(SIGSTOP, signalNames[18]); signalNumberToNameMap->add(SIGTSTP, signalNames[19]); signalNumberToNameMap->add(SIGTTIN, signalNames[20]); signalNumberToNameMap->add(SIGTTOU, signalNames[21]); signalNumberToNameMap->add(SIGURG, signalNames[22]); signalNumberToNameMap->add(SIGXCPU, signalNames[23]); signalNumberToNameMap->add(SIGXFSZ, signalNames[24]); signalNumberToNameMap->add(SIGVTALRM, signalNames[25]); signalNumberToNameMap->add(SIGPROF, signalNames[26]); signalNumberToNameMap->add(SIGWINCH, signalNames[27]); signalNumberToNameMap->add(SIGIO, signalNames[28]); #ifdef SIGINFO signalNameToNumberMap->add(signalNames[29], SIGINFO); #endif signalNumberToNameMap->add(SIGSYS, signalNames[30]); }); if (!signalToContextIdsMap) { signalToContextIdsMap = new HashMap>(); } if (isAdded) { if (auto signalNumber = signalNameToNumberMap->get(eventName.string())) { uint32_t contextId = eventEmitter.scriptExecutionContext()->identifier(); Locker lock { signalToContextIdsMapLock }; if (!signalToContextIdsMap->contains(signalNumber)) { HashSet contextIds; contextIds.add(contextId); signalToContextIdsMap->set(signalNumber, contextIds); lock.unlockEarly(); struct sigaction action; memset(&action, 0, sizeof(struct sigaction)); // Set the handler in the action struct action.sa_handler = [](int signalNumber) { if (UNLIKELY(signalNumberToNameMap->find(signalNumber) == signalNumberToNameMap->end())) return; Locker lock { signalToContextIdsMapLock }; if (UNLIKELY(signalToContextIdsMap->find(signalNumber) == signalToContextIdsMap->end())) return; auto contextIds = signalToContextIdsMap->get(signalNumber); for (int contextId : contextIds) { auto* context = ScriptExecutionContext::getScriptExecutionContext(contextId); if (UNLIKELY(!context)) continue; JSGlobalObject* lexicalGlobalObject = context->jsGlobalObject(); Zig::GlobalObject* globalObject = jsCast(lexicalGlobalObject); Process* process = jsCast(globalObject->processObject()); context->postCrossThreadTask(*process, &Process::emitSignalEvent, signalNumber); } }; // Clear the sa_mask sigemptyset(&action.sa_mask); sigaddset(&action.sa_mask, signalNumber); action.sa_flags = SA_RESTART; sigaction(signalNumber, &action, nullptr); } else { auto contextIds = signalToContextIdsMap->get(signalNumber); contextIds.add(contextId); signalToContextIdsMap->set(signalNumber, contextIds); } } } else { if (auto signalNumber = signalNameToNumberMap->get(eventName.string())) { uint32_t contextId = eventEmitter.scriptExecutionContext()->identifier(); Locker lock { signalToContextIdsMapLock }; if (signalToContextIdsMap->find(signalNumber) != signalToContextIdsMap->end()) { HashSet contextIds = signalToContextIdsMap->get(signalNumber); contextIds.remove(contextId); if (contextIds.isEmpty()) { signal(signalNumber, SIG_DFL); signalToContextIdsMap->remove(signalNumber); } else { signalToContextIdsMap->set(signalNumber, contextIds); } } } } } #endif void Process::emitSignalEvent(int signalNumber) { #if !OS(WINDOWS) String signalName = signalNumberToNameMap->get(signalNumber); Identifier signalNameIdentifier = Identifier::fromString(vm(), signalName); MarkedArgumentBuffer args; args.append(jsNumber(signalNumber)); wrapped().emitForBindings(signalNameIdentifier, args); #else UNUSED_PARAM(signalNumber); #endif } Process::~Process() { } JSC_DEFINE_HOST_FUNCTION(Process_functionAbort, (JSGlobalObject * globalObject, CallFrame*)) { abort(); __builtin_unreachable(); } JSC_DEFINE_HOST_FUNCTION(Process_emitWarning, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { Zig::GlobalObject* globalObject = jsCast(lexicalGlobalObject); VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (callFrame->argumentCount() < 1) { throwVMError(globalObject, scope, "Not enough arguments"_s); return JSValue::encode(jsUndefined()); } RETURN_IF_EXCEPTION(scope, encodedJSValue()); auto* process = jsCast(globalObject->processObject()); JSObject* errorInstance = ([&]() -> JSObject* { JSValue arg0 = callFrame->uncheckedArgument(0); if (!arg0.isEmpty() && arg0.isCell() && arg0.asCell()->type() == ErrorInstanceType) { return arg0.getObject(); } WTF::String str = arg0.toWTFString(globalObject); return createError(globalObject, str); })(); errorInstance->putDirect(vm, Identifier::fromString(vm, "name"_s), jsString(vm, String("warn"_s)), JSC::PropertyAttribute::DontEnum | 0); auto ident = Identifier::fromString(vm, "warning"_s); if (process->wrapped().hasEventListeners(ident)) { JSC::MarkedArgumentBuffer args; args.append(errorInstance); process->wrapped().emit(ident, args); return JSValue::encode(jsUndefined()); } auto jsArgs = JSValue::encode(errorInstance); Zig__ConsoleClient__messageWithTypeAndLevel(reinterpret_cast(globalObject->consoleClient().get())->m_client, static_cast(MessageType::Log), static_cast(MessageLevel::Warning), globalObject, &jsArgs, 1); return JSValue::encode(jsUndefined()); } JSC_DEFINE_CUSTOM_GETTER(processExitCode, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName name)) { Process* process = jsDynamicCast(JSValue::decode(thisValue)); if (!process) { return JSValue::encode(jsUndefined()); } return JSValue::encode(jsNumber(Bun__getExitCode(jsCast(process->globalObject())->bunVM()))); } JSC_DEFINE_CUSTOM_SETTER(setProcessExitCode, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, JSC::PropertyName)) { Process* process = jsDynamicCast(JSValue::decode(thisValue)); if (!process) { return false; } auto throwScope = DECLARE_THROW_SCOPE(process->vm()); JSValue exitCode = JSValue::decode(value); if (!exitCode.isNumber()) { throwTypeError(lexicalGlobalObject, throwScope, "exitCode must be a number"_s); return false; } if (!exitCode.isInt32()) { throwRangeError(lexicalGlobalObject, throwScope, "The \"code\" argument must be an integer"_s); return JSC::JSValue::encode(JSC::JSValue {}); } int exitCodeInt = exitCode.toInt32(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, false); if (exitCodeInt < 0 || exitCodeInt > 255) { throwRangeError(lexicalGlobalObject, throwScope, "exitCode must be between 0 and 255"_s); return false; } void* ptr = jsCast(process->globalObject())->bunVM(); Bun__setExitCode(ptr, static_cast(exitCodeInt)); return true; } JSC_DEFINE_CUSTOM_GETTER(processConnected, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName name)) { Process* process = jsDynamicCast(JSValue::decode(thisValue)); if (!process) { return JSValue::encode(jsUndefined()); } return JSValue::encode(jsBoolean(Bun__GlobalObject__hasIPC(process->globalObject()))); } JSC_DEFINE_CUSTOM_SETTER(setProcessConnected, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, JSC::PropertyName)) { return false; } 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(); 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) { auto* globalObject = processObject->globalObject(); // target_defaults: // { cflags: [], // default_configuration: 'Release', // defines: [], // include_dirs: [], // libraries: [] }, // variables: // { // host_arch: 'x64', // napi_build_version: 5, // node_install_npm: 'true', // node_prefix: '', // node_shared_cares: 'false', // node_shared_http_parser: 'false', // node_shared_libuv: 'false', // node_shared_zlib: 'false', // node_use_openssl: 'true', // node_shared_openssl: 'false', // strict_aliasing: 'true', // target_arch: 'x64', // v8_use_snapshot: 1 // } // } JSC::JSObject* config = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 2); JSC::JSObject* variables = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1); variables->putDirect(vm, JSC::Identifier::fromString(vm, "v8_enable_i8n_support"_s), JSC::jsNumber(1), 0); config->putDirect(vm, JSC::Identifier::fromString(vm, "target_defaults"_s), JSC::constructEmptyObject(globalObject), 0); config->putDirect(vm, JSC::Identifier::fromString(vm, "variables"_s), variables, 0); return config; } static JSValue constructProcessHrtimeObject(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); JSC::JSFunction* hrtime = JSC::JSFunction::create(vm, globalObject, 0, String("hrtime"_s), Process_functionHRTime, ImplementationVisibility::Public); JSC::JSFunction* hrtimeBigInt = JSC::JSFunction::create(vm, globalObject, 0, String("bigint"_s), Process_functionHRTimeBigInt, ImplementationVisibility::Public); hrtime->putDirect(vm, JSC::Identifier::fromString(vm, "bigint"_s), hrtimeBigInt); return hrtime; } static JSValue constructStdioWriteStream(JSC::JSGlobalObject* globalObject, int fd) { auto& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSC::JSFunction* getStdioWriteStream = JSC::JSFunction::create(vm, processObjectInternalsGetStdioWriteStreamCodeGenerator(vm), globalObject); JSC::MarkedArgumentBuffer args; args.append(JSC::jsNumber(fd)); auto clientData = WebCore::clientData(vm); JSC::CallData callData = JSC::getCallData(getStdioWriteStream); NakedPtr returnedException = nullptr; auto result = JSC::call(globalObject, getStdioWriteStream, callData, globalObject->globalThis(), args, returnedException); RETURN_IF_EXCEPTION(scope, {}); if (returnedException) { throwException(globalObject, scope, returnedException.get()); return {}; } return result; } static JSValue constructStdout(VM& vm, JSObject* processObject) { auto* globalObject = Bun__getDefaultGlobal(); return constructStdioWriteStream(globalObject, 1); } static JSValue constructStderr(VM& vm, JSObject* processObject) { auto* globalObject = Bun__getDefaultGlobal(); return constructStdioWriteStream(globalObject, 2); } #if OS(WINDOWS) #define STDIN_FILENO 0 #endif static JSValue constructStdin(VM& vm, JSObject* processObject) { auto* globalObject = Bun__getDefaultGlobal(); auto scope = DECLARE_THROW_SCOPE(vm); auto* thisObject = reinterpret_cast(globalObject); JSC::JSFunction* getStdioWriteStream = JSC::JSFunction::create(vm, processObjectInternalsGetStdinStreamCodeGenerator(vm), globalObject); JSC::MarkedArgumentBuffer args; args.append(JSC::jsNumber(STDIN_FILENO)); auto clientData = WebCore::clientData(vm); JSC::CallData callData = JSC::getCallData(getStdioWriteStream); NakedPtr returnedException = nullptr; auto result = JSC::call(globalObject, getStdioWriteStream, callData, globalObject, args, returnedException); RETURN_IF_EXCEPTION(scope, {}); if (UNLIKELY(returnedException)) { throwException(globalObject, scope, returnedException.get()); return {}; } RELEASE_AND_RETURN(scope, result); } static JSValue constructProcessSend(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); if (Bun__GlobalObject__hasIPC(globalObject)) { return JSC::JSFunction::create(vm, globalObject, 1, String("send"_s), Bun__Process__send, ImplementationVisibility::Public); } else { return jsUndefined(); } } static JSValue constructProcessDisconnect(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); if (Bun__GlobalObject__hasIPC(globalObject)) { return JSC::JSFunction::create(vm, globalObject, 1, String("disconnect"_s), Bun__Process__disconnect, ImplementationVisibility::Public); } else { return jsUndefined(); } } #if OS(WINDOWS) #define getpid _getpid #endif static JSValue constructPid(VM& vm, JSObject* processObject) { return jsNumber(getpid()); } static JSValue constructPpid(VM& vm, JSObject* processObject) { #if OS(WINDOWS) return jsNumber(0); #else return jsNumber(getppid()); #endif } static JSValue constructArgv0(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); return JSValue::decode(Bun__Process__getArgv0(globalObject)); } static JSValue constructExecArgv(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); return JSValue::decode(Bun__Process__getExecArgv(globalObject)); } static JSValue constructExecPath(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); return JSValue::decode(Bun__Process__getExecPath(globalObject)); } static JSValue constructArgv(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); return JSValue::decode(Bun__Process__getArgv(globalObject)); } static JSValue constructBrowser(VM& vm, JSObject* processObject) { return jsBoolean(false); } static JSValue constructVersion(VM& vm, JSObject* processObject) { return JSC::jsString(vm, makeString("v", REPORTED_NODE_VERSION)); } static JSValue constructIsBun(VM& vm, JSObject* processObject) { return jsBoolean(true); } static JSValue constructRevision(VM& vm, JSObject* processObject) { return JSC::jsString(vm, makeAtomString(Bun__version_sha)); } static JSValue constructEnv(VM& vm, JSObject* processObject) { auto* globalObject = jsCast(processObject->globalObject()); return globalObject->processEnvObject(); } #if OS(WINDOWS) static int getuid() { return 0; } static int geteuid() { return 0; } static int getegid() { return 0; } static int getgid() { return 0; } #endif JSC_DEFINE_HOST_FUNCTION(Process_functiongetuid, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(jsNumber(getuid())); } JSC_DEFINE_HOST_FUNCTION(Process_functiongeteuid, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(jsNumber(geteuid())); } JSC_DEFINE_HOST_FUNCTION(Process_functiongetegid, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(jsNumber(getegid())); } JSC_DEFINE_HOST_FUNCTION(Process_functiongetgid, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(jsNumber(getgid())); } JSC_DEFINE_HOST_FUNCTION(Process_functiongetgroups, (JSGlobalObject * globalObject, CallFrame* callFrame)) { #if !OS(WINDOWS) auto& vm = globalObject->vm(); int ngroups = getgroups(0, nullptr); auto throwScope = DECLARE_THROW_SCOPE(vm); if (ngroups == -1) { throwSystemError(throwScope, globalObject, "getgroups"_s, errno); return JSValue::encode(jsUndefined()); } gid_t egid = getegid(); JSArray* groups = constructEmptyArray(globalObject, nullptr, static_cast(ngroups)); Vector groupVector(ngroups); getgroups(1, &egid); bool needsEgid = true; for (unsigned i = 0; i < ngroups; i++) { auto current = groupVector[i]; if (current == needsEgid) { needsEgid = false; } groups->putDirectIndex(globalObject, i, jsNumber(current)); } if (needsEgid) groups->push(globalObject, jsNumber(egid)); return JSValue::encode(groups); #else return JSValue::encode(jsUndefined()); #endif } JSC_DEFINE_HOST_FUNCTION(Process_functionAssert, (JSGlobalObject * globalObject, CallFrame* callFrame)) { auto& vm = globalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); JSValue arg0 = callFrame->argument(0); bool condition = arg0.toBoolean(globalObject); RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); if (condition) { return JSValue::encode(jsUndefined()); } JSValue arg1 = callFrame->argument(1); String message = arg1.isUndefined() ? String() : arg1.toWTFString(globalObject); RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); auto error = createError(globalObject, makeString("Assertion failed: "_s, message)); error->putDirect(vm, Identifier::fromString(vm, "code"_s), jsString(vm, makeString("ERR_ASSERTION"_s))); throwException(globalObject, throwScope, error); return JSValue::encode(jsUndefined()); } #define PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE(str, issue) \ { \ throwScope.throwException(globalObject, createError(globalObject, String("process.binding(\"" str "\") is not implemented in Bun. Track the status & thumbs up the issue: https://github.com/oven-sh/bun/issues/" issue ""_s))); \ return JSValue::encode(JSValue {}); \ } #define PROCESS_BINDING_NOT_IMPLEMENTED(str) \ { \ throwScope.throwException(globalObject, createError(globalObject, String("process.binding(\"" str "\") is not implemented in Bun. If that breaks something, please file an issue and include a reproducible code sample."_s))); \ return JSValue::encode(JSValue {}); \ } inline JSValue processBindingUtil(Zig::GlobalObject* globalObject, JSC::VM& vm) { auto& builtinNames = WebCore::builtinNames(vm); auto fn = globalObject->getDirect(vm, builtinNames.requireNativeModulePrivateName()); auto callData = JSC::getCallData(fn); JSC::MarkedArgumentBuffer args; args.append(jsString(vm, String("util/types"_s))); return JSC::call(globalObject, fn, callData, globalObject, args); } inline JSValue processBindingConfig(Zig::GlobalObject* globalObject, JSC::VM& vm) { auto config = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 9); #ifdef BUN_DEBUG config->putDirect(vm, Identifier::fromString(vm, "isDebugBuild"_s), jsBoolean(true), 0); #else config->putDirect(vm, Identifier::fromString(vm, "isDebugBuild"_s), jsBoolean(false), 0); #endif config->putDirect(vm, Identifier::fromString(vm, "hasOpenSSL"_s), jsBoolean(true), 0); config->putDirect(vm, Identifier::fromString(vm, "fipsMode"_s), jsBoolean(true), 0); config->putDirect(vm, Identifier::fromString(vm, "hasIntl"_s), jsBoolean(true), 0); config->putDirect(vm, Identifier::fromString(vm, "hasTracing"_s), jsBoolean(true), 0); config->putDirect(vm, Identifier::fromString(vm, "hasNodeOptions"_s), jsBoolean(true), 0); config->putDirect(vm, Identifier::fromString(vm, "hasInspector"_s), jsBoolean(true), 0); config->putDirect(vm, Identifier::fromString(vm, "noBrowserGlobals"_s), jsBoolean(false), 0); config->putDirect(vm, Identifier::fromString(vm, "bits"_s), jsNumber(64), 0); return config; } JSC_DEFINE_HOST_FUNCTION(Process_functionBinding, (JSGlobalObject * jsGlobalObject, CallFrame* callFrame)) { auto& vm = jsGlobalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); auto globalObject = jsCast(jsGlobalObject); auto process = jsCast(globalObject->processObject()); auto moduleName = callFrame->argument(0).toWTFString(globalObject); // clang-format off if (moduleName == "async_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("async_wrap"); if (moduleName == "buffer"_s) PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE("buffer", "2020"); if (moduleName == "cares_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("cares_wrap"); if (moduleName == "config"_s) return JSValue::encode(processBindingConfig(globalObject, vm)); if (moduleName == "constants"_s) return JSValue::encode(globalObject->processBindingConstants()); if (moduleName == "contextify"_s) PROCESS_BINDING_NOT_IMPLEMENTED("contextify"); if (moduleName == "crypto"_s) PROCESS_BINDING_NOT_IMPLEMENTED("crypto"); if (moduleName == "fs"_s) PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE("fs", "3546"); if (moduleName == "fs_event_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("fs_event_wrap"); if (moduleName == "http_parser"_s) PROCESS_BINDING_NOT_IMPLEMENTED("http_parser"); if (moduleName == "icu"_s) PROCESS_BINDING_NOT_IMPLEMENTED("icu"); if (moduleName == "inspector"_s) PROCESS_BINDING_NOT_IMPLEMENTED("inspector"); if (moduleName == "js_stream"_s) PROCESS_BINDING_NOT_IMPLEMENTED("js_stream"); if (moduleName == "natives"_s) return JSValue::encode(process->bindingNatives()); if (moduleName == "os"_s) PROCESS_BINDING_NOT_IMPLEMENTED("os"); if (moduleName == "pipe_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("pipe_wrap"); if (moduleName == "process_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("process_wrap"); if (moduleName == "signal_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("signal_wrap"); if (moduleName == "spawn_sync"_s) PROCESS_BINDING_NOT_IMPLEMENTED("spawn_sync"); if (moduleName == "stream_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE("stream_wrap", "4957"); if (moduleName == "tcp_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("tcp_wrap"); if (moduleName == "tls_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("tls_wrap"); if (moduleName == "tty_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE("tty_wrap", "4694"); if (moduleName == "udp_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("udp_wrap"); if (moduleName == "url"_s) PROCESS_BINDING_NOT_IMPLEMENTED("url"); if (moduleName == "util"_s) return JSValue::encode(processBindingUtil(globalObject, vm)); if (moduleName == "uv"_s) return JSValue::encode(process->bindingUV()); if (moduleName == "v8"_s) PROCESS_BINDING_NOT_IMPLEMENTED("v8"); if (moduleName == "zlib"_s) PROCESS_BINDING_NOT_IMPLEMENTED("zlib"); // clang-format on throwScope.throwException(globalObject, createError(globalObject, makeString("No such module: "_s, moduleName))); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(Process_functionReallyExit, (JSGlobalObject * globalObject, CallFrame* callFrame)) { auto& vm = globalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); uint8_t exitCode = 0; JSValue arg0 = callFrame->argument(0); if (arg0.isNumber()) { if (!arg0.isInt32()) { throwRangeError(globalObject, throwScope, "The \"code\" argument must be an integer"_s); return JSC::JSValue::encode(JSC::JSValue {}); } int extiCode32 = arg0.toInt32(globalObject) % 256; RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::JSValue {})); exitCode = static_cast(extiCode32); } else if (!arg0.isUndefinedOrNull()) { throwTypeError(globalObject, throwScope, "The \"code\" argument must be an integer"_s); return JSC::JSValue::encode(JSC::JSValue {}); } else { exitCode = Bun__getExitCode(Bun__getVM()); } auto* zigGlobal = jsDynamicCast(globalObject); if (UNLIKELY(!zigGlobal)) { zigGlobal = Bun__getDefaultGlobal(); } Bun__Process__exit(zigGlobal, exitCode); return JSC::JSValue::encode(jsUndefined()); } template void Process::visitChildrenImpl(JSCell* cell, Visitor& visitor) { Process* thisObject = jsCast(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); thisObject->m_cpuUsageStructure.visit(visitor); thisObject->m_memoryUsageStructure.visit(visitor); thisObject->m_bindingUV.visit(visitor); thisObject->m_bindingNatives.visit(visitor); } DEFINE_VISIT_CHILDREN(Process); static Structure* constructCPUUsageStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject) { JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype(globalObject, globalObject->objectPrototype(), 2); PropertyOffset offset; structure = structure->addPropertyTransition( vm, structure, JSC::Identifier::fromString(vm, "user"_s), 0, offset); structure = structure->addPropertyTransition( vm, structure, JSC::Identifier::fromString(vm, "system"_s), 0, offset); return structure; } static Structure* constructMemoryUsageStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject) { JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype(globalObject, globalObject->objectPrototype(), 5); PropertyOffset offset; structure = structure->addPropertyTransition( vm, structure, JSC::Identifier::fromString(vm, "rss"_s), 0, offset); structure = structure->addPropertyTransition( vm, structure, JSC::Identifier::fromString(vm, "heapTotal"_s), 0, offset); structure = structure->addPropertyTransition( vm, structure, JSC::Identifier::fromString(vm, "heapUsed"_s), 0, offset); structure = structure->addPropertyTransition( vm, structure, JSC::Identifier::fromString(vm, "external"_s), 0, offset); structure = structure->addPropertyTransition( vm, structure, JSC::Identifier::fromString(vm, "arrayBuffers"_s), 0, offset); return structure; } static Process* getProcessObject(JSC::JSGlobalObject* lexicalGlobalObject, JSValue thisValue) { Process* process = jsDynamicCast(thisValue); // Handle "var memoryUsage = process.memoryUsage; memoryUsage()" if (UNLIKELY(!process)) { // Handle calling this function from inside a node:vm Zig::GlobalObject* zigGlobalObject = jsDynamicCast(lexicalGlobalObject); if (UNLIKELY(!zigGlobalObject)) { zigGlobalObject = Bun__getDefaultGlobal(); } return jsCast(zigGlobalObject->processObject()); } return process; } JSC_DEFINE_HOST_FUNCTION(Process_functionConstrainedMemory, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { #if OS(LINUX) || OS(FREEBSD) return JSValue::encode(jsDoubleNumber(static_cast(WTF::ramSize()))); #else return JSValue::encode(jsUndefined()); #endif } JSC_DEFINE_HOST_FUNCTION(Process_functionCpuUsage, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); #if !OS(WINDOWS) struct rusage rusage; if (getrusage(RUSAGE_SELF, &rusage) != 0) { throwSystemError(throwScope, globalObject, "Failed to get CPU usage"_s, "getrusage"_s, errno); return JSValue::encode(jsUndefined()); } #else uv_rusage_t rusage; if (uv_getrusage(&rusage) != 0) { throwSystemError(throwScope, globalObject, "Failed to get CPU usage"_s, "uv_getrusage"_s, errno); return JSValue::encode(jsUndefined()); } #endif auto* process = getProcessObject(globalObject, callFrame->thisValue()); Structure* cpuUsageStructure = process->cpuUsageStructure(); constexpr double MICROS_PER_SEC = 1000000.0; double user = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec; double system = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec; if (callFrame->argumentCount() > 0) { JSValue comparatorValue = callFrame->argument(0); if (!comparatorValue.isUndefined()) { if (UNLIKELY(!comparatorValue.isObject())) { throwTypeError(globalObject, throwScope, "Expected an object as the first argument"_s); return JSC::JSValue::encode(JSC::jsUndefined()); } JSC::JSObject* comparator = comparatorValue.getObject(); JSValue userValue; JSValue systemValue; if (LIKELY(comparator->structureID() == cpuUsageStructure->id())) { userValue = comparator->getDirect(0); systemValue = comparator->getDirect(1); } else { userValue = comparator->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "user"_s)); RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); systemValue = comparator->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "system"_s)); RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); } if (UNLIKELY(!userValue || !userValue.isNumber())) { throwTypeError(globalObject, throwScope, "Expected a number for the user property"_s); return JSC::JSValue::encode(JSC::jsUndefined()); } if (UNLIKELY(!systemValue || !systemValue.isNumber())) { throwTypeError(globalObject, throwScope, "Expected a number for the system property"_s); return JSC::JSValue::encode(JSC::jsUndefined()); } double userComparator = userValue.asNumber(); double systemComparator = systemValue.asNumber(); user -= userComparator; system -= systemComparator; } } JSC::JSObject* result = JSC::constructEmptyObject(vm, cpuUsageStructure); RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); result->putDirectOffset(vm, 0, JSC::jsNumber(user)); result->putDirectOffset(vm, 1, JSC::jsNumber(system)); RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(result)); } int getRSS(size_t* rss) { #if defined(__APPLE__) mach_msg_type_number_t count; task_basic_info_data_t info; kern_return_t err; count = TASK_BASIC_INFO_COUNT; err = task_info(mach_task_self(), TASK_BASIC_INFO, reinterpret_cast(&info), &count); if (err == KERN_SUCCESS) { *rss = (size_t)info.resident_size; return 0; } return -1; #elif defined(__linux__) // Taken from libuv. char buf[1024]; const char* s; ssize_t n; long val; int fd; int i; do fd = open("/proc/self/stat", O_RDONLY); while (fd == -1 && errno == EINTR); if (fd == -1) return errno; do n = read(fd, buf, sizeof(buf) - 1); while (n == -1 && errno == EINTR); int closeErrno = 0; do { closeErrno = close(fd); } while (closeErrno == -1 && errno == EINTR); if (n == -1) return errno; buf[n] = '\0'; s = strchr(buf, ' '); if (s == NULL) goto err; s += 1; if (*s != '(') goto err; s = strchr(s, ')'); if (s == NULL) goto err; for (i = 1; i <= 22; i++) { s = strchr(s + 1, ' '); if (s == NULL) goto err; } errno = 0; val = strtol(s, NULL, 10); if (errno != 0) goto err; if (val < 0) goto err; *rss = val * getpagesize(); return 0; err: return EINVAL; #elif OS(WINDOWS) return uv_resident_set_memory(rss); #else #error "Unknown platform" #endif } JSC_DEFINE_HOST_FUNCTION(Process_functionMemoryUsage, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); auto* process = getProcessObject(globalObject, callFrame->thisValue()); size_t current_rss = 0; if (getRSS(¤t_rss) != 0) { throwSystemError(throwScope, globalObject, "Failed to get memory usage"_s, "memoryUsage"_s, errno); return JSC::JSValue::encode(JSC::JSValue {}); } JSC::JSObject* result = JSC::constructEmptyObject(vm, process->memoryUsageStructure()); if (UNLIKELY(throwScope.exception())) { return JSC::JSValue::encode(JSC::JSValue {}); } // Node.js: // { // rss: 4935680, // heapTotal: 1826816, // heapUsed: 650472, // external: 49879, // arrayBuffers: 9386 // } result->putDirectOffset(vm, 0, JSC::jsNumber(current_rss)); result->putDirectOffset(vm, 1, JSC::jsNumber(vm.heap.blockBytesAllocated())); // heap.size() loops through every cell... // TODO: add a binding for heap.sizeAfterLastCollection() result->putDirectOffset(vm, 2, JSC::jsNumber(vm.heap.sizeAfterLastEdenCollection())); result->putDirectOffset(vm, 3, JSC::jsNumber(vm.heap.externalMemorySize())); // We report 0 for this because m_arrayBuffers in JSC::Heap is private and we need to add a binding // If we use objectTypeCounts(), it's hideously slow because it loops through every single object in the heap // TODO: add a binding for m_arrayBuffers, registerWrapper() in TypedArrayController doesn't work result->putDirectOffset(vm, 4, JSC::jsNumber(0)); RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(result)); } JSC_DEFINE_HOST_FUNCTION(Process_functionMemoryUsageRSS, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); size_t current_rss = 0; if (getRSS(¤t_rss) != 0) { throwSystemError(throwScope, globalObject, "Failed to get memory usage"_s, "memoryUsage"_s, errno); return JSC::JSValue::encode(JSC::JSValue {}); } RELEASE_AND_RETURN(throwScope, JSValue::encode(jsNumber(current_rss))); } JSC_DEFINE_HOST_FUNCTION(Process_functionOpenStdin, (JSGlobalObject * globalObject, CallFrame* callFrame)) { auto& vm = globalObject->vm(); Zig::GlobalObject* global = jsDynamicCast(globalObject); if (UNLIKELY(!global)) { global = Bun__getDefaultGlobal(); } auto throwScope = DECLARE_THROW_SCOPE(vm); if (JSValue stdinValue = global->processObject()->getIfPropertyExists(globalObject, Identifier::fromString(vm, "stdin"_s))) { RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); if (!stdinValue.isObject()) { throwTypeError(globalObject, throwScope, "stdin is not an object"_s); return JSValue::encode(jsUndefined()); } JSValue resumeValue = stdinValue.getObject()->getIfPropertyExists(globalObject, Identifier::fromString(vm, "resume"_s)); RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); if (!resumeValue.isUndefinedOrNull()) { auto resumeFunction = jsDynamicCast(resumeValue); if (UNLIKELY(!resumeFunction)) { throwTypeError(globalObject, throwScope, "stdin.resume is not a function"_s); return JSValue::encode(jsUndefined()); } auto callData = getCallData(resumeFunction); MarkedArgumentBuffer args; JSC::call(globalObject, resumeFunction, callData, stdinValue, args); RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); } RELEASE_AND_RETURN(throwScope, JSValue::encode(stdinValue)); } RELEASE_AND_RETURN(throwScope, JSValue::encode(jsUndefined())); } JSC_DEFINE_HOST_FUNCTION(Process_stubEmptyFunction, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(Process_stubFunctionReturningArray, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(JSC::constructEmptyArray(globalObject, nullptr)); } static JSValue Process_stubEmptyObject(VM& vm, JSObject* processObject) { return JSC::constructEmptyObject(processObject->globalObject()); } static JSValue Process_stubEmptyArray(VM& vm, JSObject* processObject) { return JSC::constructEmptyArray(processObject->globalObject(), nullptr); } static JSValue Process_stubEmptySet(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); return JSSet::create(vm, globalObject->setStructure()); } static JSValue constructMemoryUsage(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); JSC::JSFunction* memoryUsage = JSC::JSFunction::create(vm, globalObject, 0, String("memoryUsage"_s), Process_functionMemoryUsage, ImplementationVisibility::Public); JSC::JSFunction* rss = JSC::JSFunction::create(vm, globalObject, 0, String("rss"_s), Process_functionMemoryUsageRSS, ImplementationVisibility::Public); memoryUsage->putDirect(vm, JSC::Identifier::fromString(vm, "rss"_s), rss, 0); return memoryUsage; } JSC_DEFINE_HOST_FUNCTION(jsFunctionReportUncaughtException, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSValue arg0 = callFrame->argument(0); Bun__reportUnhandledError(globalObject, JSValue::encode(arg0)); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(jsFunctionDrainMicrotaskQueue, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { globalObject->vm().drainMicrotasks(); return JSValue::encode(jsUndefined()); } static JSValue constructProcessNextTickFn(VM& vm, JSObject* processObject) { JSGlobalObject* lexicalGlobalObject = processObject->globalObject(); Zig::GlobalObject* globalObject = jsCast(lexicalGlobalObject); JSValue nextTickQueueObject; if (!globalObject->m_nextTickQueue) { nextTickQueueObject = Bun::JSNextTickQueue::create(globalObject); globalObject->m_nextTickQueue.set(vm, globalObject, nextTickQueueObject); } else { nextTickQueueObject = jsCast(globalObject->m_nextTickQueue.get()); } JSC::JSFunction* initializer = JSC::JSFunction::create(vm, processObjectInternalsInitializeNextTickQueueCodeGenerator(vm), lexicalGlobalObject); JSC::MarkedArgumentBuffer args; args.append(processObject); args.append(nextTickQueueObject); args.append(JSC::JSFunction::create(vm, globalObject, 1, String(), jsFunctionDrainMicrotaskQueue, ImplementationVisibility::Private)); args.append(JSC::JSFunction::create(vm, globalObject, 1, String(), jsFunctionReportUncaughtException, ImplementationVisibility::Private)); return JSC::call(globalObject, initializer, JSC::getCallData(initializer), globalObject->globalThis(), args); } static JSValue constructFeatures(VM& vm, JSObject* processObject) { // { // inspector: true, // debug: false, // uv: true, // ipv6: true, // tls_alpn: true, // tls_sni: true, // tls_ocsp: true, // tls: true, // cached_builtins: [Getter] // } auto* globalObject = processObject->globalObject(); auto* object = constructEmptyObject(globalObject); object->putDirect(vm, Identifier::fromString(vm, "inspector"_s), jsBoolean(true)); #ifdef BUN_DEBUG object->putDirect(vm, Identifier::fromString(vm, "debug"_s), jsBoolean(true)); #else object->putDirect(vm, Identifier::fromString(vm, "debug"_s), jsBoolean(false)); #endif // lying object->putDirect(vm, Identifier::fromString(vm, "uv"_s), jsBoolean(true)); object->putDirect(vm, Identifier::fromString(vm, "ipv6"_s), jsBoolean(true)); object->putDirect(vm, Identifier::fromString(vm, "tls_alpn"_s), jsBoolean(true)); object->putDirect(vm, Identifier::fromString(vm, "tls_sni"_s), jsBoolean(true)); object->putDirect(vm, Identifier::fromString(vm, "tls_ocsp"_s), jsBoolean(true)); object->putDirect(vm, Identifier::fromString(vm, "tls"_s), jsBoolean(true)); object->putDirect(vm, Identifier::fromString(vm, "cached_builtins"_s), jsBoolean(true)); return object; } static int _debugPort; JSC_DEFINE_CUSTOM_GETTER(processDebugPort, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { if (_debugPort == 0) { _debugPort = 9229; } return JSC::JSValue::encode(jsNumber(_debugPort)); } JSC_DEFINE_CUSTOM_SETTER(setProcessDebugPort, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName)) { auto& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue value = JSValue::decode(encodedValue); if (!value.isInt32()) { throwRangeError(globalObject, scope, "debugPort must be 0 or in range 1024 to 65535"_s); return false; } int port = value.asInt32(); if (port != 0) { if (port < 1024 || port > 65535) { throwRangeError(globalObject, scope, "debugPort must be 0 or in range 1024 to 65535"_s); return false; } } _debugPort = port; return true; } JSC_DEFINE_CUSTOM_GETTER(processTitle, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { #if !OS(WINDOWS) ZigString str; Bun__Process__getTitle(globalObject, &str); return JSValue::encode(Zig::toJSStringValue(str, globalObject)); #else auto& vm = globalObject->vm(); char title[1024]; if (uv_get_process_title(title, sizeof(title)) != 0) { return JSValue::encode(jsString(vm, String("bun"_s))); } return JSValue::encode(jsString(vm, WTF::String::fromUTF8(title))); #endif } JSC_DEFINE_CUSTOM_SETTER(setProcessTitle, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, JSC::PropertyName)) { JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSC::JSObject* thisObject = JSC::jsDynamicCast(JSValue::decode(thisValue)); JSC::JSString* jsString = JSC::jsDynamicCast(JSValue::decode(value)); if (!thisObject || !jsString) { return false; } #if !OS(WINDOWS) ZigString str = Zig::toZigString(jsString, globalObject); Bun__Process__setTitle(globalObject, &str); return true; #else WTF::String str = jsString->value(globalObject); RETURN_IF_EXCEPTION(scope, false); CString cstr = str.utf8(); return uv_set_process_title(cstr.data()) == 0; #endif } JSC_DEFINE_HOST_FUNCTION(Process_functionCwd, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::JSValue result = JSC::JSValue::decode(Bun__Process__getCwd(globalObject)); JSC::JSObject* obj = result.getObject(); if (UNLIKELY(obj != nullptr && obj->isErrorInstance())) { scope.throwException(globalObject, obj); return JSValue::encode(JSC::jsUndefined()); } return JSC::JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(Process_functionReallyKill, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); int pid = callFrame->argument(0).toInt32(globalObject); RETURN_IF_EXCEPTION(scope, {}); int signal = callFrame->argument(1).toInt32(globalObject); RETURN_IF_EXCEPTION(scope, {}); #if !OS(WINDOWS) int result = kill(pid, signal); #else int result = uv_kill(pid, signal); #endif if (result < 0) { throwSystemError(scope, globalObject, "kill"_s, errno); } RELEASE_AND_RETURN(scope, JSValue::encode(jsUndefined())); } JSC_DEFINE_HOST_FUNCTION(Process_functionKill, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); int pid = callFrame->argument(0).toInt32(globalObject); RETURN_IF_EXCEPTION(scope, {}); if (pid < 0) { throwRangeError(globalObject, scope, "pid must be a positive integer"_s); return JSValue::encode(jsUndefined()); } JSC::JSValue signalValue = callFrame->argument(1); #if !OS(WINDOWS) int signal = SIGTERM; if (signalValue.isNumber()) { signal = signalValue.toInt32(globalObject); RETURN_IF_EXCEPTION(scope, {}); } else if (signalValue.isString()) { loadSignalNumberMap(); if (auto num = signalNameToNumberMap->get(signalValue.toWTFString(globalObject))) { signal = num; RETURN_IF_EXCEPTION(scope, {}); } else { throwRangeError(globalObject, scope, "Unknown signal name"_s); return JSValue::encode(jsUndefined()); } RETURN_IF_EXCEPTION(scope, {}); } else if (!signalValue.isUndefinedOrNull()) { throwTypeError(globalObject, scope, "signal must be a string or number"_s); return JSValue::encode(jsUndefined()); } int result = kill(pid, signal); #else int signal = 1; if (signalValue.isNumber()) { signal = signalValue.toInt32(globalObject); RETURN_IF_EXCEPTION(scope, {}); } else if (signalValue.isString()) { throwTypeError(globalObject, scope, "TODO: implement this function with strings on Windows! Sorry!!"_s); RETURN_IF_EXCEPTION(scope, {}); } else if (!signalValue.isUndefinedOrNull()) { throwTypeError(globalObject, scope, "signal must be a string or number"_s); return JSValue::encode(jsUndefined()); } int result = uv_kill(pid, signal); #endif if (result < 0) { throwSystemError(scope, globalObject, "kill"_s, errno); return JSValue::encode(jsUndefined()); } return JSValue::encode(jsBoolean(true)); } extern "C" void Process__emitMessageEvent(Zig::GlobalObject* global, EncodedJSValue value) { auto* process = static_cast(global->processObject()); auto& vm = global->vm(); auto ident = Identifier::fromString(vm, "message"_s); if (process->wrapped().hasEventListeners(ident)) { JSC::MarkedArgumentBuffer args; args.append(JSValue::decode(value)); process->wrapped().emit(ident, args); } } extern "C" void Process__emitDisconnectEvent(Zig::GlobalObject* global) { auto* process = static_cast(global->processObject()); auto& vm = global->vm(); auto ident = Identifier::fromString(vm, "disconnect"_s); if (process->wrapped().hasEventListeners(ident)) { JSC::MarkedArgumentBuffer args; process->wrapped().emit(ident, args); } } /* Source for Process.lut.h @begin processObjectTable abort Process_functionAbort Function 1 allowedNodeEnvironmentFlags Process_stubEmptySet PropertyCallback arch constructArch PropertyCallback argv constructArgv PropertyCallback argv0 constructArgv0 PropertyCallback assert Process_functionAssert Function 1 binding Process_functionBinding Function 1 browser constructBrowser PropertyCallback chdir Process_functionChdir Function 1 config constructProcessConfigObject PropertyCallback connected processConnected CustomAccessor constrainedMemory Process_functionConstrainedMemory Function 0 cpuUsage Process_functionCpuUsage Function 1 cwd Process_functionCwd Function 1 debugPort processDebugPort CustomAccessor disconnect constructProcessDisconnect PropertyCallback dlopen Process_functionDlopen Function 1 emitWarning Process_emitWarning Function 1 env constructEnv PropertyCallback execArgv constructExecArgv PropertyCallback execPath constructExecPath PropertyCallback exit Process_functionExit Function 1 exitCode processExitCode CustomAccessor features constructFeatures PropertyCallback getActiveResourcesInfo Process_stubFunctionReturningArray Function 0 getegid Process_functiongetegid Function 0 geteuid Process_functiongeteuid Function 0 getgid Process_functiongetgid Function 0 getgroups Process_functiongetgroups Function 0 getuid Process_functiongetuid Function 0 hrtime constructProcessHrtimeObject PropertyCallback isBun constructIsBun PropertyCallback kill Process_functionKill Function 2 mainModule processObjectInternalsMainModuleCodeGenerator Builtin|Accessor memoryUsage constructMemoryUsage PropertyCallback moduleLoadList Process_stubEmptyArray PropertyCallback nextTick constructProcessNextTickFn PropertyCallback openStdin Process_functionOpenStdin Function 0 pid constructPid PropertyCallback platform constructPlatform PropertyCallback 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 stderr constructStderr PropertyCallback stdin constructStdin PropertyCallback stdout constructStdout PropertyCallback title processTitle CustomAccessor umask Process_functionUmask Function 1 uptime Process_functionUptime Function 1 version constructVersion PropertyCallback versions constructVersions PropertyCallback _debugEnd Process_stubEmptyFunction Function 0 _debugProcess Process_stubEmptyFunction Function 0 _fatalException Process_stubEmptyFunction Function 1 _getActiveRequests Process_stubFunctionReturningArray Function 0 _getActiveHandles Process_stubFunctionReturningArray Function 0 _linkedBinding Process_stubEmptyFunction Function 0 _preload_modules Process_stubEmptyArray PropertyCallback _rawDebug Process_stubEmptyFunction Function 0 _startProfilerIdleNotifier Process_stubEmptyFunction Function 0 _stopProfilerIdleNotifier Process_stubEmptyFunction Function 0 _tickCallback Process_stubEmptyFunction Function 0 _kill Process_functionReallyKill Function 2 @end */ #include "BunProcess.lut.h" const JSC::ClassInfo Process::s_info = { "Process"_s, &Base::s_info, &processObjectTable, nullptr, CREATE_METHOD_TABLE(Process) }; void Process::finishCreation(JSC::VM& vm) { Base::finishCreation(vm); #ifndef WIN32 wrapped().onDidChangeListener = &onDidChangeListeners; #endif m_cpuUsageStructure.initLater([](const JSC::LazyProperty::Initializer& init) { init.set(constructCPUUsageStructure(init.vm, init.owner->globalObject())); }); m_memoryUsageStructure.initLater([](const JSC::LazyProperty::Initializer& init) { init.set(constructMemoryUsageStructure(init.vm, init.owner->globalObject())); }); m_bindingUV.initLater([](const JSC::LazyProperty::Initializer& init) { init.set(Bun::ProcessBindingUV::create(init.vm, init.owner->globalObject())); }); m_bindingNatives.initLater([](const JSC::LazyProperty::Initializer& init) { init.set(Bun::ProcessBindingNatives::create(init.vm, ProcessBindingNatives::createStructure(init.vm, init.owner->globalObject()))); }); putDirect(vm, vm.propertyNames->toStringTagSymbol, jsString(vm, String("process"_s)), 0); } } // namespace Bun