#include "ProcessBindingUV.h" #include "JavaScriptCore/ArrayAllocationProfile.h" #include "JavaScriptCore/JSCJSValue.h" #include "JavaScriptCore/ThrowScope.h" #include "ZigGlobalObject.h" #include "JavaScriptCore/ObjectConstructor.h" #include "JavaScriptCore/JSMap.h" #include "JavaScriptCore/JSMapInlines.h" // clang-format off #if !defined(E2BIG) #define E2BIG 7 #endif #if !defined(EACCES) #define EACCES 13 #endif #if !defined(EADDRINUSE) #define EADDRINUSE 48 #endif #if !defined(EADDRNOTAVAIL) #define EADDRNOTAVAIL 49 #endif #if !defined(EAFNOSUPPORT) #define EAFNOSUPPORT 47 #endif #if !defined(EAGAIN) #define EAGAIN 35 #endif #if !defined(EAI_ADDRFAMILY) #define EAI_ADDRFAMILY 3000 #endif #if !defined(EAI_AGAIN) #define EAI_AGAIN 3001 #endif #if !defined(EAI_BADFLAGS) #define EAI_BADFLAGS 3002 #endif #if !defined(EAI_BADHINTS) #define EAI_BADHINTS 3013 #endif #if !defined(EAI_CANCELED) #define EAI_CANCELED 3003 #endif #if !defined(EAI_FAIL) #define EAI_FAIL 3004 #endif #if !defined(EAI_FAMILY) #define EAI_FAMILY 3005 #endif #if !defined(EAI_MEMORY) #define EAI_MEMORY 3006 #endif #if !defined(EAI_NODATA) #define EAI_NODATA 3007 #endif #if !defined(EAI_NONAME) #define EAI_NONAME 3008 #endif #if !defined(EAI_OVERFLOW) #define EAI_OVERFLOW 3009 #endif #if !defined(EAI_PROTOCOL) #define EAI_PROTOCOL 3014 #endif #if !defined(EAI_SERVICE) #define EAI_SERVICE 3010 #endif #if !defined(EAI_SOCKTYPE) #define EAI_SOCKTYPE 3011 #endif #if !defined(EALREADY) #define EALREADY 37 #endif #if !defined(EBADF) #define EBADF 9 #endif #if !defined(EBUSY) #define EBUSY 16 #endif #if !defined(ECANCELED) #define ECANCELED 89 #endif #if !defined(ECHARSET) #define ECHARSET 4080 #endif #if !defined(ECONNABORTED) #define ECONNABORTED 53 #endif #if !defined(ECONNREFUSED) #define ECONNREFUSED 61 #endif #if !defined(ECONNRESET) #define ECONNRESET 54 #endif #if !defined(EDESTADDRREQ) #define EDESTADDRREQ 39 #endif #if !defined(EEXIST) #define EEXIST 17 #endif #if !defined(EFAULT) #define EFAULT 14 #endif #if !defined(EFBIG) #define EFBIG 27 #endif #if !defined(EHOSTUNREACH) #define EHOSTUNREACH 65 #endif #if !defined(EINTR) #define EINTR 4 #endif #if !defined(EINVAL) #define EINVAL 22 #endif #if !defined(EIO) #define EIO 5 #endif #if !defined(EISCONN) #define EISCONN 56 #endif #if !defined(EISDIR) #define EISDIR 21 #endif #if !defined(ELOOP) #define ELOOP 62 #endif #if !defined(EMFILE) #define EMFILE 24 #endif #if !defined(EMSGSIZE) #define EMSGSIZE 40 #endif #if !defined(ENAMETOOLONG) #define ENAMETOOLONG 63 #endif #if !defined(ENETDOWN) #define ENETDOWN 50 #endif #if !defined(ENETUNREACH) #define ENETUNREACH 51 #endif #if !defined(ENFILE) #define ENFILE 23 #endif #if !defined(ENOBUFS) #define ENOBUFS 55 #endif #if !defined(ENODEV) #define ENODEV 19 #endif #if !defined(ENOENT) #define ENOENT 2 #endif #if !defined(ENOMEM) #define ENOMEM 12 #endif #if !defined(ENONET) #define ENONET 4056 #endif #if !defined(ENOPROTOOPT) #define ENOPROTOOPT 42 #endif #if !defined(ENOSPC) #define ENOSPC 28 #endif #if !defined(ENOSYS) #define ENOSYS 78 #endif #if !defined(ENOTCONN) #define ENOTCONN 57 #endif #if !defined(ENOTDIR) #define ENOTDIR 20 #endif #if !defined(ENOTEMPTY) #define ENOTEMPTY 66 #endif #if !defined(ENOTSOCK) #define ENOTSOCK 38 #endif #if !defined(ENOTSUP) #define ENOTSUP 45 #endif #if !defined(EOVERFLOW) #define EOVERFLOW 84 #endif #if !defined(EPERM) #define EPERM 1 #endif #if !defined(EPIPE) #define EPIPE 32 #endif #if !defined(EPROTO) #define EPROTO 100 #endif #if !defined(EPROTONOSUPPORT) #define EPROTONOSUPPORT 43 #endif #if !defined(EPROTOTYPE) #define EPROTOTYPE 41 #endif #if !defined(ERANGE) #define ERANGE 34 #endif #if !defined(EROFS) #define EROFS 30 #endif #if !defined(ESHUTDOWN) #define ESHUTDOWN 58 #endif #if !defined(ESPIPE) #define ESPIPE 29 #endif #if !defined(ESRCH) #define ESRCH 3 #endif #if !defined(ETIMEDOUT) #define ETIMEDOUT 60 #endif #if !defined(ETXTBSY) #define ETXTBSY 26 #endif #if !defined(EXDEV) #define EXDEV 18 #endif #if !defined(UNKNOWN) #define UNKNOWN 4094 #endif // this is intentionally always overridden #if defined(EOF) #undef EOF #endif #define EOF 4095 #if !defined(ENXIO) #define ENXIO 6 #endif #if !defined(EMLINK) #define EMLINK 31 #endif #if !defined(EHOSTDOWN) #define EHOSTDOWN 64 #endif #if !defined(EREMOTEIO) #define EREMOTEIO 4030 #endif #if !defined(ENOTTY) #define ENOTTY 25 #endif #if !defined(EFTYPE) #define EFTYPE 79 #endif #if !defined(EILSEQ) #define EILSEQ 92 #endif #if !defined(ESOCKTNOSUPPORT) #define ESOCKTNOSUPPORT 44 #endif #if !defined(ENODATA) #define ENODATA 96 #endif #if !defined(EUNATCH) #define EUNATCH 4023 #endif #define BUN_UV_ERRNO_MAP(macro) \ macro(E2BIG, "argument list too long") \ macro(EACCES, "permission denied") \ macro(EADDRINUSE, "address already in use") \ macro(EADDRNOTAVAIL, "address not available") \ macro(EAFNOSUPPORT, "address family not supported") \ macro(EAGAIN, "resource temporarily unavailable") \ macro(EAI_ADDRFAMILY, "address family not supported") \ macro(EAI_AGAIN, "temporary failure") \ macro(EAI_BADFLAGS, "bad ai_flags value") \ macro(EAI_BADHINTS, "invalid value for hints") \ macro(EAI_CANCELED, "request canceled") \ macro(EAI_FAIL, "permanent failure") \ macro(EAI_FAMILY, "ai_family not supported") \ macro(EAI_MEMORY, "out of memory") \ macro(EAI_NODATA, "no address") \ macro(EAI_NONAME, "unknown node or service") \ macro(EAI_OVERFLOW, "argument buffer overflow") \ macro(EAI_PROTOCOL, "resolved protocol is unknown") \ macro(EAI_SERVICE, "service not available for socket type") \ macro(EAI_SOCKTYPE, "socket type not supported") \ macro(EALREADY, "connection already in progress") \ macro(EBADF, "bad file descriptor") \ macro(EBUSY, "resource busy or locked") \ macro(ECANCELED, "operation canceled") \ macro(ECHARSET, "invalid Unicode character") \ macro(ECONNABORTED, "software caused connection abort") \ macro(ECONNREFUSED, "connection refused") \ macro(ECONNRESET, "connection reset by peer") \ macro(EDESTADDRREQ, "destination address required") \ macro(EEXIST, "file already exists") \ macro(EFAULT, "bad address in system call argument") \ macro(EFBIG, "file too large") \ macro(EHOSTUNREACH, "host is unreachable") \ macro(EINTR, "interrupted system call") \ macro(EINVAL, "invalid argument") \ macro(EIO, "i/o error") \ macro(EISCONN, "socket is already connected") \ macro(EISDIR, "illegal operation on a directory") \ macro(ELOOP, "too many symbolic links encountered") \ macro(EMFILE, "too many open files") \ macro(EMSGSIZE, "message too long") \ macro(ENAMETOOLONG, "name too long") \ macro(ENETDOWN, "network is down") \ macro(ENETUNREACH, "network is unreachable") \ macro(ENFILE, "file table overflow") \ macro(ENOBUFS, "no buffer space available") \ macro(ENODEV, "no such device") \ macro(ENOENT, "no such file or directory") \ macro(ENOMEM, "not enough memory") \ macro(ENONET, "machine is not on the network") \ macro(ENOPROTOOPT, "protocol not available") \ macro(ENOSPC, "no space left on device") \ macro(ENOSYS, "function not implemented") \ macro(ENOTCONN, "socket is not connected") \ macro(ENOTDIR, "not a directory") \ macro(ENOTEMPTY, "directory not empty") \ macro(ENOTSOCK, "socket operation on non-socket") \ macro(ENOTSUP, "operation not supported on socket") \ macro(EOVERFLOW, "value too large for defined data type") \ macro(EPERM, "operation not permitted") \ macro(EPIPE, "broken pipe") \ macro(EPROTO, "protocol error") \ macro(EPROTONOSUPPORT, "protocol not supported") \ macro(EPROTOTYPE, "protocol wrong type for socket") \ macro(ERANGE, "result too large") \ macro(EROFS, "read-only file system") \ macro(ESHUTDOWN, "cannot send after transport endpoint shutdown") \ macro(ESPIPE, "invalid seek") \ macro(ESRCH, "no such process") \ macro(ETIMEDOUT, "connection timed out") \ macro(ETXTBSY, "text file is busy") \ macro(EXDEV, "cross-device link not permitted") \ macro(UNKNOWN, "unknown error") \ macro(EOF, "end of file") \ macro(ENXIO, "no such device or address") \ macro(EMLINK, "too many links") \ macro(EHOSTDOWN, "host is down") \ macro(EREMOTEIO, "remote I/O error") \ macro(ENOTTY, "inappropriate ioctl for device") \ macro(EFTYPE, "inappropriate file type or format") \ macro(EILSEQ, "illegal byte sequence") \ macro(ESOCKTNOSUPPORT, "socket type not supported") \ macro(ENODATA, "no data available") \ macro(EUNATCH, "protocol driver not attached") // clang-format on namespace Bun { namespace ProcessBindingUV { JSC_DEFINE_HOST_FUNCTION(jsErrname, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { auto& vm = JSC::getVM(globalObject); auto arg0 = callFrame->argument(0); // Node.js crashes here: // However, we should ensure this function never throws // That's why we do not call toPrimitive here or throw on invalid input. if (!arg0.isInt32AsAnyInt()) [[unlikely]] { return JSValue::encode(jsString(vm, String("Unknown system error"_s))); } auto err = arg0.toInt32(globalObject); #define CASE(name, desc) \ if (err == -name) return JSValue::encode(JSC::jsString(vm, String(#name##_s))); BUN_UV_ERRNO_MAP(CASE) #undef CASE return JSValue::encode(jsString(vm, makeString("Unknown system error: "_s, err))); } JSC_DEFINE_HOST_FUNCTION(jsGetErrorMap, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { auto& vm = JSC::getVM(globalObject); auto map = JSC::JSMap::create(vm, globalObject->mapStructure()); // Inlining each of these via macros costs like 300 KB. const auto putProperty = [](JSC::VM& vm, JSC::JSMap* map, JSC::JSGlobalObject* globalObject, ASCIILiteral name, int value, ASCIILiteral desc) -> void { auto arr = JSC::constructEmptyArray(globalObject, static_cast(nullptr), 2); // RETURN_IF_EXCEPTION arr->putDirectIndex(globalObject, 0, JSC::jsString(vm, String(name))); arr->putDirectIndex(globalObject, 1, JSC::jsString(vm, String(desc))); map->set(globalObject, JSC::jsNumber(value), arr); }; #define PUT_PROPERTY(name, desc) putProperty(vm, map, globalObject, #name##_s, -name, desc##_s); BUN_UV_ERRNO_MAP(PUT_PROPERTY) #undef PUT_PROPERTY return JSValue::encode(map); } JSObject* create(VM& vm, JSGlobalObject* globalObject) { auto bindingObject = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 0); EnsureStillAliveScope ensureStillAlive(bindingObject); bindingObject->putDirect(vm, JSC::Identifier::fromString(vm, "errname"_s), JSC::JSFunction::create(vm, globalObject, 1, "errname"_s, jsErrname, ImplementationVisibility::Public)); // Inlining each of these via macros costs like 300 KB. // Before: 96305608 // After: 95973832 const auto putNamedProperty = [](JSC::VM& vm, JSObject* bindingObject, const ASCIILiteral name, int value) -> void { bindingObject->putDirect(vm, JSC::Identifier::fromString(vm, name), JSC::jsNumber(value)); }; #define PUT_PROPERTY(name, desc) \ putNamedProperty(vm, bindingObject, "UV_" #name##_s, -name); BUN_UV_ERRNO_MAP(PUT_PROPERTY) #undef PUT_PROPERTY bindingObject->putDirect(vm, JSC::Identifier::fromString(vm, "getErrorMap"_s), JSC::JSFunction::create(vm, globalObject, 0, "getErrorMap"_s, jsGetErrorMap, ImplementationVisibility::Public)); return bindingObject; } } // namespace ProcessBindingUV } // namespace Bun