summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--vm.c73
1 files changed, 58 insertions, 15 deletions
diff --git a/vm.c b/vm.c
index 9322cba8..8664b804 100644
--- a/vm.c
+++ b/vm.c
@@ -545,28 +545,71 @@ NOINLINE static void vm_gcall(struct vm *vm, vm_word_t insn)
unsigned nargs = vm_insn_extra(insn);
unsigned dest = vm_insn_operand(insn);
vm_word_t argw = vm->code[vm->ip++];
- unsigned fun = vm_arg_operand_lo(argw);
+ unsigned funidx = vm_arg_operand_lo(argw);
+ val fun = deref(vm_stab(vm, funidx, lookup_fun, lit("function")));
val result;
- args_decl (args, max(nargs, ARGS_MIN));
-
- if (nargs--) {
- args_add(args, vm_getz(vm->dspl, vm_arg_operand_hi(argw)));
- while (nargs >= 2) {
- nargs -= 2;
- argw = vm->code[vm->ip++];
- args_add(args, vm_getz(vm->dspl, vm_arg_operand_lo(argw)));
- args_add(args, vm_getz(vm->dspl, vm_arg_operand_hi(argw)));
+ switch (nargs) {
+ case 0:
+ result = funcall(fun);
+ break;
+ case 1:
+ {
+ val arg1 = vm_getz(vm->dspl, vm_arg_operand_hi(argw));
+ result = funcall1(fun, z(arg1));
+ }
+ break;
+ case 2:
+ {
+ vm_word_t argx = vm->code[vm->ip++];
+ val arg1 = vm_getz(vm->dspl, vm_arg_operand_hi(argw));
+ val arg2 = vm_getz(vm->dspl, vm_arg_operand_lo(argx));
+ result = funcall2(fun, z(arg1), z(arg2));
}
+ break;
+ case 3:
+ {
+ vm_word_t argx = vm->code[vm->ip++];
+ val arg1 = vm_getz(vm->dspl, vm_arg_operand_hi(argw));
+ val arg2 = vm_getz(vm->dspl, vm_arg_operand_lo(argx));
+ val arg3 = vm_getz(vm->dspl, vm_arg_operand_hi(argx));
+ result = funcall3(fun, z(arg1), z(arg2), z(arg3));
+ }
+ break;
+ case 4:
+ {
+ vm_word_t argx = vm->code[vm->ip++];
+ vm_word_t argy = vm->code[vm->ip++];
+ val arg1 = vm_getz(vm->dspl, vm_arg_operand_hi(argw));
+ val arg2 = vm_getz(vm->dspl, vm_arg_operand_lo(argx));
+ val arg3 = vm_getz(vm->dspl, vm_arg_operand_hi(argx));
+ val arg4 = vm_getz(vm->dspl, vm_arg_operand_lo(argy));
+ result = funcall4(fun, z(arg1), z(arg2), z(arg3), z(arg4));
+ }
+ break;
+ default:
+ {
+ args_decl (args, max(nargs, ARGS_MIN));
+ args_add(args, vm_getz(vm->dspl, vm_arg_operand_hi(argw)));
+ nargs--;
- if (nargs) {
- argw = vm->code[vm->ip++];
- args_add(args, vm_getz(vm->dspl, vm_arg_operand_lo(argw)));
+ while (nargs >= 2) {
+ nargs -= 2;
+ argw = vm->code[vm->ip++];
+ args_add(args, vm_getz(vm->dspl, vm_arg_operand_lo(argw)));
+ args_add(args, vm_getz(vm->dspl, vm_arg_operand_hi(argw)));
+ }
+
+ if (nargs) {
+ argw = vm->code[vm->ip++];
+ args_add(args, vm_getz(vm->dspl, vm_arg_operand_lo(argw)));
+ }
+
+ result = generic_funcall(fun, args);
}
+ break;
}
- result = generic_funcall(deref(vm_stab(vm, fun, lookup_fun,
- lit("function"))), args);
vm_set(vm->dspl, dest, result);
}