Version 5 (modified by cotto, 12 years ago)

--

NOTE: pmichaud estimates that the overhead for nqp caused by Parrot's lack of an lvalue model is about 4%. This may be worth fixing eventually but it's probably not a low-hanging fruit.

<pmichaud> 
cotto_work: I do expect to try to generate smarter pir, yes.  However, the structure of 
Parrot doesn't allow for a lot smarter PIR.  (I'm hoping parrot will change that... but 
I don't expect it to happen anytime in the near future.)

<cotto_work>
ok.  How could Parrot enable smarter code generation?

<pmichaud>
cotto_work: well, one of the big stumbling blocks at the moment is that lexicals can only be PMCs
so anything that goes into a lexical ends up having to be boxed into a PMC
an even bigger stumbling block is that Parrot doesn't have a good lvalue model or assignment semantics
it tends to confuse "bind" with "assign"
at least, it does that for most of the default PMC types
there's also not a good reference model
for keeping track of object references
as a result, the code that nqp generates tends to have to be somewhat pessimistic, such as continually 
refetching lexical and global symbol tables because of the possibility of a symbol being rebound

<cotto_work> 
That explains some of the generated code then.

<pmichaud>
cotto_work: I do plan to have an option whereby code can say "assume this lexical/symbol isn't 
being rebound" but since parrot doesn't have a good assignment model, most folks end up doing rebinds
partcl-nqp just went through this yesterday (until I fixed it this morning) whereby symbols were being
re-bound to new PMCs instead of changing the value of an existing multiply-bound PMC

<cotto_work> 
What's the difference between assignment and binding?

<pmichaud>
assignment changes the value of an existing PMC
binding causes a symbol table entry to point to a PMC
so, for example
 $P0 = box 1
 $P1 = $P0
these are examples of binding
if after the above, I do:    $P0 = box 3
then $P1 ends up still being bound to the PMC containing 1
and $P0 is bound to a new PMC containing 3
okay so far?

<cotto_work> 
yes

<pmichaud> 
 $P0 = box 1
 $P1 = $P0
 assign $P0, 3
in this case,  $P0 and $P1 still point to the same PMC, and the value of that PMC has changed to 3
still okay?

<cotto_work> 
yes

<pmichaud> 
that's the difference
now then, let's look at something like
 $P0 = new ['ResizablePMCArray']
 $P0[0] = 1
 $P1 = $P0[0]
in this case, $P1 and $P0[0] are pointing to the same PMC  (containing 1)
but if we then do...
 $P0[0] = 3
that's a binding, not an assignment
such that $P1 refers to the old PMC (1), while $P0[0] refers to the new one (3)
in other words, changing the value in the array has broken the bind

<moritz> 
pmichaud: this is becoming an FAQ... you should put that on a wiki page or so

<pmichaud> 
moritz: well, I have a few hours car ride today, perhaps I can type it up.
but I also plan to do a NQP/compiler tutorial

<cotto_work> 
Thanks.

<pmichaud> 
where it gets *really* nasty is with
   $P0 = find_lex '$a'
   'foo'()
if the "foo" subroutine does   store_lex  '$a', $P99    to put a new value in lexical $a
then when we get back from 'foo', $P0 no longer points to the PMC associated with $a
because store_lex does a bind
and not an assign

<cotto_work> 
Then $P0 will have an out-of-date value

<pmichaud> 
exactly
so, every time we need access to $a, we end up having to do a re-fetch
because it's possible some other operation will have re-bound it to a different PMC
ideally there would be an opcode that makes it easier to do assignment
there is an opcode called 'assign', but it tends to do weird things with the built-in PMCs
for example
 $P0 = new ['ResizablePMCArray']
 store_lex '$a', $P0
which sets $a to be a RPA
now we want to do the equivalent of  $a = 3   -- i.e., change it to an Integer 3
 $P1 = find_lex '$a'
 assign $P1, 3      #   oooops!

<cotto_work> 
That changes the length to 3, doesn't it?

<pmichaud> 
what we want is $P1 to be an Integer 3
right
so the 'assign' opcode doesn't do what we want here
late last year we added the 'copy' opcode to try to do this
so we'd have
 $P1 = find_lex '$a'
 $P2 = box 3
 copy $P1, $P2    (replace $P1 with $P2)
but it's horribly inefficient, because it involves making a clone of $P2 and then copying that 
structure into the PMC header for $P1 but so far it's about the best we can do everything gets
worse when we start talking about aggregate access because there's not a    copy $P0[0], $P2    
opcode yet and this leads to allison's comment that it really should be the PMCs/vtables that determine 
behavior instead of opcodes (which is where the model completely breaks down)

<cotto_work> 
There's a lot conspiring to prevent good code generation from nqp.
Thanks you for that explanation.

<pmichaud> 
sure thing!
ultimately it's that Parrot (vtable and core types) doesn't have a good container/value/lvalue model
or, at least, one that doesn't map well to the HLL's we're targeting.