| I continued the work on this and got some good results. I integrated 3.x function loading into the 4.x loaders such that the loaders will find and load 3x functions with lower precedence than 4.x functions as before, but now per module only - thus a module with both 3.x and 4.x can no longer have its 3x functions overridden by 4.x functions in modules coming after it on the module path. With the new approach the 3.x functions are still loaded the old way to allow code that calls scope.function_xxx to work as before. (The actual 3x loading code is unchanged to reduce risk). Instead, the 4.x loader creates a wrapper 4.x function that delegates the call using the scope.function_xxx calling convention (again to reduce risk). I also included the rewrite of returned values from 3.x functions to remove the problem of returning 4.x runtime incompatible :undef instead of nil (this is a separate ticket as well). Needed to do this in the new wrapper since the calling side does not know this needs to be done. First run of benchmarking this (10 iterations on my machine) showed promising results as the baseline was 16.05s before the change and 15.64s after (both single runs, but still indicative of a possible wash in terms of performance). There may be an opportunity to shave a little more off since a 3.x function is actually two methods; one dispatcher (the function_xxx method) that checks the argument constraints and raises errors, and the actual function (the real_function_xxx method). Since the 4x function wrapper also checks arguments it may be possible to short circuit one level of indirection per call. Impact of this is probably small in this particular benchmark. Work remains to write tests for this before putting up a PR. |