I have a question about Vladimir's proposal upthread (from Aug 30) for passing implicit mv arrays. The idea is to pass MV by setting FOO.MV before calling FOO, and to read MV passed to oneself as ARGUMENTS.CALLEE.MV.
As we've been discussing, correct MVR must: (1) enable passthrough where it's wanted, and (2) suppress passthrough where it's not wanted. This proposal gets (1) by instrumenting code to pass MV everywhere it might be needed, and (2) by simply not instrumenting where it isn't wanted [*]. Here's Vladimir's original example (with comment edited):
(defun foo (x y z) (values x y z))
(defun bar () (foo) (foo))
function bar () { foo(); // no instrumentation since passthrough is not wanted foo.mv = arguments.callee.mv; var result = foo(); delete foo.mv; return result; }
But passthrough is transitive, so we can't just instrument tail calls to FOO [**]. We also have to instrument tail calls to things that tail call FOO, like BAZ here:
(defun foo (x y z) (values x y z))
(defun baz () (foo))
(defun bar () (foo) (baz))
Given this transitivity, how do you distinguish which tail calls are potentially-multi-valued in order to instrument them? Keep in mind that passthrough also has to work in cases like:
(defun baz2 (fn) (apply fn '(1 2 3))
(defun baz3 () (funcall *fn* 1 2 3))
... whenever the calls to FN and *FN* are potentially-multi-valued.
The only easy implementation I can think of is to mv-instrument every tail call in the program, but that is surely overkill.
Daniel
[*] There's also the recursive case we've been discussing, where you might both want the instrumentation and not want it -- but since my question doesn't depend on that complication, let's just ignore it here.
[**] Just to be clear, all I mean by "tail call" is any expression "(return (some-function))" once PS is done adding in all the implicit returns.