mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
A nested entry below the mark makes its context with ni_make_context, so macOS clears only the top slice of the range instead of the whole of Node's stack below the mark on every nested call (17 ms per call, and the cross-heap GC test ran past its timeout). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
101 lines
3.2 KiB
C
101 lines
3.2 KiB
C
/* Loads a libnode pack the way scr_node_island.c does (dlopen the bridge,
|
|
* check its ABI, start Node from the snapshot with the runtime's embedded
|
|
* bootstrap) and makes calls through the bridge: synchronous results and
|
|
* errors, and an asynchronous call settled by Node's own loop, which this
|
|
* host runs the way the runtime's hosted loop does (host_loop, a
|
|
* checkpoint, run_loop) with no runtime work of its own. bridge.test.ts
|
|
* compares the transcript. Usage: bridge-smoke <pack dir> <module path> */
|
|
#include <dlfcn.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "scr_node_bridge.h"
|
|
#include "scr_node_island_host.h"
|
|
|
|
#ifdef __APPLE__
|
|
#define BRIDGE_FILE "libscr_node_bridge.dylib"
|
|
#else
|
|
#define BRIDGE_FILE "libscr_node_bridge.so"
|
|
#endif
|
|
|
|
static int settled = 0;
|
|
|
|
static void settle(uint32_t id, const char *outcome, size_t len) {
|
|
printf("settle %u %.*s\n", id, (int)len, outcome);
|
|
settled++;
|
|
}
|
|
|
|
static void on_exit_code(int code) {
|
|
printf("exit %d\n", code);
|
|
fflush(stdout);
|
|
_Exit(code);
|
|
}
|
|
|
|
static void run(uint32_t kind, uint32_t token) {
|
|
printf("run %u %u\n", kind, token);
|
|
}
|
|
|
|
static void io_state(ScrNodeIoState *state) {
|
|
state->nfds = 0;
|
|
state->alive = 0;
|
|
state->ready = 0;
|
|
state->cap_ms = -1;
|
|
}
|
|
|
|
static void io_dispatch(void) {}
|
|
static void microtasks_done(void) {}
|
|
|
|
static void listen(uint32_t event, const char *name, uint32_t listener, int add, int once) {
|
|
printf("listen %u %s %u %d %d\n", event, name, listener, add, once);
|
|
}
|
|
|
|
static uintptr_t stack_limit(void) { return 0; }
|
|
static uintptr_t stack_start(void) { return 0; }
|
|
|
|
static const ScrNodeBridgeHost host = {settle, on_exit_code, run, io_state, io_dispatch,
|
|
microtasks_done, listen, stack_limit, stack_start};
|
|
|
|
static void call(const ScrNodeBridge *b, uint32_t id, int sync, const char *module,
|
|
const char *name, const char *args) {
|
|
size_t len = 0;
|
|
char *out = b->call(id, sync, module, "./smoke.cjs", name, args, strlen(args), &len);
|
|
if (out != NULL) {
|
|
printf("%s %s -> %.*s\n", sync ? "sync" : "async", name, (int)len, out);
|
|
b->release(out);
|
|
} else {
|
|
printf("%s %s -> pending\n", sync ? "sync" : "async", name);
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
if (argc != 3) return 2;
|
|
char path[4096];
|
|
snprintf(path, sizeof path, "%s/" BRIDGE_FILE, argv[1]);
|
|
void *lib = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
|
|
if (lib == NULL) {
|
|
fprintf(stderr, "%s\n", dlerror());
|
|
return 1;
|
|
}
|
|
const ScrNodeBridge *(*entry)(void) = (const ScrNodeBridge *(*)(void))dlsym(lib, SCR_NODE_BRIDGE_ENTRY);
|
|
const ScrNodeBridge *b = entry();
|
|
printf("abi %u ok %d\n", b->abi, b->abi == SCR_NODE_BRIDGE_ABI);
|
|
char *error = b->start(&host, scr_node_island_host_js, argv[0], 0);
|
|
if (error != NULL) {
|
|
fprintf(stderr, "%s\n", error);
|
|
return 1;
|
|
}
|
|
/* The caller file is the module itself: "./smoke.cjs" resolves beside it. */
|
|
const char *file = argv[2];
|
|
call(b, 0, 1, file, "add", "[2,3]");
|
|
call(b, 0, 1, file, "fails", "[]");
|
|
call(b, 0, 1, file, "missing", "[]");
|
|
call(b, 7, 0, file, "later", "[5]");
|
|
b->host_loop();
|
|
b->checkpoint(0);
|
|
b->run_loop(0);
|
|
call(b, 0, 1, file, "quit", "[3]");
|
|
return 0;
|
|
}
|