aboutsummaryrefslogtreecommitdiff
path: root/src/micro/micro.c
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-15 17:03:03 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-15 17:03:03 +0330
commit7cb983bbea98d2038b2a8015a6d1f1afd40991c9 (patch)
treeec3d88a15801207fc6d8d3c6d142617ffec85460 /src/micro/micro.c
parentmerge work/borrow: borrow returns before definition, borrows clause, borrow m... (diff)
parentbench: rss probe path fix (diff)
merge work/actors: wasm seed bootstrap (seed/MANIFEST), shared copy-on-write actor memory, top-level hold blocks on all backends and lsp
Diffstat (limited to 'src/micro/micro.c')
-rw-r--r--src/micro/micro.c50
1 files changed, 44 insertions, 6 deletions
diff --git a/src/micro/micro.c b/src/micro/micro.c
index 23994dd..e095451 100644
--- a/src/micro/micro.c
+++ b/src/micro/micro.c
@@ -34,6 +34,10 @@
#include "micro_port.h"
#include "fops.h"
#include "bops.h"
+#ifdef ZY_THREADS
+#define HOLD_THREADS
+#endif
+#include "hold.h"
#define NENH 512
#define XOP0 22
#define XPOOL 4096
@@ -537,6 +541,11 @@ static int run_from(int p, int s, int r)
/* poll: a streaming port suspends once, so its host can deliver input that is waiting */
result = micro_syscall(m, b, 0, 0, 0);
if (result == MICRO_WAIT) { sus_p = p - 1; sus_s = s; sus_r = r; return MICRO_SUSPENDED; }
+ } else if (b == 57) {
+ result = hold_enter(m, mw, m[a + 1], m[a + 2]);
+ if (result == -2) { micro_msg("zy: a hold block was entered while a later one was held; hold blocks are entered in the order they are declared\n"); context_call(7, 2, 0, 0, s + 2, r); return 1; } /* a trap: exit status 2 */
+ } else if (b == 58) {
+ result = hold_leave(m, mw, m[a + 1], m[a + 2]);
} else result = context_call(b, m[a + 1], m[a + 2], m[a + 3], s + 2, r);
m[a] = result;
s += 2;
@@ -647,6 +656,11 @@ extern size_t micro_context_port_size(void);
extern void micro_context_port_save(void *);
extern void micro_context_port_restore(const void *);
extern void micro_context_port_free(void);
+#ifndef _WIN32
+extern Cell *micro_mem_clone(void);
+extern void micro_mem_adopt(Cell *mem, UCell words);
+extern void micro_mem_release(Cell *mem);
+#endif
#define CONTEXT_HANDLE_LO 0x40000000
typedef struct ContextChannel { Cell handle; int fd; struct ContextChannel *next; } ContextChannel;
typedef struct VmContext {
@@ -658,6 +672,7 @@ typedef struct VmContext {
UCell words, limit, initial;
int sp, rp, exit_code, requested_exit, enhancement_count, input_flag, input_known;
Cell *memory;
+ int memory_mapped;
void *port;
Xop operations[XPOOL];
Enh enhancements[NENH];
@@ -683,15 +698,26 @@ static int context_close(Cell handle) {
}
static void context_snapshot_free(VmContext *context) {
free(context->port);
- if (context->memory) { free(context->memory); atomic_fetch_sub(&context_memory_live, 1); }
+ if (context->memory) {
+#ifndef _WIN32
+ if (context->memory_mapped) micro_mem_release(context->memory); else
+#endif
+ free(context->memory);
+ atomic_fetch_sub(&context_memory_live, 1);
+ }
}
static void *context_worker(void *opaque) {
VmContext *context = opaque;
context_current = context; context->worker_channel.next = context_channels; context_channels = &context->worker_channel;
micro_context_port_restore(context->port); free(context->port); context->port = 0;
memory_limit = context->limit; memory_initial = context->initial;
+ if (context->memory_mapped) {
+#ifndef _WIN32
+ micro_mem_adopt(context->memory, context->words); context->memory = 0;
+#endif
+ }
if (!mem_grow_words(context->words)) { context->exit_code = -1; context_close(context->worker_channel.handle); return 0; }
- memcpy(m, context->memory, (size_t)context->words * sizeof(Cell)); free(context->memory); context->memory = 0;
+ if (context->memory) { memcpy(m, context->memory, (size_t)context->words * sizeof(Cell)); free(context->memory); context->memory = 0; }
stack_control = context->stack; jflag = context->input_flag; jknown = context->input_known;
xuse = context->enhancement_count; memcpy(xops, context->operations, sizeof xops); memcpy(enh, context->enhancements, sizeof enh);
int sp = context->sp, rp = context->rp; Cell entry = context->entry;
@@ -701,7 +727,7 @@ static void *context_worker(void *opaque) {
if (!context->requested_exit) context->exit_code = context_cancelled() ? 0 : result ? -1 : inmem(final_s) ? (int)m[final_s] : 0;
context_close(context->worker_channel.handle);
while (context_children) context_join(context_children->token, 1);
- micro_context_port_free(); m = 0; atomic_fetch_sub(&context_memory_live, 1); context_current = 0; return 0;
+ hold_release_all(); micro_context_port_free(); m = 0; atomic_fetch_sub(&context_memory_live, 1); context_current = 0; return 0;
}
static Cell context_start(Cell entry, Cell channel, int sp, int rp) {
if (!inmem(entry) || !inmem(channel) || (entry >= HEAP_LO && (!inmem(entry - 3) || m[entry - 3] != (entry ^ 0x2B7E1516)))) return -1;
@@ -714,12 +740,17 @@ static Cell context_start(Cell entry, Cell channel, int sp, int rp) {
context->parent_channel.handle = CONTEXT_HANDLE_LO + atomic_fetch_add(&context_sequence, 1) + 1;
context->worker_channel.handle = CONTEXT_HANDLE_LO + atomic_fetch_add(&context_sequence, 1) + 1;
context->parent_channel.fd = fd[0]; context->worker_channel.fd = fd[1]; atomic_init(&context->stop, 0);
- context->port = malloc(micro_context_port_size()); context->memory = malloc((size_t)mw * sizeof(Cell));
+ context->port = malloc(micro_context_port_size());
+#ifndef _WIN32
+ context->memory = micro_mem_clone(); context->memory_mapped = context->memory != 0;
+ if (!context->memory)
+#endif
+ context->memory = malloc((size_t)mw * sizeof(Cell));
if (context->memory) atomic_fetch_add(&context_memory_live, 1);
if (!context->port || !context->memory) goto failed;
- micro_context_port_save(context->port); memcpy(context->memory, m, (size_t)mw * sizeof(Cell)); context->memory[channel] = context->worker_channel.handle;
+ micro_context_port_save(context->port); if (!context->memory_mapped) memcpy(context->memory, m, (size_t)mw * sizeof(Cell)); context->memory[channel] = context->worker_channel.handle;
memcpy(context->operations, xops, sizeof xops); memcpy(context->enhancements, enh, sizeof enh);
- pthread_attr_t attributes; pthread_attr_init(&attributes); pthread_attr_setstacksize(&attributes, 16u << 20);
+ pthread_attr_t attributes; pthread_attr_init(&attributes); pthread_attr_setstacksize(&attributes, 4u << 20); /* the vm keeps its own stacks in vm memory; 4 MB of address space covers the deepest native recursion (jit compile, o3) */
int result = pthread_create(&context->thread, &attributes, context_worker, context); pthread_attr_destroy(&attributes);
if (result) goto failed;
context->parent_channel.next = context_channels; context_channels = &context->parent_channel;
@@ -776,6 +807,13 @@ int micro_run(void)
micro_msg("zy: genome does not fit\n");
return 1;
}
+#ifdef MICRO_PORT_IMAGE
+ /* the port may hand over an image of its own in place of the embedded one
+ (the wasm bootstrap seed does, to run a freshly built compiler) */
+ i = micro_port_image(m, (UCell)GORG, (UCell)FBOT);
+ if (i < 0) { micro_msg("zy: bad image\n"); return 1; }
+ if (i == 0)
+#endif
for (i = 0; i < GLEN; i++) m[GORG + i] = genome_word(i);
jknown = 0;
return run(GORG);