diff options
Diffstat (limited to 'docs/history/10-zc/code/core.c')
| -rw-r--r-- | docs/history/10-zc/code/core.c | 332 |
1 files changed, 0 insertions, 332 deletions
diff --git a/docs/history/10-zc/code/core.c b/docs/history/10-zc/code/core.c deleted file mode 100644 index ed148c6..0000000 --- a/docs/history/10-zc/code/core.c +++ /dev/null @@ -1,332 +0,0 @@ -/* zygote core: puts the genome (the zc compiler and its runtime, both vm code) - into memory and runs it. on arm64, every block of vm code is translated to - arm64 the first time it is reached, straight from live memory. stores that - land on translated words throw those translations away, so code that - rewrites itself, including the resident compiler, just gets retranslated - on the next visit. on other hosts (or with -DZYINTERP) a plain interpreter - with the same semantics runs instead. ZYTRACE=1 logs translations on stderr. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#if defined(__aarch64__) && !defined(ZYINTERP) -#define ZYJIT 1 -#include <sys/mman.h> -#ifdef __APPLE__ -#include <pthread.h> -#include <libkern/OSCacheControl.h> -#endif -#endif -#include "genome.h" - -#ifndef JTYPE -#define JTYPE char -#endif -char Q(void); -void G(char); -extern JTYPE J; - -#define MW (1 << 20) /* memory, in words */ -#define DS0 (MW - 16) /* data stack grows down from here */ -#define RS0 0xF0000 /* return stack grows up from here */ -#define CODEW (4 << 20) /* 16 MB of code, in instruction words */ -#define MAXB 65536 -#define BLKW 1024 /* longest block, in vm words */ - -static int m[MW]; -static int trace; -#ifdef ZYJIT -static unsigned char cov[MW]; /* 1 if a live translation covers the word */ -static void *tab[MW]; /* vm address -> translation */ -static struct { int a, b; } bl[MAXB]; /* live translations cover [a,b); a < 0 is dead */ -static int nbl; -static unsigned *code, *cp, *x_enter, *x_exit, *x_disp, *x_first; -static long S[9]; /* m, s, r, tab, cov, Q, G, &J, store hook; read by the stubs */ - -enum { W0 = 0, W1 = 1, X9 = 9, X10, X11, M = 19, SP = 20, RP = 21, TAB = 22, ST = 23 }; - -static void E(unsigned x) { *cp++ = x; } -static void li(int d, int v) -{ - unsigned u = (unsigned)v; - E(0x52800000 | (u & 0xffff) << 5 | d); - if (u >> 16) E(0x72a00000 | (u >> 16) << 5 | d); -} -static void ldr_post(int t, int n, int i) { E(0xb8400400 | (i & 0x1ff) << 12 | n << 5 | t); } -static void ldr_pre(int t, int n, int i) { E(0xb8400c00 | (i & 0x1ff) << 12 | n << 5 | t); } -static void str_pre(int t, int n, int i) { E(0xb8000c00 | (i & 0x1ff) << 12 | n << 5 | t); } -static void str_post(int t, int n, int i) { E(0xb8000400 | (i & 0x1ff) << 12 | n << 5 | t); } -static void ldr_u(int t, int n, int o) { E(0xb9400000 | (o / 4) << 10 | n << 5 | t); } -static void str_u(int t, int n, int o) { E(0xb9000000 | (o / 4) << 10 | n << 5 | t); } -static void ldrx_u(int t, int n, int o) { E(0xf9400000 | (o / 8) << 10 | n << 5 | t); } -static void ldr_rr(int t, int n, int r, int ext) { E(0xb8600800 | r << 16 | ext << 13 | 1 << 12 | n << 5 | t); } -static void str_rr(int t, int n, int r, int ext) { E(0xb8200800 | r << 16 | ext << 13 | 1 << 12 | n << 5 | t); } -static void ldp_post(int t, int u, int n, int i) { E(0x28c00000 | ((i / 4) & 0x7f) << 15 | u << 10 | n << 5 | t); } -static void op3(unsigned op, int d, int n, int r) { E(op | r << 16 | n << 5 | d); } -static void addx_ext(int d, int n, int r, int ext) { E(0x8b200000 | r << 16 | ext << 13 | 2 << 10 | n << 5 | d); } -static void movw(int d, int r) { E(0x2a0003e0 | r << 16 | d); } -static void blr(int n) { E(0xd63f0000 | n << 5); } -static void b_to(unsigned *t) { long o = t - cp; E(0x14000000 | (o & 0x3ffffff)); } -static void cb_fix(unsigned *at, unsigned *to) { *at |= ((to - at) & 0x7ffff) << 5; } -#define SXTW 6 -#define UXTW 2 - -static void build_stubs(void) -{ - cp = code; - x_enter = cp; /* int enter(long *S, void *code) */ - E(0xa9bc7bfd); /* stp x29, x30, [sp, #-64]! */ - E(0x910003fd); /* mov x29, sp */ - E(0xa90153f3); /* stp x19, x20, [sp, #16] */ - E(0xa9025bf5); /* stp x21, x22, [sp, #32] */ - E(0xf9001bf7); /* str x23, [sp, #48] */ - E(0xaa0003f7); /* mov x23, x0 */ - ldrx_u(M, ST, 0); - ldr_u(X9, ST, 8); addx_ext(SP, M, X9, UXTW); - ldr_u(X9, ST, 16); addx_ext(RP, M, X9, UXTW); - ldrx_u(TAB, ST, 24); - E(0xd61f0020); /* br x1 */ - x_exit = cp; /* w0 = next vm address */ - op3(0xcb000000, X9, SP, M); E(0xd342fd29); str_u(X9, ST, 8); /* s = (x20 - x19) >> 2 */ - op3(0xcb000000, X9, RP, M); E(0xd342fd29); str_u(X9, ST, 16); - E(0xa94153f3); /* ldp x19, x20, [sp, #16] */ - E(0xa9425bf5); /* ldp x21, x22, [sp, #32] */ - E(0xf9401bf7); /* ldr x23, [sp, #48] */ - E(0xa8c47bfd); /* ldp x29, x30, [sp], #64 */ - E(0xd65f03c0); /* ret */ - x_disp = cp; /* w0 = target: chain through tab[] or fall back to c */ - E(0x7144001f); /* cmp w0, #MW */ - E(0x54000002 | ((x_exit - cp) & 0x7ffff) << 5); /* b.hs exit */ - E(0xf8605ac9); /* ldr x9, [x22, w0, uxtw #3] */ - E(0xb4000009 | ((x_exit - cp) & 0x7ffff) << 5); /* cbz x9, exit */ - E(0xd61f0120); /* br x9 */ - x_first = cp; -} - -static void flush(void) -{ - memset(tab, 0, sizeof tab); - memset(cov, 0, sizeof cov); - nbl = 0; - cp = x_first; - if (trace) fprintf(stderr, "jit: flushed\n"); -} - -static void jitwrite(int on) -{ -#ifdef __APPLE__ - pthread_jit_write_protect_np(!on); -#else - (void)on; -#endif -} - -static void syncicache(unsigned *a, unsigned *b) -{ -#ifdef __APPLE__ - sys_icache_invalidate(a, (char *)b - (char *)a); -#else - __builtin___clear_cache((char *)a, (char *)b); -#endif -} - -/* store hook for words that are covered by a translation */ -static int hook(int a, int v) -{ - int j, x, hit = 0; - if (m[a] == v) return 0; - m[a] = v; - for (j = 0; j < nbl; j++) - if (bl[j].a >= 0 && bl[j].a <= a && a < bl[j].b) { - tab[bl[j].a] = 0; - for (x = bl[j].a; x < bl[j].b; x++) cov[x] = 0; - if (trace) fprintf(stderr, "jit: dropped %d..%d\n", bl[j].a, bl[j].b - 1); - bl[j].a = -1; - hit = 1; - } - for (j = 0; j < nbl; j++) - if (bl[j].a >= 0) for (x = bl[j].a; x < bl[j].b; x++) cov[x] = 1; - return hit; -} - -static void op(int i, int k) /* everything except control flow */ -{ - unsigned *a, *b, *c, *z; - switch (k) { - case 1: ldr_u(X9, SP, 0); ldr_rr(X9, M, X9, SXTW); str_u(X9, SP, 0); return; - case 2: /* store: inline unless the target word is translated */ - ldp_post(X9, X10, SP, 8); - E(0x7144013f); /* cmp w9, #MW */ - a = cp; E(0x54000002); /* b.hs done */ - ldrx_u(X11, ST, 32); - E(0x3869496b); /* ldrb w11, [x11, w9, uxtw] */ - b = cp; E(0x3500000b); /* cbnz w11, slow */ - str_rr(X10, M, X9, UXTW); - c = cp; E(0x14000000); /* b done */ - cb_fix(b, cp); /* slow: hook(a, v) */ - movw(W0, X9); movw(W1, X10); ldrx_u(X11, ST, 64); blr(X11); - z = cp; E(0x34000000); /* cbz w0, done */ - li(W0, i + 1); b_to(x_exit); /* a translation died: resume at i+1 in c */ - cb_fix(a, cp); cb_fix(z, cp); - *c |= (cp - c) & 0x3ffffff; - return; - case 3: ldr_u(X9, SP, 0); E(0x9100128a); ldr_rr(X9, X10, X9, SXTW); str_u(X9, SP, 0); return; /* add x10, x20, #4 */ - case 4: E(0x91001294); return; /* add x20, x20, #4 */ - case 5: E(0x29402a89); E(0x2900268a); return; /* ldp w9, w10, [x20]; stp w10, w9, [x20] */ - case 10: ldrx_u(X11, ST, 40); blr(X11); E(0x13001c09); str_pre(X9, SP, -4); return; /* sxtb w9, w0 */ - case 11: - ldrx_u(X9, ST, 56); - if (sizeof J == 1) E(0x39400129); else ldr_u(X9, X9, 0); /* ldrb w9, [x9] */ - str_pre(X9, SP, -4); - return; - case 12: ldr_post(W0, SP, 4); E(0x13001c00); ldrx_u(X11, ST, 48); blr(X11); return; /* sxtb w0, w0 */ - } - ldr_post(X9, SP, 4); - ldr_u(X10, SP, 0); - switch (k) { - case 13: op3(0x0b000000, X10, X10, X9); break; - case 14: op3(0x4b000000, X10, X10, X9); break; - case 15: op3(0x1b007c00, X10, X10, X9); break; - case 16: op3(0x0a000000, X10, X10, X9); break; - case 17: op3(0x2a000000, X10, X10, X9); break; - case 18: op3(0x4a000000, X10, X10, X9); break; - case 19: op3(0x1ac02800, X10, X10, X9); break; - default: E(0x6b09015f); E(0x1a9fa7ea); /* cmp w10, w9; cset w10, lt */ - } - str_u(X10, SP, 0); -} - -static void *translate(int p) -{ - unsigned *start; - int i = p, n = 0, w, k, t; - if (cp - code > CODEW - 65536 || nbl >= MAXB) flush(); - start = cp; - for (;;) { - if (i >= MW) { E(0x12800000); b_to(x_exit); break; } /* movn w0, #0: halt */ - if (n++ >= BLKW) { li(W0, i); b_to(x_disp); break; } - w = m[i]; - cov[i] = 1; - if (w & 1 && i + 1 < MW && !(m[i + 1] & 1) && (k = m[i + 1] / 2) >= 6 && k <= 8) { - t = (w - 1) / 2; /* literal + call/jmp/jz with a known target */ - cov[i + 1] = 1; - if (k == 8) { - unsigned *a; - ldr_post(X10, SP, 4); - a = cp; E(0x3500000a); /* cbnz w10, fallthrough */ - li(W0, t); b_to(x_disp); - cb_fix(a, cp); - i += 2; - continue; - } - li(X10, i + 2); - if (k == 6) str_post(X10, RP, 4); else str_u(X10, RP, 0); - li(W0, t); b_to(x_disp); - i += 2; - break; - } - if (w & 1) { li(X9, (w - 1) / 2); str_pre(X9, SP, -4); i++; continue; } - k = w / 2; - if (k == 0) { E(0x12800000); b_to(x_exit); i++; break; } - if (k < 0 || k == 6 || k == 7) { - ldr_post(W0, SP, 4); - li(X10, i + 1); - if (k == 6) str_post(X10, RP, 4); else str_u(X10, RP, 0); - if (k < 0) { li(X11, 7 - k); addx_ext(RP, RP, X11, SXTW); } - b_to(x_disp); - i++; - break; - } - if (k == 8) { /* jz: taken leaves, not taken keeps going */ - ldp_post(X9, X10, SP, 8); - E(0x3500006a); /* cbnz w10, +3 */ - movw(W0, X9); - b_to(x_disp); - i++; - continue; - } - if (k == 9) { ldr_pre(W0, RP, -4); b_to(x_disp); i++; break; } - op(i, k); - i++; - } - bl[nbl].a = p; - bl[nbl++].b = i; - tab[p] = start; - syncicache(start, cp); - if (trace) fprintf(stderr, "jit: %d..%d -> %ld bytes\n", p, i - 1, (long)((char *)cp - (char *)start)); - return start; -} - -#else -/* portable path for hosts without the arm64 jit: a plain interpreter with - the same semantics (shift counts wrap at 32, stores outside memory are - ignored, loads outside memory read 0, leaving memory halts). */ -#define LD(x) ((unsigned)(x) < MW ? m[x] : 0) -static void run(int p) -{ - int s = DS0, r = RS0, w, a, b; - unsigned long long steps = 0; - while ((unsigned)p < MW) { - w = m[p++]; - steps++; - if (w & 1) { m[--s] = w >> 1; continue; } - a = m[s]; b = m[s + 1]; - switch (w / 2) { - case 1: m[s] = LD(a); break; - case 2: if ((unsigned)a < MW) m[a] = b; s += 2; break; - case 3: m[s] = LD(s + 1 + a); break; - case 4: s++; break; - case 5: m[s] = b; m[s + 1] = a; break; - case 6: m[r++] = p; p = a; s++; break; - case 7: p = a; s++; break; - case 8: if (!b) p = a; s += 2; break; - case 9: p = m[--r]; break; - case 10: m[--s] = (signed char)Q(); break; - case 11: m[--s] = J; break; - case 12: G((char)a); s++; break; - case 13: m[++s] = b + a; break; - case 14: m[++s] = (int)((unsigned)b - (unsigned)a); break; - case 15: m[++s] = (int)((unsigned)b * (unsigned)a); break; - case 16: m[++s] = b & a; break; - case 17: m[++s] = b | a; break; - case 18: m[++s] = b ^ a; break; - case 19: m[++s] = b >> (a & 31); break; - case 20: m[++s] = b < a; break; - default: p = MW; break; /* halt, and the reserved negative opcodes */ - } - } - if (trace) fprintf(stderr, "interp: %llu steps\n", steps); -} -#endif - -int main(void) -{ - trace = getenv("ZYTRACE") != 0; - memcpy(m + GORG, genome, sizeof genome); -#ifdef ZYJIT - { - int p = GORG; - union { unsigned *u; int (*f)(long *, void *); } enter; -#ifdef __APPLE__ - code = mmap(0, CODEW * 4, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON | MAP_JIT, -1, 0); -#else - code = mmap(0, CODEW * 4, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -#endif - if (code == MAP_FAILED) { perror("mmap"); return 1; } - jitwrite(1); - build_stubs(); - jitwrite(0); - syncicache(code, cp); - S[0] = (long)m; S[1] = DS0; S[2] = RS0; S[3] = (long)tab; S[4] = (long)cov; - S[5] = (long)Q; S[6] = (long)G; S[7] = (long)&J; S[8] = (long)hook; - enter.u = x_enter; - while ((unsigned)p < MW) { - void *c = tab[p]; - if (!c) { jitwrite(1); c = translate(p); jitwrite(0); } - p = enter.f(S, c); - } - } -#else - run(GORG); -#endif - return 0; -} |
