In any case, interoperability with non-PS programs is a separate issue- as far as I can tell, neither the GV nor foo.mv designs can achieve it.
With the function object approach, JS functions will always return exactly one value. IMO, having them pass through multiple values would be the wrong thing.
I see a problem in that you'd have to instrument not just return statments, but any kind of control flow that goes up the stack - so you'd have to put the suppression code at the end of every function definition, and also wrap throws.
I haven't come up with any examples of this yet and would like to see one. It seems the question is, how might the GV design fail to clean up dangling MV state? There are three ways for MV state to flow in GV:
(1) non-tail calls that clear MV; (2) non-tail calls that bind MV and then clear it; (3) tail calls that let MV pass through.
Other exit points from a function are throws and control reaching the end of the function. So both are going to have to get instrumented.
It's worth noting that foo.mv might have a problem with errors too:
foo.mv = arguments.callee.mv; var result = foo(); delete foo.mv; return result;
If foo() throws an error, there is a dangling foo.mv. Might that be harmless? If it isn't, you need something like:
foo.mv = arguments.callee.mv; try { return foo(); } finally { delete foo.mv; }
... around every tail call in the program. The possible performance hit is worrisome. That's on top of the possible performance hit of arguments.callee.mv, which is the kind of thing that causes V8 to turn off optimizations.
Yeah, I just finished up coding the function object approach, and the generated code gets ugly.
I don't see a way around instrumenting tail calls if you want to implement multiple value pass-through correctly.
I do see a way to combine the global variable and function object approach to simplify things:
Since there's only one way the values can travel up the stack, we can use a single global variable to store the multiple values with the function object that returned them. That way multiple-value-bind can check the array, and if it has values from any but the expected function object, we can just ignore them. To pass through multiple values, every tail call now has to check the global variable to see if multiple values got returned by the tail function. If so, it just replaces the function object they're tagged with with itself.
I can see that approach failing for a recursive function that sets multiple values in one of its sub-invocations, but doesn't return multiple values to whoever originally called it expecting multiple values.
Vladimir