[64 bits] Object pointers in jitted code

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

[64 bits] Object pointers in jitted code

melkyades
 
Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm). So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case. Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Cheers!
Pocho

--
Javier Pimás
Ciudad de Buenos Aires
Reply | Threaded
Open this post in threaded view
|

Re: [64 bits] Object pointers in jitted code

Clément Béra
 


On Wed, Feb 28, 2018 at 2:16 PM, Javier Pimás <[hidden email]> wrote:
 
Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm). So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case. Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Just generate & disassemble any method with literals from the Squeak image (in-image compilation workspace scripts) with different ISA and look at the disassembled code, it takes 1 second and you'll see by yourself how pointer size constants (literals) are dealt with. 

The ARM JIT dumps pointer size constants somewhere unreachable by machine code execution but near by (in-between jumps for example) and access it with PC-relative instructions, that's one good way to work around it.

Best,

Cheers!
Pocho

--
Javier Pimás
Ciudad de Buenos Aires




--
Clément Béra
Pharo consortium engineer
Bâtiment B 40, avenue Halley 59650 Villeneuve d'Ascq
Reply | Threaded
Open this post in threaded view
|

Re: [64 bits] Object pointers in jitted code

Eliot Miranda-2
In reply to this post by melkyades
 
Hi Javier,


> On Feb 28, 2018, at 5:16 AM, Javier Pimás <[hidden email]> wrote:
>
> Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm).

That's not quite right.  On x86_64 instructions can load 64-bit constants into registers.  What is restricted is loading/storing through a 64-bit immediate address.  That can only be done to/from %rax.  So when loading an arbitrary register from memory the JIT often generates sequences like:

    xchgq %r15,%rax
    moveq 123456789AB0,%rax
    xchgq %r15,%rax

> So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case.

Yes.  The easy way to see this is to use in-image compilation.  e.g. in a VMMaker.oscog image (scripts to build them being in the image directory) run the following with a Transcript open:

StackToRegisterMappingCogit
    genAndDis: Object>>#printOn: "includes 'a ' and 'an '"
    options: #(ObjectMemory Spur64BitCoMemoryManager)

and the generated machine code method will be output to the transcript.

> Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Yes, we should implement this and see how it compares.  It's not particularly compelling in x86_64 because we can load 64-bit immediates inline but performance might differ significantly.

> Cheers!
> Pocho
>
> --
> Javier Pimás
> Ciudad de Buenos Aires
Reply | Threaded
Open this post in threaded view
|

Re: [64 bits] Object pointers in jitted code

Eliot Miranda-2
In reply to this post by Clément Béra
 


On Feb 28, 2018, at 6:13 AM, Clément Bera <[hidden email]> wrote:



On Wed, Feb 28, 2018 at 2:16 PM, Javier Pimás <[hidden email]> wrote:
 
Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm). So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case. Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Just generate & disassemble any method with literals from the Squeak image (in-image compilation workspace scripts) with different ISA and look at the disassembled code, it takes 1 second and you'll see by yourself how pointer size constants (literals) are dealt with. 

The ARM JIT dumps pointer size constants somewhere unreachable by machine code execution but near by (in-between jumps for example) and access it with PC-relative instructions, that's one good way to work around it.

+1


Best,

Cheers!
Pocho

--
Javier Pimás
Ciudad de Buenos Aires




--
Clément Béra
Pharo consortium engineer
Bâtiment B 40, avenue Halley 59650 Villeneuve d'Ascq
Reply | Threaded
Open this post in threaded view
|

Re: [64 bits] Object pointers in jitted code

melkyades
In reply to this post by Eliot Miranda-2
 


On Wed, Feb 28, 2018 at 12:03 PM, Eliot Miranda <[hidden email]> wrote:

Hi Javier,


> On Feb 28, 2018, at 5:16 AM, Javier Pimás <[hidden email]> wrote:
>
> Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm).

That's not quite right.  On x86_64 instructions can load 64-bit constants into registers.  What is restricted is loading/storing through a 64-bit immediate address.  That can only be done to/from %rax.  So when loading an arbitrary register from memory the JIT often generates sequences like:

    xchgq %r15,%rax
    moveq 123456789AB0,%rax
    xchgq %r15,%rax


yes, I meant a solution like this. You also need a scratch register if you want to push a pointer but it's not a huge problem.
 
> So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case.

