picrin/src/vm.c

292 lines
5.5 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"
2013-10-20 22:42:21 -04:00
#include "picrin/string.h"
void
pic_get_args(pic_state *pic, const char *format, ...)
{
char c;
int i = -1;
va_list ap;
va_start(ap, format);
while ((c = *format++)) {
switch (c) {
case 'o':
{
pic_value *p;
p = va_arg(ap, pic_value*);
2013-10-20 22:42:21 -04:00
*p = pic->sp[i--];
}
break;
2013-10-15 10:25:07 -04:00
case 'f':
{
double *f;
f = va_arg(ap, double *);
2013-10-20 22:42:21 -04:00
*f = pic_float(pic->sp[i--]);
}
break;
case 's':
{
pic_value str;
char **cstr;
size_t *len;
cstr = va_arg(ap, char **);
len = va_arg(ap, size_t *);
str = pic->sp[i--];
*cstr = pic_str_ptr(str)->str;
*len = pic_str_ptr(str)->len;
2013-10-15 10:25:07 -04:00
}
break;
}
}
}
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;
proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc *), PIC_TT_PROC);
proc->cfunc_p = false;
proc->u.irep = 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
}