Skip to content

Commit

Permalink
Move exception raising logic to vm.c.
Browse files Browse the repository at this point in the history
  • Loading branch information
macournoyer committed Apr 8, 2009
1 parent ab3ff29 commit 9737cba
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 68 deletions.
18 changes: 9 additions & 9 deletions test/raise.rb
Expand Up @@ -6,17 +6,17 @@ def deep_in
guacamole
end

begin
# begin
deep_in
puts "oh no boy, ur not coming here!"
rescue RuntimeError
puts $!
puts $@
rescue
puts "nooo!"
ensure
puts "ensured"
end
# rescue RuntimeError
# puts $!
# puts $@
# rescue
# puts "nooo!"
# ensure
# puts "ensured"
# end

# => ouch!
# => test/raise.rb:2:in `guacamole'
Expand Down
39 changes: 2 additions & 37 deletions vm/error.c
Expand Up @@ -52,11 +52,11 @@ static OBJ TrException_message(VM, OBJ self) {
return tr_getivar(self, "@message");
}

static OBJ TrException_backtrace(VM, OBJ self) {
OBJ TrException_backtrace(VM, OBJ self) {
return tr_getivar(self, "@backtrace");
}

static void TrException_default_handler(VM, OBJ exception) {
void TrException_default_handler(VM, OBJ exception) {
TrClass *c = TR_CCLASS(TR_CLASS(exception));
OBJ msg = tr_getivar(exception, "@message");
OBJ backtrace = tr_getivar(exception, "@backtrace");
Expand All @@ -70,41 +70,6 @@ static void TrException_default_handler(VM, OBJ exception) {
exit(1);
}

void TrException_raise(VM, OBJ exception) {
/* Error before VM was started? */
if (vm->cf < 0) TrException_default_handler(vm, exception);

OBJ backtrace = tr_getivar(exception, "@backtrace");
tr_setglobal("$!", exception);
tr_setglobal("$@", backtrace);

/* Unwind the stack frame to browse a rescue handler that can handle the exception.
building the backtrace at the same time. */
TrFrame *f;
while ((f = TrVM_pop_frame(vm))) {
OBJ str;
char *filename = f->filename ? TR_STR_PTR(f->filename) : "?";
if (f->method)
str = tr_sprintf(vm, "\tfrom %s:%lu:in `%s'",
filename, f->line, TR_STR_PTR(TR_CMETHOD(f->method)->name));
else
str = tr_sprintf(vm, "\tfrom %s:%lu",
filename, f->line);
TR_ARRAY_PUSH(backtrace, str);

size_t i;
for (i = 0; i < kv_size(f->rescues); ++i) {
TrRescue *r = &kv_A(f->rescues, i);
/* TODO compare using kind_of or something similar */
if (r->class == TR_CLASS(exception))
longjmp(r->jmp, 1);
}
}

/* not rescued, use default handler */
TrException_default_handler(vm, exception);
}

void TrError_init(VM) {
OBJ c = vm->cException = tr_defclass("Exception", 0);
tr_metadef(c, "exception", TrException_cexception, -1);
Expand Down
2 changes: 1 addition & 1 deletion vm/kernel.c
Expand Up @@ -60,7 +60,7 @@ static OBJ TrKernel_raise(VM, OBJ self, int argc, OBJ argv[]) {
default:
tr_raise(ArgumentError, "wrong number of arguments (%d for 2)", argc);
}
TrException_raise(vm, e);
TrVM_raise(vm, e);
return TR_NIL;
}

Expand Down
18 changes: 8 additions & 10 deletions vm/tr.h
Expand Up @@ -27,7 +27,7 @@
#define TR_CLASS(X) (TR_IMMEDIATE(X) ? vm->classes[TR_TYPE(X)] : TR_COBJECT(X)->class)
#define TR_IS_A(X,T) (TR_TYPE(X) == TR_T_##T)
#define TR_COBJECT(X) ((TrObject*)(X))
#define TR_TYPE_ERROR(T) TrException_raise(vm, TrException_new(vm, vm->cTypeError, TrString_new2(vm, "Expected " #T)))
#define TR_TYPE_ERROR(T) TrVM_raise(vm, TrException_new(vm, vm->cTypeError, TrString_new2(vm, "Expected " #T)))
#define TR_CTYPE(X,T) ((TR_IS_A(X,T) ? 0 : TR_TYPE_ERROR(T)),(Tr##T*)(X))
#define TR_CCLASS(X) ((TR_IS_A(X,Class) || TR_IS_A(X,Module) ? 0 : TR_TYPE_ERROR(T)),(TrClass*)(X))
#define TR_CMODULE(X) TR_CCLASS(X)
Expand Down Expand Up @@ -122,7 +122,7 @@
#define tr_getglobal(N) TR_KH_GET(vm->globals, tr_intern(N))
#define tr_setglobal(N,V) TR_KH_SET(vm->globals, tr_intern(N), V)
#define tr_intern(S) TrSymbol_new(vm, (S))
#define tr_raise(T,M,...) TrException_raise(vm, TrException_new(vm, vm->c##T, tr_sprintf(vm, (M), ##__VA_ARGS__)))
#define tr_raise(T,M,...) TrVM_raise(vm, TrException_new(vm, vm->c##T, tr_sprintf(vm, (M), ##__VA_ARGS__)))
#define tr_raise_errno(M) tr_raise(SystemCallError, "%s: %s", strerror(errno), (M))
#define tr_rescue(B) FRAME->has_rescue_jmp = 1; if (setjmp(FRAME->rescue_jmp)) { B }
#define tr_def(C,N,F,A) TrModule_add_method(vm, (C), tr_intern(N), TrMethod_new(vm, (TrFunc *)(F), TR_NIL, (A)))
Expand Down Expand Up @@ -177,6 +177,8 @@ typedef struct TrBlock {
OBJ filename;
size_t line;
struct TrBlock *parent;
struct TrBlock *rescue;
struct TrBlock *ensure;
/* dynamic */
kvec_t(TrCallSite) sites;
} TrBlock;
Expand All @@ -203,11 +205,6 @@ typedef struct {
int arity;
} TrMethod;

typedef struct TrRescue {
OBJ class;
jmp_buf jmp;
} TrRescue;

typedef struct TrFrame {
TrClosure *closure;
TrMethod *method; /* current called method */
Expand All @@ -217,7 +214,7 @@ typedef struct TrFrame {
OBJ class;
OBJ filename;
size_t line;
kvec_t(TrRescue) rescues;
jmp_buf throw_env;
} TrFrame;

typedef struct {
Expand Down Expand Up @@ -298,7 +295,7 @@ typedef struct {

/* vm */
TrVM *TrVM_new();
TrFrame *TrVM_pop_frame(VM);
void TrVM_raise(VM, OBJ exception);
OBJ TrVM_eval(VM, char *code, char *filename);
OBJ TrVM_load(VM, char *filename);
OBJ TrVM_run(VM, TrBlock *b, OBJ self, OBJ class, int argc, OBJ argv[]);
Expand Down Expand Up @@ -370,7 +367,8 @@ void TrPrimitive_init(VM);

/* error */
OBJ TrException_new(VM, OBJ class, OBJ message);
void TrException_raise(VM, OBJ exception);
OBJ TrException_backtrace(VM, OBJ self);
void TrException_default_handler(VM, OBJ exception);
void TrError_init(VM);

/* compiler */
Expand Down
37 changes: 26 additions & 11 deletions vm/vm.c
Expand Up @@ -14,24 +14,13 @@ static inline void TrFrame_push(VM, OBJ self, OBJ class, TrClosure *closure) {
f->self = self;
f->class = class;
f->closure = closure;
kv_init(f->rescues);
}

static inline void TrFrame_pop(VM) {
register TrFrame *f = FRAME;
/* TODO for GC: release everything on the stack */
if (kv_size(f->rescues)) kv_destroy(f->rescues);
vm->cf--;
}

TrFrame *TrVM_pop_frame(VM) {
if (vm->cf > 0) {
TrFrame_pop(vm);
return FRAME;
}
return 0;
}

static OBJ TrVM_lookup(VM, TrBlock *b, OBJ receiver, OBJ msg, TrInst *ip) {
OBJ method = TrObject_method(vm, receiver, msg);
if (!method) tr_raise(NoMethodError, "Method not found: `%s'", TR_STR_PTR(msg));
Expand Down Expand Up @@ -328,6 +317,32 @@ static OBJ TrVM_interpret(VM, register TrFrame *f, TrBlock *b, int start, int ar
END_OPCODES;
}

void TrVM_raise(VM, OBJ exception) {
/* Error before VM was started? */
if (vm->cf < 0) TrException_default_handler(vm, exception);

OBJ backtrace = TrException_backtrace(vm, exception);
tr_setglobal("$!", exception);
tr_setglobal("$@", backtrace);

TrFrame *f;
TrFrame_pop(vm);
for (f = FRAME; vm->cf >= 0; TrFrame_pop(vm), f = FRAME) {
OBJ str;
char *filename = f->filename ? TR_STR_PTR(f->filename) : "?";
if (f->method)
str = tr_sprintf(vm, "\tfrom %s:%lu:in `%s'",
filename, f->line, TR_STR_PTR(TR_CMETHOD(f->method)->name));
else
str = tr_sprintf(vm, "\tfrom %s:%lu",
filename, f->line);
TR_ARRAY_PUSH(backtrace, str);
}

/* not rescued, use default handler */
TrException_default_handler(vm, exception);
}

OBJ TrVM_eval(VM, char *code, char *filename) {
TrBlock *b = TrBlock_compile(vm, code, filename, 0);
if (vm->debug) TrBlock_dump(vm, b);
Expand Down

0 comments on commit 9737cba

Please sign in to comment.