[Vm-dev] Exploring the simulator (was Re: REPL image for
simulation)
Clément Bera
bera.clement at gmail.com
Mon May 30 15:35:01 UTC 2016
I did a post out of this thread:
https://clementbera.wordpress.com/2016/05/30/simulating-the-cog-vm/
On Mon, May 30, 2016 at 4:12 PM, Clément Bera <bera.clement at gmail.com>
wrote:
> Hi !
>
> On Mon, May 30, 2016 at 2:39 PM, Ben Coman <btc at openinworld.com> wrote:
>
>>
>> On Sun, May 29, 2016 at 10:14 AM, Ben Coman <btc at openinworld.com> wrote:
>> > Hi Clement, Thanks for your detailed reply. I particularly liked your
>> > warm up exercises. Goal directed learning is better than general
>> > browsing.
>> >
>> > On Tue, May 24, 2016 at 1:29 AM, Clément Bera <bera.clement at gmail.com>
>> wrote:
>> >>
>> >> Hi Ben,
>> >>
>> >> The REPL image expects chunk format. Hence you need to write "3 + 4 !"
>> >>
>> >> To get warmed-up:
>> >> 1) Inspect the object memory, then look for the first class table page
>> instance variable. It's an oop referencing an array, try in the simulator
>> to "printOop:" the address of the first class table page that you found. It
>> should print it in the Transcript, the first entries are immediate, in
>> Spur32 SmallInteger/Character/SmallInteger.
>> >
>> > The inspector showed a Spur32MMLECoSimulator and classTableFirstPage
>> > held 16r5311F8. Plugging that into [print oop...] showed...
>>
>> 16r5311F8: a(n) Array
>> 16r52D108 nil 16r15C3A50 class SmallInteger 16r878D70 class
>> Character 16r15C3A50 class SmallInteger
>> 16r1111DC0 class SmallFloat64 16r52D108 nil 16r52D108 nil
>> 16r52D108 nil
>> 16r52D108 nil 16r52D108 nil 16r52D108 nil 16r52D108 nil
>> 16r52D108 nil 16r52D108 nil 16r52D108 nil 16r52D108 nil
>> 16r87AE60 class Array 16r52D108 nil 16r52D108 nil 16r52D108 nil
>> 16r52D108 nil 16r52D108 nil 16r52D108 nil 16r52D108 nil
>> 16r52D108 nil 16r52D108 nil 16r52D108 nil 16r52D108 nil
>> 16r52D108 nil 16r52D108 nil 16r52D108 nil 16r52D108 nil
>> 16r878C58 class LargeNegativeInteger 16r878C90 class
>> LargePositiveInteger 16r10AEAE8 class BoxedFloat64 16r879438 class
>> Message
>
>
>> All the nils I guess are due to the class table being a hash map?
>>
>> Is there some way from within the simulation to reference an object by
>> its hex number. For example, to use the size of that array from
>> within the simulation, something like...
>>
>> classTableSize := 16r5311F8 objectFromHex size
>>
>
> You got the right result. The the class table is a linked list of pages,
> each page being an array. The first page, shown here, is reserved for
> frequently used classes.
>
> Indexes 0-15 are reserved for tagged object.
> Indexes 16-32 are reserved for hidden classes. Typically the class table
> pages are instances of Array, but the use index 16 so the VM know they are
> hidden.
> The rest is for real classes that are frequently used. There are many nils
> so we have free space for new features. It's not a hash map.
>
> I don't think things like that exists: *classTableSize := 16r5311F8
> objectFromHex size. *For oops debugging features are tied to printing
> through the simulator instance right now. However there is something like
> that in the JIT. In the machine code zone we can access part of the bytes
> as CogMethodSurrogate and its subclasses and in the stack we can do the
> same for stack pages with the corresponding surrogate. In this case one can
> do something like:
> CogMethodSurrogate at: 16r51578 objectMemory: objectMemory cogit: cogit
> And then one can ask the surrogate things like:
> surrogate cmRefersToYoung
> And it reads the correct bytes for you, in this case answering if the cog
> method has a reference to a young object.
>
>
>> >
>> >
>> >> 2) print the active stack, look for the method's address. Try to print
>> it as an oop, and if it tells you "address in the machine code zone", print
>> the cog method and its machine code instead.
>>
>> I presume is the active stack is
>> [print call stack] which produces...
>>
>> 16r1012F8 M MultiByteFileStream(StandardFileStream)>basicNext
>> 16r1E7408: a(n) MultiByteFileStream
>> 16r101334 M UTF8TextConverter>nextFromStream: 16r1EA418: a(n)
>> UTF8TextConverter
>> 16r10135C M MultiByteFileStream>next 16r1E7408: a(n) MultiByteFileStream
>> 16r10138C I MultiByteFileStream(PositionableStream)>nextChunkNoTag
>> 16r1E7408: a(n) MultiByteFileStream
>> 16r1013B0 I StdioListener>run 16r1E7C98: a(n) StdioListener
>> 16r1013D0 I [] in UndefinedObject>(nil) 16r52D108: a(n) UndefinedObject
>> 16r1013F0 I [] in BlockClosure>newProcess 16r1E7E00: a(n) BlockClosure
>> ---------
>>
>> [print oop...] 16r1012F8 tells me...
>> 16r1012F8 is in the stack zone
>>
>> [print cog method for...] 16r1012F8 tells me...
>> not a method
>>
>> [print mc/cog frame] says...
>> Assertion failed
>> with debugger at CogVMSimulatorLSD(CoInterpreter)>>isMachineCodeFrame:
>>
>> So I seem to be missing something.
>>
>>
>> I restarted the simulator and this time...
>> [print call stack...]
>> 16r1012F8 M MultiByteFileStream(StandardFileStream)>basicNext
>> 16r2A1BA8: a(n) MultiByteFileStream
>> 16r101334 M UTF8TextConverter>nextFromStream: 16r2A2188: a(n)
>> UTF8TextConverter
>> 16r10135C M MultiByteFileStream>next 16r2A1BA8: a(n) MultiByteFileStream
>> 16r10138C I MultiByteFileStream(PositionableStream)>nextChunkNoTag
>> 16r2A1BA8: a(n) MultiByteFileStream
>> 16r1013B0 I StdioListener>run 16r2A1B00: a(n) StdioListener
>> 16r1013D0 I [] in UndefinedObject>(nil) 16r52D108: a(n) UndefinedObject
>> 16r1013F0 I [] in BlockClosure>newProcess 16r2A1690: a(n) BlockClosure
>> ----------
>>
>> [print oop...] 16r1012F8
>> 16r1012F8 is in the stack zone
>>
>> [print oop...] 16r2A1BA8
>> 16r2A1BA8: a(n) MultiByteFileStream
>> 16r2A2740
>> '????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????'
>> 16r1 =0 (16r0) 16r1 =0 (16r0) 16r52D108 nil
>> 16r52D108 nil 16r52D118 false 16r9AA1E8 #stdin 16r24CC18 a
>> ByteArray
>> 16r2A2728 '?' 16r52D108 nil 16r2A2188 an UTF8TextConverter
>> 16r6DF1D8 #lf
>> 16r52D128 true
>> -----------
>>
>> Now after doing 3+4! several times,
>> [print call stack...] produces...
>> 16r101300 M MultiByteFileStream(StandardFileStream)>basicNext
>> 16r2A1BA8: a(n) MultiByteFileStream
>> 16r10133C M UTF8TextConverter>nextFromStream: 16r2A2188: a(n)
>> UTF8TextConverter
>> 16r101364 M MultiByteFileStream>next 16r2A1BA8: a(n) MultiByteFileStream
>> 16r10138C M MultiByteFileStream(PositionableStream)>nextChunkNoTag
>> 16r2A1BA8: a(n) MultiByteFileStream
>> 16r1013B0 I StdioListener>run 16r2A1B00: a(n) StdioListener
>> 16r1013D0 I [] in UndefinedObject>(nil) 16r52D108: a(n) UndefinedObject
>> 16r1013F0 I [] in BlockClosure>newProcess 16r2A1690: a(n) BlockClosure
>>
>> btw, What is the meaning of the M and I in the second column? I
>> notice that 16r10138C has changed from an I to a M.
>>
>> Also the address associated with basicNext changed from 16r1012F8 to
>> 16r101300. Can some meaning be inferred from that?
>>
>
> Some explanations are needed here :-)
>
> The M or I at the beginning of the printing are for 'Interpreted frame' or
> 'Machine code frame'.
>
> When you do [print call stack], you print the list of stack frame in the
> current stack. For example,
> 16r101300 M MultiByteFileStream(StandardFileStream)>basicNext
> means that:
> - the stack frame address in the stack zone is 16r101300
> - the machine code version of the method is executed in this frame (M and
> not I).
> - the receiver has the type MultiByteFileStream
> - the stack frame on top of the stack is the activation for the method
> StandardFileStream>>basicNext
>
> Now what you tried to do is to print the frame as a method, and that won't
> work (It's not obvious and my exercise was not very precised, sorry).
>
> You can use [print frame ...] and put the frame's hex to print it.
> Alternatively, asyou usually want the top (a.k.a. head) frame, you can
> directly use [print ext head frame] if it's a machine code frame.
>
> That should print something like that (I print a random frame here):
> 16r103160: arg1: 16r8239 =16668(16r411C)
> 16r10315C: arg2: 16r825D =16686(16r412E)
> 16r103158: arg3: 16r2E21C0 =a(n) Point
> 16r103154: arg4: 16r9BC480 =a(n) StrikeFont
> 16r103150: arg5: 16r1 =0(16r0)
> 16r10314C: caller ip: 16r564E0=353504
> 16r103148: saved fp: 16r103184=1061252
> 16r103144: method: 16r51578 16r102BDD0 16r102BDD0: a(n)
> CompiledMethod
> 16r103144: mcfrm flags: 16r0 numArgs: 6 noContext notBlock
> 16r103140: context: 16r52D108 nil
> 16r10313C: receiver: 16r2E0078 a GrafPort
> 16r103138: stck: 16r2E0078 a GrafPort
> 16r103134: stck: 16r1A115D0
>
> Now that you've print the frame, you can see the method addresses in this
> line:
> 16r103144: method: 16r51578 16r102BDD0 16r102BDD0: a(n)
> CompiledMethod.
> This is a machine code frame, so the method has two addresses:
> 16r51578 => in generated method, so you need to use
> [disassembleMethod/trampoline...] and write down the hex to see the
> disassembly. (Toggle Transcript first and open a large Transcript if you do
> that).
> 16r102BDD0 => in the heap. This is the bytecode version of the method.
> You can print it using [print oop...]
>
>
> Ok ! One last warm-up exercise:
>
> 3) When the simulator has started and the REPL window has popped up,
> select [single step]. Then enter something in the REPL window and execute
> it. Once done, do [report recent instructions]. You should be able to see
> in the Transcript the last 100 machine instruction with the register state
> in-between each instruction.
>
> I think I should write down those exercise as a blog post...
>
>
>
>
>
>> cheers -ben
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20160530/2d773f1f/attachment-0001.htm
More information about the Vm-dev
mailing list