#include "cell.h" #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #else #include #include #include #ifdef __linux__ #include #include #include #include #include #endif #endif #include static JSClassID js_dylib_class_id; static void js_dylib_finalizer(JSRuntime *rt, JSValue val) { void *handle = JS_GetOpaque(val, js_dylib_class_id); if (handle) { #ifdef _WIN32 FreeLibrary((HMODULE)handle); #else dlclose(handle); #endif } } static JSClassDef js_dylib_class = { "dylib", .finalizer = js_dylib_finalizer, }; #include JSC_CCALL(os_now, #ifdef _WIN32 LARGE_INTEGER frequency, counter; QueryPerformanceFrequency(&frequency); QueryPerformanceCounter(&counter); return number2js(js, (double)counter.QuadPart / (double)frequency.QuadPart); #elif defined(__APPLE__) static mach_timebase_info_data_t timebase = {0, 0}; if (timebase.denom == 0) { mach_timebase_info(&timebase); } uint64_t time = mach_absolute_time(); return number2js(js, (double)time * timebase.numer / timebase.denom / 1000000000.0); #else struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return number2js(js, (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0); #endif ) JSC_CCALL(os_sleep, double secs = js2number(js,argv[0]); #ifdef _WIN32 Sleep((DWORD)(secs * 1000)); #else struct timespec ts; ts.tv_sec = (time_t)secs; ts.tv_nsec = (long)((secs - ts.tv_sec) * 1000000000); nanosleep(&ts, NULL); #endif ) static JSValue js_os_totalmem(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; #ifdef _WIN32 MEMORYSTATUSEX statex; statex.dwLength = sizeof(statex); if (!GlobalMemoryStatusEx(&statex)) return JS_ThrowInternalError(js,"GlobalMemoryStatusEx failed"); return JS_NewInt64(js,(int64_t)(statex.ullTotalPhys / (1024 * 1024))); #elif defined(__linux__) struct sysinfo info; if (sysinfo(&info) == 0) return JS_NewInt64(js,(int64_t)((info.totalram * info.mem_unit) / (1024 * 1024))); return JS_NewInt64(js,0); #elif defined(__APPLE__) int mib[2] = {CTL_HW, HW_MEMSIZE}; int64_t memsize; size_t len = sizeof(memsize); if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) return JS_NewInt64(js, memsize / (1024 * 1024)); return JS_NewInt64(js,0); #else long pages = sysconf(_SC_PHYS_PAGES); long page_size = sysconf(_SC_PAGE_SIZE); if (pages < 0 || page_size < 0) return JS_NewInt64(js,0); return JS_NewInt64(js,(int64_t)((pages * page_size) / (1024 * 1024))); #endif return ret; } static JSValue js_os_platform(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; #ifdef _WIN32 return JS_NewString(js,"Windows"); #elif defined(__linux__) return JS_NewString(js,"Linux"); #elif defined(__APPLE__) return JS_NewString(js,"macOS"); #elif defined(__FreeBSD__) return JS_NewString(js,"FreeBSD"); #elif defined(__OpenBSD__) return JS_NewString(js,"OpenBSD"); #elif defined(__NetBSD__) return JS_NewString(js,"NetBSD"); #else return JS_NewString(js,"Unknown"); #endif return ret; } static JSValue js_os_hostname(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; #ifdef _WIN32 TCHAR buffer[256] = TEXT(""); DWORD size = sizeof(buffer) / sizeof(TCHAR); GetComputerName(buffer, &size); return JS_NewString(js, buffer); #else struct utsname buffer; if (uname(&buffer) != 0) return JS_ThrowReferenceError(js,"Could not get hostname."); return JS_NewString(js, buffer.nodename); #endif return ret; } static JSValue js_os_arch(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; #if defined(__x86_64__) || defined(_M_X64) return JS_NewString(js,"x64"); #elif defined(__aarch64__) || defined(_M_ARM64) return JS_NewString(js,"arm64"); #elif defined(__arm__) || defined(_M_ARM) return JS_NewString(js,"arm"); #elif defined(__i386__) || defined(_M_IX86) return JS_NewString(js,"ia32"); #elif defined(__loongarch__) || defined(__loongarch32) || defined(__loongarch64) return JS_NewString(js,"loong64"); #elif defined(__mips__) || defined(__mips) || defined(_M_MIPS) // You might want to distinguish mips vs mipsel return JS_NewString(js,"mips"); #elif defined(__ppc64__) || defined(__powerpc64__) || defined(_M_PPC) // You might want to distinguish ppc vs ppc64, big-endian vs little-endian return JS_NewString(js,"ppc64"); #elif defined(__riscv) && __riscv_xlen == 64 return JS_NewString(js,"riscv64"); #elif defined(__s390x__) return JS_NewString(js,"s390x"); #else return JS_NewString(js,"unknown"); #endif return ret; } static JSValue js_os_freemem(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; #ifdef _WIN32 MEMORYSTATUSEX statex; statex.dwLength = sizeof(statex); if (!GlobalMemoryStatusEx(&statex)) return JS_ThrowInternalError(js,"GlobalMemoryStatusEx failed"); return JS_NewInt64(js,(int64_t)statex.ullAvailPhys); #elif defined(__linux__) struct sysinfo info; if (sysinfo(&info) == 0) return JS_NewInt64(js,(int64_t)info.freeram * info.mem_unit); return JS_NewInt64(js,0); #elif defined(__FreeBSD__) || defined(__OpenBSD__) // A very rough fallback using the same sysconf approach // (macOS or *BSD typically need specialized APIs to get free mem accurately) // This is often only "unused" pages, ignoring caches, etc. long pages = sysconf(_SC_AVPHYS_PAGES); long page_size = sysconf(_SC_PAGE_SIZE); if (pages < 0 || page_size < 0) return JS_NewInt64(js,0); return JS_NewInt64(js,(int64_t)pages * (int64_t)page_size); #else // Fallback: unknown return JS_NewInt64(js,0); #endif return ret; } static JSValue js_os_version(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; #ifdef _WIN32 typedef LONG (WINAPI *RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); HMODULE h = GetModuleHandleA("ntdll.dll"); if (h) { RtlGetVersionPtr fx = (RtlGetVersionPtr)GetProcAddress(h, "RtlGetVersion"); if (fx) { RTL_OSVERSIONINFOW ver; memset(&ver, 0, sizeof(ver)); ver.dwOSVersionInfoSize = sizeof(ver); if (!fx(&ver)) { char buf[128]; sprintf(buf, "%u.%u.%u", (unsigned)ver.dwMajorVersion, (unsigned)ver.dwMinorVersion, (unsigned)ver.dwBuildNumber ); return JS_NewString(js, buf); } } } OSVERSIONINFOW wver; memset(&wver, 0, sizeof(wver)); wver.dwOSVersionInfoSize = sizeof(wver); if (GetVersionExW(&wver)) { char buf[128]; sprintf(buf, "%u.%u.%u", (unsigned)wver.dwMajorVersion, (unsigned)wver.dwMinorVersion, (unsigned)wver.dwBuildNumber ); return JS_NewString(js, buf); } return JS_NewString(js, "Windows_Unknown"); #else struct utsname info; if (!uname(&info)) return JS_NewString(js, info.release); return JS_NewString(js, ""); #endif return ret; } JSC_CCALL(os_buffer2string, if (argc < 1) { return JS_ThrowTypeError(js, "buffer2string expects an ArrayBuffer"); } size_t len; uint8_t *buf = js_get_blob_data(js, &len, argv[0]); if (!buf) { return JS_ThrowTypeError(js, "First argument must be an ArrayBuffer"); } // Create a null-terminated string from the buffer char *str = js_malloc(js, len + 1); if (!str) { return JS_ThrowInternalError(js, "Failed to allocate memory"); } memcpy(str, buf, len); str[len] = '\0'; JSValue result = JS_NewString(js, str); js_free(js, str); return result; ) #define JSOBJ_ADD_FIELD(OBJ, STRUCT, FIELD, TYPE) \ JS_SetPropertyStr(js, OBJ, #FIELD, TYPE##2js(js,STRUCT.FIELD));\ #define JSJMEMRET(FIELD) JSOBJ_ADD_FIELD(ret, jsmem, FIELD, number) JSC_CCALL(os_mallinfo, ret = JS_NULL; /*struct mallinfo jsmem = mallinfo(); ret = JS_NewObject(js); JSJMEMRET(arena); JSJMEMRET(ordblks); JSJMEMRET(smblks); JSJMEMRET(hblks); JSJMEMRET(hblkhd); JSJMEMRET(usmblks); JSJMEMRET(fsmblks); JSJMEMRET(uordblks); JSJMEMRET(fordblks); JSJMEMRET(keepcost);*/ ) static JSValue js_os_rusage(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; ret = JS_NewObject(js); #if defined(__linux__) || defined(__APPLE__) struct rusage jsmem; getrusage(RUSAGE_SELF, &jsmem); JSJMEMRET(ru_maxrss); JSJMEMRET(ru_ixrss); JSJMEMRET(ru_idrss); JSJMEMRET(ru_isrss); JSJMEMRET(ru_minflt); JSJMEMRET(ru_majflt); JSJMEMRET(ru_nswap); JSJMEMRET(ru_inblock); JSJMEMRET(ru_oublock); JSJMEMRET(ru_msgsnd); JSJMEMRET(ru_msgrcv); JSJMEMRET(ru_nsignals); JSJMEMRET(ru_nvcsw); JSJMEMRET(ru_nivcsw); #endif return ret; } JSC_SCALL(os_system, int err = system(str); ret = number2js(js,err); ) JSC_SCALL(os_exit, exit(0); ) static JSValue js_os_dylib_open(JSContext *js, JSValue self, int argc, JSValue *argv) { if (argc < 1) { return JS_ThrowTypeError(js, "dylib_open requires a path argument"); } const char *path = JS_ToCString(js, argv[0]); if (!path) { return JS_ThrowTypeError(js, "path must be a string"); } void *handle; #ifdef _WIN32 handle = LoadLibraryA(path); #else handle = dlopen(path, RTLD_NOW | RTLD_LOCAL); #endif JS_FreeCString(js, path); if (!handle) { const char *error_msg = "Could not load library"; #ifndef _WIN32 const char *dl_error = dlerror(); if (dl_error) { error_msg = dl_error; } #endif return JS_ThrowReferenceError(js, "Failed to load library: %s", error_msg); } JSValue dylib_obj = JS_NewObjectClass(js, js_dylib_class_id); if (JS_IsException(dylib_obj)) { #ifdef _WIN32 FreeLibrary((HMODULE)handle); #else dlclose(handle); #endif return dylib_obj; } JS_SetOpaque(dylib_obj, handle); return dylib_obj; } static JSValue js_os_dylib_symbol(JSContext *js, JSValue self, int argc, JSValue *argv) { if (argc < 2) { return JS_ThrowTypeError(js, "dylib_symbol requires dylib object and symbol name"); } void *handle = JS_GetOpaque(argv[0], js_dylib_class_id); if (!handle) { return JS_ThrowTypeError(js, "First argument must be a dylib object"); } const char *symbol_name = JS_ToCString(js, argv[1]); if (!symbol_name) { return JS_ThrowTypeError(js, "symbol name must be a string"); } JSValue (*symbol)(JSContext *js); #ifdef _WIN32 symbol = GetProcAddress((HMODULE)handle, symbol_name); #else symbol = dlsym(handle, symbol_name); #endif JS_FreeCString(js, symbol_name); if (!symbol) { const char *error_msg = "Symbol not found"; #ifndef _WIN32 const char *dl_error = dlerror(); if (dl_error) { error_msg = dl_error; } #endif return JS_ThrowReferenceError(js, "Failed to get symbol: %s", error_msg); } // Return the symbol as a pointer value return symbol(js); } JSC_CCALL(os_print, size_t len; const char *str = JS_ToCStringLen(js, &len, argv[0]); printf("%.*s", (int)len, str); JS_FreeCString(js, str); ) static JSValue js_os_load_internal(JSContext *js, JSValue self, int argc, JSValue *argv) { void *handle; #ifdef _WIN32 handle = GetModuleHandle(NULL); #else handle = dlopen(NULL, RTLD_LAZY); #endif if (argc < 1) return JS_ThrowTypeError(js, "load_internal requires a symbol name"); const char *symbol_name = JS_ToCString(js, argv[0]); if (!symbol_name) return JS_ThrowTypeError(js, "symbol name must be a string"); JSValue (*symbol)(JSContext *js); #if defined(_WIN32) symbol = GetProcAddress((HMODULE)handle, symbol_name); #else symbol = dlsym(handle, symbol_name); #endif JS_FreeCString(js, symbol_name); if (!symbol) return JS_NULL; return symbol(js); } #if defined(_WIN32) // ------- Windows: use BCryptGenRandom ------- int randombytes(void *buf, size_t n) { NTSTATUS status = BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)n, BCRYPT_USE_SYSTEM_PREFERRED_RNG); return (status == 0) ? 0 : -1; } #elif defined(__linux__) // ------- Linux: try getrandom, fall back to /dev/urandom ------- static int randombytes_fallback(void *buf, size_t n) { int fd = open("/dev/urandom", O_RDONLY); if (fd < 0) return -1; ssize_t r = read(fd, buf, n); close(fd); return (r == (ssize_t)n) ? 0 : -1; } int randombytes(void *buf, size_t n) { #ifdef SYS_getrandom // Try getrandom(2) if available ssize_t ret = syscall(SYS_getrandom, buf, n, 0); if (ret < 0) { // If getrandom is not supported or fails, fall back if (errno == ENOSYS) { return randombytes_fallback(buf, n); } return -1; } return (ret == (ssize_t)n) ? 0 : -1; #else // getrandom not available, just fallback return randombytes_fallback(buf, n); #endif } #else // ------- Other Unix: read from /dev/urandom ------- static int rand_fd = -1; int randombytes(void *buf, size_t n) { if (rand_fd < 0) { rand_fd = open("/dev/urandom", O_RDONLY); if (rand_fd < 0) return -1; } ssize_t r = read(rand_fd, buf, n); return (r == (ssize_t)n) ? 0 : -1; } #endif JSC_CCALL(os_random, double random_double; uint8_t *buf = (uint8_t *)&random_double; if (randombytes(buf, sizeof(double)) != 0) { return JS_ThrowInternalError(js, "failed to generate random bytes"); } return JS_NewInt32(js, random_double); ) static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, platform, 0), MIST_FUNC_DEF(os, arch, 0), MIST_FUNC_DEF(os, totalmem, 0), MIST_FUNC_DEF(os, freemem, 0), MIST_FUNC_DEF(os, hostname, 0), MIST_FUNC_DEF(os, version, 0), MIST_FUNC_DEF(os, now, 0), MIST_FUNC_DEF(os, rusage, 0), MIST_FUNC_DEF(os, mallinfo, 0), MIST_FUNC_DEF(os, buffer2string, 1), MIST_FUNC_DEF(os, system, 1), MIST_FUNC_DEF(os, exit, 0), MIST_FUNC_DEF(os, sleep, 1), MIST_FUNC_DEF(os, dylib_open, 1), MIST_FUNC_DEF(os, dylib_symbol, 2), MIST_FUNC_DEF(os, load_internal, 1), MIST_FUNC_DEF(os, print, 1), MIST_FUNC_DEF(os, random, 0), }; JSValue js_os_use(JSContext *js) { JS_NewClassID(&js_dylib_class_id); JS_NewClass(JS_GetRuntime(js), js_dylib_class_id, &js_dylib_class); JSValue mod = JS_NewObject(js); JS_SetPropertyFunctionList(js,mod,js_os_funcs,countof(js_os_funcs)); return mod; }