Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' into raise

* master:
  Store call frames as a linked list and stack on the C stack.

Conflicts:

	vm/call.h
	vm/vm.c
  • Loading branch information...
commit aef99621b7c8d569fc2cb02cfdbda4e1ad00889e 2 parents e5c97e0 + a4658fb
@macournoyer authored
View
7 test/ivar.rb
@@ -0,0 +1,7 @@
+@a = 1
+puts @a
+# => 1
+
+@a = 2
+puts @a
+# => 2
View
104 vm/call.h
@@ -1,62 +1,64 @@
/* Inlined functions frequently used in the method calling process. */
-inline void TrFrame_push(VM, OBJ self, OBJ class, TrClosure *closure) {
- register int cf = ++vm->cf;
- if (cf >= TR_MAX_FRAMES) tr_raise(SystemStackError, "Stack overflow");
- register TrFrame *f = FRAME;
- f->self = self;
- f->class = class;
- f->closure = closure;
-}
+#include <alloca.h>
-inline void TrFrame_pop(VM) {
- /* TODO for GC: release everything on the stack */
- vm->cf--;
-}
+#define TR_WITH_FRAME(SELF,CLASS,CLOS,BODY) ({ \
+ /* push a frame */ \
+ if (unlikely(++vm->cf >= TR_MAX_FRAMES)) tr_raise(SystemStackError, "Stack overflow"); \
+ TrFrame __f; \
+ register TrFrame *__fp = &__f; \
+ __f.previous = vm->frame; \
+ if (vm->cf == 0) vm->top_frame = __fp; \
+ vm->frame = __fp; \
+ __f.self = SELF; \
+ __f.class = CLASS; \
+ __f.closure = CLOS; \
+ /* execute BODY inside the frame */ \
+ BODY \
+ /* pop the frame */ \
+ vm->cf--; \
+ vm->frame = vm->frame->previous; \
+})
-inline OBJ TrMethod_call(VM, OBJ self, OBJ receiver, int argc, OBJ *args, int splat, TrClosure *cl) {
- /* prepare call frame */
- TrFrame_push(vm, receiver, TR_CLASS(receiver), cl);
- TrFrame *f = FRAME;
- TrMethod *m = f->method = TR_CMETHOD(self);
- TrFunc *func = f->method->func;
+static inline OBJ TrMethod_call(VM, OBJ self, OBJ receiver, int argc, OBJ *args, int splat, TrClosure *cl) {
OBJ ret = TR_NIL;
+ TrFrame *f = 0;
+ TR_WITH_FRAME(receiver, TR_CLASS(receiver), cl, {
+ f = vm->frame;
+ TrMethod *m = f->method = TR_CMETHOD(self);
+ TrFunc *func = f->method->func;
- /* splat last arg is needed */
- if (unlikely(splat)) {
- OBJ splated = args[argc-1];
- int splatedn = TR_ARRAY_SIZE(splated);
- OBJ *new_args = TR_ALLOC_N(OBJ, argc);
- TR_MEMCPY_N(new_args, args, OBJ, argc-1);
- TR_MEMCPY_N(new_args + argc-1, &TR_ARRAY_AT(splated, 0), OBJ, splatedn);
- argc += splatedn-1;
- args = new_args;
- }
-
- /* printf("call %s in frame %d\n", TR_STR_PTR(m->name), vm->cf); */
-
- /* calls the C function */
- if (m->arity == -1) {
- ret = func(vm, receiver, argc, args);
- } else {
- if (m->arity != argc) tr_raise(ArgumentError, "Expected %d arguments, got %d.", f->method->arity, argc);
- switch (argc) {
- case 0: ret = func(vm, receiver); break;
- case 1: ret = func(vm, receiver, args[0]); break;
- case 2: ret = func(vm, receiver, args[0], args[1]); break;
- case 3: ret = func(vm, receiver, args[0], args[1], args[2]); break;
- case 4: ret = func(vm, receiver, args[0], args[1], args[2], args[3]); break;
- case 5: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4]); break;
- case 6: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5]); break;
- case 7: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break;
- case 8: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break;
- case 9: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break;
- case 10: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); break;
- default: tr_raise(ArgumentError, "Too much arguments: %d, max is %d for now.", argc, 10);
+ /* splat last arg is needed */
+ if (unlikely(splat)) {
+ OBJ splated = args[argc-1];
+ int splatedn = TR_ARRAY_SIZE(splated);
+ OBJ *new_args = TR_ALLOC_N(OBJ, argc);
+ TR_MEMCPY_N(new_args, args, OBJ, argc-1);
+ TR_MEMCPY_N(new_args + argc-1, &TR_ARRAY_AT(splated, 0), OBJ, splatedn);
+ argc += splatedn-1;
+ args = new_args;
}
- }
- TrFrame_pop(vm);
+ if (m->arity == -1) {
+ ret = func(vm, receiver, argc, args);
+ } else {
+ if (m->arity != argc) tr_raise(ArgumentError, "Expected %d arguments, got %d.", f->method->arity, argc);
+ switch (argc) {
+ case 0: ret = func(vm, receiver); break;
+ case 1: ret = func(vm, receiver, args[0]); break;
+ case 2: ret = func(vm, receiver, args[0], args[1]); break;
+ case 3: ret = func(vm, receiver, args[0], args[1], args[2]); break;
+ case 4: ret = func(vm, receiver, args[0], args[1], args[2], args[3]); break;
+ case 5: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4]); break;
+ case 6: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5]); break;
+ case 7: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break;
+ case 8: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break;
+ case 9: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break;
+ case 10: ret = func(vm, receiver, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); break;
+ default: tr_raise(ArgumentError, "Too much arguments: %d, max is %d for now.", argc, 10);
+ }
+ }
+ });
/* handle throw if some */
if (unlikely(ret == TR_UNDEF)) {
View
6 vm/error.c
@@ -34,7 +34,7 @@
OBJ TrException_new(VM, OBJ class, OBJ message) {
OBJ e = TrObject_alloc(vm, class);
tr_setivar(e, "@message", message);
- tr_setivar(e, "@backtrace", TrArray_new(vm));
+ tr_setivar(e, "@backtrace", TR_NIL);
return (OBJ)e;
}
@@ -56,6 +56,10 @@ OBJ TrException_backtrace(VM, OBJ self) {
return tr_getivar(self, "@backtrace");
}
+OBJ TrException_set_backtrace(VM, OBJ self, OBJ backtrace) {
+ return tr_setivar(self, "@backtrace", backtrace);
+}
+
void TrException_default_handler(VM, OBJ exception) {
TrClass *c = TR_CCLASS(TR_CLASS(exception));
OBJ msg = tr_getivar(exception, "@message");
View
4 vm/kernel.c
@@ -20,7 +20,7 @@ static OBJ TrKernel_puts(VM, OBJ self, int argc, OBJ argv[]) {
static OBJ TrKernel_binding(VM, OBJ self) {
UNUSED(self);
- return TrBinding_new(vm, PREV_FRAME);
+ return TrBinding_new(vm, vm->frame->previous);
}
static OBJ TrKernel_eval(VM, OBJ self, int argc, OBJ argv[]) {
@@ -28,7 +28,7 @@ static OBJ TrKernel_eval(VM, OBJ self, int argc, OBJ argv[]) {
if (argc < 1) tr_raise(ArgumentError, "string argument required");
if (argc > 4) tr_raise(ArgumentError, "Too much arguments");
OBJ string = argv[0];
- TrFrame *f = (argc > 1 && argv[1]) ? TR_CBINDING(argv[1])->frame : FRAME;
+ TrFrame *f = (argc > 1 && argv[1]) ? TR_CBINDING(argv[1])->frame : vm->frame;
char *filename = (argc > 2 && argv[1]) ? TR_STR_PTR(argv[2]) : "<eval>";
size_t lineno = argc > 3 ? TR_FIX2INT(argv[3]) : 0;
TrBlock *blk = TrBlock_compile(vm, TR_STR_PTR(string), filename, lineno);
View
6 vm/string.c
@@ -1,3 +1,4 @@
+#include <alloca.h>
#include <stdarg.h>
#include <stdio.h>
#include "tr.h"
@@ -124,14 +125,11 @@ OBJ tr_sprintf(VM, const char *fmt, ...) {
va_list arg;
va_start(arg, fmt);
int len = vsnprintf(NULL, 0, fmt, arg);
- /* HACK causes Bus error in Bohem GC */
- /* char *ptr = TR_ALLOC_N(char, len); */
- char ptr[4096]; assert(len < 4096);
+ char *ptr = alloca(sizeof(char) * len);
va_end(arg);
va_start(arg, fmt);
vsprintf(ptr, fmt, arg);
va_end(arg);
- /* TODO do not allocate twice */
OBJ str = TrString_new(vm, ptr, len);
TR_FREE(ptr);
return str;
View
12 vm/tr.h
@@ -70,7 +70,6 @@
khash_t(OBJ) *kh = (KH); \
int ret; \
khiter_t k = kh_put(OBJ, kh, key, &ret); \
- if (!ret) kh_del(OBJ, kh, k); \
kh_value(kh, k) = (V); \
})
#define TR_KH_EACH(H,I,V,B) ({ \
@@ -84,8 +83,6 @@
/* vm macros */
#define VM struct TrVM *vm
-#define FRAME (&vm->frames[vm->cf])
-#define PREV_FRAME (&vm->frames[vm->cf-1])
#define TR_THROW(R,V) ({ \
vm->throw_reason = TR_THROW_##R; \
@@ -218,12 +215,13 @@ typedef struct {
typedef struct TrFrame {
TrClosure *closure;
TrMethod *method; /* current called method */
- OBJ stack[255]; /* TODO allocate dynamically to use less mem */
+ OBJ *stack;
OBJ *upvals;
OBJ self;
OBJ class;
OBJ filename;
size_t line;
+ struct TrFrame *previous;
} TrFrame;
typedef struct {
@@ -236,8 +234,9 @@ typedef struct TrVM {
khash_t(OBJ) *globals;
khash_t(OBJ) *consts; /* TODO this goes in modules */
OBJ classes[TR_T_MAX]; /* core classes */
- TrFrame frames[TR_MAX_FRAMES]; /* TODO allocate dynamically to use less mem */
- int cf; /* current frame */
+ TrFrame *top_frame; /* top level frame */
+ TrFrame *frame; /* current frame */
+ int cf; /* current frame number */
OBJ self; /* root object */
int debug;
int throw_reason;
@@ -388,6 +387,7 @@ void TrPrimitive_init(VM);
/* error */
OBJ TrException_new(VM, OBJ class, OBJ message);
OBJ TrException_backtrace(VM, OBJ self);
+OBJ TrException_set_backtrace(VM, OBJ self, OBJ backtrace);
void TrException_default_handler(VM, OBJ exception);
void TrError_init(VM);
View
74 vm/vm.c
@@ -31,49 +31,49 @@ static OBJ TrVM_lookup(VM, TrBlock *b, OBJ receiver, OBJ msg, TrInst *ip) {
}
static OBJ TrVM_defclass(VM, OBJ name, TrBlock *b, int module, OBJ super) {
- OBJ mod = TrObject_const_get(vm, FRAME->class, name);
+ OBJ mod = TrObject_const_get(vm, vm->frame->class, name);
if (!mod) { /* new module/class */
if (module)
mod = TrModule_new(vm, name);
else
mod = TrClass_new(vm, name, super ? super : TR_CORE_CLASS(Object));
- TrObject_const_set(vm, FRAME->class, name, mod);
+ TrObject_const_set(vm, vm->frame->class, name, mod);
}
- TrFrame_push(vm, mod, mod, 0);
- TrVM_interpret(vm, FRAME, b, 0, 0, 0, 0);
- TrFrame_pop(vm);
+ TR_WITH_FRAME(mod, mod, 0, {
+ TrVM_interpret(vm, vm->frame, b, 0, 0, 0, 0);
+ });
return mod;
}
static OBJ TrVM_interpret_method(VM, OBJ self, int argc, OBJ argv[]) {
UNUSED(self);
- assert(FRAME->method);
- register TrBlock *b = (TrBlock *)TR_CMETHOD(FRAME->method)->data;
+ assert(vm->frame->method);
+ register TrBlock *b = (TrBlock *)TR_CMETHOD(vm->frame->method)->data;
if (unlikely(argc != (int)b->argc)) tr_raise(ArgumentError, "wrong number of arguments (%d for %lu)", argc, b->argc);
- return TrVM_interpret(vm, FRAME, b, 0, argc, argv, 0);
+ return TrVM_interpret(vm, vm->frame, b, 0, argc, argv, 0);
}
static OBJ TrVM_interpret_method_with_defaults(VM, OBJ self, int argc, OBJ argv[]) {
UNUSED(self);
- assert(FRAME->method);
- register TrBlock *b = (TrBlock *)TR_CMETHOD(FRAME->method)->data;
+ assert(vm->frame->method);
+ register TrBlock *b = (TrBlock *)TR_CMETHOD(vm->frame->method)->data;
int req_argc = b->argc - kv_size(b->defaults);
if (argc < req_argc) tr_raise(ArgumentError, "wrong number of arguments (%d for %d)", argc, req_argc);
if (argc > (int)b->argc) tr_raise(ArgumentError, "wrong number of arguments (%d for %lu)", argc, b->argc);
int defi = argc - req_argc - 1; /* index in defaults table or -1 for none */
- return TrVM_interpret(vm, FRAME, b, defi < 0 ? 0 : kv_A(b->defaults, defi), argc, argv, 0);
+ return TrVM_interpret(vm, vm->frame, b, defi < 0 ? 0 : kv_A(b->defaults, defi), argc, argv, 0);
}
static OBJ TrVM_interpret_method_with_splat(VM, OBJ self, int argc, OBJ argv[]) {
UNUSED(self);
- assert(FRAME->method);
- register TrBlock *b = (TrBlock *)TR_CMETHOD(FRAME->method)->data;
+ assert(vm->frame->method);
+ register TrBlock *b = (TrBlock *)TR_CMETHOD(vm->frame->method)->data;
/* TODO support defaults */
assert(kv_size(b->defaults) == 0 && "defaults with splat not supported for now");
if (argc < (int)b->argc-1) tr_raise(ArgumentError, "wrong number of arguments (%d for %lu)", argc, b->argc-1);
argv[b->argc-1] = TrArray_new3(vm, argc - b->argc + 1, &argv[b->argc-1]);
- return TrVM_interpret(vm, FRAME, b, 0, b->argc, argv, 0);
+ return TrVM_interpret(vm, vm->frame, b, 0, b->argc, argv, 0);
}
static OBJ TrVM_defmethod(VM, TrFrame *f, OBJ name, TrBlock *b, int meta, OBJ receiver) {
@@ -95,9 +95,10 @@ static OBJ TrVM_defmethod(VM, TrFrame *f, OBJ name, TrBlock *b, int meta, OBJ re
static inline OBJ TrVM_yield(VM, TrFrame *f, int argc, OBJ argv[]) {
TrClosure *cl = f->closure;
if (!cl) tr_raise(LocalJumpError, "no block given");
- TrFrame_push(vm, cl->self, cl->class, cl->parent);
- OBJ ret = TrVM_interpret(vm, FRAME, cl->block, 0, argc, argv, cl);
- TrFrame_pop(vm);
+ OBJ ret = TR_NIL;
+ TR_WITH_FRAME(cl->self, cl->class, cl->parent, {
+ ret = TrVM_interpret(vm, vm->frame, cl->block, 0, argc, argv, cl);
+ });
return ret;
}
@@ -129,6 +130,7 @@ static inline OBJ TrVM_yield(VM, TrFrame *f, int argc, OBJ argv[]) {
#define SITE (b->sites.a)
static OBJ TrVM_interpret(VM, register TrFrame *f, TrBlock *b, int start, int argc, OBJ argv[], TrClosure *closure) {
+ f->stack = alloca(sizeof(OBJ) * b->regc);
#if TR_USE_MACHINE_REGS && __i386__
register TrInst *ip __asm__ ("esi") = b->code.a + start;
register OBJ *stack __asm__ ("edi") = f->stack;
@@ -169,13 +171,17 @@ static OBJ TrVM_interpret(VM, register TrFrame *f, TrBlock *b, int start, int ar
OP(NEWRANGE): R[A] = TrRange_new(vm, R[A], R[B], C); DISPATCH;
/* return */
- OP(LEAVE): return R[A];
+ OP(LEAVE):
+ /* TODO for GC: release everything on the stack before returning */
+ return R[A];
OP(RETURN):
+ /* TODO for GC: release everything on the stack before returning */
if (unlikely(closure))
TR_THROW(RETURN, R[A]);
else
return R[A];
OP(BREAK):
+ /* TODO for GC: release everything on the stack before returning */
if (likely(closure))
TR_THROW(BREAK, TR_NIL);
else
@@ -273,17 +279,15 @@ static OBJ TrVM_interpret(VM, register TrFrame *f, TrBlock *b, int start, int ar
END_OPCODES;
}
-void TrVM_raise(VM, OBJ exception) {
- /* Short-circuit when error before VM was started */
- if (vm->cf < 0) TrException_default_handler(vm, exception);
+/* returns the backtrace of the current call frames */
+static OBJ TrVM_backtrace(VM) {
+ OBJ backtrace = TrArray_new(vm);
- OBJ backtrace = TrException_backtrace(vm, exception);
- tr_setglobal("$!", exception);
- tr_setglobal("$@", backtrace);
+ if (!vm->frame) return backtrace;
- TrFrame *f;
- TrFrame_pop(vm);
- for (f = FRAME; vm->cf >= 0; TrFrame_pop(vm), f = FRAME) {
+ /* skip a frame since it's the one doing the raising */
+ TrFrame *f = vm->frame->previous;
+ while (f) {
OBJ str;
char *filename = f->filename ? TR_STR_PTR(f->filename) : "?";
if (f->method)
@@ -294,10 +298,15 @@ void TrVM_raise(VM, OBJ exception) {
filename, f->line);
TR_ARRAY_PUSH(backtrace, str);
- /* TODO run rescue and ensure blocks */
+ f = f->previous;
}
- /* not rescued, use default handler */
+ return backtrace;
+}
+
+void TrVM_raise(VM, OBJ exception) {
+ /* TODO unwind the frames */
+ TrException_set_backtrace(vm, exception, TrVM_backtrace(vm));
TrException_default_handler(vm, exception);
}
@@ -324,9 +333,10 @@ OBJ TrVM_load(VM, char *filename) {
}
OBJ TrVM_run(VM, TrBlock *b, OBJ self, OBJ class, int argc, OBJ argv[]) {
- TrFrame_push(vm, self, class, 0);
- OBJ ret = TrVM_interpret(vm, FRAME, b, 0, argc, argv, 0);
- TrFrame_pop(vm);
+ OBJ ret = TR_NIL;
+ TR_WITH_FRAME(self, class, 0, {
+ ret = TrVM_interpret(vm, vm->frame, b, 0, argc, argv, 0);
+ });
return ret;
}
Please sign in to comment.
Something went wrong with that request. Please try again.