Hi Andy,
Sorry for the delay, short answer – this all sounds great. I'd like to suggest
what I think is possibly a slight tweak to the sequence of the development as I
understand it, but the basic direction all seems sound.
One thing to clarify – your example allocation looked fine, but I just wanted
to check, the example didn't contain a top level 'let':
function f(a, b)
{
let x = a;
var y = b;
return function(){ return x + y; };
}
In this example, 'x' would be stored on the activation I assume – there should
be no need for two scope object to be allocated.
You're proposing introducing a new type of static scope object that supports
lazy tear off, but that only supported capturing local variables. I'd like to
make three observations:
• I think it should be relatively straightforward to fix the existing
activation objects such that they can be parameterized to only capture a subset
of locals, and not the function's arguments (and to allow more than one per
CodeBlock). If you were to do so, this class would be usable to implement
block scopes. I believe this would be a faster route to get something working
and being testable, since the existing activation objects are already supported
throughout the engine (e.g. have existing JIT & interpreter support).
• If it is a useful optimization to have a type of scope object that only
supports capturing locals (not arguments, and without support for dynamically
introduced vars) then the place we're going to benefit from this the most will
be implementing the capturing scope for functions that do not contain eval or
capture their arguments (plenty of such code exists on the web, code relying on
block scopes does not). It would be a little tragic to introduce an optimized
scope object, and then to only use it for block scopes and not where it will
give us the greatest benefit.
• If we are going to introduce the complexity of a new class and a new set of
opcodes to support it, then it would be best to do this in a fashion that
demonstrated the benefit of doing so (in comparison to parameterizing the
existing activation object).
As such, three roadmaps spring to mind in how the block scope work could be
implemented:
(1) Initially implement block-scoped variables using modified activations
(don't capture arguments, just the appropriate range of the register file).
Then, as a separate iterative step, introduce a new scope object that only
captures locals, demonstrate this to be a benefit, and switch both block scopes
and function scopes that don't capture arguments or use eval to use the new
scope type.
(2) Introduce a new scope object for use in place of the activation for
functions that don't capture arguments or use eval, switch such functions over
to use the new scope object, demonstrate a benefit, and adopt this approach .
Then as a separate step use the new scope object to implement block scopes.
(3) Introduce a new type of scope object, use this to implement block scoped
variables. Then try using the new scope object to implement the scope for
functions that don't capture arguments or use eval, and either: (a) discover
that this was a good idea, in which case adopt this approach, or (b) discover
that this doesn't actually provide any benefit. In the latter case, this
probably implies that the additional complexity isn't buying us anything for
block scopes either, in which case the next step would likely be to switch the
block scope work over to use modified activation objects, and remove the
additional complexity associated with the additional scope class and set of
opcodes.
It seems that option 3 can only be strictly worse than the first two, since
there is the danger of introducing unnecessary churn in the tree. I'm not
going to try to force you down any particular path here, but I would suggest
thinking about which route you wish to follow. :-)
BTW, for the new scope object, I'd suggest the name 'JSClosure'.
cheers,
G.
_______________________________________________
squirrelfish-dev mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/squirrelfish-dev