SLVAL sl_vm_exec(sl_vm_exec_ctx_t* ctx, size_t ip) { int line = 0; sl_vm_t* vm = ctx->vm; sl_vm_exception_handler_t* volatile exception_handler = NULL; sl_vm_section_t* section = ctx->section; sl_vm_frame_t catch_frame; sl_vm_frame_t call_frame; call_frame.prev = vm->call_stack; call_frame.frame_type = SL_VM_FRAME_SLASH; call_frame.as.call_frame.method = section->name; call_frame.as.call_frame.filename = (char*)section->filename; call_frame.as.call_frame.line = (int*)&line; vm->call_stack = &call_frame; if(ctx->section->has_try_catch) { catch_frame.frame_type = SL_VM_FRAME_HANDLER; catch_frame.as.handler_frame.value = vm->lib.nil; reset_exception_handler: catch_frame.prev = vm->call_stack; vm->call_stack = &catch_frame; if(sl_setjmp(catch_frame.as.handler_frame.env)) { vm->call_stack = catch_frame.prev; if(exception_handler && (catch_frame.as.handler_frame.unwind_type & SL_UNWIND_EXCEPTION)) { ip = exception_handler->catch_ip; goto reset_exception_handler; } else { vm->call_stack = call_frame.prev; sl_unwind(vm, catch_frame.as.handler_frame.value, catch_frame.as.handler_frame.unwind_type); } } } while(1) { switch(NEXT().opcode) { #undef INSTRUCTION #define INSTRUCTION(opcode, code) \ case opcode: { \ code; \ } break; #include "vm_defn.inc" default: sl_throw_message(vm, "BUG: Unknown opcode in VM"); /* never reached */ } } }
static SLVAL call_c_func(sl_vm_t* vm, SLVAL recv, sl_method_t* method, size_t argc, SLVAL* argv) { if(method->arity < 0) { return method->as.c.func(vm, recv, argc, argv); } else { switch(method->arity) { case 0: return method->as.c.func(vm, recv); case 1: return method->as.c.func(vm, recv, argv[0]); case 2: return method->as.c.func(vm, recv, argv[0], argv[1]); case 3: return method->as.c.func(vm, recv, argv[0], argv[1], argv[2]); case 4: return method->as.c.func(vm, recv, argv[0], argv[1], argv[2], argv[3]); default: sl_throw_message(vm, "Too many arguments for C function"); } } return vm->lib.nil; /* never reached */ }
SLVAL sl_imc_setup_call(sl_vm_t* vm, sl_vm_inline_method_cache_t* imc, SLVAL recv, SLVAL* argv) { SLVAL klass = SL_IS_INT(recv) ? vm->lib.Int : sl_get_ptr(recv)->klass; sl_method_t* method = lookup_method_rec(vm, klass, imc->id); if(method) { imc->state = vm->state_method; imc->klass = klass; imc->method = method; if(method->base.user_flags & SL_FLAG_METHOD_IS_C_FUNC) { if(method->arity < 0) { if(sl_likely(-imc->argc - 1 <= method->arity)) { imc->call = dispatch_c_call_variadic; } else { imc->call = sl_imc_cached_call; // cop out } } else { if(sl_likely(imc->argc == method->arity)) { switch(method->arity) { case 0: imc->call = dispatch_c_call_0; break; case 1: imc->call = dispatch_c_call_1; break; case 2: imc->call = dispatch_c_call_2; break; case 3: imc->call = dispatch_c_call_3; break; case 4: imc->call = dispatch_c_call_4; break; default: sl_throw_message(vm, "Too many arguments for C function"); } } else { imc->call = sl_imc_cached_call; // cop out } } } else { if(method->arity >= 0 && imc->argc >= method->arity && method->as.sl.section->can_stack_alloc_frame && !method->as.sl.section->opt_skip) { imc->call = dispatch_slash_call_stack_regs; } else { imc->call = sl_imc_cached_call; // cop out } } return imc->call(vm, imc, recv, argv); } else { return sl_send_missing(vm, recv, imc->id, imc->argc, argv); } }