So the entries of interest for highlighting are

Debugger>>contentsSelection
Debugger>>pcRange
CompiledMethod>>debuggerMap
DebuggerMethodMap class>>forMethod:
DebuggerMethodMap>>rangeForPC:contextIsActiveContext:

Then you see the DebuggerMethodMap>>forMethod:methodNode: takes both a
CompiledMethod and its #methodNode.
CompiledMethod>>methodNode invokes the Parser to get the
AbstractSyntaxTree from method source, and if it ever fails ends up by
trying to decompile the byteCodes.

This is the easy part. Now we to deal with #abstractPCForConcretePC:
and #abstractSourceMap.

By reading CompiledMethod>>abstractPCForConcretePC: you should quickly
understand that a concrete PC is a byte offset of current byteCode
(the offsets displayed in the byteCode view) while the abstractPC is
just the rank of current byteCode in the list of byteCodes
instructions composing the CompiledMethod. This is just because
"byteCodes" may spread on several bytes beside their name...
This will use InstructionStream and InstructionClient which are just
an iterator and a sort of visitor on byteCode instructions.
So this is not really interesting.

The more interesting part is #abstractSourceMap
There is a first step to obtain CompiledMethod>>rawSourceRangesAndMethodDo:
This is the most important part.
The rest is again a mapping from concretePC (instruction byte offset)
to abstractPC (instruction rank).
And some build of a dictionary mapping instruction rank (abstractPC)
-> selected range.

Note that the last trick seems to use a regenerated CompiledMethod
(theMethodToScan) rather than the original CompiledMethod. There is no
assertion whether these two are equivalent or not. A priori, they
should, unless the Compiler changed since last compilation or if its
behaviour is affected by some Preferences... Would we introduce some
customizable Compiler optimizations that this could become a problem
(We would then add to map decompiled AST to source code AST, probably
with guesses, unless the CompiledMethod would contain debugger
friendly hints...)
We will consider this is not a problem by now.

So let's now concentrate on rawSourceRangesAndMethodDo:
The nice thing is that you now can just debug this

(ClosureTests>>#testToDoOutsideTemp) methodNode
rawSourceRangesAndMethodDo: [:rs :mth | ]

and see how it goes in Squeak. I did not look in Pharo yet, but I
would be amazed to see it much different.
It's now late, and my spare time is off, but you have clues to get
more insights. I wish you good debugging, and come back to me if it
ever goes in deeper complications.

Cheers

Nicolas

2011/8/24 Michael Roberts <[email protected]>:
>
>>
>> Ok I'm curious to know then.
>
> Here is a little trace from this example method:
>
> toDoOutsideTemp
> | temp collection |
> collection := OrderedCollection new.
> 1 to: 5 do: [ :index |
> temp := index.
> collection add: [ temp ] ]
>
> Trace is start,stop position of the highlight for each 'step over'.
>
> Whilst the numbers are hard to visualise, below you can see how they
> slightly diverge.
> Left Pharo  Right  Squeak
>
> 50, 73     71, 73       diff
> 71, 73     71, 73
> 50, 73     50, 73
> 108, 115   79, 121      diff
> 79, 121    79, 121
> 108, 115   108, 115
> 132, 144   132, 144
> 147, 146   146, 146     (diff negative size means no highlight)
> 146, 146   146, 146
> 79, 121    79, 121
> 108, 115   108, 115
> 132, 144   132, 144
> 147, 146   146, 146
> 146, 146   146, 146
> 79, 121    79, 121
> 108, 115   108, 115
> 132, 144   132, 144
> 147, 146   146, 146
> 146, 146   146, 146
> 79, 121    79, 121
> 108, 115   108, 115
> etc...
> For example the first difference is because Pharo shows the whole assignment
> of the first line as the first send, even though it is not.
> The second difference is that Pharo shows the assignment inside the block as
> the first highlight of the loop even though the to:do should be
> highlighted....but both Pharo & Squeak get the to:do: wrong when they choose
> to show it.
> hope you get the idea...
> Mike

Reply via email to