Yes.  The easy way to see this is to use in-image compilation.  e.g. in a VMMaker.oscog image (scripts to build them being in the image directory) run the following with a Transcript open:

StackToRegisterMappingCogit
    genAndDis: Object>>#printOn: "includes 'a ' and 'an '"
    options: #(ObjectMemory Spur64BitCoMemoryManager)


Nice! I'll try it
 
and the generated machine code method will be output to the transcript.

> Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Yes, we should implement this and see how it compares.  It's not particularly compelling in x86_64 because we can load 64-bit immediates inline but performance might differ significantly.

> Cheers!
> Pocho
>
> --
> Javier Pimás
> Ciudad de Buenos Aires



--
Javier Pimás
Ciudad de Buenos Aires
Reply | Threaded
Open this post in threaded view
|

Re: [64 bits] Object pointers in jitted code

melkyades
In reply to this post by Clément Béra
 


On Wed, Feb 28, 2018 at 11:13 AM, Clément Bera <[hidden email]> wrote:
 


On Wed, Feb 28, 2018 at 2:16 PM, Javier Pimás <[hidden email]> wrote:
 
Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm). So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case. Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Just generate & disassemble any method with literals from the Squeak image (in-image compilation workspace scripts) with different ISA and look at the disassembled code, it takes 1 second and you'll see by yourself how pointer size constants (literals) are dealt with. 

The ARM JIT dumps pointer size constants somewhere unreachable by machine code execution but near by (in-between jumps for example) and access it with PC-relative instructions, that's one good way to work around it.

The arm jit also seems to support the two approaches (CogInLineLiteralsARMCompiler, CogOutOfLineLiteralsARMCompiler), how do you do gc with inline literals there?


Best,

Cheers!
Pocho

--
Javier Pimás
Ciudad de Buenos Aires




--
Clément Béra
Pharo consortium engineer
Bâtiment B 40, avenue Halley 59650 Villeneuve d'Ascq




--
Javier Pimás
Ciudad de Buenos Aires
Reply | Threaded
Open this post in threaded view
|

Re: [64 bits] Object pointers in jitted code

Eliot Miranda-2
In reply to this post by melkyades
 
Hi Javier,

On Feb 28, 2018, at 7:33 AM, Javier Pimás <[hidden email]> wrote:

On Wed, Feb 28, 2018 at 12:03 PM, Eliot Miranda <[hidden email]> wrote:

Hi Javier,

> On Feb 28, 2018, at 5:16 AM, Javier Pimás <[hidden email]> wrote:
>
> Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm).

That's not quite right.  On x86_64 instructions can load 64-bit constants into registers.  What is restricted is loading/storing through a 64-bit immediate address.  That can only be done to/from %rax.  So when loading an arbitrary register from memory the JIT often generates sequences like:

    xchgq %r15,%rax
    moveq 123456789AB0,%rax
    xchgq %r15,%rax


yes, I meant a solution like this. You also need a scratch register if you want to push a pointer but it's not a huge problem.

On both x86_64 & ARM we dedicate a register that points at variables in the interpreter such as stackPointer, argumentCount et al.  See VarBaseReg (VarBaseRegister?).

> So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case.

Yes.  The easy way to see this is to use in-image compilation.  e.g. in a VMMaker.oscog image (scripts to build them being in the image directory) run the following with a Transcript open:

StackToRegisterMappingCogit
    genAndDis: Object>>#printOn: "includes 'a ' and 'an '"
    options: #(ObjectMemory Spur64BitCoMemoryManager)


Nice! I'll try it
 
and the generated machine code method will be output to the transcript.

> Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Yes, we should implement this and see how it compares.  It's not particularly compelling in x86_64 because we can load 64-bit immediates inline but performance might differ significantly.

> Cheers!
> Pocho
>
> --
> Javier Pimás
> Ciudad de Buenos Aires
--
Javier Pimás
Ciudad de Buenos Aires
Reply | Threaded
Open this post in threaded view
|

Re: [64 bits] Object pointers in jitted code

Eliot Miranda-2
In reply to this post by melkyades
 
Hi Javier,

On Wed, Feb 28, 2018 at 7:36 AM, Javier Pimás <[hidden email]> wrote:

On Wed, Feb 28, 2018 at 11:13 AM, Clément Bera <[hidden email]> wrote:
 
