[Vm-dev] Exploring the simulator (was Re: REPL image for simulation)

Ben Coman btc at openinworld.com
Sun Jun 12 06:35:18 UTC 2016


I am stepping for the first time through the CogVM, having [set break
selector...] forkAt:
After stepping in a few times I get to #activateCoggedNewMethod.
  CogVMSimulatorLSB(CoInterpreter)>>dispatchOn:in:
  CogVMSimulatorLSB(CoInterpreter)>>sendLiteralSelector1ArgBytecode
  CogVMSimulatorLSB(CoInterpreter)>>commonSendOrdinary
  CogVMSimulatorLSB(CoInterpreter)>>insternalExecuteNewMethod
  CogVMSimulatorLSB(CoInterpreter)>>activateCoggedNewMethod

Here from the code at the top.
    methodHeader := self rawHeaderOf: newMethod.
    self assert: (self isCogMethodReference: methodHeader).
    cogMethod := self cCoerceSimple: methodHeader to: #'CogMethod *'.
    methodHeader := cogMethod methodHeader.

I guess methodHeader's double assignment above is related to the
machine code frame having two addresses as Clement described...

>> On Mon, May 30, 2016 at 4:12 PM, Clément Bera <bera.clement at gmail.com> wrote:
>>> 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.
>>> 16r102BDD0 => in the heap. This is the bytecode version of the method. You can print it using [print oop...]

This time...
[print ext head frame] ==>
  16r101214 M BlockClosure>forkAt: 16r2FC420: a(n) BlockClosure
  16r101210: method:     16rBBF0  16rC4E948 16rC4E948: a(n) CompiledMethod

self rawHeaderOf: newMethod ==> 16rBBF0
So the "raw header" is the cogged method.

Looking at the output below, the space ship operator <-> seems to link
between cogged method headers like a call stack, except   #forkAt:
calls  #newProcess  which calls  #asContext

[print cog method for...] 16rBBF0 ==>
  16rBBF0 <-> 16rBC80: method: 16rC4E948 selector: 16r6CC798 forkAt:

[print cog method for...] 16rBC80 ==>
   16rBC80 <-> 16rBEA8: method: 16rC51970 prim 19 selector: 16r6D1620 newProcess

[print cog method for...] 16rBEA8 ==>
   16rBEA8 <->     16rBF28: method:   16rC518C0 selector:   16r76A600 asContext

However the links don't seem to go back up the call stack but forward,
to statements to be executed in the future.   So I am confused?

-------------

Considering further [print cog method for...] 16rBBF0 ==>
  16rBBF0 <-> 16rBC80: method: 16rC4E948 selector: 16r6CC798 forkAt:

[print oop...] 16r6CC798 ==>
   a(n) ByteSymbol nbytes 7  forkAt:

Clement early advised is the bytecode version of the method is this...
[print oop...] 16rC4E948 ==>
  16rC4E948: a(n) CompiledMethod nbytes 37
     16rBBF0  is in generated methods
   16r6D1620 #newProcess   16r6CC650 #priority:   16r6CC690 #resume
   16r6CC798 #forkAt:   16rAE5490 a ClassBinding #BlockClosure -> 16r0088D618
  16rC4E968:  70/112 D0/208 88/136 10/16 E1/225 87/135 D2/210 7C/124
  16rC4E970:  28/40 AF/175 BA/186 F3/243 20/32

Now I've been a bit slow on the uptake and only just realised, but to confirm...
the line 16r6CC798 is the one specifying the method as BlockClosure>>forkAt:

For the last two lines, I notice the numbers before the slash (70, 88,
10...) are the method bytecode, but what are the numbers after the
slash?

----------------

In #activeCoggedNewMethod: the second assignment to methodHeader
  ==> 16r208000B

which matches the mthhdr field of the raw header
[print cog method header for...] 16rBBF0 ==>
    BBF0
    objhdr: 8000000A000035
    nArgs: 1 type: 2
    blksiz: 90
    method: C4E948
    mthhdr: 208000B
    selctr: 6CC798=#forkAt:
    blkentry: 0
    stackCheckOffset: 5E/BC4E
    cmRefersToYoung: no cmIsFullBlock: no

What is "type: 2" ?

--------------------------

Stepping through to  Cogit>>ceEnterCogCodePopReceiverReg
I notice its protocol is "simulation only"
and it calls  "simulateEnilopmart:numArgs: ceEnterCogCodePopReceiverReg"
but I don't see any other implementors of #ceEnterCogCodePopReceiverReg.
Also there is a pragma <doNotGenerate>.

Obviously the real non-simulated VM works differently, but I can't
determine how.

btw, I have noticed that  ceEnterCogCodePopReceiverReg
   ==> 16r10B8
and [print cog method for...] 16r10B8
   ==> trampoline ceEnterCogCodePopReceiverReg

Is ceEnterCogCodePopReceiverReg provided by the platform C code?

---------------------------
Stepping through to simulateCogCodeAt:
it called processor singleStepIn:minimumAddress:readOnlyBelow:
which called BochsIA32Alien>>primitiveSingleStepInMemory:minimumAddress:readOnlyBelow:
     <primitive: 'primitiveSingleStepInMemoryMinimumAddressReadWrite'
       module: 'BochsIA32Plugin'
       error: ec>
     ^ec == #'inappropriate operation'
         ifTrue: [self handleExecutionPrimitiveFailureIn: memoryArray
                minimumAddress: minimumAddress]
         ifFalse: [self reportPrimitiveFailure]

and the debugger cursor was inside the ifTrue: statement.  I found I
didn't have bochs installed, but after installing bochs-2.6-2, I go
the same result. So could I get some background around this..

Also I'm curious how the simulator seemed to be running a CogVM before
bochs was installed. Perhaps since I was not debugging through it, the
machine code ran for real rather than being simulated.

cheers -ben


More information about the Vm-dev mailing list