Accessing temp variables bindings in a BlockClosure

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Accessing temp variables bindings in a BlockClosure

Stéphane Rollandin
Hello,

Is there a way to map the temp variables stored in a BlockClosure with
their names as they appear in the decompileString?

For example we have:

        | y |
        y := 10.
        [:x | y + x] basicAt: 1 "returns 10"

and

        | y |
        y := 10.
        [:x | y + x] decompileString "returns '[:x | y + x]'"


What I would like is something like

        | y |
        y := 10.
        [:x | y + x] tempBindingAt: 1 "would return #y -> 10"


Stef

Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Christoph Thiede

Hi Stef,


good question. You can get the argument names via aBlock decompile arguments, and if you also care about the temp names, you can append aBlock decompile temporaries. But you probably knew that already :)


If you have the possibility to invoke the block, you could also try something like:


| y |
y := 10.
([:x | y + x. thisContext] value: 42) tempsAndValues


If you cannot invoke the block, here would an even more hacky alternative:


| y |
y := 10.
aBlock := [:x | y + x].
(aBlock simulateValueWithArguments: (Array new: aBlock numArgs) caller: aBlock outerContext) tempsAndValues


But I agree that these are no nice solutions at all. I suppose the point is that in contrast to literal bindings, temporary variables are never actually stored as bindings in the block method. For what purpose do you need the bindings?

Best,
Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Stéphane Rollandin <[hidden email]>
Gesendet: Sonntag, 19. April 2020 18:18 Uhr
An: liste [Squeak-dev]
Betreff: [squeak-dev] Accessing temp variables bindings in a BlockClosure
 
Hello,

Is there a way to map the temp variables stored in a BlockClosure with
their names as they appear in the decompileString?

For example we have:

        | y |
        y := 10.
        [:x | y + x] basicAt: 1         "returns 10"

and

        | y |
        y := 10.
        [:x | y + x] decompileString    "returns '[:x | y + x]'"


What I would like is something like

        | y |
        y := 10.
        [:x | y + x] tempBindingAt: 1    "would return #y -> 10"


Stef



Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Stéphane Rollandin
> But I agree that these are no nice solutions at all. I suppose the point
> is that in contrast to literal bindings, temporary variables are never
> actually stored as bindings in the block method. For what purpose do you
> need the bindings?

