touched up stack management code

added hawk::call()
This commit is contained in:
hyung-hwan 2020-04-12 18:23:44 +00:00
parent 9eb3c4fc42
commit e4de922f7d
11 changed files with 377 additions and 348 deletions

View File

@ -129,7 +129,7 @@ const hawk_ooch_t* hawk_dfl_errstr (hawk_errnum_t errnum)
HAWK_T("word after @ not recognized"), HAWK_T("word after @ not recognized"),
HAWK_T("@ not followed by a valid word"), HAWK_T("@ not followed by a valid word"),
HAWK_T("stack error"), HAWK_T("stack full"),
HAWK_T("divide by zero"), HAWK_T("divide by zero"),
HAWK_T("invalid operand"), HAWK_T("invalid operand"),
HAWK_T("wrong position index"), HAWK_T("wrong position index"),

View File

@ -362,14 +362,6 @@ struct hawk_chain_t
hawk_chain_t* next; hawk_chain_t* next;
}; };
#define HAWK_RTX_STACK_AT(rtx,n) ((rtx)->stack[(rtx)->stack_base+(n)])
#define HAWK_RTX_STACK_NARGS(rtx) HAWK_RTX_STACK_AT(rtx,3)
#define HAWK_RTX_STACK_ARG(rtx,n) HAWK_RTX_STACK_AT(rtx,3+1+(n))
#define HAWK_RTX_STACK_LCL(rtx,n) HAWK_RTX_STACK_AT(rtx,3+(hawk_oow_t)HAWK_RTX_STACK_NARGS(rtx)+1+(n))
#define HAWK_RTX_STACK_RETVAL(rtx) HAWK_RTX_STACK_AT(rtx,2)
#define HAWK_RTX_STACK_GBL(rtx,n) ((rtx)->stack[(n)])
#define HAWK_RTX_STACK_RETVAL_GBL(rtx) ((rtx)->stack[(rtx)->hawk->tree.ngbls+2])
struct hawk_rtx_t struct hawk_rtx_t
{ {
HAWK_RTX_HDR; HAWK_RTX_HDR;
@ -536,6 +528,35 @@ struct hawk_mod_data_t
hawk_mod_t mod; hawk_mod_t mod;
}; };
#define HAWK_RTX_STACK_AT(rtx,n) ((rtx)->stack[(rtx)->stack_base+(n)])
#define HAWK_RTX_STACK_NARGS(rtx) HAWK_RTX_STACK_AT(rtx,3)
#define HAWK_RTX_STACK_ARG(rtx,n) HAWK_RTX_STACK_AT(rtx,3+1+(n))
#define HAWK_RTX_STACK_LCL(rtx,n) HAWK_RTX_STACK_AT(rtx,3+(hawk_oow_t)HAWK_RTX_STACK_NARGS(rtx)+1+(n))
#define HAWK_RTX_STACK_RETVAL(rtx) HAWK_RTX_STACK_AT(rtx,2)
#define HAWK_RTX_STACK_GBL(rtx,n) ((rtx)->stack[(n)])
#define HAWK_RTX_STACK_RETVAL_GBL(rtx) ((rtx)->stack[(rtx)->hawk->tree.ngbls+2])
#define HAWK_RTX_STACK_AVAIL(rtx) ((rtx)->stack_limit - (rtx)->stack_top)
#if defined(HAWK_HAVE_INLINE)
static HAWK_INLINE void HAWK_RTX_STACK_PUSH (hawk_rtx_t* rtx, hawk_val_t* val)
{
/*HAWK_ASSERT (rtx->stack_top < rtx->stack_limit);*/
rtx->stack[rtx->stack_top++] = val;
}
static HAWK_INLINE void HAWK_RTX_STACK_POP (hawk_rtx_t* rtx)
{
/*HAWK_ASSERT (rtx->stack_top > rtx->stack_base);*/
rtx->stack_top--;
}
#else
#define HAWK_RTX_STACK_PUSH(rtx,val) ((rtx)->stack[(rtx)->stack_top++] = val)
#define HAWK_RTX_STACK_POP(rtx) ((rtx)->stack_top--)
#endif
#define HAWK_RTX_INIT_REF_VAL(refval, _id, _adr, _nrefs) \ #define HAWK_RTX_INIT_REF_VAL(refval, _id, _adr, _nrefs) \
do { \ do { \
(refval)->v_type = HAWK_VAL_REF; \ (refval)->v_type = HAWK_VAL_REF; \

View File

@ -27,10 +27,91 @@
#include "mod-hawk.h" #include "mod-hawk.h"
#include "hawk-prv.h" #include "hawk-prv.h"
struct pafs_t
{
hawk_oow_t stack_base;
hawk_oow_t start_index;
hawk_oow_t end_index;
};
static hawk_oow_t push_args_from_stack (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, void* data)
{
struct pafs_t* pasf = (struct pafs_t*)data;
hawk_oow_t org_stack_base, i;
hawk_val_t* v;
if (HAWK_RTX_STACK_AVAIL(rtx) < pasf->end_index - pasf->start_index + 1)
{
hawk_rtx_seterrnum (rtx, &call->loc, HAWK_ESTACK);
return (hawk_oow_t)-1;
}
org_stack_base = rtx->stack_base;
for (i = pasf->start_index; i <= pasf->end_index; i++)
{
rtx->stack_base = pasf->stack_base;
v = HAWK_RTX_STACK_ARG(rtx, i);
rtx->stack_base = org_stack_base;
HAWK_RTX_STACK_PUSH (rtx, v);
hawk_rtx_refupval (rtx, v);
}
return pasf->end_index - pasf->start_index + 1;
}
static int fnc_call (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
{
hawk_fun_t* fun;
hawk_oow_t nargs;
hawk_nde_fncall_t call;
struct pafs_t pafs;
hawk_val_t* v, * a0;
int rx = -1;
/* this function is similar to hawk_rtx_callfun() but it is more simplified */
a0 = hawk_rtx_getarg(rtx, 0);
fun = hawk_rtx_valtofun(rtx, hawk_rtx_getarg(rtx, 1));
if (!fun) goto done;
nargs = hawk_rtx_getnargs(rtx);
if (nargs - 2 > fun->nargs)
{
/*hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EARGTM);
return HAWK_NULL;*/
goto done;
}
HAWK_MEMSET (&call, 0, HAWK_SIZEOF(call));
call.type = HAWK_NDE_FNCALL_FUN;
call.u.fun.name = fun->name;
call.nargs = nargs - 2;
/* keep HAWK_NULL in call.args so that hawk_rtx_evalcall() knows it's a fake call structure */
call.arg_base = rtx->stack_base + 6; /* 6 = 4(stack frame prologue) + 2(the first two arguments to hawk::call()) */
pafs.stack_base = rtx->stack_base;
pafs.start_index = 2;
pafs.end_index = nargs - 1;
v = hawk_rtx_evalcall(rtx, &call, fun, push_args_from_stack, (void*)&pafs, HAWK_NULL, HAWK_NULL);
if (HAWK_LIKELY(v))
{
hawk_rtx_refupval (rtx, v);
rx = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)a0, v);
hawk_rtx_refdownval (rtx, v);
}
done:
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, rx));
return 0;
}
/* /*
hawk::gc(); hawk::gc();
hawk::gc_set_threshold(gen)
hawk::gc_get_threshold(gen) hawk::gc_get_threshold(gen)
hawk::gc_set_threshold(gen, threshold)
hawk::GC_NUM_GENS hawk::GC_NUM_GENS
*/ */
@ -107,6 +188,7 @@ struct inttab_t
static fnctab_t fnctab[] = static fnctab_t fnctab[] =
{ {
/* keep this table sorted for binary search in query(). */ /* keep this table sorted for binary search in query(). */
{ HAWK_T("call"), { { 2, A_MAX, HAWK_T("rvR") }, fnc_call, 0 } },
{ HAWK_T("gc"), { { 0, 1, HAWK_NULL }, fnc_gc, 0 } }, { HAWK_T("gc"), { { 0, 1, HAWK_NULL }, fnc_gc, 0 } },
{ HAWK_T("gc_get_threshold"), { { 1, 1, HAWK_NULL }, fnc_gc_get_threshold, 0 } }, { HAWK_T("gc_get_threshold"), { { 1, 1, HAWK_NULL }, fnc_gc_get_threshold, 0 } },
{ HAWK_T("gc_set_threshold"), { { 2, 2, HAWK_NULL }, fnc_gc_set_threshold, 0 } } { HAWK_T("gc_set_threshold"), { { 2, 2, HAWK_NULL }, fnc_gc_set_threshold, 0 } }

View File

@ -350,7 +350,6 @@ static int fnc_tocharcode (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
return 0; return 0;
} }
static int fnc_frommbs (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) static int fnc_frommbs (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
{ {
/* str::frommbs(B"byte-string" [, "encoding-name"]) /* str::frommbs(B"byte-string" [, "encoding-name"])

View File

@ -1460,7 +1460,8 @@ static hawk_nde_t* parse_function (hawk_t* awk)
for (i = argspeccapa; i < newcapa; i++) argspec[i] = HAWK_T(' '); for (i = argspeccapa; i < newcapa; i++) argspec[i] = HAWK_T(' ');
argspeccapa = newcapa; argspeccapa = newcapa;
} }
argspec[nargs] = HAWK_T('r'); argspec[nargs] = 'r';
argspec[nargs + 1] = '\0';
if (get_token(awk) <= -1) goto oops; if (get_token(awk) <= -1) goto oops;
} }

View File

@ -140,6 +140,17 @@ int hawk_rtx_cmpval (
int* ret int* ret
); );
hawk_val_t* hawk_rtx_evalcall (
hawk_rtx_t* rtx,
hawk_nde_fncall_t* call,
hawk_fun_t* fun,
hawk_oow_t(*argpusher)(hawk_rtx_t*,hawk_nde_fncall_t*,void*),
void* apdata, /* data to argpusher */
void(*errhandler)(void*),
void* eharg
);
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif

View File

@ -174,14 +174,6 @@ static hawk_val_t* eval_fncall_fnc (hawk_rtx_t* rtx, hawk_nde_t* nde);
static hawk_val_t* eval_fncall_fun (hawk_rtx_t* rtx, hawk_nde_t* nde); static hawk_val_t* eval_fncall_fun (hawk_rtx_t* rtx, hawk_nde_t* nde);
static hawk_val_t* eval_fncall_var (hawk_rtx_t* rtx, hawk_nde_t* nde); static hawk_val_t* eval_fncall_var (hawk_rtx_t* rtx, hawk_nde_t* nde);
static hawk_val_t* __eval_call (
hawk_rtx_t* rtx,
hawk_nde_t* nde,
hawk_fun_t* fun,
hawk_oow_t(*argpusher)(hawk_rtx_t*,hawk_nde_fncall_t*,void*),
void* apdata, /* data to argpusher */
void(*errhandler)(void*),
void* eharg);
static int get_reference (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_val_t*** ref); static int get_reference (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_val_t*** ref);
static hawk_val_t** get_reference_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var); static hawk_val_t** get_reference_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var);
@ -1336,36 +1328,6 @@ oops:
return n; return n;
} }
static HAWK_INLINE int __raw_push (hawk_rtx_t* rtx, void* val)
{
if (rtx->stack_top >= rtx->stack_limit)
{
/*
void** tmp;
hawk_oow_t n;
n = rtx->stack_limit + HAWK_RTX_STACK_INCREMENT;
tmp = (void**)hawk_rtx_reallocmem(rtx, rtx->stack, n * HAWK_SIZEOF(void*));
if (!tmp) return -1;
rtx->stack = tmp;
rtx->stack_limit = n;
*/
hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_ESTACK, HAWK_T("runtime stack full"));
return -1;
}
rtx->stack[rtx->stack_top++] = val;
return 0;
}
#define __raw_pop(rtx) \
do { \
HAWK_ASSERT ((rtx)->stack_top > (rtx)->stack_base); \
(rtx)->stack_top--; \
} while (0)
/* /*
* create global variables into the runtime stack * create global variables into the runtime stack
* each variable is initialized to nil or zero. * each variable is initialized to nil or zero.
@ -1375,31 +1337,38 @@ static int prepare_globals (hawk_rtx_t* rtx)
hawk_oow_t saved_stack_top; hawk_oow_t saved_stack_top;
hawk_oow_t ngbls; hawk_oow_t ngbls;
saved_stack_top = rtx->stack_top;
ngbls = rtx->hawk->tree.ngbls; ngbls = rtx->hawk->tree.ngbls;
if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < ngbls))
{
hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_ESTACK);
return -1;
}
saved_stack_top = rtx->stack_top;
/* initialize all global variables to nil by push nils to the stack */ /* initialize all global variables to nil by push nils to the stack */
while (ngbls > 0) while (ngbls > 0)
{ {
--ngbls; --ngbls;
if (HAWK_UNLIKELY(__raw_push(rtx,hawk_val_nil) <= -1)) goto oops; HAWK_RTX_STACK_PUSH (rtx, hawk_val_nil);
} }
/* override NF to zero */ /* override NF to zero */
if (hawk_rtx_setgbl(rtx, HAWK_GBL_NF, HAWK_VAL_ZERO) <= -1) goto oops; if (hawk_rtx_setgbl(rtx, HAWK_GBL_NF, HAWK_VAL_ZERO) <= -1)
{
/* return success */ /* restore the stack_top this way instead of calling HAWK_RTX_STACK_POP()
return 0; * as many times as successful HAWK_RTX_STACK_PUSH(). it is ok because
oops:
/* restore the stack_top this way instead of calling __raw_pop()
* as many times as successful __raw_push(). it is ok because
* the values pushed so far are hawk_val_nils and HAWK_VAL_ZEROs. * the values pushed so far are hawk_val_nils and HAWK_VAL_ZEROs.
*/ */
rtx->stack_top = saved_stack_top; rtx->stack_top = saved_stack_top;
return -1; return -1;
} }
/* return success */
return 0;
}
/* /*
* assign initial values to the global variables whose desired initial * assign initial values to the global variables whose desired initial
* values are not nil or zero. some are handled in prepare_globals () and * values are not nil or zero. some are handled in prepare_globals () and
@ -1472,7 +1441,7 @@ static void refdown_globals (hawk_rtx_t* rtx, int pop)
{ {
--ngbls; --ngbls;
hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_GBL(rtx,ngbls)); hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_GBL(rtx,ngbls));
if (pop) __raw_pop (rtx); if (pop) HAWK_RTX_STACK_POP (rtx);
else HAWK_RTX_STACK_GBL(rtx,ngbls) = hawk_val_nil; else HAWK_RTX_STACK_GBL(rtx,ngbls) = hawk_val_nil;
} }
} }
@ -1507,47 +1476,6 @@ static void capture_retval_on_exit (void* arg)
hawk_rtx_refupval (data->rtx, data->val); hawk_rtx_refupval (data->rtx, data->val);
} }
static int enter_stack_frame (hawk_rtx_t* rtx)
{
hawk_oow_t saved_stack_top;
/* remember the current stack top */
saved_stack_top = rtx->stack_top;
/* push the current stack base */
if (HAWK_UNLIKELY(__raw_push(rtx,(void*)rtx->stack_base) <= -1)) goto oops;
/* push the current stack top before push the current stack base */
if (HAWK_UNLIKELY(__raw_push(rtx,(void*)saved_stack_top) <= -1)) goto oops;
/* secure space for a return value */
if (HAWK_UNLIKELY(__raw_push(rtx,hawk_val_nil) <= -1)) goto oops;
/* secure space for HAWK_RTX_STACK_NARGS */
if (HAWK_UNLIKELY(__raw_push(rtx,hawk_val_nil) <= -1)) goto oops;
/* let the stack top remembered be the base of a new stack frame */
rtx->stack_base = saved_stack_top;
return 0;
oops:
/* restore the stack top in a cheesy(?) way.
* it is ok to do so as the values pushed are
* nils and binary numbers. */
rtx->stack_top = saved_stack_top;
return -1;
}
static void exit_stack_frame (hawk_rtx_t* run)
{
/* At this point, the current stack frame should have
* the 4 entries pushed in enter_stack_frame(). */
HAWK_ASSERT ((run->stack_top-run->stack_base) == 4);
run->stack_top = (hawk_oow_t)run->stack[run->stack_base + 1];
run->stack_base = (hawk_oow_t)run->stack[run->stack_base + 0];
}
static hawk_val_t* run_bpae_loop (hawk_rtx_t* rtx) static hawk_val_t* run_bpae_loop (hawk_rtx_t* rtx)
{ {
hawk_nde_t* nde; hawk_nde_t* nde;
@ -1660,15 +1588,38 @@ static hawk_val_t* run_bpae_loop (hawk_rtx_t* rtx)
hawk_val_t* hawk_rtx_loop (hawk_rtx_t* rtx) hawk_val_t* hawk_rtx_loop (hawk_rtx_t* rtx)
{ {
hawk_val_t* retv = HAWK_NULL; hawk_val_t* retv = HAWK_NULL;
hawk_oow_t saved_stack_top;
rtx->exit_level = EXIT_NONE; rtx->exit_level = EXIT_NONE;
if (enter_stack_frame(rtx) == 0) /* make a new stack frame */
if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < 4))
{ {
retv = run_bpae_loop(rtx); /* restore the stack top in a cheesy(?) way.
exit_stack_frame (rtx); * it is ok to do so as the values pushed are
* nils and binary numbers. */
hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_ESTACK);
return HAWK_NULL;
} }
saved_stack_top = rtx->stack_top; /* remember the current stack top */
HAWK_RTX_STACK_PUSH (rtx, (void*)rtx->stack_base); /* push the current stack base */
HAWK_RTX_STACK_PUSH (rtx, (void*)saved_stack_top); /* push the current stack top before push the current stack base */
HAWK_RTX_STACK_PUSH (rtx, hawk_val_nil); /* secure space for a return value */
HAWK_RTX_STACK_PUSH (rtx, hawk_val_nil); /* secure space for HAWK_RTX_STACK_NARGS */
/* enter the new stack frame */
rtx->stack_base = saved_stack_top; /* let the stack top remembered be the base of a new stack frame */
/* run the BEGIN/pattern-action/END loop */
retv = run_bpae_loop(rtx);
/* exit the stack frame */
HAWK_ASSERT ((rtx->stack_top - rtx->stack_base) == 4); /* at this point, the current stack frame should have the 4 entries pushed above */
rtx->stack_top = (hawk_oow_t)rtx->stack[rtx->stack_base + 1];
rtx->stack_base = (hawk_oow_t)rtx->stack[rtx->stack_base + 0];
/* reset the exit level */ /* reset the exit level */
rtx->exit_level = EXIT_NONE; rtx->exit_level = EXIT_NONE;
@ -1771,7 +1722,7 @@ hawk_val_t* hawk_rtx_callfun (hawk_rtx_t* rtx, hawk_fun_t* fun, hawk_val_t* args
pafv.nargs = nargs; pafv.nargs = nargs;
pafv.argspec = fun->argspec; pafv.argspec = fun->argspec;
if (rtx->exit_level >= EXIT_GLOBAL) if (HAWK_UNLIKELY(rtx->exit_level >= EXIT_GLOBAL))
{ {
/* cannot call the function again when exit() is called /* cannot call the function again when exit() is called
* in an AWK program or hawk_rtx_halt() is invoked */ * in an AWK program or hawk_rtx_halt() is invoked */
@ -1795,7 +1746,7 @@ hawk_val_t* hawk_rtx_callfun (hawk_rtx_t* rtx, hawk_fun_t* fun, hawk_val_t* args
call.type = HAWK_NDE_FNCALL_FUN; call.type = HAWK_NDE_FNCALL_FUN;
call.u.fun.name = fun->name; call.u.fun.name = fun->name;
call.nargs = nargs; call.nargs = nargs;
/* keep HAWK_NULL in call.args so that __eval_call() knows it's a fake call structure */ /* keep HAWK_NULL in call.args so that hawk_rtx_evalcall() knows it's a fake call structure */
/* check if the number of arguments given is more than expected */ /* check if the number of arguments given is more than expected */
if (nargs > fun->nargs) if (nargs > fun->nargs)
@ -1811,7 +1762,7 @@ hawk_val_t* hawk_rtx_callfun (hawk_rtx_t* rtx, hawk_fun_t* fun, hawk_val_t* args
crdata.rtx = rtx; crdata.rtx = rtx;
crdata.val = HAWK_NULL; crdata.val = HAWK_NULL;
v = __eval_call(rtx, (hawk_nde_t*)&call, fun, push_arg_from_vals, (void*)&pafv, capture_retval_on_exit, &crdata); v = hawk_rtx_evalcall(rtx, &call, fun, push_arg_from_vals, (void*)&pafv, capture_retval_on_exit, &crdata);
if (HAWK_UNLIKELY(!v)) if (HAWK_UNLIKELY(!v))
{ {
@ -2159,24 +2110,22 @@ static HAWK_INLINE int run_block0 (hawk_rtx_t* rtx, hawk_nde_blk_t* nde)
nlcls = nde->nlcls; nlcls = nde->nlcls;
#if defined(DEBUG_RUN) #if defined(DEBUG_RUN)
hawk_logfmt (hawk_rtx_gethawk(rtx), hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("securing space for local variables nlcls = %d\n"), (int)nlcls);
HAWK_T("securing space for local variables nlcls = %d\n"),
(int)nlcls);
#endif #endif
saved_stack_top = rtx->stack_top;
/* secure space for local variables */ /* secure space for local variables */
while (nlcls > 0) if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < nlcls))
{ {
--nlcls; hawk_rtx_seterrnum (rtx, &nde->loc, HAWK_ESTACK);
if (HAWK_UNLIKELY(__raw_push(rtx,hawk_val_nil) <= -1))
{
/* restore stack top */
rtx->stack_top = saved_stack_top;
return -1; return -1;
} }
saved_stack_top = rtx->stack_top;
while (nlcls > 0)
{
--nlcls;
HAWK_RTX_STACK_PUSH (rtx, hawk_val_nil);
/* refupval is not required for hawk_val_nil */ /* refupval is not required for hawk_val_nil */
} }
@ -2186,7 +2135,7 @@ static HAWK_INLINE int run_block0 (hawk_rtx_t* rtx, hawk_nde_blk_t* nde)
while (p != HAWK_NULL && rtx->exit_level == EXIT_NONE) while (p != HAWK_NULL && rtx->exit_level == EXIT_NONE)
{ {
if (run_statement(rtx, p) <= -1) if (HAWK_UNLIKELY(run_statement(rtx, p) <= -1))
{ {
n = -1; n = -1;
break; break;
@ -2203,7 +2152,7 @@ static HAWK_INLINE int run_block0 (hawk_rtx_t* rtx, hawk_nde_blk_t* nde)
{ {
--nlcls; --nlcls;
hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_LCL(rtx, nlcls)); hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_LCL(rtx, nlcls));
__raw_pop (rtx); HAWK_RTX_STACK_POP (rtx);
} }
return n; return n;
@ -2687,7 +2636,7 @@ static int run_return (hawk_rtx_t* rtx, hawk_nde_return_t* nde)
static int run_exit (hawk_rtx_t* rtx, hawk_nde_exit_t* nde) static int run_exit (hawk_rtx_t* rtx, hawk_nde_exit_t* nde)
{ {
if (nde->val != HAWK_NULL) if (nde->val)
{ {
hawk_val_t* val; hawk_val_t* val;
@ -5938,7 +5887,7 @@ static hawk_val_t* eval_fncall_fnc (hawk_rtx_t* rtx, hawk_nde_t* nde)
hawk_nde_fncall_t* call = (hawk_nde_fncall_t*)nde; hawk_nde_fncall_t* call = (hawk_nde_fncall_t*)nde;
/* the parser must make sure that the number of arguments is proper */ /* the parser must make sure that the number of arguments is proper */
HAWK_ASSERT (call->nargs >= call->u.fnc.spec.arg.min && call->nargs <= call->u.fnc.spec.arg.max); HAWK_ASSERT (call->nargs >= call->u.fnc.spec.arg.min && call->nargs <= call->u.fnc.spec.arg.max);
return __eval_call(rtx, nde, HAWK_NULL, push_arg_from_nde, (void*)call->u.fnc.spec.arg.spec, HAWK_NULL, HAWK_NULL); return hawk_rtx_evalcall(rtx, call, HAWK_NULL, push_arg_from_nde, (void*)call->u.fnc.spec.arg.spec, HAWK_NULL, HAWK_NULL);
} }
static HAWK_INLINE hawk_val_t* eval_fncall_fun_ex (hawk_rtx_t* rtx, hawk_nde_t* nde, void(*errhandler)(void*), void* eharg) static HAWK_INLINE hawk_val_t* eval_fncall_fun_ex (hawk_rtx_t* rtx, hawk_nde_t* nde, void(*errhandler)(void*), void* eharg)
@ -5982,7 +5931,7 @@ static HAWK_INLINE hawk_val_t* eval_fncall_fun_ex (hawk_rtx_t* rtx, hawk_nde_t*
return HAWK_NULL; return HAWK_NULL;
} }
return __eval_call(rtx, nde, fun, push_arg_from_nde, HAWK_NULL, errhandler, eharg); return hawk_rtx_evalcall(rtx, call, fun, push_arg_from_nde, fun->argspec, errhandler, eharg);
} }
static hawk_val_t* eval_fncall_fun (hawk_rtx_t* rtx, hawk_nde_t* nde) static hawk_val_t* eval_fncall_fun (hawk_rtx_t* rtx, hawk_nde_t* nde)
@ -5997,11 +5946,11 @@ static hawk_val_t* eval_fncall_var (hawk_rtx_t* rtx, hawk_nde_t* nde)
hawk_fun_t* fun; hawk_fun_t* fun;
fv = eval_expression(rtx, (hawk_nde_t*)call->u.var.var); fv = eval_expression(rtx, (hawk_nde_t*)call->u.var.var);
if (!fv) return HAWK_NULL; if (HAWK_UNLIKELY(!fv)) return HAWK_NULL;
hawk_rtx_refupval (rtx, fv); hawk_rtx_refupval (rtx, fv);
fun = hawk_rtx_valtofun(rtx, fv); fun = hawk_rtx_valtofun(rtx, fv);
if (!fun) if (HAWK_UNLIKELY(!fun))
{ {
if (hawk_rtx_geterrnum(rtx) == HAWK_EINVAL) if (hawk_rtx_geterrnum(rtx) == HAWK_EINVAL)
hawk_rtx_seterrfmt (rtx, &nde->loc, HAWK_ENOTFUN, HAWK_T("non-function value in %.*js"), call->u.var.var->id.name.len, call->u.var.var->id.name.ptr); hawk_rtx_seterrfmt (rtx, &nde->loc, HAWK_ENOTFUN, HAWK_T("non-function value in %.*js"), call->u.var.var->id.name.len, call->u.var.var->id.name.ptr);
@ -6010,48 +5959,20 @@ static hawk_val_t* eval_fncall_var (hawk_rtx_t* rtx, hawk_nde_t* nde)
} }
else else
{ {
rv = __eval_call(rtx, nde, fun, push_arg_from_nde, HAWK_NULL, HAWK_NULL, HAWK_NULL); rv = hawk_rtx_evalcall(rtx, call, fun, push_arg_from_nde, fun->argspec, HAWK_NULL, HAWK_NULL);
} }
hawk_rtx_refdownval (rtx, fv); hawk_rtx_refdownval (rtx, fv);
return rv; return rv;
} }
/* run->stack_base has not been set for this hawk_val_t* hawk_rtx_evalcall (
* stack frame. so the HAWK_RTX_STACK_ARG macro cannot be used as in hawk_rtx_t* rtx, hawk_nde_fncall_t* call, hawk_fun_t* fun,
* hawk_rtx_refdownval (run, HAWK_RTX_STACK_ARG(run,nargs));*/
#define UNWIND_HAWK_RTX_STACK_ARG(rtx,nargs) \
do { \
while ((nargs) > 0) \
{ \
--(nargs); \
hawk_rtx_refdownval ((rtx), (rtx)->stack[(rtx)->stack_top-1]); \
__raw_pop (rtx); \
} \
} while (0)
#define UNWIND_HAWK_RTX_STACK_BASE(rtx) \
do { \
__raw_pop (rtx); /* nargs */ \
__raw_pop (rtx); /* return */ \
__raw_pop (rtx); /* prev stack top */ \
__raw_pop (rtx); /* prev stack back */ \
} while (0)
#define UNWIND_RTX_STACK(rtx,nargs) \
do { \
UNWIND_HAWK_RTX_STACK_ARG (rtx,nargs); \
UNWIND_HAWK_RTX_STACK_BASE (rtx); \
} while (0)
static hawk_val_t* __eval_call (
hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_fun_t* fun,
hawk_oow_t(*argpusher)(hawk_rtx_t*,hawk_nde_fncall_t*,void*), void* apdata, hawk_oow_t(*argpusher)(hawk_rtx_t*,hawk_nde_fncall_t*,void*), void* apdata,
void(*errhandler)(void*), void* eharg) void(*errhandler)(void*), void* eharg)
{ {
hawk_nde_fncall_t* call = (hawk_nde_fncall_t*)nde; hawk_oow_t saved_stack_top, saved_arg_stack_top;
hawk_oow_t saved_stack_top; hawk_oow_t nargs, i, stack_req;
hawk_oow_t nargs, i;
hawk_val_t* v; hawk_val_t* v;
int n; int n;
@ -6104,88 +6025,47 @@ static hawk_val_t* __eval_call (
hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("setting up function stack frame top=%zd base=%zd\n"), (hawk_oow_t)rtx->stack_top, (hawk_oow_t)rtx->stack_base); hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("setting up function stack frame top=%zd base=%zd\n"), (hawk_oow_t)rtx->stack_top, (hawk_oow_t)rtx->stack_base);
#endif #endif
if (HAWK_UNLIKELY(__raw_push(rtx,(void*)rtx->stack_base) <= -1)) /* make a new stack frame */
stack_req = 4 + call->nargs;
if (fun)
{ {
ADJERR_LOC (rtx, &nde->loc); HAWK_ASSERT (fun->nargs >= call->nargs); /* the compiler must guarantee this */
stack_req += fun->nargs - call->nargs;
}
/* if fun is HAWK_NULL, there is no way for this function to know expected argument numbers.
* the argument pusher must ensure the stack availality before pushing arguments */
if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < stack_req))
{
hawk_rtx_seterrnum (rtx, &call->loc, HAWK_ESTACK);
return HAWK_NULL; return HAWK_NULL;
} }
if (HAWK_UNLIKELY(__raw_push(rtx,(void*)saved_stack_top) <= -1)) HAWK_RTX_STACK_PUSH (rtx, (void*)rtx->stack_base);
{ HAWK_RTX_STACK_PUSH (rtx, (void*)saved_stack_top);
__raw_pop (rtx); HAWK_RTX_STACK_PUSH (rtx, hawk_val_nil); /* space for return value */
ADJERR_LOC (rtx, &nde->loc); HAWK_RTX_STACK_PUSH (rtx, hawk_val_nil); /* space for number of arguments */
return HAWK_NULL;
}
/* secure space for a return value. */ saved_arg_stack_top = rtx->stack_top;
if (HAWK_UNLIKELY(__raw_push(rtx,hawk_val_nil) <= -1))
{
__raw_pop (rtx);
__raw_pop (rtx);
ADJERR_LOC (rtx, &nde->loc);
return HAWK_NULL;
}
/* secure space for nargs */
if (HAWK_UNLIKELY(__raw_push(rtx,hawk_val_nil) <= -1))
{
__raw_pop (rtx);
__raw_pop (rtx);
__raw_pop (rtx);
ADJERR_LOC (rtx, &nde->loc);
return HAWK_NULL;
}
/* push all arguments onto the stack */ /* push all arguments onto the stack */
nargs = argpusher(rtx, call, apdata); nargs = argpusher(rtx, call, apdata);
if (nargs == (hawk_oow_t)-1) if (nargs == (hawk_oow_t)-1) goto oops_making_stack_frame;
{
UNWIND_HAWK_RTX_STACK_BASE (rtx);
return HAWK_NULL;
}
HAWK_ASSERT (nargs == call->nargs); HAWK_ASSERT (nargs == call->nargs);
if (fun) if (fun)
{ {
/* extra step for normal awk functions */ /* extra step for normal awk functions */
if (fun->argspec && call->args) /* hawk_rtx_callfun() sets up a fake call structure with nargs > 0 but args == HAWK_NULL */
{
/* sanity check for pass-by-reference parameters of a normal awk function.
* it tests if each pass-by-reference argument is referenceable. */
hawk_nde_t* p = call->args;
for (i = 0; i < nargs; i++)
{
if (fun->argspec[i] == HAWK_T('r'))
{
hawk_val_t** ref;
if (get_reference(rtx, p, &ref) <= -1)
{
UNWIND_RTX_STACK (rtx, nargs);
return HAWK_NULL;
}
}
p = p->next;
}
}
while (nargs < fun->nargs) while (nargs < fun->nargs)
{ {
/* push as many nils as the number of missing actual arguments */ /* push as many nils as the number of missing actual arguments */
if (HAWK_UNLIKELY(__raw_push(rtx, hawk_val_nil) <= -1)) HAWK_RTX_STACK_PUSH (rtx, hawk_val_nil);
{
UNWIND_RTX_STACK (rtx, nargs);
ADJERR_LOC (rtx, &nde->loc);
return HAWK_NULL;
}
nargs++; nargs++;
} }
} }
/* entering a new stack frame */
rtx->stack_base = saved_stack_top; rtx->stack_base = saved_stack_top;
HAWK_RTX_STACK_NARGS(rtx) = (void*)nargs; HAWK_RTX_STACK_NARGS(rtx) = (void*)nargs;
@ -6209,7 +6089,7 @@ static hawk_val_t* __eval_call (
if (call->u.fnc.spec.impl) if (call->u.fnc.spec.impl)
{ {
n = call->u.fnc.spec.impl(rtx, &call->u.fnc.info); n = call->u.fnc.spec.impl(rtx, &call->u.fnc.info);
if (HAWK_UNLIKELY(n <= -1)) ADJERR_LOC (rtx, &nde->loc); if (HAWK_UNLIKELY(n <= -1)) ADJERR_LOC (rtx, &call->loc);
} }
} }
@ -6219,7 +6099,8 @@ static hawk_val_t* __eval_call (
hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("block rtx complete nargs = %d\n"), (int)nargs); hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("block rtx complete nargs = %d\n"), (int)nargs);
#endif #endif
if (fun && fun->argspec && call->args && call->nargs > 0) /* hawk_rtx_callfun() sets up a fake call structure with nargs > 0 but args == HAWK_NULL */ i = 0;
if (fun && fun->argspec && call->nargs > 0) /* hawk_rtx_callfun() sets up a fake call structure with call->nargs > 0 but call->args == HAWK_NULL */
{ {
/* set back the values for pass-by-reference parameters of normal functions. /* set back the values for pass-by-reference parameters of normal functions.
* the intrinsic functions are not handled here but their implementation would * the intrinsic functions are not handled here but their implementation would
@ -6231,51 +6112,87 @@ static hawk_val_t* __eval_call (
* all parameters are nils in this case. nargs and fun->nargs are 2 but call->nargs is 0. * all parameters are nils in this case. nargs and fun->nargs are 2 but call->nargs is 0.
*/ */
if (call->args)
{
hawk_oow_t cur_stack_base = rtx->stack_base; hawk_oow_t cur_stack_base = rtx->stack_base;
hawk_oow_t prev_stack_base = (hawk_oow_t)rtx->stack[rtx->stack_base + 0]; hawk_oow_t prev_stack_base = (hawk_oow_t)rtx->stack[rtx->stack_base + 0];
hawk_nde_t* p = call->args; hawk_nde_t* p = call->args;
for (i = 0; i < call->nargs; i++)
for (; i < call->nargs; i++)
{ {
if (n >= 0 && fun->argspec[i] == HAWK_T('r')) if (n >= 0 && (fun->argspec[i] == 'r' || fun->argspec[i] == 'R'))
{ {
hawk_val_t** ref; hawk_val_t** ref;
hawk_val_ref_t refv; hawk_val_ref_t refv;
int r;
/* if an argument passed is a local variable or a parameter to the previous caller, /* if an argument passed is a local variable or a parameter to the previous caller,
* the argument node information stored is relative to the previous stack frame. * the argument node information stored is relative to the previous stack frame.
* i revert rtx->stack_base to the previous stack frame base before calling * i revert rtx->stack_base to the previous stack frame base before calling
* get_reference() and restors it back to the current base. this tactic * get_reference() and restors it back to the current base. this tactic
* is very ugly because the assumptions for this is dependent on get_reference() * is very ugly because the assumptions for this is depecallnt on get_reference()
* implementation */ * implementation */
rtx->stack_base = prev_stack_base; /* UGLY */ rtx->stack_base = prev_stack_base; /* UGLY */
get_reference (rtx, p, &ref); /* no failure check as it must succeed here for the check done above */ r = get_reference(rtx, p, &ref);
rtx->stack_base = cur_stack_base; /* UGLY */ rtx->stack_base = cur_stack_base; /* UGLY */
/* if argspec is 'r', get_reference() must succeed all the time.
* if argspec is 'R', it may fail. if it happens, don't copy the value */
if (HAWK_LIKELY(r >= 0))
{
HAWK_RTX_INIT_REF_VAL (&refv, p->type - HAWK_NDE_NAMED, ref, 9); /* initialize a fake reference variable. 9 chosen randomly */ HAWK_RTX_INIT_REF_VAL (&refv, p->type - HAWK_NDE_NAMED, ref, 9); /* initialize a fake reference variable. 9 chosen randomly */
if (HAWK_UNLIKELY(hawk_rtx_setrefval(rtx, &refv, HAWK_RTX_STACK_ARG(rtx, i)) <= -1)) if (HAWK_UNLIKELY(hawk_rtx_setrefval(rtx, &refv, HAWK_RTX_STACK_ARG(rtx, i)) <= -1))
{ {
n = -1; n = -1;
ADJERR_LOC (rtx, &nde->loc); ADJERR_LOC (rtx, &call->loc);
}
} }
} }
hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_ARG(rtx,i)); hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_ARG(rtx,i));
p = p->next; p = p->next;
} }
}
else if (call->arg_base > 0) /* special case. set by hawk::call() */
{
/*
* function f1(a,&b) { b *= 20; }
* BEGIN { q = 4; hawk::call(r, "f1", 20, q); print q;
* }
* the fourth argument to hawk::call() must map to the second argument to f1().
* hawk::call() accepts the third to the last arguments as reference if possible.
* this function attempts to copy back the pass-by-reference values to
* one stack frame up.
*
* f1(1, 2) is an error as 2 is not referenceable.
* hakw::call(r, "f1", 1, 2) is not an error but can't capture changes made inside f1.
*/
for (; i < call->nargs; i++)
{
if (n >= 0 && (fun->argspec[i] == 'r' || fun->argspec[i] == 'R'))
{
hawk_val_t* v;
v = rtx->stack[call->arg_base + i]; /* UGLY */
if (HAWK_RTX_GETVALTYPE(rtx, v) == HAWK_VAL_REF)
{
if (HAWK_UNLIKELY(hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)v, HAWK_RTX_STACK_ARG(rtx, i)) <= -1))
{
n = -1;
ADJERR_LOC (rtx, &call->loc);
}
}
}
hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_ARG(rtx,i));
}
}
}
for (; i < nargs; i++) for (; i < nargs; i++)
{ {
hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_ARG(rtx,i)); hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_ARG(rtx,i));
} }
}
else
{
for (i = 0; i < nargs; i++)
{
hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_ARG(rtx,i));
}
}
#if defined(DEBUG_RUN) #if defined(DEBUG_RUN)
hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("got return value\n")); hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("got return value\n"));
@ -6286,13 +6203,13 @@ static hawk_val_t* __eval_call (
{ {
if (hawk_rtx_geterrnum(rtx) == HAWK_ENOERR && errhandler != HAWK_NULL) if (hawk_rtx_geterrnum(rtx) == HAWK_ENOERR && errhandler != HAWK_NULL)
{ {
/* errhandler is passed only when __eval_call() is /* errhandler is passed only when hawk_rtx_evalcall() is
* invoked from hawk_rtx_call(). Under this * invoked from hawk_rtx_call(). Ucallr this
* circumstance, this stack frame is the first * circumstance, this stack frame is the first
* activated and the stack base is the first element * activated and the stack base is the first element
* after the global variables. so HAWK_RTX_STACK_RETVAL(rtx) * after the global variables. so HAWK_RTX_STACK_RETVAL(rtx)
* effectively becomes HAWK_RTX_STACK_RETVAL_GBL(rtx). * effectively becomes HAWK_RTX_STACK_RETVAL_GBL(rtx).
* As __eval_call() returns HAWK_NULL on error and * As hawk_rtx_evalcall() returns HAWK_NULL on error and
* the reference count of HAWK_RTX_STACK_RETVAL(rtx) should be * the reference count of HAWK_RTX_STACK_RETVAL(rtx) should be
* decremented, it can't get the return value * decremented, it can't get the return value
* if it turns out to be terminated by exit(). * if it turns out to be terminated by exit().
@ -6336,6 +6253,27 @@ static hawk_val_t* __eval_call (
hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("returning from function top=%zd, base=%zd\n"), (hawk_oow_t)rtx->stack_top, (hawk_oow_t)rtx->stack_base); hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("returning from function top=%zd, base=%zd\n"), (hawk_oow_t)rtx->stack_top, (hawk_oow_t)rtx->stack_base);
#endif #endif
return (n <= -1)? HAWK_NULL: v; return (n <= -1)? HAWK_NULL: v;
oops_making_stack_frame:
while (rtx->stack_top > saved_arg_stack_top)
{
/* call hawk_rtx_refdownval() for all arguments.
* it is safe because nil or quickint is immune to excessive hawk_rtx_refdownval() calls */
hawk_rtx_refdownval(rtx, rtx->stack[rtx->stack_top - 1]);
HAWK_RTX_STACK_POP (rtx);
}
HAWK_ASSERT (rtx->stack_top - saved_stack_top == 4);
while (rtx->stack_top > saved_stack_top)
{
/* the stack frame prologue does not have a reference-counted value
* before being entered. so no hawk_rtx_refdownval().
* three slots contains raw integers for internal use.. only one
* slot that contains the return value would be reference counted
* after it is set to a reference counted value. here, it never happens */
HAWK_RTX_STACK_POP (rtx);
}
ADJERR_LOC (rtx, &call->loc);
return HAWK_NULL;
} }
static hawk_oow_t push_arg_from_vals (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, void* data) static hawk_oow_t push_arg_from_vals (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, void* data)
@ -6343,51 +6281,33 @@ static hawk_oow_t push_arg_from_vals (hawk_rtx_t* rtx, hawk_nde_fncall_t* call,
struct pafv_t* pafv = (struct pafv_t*)data; struct pafv_t* pafv = (struct pafv_t*)data;
hawk_oow_t nargs = 0; hawk_oow_t nargs = 0;
if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < pafv->nargs))
{
hawk_rtx_seterrnum (rtx, &call->loc, HAWK_ESTACK);
return (hawk_oow_t)-1;
}
for (nargs = 0; nargs < pafv->nargs; nargs++) for (nargs = 0; nargs < pafv->nargs; nargs++)
{ {
if (pafv->argspec && pafv->argspec[nargs] == HAWK_T('r')) if (pafv->argspec && (pafv->argspec[nargs] == 'r' || pafv->argspec[nargs] == 'R'))
{ {
hawk_val_t** ref; hawk_val_t** ref;
hawk_val_t* v; hawk_val_t* v;
ref = (hawk_val_t**)&pafv->args[nargs]; ref = (hawk_val_t**)&pafv->args[nargs];
v = hawk_rtx_makerefval(rtx, HAWK_VAL_REF_LCL, ref); /* this type(HAWK_VAL_REF_LCL) is fake */ v = hawk_rtx_makerefval(rtx, HAWK_VAL_REF_LCL, ref); /* this type(HAWK_VAL_REF_LCL) is fake */
if (!v) if (HAWK_UNLIKELY(!v))
{ {
UNWIND_HAWK_RTX_STACK_ARG (rtx, nargs);
ADJERR_LOC (rtx, &call->loc);
return (hawk_oow_t)-1;
}
if (HAWK_UNLIKELY(__raw_push(rtx, v) <= -1))
{
hawk_rtx_refupval (rtx, v);
hawk_rtx_refdownval (rtx, v);
UNWIND_HAWK_RTX_STACK_ARG (rtx, nargs);
ADJERR_LOC (rtx, &call->loc); ADJERR_LOC (rtx, &call->loc);
return (hawk_oow_t)-1; return (hawk_oow_t)-1;
} }
HAWK_RTX_STACK_PUSH (rtx, v);
hawk_rtx_refupval (rtx, v); hawk_rtx_refupval (rtx, v);
} }
else else
{ {
if (HAWK_UNLIKELY(__raw_push(rtx, pafv->args[nargs]) <= -1)) HAWK_RTX_STACK_PUSH (rtx, pafv->args[nargs]);
{
/* ugly - arg needs to be freed if it doesn't have
* any reference. but its reference has not been
* updated yet as it is carried out after successful
* stack push. so it adds up a reference and
* dereferences it */
hawk_rtx_refupval (rtx, pafv->args[nargs]);
hawk_rtx_refdownval (rtx, pafv->args[nargs]);
UNWIND_HAWK_RTX_STACK_ARG (rtx, nargs);
ADJERR_LOC (rtx, &call->loc);
return (hawk_oow_t)-1;
}
hawk_rtx_refupval (rtx, pafv->args[nargs]); hawk_rtx_refupval (rtx, pafv->args[nargs]);
} }
} }
@ -6400,11 +6320,17 @@ static hawk_oow_t push_arg_from_nde (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, v
hawk_nde_t* p; hawk_nde_t* p;
hawk_val_t* v; hawk_val_t* v;
hawk_oow_t nargs; hawk_oow_t nargs;
const hawk_ooch_t* fnc_arg_spec = (const hawk_ooch_t*)data; const hawk_ooch_t* arg_spec = (const hawk_ooch_t*)data;
hawk_oow_t spec_len; hawk_oow_t spec_len;
spec_len = fnc_arg_spec? hawk_count_oocstr(fnc_arg_spec): 0; if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < call->nargs))
for (p = call->args, nargs = 0; p != HAWK_NULL; p = p->next, nargs++) {
hawk_rtx_seterrnum (rtx, &call->loc, HAWK_ESTACK);
return (hawk_oow_t)-1;
}
spec_len = arg_spec? hawk_count_oocstr(arg_spec): 0;
for (p = call->args, nargs = 0; p; p = p->next, nargs++)
{ {
hawk_ooch_t spec; hawk_ooch_t spec;
@ -6414,59 +6340,47 @@ static hawk_oow_t push_arg_from_nde (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, v
{ {
/* not sufficient number of spec characters given. /* not sufficient number of spec characters given.
* take the last value and use it */ * take the last value and use it */
spec = fnc_arg_spec[spec_len - 1]; spec = arg_spec[spec_len - 1];
} }
else else
{ {
spec = fnc_arg_spec[nargs]; spec = arg_spec[nargs];
} }
} }
else spec = '\0'; else spec = '\0';
if (spec == 'r') switch (spec)
{
case 'R': /* make reference if a referenceable is given. otherwise accept a normal value - useful for hawk::call() */
case 'r': /* make reference. a non-referenceable value is rejected */
{ {
hawk_val_t** ref; hawk_val_t** ref;
if (get_reference(rtx, p, &ref) <= -1) if (get_reference(rtx, p, &ref) <= -1)
{ {
UNWIND_HAWK_RTX_STACK_ARG (rtx, nargs); if (spec == 'R') goto normal_arg;
return (hawk_oow_t)-1; return (hawk_oow_t)-1; /* return -1 without unwinding stack as hawk_rtx_evalcall() does it */
} }
/* 'p->type - HAWK_NDE_NAMED' must produce a relevant HAWK_VAL_REF_XXX value. */ /* 'p->type - HAWK_NDE_NAMED' must produce a relevant HAWK_VAL_REF_XXX value. */
v = hawk_rtx_makerefval(rtx, p->type - HAWK_NDE_NAMED, ref); v = hawk_rtx_makerefval(rtx, p->type - HAWK_NDE_NAMED, ref);
break;
} }
else if (spec == 'x')
{ case 'x':
/* a regular expression is passed to the function as it is */ /* a regular expression is passed to the function as it is */
v = eval_expression0(rtx, p); v = eval_expression0(rtx, p);
} break;
else
{ default:
normal_arg:
v = eval_expression(rtx, p); v = eval_expression(rtx, p);
break;
} }
if (HAWK_UNLIKELY(!v)) if (HAWK_UNLIKELY(!v)) return (hawk_oow_t)-1; /* return -1 without unwinding stack as hawk_rtx_evalcall() does it */
{
UNWIND_HAWK_RTX_STACK_ARG (rtx, nargs);
return (hawk_oow_t)-1;
}
if (HAWK_UNLIKELY(__raw_push(rtx,v) <= -1))
{
/* ugly - v needs to be freed if it doesn't have
* any reference. but its reference has not been
* updated yet as it is carried out after the
* successful stack push. so it adds up a reference
* and dereferences it */
hawk_rtx_refupval (rtx, v);
hawk_rtx_refdownval (rtx, v);
UNWIND_HAWK_RTX_STACK_ARG (rtx, nargs);
ADJERR_LOC (rtx, &call->loc);
return (hawk_oow_t)-1;
}
HAWK_RTX_STACK_PUSH (rtx, v);
hawk_rtx_refupval (rtx, v); hawk_rtx_refupval (rtx, v);
} }

View File

@ -224,6 +224,7 @@ struct hawk_nde_fncall_t
} u; } u;
hawk_nde_t* args; hawk_nde_t* args;
hawk_oow_t nargs; hawk_oow_t nargs;
hawk_oow_t arg_base; /* special field set by hawk::call() and handled by hawk_rtx_evalcall() */
}; };
/* HAWK_NDE_GETLINE */ /* HAWK_NDE_GETLINE */