I should read the list and respond to the outstanding stuff, but I should also get this done, and since the former probably precludes the latter...

Why, exactly, have I spec'd (nay, demanded!) that every darned operation in a PMC's vtable have a keyed variant?

Simple. A combination of speed and space. (And yes, I know we're going to fight over this one)

Now, for aggregates that hold PMCs and are relatively passive containers (that is, they don't get in the way of anything besides load and store operations, if that) the keyed variants provide no benefit to speak of. Less opcode dispatch overhead, but there's not a whole lot of that in general anyway, and on JITted cores there's no win at all.

For aggregates that *don't* hold PMCs, though, that's where the win is. Those are the sorts of aggregates we're aggressively targeting as well. One of the big issues with perl, python, and ruby is that the base variable data structure is big. (And we're not making it any smaller with Parrot--our PMCs are pretty hefty still) Optimizing the size of an individual scalar isn't much of a win, but optimizing the size of arrays and hashes of scalars is a win. (This is one of the lessons learned from Chip's Topaz project) Many hashes and arrays don't need full-fledged PMCs in them, nor the space that full PMCs take. A string, integer, or bool array is sufficient for many of the uses that aggregates are put to.

This is a good argument for abstract aggregate element access, which we have now, and that's good. Saves us space, potentially. Yay us.

How this argues for keyed access to the operations on aggregate elements, however, is less obvious, but I think it's worth it.

If we don't have direct operations on aggregate elements but instead have to do a fetch and perform the operation on what we fetch, it means we have to create a temporary PMC for each 'fake' entry, one potentially with a fair amount of knowledge about how the aggregate works, which means that every aggregate will need to provide two vtables, one for itself and one for an aggregate entry.

Going with direct operations on keyed aggregates, then, makes the code somewhat more dense, since we only need to access one vtable per operand rather than two (one to fetch the data and one to operate on it). That's balanced somewhat by having to have two sets of PMC opcodes, one that operates on all parts keyed and one that doesn't.

The integrated approach *also* makes it easier to optimize the operation. For example, this code:

foo[12] = foo[12] + bar[15];

or the more compact

foo[12] += bar[15];

has the destination identical to one of the sources. In the keyed access scheme, that's a single operation, one where foo's vtable function can *easily* determine that the destination and one of the sources is identical. (It's a pair of comparisons) If accessing foo is somewhat expensive--for example requiring a DB access--having knowledge that the source and destination are identical can allow for optimizations that wouldn't otherwise be allowable. (For example, if foo and bar represented fields in two tables, knowing that the destination and one of the sources is identical can potentially cut out one of the DB accesses) While this is doable if we pass in plain scalar PMCs, it'll have to be more expensive, and as such is less likely to be done.

Yes, I also know that this potentially breaks down in more complex expressions. That's fine--it means that we can optimize some access rather than all access. I'm OK with that, as it's better than optimizing all accesses.

More information's available if anyone wants it, but this *is* the way we're going unless someone proves that it's suboptimal in the common case.
--
Dan


--------------------------------------"it's like this"-------------------
Dan Sugalski                          even samurai
[EMAIL PROTECTED]                         have teddy bears and even
                                      teddy bears get drunk

Reply via email to