For inspection - I would like the var names to appear in the explorer as
the keys (instead of the #basicAt: indexes).

The code I am dealing with at the moment is choke-full of nested blocks,
and it is a pain to see the values of the temp vars in the closures. I
am hacking a modified Explorer to better display this particular info,
but I'm having a hard time...

Stef

Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Stéphane Rollandin
In reply to this post by Christoph Thiede
At the moment I have something working in many cases, but not all (attached)

It can do

        | y |
        y := 10.
        [:x | y + x] tempBindings "returns {'y'->10}"

and

        | y x |
        y := 10.
        x := 8.
        [:a :b | a + y + x] tempBindings " {'y'->10 . 'x'->8} "


but fails for example here:

        |blockSourceStream methodNode compiledMethod block |

        blockSourceStream :=
                '|x y| [:a :b | x := b. y := a. x + y]' readStream.

        methodNode := nil class evaluatorClass new
                compileNoPattern: blockSourceStream
                in: nil class notifying: nil ifFail: [nil].

        compiledMethod := methodNode generateWithTempNames.

        block := nil withArgs: #() executeMethod: compiledMethod.

        block tempBindings "Error !!"

because the block basicAt: 1 is actually a list with the value of both x
and y - and I do not see how to detect this case.

Stef



BlockClosure-tempBindings.st (558 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Stéphane Rollandin
> At the moment I have something working in many cases, but not all (attached)
>
> It can do
> | y x |
> y := 10.
> x := 8.
> [:a :b | a + y + x] tempBindings " {'y'->10 . 'x'->8} "

... well in fact it can't, because just switching x and y in the block
leads to:

        | y x |
        y := 10.
        x := 8.
        [:a :b | a + x + y] tempBindings "  {'x'->10 . 'y'->8} "

So I'm stuck.

Stef



Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Christoph Thiede
In reply to this post by Stéphane Rollandin

For inspection - I would like the var names to appear in the explorer as the keys (instead of the #basicAt: indexes).


Are you sure you are not actually inspecting a context object?


This is how the explorer on a FullBlockClosure looks in my image:




This is how its corresponding Context looks like:




But these indexes cannot be mapped directly to the temporaries. Here is a counter-example:


| y |
y := 10.
[| x | y raisedTo: (x := 13) modulo: 42] newProcess
runUntil: [:c | c actualStackSize = 2];
suspendedContext




Contexts also hold "anonymous temps" that are only visible on the stack during execution and depend on the bytecode set.


But we could probably override Context >> #explorerContents in the following way:




See attachment. :-)

Best,
Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Stéphane Rollandin <[hidden email]>
Gesendet: Sonntag, 19. April 2020 23:56 Uhr
An: [hidden email]
Betreff: Re: [squeak-dev] Accessing temp variables bindings in a BlockClosure
 
> But I agree that these are no nice solutions at all. I suppose the point
> is that in contrast to literal bindings, temporary variables are never
> actually stored as bindings in the block method. For what purpose do you
> need the bindings?

For inspection - I would like the var names to appear in the explorer as
the keys (instead of the #basicAt: indexes).

The code I am dealing with at the moment is choke-full of nested blocks,
and it is a pain to see the values of the temp vars in the closures. I
am hacking a modified Explorer to better display this particular info,
but I'm having a hard time...

Stef




Context-explorerContents.st (880 bytes) Download Attachment
Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Stéphane Rollandin
Here is a picture of what I want (it is from my custom explorer which
happens to give an ok result in this specific case)

You can see that in there the 'alarms' set of blocks is displayed as a
list of decompileStrings, and each temp vars such as 'aBlock' or
'aTimeLapse' is featured with its corresponding value.

Stef



explorer.png (179K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Christoph Thiede
In reply to this post by Stéphane Rollandin

Hi Stef,


because the block basicAt: 1 is actually a list with the value of both x and y - and I do not see how to detect this case.


I may be wrong, but sending #basicAt: to BlockClosures should access its closured objects only, in the way their sender wrote them on it. I suppose this is not a reliable way to access temporaries from it?


The array you found is a remote temp vector, which is basically an implementation detail of how closures work. In a nutshell, a BlockClosure holds a copy of each variable it accesses ("closures") from its outerContext, in order to optimize the execution of blocks. However, if a block must be supposed to reassign some of these variables, we would need to sync these copies with their originals. To avoid this expensive operation, variables that are assigned from within the block are stored in an extra remote temp vector that is common to the block and its outer context(s). You can study the following observations if you're interested:


| a b c d e |
a := 1.
b := 2.
c := 3.
d := 4.
e := 5.
[a. b. c := 6. d := 7]



| x |
x := 2.
[
thisContext sender tempAt: 1 put: 3.
x
] value. "2"


Disclaimer: I played some time around with this amazing stuff and received a number of valuable explanations from the community, but I'm still new to the domain. Nothing I try to explain must be correct or make sense and others can probably tell you better :-)


Here is a really nice explanation by Eliot: http://forum.world.st/BUG-Cannot-compile-cascade-sent-to-block-tp5108942p5109012.html


Best,

Christoph


PS: Just saw your screenshot. If you do not need to access temporaries/args that are local to the blocks, shouldn't you be fine with aBlock outerContext tempsAndValues?




Von: Squeak-dev <[hidden email]> im Auftrag von Stéphane Rollandin <[hidden email]>
Gesendet: Montag, 20. April 2020 00:24:45
An: [hidden email]
Betreff: Re: [squeak-dev] Accessing temp variables bindings in a BlockClosure
 
> At the moment I have something working in many cases, but not all (attached)
>
> It can do
>        | y x |
>        y := 10.
>        x := 8.
>        [:a :b | a + y + x] tempBindings         " {'y'->10 . 'x'->8} "

... well in fact it can't, because just switching x and y in the block
leads to:

        | y x |
        y := 10.
        x := 8.
        [:a :b | a + x + y] tempBindings        "  {'x'->10 . 'y'->8} "

So I'm stuck.

Stef





Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Stéphane Rollandin

> PS: Just saw your screenshot. If you do not need to access
> temporaries/args that are local to the blocks, shouldn't you be fine
> with aBlock outerContext tempsAndValues?


Yes, thanks for this pointer. It seems that the #tempBindings
implementation I got from it works for me at this point (it is attached).

Stef



Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Stéphane Rollandin
In reply to this post by Christoph Thiede
> PS: Just saw your screenshot. If you do not need to access
> temporaries/args that are local to the blocks, shouldn't you be fine
> with aBlock outerContext tempsAndValues?

Yes, thanks for this pointer. It seems that the #tempBindings
implementation I got from it works for me at this point (it is attached,
this time...).

Stef





BlockClosure-tempBindings.st (518 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Eliot Miranda-2
In reply to this post by Stéphane Rollandin
Hi Stef,

    take a look at ContextInspector and DebuggerMethodMap.  The clue is that the debugger correctly displays the names of block temporaries and values in the hi text inspector in the bottom left of a debugger.

The interface is not easy because of the indirect temp vector implementation of modified closed over temporaries.  I apologize for the complexity and inconvenience but it is key to achieving high performance context-to-stack mapping, which itself is key to efficient execution while retaining contexts with their many benefits.  Note that the indirect temp vector implementation of modified closed over temporaries is a standard one taken from lisp implementations.

_,,,^..^,,,_ (phone)

> On Apr 19, 2020, at 9:18 AM, Stéphane Rollandin <[hidden email]> wrote:
>
> Hello,
>
> Is there a way to map the temp variables stored in a BlockClosure with their names as they appear in the decompileString?
>
> For example we have:
>
>    | y |
>    y := 10.
>    [:x | y + x] basicAt: 1        "returns 10"
>
> and
>
>    | y |
>    y := 10.
>    [:x | y + x] decompileString    "returns '[:x | y + x]'"
>
>
> What I would like is something like
>
>    | y |
>    y := 10.
>    [:x | y + x] tempBindingAt: 1    "would return #y -> 10"
>
>
> Stef
>

Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Herbert König
In reply to this post by Stéphane Rollandin
Interesting class names! Care to give some hints?

Herbert

Am 20.04.2020 um 00:47 schrieb Stéphane Rollandin:
Here is a picture of what I want (it is from my custom explorer which happens to give an ok result in this specific case)

You can see that in there the 'alarms' set of blocks is displayed as a list of decompileStrings, and each temp vars such as 'aBlock' or 'aTimeLapse' is featured with its corresponding value.

Stef


    



Reply | Threaded
Open this post in threaded view
|

Re: Accessing temp variables bindings in a BlockClosure

Stéphane Rollandin
> Interesting class names! Care to give some hints?

Ahah:) It's from a 2D, top-down morphic roguelike game engine. What you
are seeing is the components-based AI architecture responsible for the
behavior of a snake.

Stef