Skip to content

Commit

Permalink
sigopt: abuse unused vm_proto self arg for numargs
Browse files Browse the repository at this point in the history
  • Loading branch information
Reini Urban committed Jun 18, 2013
1 parent d5b7801 commit 3b3bf7b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 19 deletions.
4 changes: 3 additions & 1 deletion core/potion.h
Expand Up @@ -179,7 +179,9 @@ struct PNVtable;
#define PN_IS_PROTO(v) (PN_TYPE(v) == PN_TPROTO)
#define PN_IS_REF(v) (PN_TYPE(v) == PN_TWEAK)
#define PN_IS_METACLASS(v) (((struct PNVtable *)v)->meta == PN_NIL)
#define PN_IS_FFIPTR(p) (PN_IS_PTR(p) && !(p >= (_PN)P->mem && p <= (_PN)P->mem->old_hi))
#define PN_IS_FFIPTR(p) ((PN_IS_PTR(p) && !(p >= (_PN)P->mem && p <= (_PN)P->mem->birth_hi)) \
|| (!PN_IS_PTR(p) && p > (_PN)P->mem->birth_hi))


///\class PNNumber
/// Either a PN_INT immediate object (no struct) 0x...1
Expand Down
28 changes: 22 additions & 6 deletions core/vm.c
Expand Up @@ -116,34 +116,50 @@ void potion_vm_init(Potion *P) {

/**
entrypoint for all bytecode methods from the C api. \see potion_test_eval()
\param cl PNClosure to be called
\param self PN - sets self (ignored for most user defined functions).
if self is a int < 10 it defines the number of args provided
\param ... - arguments to the cl
x
\verbatim
add = potion_eval(P, potion_str(P, "(x=N,y=N): x + y."), 0);
add = potion_eval(P, potion_str(P, "(x=N|y=N): x + y."), 0);
addfn = PN_CLOSURE_F(add); // i.e. potion_vm_proto
num = addfn(P, add, PN_NUM(3), PN_NUM(5));
num = addfn(P, add, 2, PN_NUM(3), PN_NUM(5));
num = addfn(P, add, 1, PN_NUM(3)); // 1 arg provided, 2nd arg=0
\endverbatim
Note that methods with optional arguments ... are not very safe to call.
potion_vm_proto() does not know the number of arguments on the stack.
So it checks for all optional args the matching type. */
So it checks for all optional args the matching type.
You can help by providing numargs as self argument if numargs < 10. */
PN potion_vm_proto(Potion *P, PN cl, PN self, ...) {
PN ary = PN_NIL;
vPN(Proto) f = (struct PNProto *)PN_CLOSURE(cl)->data[0];
if (PN_IS_TUPLE(f->sig)) {
PN_SIZE i;
int arity = PN_CLOSURE(cl)->arity;
int minargs = PN_CLOSURE(cl)->minargs;
int numargs = 0;
va_list args;
ary = PN_TUP0();
va_start(args, self);
//ary = PN_PUSH(ary, self);
if (self < 10) {
numargs = self;
self = 0;
}
for (i=0; i < arity; i++) {
PN s = potion_sig_at(P, f->sig, i);
if (i < minargs || PN_TUPLE_LEN(s) < 2) { //mandatory or no type
ary = PN_PUSH(ary, va_arg(args, PN));
} else { //vararg call heuristic: check type of stack var, replace with default
PN arg = va_arg(args, PN);
char type = (char)(PN_TUPLE_LEN(s) > 1 ? PN_INT(PN_TUPLE_AT(s,1)) : 0);
if (PN_IS_FFIPTR(arg) || (type && potion_type_char(PN_TYPE(arg)) != type)) { //replace with default
char type = (char)(PN_TUPLE_LEN(s) > 2
? potion_type_char(PN_TYPE(PN_TUPLE_AT(s,2)))
: PN_TUPLE_LEN(s) > 1
? PN_INT(PN_TUPLE_AT(s,1)) : 0);
if ((numargs && (i >= numargs)) //numargs provided via self
|| PN_IS_FFIPTR(arg)
|| (type && (potion_type_char(PN_TYPE(arg)) != type))) { //replace with default
// default value or 0
ary = PN_PUSH(ary, PN_TUPLE_LEN(s) == 3 ? PN_TUPLE_AT(s,2) : potion_type_default(type));
} else {
Expand Down
23 changes: 11 additions & 12 deletions test/api/potion-test.c
Expand Up @@ -163,44 +163,43 @@ void potion_test_eval(CuTest *T) {
add = potion_eval(P, potion_str(P, "(x, y): x + y."), 0);
addfn = PN_CLOSURE_F(add); // c callback
CuAssertPtrNotNull(T, addfn);
num = addfn(P, add, PN_NUM(3), PN_NUM(5));
num = addfn(P, add, 0, PN_NUM(3), PN_NUM(5));
CuAssertIntEquals(T, "calling closure as c func", 8, PN_INT(num));

add = potion_eval(P, potion_str(P, "(x=N|y=N): x + y."), 0);
addfn = PN_CLOSURE_F(add);
num = addfn(P, add, PN_NUM(3), PN_NUM(5));
num = addfn(P, add, 0, PN_NUM(3), PN_NUM(5));
CuAssertIntEquals(T, "calling closure as c func (opt)", 8, PN_INT(num));
num = addfn(P, add, PN_NUM(1), PN_NUM(3));
num = addfn(P, add, 1, PN_NUM(3));
CuAssertIntEquals(T, "optional num = 0", 3, PN_INT(num));

add = potion_eval(P, potion_str(P, "(x=N,y:=1): x + y."), 0); //TODO: x=N|y:=1
addfn = PN_CLOSURE_F(add);
num = addfn(P, add, PN_NUM(3), PN_NUM(5));
CuAssertIntEquals(T, "calling closure as c func (default)",
PN_INT(num), 8);
num = addfn(P, add, PN_NUM(3));
num = addfn(P, add, 2, PN_NUM(3), PN_NUM(5));
CuAssertIntEquals(T, "calling closure as c func (default)", 8, PN_INT(num));
num = addfn(P, add, 1, PN_NUM(3));
CuAssertIntEquals(T, "default num = 1", 4, PN_INT(num));

#if POTION_JIT
add = potion_eval(P, potion_str(P, "(x, y): x + y."), POTION_JIT);
addfn = PN_CLOSURE_F(add); // c callback
CuAssertPtrNotNull(T, addfn);
num = addfn(P, add, PN_NUM(3), PN_NUM(5));
num = addfn(P, add, 0, PN_NUM(3), PN_NUM(5));
CuAssertIntEquals(T, "calling closure as c func (jit)", 8, PN_INT(num));

//P->flags += DEBUG_COMPILE;
add = potion_eval(P, potion_str(P, "(x=N|y=N): x + y."), POTION_JIT);
addfn = PN_CLOSURE_F(add);
num = addfn(P, add, PN_NUM(3), PN_NUM(5));
num = addfn(P, add, 0, PN_NUM(3), PN_NUM(5));
CuAssertIntEquals(T, "calling closure as c func (jit+opt)", 8, PN_INT(num));
num = addfn(P, add, PN_NUM(3));
num = addfn(P, add, 1, PN_NUM(3));
CuAssertIntEquals(T, "optional num = 0 (jit)", 3, PN_INT(num));

add = potion_eval(P, potion_str(P, "(x=N|y:=1): x + y."), POTION_JIT);
addfn = PN_CLOSURE_F(add);
num = addfn(P, add, PN_NUM(3), PN_NUM(5));
num = addfn(P, add, 0, PN_NUM(3), PN_NUM(5));
CuAssertIntEquals(T, "calling closure as c func (jit+default)", 8, PN_INT(num));
num = addfn(P, add, PN_NUM(3));
num = addfn(P, add, 1, PN_NUM(3));
CuAssertIntEquals(T, "default num = 1 (jit)", 4, PN_INT(num));
#endif

Expand Down

0 comments on commit 3b3bf7b

Please sign in to comment.