picrin/src/vm.c

327 lines
6.1 KiB
C
Raw Normal View History

2013-10-12 05:48:35 -04:00
#include <stdio.h>
#include <stdarg.h>
2013-10-11 11:16:19 -04:00
#include "picrin.h"
2013-10-19 23:34:57 -04:00
#include "picrin/pair.h"
2013-10-20 04:06:47 -04:00
#include "picrin/proc.h"
#include "picrin/irep.h"
#define GET_OPERAND(pic,n) ((pic)->sp[-1-(n)])
int
pic_get_args(pic_state *pic, const char *format, ...)
{
char c;
int i = 0, argc = pic->ci->argc - 1;
va_list ap;
bool opt = false;
va_start(ap, format);
while ((c = *format++)) {
switch (c) {
default:
if (argc <= i && ! opt) {
pic_error(pic, "wrong number of arguments");
}
break;
case '|':
break;
}
/* in order to run out of all arguments passed to this function
(i.e. do va_arg for each argument), optional argument existence
check is done in every case closure */
switch (c) {
case '|':
opt = true;
break;
case 'o':
{
pic_value *p;
p = va_arg(ap, pic_value*);
if (i < argc) {
*p = GET_OPERAND(pic,i);
i++;
}
}
break;
2013-10-15 10:25:07 -04:00
case 'f':
{
double *f;
f = va_arg(ap, double *);
if (i < argc) {
*f = pic_float(GET_OPERAND(pic,i));
i++;
}
2013-10-20 22:42:21 -04:00
}
break;
case 's':
{
pic_value str;
char **cstr;
size_t *len;
cstr = va_arg(ap, char **);
len = va_arg(ap, size_t *);
if (i < argc) {
str = GET_OPERAND(pic,i);
*cstr = pic_str_ptr(str)->str;
*len = pic_str_ptr(str)->len;
i++;
}
2013-10-15 10:25:07 -04:00
}
break;
default:
{
pic_error(pic, "pic_get_args: invalid argument specifier given");
}
}
}
if (argc > i) {
pic_error(pic, "wrong number of arguments");
}
va_end(ap);
return i;
}
2013-10-17 00:54:48 -04:00
#if PIC_DIRECT_THREADED_VM
# define VM_LOOP JUMP;
# define CASE(x) L_##x:
# define NEXT ++pc; JUMP;
# define JUMP goto *oplabels[pc->insn];
# define VM_LOOP_END
#else
# define VM_LOOP for (;;) { switch (pc->insn) {
# define CASE(x) case x:
# define NEXT pc++; break
# define JUMP break
# define VM_LOOP_END } }
#endif
2013-10-12 05:48:35 -04:00
#define PUSH(v) (*++pic->sp = (v))
#define POP() (*pic->sp--)
2013-10-19 14:05:42 -04:00
#define POPN(i) ((void)(pic->sp-=i))
#define PUSHCI() (++pic->ci)
#define POPCI() (pic->ci--)
2013-10-15 10:29:34 -04:00
2013-10-12 00:06:02 -04:00
pic_value
pic_run(pic_state *pic, struct pic_proc *proc, pic_value args)
{
struct pic_code *pc;
2013-10-13 04:29:21 -04:00
int ai = pic_gc_arena_preserve(pic);
2013-10-20 10:30:01 -04:00
jmp_buf jmp;
2013-10-12 00:06:02 -04:00
2013-10-17 00:54:48 -04:00
#if PIC_DIRECT_THREADED_VM
static void *oplabels[] = {
&&L_OP_POP, &&L_OP_PUSHNIL, &&L_OP_PUSHTRUE, &&L_OP_PUSHFALSE, &&L_OP_PUSHNUM,
2013-10-20 20:29:56 -04:00
&&L_OP_PUSHCONST, &&L_OP_GREF, &&L_OP_GSET, &&L_OP_LREF, &&L_OP_JMP, &&L_OP_JMPIF,
2013-10-19 14:48:06 -04:00
&&L_OP_CALL, &&L_OP_RET, &&L_OP_LAMBDA, &&L_OP_CONS, &&L_OP_CAR, &&L_OP_CDR,
2013-10-19 14:53:02 -04:00
&&L_OP_NILP, &&L_OP_ADD, &&L_OP_SUB, &&L_OP_MUL, &&L_OP_DIV, &&L_OP_STOP
2013-10-17 00:54:48 -04:00
};
#endif
2013-10-12 00:06:02 -04:00
pc = proc->u.irep->code;
2013-10-15 20:28:58 -04:00
2013-10-20 10:30:01 -04:00
if (setjmp(jmp) == 0) {
pic->jmp = &jmp;
}
else {
goto L_RAISE;
}
/* adjust call frame */
pic->sp[0] = pic_obj_value(proc);
2013-10-17 12:30:35 -04:00
pic->ci->argc = 1;
pic->ci->pc = NULL;
pic->ci->sp = NULL;
2013-10-12 00:06:02 -04:00
2013-10-12 05:48:35 -04:00
VM_LOOP {
CASE(OP_POP) {
2013-10-19 14:05:42 -04:00
POPN(1);
NEXT;
}
2013-10-12 05:48:35 -04:00
CASE(OP_PUSHNIL) {
PUSH(pic_nil_value());
2013-10-16 00:17:01 -04:00
NEXT;
}
CASE(OP_PUSHTRUE) {
PUSH(pic_true_value());
NEXT;
}
CASE(OP_PUSHFALSE) {
PUSH(pic_false_value());
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 00:06:02 -04:00
}
CASE(OP_PUSHNUM) {
PUSH(pic_float_value(pc->u.f));
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 00:06:02 -04:00
}
2013-10-20 20:29:56 -04:00
CASE(OP_PUSHCONST) {
PUSH(pic->pool[pc->u.i]);
NEXT;
}
2013-10-12 05:48:35 -04:00
CASE(OP_GREF) {
PUSH(pic->globals[pc->u.i]);
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 01:40:55 -04:00
}
2013-10-12 05:48:35 -04:00
CASE(OP_GSET) {
pic->globals[pc->u.i] = POP();
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 01:40:55 -04:00
}
2013-10-16 04:20:53 -04:00
CASE(OP_LREF) {
PUSH(pic->ci->sp[pc->u.i]);
2013-10-16 04:20:53 -04:00
NEXT;
}
2013-10-16 04:42:47 -04:00
CASE(OP_JMP) {
pc += pc->u.i;
JUMP;
}
CASE(OP_JMPIF) {
pic_value v;
v = POP();
if (! pic_false_p(v)) {
pc += pc->u.i;
JUMP;
}
NEXT;
}
2013-10-15 06:18:33 -04:00
CASE(OP_CALL) {
2013-10-16 00:24:19 -04:00
pic_value c, v;
pic_callinfo *ci;
2013-10-15 06:18:33 -04:00
struct pic_proc *proc;
c = pic->sp[0];
2013-10-15 06:18:33 -04:00
proc = pic_proc_ptr(c);
2013-10-15 10:29:34 -04:00
ci = PUSHCI();
ci->argc = pc->u.i;
2013-10-16 02:30:52 -04:00
ci->pc = pc;
ci->sp = pic->sp;
2013-10-15 22:28:57 -04:00
if (pic_proc_cfunc_p(c)) {
2013-10-16 00:24:19 -04:00
v = proc->u.cfunc(pic);
2013-10-15 22:28:57 -04:00
pic->sp -= ci->argc;
POPCI();
2013-10-16 00:24:19 -04:00
PUSH(v);
2013-10-16 02:30:52 -04:00
pic_gc_arena_restore(pic, ai);
NEXT;
2013-10-15 22:28:57 -04:00
}
else {
2013-10-16 02:30:52 -04:00
pc = proc->u.irep->code;
pic_gc_arena_restore(pic, ai);
JUMP;
2013-10-15 22:28:57 -04:00
}
2013-10-16 02:30:52 -04:00
}
CASE(OP_RET) {
pic_value v;
pic_callinfo *ci;
2013-10-16 02:30:52 -04:00
2013-10-20 10:30:01 -04:00
if (pic->errmsg) {
2013-10-20 20:29:56 -04:00
L_RAISE:
2013-10-20 10:30:01 -04:00
goto L_STOP;
}
else {
v = POP();
ci = POPCI();
pc = ci->pc;
pic->sp -= ci->argc;
PUSH(v);
}
2013-10-15 22:32:30 -04:00
NEXT;
}
CASE(OP_LAMBDA) {
struct pic_proc *proc;
2013-10-21 04:35:14 -04:00
proc = pic_proc_new(pic, pic->irep[pc->u.i]);
2013-10-15 22:32:30 -04:00
PUSH(pic_obj_value(proc));
pic_gc_arena_restore(pic, ai);
2013-10-15 06:18:33 -04:00
NEXT;
}
2013-10-12 05:48:35 -04:00
CASE(OP_CONS) {
2013-10-12 00:06:02 -04:00
pic_value a, b;
2013-10-13 04:29:21 -04:00
pic_gc_protect(pic, a = POP());
pic_gc_protect(pic, b = POP());
PUSH(pic_cons(pic, a, b));
2013-10-13 04:29:21 -04:00
pic_gc_arena_restore(pic, ai);
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 00:06:02 -04:00
}
2013-10-19 14:48:06 -04:00
CASE(OP_CAR) {
pic_value p;
p = POP();
PUSH(pic_car(pic, p));
NEXT;
}
CASE(OP_CDR) {
pic_value p;
p = POP();
PUSH(pic_cdr(pic, p));
NEXT;
}
2013-10-19 14:53:02 -04:00
CASE(OP_NILP) {
pic_value p;
p = POP();
PUSH(pic_bool_value(pic_nil_p(p)));
NEXT;
}
2013-10-12 05:48:35 -04:00
CASE(OP_ADD) {
2013-10-12 00:06:02 -04:00
pic_value a, b;
a = POP();
b = POP();
PUSH(pic_float_value(pic_float(a) + pic_float(b)));
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 00:06:02 -04:00
}
2013-10-15 08:29:07 -04:00
CASE(OP_SUB) {
pic_value a, b;
a = POP();
b = POP();
PUSH(pic_float_value(pic_float(a) - pic_float(b)));
NEXT;
}
CASE(OP_MUL) {
pic_value a, b;
a = POP();
b = POP();
PUSH(pic_float_value(pic_float(a) * pic_float(b)));
NEXT;
}
CASE(OP_DIV) {
pic_value a, b;
a = POP();
b = POP();
PUSH(pic_float_value(pic_float(a) / pic_float(b)));
NEXT;
}
2013-10-12 05:48:35 -04:00
CASE(OP_STOP) {
2013-10-20 04:26:18 -04:00
pic_value val;
2013-10-12 00:06:02 -04:00
2013-10-20 10:30:01 -04:00
L_STOP:
2013-10-20 04:26:18 -04:00
val = POP();
2013-10-16 02:30:52 -04:00
2013-10-20 10:30:01 -04:00
pic->jmp = NULL;
if (pic->errmsg) {
return pic_undef_value();
}
2013-10-20 00:07:14 -04:00
#if VM_DEBUG
2013-10-20 04:26:18 -04:00
puts("**VM END STATE**");
printf("stbase = %p\nsp = %p\n", pic->stbase, pic->sp);
printf("cibase = %p\nci = %p\n", pic->cibase, pic->ci);
if (pic->stbase != pic->sp) {
pic_value *sp;
printf("* stack trace:");
for (sp = pic->stbase; pic->sp != sp; ++sp) {
pic_debug(pic, *sp);
puts("");
}
}
2013-10-16 02:30:52 -04:00
#endif
2013-10-20 04:26:18 -04:00
return val;
}
} VM_LOOP_END;
2013-10-12 01:40:27 -04:00
}