part of operations, migration to 1.30

This commit is contained in:
ProgramSnail 2024-11-02 01:19:54 +03:00
parent 2c03654cca
commit e17f1f70ed
8 changed files with 166 additions and 137 deletions

View file

@ -1,7 +1,7 @@
FLAGS=-m32 -g2 -fstack-protector-all FLAGS=-m32 -g2 -fstack-protector-all
all: src/cli.c src/parser.c src/interpreter.c src/utils.c src/types.c src/virt_stack.c all: src/cli.c src/parser.c src/interpreter.c src/utils.c src/types.c src/stack.c
$(CC) $(FLAGS) -o byterun -Iinclude/ src/utils.c src/parser.c src/virt_stack.c src/interpreter.c src/cli.c ../runtime/runtime.a $(CC) $(FLAGS) -o byterun -Iinclude/ src/cli.c src/parser.c src/interpreter.c src/utils.c src/types.c src/stack.c ../runtime/runtime.a
clean: clean:
$(RM) *.a *.o *~ byterun $(RM) *.a *.o *~ byterun

View file

@ -1,9 +1,11 @@
(rule (rule
(target byterun.exe) (target byterun.exe)
(deps (deps
(:main byterun.c) (:main src/cli.c src/interpreter.c)
(:parser src/parser.c)
(:utils src/utils.c src/types.c src/stack.c)
(:runtime ../runtime/runtime.a)) (:runtime ../runtime/runtime.a))
(mode (mode
(promote (until-clean))) (promote (until-clean)))
(action (action
(run gcc -g %{main} %{runtime} -o %{target}))) (run gcc -g -Iinclude/ %{main} %{runtime} -o %{target})))

View file

