| 2 | | <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. |
| 3 | | <pmichaud> (I'm hoping parrot will change that... but I don't expect it to happen anytime in the near future.) |
| 4 | | <cotto_work> ok. How could Parrot enable smarter code generation? |
| 5 | | <Tene> The fix isn't too bad, but I haven't done it yet. |
| 6 | | <cotto_work> It sounds like that might fit in with Lorito. |
| 7 | | <pmichaud> cotto_work: well, one of the big stumbling blocks at the moment is that lexicals can only be PMCs |
| 8 | | <pmichaud> so anything that goes into a lexical ends up having to be boxed into a PMC |
| 9 | | <pmichaud> an even bigger stumbling block is that Parrot doesn't have a good lvalue model or assignment semantics |
| 10 | | <pmichaud> it tends to confuse "bind" with "assign" |
| 11 | | <pmichaud> at least, it does that for most of the default PMC types |
| 12 | | <pmichaud> there's also not a good reference model |
| 13 | | <pmichaud> for keeping track of object references |
| 14 | | <pmichaud> 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 |
| 15 | | <Coke> pmichaud,tene: > puts [list [catch barf var] $var] |
| 16 | | <Coke> 1 {Could not find non-existent sub barf} |
| 17 | | <Coke> whee. |
| 18 | | <cotto_work> That explains some of the generated code then. |
| 19 | | * cconstantine has quit (Quit: cconstantine) |
| 20 | | <Coke> pmichaud: any issue with switching partcl-nqp to build with "nqp" instead of "parrot-nqp" for now? |
| 21 | | <Coke> (then I don't have to ping you to cut a new 'release' =-) |
| 22 | | <pmichaud> cotto_work: I do plan to have an option whereby code can say "assume this lexical/symbol isn't being rebound" |
| 23 | | <pmichaud> but since parrot doesn't have a good assignment model, most folks end up doing rebinds |
| 24 | | <pmichaud> 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 |
| 25 | | <cotto_work> What's the difference between assignment and binding? |
| 26 | | <pmichaud> assignment changes the value of an existing PMC |
| 27 | | <pmichaud> binding causes a symbol table entry to point to a PMC |
| 28 | | <pmichaud> so, for example |
| 29 | | <pmichaud> $P0 = box 1 |
| 30 | | <pmichaud> $P1 = $P0 |
| 31 | | <pmichaud> these are examples of binding |
| 32 | | <pmichaud> if after the above, I do: $P0 = box 3 |
| 33 | | <pmichaud> then $P1 ends up still being bound to the PMC containing 1 |
| 34 | | <pmichaud> and $P0 is bound to a new PMC containing 3 |
| 35 | | <pmichaud> okay so far? |
| 36 | | <cotto_work> yes |
| 37 | | <pmichaud> $P0 = box 1 |
| 38 | | <pmichaud> $P1 = $P0 |
| 39 | | <pmichaud> assign $P0, 3 |
| 40 | | <pmichaud> in this case, $P0 and $P1 still point to the same PMC, and the value of that PMC has changed to 3 |
| 41 | | <pmichaud> still okay? |
| 42 | | <cotto_work> yes |
| 43 | | <pmichaud> that's the difference |
| 44 | | <pmichaud> now then, let's look at something like |
| 45 | | <pmichaud> $P0 = new ['ResizablePMCArray'] |
| 46 | | <pmichaud> $P0[0] = 1 |
| 47 | | <pmichaud> $P1 = $P0[0] |
| 48 | | <pmichaud> in this case, $P1 and $P0[0] are pointing to the same PMC (containing 1) |
| 49 | | <pmichaud> but if we then do... |
| 50 | | <pmichaud> $P0[0] = 3 |
| 51 | | <pmichaud> that's a binding, not an assignment |
| 52 | | <pmichaud> such that $P1 refers to the old PMC (1), while $P0[0] refers to the new one (3) |
| 53 | | <pmichaud> in other words, changing the value in the array has broken the bind |
| 54 | | <moritz> pmichaud: this is becoming an FAQ... you should put that on a wiki page or so |
| 55 | | <pmichaud> moritz: well, I have a few hours car ride today, perhaps I can type it up. |
| 56 | | <pmichaud> but I also plan to do a NQP/compiler tutorial |
| 57 | | <Coke> pmichaud: is t/sanity.t working for you? |
| 58 | | <pmichaud> Coke: it was as of my last push |
| 59 | | <cotto_work> Thanks. |
| 60 | | <pmichaud> where it gets *really* nasty is with |
| 61 | | <pmichaud> $P0 = find_lex '$a' |
| 62 | | <pmichaud> 'foo'() |
| 63 | | <pmichaud> if the "foo" subroutine does store_lex '$a', $P99 to put a new value in lexical $a |
| 64 | | <pmichaud> then when we get back from 'foo', $P0 no longer points to the PMC associated with $a |
| 65 | | <dalek> nqp-rx: ae0666c | tene++ | t/nqp/44-try-catch.t: |
| 66 | | <dalek> nqp-rx: Update test plan |
| 67 | | <dalek> nqp-rx: review: http://github.com/perl6/nqp-rx/commit/ae0666cf489a209c1aa2bffb1a829ce689a3b146 |
| 68 | | <pmichaud> because store_lex does a bind |
| 69 | | <pmichaud> and not an assign |
| 70 | | <cotto_work> Then $P0 will have an out-of-date value |
| 71 | | <pmichaud> exactly |
| 72 | | <pmichaud> so, every time we need access to $a, we end up having to do a re-fetch |
| 73 | | <pmichaud> because it's possible some other operation will have re-bound it to a different PMC |
| 74 | | <dalek> rakudo: 2eb38b5 | moritz++ | perl6.pir: |
| 75 | | <dalek> rakudo: alias Object and Mu, as suggested by jnthn++; wins us back quite a few tests |
| 76 | | <dalek> rakudo: review: http://github.com/rakudo/rakudo/commit/2eb38b5bf07f1c4392a9d1d75f3fd1cf7d877105 |
| 77 | | <pmichaud> ideally there would be an opcode that makes it easier to do assignment |
| 78 | | <pmichaud> there is an opcode called 'assign', but it tends to do weird things with the built-in PMCs |
| 79 | | <pmichaud> for example |
| 80 | | <pmichaud> $P0 = new ['ResizablePMCArray'] |
| 81 | | <pmichaud> store_lex '$a', $P0 |
| 82 | | <pmichaud> which sets $a to be a RPA |
| 83 | | <pmichaud> now we want to do the equivalent of $a = 3 -- i.e., change it to an Integer 3 |
| 84 | | <pmichaud> $P1 = find_lex '$a' |
| 85 | | <pmichaud> assign $P1, 3 # oooops! |
| 86 | | <cotto_work> That changes the length to 3, doesn't it? |
| 87 | | <pmichaud> what we want is $P1 to be an Integer 3 |
| 88 | | <pmichaud> right |
| 89 | | <pmichaud> so the 'assign' opcode doesn't do what we want here |
| 90 | | <pmichaud> late last year we added the 'copy' opcode to try to do this |
| 91 | | <pmichaud> so we'd have |
| 92 | | <pmichaud> $P1 = find_lex '$a' |
| 93 | | <pmichaud> $P2 = box 3 |
| 94 | | <pmichaud> copy $P1, $P2 (replace $P1 with $P2) |
| 95 | | * pjcj (~pjcj@80-218-204-119.dclient.hispeed.ch) has joined #parrot |
| 96 | | * slavorg gives channel operator status to pjcj |
| 97 | | <pmichaud> but it's horribly inefficient, because it involves making a clone of $P2 and then copying that structure into the PMC header for $P1 |
| 98 | | <pmichaud> but so far it's about the best we can do |
| 99 | | <pmichaud> everything gets worse when we start talking about aggregate access |
| 100 | | <pmichaud> because there's not a copy $P0[0], $P2 opcode yet |
| 101 | | <pmichaud> and this leads to allison's comment that it really should be the PMCs/vtables that determine behavior instead of opcodes |
| 102 | | <pmichaud> (which is where the model completely breaks down) |
| 103 | | <cotto_work> There's a lot conspiring to prevent good code generation from nqp. |
| 104 | | <cotto_work> Thanks you for that explanation. |
| 105 | | <pmichaud> sure thing! |
| 106 | | <dukeleto> 'ello |
| 107 | | <pmichaud> ultimately it's that Parrot (vtable and core types) doesn't have a good container/value/lvalue model |
| 108 | | <pmichaud> or, at least, one that doesn't map well to the HLL's we're targing. |
| 109 | | <pmichaud> *targeting |
| | 2 | <pmichaud> |
| | 3 | 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. |
| | 4 | (I'm hoping parrot will change that... but I don't expect it to happen anytime in the near future.) |
| | 5 | |
| | 6 | <cotto_work> |
| | 7 | ok. How could Parrot enable smarter code generation? |
| | 8 | |
| | 9 | <pmichaud> |
| | 10 | cotto_work: well, one of the big stumbling blocks at the moment is that lexicals can only be PMCs |
| | 11 | so anything that goes into a lexical ends up having to be boxed into a PMC |
| | 12 | an even bigger stumbling block is that Parrot doesn't have a good lvalue model or assignment semantics |
| | 13 | it tends to confuse "bind" with "assign" |
| | 14 | at least, it does that for most of the default PMC types |
| | 15 | there's also not a good reference model |
| | 16 | for keeping track of object references |
| | 17 | 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 |
| | 18 | |
| | 19 | <cotto_work> |
| | 20 | That explains some of the generated code then. |
| | 21 | |
| | 22 | <pmichaud> |
| | 23 | cotto_work: I do plan to have an option whereby code can say "assume this lexical/symbol isn't being rebound" |
| | 24 | but since parrot doesn't have a good assignment model, most folks end up doing rebinds |
| | 25 | 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 |
| | 26 | |
| | 27 | <cotto_work> |
| | 28 | What's the difference between assignment and binding? |
| | 29 | |
| | 30 | <pmichaud> |
| | 31 | assignment changes the value of an existing PMC |
| | 32 | binding causes a symbol table entry to point to a PMC |
| | 33 | so, for example |
| | 34 | $P0 = box 1 |
| | 35 | $P1 = $P0 |
| | 36 | these are examples of binding |
| | 37 | if after the above, I do: $P0 = box 3 |
| | 38 | then $P1 ends up still being bound to the PMC containing 1 |
| | 39 | and $P0 is bound to a new PMC containing 3 |
| | 40 | okay so far? |
| | 41 | |
| | 42 | <cotto_work> |
| | 43 | yes |
| | 44 | |
| | 45 | <pmichaud> |
| | 46 | $P0 = box 1 |
| | 47 | $P1 = $P0 |
| | 48 | assign $P0, 3 |
| | 49 | in this case, $P0 and $P1 still point to the same PMC, and the value of that PMC has changed to 3 |
| | 50 | still okay? |
| | 51 | |
| | 52 | <cotto_work> |
| | 53 | yes |
| | 54 | |
| | 55 | <pmichaud> |
| | 56 | that's the difference |
| | 57 | now then, let's look at something like |
| | 58 | $P0 = new ['ResizablePMCArray'] |
| | 59 | $P0[0] = 1 |
| | 60 | $P1 = $P0[0] |
| | 61 | in this case, $P1 and $P0[0] are pointing to the same PMC (containing 1) |
| | 62 | but if we then do... |
| | 63 | $P0[0] = 3 |
| | 64 | that's a binding, not an assignment |
| | 65 | such that $P1 refers to the old PMC (1), while $P0[0] refers to the new one (3) |
| | 66 | in other words, changing the value in the array has broken the bind |
| | 67 | |
| | 68 | <moritz> |
| | 69 | pmichaud: this is becoming an FAQ... you should put that on a wiki page or so |
| | 70 | |
| | 71 | <pmichaud> |
| | 72 | moritz: well, I have a few hours car ride today, perhaps I can type it up. |
| | 73 | but I also plan to do a NQP/compiler tutorial |
| | 74 | |
| | 75 | <cotto_work> |
| | 76 | Thanks. |
| | 77 | |
| | 78 | <pmichaud> |
| | 79 | where it gets *really* nasty is with |
| | 80 | $P0 = find_lex '$a' |
| | 81 | 'foo'() |
| | 82 | if the "foo" subroutine does store_lex '$a', $P99 to put a new value in lexical $a |
| | 83 | then when we get back from 'foo', $P0 no longer points to the PMC associated with $a |
| | 84 | because store_lex does a bind |
| | 85 | and not an assign |
| | 86 | |
| | 87 | <cotto_work> |
| | 88 | Then $P0 will have an out-of-date value |
| | 89 | |
| | 90 | <pmichaud> |
| | 91 | exactly |
| | 92 | so, every time we need access to $a, we end up having to do a re-fetch |
| | 93 | because it's possible some other operation will have re-bound it to a different PMC |
| | 94 | ideally there would be an opcode that makes it easier to do assignment |
| | 95 | there is an opcode called 'assign', but it tends to do weird things with the built-in PMCs |
| | 96 | for example |
| | 97 | $P0 = new ['ResizablePMCArray'] |
| | 98 | store_lex '$a', $P0 |
| | 99 | which sets $a to be a RPA |
| | 100 | now we want to do the equivalent of $a = 3 -- i.e., change it to an Integer 3 |
| | 101 | $P1 = find_lex '$a' |
| | 102 | assign $P1, 3 # oooops! |
| | 103 | |
| | 104 | <cotto_work> |
| | 105 | That changes the length to 3, doesn't it? |
| | 106 | |
| | 107 | <pmichaud> |
| | 108 | what we want is $P1 to be an Integer 3 |
| | 109 | right |
| | 110 | so the 'assign' opcode doesn't do what we want here |
| | 111 | late last year we added the 'copy' opcode to try to do this |
| | 112 | so we'd have |
| | 113 | $P1 = find_lex '$a' |
| | 114 | $P2 = box 3 |
| | 115 | copy $P1, $P2 (replace $P1 with $P2) |
| | 116 | but it's horribly inefficient, because it involves making a clone of $P2 and then copying that structure into the PMC header for $P1 |
| | 117 | but so far it's about the best we can do |
| | 118 | everything gets worse when we start talking about aggregate access |
| | 119 | because there's not a copy $P0[0], $P2 opcode yet |
| | 120 | and this leads to allison's comment that it really should be the PMCs/vtables that determine behavior instead of opcodes |
| | 121 | (which is where the model completely breaks down) |
| | 122 | |
| | 123 | <cotto_work> |
| | 124 | There's a lot conspiring to prevent good code generation from nqp. |
| | 125 | Thanks you for that explanation. |
| | 126 | |
| | 127 | <pmichaud> |
| | 128 | sure thing! |
| | 129 | ultimately it's that Parrot (vtable and core types) doesn't have a good container/value/lvalue model |
| | 130 | or, at least, one that doesn't map well to the HLL's we're targeting. |