On Wed, Feb 28, 2018 at 2:16 PM, Javier Pimás <[hidden email]> wrote:
 
Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm). So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case. Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Just generate & disassemble any method with literals from the Squeak image (in-image compilation workspace scripts) with different ISA and look at the disassembled code, it takes 1 second and you'll see by yourself how pointer size constants (literals) are dealt with. 

The ARM JIT dumps pointer size constants somewhere unreachable by machine code execution but near by (in-between jumps for example) and access it with PC-relative instructions, that's one good way to work around it.

The arm jit also seems to support the two approaches (CogInLineLiteralsARMCompiler, CogOutOfLineLiteralsARMCompiler), how do you do gc with inline literals there?

With suitably layered abstractions.  The method map is traversed using Cogit>>#mapFor:performUntil:arg:.  mapObjectReferencesInMachineCode: is the entry point for GC and become.  e.g. a scavenge applies remapIfObjectRef:pc:hasYoung: via mapFor:performUntil:arg: to every method in the youngReferrers list (which drastically reduces the amount of machine code scanned in each scavenge; most methods don't have any references to young objects), whereas mapObjectReferencesInMachineCodeForFullGC applies #remapIfObjectRef:pc:hasYoung: via mapFor:performUntil:arg: to every machine code method, and to any object references in the generated run-time.


remapIfObjectRef:pc:hasYoung: has the following signature:

remapIfObjectRef: annotation pc: mcpc hasYoung: hasYoungPtr

If annotation is IsObjectReference then the literalsManager is asked to fetch and store literal referenced at pc via fetchLiteralAtAnnotatedAddress:using: and storeLiteral:atAnnotatedAddress:using:.  These in turn defer to the backEnd (an instance of the current CogCompilerClass, such as CogInLineLiteralsX64Compiler) to extract the address or literal from the machine code and store it back.  With in-line literals the address following the instruction is added to the map.  With out-of-line literals the address of the literal is added to the map.

Then once all relevant methods haver been processed the instruction cache is flushed and execution proceeds.


Best,

Cheers!
Pocho
--
Javier Pimás
Ciudad de Buenos Aires
--
Clément Béra
Pharo consortium engineer
Bâtiment B 40, avenue Halley 59650 Villeneuve d'Ascq
--
Javier Pimás
Ciudad de Buenos Aires

_,,,^..^,,,_
best, Eliot
Reply | Threaded
Open this post in threaded view
|

Re: [64 bits] Object pointers in jitted code

Guido Chari
In reply to this post by Eliot Miranda-2
 
Hi Eliot,

2018-02-28 16:03 GMT+01:00 Eliot Miranda <[hidden email]>:

Hi Javier,


> On Feb 28, 2018, at 5:16 AM, Javier Pimás <[hidden email]> wrote:
>
> Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm).

That's not quite right.  On x86_64 instructions can load 64-bit constants into registers.  What is restricted is loading/storing through a 64-bit immediate address.  That can only be done to/from %rax.  So when loading an arbitrary register from memory the JIT often generates sequences like:

    xchgq %r15,%rax
    moveq 123456789AB0,%rax
    xchgq %r15,%rax

> So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case.

Yes.  The easy way to see this is to use in-image compilation.  e.g. in a VMMaker.oscog image (scripts to build them being in the image directory) run the following with a Transcript open:

StackToRegisterMappingCogit
    genAndDis: Object>>#printOn: "includes 'a ' and 'an '"
    options: #(ObjectMemory Spur64BitCoMemoryManager)

and the generated machine code method will be output to the transcript.

There are plenty of scripts. I ran a few that failed while loading code. Could you point us to the one you are using?
 

> Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Yes, we should implement this and see how it compares.  It's not particularly compelling in x86_64 because we can load 64-bit immediates inline but performance might differ significantly.

> Cheers!
> Pocho
>
> --
> Javier Pimás
> Ciudad de Buenos Aires

Reply | Threaded
Open this post in threaded view
|

Re: [64 bits] Object pointers in jitted code

Clément Béra
 


On Fri, Mar 2, 2018 at 3:44 PM, Guido Chari <[hidden email]> wrote:
 
Hi Eliot,

2018-02-28 16:03 GMT+01:00 Eliot Miranda <[hidden email]>:

Hi Javier,


> On Feb 28, 2018, at 5:16 AM, Javier Pimás <[hidden email]> wrote:
>
> Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm).