@ -1,3 +1,5 @@
#pragma once
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
@ -16,126 +18,123 @@
// --- // ---
void *Bsexp(int n, ...); void Lassert(void *f, char *s, ...);
int LtagHash(char *);
// Gets a raw data_header // Gets a raw data_header
int LkindOf(void *p); aint LkindOf(void *p);
// Compare s-exprs tags // Compare s-exprs tags
int LcompareTags(void *p, void *q); aint LcompareTags(void *p, void *q);
// Functional synonym for built-in operator ":"; // Functional synonym for built-in operator ":";
void *Ls__Infix_58(void *p, void *q); void *Ls__Infix_58(void *p, void *q);
// Functional synonym for built-in operator "!!"; // Functional synonym for built-in operator "!!";
int Ls__Infix_3333(void *p, void *q); aint Ls__Infix_3333(void *p, void *q);
// Functional synonym for built-in operator "&&"; // Functional synonym for built-in operator "&&";
int Ls__Infix_3838(void *p, void *q); aint Ls__Infix_3838(void *p, void *q);
// Functional synonym for built-in operator "=="; // Functional synonym for built-in operator "==";
int Ls__Infix_6161(void *p, void *q); aint Ls__Infix_6161(void *p, void *q);
// Functional synonym for built-in operator "!="; // Functional synonym for built-in operator "!=";
int Ls__Infix_3361(void *p, void *q); aint Ls__Infix_3361(void *p, void *q);
// Functional synonym for built-in operator "<="; // Functional synonym for built-in operator "<=";
int Ls__Infix_6061(void *p, void *q); aint Ls__Infix_6061(void *p, void *q);
// Functional synonym for built-in operator "<"; // Functional synonym for built-in operator "<";
int Ls__Infix_60(void *p, void *q); aint Ls__Infix_60(void *p, void *q);
// Functional synonym for built-in operator ">="; // Functional synonym for built-in operator ">=";
int Ls__Infix_6261(void *p, void *q); aint Ls__Infix_6261(void *p, void *q);
// Functional synonym for built-in operator ">"; // Functional synonym for built-in operator ">";
int Ls__Infix_62(void *p, void *q); aint Ls__Infix_62(void *p, void *q);
// Functional synonym for built-in operator "+"; // Functional synonym for built-in operator "+";
int Ls__Infix_43(void *p, void *q); aint Ls__Infix_43(void *p, void *q);
// Functional synonym for built-in operator "-"; // Functional synonym for built-in operator "-";
int Ls__Infix_45(void *p, void *q); aint Ls__Infix_45(void *p, void *q);
// Functional synonym for built-in operator "*"; // Functional synonym for built-in operator "*";
int Ls__Infix_42(void *p, void *q); aint Ls__Infix_42(void *p, void *q);
// Functional synonym for built-in operator "/"; // Functional synonym for built-in operator "/";
int Ls__Infix_47(void *p, void *q); aint Ls__Infix_47(void *p, void *q);
// Functional synonym for built-in operator "%"; // Functional synonym for built-in operator "%";
int Ls__Infix_37(void *p, void *q); aint Ls__Infix_37(void *p, void *q);
int Llength(void *p); aint Llength(void *p);
int LtagHash(char *s); aint LtagHash(char *s);
char *de_hash(int n); char *de_hash(aint n);
int Luppercase(void *v); aint Luppercase(void *v);
int Llowercase(void *v); aint Llowercase(void *v);
int LmatchSubString(char *subj, char *patt, int pos); aint LmatchSubString(char *subj, char *patt, aint pos);
void *Lsubstring(void *subj, int p, int l); void *Lsubstring(aint *args /*void *subj, aint p, aint l*/);
struct re_pattern_buffer *Lregexp(char *regexp); regex_t *Lregexp(char *regexp);
int LregexpMatch(struct re_pattern_buffer *b, char *s, int pos); aint LregexpMatch(struct re_pattern_buffer *b, char *s, aint pos);
void *Bstring(void *p);
void *Lclone(void *p); void *Lclone(void *p);
int inner_hash(int depth, unsigned acc, void *p); aint inner_hash(aint depth, auint acc, void *p);
void *LstringInt(char *b); void *LstringInt(char *b);
int Lhash(void *p); aint Lhash(void *p);
int LflatCompare(void *p, void *q); aint LflatCompare(void *p, void *q);
int Lcompare(void *p, void *q); aint Lcompare(void *p, void *q);
void *Belem(void *p, int i); void *Belem(void *p, aint i);
void *LmakeArray(int length); void *LmakeArray(aint length);
void *LmakeString(int length); void *LmakeString(aint length);
void *Bstring(void *p); void *Bstring(aint *args /*void *p*/);
void *Lstringcat(void *p); void *Lstringcat(aint *args /* void* p */);
void *Lstring(void *p); void *Lstring(aint *args /* void *p */);
void *Bclosure(int bn, void *entry, ...); void *Bclosure(aint *args, aint bn);
void *Barray(int bn, ...); void *Barray(aint *args, aint bn);
void *Bsexp(int bn, ...); void *Bsexp(aint *args, aint bn);
int Btag(void *d, int t, int n); aint Btag(void *d, aint t, aint n);
int get_tag(data *d); aint get_tag(data *d);
int get_len(data *d); aint get_len(data *d);
int Barray_patt(void *d, int n); aint Barray_patt(void *d, aint n);
int Bstring_patt(void *x, void *y); aint Bstring_patt(void *x, void *y);
int Bclosure_tag_patt(void *x); aint Bclosure_tag_patt(void *x);
int Bboxed_patt(void *x); aint Bboxed_patt(void *x);
int Bunboxed_patt(void *x); aint Bunboxed_patt(void *x);
int Barray_tag_patt(void *x); aint Barray_tag_patt(void *x);
int Bstring_tag_patt(void *x); aint Bstring_tag_patt(void *x);
int Bsexp_tag_patt(void *x); aint Bsexp_tag_patt(void *x);
void *Bsta(void *v, int i, void *x); void *Bsta(void *v, aint i, void *x);
void Lfailure(char *s, ...); void Lfailure(char *s, ...);
void LprintfPerror(char *s, ...); void LprintfPerror(char *s, ...);
void Bmatch_failure(void *v, char *fname, int line, int col); void Bmatch_failure(void *v, char *fname, aint line, aint col);
void * /*Lstrcat*/ Li__Infix_4343(void *a, void *b); void * /*Lstrcat*/ Li__Infix_4343(void *a, void *b);
void *Lsprintf(char *fmt, ...); void *Lsprintf(char *fmt, ...);
void *LgetEnv(char *var); void *LgetEnv(char *var);
int Lsystem(char *cmd); aint Lsystem(char *cmd);
void Lfprintf(FILE *f, char *s, ...); void Lfprintf(FILE *f, char *s, ...);
void Lprintf(char *s, ...); void Lprintf(char *s, ...);
@ -152,17 +151,17 @@ void *Lhd(void *v);
void *Ltl(void *v); void *Ltl(void *v);
/* Lread is an implementation of the "read" construct */ /* Lread is an implementation of the "read" construct */
int Lread(); aint Lread();
int Lbinoperror(void); aint Lbinoperror(void);
int Lbinoperror2(void); aint Lbinoperror2(void);
/* Lwrite is an implementation of the "write" construct */ /* Lwrite is an implementation of the "write" construct */
int Lwrite(int n); aint Lwrite(aint n);
int Lrandom(int n); aint Lrandom(aint n);
int Ltime(); aint Ltime();
void set_args(int argc, char *argv[]); void set_args(aint argc, char *argv[]);

