simplified hawk::call().
fixed a bug in copying a value for a reference upon returning from a function in hawk_rtx_evalcall(). it was unable to handle the case where a reference variable is not updated in the called function
This commit is contained in:
parent
f5da432bb4
commit
a8afcca04e
@ -27,8 +27,13 @@
|
|||||||
#include "mod-hawk.h"
|
#include "mod-hawk.h"
|
||||||
#include "hawk-prv.h"
|
#include "hawk-prv.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function abc(a, b, c) { return a + b + c; }
|
||||||
|
* BEGIN { print hawk::call("abc", 10, 20, 30); }
|
||||||
|
*/
|
||||||
struct pafs_t
|
struct pafs_t
|
||||||
{
|
{
|
||||||
|
hawk_fun_t* fun;
|
||||||
hawk_oow_t stack_base;
|
hawk_oow_t stack_base;
|
||||||
hawk_oow_t start_index;
|
hawk_oow_t start_index;
|
||||||
hawk_oow_t end_index;
|
hawk_oow_t end_index;
|
||||||
@ -37,7 +42,7 @@ struct pafs_t
|
|||||||
static hawk_oow_t push_args_from_stack (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, void* data)
|
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;
|
struct pafs_t* pasf = (struct pafs_t*)data;
|
||||||
hawk_oow_t org_stack_base, i;
|
hawk_oow_t org_stack_base, spec_len, i, j;
|
||||||
hawk_val_t* v;
|
hawk_val_t* v;
|
||||||
|
|
||||||
if (HAWK_RTX_STACK_AVAIL(rtx) < pasf->end_index - pasf->start_index + 1)
|
if (HAWK_RTX_STACK_AVAIL(rtx) < pasf->end_index - pasf->start_index + 1)
|
||||||
@ -46,13 +51,21 @@ static hawk_oow_t push_args_from_stack (hawk_rtx_t* rtx, hawk_nde_fncall_t* call
|
|||||||
return (hawk_oow_t)-1;
|
return (hawk_oow_t)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spec_len = pasf->fun->argspec? hawk_count_oocstr(pasf->fun->argspec): 0;
|
||||||
|
|
||||||
org_stack_base = rtx->stack_base;
|
org_stack_base = rtx->stack_base;
|
||||||
for (i = pasf->start_index; i <= pasf->end_index; i++)
|
for (i = pasf->start_index, j = 0; i <= pasf->end_index; i++, j++)
|
||||||
{
|
{
|
||||||
rtx->stack_base = pasf->stack_base;
|
rtx->stack_base = pasf->stack_base;
|
||||||
v = HAWK_RTX_STACK_ARG(rtx, i);
|
v = HAWK_RTX_STACK_ARG(rtx, i);
|
||||||
rtx->stack_base = org_stack_base;
|
rtx->stack_base = org_stack_base;
|
||||||
|
|
||||||
|
if (j < spec_len && pasf->fun->argspec[j] == 'r' && HAWK_RTX_GETVALTYPE(rtx, v) != HAWK_VAL_REF)
|
||||||
|
{
|
||||||
|
hawk_rtx_seterrnum (rtx, &call->loc, HAWK_ENOTREF);
|
||||||
|
return (hawk_oow_t)-1;
|
||||||
|
}
|
||||||
|
|
||||||
HAWK_RTX_STACK_PUSH (rtx, v);
|
HAWK_RTX_STACK_PUSH (rtx, v);
|
||||||
hawk_rtx_refupval (rtx, v);
|
hawk_rtx_refupval (rtx, v);
|
||||||
}
|
}
|
||||||
@ -66,45 +79,36 @@ static int fnc_call (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|||||||
hawk_oow_t nargs;
|
hawk_oow_t nargs;
|
||||||
hawk_nde_fncall_t call;
|
hawk_nde_fncall_t call;
|
||||||
struct pafs_t pafs;
|
struct pafs_t pafs;
|
||||||
hawk_val_t* v, * a0;
|
hawk_val_t* v;
|
||||||
int rx = -1;
|
|
||||||
|
|
||||||
/* this function is similar to hawk_rtx_callfun() but it is more simplified */
|
/* 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, 0));
|
||||||
|
if (!fun) return -1; /* hard failure */
|
||||||
fun = hawk_rtx_valtofun(rtx, hawk_rtx_getarg(rtx, 1));
|
|
||||||
if (!fun) goto done;
|
|
||||||
|
|
||||||
nargs = hawk_rtx_getnargs(rtx);
|
nargs = hawk_rtx_getnargs(rtx);
|
||||||
if (nargs - 2 > fun->nargs)
|
if (nargs - 1 > fun->nargs)
|
||||||
{
|
{
|
||||||
/*hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EARGTM);
|
hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EARGTM);
|
||||||
return HAWK_NULL;*/
|
return -1; /* hard failure */
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HAWK_MEMSET (&call, 0, HAWK_SIZEOF(call));
|
HAWK_MEMSET (&call, 0, HAWK_SIZEOF(call));
|
||||||
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 - 2;
|
call.nargs = nargs - 1;
|
||||||
/* keep HAWK_NULL in call.args so that hawk_rtx_evalcall() 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 */
|
||||||
call.arg_base = rtx->stack_base + 6; /* 6 = 4(stack frame prologue) + 2(the first two arguments to hawk::call()) */
|
call.arg_base = rtx->stack_base + 5; /* 5 = 4(stack frame prologue) + 1(the first argument to hawk::call()) */
|
||||||
|
|
||||||
|
pafs.fun = fun;
|
||||||
pafs.stack_base = rtx->stack_base;
|
pafs.stack_base = rtx->stack_base;
|
||||||
pafs.start_index = 2;
|
pafs.start_index = 1;
|
||||||
pafs.end_index = nargs - 1;
|
pafs.end_index = nargs - 1;
|
||||||
|
|
||||||
v = hawk_rtx_evalcall(rtx, &call, fun, push_args_from_stack, (void*)&pafs, HAWK_NULL, HAWK_NULL);
|
v = hawk_rtx_evalcall(rtx, &call, fun, push_args_from_stack, (void*)&pafs, HAWK_NULL, HAWK_NULL);
|
||||||
if (HAWK_LIKELY(v))
|
if (HAWK_UNLIKELY(!v)) return -1; /* hard failure */
|
||||||
{
|
|
||||||
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, v);
|
||||||
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, rx));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +192,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("call"), { { 1, A_MAX, HAWK_T("vR") }, 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 } }
|
||||||
|
@ -1454,14 +1454,13 @@ static hawk_nde_t* parse_function (hawk_t* awk)
|
|||||||
nargs = HAWK_ARR_SIZE(awk->parse.params);
|
nargs = HAWK_ARR_SIZE(awk->parse.params);
|
||||||
if (nargs >= argspeccapa)
|
if (nargs >= argspeccapa)
|
||||||
{
|
{
|
||||||
hawk_oow_t i, newcapa = HAWK_ALIGN_POW2(nargs + 1, 64);
|
hawk_oow_t i, newcapa = HAWK_ALIGN_POW2(nargs + 2, 64);
|
||||||
argspec = hawk_reallocmem(awk, argspec, newcapa * HAWK_SIZEOF(*argspec));
|
argspec = hawk_reallocmem(awk, argspec, newcapa * HAWK_SIZEOF(*argspec));
|
||||||
if (!argspec) goto oops;
|
if (!argspec) goto oops;
|
||||||
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] = 'r';
|
argspec[nargs] = 'r';
|
||||||
argspec[nargs + 1] = '\0';
|
|
||||||
if (get_token(awk) <= -1) goto oops;
|
if (get_token(awk) <= -1) goto oops;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1522,6 +1521,7 @@ static hawk_nde_t* parse_function (hawk_t* awk)
|
|||||||
while (MATCH(awk,TOK_NEWLINE));
|
while (MATCH(awk,TOK_NEWLINE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (argspec) argspec[nargs + 1] = '\0';
|
||||||
if (get_token(awk) <= -1) goto oops;
|
if (get_token(awk) <= -1) goto oops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6124,8 +6124,24 @@ hawk_val_t* hawk_rtx_evalcall (
|
|||||||
{
|
{
|
||||||
hawk_val_t** ref;
|
hawk_val_t** ref;
|
||||||
hawk_val_ref_t refv;
|
hawk_val_ref_t refv;
|
||||||
|
hawk_val_t* av;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
av = HAWK_RTX_STACK_ARG(rtx, i);
|
||||||
|
if (HAWK_RTX_GETVALTYPE(rtx, av) == HAWK_VAL_REF)
|
||||||
|
{
|
||||||
|
/* the argument still has the reference type.
|
||||||
|
* this means, the argument has not been set.
|
||||||
|
*
|
||||||
|
* function f1(&a, &b) { b = 20 }
|
||||||
|
*
|
||||||
|
* since a is not set in f1, the value for a is still the pushed value which is a reference
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ---- DO NOTHING ---- */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* 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
|
||||||
@ -6141,13 +6157,14 @@ hawk_val_t* hawk_rtx_evalcall (
|
|||||||
if (HAWK_LIKELY(r >= 0))
|
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, av) <= -1))
|
||||||
{
|
{
|
||||||
n = -1;
|
n = -1;
|
||||||
ADJERR_LOC (rtx, &call->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;
|
||||||
@ -6157,8 +6174,8 @@ hawk_val_t* hawk_rtx_evalcall (
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* function f1(a,&b) { b *= 20; }
|
* function f1(a,&b) { b *= 20; }
|
||||||
* BEGIN { q = 4; hawk::call(r, "f1", 20, q); print q;
|
* 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().
|
* 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.
|
* 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
|
* this function attempts to copy back the pass-by-reference values to
|
||||||
@ -6171,18 +6188,26 @@ hawk_val_t* hawk_rtx_evalcall (
|
|||||||
{
|
{
|
||||||
if (n >= 0 && (fun->argspec[i] == 'r' || fun->argspec[i] == 'R'))
|
if (n >= 0 && (fun->argspec[i] == 'r' || fun->argspec[i] == 'R'))
|
||||||
{
|
{
|
||||||
hawk_val_t* v;
|
hawk_val_t* v, * av;
|
||||||
|
|
||||||
|
av = HAWK_RTX_STACK_ARG(rtx, i);
|
||||||
|
if (HAWK_RTX_GETVALTYPE(rtx, av) == HAWK_VAL_REF)
|
||||||
|
{
|
||||||
|
/* ---- DO NOTHING ---- */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
v = rtx->stack[call->arg_base + i]; /* UGLY */
|
v = rtx->stack[call->arg_base + i]; /* UGLY */
|
||||||
if (HAWK_RTX_GETVALTYPE(rtx, v) == HAWK_VAL_REF)
|
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))
|
if (HAWK_UNLIKELY(hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)v, av) <= -1))
|
||||||
{
|
{
|
||||||
n = -1;
|
n = -1;
|
||||||
ADJERR_LOC (rtx, &call->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));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user