That's not quite right.  On x86_64 instructions can load 64-bit constants into registers.  What is restricted is loading/storing through a 64-bit immediate address.  That can only be done to/from %rax.  So when loading an arbitrary register from memory the JIT often generates sequences like:

    xchgq %r15,%rax
    moveq 123456789AB0,%rax
    xchgq %r15,%rax

> So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case.

Yes.  The easy way to see this is to use in-image compilation.  e.g. in a VMMaker.oscog image (scripts to build them being in the image directory) run the following with a Transcript open:

StackToRegisterMappingCogit
    genAndDis: Object>>#printOn: "includes 'a ' and 'an '"
    options: #(ObjectMemory Spur64BitCoMemoryManager)

and the generated machine code method will be output to the transcript.

There are plenty of scripts. I ran a few that failed while loading code. Could you point us to the one you are using?

My normal workflow from loading is to run StackVMSimulator from VM simulation workspace, then Cog Simulator from VM simulation workspace, then in-image compilation from In-image compilation workspace. I frequently pick up a new image and annoy Eliot if it does not work, so normally things should be working. Sometimes the last one does not work if the first ones are not run first. In any case in-image compilation requires a VM with a processor simulator external plugins (else it fails on prim New CPU). To build such a VM go in the build folder and follow HowToBuild file instructions, especially the section on Bochs.

StackVMSimulator script looks like

| cos |
cos := StackInterpreterSimulator newWithOptions: #( ...
 
CogSimulator script looks like
| cos |
cos := CogVMSimulator newWithOptions: #(...

In-image compilation are the scripts using #genAndDis:options: 

 

> Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Yes, we should implement this and see how it compares.  It's not particularly compelling in x86_64 because we can load 64-bit immediates inline but performance might differ significantly.

> Cheers!
> Pocho
>
> --
> Javier Pimás
> Ciudad de Buenos Aires





--
Clément Béra
Pharo consortium engineer
Bâtiment B 40, avenue Halley 59650 Villeneuve d'Ascq
Reply | Threaded
Open this post in threaded view
|

Re: [64 bits] Object pointers in jitted code

Eliot Miranda-2
In reply to this post by Guido Chari
 
Hi Guidi,

On Mar 2, 2018, at 6:44 AM, Guido Chari <[hidden email]> wrote:

Hi Eliot,

2018-02-28 16:03 GMT+01:00 Eliot Miranda <[hidden email]>:

Hi Javier,


> On Feb 28, 2018, at 5:16 AM, Javier Pimás <[hidden email]> wrote:
>
> Hi! This time I'm investigating how cog jit handles pointers to objects in native code. In x86-32 its easier because you have immediates of the size of a pointer, but in x64 the immediates are restricted to 32bits (and I think less in arm).

That's not quite right.  On x86_64 instructions can load 64-bit constants into registers.  What is restricted is loading/storing through a 64-bit immediate address.  That can only be done to/from %rax.  So when loading an arbitrary register from memory the JIT often generates sequences like:

    xchgq %r15,%rax
    moveq 123456789AB0,%rax
    xchgq %r15,%rax

> So I wonder how people works around that, if using a movabs instruction every time you need a pointer or if doing something else. I found a mail in the list dated from 2011 (titled "questions about cog internals") where you (Eliot) said that pointers were inlined in jit code, but I don't know if that's still the case.

Yes.  The easy way to see this is to use in-image compilation.  e.g. in a VMMaker.oscog image (scripts to build them being in the image directory) run the following with a Transcript open:

StackToRegisterMappingCogit
    genAndDis: Object>>#printOn: "includes 'a ' and 'an '"
    options: #(ObjectMemory Spur64BitCoMemoryManager)

and the generated machine code method will be output to the transcript.

There are plenty of scripts. I ran a few that failed while loading code. Could you point us to the one you are using?

image/buildspurtrunk64vmmaker.sh
image/buildspurtrunkvmmaker.sh

 

> Looking at the slang code I found CogOutOfLineLiteralsX64Compiler, but it seems it is not used (yet?).

Yes, we should implement this and see how it compares.  It's not particularly compelling in x86_64 because we can load 64-bit immediates inline but performance might differ significantly.

> Cheers!
> Pocho
>
> --
> Javier Pimás
> Ciudad de Buenos Aires