View file

@ -8,13 +8,12 @@
#include "stdlib.h" #include "stdlib.h"
void s_push(struct State *s, void *val); void s_push(struct State *s, void *val);
void s_push_i(struct State *s, aint val);
void s_push_nil(struct State *s); void s_push_nil(struct State *s);
void s_pushn_nil(struct State *s, size_t n); void s_pushn_nil(struct State *s, size_t n);
void *s_pop(struct State *s); void *s_pop(struct State *s);
aint s_pop_i(struct State *s);
void s_popn(struct State *s, size_t n); void s_popn(struct State *s, size_t n);
// ------ functions ------ // ------ functions ------
@ -25,13 +24,9 @@ void s_popn(struct State *s, size_t n);
// //
// where |> defines corresponding frame pointer, | is stack pointer // where |> defines corresponding frame pointer, | is stack pointer
// location before / after new frame added // location before / after new frame added
void s_enter_f(struct State *s, char *func_ip, size_t params_sz, void s_enter_f(struct State *s, char *func_ip, auint params_sz,
size_t locals_sz); auint locals_sz);
void s_exit_f(struct State *s); void s_exit_f(struct State *s);
void **var_by_category(struct State *s, enum VarCategory category, int id); void **var_by_category(struct State *s, enum VarCategory category, int id);
// --- changed runtime operations ---
void *s_Bsexp(struct State *state, int bn, int tag);

View file

