Always wrap functions in closures.

This has a couple of pros:

- It simplifies some code that used to have to check whether a called
  thing is a bare function or a closure.
- It's faster because we don't need to do the above checks every time
  something is called.
- It lets us more precisely type some fields that used to be Obj*
  because they could hold an ObjClosure* or ObjFn*.

The cost is that we allocate a closure every time a function is
declared, even if it has no upvalues. Since functions are called way
more often than they are declared, this is still a net win.

On my Mac laptop:

api_call - wren            0.06s 0.0020 104.73%
api_foreign_method - wren  0.32s 0.0040 101.89%
binary_trees - wren        0.23s 0.0057  98.82%
binary_trees_gc - wren     0.79s 0.0170  98.46%
delta_blue - wren          0.13s 0.0031 101.36%
fib - wren                 0.23s 0.0038 103.15%
fibers - wren              0.04s 0.0017  98.97%
for - wren                 0.08s 0.0017 107.81%
method_call - wren         0.12s 0.0024  98.60%
map_numeric - wren         0.31s 0.0052 103.93%
map_string - wren          0.11s 0.0113  97.97%
string_equals - wren       0.20s 0.0023 107.75%
This commit is contained in:
Bob Nystrom
2016-03-26 14:00:17 -07:00
parent a5f95b90e9
commit 6dc4286ffa
8 changed files with 149 additions and 168 deletions
+12 -5
View File
@@ -12,17 +12,24 @@ void metaCompile(WrenVM* vm)
// Evaluate the code in the module where the calling function was defined.
// That's one stack frame back from the top since the top-most frame is the
// helper eval() method in Meta itself.
Value callingFn = OBJ_VAL(vm->fiber->frames[vm->fiber->numFrames - 2].fn);
ObjModule* module = IS_FN(callingFn)
? AS_FN(callingFn)->module
: AS_CLOSURE(callingFn)->fn->module;
ObjClosure* caller = vm->fiber->frames[vm->fiber->numFrames - 2].closure;
ObjModule* module = caller->fn->module;
// Compile it.
ObjFn* fn = wrenCompile(vm, module, wrenGetSlotString(vm, 1), false);
// Return the result. We can't use the public API for this since we have a
// bare ObjFn.
vm->apiStack[0] = fn != NULL ? OBJ_VAL(fn) : NULL_VAL;
if (fn == NULL)
{
vm->apiStack[0] = NULL_VAL;
}
else
{
wrenPushRoot(vm, (Obj*)fn);
vm->apiStack[0] = OBJ_VAL(wrenNewClosure(vm, fn));
wrenPopRoot(vm);
}
}
const char* wrenMetaSource()