/* 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 */