/* Stuff needed to interpret programs and closures */ #ifndef INTERPRET_H #define INTERPRET_H #include "alloc.h" struct control_ret { struct frame *fp; union svalue *sp; }; union control_virtual { uint16 *variable; uint8 *function_8; uint16 *function_16; }; typedef struct control_ret (*inter_callback)(svalue result, struct frame *fp); struct frame { union svalue arguments[1]; /* last argument */ union svalue *shared; union svalue *variable; union control_virtual virtual; union svalue object; struct program *program; union { p_int i; inter_callback fun; } return_mode; unsigned char *funstart; uint8 *pc; struct frame *previous; union svalue locals[0]; #define CONTROL_LOCALS(fp) ((fp)[1].arguments) }; #define IR_LOCAL 0 #define IR_LOCAL_XF 1 /* frame in external stack */ #define IR_EXTERN 2 #define IR_EXTERN_XF 3 #define IR_CATCH 4 /* must be largest for correct error handling */ /* * Most frames are allocated on the general stack, and are above arguments, * but below local variables. Alas, to make efun closures work that eat * up their arguments and might call functions, call_lambda() uses the * external part, which is above everything in the general stack and thus * avoids extra popping. * Moreover, it is used for calls to ALIEN_EFUN closures to store the * outer frame, so that the arguments are just one frame off the locals. */ extern struct inter_stack { union svalue general[1024]; struct frame external[256]; } inter_stack; /* * Usually, sp and fp are passed up and down as function arguments / * return values; only the interpreter itself needs to know pc. Error * handling goes via the return chain, sometimes with modifying the * return_mode first. Loading objects is a special case: while the * compiler is active, it can't return, thus it defines a new bottom * of possible return and suspend depth. * Since it would be very hard and pretty pointless to pass sp and fp * of the interpreter up and down in the compiler, these values are * stored in inter_sp and inter_fp, respectively, while compiling is done. * A number of driver hooks will also define a new return/suspend bottom * for modularity reasons. */ extern union svalue *inter_sp, *inter_general_stack_bottom; extern struct frame *inter_fp, *inter_ex_fp, *inter_external_stack_bottom; /* * funstart could be saved by making error tracebacks search the program for * the function enclosing pc; but having it makes function setup & iteration * easier too. */ extern struct frame control_stack[]; #define PUSH_NUMBER(n) ((void)((++inter_sp)->i = (n) << 1)) #define PUSH_REFERENCED_SVALUE(sv) (*++inter_sp = (sv)) extern int inter_errno; extern enum eval_state { off = 0x00, on = 0xff } eval_switch; extern int32 eval_cost, last_eval_cost; #define ASSIGN_EVAL_COST(ob) ((void)(\ (ob)->x.uid->self->total_eval_cost += eval_cost - last_eval_cost,\ last_eval_cost = eval_cost \ )) /* types are sorted by number of indizes - the code relies on this. */ #define LVALUE_SIMPLE 0 #define LVALUE_PROTECTED 1 #define LVALUE_CHAR 2 #define LVALUE_CBR_CHAR 3 #define LVALUE_NN_INDEXED 4 #define LVALUE_NR_INDEXED 5 #define LVALUE_RN_INDEXED 6 #define LVALUE_RR_INDEXED 7 #define LVALUE_CATCH 8 /* not actually an lvalue */ struct call_cache_entry { union svalue name; /* shared string function name */ p_int cache_id; struct program *program; uint8 *funstart; uint16 cache_virtual_index_offset; uint16 cache_variable_index_offset; }; /* This structure should have a size of 20 bytes, this makes indexing * only take some shifts and one addition if no fast integer multiply is * available. */ struct call_cache_cell { uint8 last_written; uint8 unstatic[3]; /* protected is marked like undefined */ /* 0x80 : freely callable 0: static 1: undefined/protected */ struct call_cache_entry entry[3]; }; struct leaf_inherit_cache_tag { union svalue name; /* shared string function name */ p_int cache_id; }; struct leaf_inherit_cache_cell { struct leaf_inherit_cache_tag tag[3]; uint16 index[3]; uint8 last_written; }; struct cache_call_ret { union { svalue ob; char unstatic; } u; struct call_cache_entry *entry; } ALIGN8 cache_call(svalue ob, union svalue name, struct frame *fp); struct control_ret make_frame(union svalue *, int, uint8 *); struct control_ret closure_frame (svalue, svalue *, struct frame *, int, uint8*, p_int); svalue interpreter(struct frame *fp, svalue *sp); union svalue *(*efun_table[])(union svalue *); extern svalue *f_text_message(svalue *, struct frame *); extern svalue *f_shadow(svalue *, struct frame *); extern svalue *f_set_interactive_hook(svalue *, struct frame *); extern svalue *f_get_dir(svalue *, struct frame *); extern svalue *f_write_file(svalue *, struct frame *); extern svalue *f_sprintf(svalue *, int); extern svalue *f_range(svalue *, struct frame *, svalue, int); extern svalue *f_member(svalue *); #endif /* INTERPRET_H */