@ -16,23 +16,21 @@ enum Type {
static const size_t MAX_ARRAY_SIZE = 0x11111110; static const size_t MAX_ARRAY_SIZE = 0x11111110;
static inline union VarT *to_var(struct NilT *var) { return (union VarT *)var; }
// ------ Frame ------ // ------ Frame ------
struct Frame { struct Frame {
void *ret; // store returned value [gc pointer] void *ret; // store returned value [gc pointer]
char *rp; // ret instruction pointer [not gc pointer] char *rp; // ret instruction pointer [not gc pointer]
size_t to_prev_fp_box; // ret function frame pointer [boxed value, not gc aint to_prev_fp_box; // ret function frame pointer [boxed value, not gc
// pointer] // pointer]
size_t args_sz_box; // store arguments [boxed value, not gc pointer] aint args_sz_box; // store arguments [boxed value, not gc pointer]
size_t locals_sz_box; // store locals [boxed value, not gc pointer] aint locals_sz_box; // store locals [boxed value, not gc pointer]
}; };
size_t frame_sz(); auint frame_sz();
void **f_prev_fp(struct Frame *fp); void **f_prev_fp(struct Frame *fp);
uint64_t f_locals_sz(struct Frame *fp); auint f_locals_sz(struct Frame *fp);
uint64_t f_args_sz(struct Frame *fp); auint f_args_sz(struct Frame *fp);
void **f_locals(struct Frame *fp); void **f_locals(struct Frame *fp);
void **f_args(struct Frame *fp); void **f_args(struct Frame *fp);

View file

@ -8,6 +8,8 @@
#include "stack.h" #include "stack.h"
#include "runtime_externs.h" #include "runtime_externs.h"
extern size_t STACK_SIZE;
int ip_read_int(char** ip) { int ip_read_int(char** ip) {
*ip += sizeof(int); *ip += sizeof(int);
return *(int*)((*ip) - sizeof(int)); return *(int*)((*ip) - sizeof(int));
@ -28,7 +30,7 @@ void run(bytefile *bf) {
const size_t OPS_SIZE = 13; const size_t OPS_SIZE = 13;
const char *ops [] = {"+", "-", "*", "/", "%", "<", "<=", ">", ">=", "==", "!=", "&&", "!!"}; const char *ops [] = {"+", "-", "*", "/", "%", "<", "<=", ">", ">=", "==", "!=", "&&", "!!"};
int(*ops_func[])(void*, void*) = { aint(*ops_func[])(void*, void*) = {
&Ls__Infix_43, // + &Ls__Infix_43, // +
&Ls__Infix_45, // - &Ls__Infix_45, // -
&Ls__Infix_42, // * &Ls__Infix_42, // *
@ -75,16 +77,19 @@ void run(bytefile *bf) {
case 1: case 1:
switch (l) { switch (l) {
case 0: // CONST %d case 0: // CONST %d
s_push(&s, (void*)BOX(ip_read_int(&s.ip))); s_push_i(&s, BOX(ip_read_int(&s.ip)));
break; break;
case 1: // STRING %s case 1: { // STRING %s
s_push(&s, Bstring((void*)ip_read_string(&s.ip, bf))); void* str = ip_read_string(&s.ip, bf);
s_push(&s, Bstring((aint*)&str));
break; break;
}
case 2: // SEXP %s %d // create sexpr with tag=%s and %d elements from stack case 2: // SEXP %s %d // create sexpr with tag=%s and %d elements from stack
// params read from stack // params read from stack
s_put_sexp(&s, ip_read_string(&s.ip, bf), ip_read_int(&s.ip)); s_push_i(&s, LtagHash(ip_read_string(&s.ip, bf)));
Bsexp((aint*)s.sp, ip_read_int(&s.ip)); // TODO: check order
break; break;
case 3: // STI case 3: // STI
@ -108,12 +113,12 @@ void run(bytefile *bf) {
break; break;
case 8: // DROP case 8: // DROP
s_drop_var(&s); s_pop(&s);
break; break;
case 9: // DUP case 9: // DUP
{ // guess {
if (s.sp == s.stack || (s.fp != NULL && s.sp == s.fp->end)) { if (s.sp == s.stack + STACK_SIZE || (s.fp != NULL && s.sp == f_locals(s.fp))) {
failure("can't DUP: no value on stack"); failure("can't DUP: no value on stack");
} }
*s.sp = *(s.sp - 1); *s.sp = *(s.sp - 1);
@ -123,32 +128,22 @@ void run(bytefile *bf) {
case 10: // SWAP case 10: // SWAP
{ // guess { // guess
struct NilT* v = *s.sp; if (s.sp + 1 >= s.stack + STACK_SIZE || (s.fp != NULL && s.sp + 1 >= f_locals(s.fp))) {
*s.sp = *(s.sp - 1); failure("can't SWAP: < 2 values on stack");
*(s.sp - 1) = v; }
void* v = *s.sp;
push_extra_root(v);
*s.sp = *(s.sp + 1);
*(s.sp + 1) = v;
pop_extra_root(v);
} }
break; break;
case 11: // ELEM case 11: // ELEM
{ {
union VarT* array = s_take_var(&s); void* array = s_pop(&s);
union VarT* index = s_take_var(&s); aint index = s_pop_i(&s);
if (dh_type(array->nil.data_header) != ARRAY_T) { s_push(&s, Belem(array, index));
failure("ELEM: elem, previous element is not array");
}
if (dh_type(index->nil.data_header) != INT_T) {
failure("ELEM: elem, last element is not int");
}
if (index->int_t.value < 0) {
failure("ELEM: can't access by index < 0");
}
if (index->int_t.value >= dh_param(array->array.data_header)) {
failure("ELEM: array index is out of range");
}
s_put_var(&s, array->array.values[index->int_t.value]);
free_var_ptr(array);
free_var_ptr(index);
} }
break; break;
@ -159,34 +154,34 @@ void run(bytefile *bf) {
case 2: { // LD %d case 2: { // LD %d
int8_t category = ip_read_byte(&s.ip); int8_t category = ip_read_byte(&s.ip);
union VarT** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip)); void** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip));
s_put_var(&s, (struct NilT*)*var_ptr); // TODO: check s_push(&s, *var_ptr);
break; break;
} }
case 3: { // LDA %d case 3: { // LDA %d
int8_t category = ip_read_byte(&s.ip); int8_t category = ip_read_byte(&s.ip);
union VarT** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip)); void** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip));
// TODO // TODO
break; break;
} }
case 4: { // ST %d case 4: { // ST %d
int8_t category = ip_read_byte(&s.ip); int8_t category = ip_read_byte(&s.ip);
union VarT** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip)); void** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip));
*var_ptr = s_take_var(&s); // TODO: check *var_ptr = s_pop(&s);
break; break;
} }
case 5: case 5:
switch (l) { switch (l) {
case 0: { // CJMPz 0x%.8x case 0: { // CJMPz 0x%.8x
char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
if (s_take_i(&s) != 0) { if (s_pop_i(&s) != UNBOX(0)) {
s.ip = new_ip; s.ip = new_ip;
} }
break; break;
} }
case 1: { // CJMPnz 0x%.8x case 1: { // CJMPnz 0x%.8x
char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
if (s_take_i(&s) == 0) { if (s_pop_i(&s) == UNBOX(0)) {
s.ip = new_ip; s.ip = new_ip;
} }
break; break;
@ -200,6 +195,7 @@ void run(bytefile *bf) {
break; break;
case 4: // CLOSURE 0x%.8x case 4: // CLOSURE 0x%.8x
// TODO
{ {
int n = ip_read_int(&s.ip); int n = ip_read_int(&s.ip);
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
@ -226,14 +222,14 @@ void run(bytefile *bf) {
break; break;
case 7: // TAG %s case 7: // TAG %s
// TODO: ?? s_push_i(&s, LtagHash(ip_read_string(&s.ip, bf))); // TODO: check
break; break;
case 8: // ARRAY %d case 8: // ARRAY %d
s_put_array(&s, ip_read_int(&s.ip)); Barray((aint*)s.sp, ip_read_int(&s.ip));
break; break;
case 9: // FAIL %d %d case 9: // FAIL %d %d // TODO
failure("[FAIL]: %d-%d\n", ip_read_int(&s.ip), ip_read_int(&s.ip)); failure("[FAIL]: %d-%d\n", ip_read_int(&s.ip), ip_read_int(&s.ip));
break; break;
@ -247,30 +243,62 @@ void run(bytefile *bf) {
break; break;
case 6: // PATT pats[l] case 6: // PATT pats[l]
// TODO: JMP if same to pattern ?? // {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"}
switch (l) {
case 0: // =str
s_push_i(&s, Bstring_patt(s_pop(&s), s_pop(&s))); // TODO: order
break;
case 1: // #string
s_push_i(&s, Bstring_tag_patt(s_pop(&s)));
break;
case 2: // #array
s_push_i(&s, Barray_tag_patt(s_pop(&s)));
break;
case 3: // #sexp
s_push_i(&s, Bsexp_tag_patt(s_pop(&s)));
break;
case 4: // #ref
// TODO
break;
case 5: // #val
// TODO
break;
case 6: // #fun
s_push_i(&s, Bclosure_tag_patt(s_pop(&s)));
break;
default:
failure("invalid opcode %d-%d\n", h, l);
}
break; break;
case 7: { case 7: {
switch (l) { switch (l) {
case 0: // CALL Lread case 0: // CALL Lread
f_read(&s); s_push_i(&s, Lread());
break; break;
case 1: // CALL Lwrite case 1: // CALL Lwrite
f_write(&s); Lwrite(s_pop_i(&s));
break; break;
case 2: // CALL Llength case 2: // CALL Llength
f_length(&s); s_push_i(&s, Llength(s_pop(&s)));
break; break;
case 3: // CALL Lstring case 3: { // CALL Lstring
f_string(&s); void* str = Lstring((aint*)s.sp);
s_pop(&s);
s_push(&s, str);
break; break;
}
case 4: // CALL Barray %d case 4: { // CALL Barray %d
f_array(&s, ip_read_int(&s.ip)); size_t n = ip_read_int(&s.ip);
void* array = Barray((aint*)s.sp, n); // TODO: are elems added (?)
s_popn(&s, n);
s_push(&s, array);
break; break;
}
default: default:
failure("invalid opcode %d-%d\n", h, l); failure("invalid opcode %d-%d\n", h, l);

View file

@ -11,6 +11,7 @@ extern size_t __gc_stack_top, __gc_stack_bottom;
flag = __gc_stack_top == 0; \ flag = __gc_stack_top == 0; \
if (flag) { __gc_stack_top = (size_t)__builtin_frame_address(0); } \ if (flag) { __gc_stack_top = (size_t)__builtin_frame_address(0); } \
assert(__gc_stack_top != 0); \ assert(__gc_stack_top != 0); \
assert((__gc_stack_top & 0xF) == 0); \
assert(__builtin_frame_address(0) <= (void *)__gc_stack_top); assert(__builtin_frame_address(0) <= (void *)__gc_stack_top);
#define POST_GC() \ #define POST_GC() \
@ -27,6 +28,10 @@ void s_push(struct State *s, void *val) {
*s->sp = val; *s->sp = val;
} }
void s_push_i(struct State *s, aint val) {
s_push(s, (void*)val);
}
void s_push_nil(struct State *s) { void s_push_nil(struct State *s) {
s_push(s, NULL); s_push(s, NULL);
} }
@ -48,6 +53,10 @@ void* s_pop(struct State *s) {
return value; return value;
} }
aint s_pop_i(struct State *s) {
return (aint)s_pop(s);
}
void s_popn(struct State *s, size_t n) { void s_popn(struct State *s, size_t n) {
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
s_pop(s); s_pop(s);
@ -56,10 +65,10 @@ void s_popn(struct State *s, size_t n) {
// ------ functions ------ // ------ functions ------
void s_enter_f(struct State *s, char *func_ip, size_t args_sz, void s_enter_f(struct State *s, char *func_ip, auint args_sz,
size_t locals_sz) { auint locals_sz) {
// check that params count is valid // check that params count is valid
if (args_sz > s->sp + STACK_SIZE - s->stack || if (s->sp + (aint)args_sz - 1 >= s->stack + STACK_SIZE ||
(s->fp != NULL && args_sz > s->sp + STACK_SIZE - f_locals(s->fp))) { (s->fp != NULL && args_sz > s->sp + STACK_SIZE - f_locals(s->fp))) {
failure("not enough parameters in stack"); failure("not enough parameters in stack");
} }
@ -147,5 +156,3 @@ void **var_by_category(struct State *s, enum VarCategory category,
return var; return var;
} }
// --- changed runtime operations ---

View file

@ -17,8 +17,8 @@ size_t frame_sz() {
void **f_prev_fp(struct Frame *fp) { void **f_prev_fp(struct Frame *fp) {
return (void **)fp + UNBOX(fp->to_prev_fp_box); return (void **)fp + UNBOX(fp->to_prev_fp_box);
} }
uint64_t f_locals_sz(struct Frame *fp) { return UNBOX(fp->locals_sz_box); } auint f_locals_sz(struct Frame *fp) { return UNBOX(fp->locals_sz_box); }
uint64_t f_args_sz(struct Frame *fp) { return UNBOX(fp->args_sz_box); } auint f_args_sz(struct Frame *fp) { return UNBOX(fp->args_sz_box); }
void **f_locals(struct Frame *fp) { return (void **)fp - f_locals_sz(fp) - frame_sz(); } void **f_locals(struct Frame *fp) { return (void **)fp - f_locals_sz(fp) - frame_sz(); }
void **f_args(struct Frame *fp) { return (void **)fp + 1; } void **f_args(struct Frame *fp) { return (void **)fp + 1; }