Fn call: move arity check into interpret loop, which avoid the expensive if after the call, since runtime errors originating inside the call itself will still be handled, we only have the one emitted from call itself.

This brings the benchmark back up to where it was.
This commit is contained in:
ruby0x1
2020-09-18 15:42:37 -07:00
parent beae242a41
commit 45c67fae0c
3 changed files with 23 additions and 8 deletions

View File

@ -248,13 +248,6 @@ DEF_PRIMITIVE(fn_arity)
static void call_fn(WrenVM* vm, Value* args, int numArgs)
{
// We only care about missing arguments, not extras.
if (AS_CLOSURE(args[0])->fn->arity > numArgs)
{
vm->fiber->error = CONST_STRING(vm, "Function expects more arguments.");
return;
}
// +1 to include the function itself.
wrenCallFunction(vm, vm->fiber, AS_CLOSURE(args[0]), numArgs + 1);
}

View File

@ -774,6 +774,21 @@ static Value getModuleVariable(WrenVM* vm, ObjModule* module,
return NULL_VAL;
}
inline static bool checkArity(WrenVM* vm, Value value, int numArgs)
{
ASSERT(IS_CLOSURE(value), "Receiver must be a closure.");
ObjFn* fn = AS_CLOSURE(value)->fn;
// We only care about missing arguments, not extras. The "- 1" is because
// numArgs includes the receiver, the function itself, which we don't want to
// count.
if (numArgs - 1 >= fn->arity) return true;
vm->fiber->error = CONST_STRING(vm, "Function expects more arguments.");
return false;
}
// The main bytecode interpreter loop. This is where the magic happens. It is
// also, as you can imagine, highly performance critical.
static WrenInterpretResult runInterpreter(WrenVM* vm, register ObjFiber* fiber)
@ -1016,9 +1031,13 @@ static WrenInterpretResult runInterpreter(WrenVM* vm, register ObjFiber* fiber)
break;
case METHOD_FUNCTION_CALL:
if (!checkArity(vm, args[0], numArgs)) {
RUNTIME_ERROR();
break;
}
STORE_FRAME();
method->as.primitive(vm, args);
if (wrenHasError(fiber)) RUNTIME_ERROR();
LOAD_FRAME();
break;

View File

@ -0,0 +1,3 @@
var f1 = Fn.new {|a, b| a + b } // expect runtime error: Bool does not implement '+(_)'.
f1.call(true, false)