mud/fluffos-2.23-ds03/function.c
2020-09-06 05:43:07 -07:00

347 lines
9.8 KiB
C

#define SUPPRESS_COMPILER_INLINES
#include "std.h"
#include "lpc_incl.h"
#include "eoperators.h"
#include "compiler.h"
#include "replace_program.h"
INLINE void
dealloc_funp (funptr_t * fp)
{
program_t *prog = 0;
switch (fp->hdr.type) {
case FP_LOCAL | FP_NOT_BINDABLE:
if (fp->hdr.owner)
prog = fp->hdr.owner->prog;
break;
case FP_FUNCTIONAL:
case FP_FUNCTIONAL | FP_NOT_BINDABLE:
prog = fp->f.functional.prog;
break;
}
if (fp->hdr.owner)
free_object(&fp->hdr.owner, "free_funp");
if (fp->hdr.args)
free_array(fp->hdr.args);
if (prog) {
prog->func_ref--;
debug(d_flag, ("subtr func ref /%s: now %i\n",
prog->filename, prog->func_ref));
if (!prog->func_ref && !prog->ref)
deallocate_program(prog);
}
FREE(fp);
}
INLINE void
free_funp (funptr_t * fp)
{
fp->hdr.ref--;
if (fp->hdr.ref > 0) {
return;
}
dealloc_funp(fp);
}
INLINE void
push_refed_funp (funptr_t * fp)
{
STACK_INC;
sp->type = T_FUNCTION;
sp->u.fp = fp;
}
INLINE void
push_funp (funptr_t * fp)
{
STACK_INC;
sp->type = T_FUNCTION;
sp->u.fp = fp;
fp->hdr.ref++;
}
/* num_arg args are on the stack, and the args from the array vec should be
* put in front of them. This is so that the order of arguments is logical.
*
* evaluate( (: f, a :), b) -> f(a,b) and not f(b, a) which would happen
* if we simply pushed the args from vec at this point. (Note that the
* old function pointers are broken in this regard)
*/
int merge_arg_lists (int num_arg, array_t * arr, int start) {
int num_arr_arg = arr->size - start;
svalue_t *sptr;
if (num_arr_arg) {
CHECK_STACK_OVERFLOW(num_arr_arg);
sptr = (sp += num_arr_arg);
if (num_arg) {
/* We need to do some stack movement so that the order
of arguments is logical */
while (num_arg--) {
*sptr = *(sptr - num_arr_arg);
sptr--;
}
}
num_arg = arr->size;
while (--num_arg >= start)
assign_svalue_no_free(sptr--, &arr->item[num_arg]);
/* could just return num_arr_arg if num_arg is 0 but .... -Sym */
return (sp - sptr);
}
return num_arg;
}
INLINE funptr_t *
make_efun_funp (int opcode, svalue_t * args)
{
funptr_t *fp;
fp = (funptr_t *)DXALLOC(sizeof(funptr_t),
TAG_FUNP, "make_efun_funp");
fp->hdr.owner = current_object;
add_ref( current_object, "make_efun_funp" );
fp->hdr.type = FP_EFUN;
fp->f.efun.index = opcode;
if (args->type == T_ARRAY) {
fp->hdr.args = args->u.arr;
args->u.arr->ref++;
} else
fp->hdr.args = 0;
fp->hdr.ref = 1;
return fp;
}
INLINE funptr_t *
make_lfun_funp (int index, svalue_t * args)
{
funptr_t *fp;
int newindex;
if (replace_program_pending(current_object))
error("cannot bind an lfun fp to an object with a pending replace_program()\n");
fp = (funptr_t *)DXALLOC(sizeof(funptr_hdr_t) + sizeof(local_ptr_t),
TAG_FUNP, "make_lfun_funp");
fp->hdr.owner = current_object;
add_ref( current_object, "make_lfun_funp" );
fp->hdr.type = FP_LOCAL | FP_NOT_BINDABLE;
fp->hdr.owner->prog->func_ref++;
debug(d_flag, ("add func ref /%s: now %i\n",
fp->hdr.owner->prog->filename,
fp->hdr.owner->prog->func_ref));
newindex = index + function_index_offset;
if (current_object->prog->function_flags[newindex] & FUNC_ALIAS)
newindex = current_object->prog->function_flags[newindex] & ~FUNC_ALIAS;
fp->f.local.index = newindex;
if (args->type == T_ARRAY) {
fp->hdr.args = args->u.arr;
args->u.arr->ref++;
} else
fp->hdr.args = 0;
fp->hdr.ref = 1;
return fp;
}
INLINE funptr_t *
make_simul_funp (int index, svalue_t * args)
{
funptr_t *fp;
fp = (funptr_t *)DXALLOC(sizeof(funptr_hdr_t) + sizeof(simul_ptr_t),
TAG_FUNP, "make_simul_funp");
fp->hdr.owner = current_object;
add_ref( current_object, "make_simul_funp" );
fp->hdr.type = FP_SIMUL;
fp->f.simul.index = index;
if (args->type == T_ARRAY) {
fp->hdr.args = args->u.arr;
args->u.arr->ref++;
} else
fp->hdr.args = 0;
fp->hdr.ref = 1;
return fp;
}
INLINE funptr_t *
make_functional_funp (short num_arg, short num_local, short len, svalue_t * args, int flag)
{
funptr_t *fp;
if (replace_program_pending(current_object))
error("cannot bind a functional to an object with a pending replace_program()\n");
fp = (funptr_t *)DXALLOC(sizeof(funptr_hdr_t) + sizeof(functional_t),
TAG_FUNP, "make_functional_funp");
fp->hdr.owner = current_object;
add_ref( current_object, "make_functional_funp" );
fp->hdr.type = FP_FUNCTIONAL + flag;
current_prog->func_ref++;
debug(d_flag, ("add func ref /%s: now %i\n",
current_prog->filename,
current_prog->func_ref));
fp->f.functional.prog = current_prog;
fp->f.functional.offset = pc - current_prog->program;
fp->f.functional.num_arg = num_arg;
fp->f.functional.num_local = num_local;
fp->f.functional.fio = function_index_offset;
fp->f.functional.vio = variable_index_offset;
pc += len;
if (args && args->type == T_ARRAY) {
fp->hdr.args = args->u.arr;
args->u.arr->ref++;
fp->f.functional.num_arg += args->u.arr->size;
} else
fp->hdr.args = 0;
fp->hdr.ref = 1;
return fp;
}
typedef void (*func_t) (void);
extern func_t efun_table[];
svalue_t *
call_function_pointer (funptr_t * funp, int num_arg)
{
static func_t *oefun_table = efun_table - BASE;
array_t *v;
int extfr = 1;
if (!funp->hdr.owner || (funp->hdr.owner->flags & O_DESTRUCTED))
error("Owner (/%s) of function pointer is destructed.\n",
(funp->hdr.owner ? funp->hdr.owner->obname : "(null)"));
setup_fake_frame(funp);
if ((v=funp->hdr.args)) {
check_for_destr(v);
num_arg = merge_arg_lists(num_arg, v, 0);
}
switch (funp->hdr.type) {
case FP_SIMUL:
call_simul_efun(funp->f.simul.index, num_arg);
break;
case FP_EFUN:
{
int i, def;
fp = sp - num_arg + 1;
i = funp->f.efun.index;
if (num_arg == instrs[i].min_arg - 1 &&
((def = instrs[i].Default) != DEFAULT_NONE)) {
if (def == DEFAULT_THIS_OBJECT) {
push_object(current_object);
} else {
push_number(def);
}
num_arg++;
} else
if (num_arg < instrs[i].min_arg) {
error("Too few arguments to efun %s in efun pointer.\n", query_instr_name(i));
} else if (num_arg > instrs[i].max_arg && instrs[i].max_arg != -1) {
error("Too many arguments to efun %s in efun pointer.\n", query_instr_name(i));
}
/* possibly we should add TRACE, OPC, etc here;
also on eval_cost here, which is ok for just 1 efun */
{
int j, n = num_arg;
st_num_arg = num_arg;
if (n >= 4 || instrs[i].max_arg == -1)
n = instrs[i].min_arg;
for (j = 0; j < n; j++) {
CHECK_TYPES(sp - num_arg + j + 1, instrs[i].type[j], j + 1, i);
}
(*oefun_table[i])();
free_svalue(&apply_ret_value, "call_function_pointer");
if (instrs[i].ret_type == TYPE_NOVALUE)
apply_ret_value = const0;
else
apply_ret_value = *sp--;
remove_fake_frame();
return &apply_ret_value;
}
}
case FP_LOCAL | FP_NOT_BINDABLE: {
function_t *func;
fp = sp - num_arg + 1;
if (current_object->prog->function_flags[funp->f.local.index] & (FUNC_PROTOTYPE|FUNC_UNDEFINED))
error("Undefined lfun pointer called: %s\n", function_name(current_object->prog, funp->f.local.index));
push_control_stack(FRAME_FUNCTION);
current_prog = funp->hdr.owner->prog;
caller_type = ORIGIN_LOCAL;
csp->num_local_variables = num_arg;
func = setup_new_frame(funp->f.local.index);
call_program(current_prog, func->address);
break;
}
case FP_FUNCTIONAL:
case FP_FUNCTIONAL | FP_NOT_BINDABLE: {
fp = sp - num_arg + 1;
push_control_stack(FRAME_FUNP);
current_prog = funp->f.functional.prog;
csp->fr.funp = funp;
caller_type = ORIGIN_FUNCTIONAL;
setup_variables(num_arg, funp->f.functional.num_local,
funp->f.functional.num_arg);
function_index_offset = funp->f.functional.fio;
variable_index_offset = funp->f.functional.vio;
call_program(funp->f.functional.prog, funp->f.functional.offset);
break;
}
default:
error("Unsupported function pointer type.\n");
}
free_svalue(&apply_ret_value, "call_function_pointer");
apply_ret_value = *sp--;
remove_fake_frame();
return &apply_ret_value;
}
svalue_t *
safe_call_function_pointer (funptr_t * funp, int num_arg)
{
error_context_t econ;
svalue_t *ret;
if (!save_context(&econ))
return 0;
if (!SETJMP(econ.context)) {
ret = call_function_pointer(funp, num_arg);
} else {
restore_context(&econ);
/* condition was restored to where it was when we came in */
pop_n_elems(num_arg);
ret = 0;
}
pop_context(&econ);
return ret;
}