On Fri, Aug 02, 2002 at 08:50:27AM -0700, Sean O'Rourke wrote: > On Fri, 2 Aug 2002, Jerome Vouillon wrote: > > > On Thu, Aug 01, 2002 at 10:57:34AM -0700, Sean O'Rourke wrote: > > > My naive implementation would have an array of hashes for each sub, with > > > one entry for each level of scope within. > > > > I would use an array of arrays or a linked-list of arrays. This is > > hardly more difficult to implement (you just need to keep track of the > > variable indices during compilation) and the generated code will be a > > lot more efficient. > > I don't see how you can cope with '%MY' unless you have a hash. You could > have a hash in addition to the array, I suppose.
Sure, you need a hash. But this can be a statically allocated hash, mapping variable names to indices. > In any case, Dan has > promised us some sort of indexed "back-door" access to our hashes, so I > get the feeling the point is moot -- hashes will be arrays in some sense. Allocating a hash will certainly remain a lot more expensive than allocating an array. And we are going to allocate pads pretty often... > > > This is just like the > > > pad_stack, but implemented using only language features. (Dynamic) > > > lexical lookup works its way through this stack. Static lookups can > > > probably be resolved to registers, with code inserted to fetch values out > > > of the pad the first time they are used, and store them back when a scope > > > is exited. > > > I think it is good enough for the moment to always go through the > > stack. > > Without performance numbers, this is hard to test, but it can potentially > turn a single "a = b + c", which is just "add P0, P1, P2" if a, b, and c > have been referenced, into a hideous five instructions: > > fetch_lex P0, 'a' # Because how we store result depends on a's type > fetch_lex P1, 'b' > fetch_lex P2, 'c' > add P0, P1, P2 > store_lex P0, 'a' Sure, but this seems to be a non-trivial optimization (I may be wrong). I think we should implement a larger part of the language first. By the way, the code should probably be: fetch_lex P0, 'a' # Get the PMC of variable 'a' fetch_lex P1, 'b' # Get the PMC of variable 'b' fetch_lex P2, 'c' # Get the PMC of variable 'c' add P0, P1, P2 # Add the values contained in the PMC of 'b' and 'c' and store them in the PMC of 'a' The opcode store_lex is only needed for the operator := (and maybe for variable initialization). > > > Returning a closure would make a copy of the scope array, containing > > > references to the pad hashes (here's where GC makes me happy, and where I > > > may make the GC unhappy). > > > > You don't need to make a copy at this point. Instead, the copy should > > happen each time you enter a block containing lexical variables. (You > > should also allocate and fill a new pad at this time.) > > Making a copy on every scope entry would solve the problem (the Befunge > stack-stack metaphor grows stronger!), but I was hoping we could do > better, since most lexical scopes won't be creating closures. The more I > think about it, though, the more complicated that gets. Note that when you have a loop you need to allocate some fresh lexical variables at each iteration (so, you need to create a new pad each time). Furthermore, you can create loops with callcc, so the piece of code below could be a loop, if the function foo captures the current continuation and the function bar resumes it. foo(); do { my $x = ... } bar(); > And actually, thanks to %MY and caller.MY, we need a new pad even > for scopes without lexicals, since they can be inserted later. I really hope %MY and caller.MY will not be able to extend the lexical scope: we would get a really huge speed penalty for a feature which would hardly ever be used. -- Jerome