A small idea how to get closer to hardware with small efforts :)

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

A small idea how to get closer to hardware with small efforts :)

Igor Stasenko
Hello again,

it is about running a native code , stored in compiled methods.

All we need is:

a) allow code execution for object memory. On most platforms this is
trivial - just pass additional flags to virtual memory allocation
functions.
b) add a single primitive 'call a native code'
c) use a special compiled method trailer, which will store the native
code inside itself

Then we could place any native code inside a compiled method and use a
single primitive to run this code.
This is quite simple thing, given that both pharo and squeak adopted
method trailers, so
a primitive, before running the code, needs few checks:
 - a method's trailer format is valid (we could reserve a terminal
byte value for that)
 - a native code, placed inside a method trailer is targeted for same
platform as currently running on

if not, then primitive will simply fail, and interpreter will run the
method's bytecode, which , depending on a situation, can check if it
can recompile the code
(if platform doesn't match) or use a workaround.
The only limitation of such approach, that native code, placed in
compiled method should be relocate-agnostic, i.e.
never use absolute jumps, only relative ones and so on.

Also, we could force, that code using a specific calling convention,
so it will be easy to fetch values from stack and other useful stuff
from interpreter/object memory (like passing an interpreterProxy
pointer).
This could be a good answer in generating a trampoline code for
FFI/Alien on the fly.

What you think?

--
Best regards,
Igor Stasenko AKA sig.

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: A small idea how to get closer to hardware with small efforts :)

Igor Stasenko
Here the proof of concept implementation.

1. Build VM with a new primitive (in Interpreter-primitiveNativeCall.st)

2. run image with new VM
 - file-in a NativeCodeTrailers
 - then NativeCodeTests

I found that on my WinXP, i even haven't to change a platform-specific
code to run it - only this tiny primitive!!
Seems like someone put a right flags into memory allocation procedure already :)

If you look at primitive, it is quite primitive :)
The one thing, which bothers me above everything is a sanity check,
which should be done more appropriately.
A primitive checks that trailer contains a right platform code, and if
it contains something else, then it fails.
This is done, obviously, in order to prevent running a native code,
generated for different platform.
The problem, that VMMaker don't having any notion of platform code, to
my knowledge,
so i put there '1' for now. But for correct behavior, there should be
one, set by VMMaker at initialization,
so for different platforms, VM built for that platform will answer
different code, i.e. windoze32 = 1, linux32 = 2 ... and so on.

So, here the questions, which i like to be answered:
1. reserve a numbered primitive
2. discuss the calling convention
3. add a 'platform id' code to VMMaker, and let language side know ,
on which platform id VM currently runs on (through additional
primitive)

P.S. And yes. The ' MethodNativeCodeTest new testAnswer42 '  runs
flawlessly , at least on my box :)
And I'm already having an tiny assember lying over there , which i can
use for generating the native stuff ..
It would be cool to adapt this stuff for generating an FFI/Alien
trampoline code.

--
Best regards,
Igor Stasenko AKA sig.

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project

NativeCodeTrailers.1.cs (8K) Download Attachment
NativeCodeTests.2.cs (1K) Download Attachment
Interpreter-primitiveNativeCall.st (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: A small idea how to get closer to hardware with small efforts :)

David T. Lewis
On Mon, Apr 05, 2010 at 03:13:51PM +0300, Igor Stasenko wrote:
> Here the proof of concept implementation.


> So, here the questions, which i like to be answered:
> 1. reserve a numbered primitive

Probably a named primitive in the interpreter is best, see comment in
John's new primitiveMicrosecondClock. I don't think that there is any
performance implication once the primitive name has been resolved once.

> 2. discuss the calling convention
> 3. add a 'platform id' code to VMMaker, and let language side know ,
> on which platform id VM currently runs on (through additional
> primitive)

I'm not sure how to handle #3, but there are a lot of different CPUs
and operating systems out there, not to mention all the different modes
of say an Intel CPU. So it may not be trivial to answer the question
"can this snippet of compiled code be executed in my current runtime
environment".

Dave


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A small idea how to get closer to hardware with small efforts :)

Stéphane Ducasse
In reply to this post by Igor Stasenko
igor

I'm confused.
Do you want to write C code in our smalltalk editor? (as in Smalltalk/X)
Where the native code is coming?
Who compiles it?
Can I edit it?

Do you have a scenario in mind to help understanding what is your vision behind your suggestion?
Stef

On Apr 5, 2010, at 10:13 AM, Igor Stasenko wrote:

> Hello again,
>
> it is about running a native code , stored in compiled methods.
>
> All we need is:
>
> a) allow code execution for object memory. On most platforms this is
> trivial - just pass additional flags to virtual memory allocation
> functions.
> b) add a single primitive 'call a native code'
> c) use a special compiled method trailer, which will store the native
> code inside itself
>
> Then we could place any native code inside a compiled method and use a
> single primitive to run this code.
> This is quite simple thing, given that both pharo and squeak adopted
> method trailers, so
> a primitive, before running the code, needs few checks:
> - a method's trailer format is valid (we could reserve a terminal
> byte value for that)
> - a native code, placed inside a method trailer is targeted for same
> platform as currently running on
>
> if not, then primitive will simply fail, and interpreter will run the
> method's bytecode, which , depending on a situation, can check if it
> can recompile the code
> (if platform doesn't match) or use a workaround.
> The only limitation of such approach, that native code, placed in
> compiled method should be relocate-agnostic, i.e.
> never use absolute jumps, only relative ones and so on.
>
> Also, we could force, that code using a specific calling convention,
> so it will be easy to fetch values from stack and other useful stuff
> from interpreter/object memory (like passing an interpreterProxy
> pointer).
> This could be a good answer in generating a trampoline code for
> FFI/Alien on the fly.
>
> What you think?
>
> --
> Best regards,
> Igor Stasenko AKA sig.
>


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A small idea how to get closer to hardware with small efforts :)

Igor Stasenko
On 5 April 2010 16:49, Stéphane Ducasse <[hidden email]> wrote:
> igor
>
> I'm confused.
> Do you want to write C code in our smalltalk editor? (as in Smalltalk/X)

err.. no. why i would want that, if i can just generate native code directly?
We could use Exupery for generating it, with slight modifications.
Or implement different native code generator.

> Where the native code is coming?
> Who compiles it?
> Can I edit it?
>

There is no any implications where the native code comes from.
It could be from compiler, implemented in smalltalk, or may be stored
in some file.. not really matters.
And yes, you can edit the code and generate it dynamically.
If you look at example of how i did run a native code routine, it
creates a native code on the fly,

code :=  #(184 85 0 0 0 195) asByteArray.

trailer nativeCode: code platformId: 1.
method := (self class methodDict at: #theStub) copyWithTrailerBytes: trailer.

and then runs it, by invokind a generated method.
Here, the  #(184 85 0 0 0 195) is an x86 instructions:

mov eax, (42 << 1 +1)
ret

so, when you run it, a native routine returns a 42 smallinteger.

> Do you have a scenario in mind to help understanding what is your vision behind your suggestion?
> Stef
>
> On Apr 5, 2010, at 10:13 AM, Igor Stasenko wrote:
>
>> Hello again,
>>
>> it is about running a native code , stored in compiled methods.
>>
>> All we need is:
>>
>> a) allow code execution for object memory. On most platforms this is
>> trivial - just pass additional flags to virtual memory allocation
>> functions.
>> b) add a single primitive 'call a native code'
>> c) use a special compiled method trailer, which will store the native
>> code inside itself
>>
>> Then we could place any native code inside a compiled method and use a
>> single primitive to run this code.
>> This is quite simple thing, given that both pharo and squeak adopted
>> method trailers, so
>> a primitive, before running the code, needs few checks:
>> - a method's trailer format is valid (we could reserve a terminal
>> byte value for that)
>> - a native code, placed inside a method trailer is targeted for same
>> platform as currently running on
>>
>> if not, then primitive will simply fail, and interpreter will run the
>> method's bytecode, which , depending on a situation, can check if it
>> can recompile the code
>> (if platform doesn't match) or use a workaround.
>> The only limitation of such approach, that native code, placed in
>> compiled method should be relocate-agnostic, i.e.
>> never use absolute jumps, only relative ones and so on.
>>
>> Also, we could force, that code using a specific calling convention,
>> so it will be easy to fetch values from stack and other useful stuff
>> from interpreter/object memory (like passing an interpreterProxy
>> pointer).
>> This could be a good answer in generating a trampoline code for
>> FFI/Alien on the fly.
>>
>> What you think?
>>
>> --
>> Best regards,
>> Igor Stasenko AKA sig.
>>
>
>
> _______________________________________________
> Pharo-project mailing list
> [hidden email]
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>



--
Best regards,
Igor Stasenko AKA sig.

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: A small idea how to get closer to hardware with small efforts :)

Igor Stasenko
In reply to this post by David T. Lewis
On 5 April 2010 15:42, David T. Lewis <[hidden email]> wrote:

> On Mon, Apr 05, 2010 at 03:13:51PM +0300, Igor Stasenko wrote:
>> Here the proof of concept implementation.
>
>
>> So, here the questions, which i like to be answered:
>> 1. reserve a numbered primitive
>
> Probably a named primitive in the interpreter is best, see comment in
> John's new primitiveMicrosecondClock. I don't think that there is any
> performance implication once the primitive name has been resolved once.
>
this is true, but numbered primitive could be inlined into an interpret() loop.
Then this will make some difference :)

>> 2. discuss the calling convention
>> 3. add a 'platform id' code to VMMaker, and let language side know ,
>> on which platform id VM currently runs on (through additional
>> primitive)
>
> I'm not sure how to handle #3, but there are a lot of different CPUs
> and operating systems out there, not to mention all the different modes
> of say an Intel CPU. So it may not be trivial to answer the question
> "can this snippet of compiled code be executed in my current runtime
> environment".
>
Well, a 2 bytes for code gives us 65536 variants. If this is not
enough, we could use 32 bits for platform id code.
Also, i thinking , maybe we could use masks for platform id,
so, then one could generate/use the same native code for multiple
kinds of OS-es.
But then , a number of variants will be much more limited, because
platform id will be treated as a bit field, instead of integer value.

> Dave
>
>
>



--
Best regards,
Igor Stasenko AKA sig.

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: A small idea how to get closer to hardware with small efforts :)

Marcus Denker-4
In reply to this post by Igor Stasenko
Hi,

I always liked how Smalltalk X did it... they have

        -> an ivar in CompiledMethod that is the "native code pointer".
        -> Primitive methods are just methods that have this pointer set
             to the primitive in the vm.
        -> Methods with embedded C-code are compiled and linked with
             the Smtk->C cross-compiler, the pointer than points to that function
        -> the JIT just put a pointer to the code it generates.  

So they merge primitives / static compiling(+embedded c-code) *and* the JIT
into one not that ugly mechanism. In STX, the memory is managed by the VM, though (the
code is not allocated in the GCed object memory by the JIT).

So: Yes, I like this :-) and your mechanism is a nice way to get it easily integrated into the current
system.

Q: what happens when code is moved by the GC?

--
Marcus Denker  -- http://www.marcusdenker.de
INRIA Lille -- Nord Europe. Team RMoD.


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: A small idea how to get closer to hardware with small efforts :)

Igor Stasenko
On 6 April 2010 14:46, Marcus Denker <[hidden email]> wrote:

> Hi,
>
> I always liked how Smalltalk X did it... they have
>
>        -> an ivar in CompiledMethod that is the "native code pointer".
>        -> Primitive methods are just methods that have this pointer set
>             to the primitive in the vm.
>        -> Methods with embedded C-code are compiled and linked with
>             the Smtk->C cross-compiler, the pointer than points to that function
>        -> the JIT just put a pointer to the code it generates.
>
> So they merge primitives / static compiling(+embedded c-code) *and* the JIT
> into one not that ugly mechanism. In STX, the memory is managed by the VM, though (the
> code is not allocated in the GCed object memory by the JIT).
>
> So: Yes, I like this :-) and your mechanism is a nice way to get it easily integrated into the current
> system.
>
> Q: what happens when code is moved by the GC?
>
Yeah, it will break the whole thing :)
To avoid that, a native code should not issue any memory allocation,
which may cause GC.

Perhaps, there is a way to counter this , while still being able to
move the code.
A primitive could set a flag that its going to call a native code,
embedded into compiled method,
so, then, after GC, if this flag is set, VM knows, that memory
allocation is issued from native code,
and should fix the return address (1) on stack, before returning to
native code, which moved to the new code location:

primitive -> native code --(1)-> VM allocation procedure -> GC

(1) - a return address , which should be fixed.

> --
> Marcus Denker  -- http://www.marcusdenker.de
> INRIA Lille -- Nord Europe. Team RMoD.
>
>
> _______________________________________________
> Pharo-project mailing list
> [hidden email]
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>



--
Best regards,
Igor Stasenko AKA sig.

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: A small idea how to get closer to hardware with small efforts :)

Igor Stasenko
Okay, here the small snippet of code, which does the trick! :)

Compile it with:

 gcc calltest.c callgate.s -o calltest

Here, a fn1() and fn2()
is equal functions (almost), which imitating the native code, which
moved during the VM call.

And fnCallGate() is a special function, which needs to be called
instead of actual function,
which potentially could move our code.

extern void fnCallGate(void* fn, ...);

it take a first argument - a function which needs to be called, and
then rest of arguments (if any),
which belong to that function.

This gate function using another function, which returns a current
value of a method oop.
In terms of Squeak VM, this is a method oop, which it retrieving
before calling a VM function
and after calling it (interpreterProxy->primitiveMethod).
So, in case if method oop is moved during GC, it will change the
return address by the same offset
as a difference between old method oop value and new one.

And so, with this trick, a native code could safely call any VM
function (through a gate function)
without the risk that if native code is moved during GC, it will
return to wrong address and cause a system crash.

On 6 April 2010 23:49, Igor Stasenko <[hidden email]> wrote:

> On 6 April 2010 14:46, Marcus Denker <[hidden email]> wrote:
>> Hi,
>>
>> I always liked how Smalltalk X did it... they have
>>
>>        -> an ivar in CompiledMethod that is the "native code pointer".
>>        -> Primitive methods are just methods that have this pointer set
>>             to the primitive in the vm.
>>        -> Methods with embedded C-code are compiled and linked with
>>             the Smtk->C cross-compiler, the pointer than points to that function
>>        -> the JIT just put a pointer to the code it generates.
>>
>> So they merge primitives / static compiling(+embedded c-code) *and* the JIT
>> into one not that ugly mechanism. In STX, the memory is managed by the VM, though (the
>> code is not allocated in the GCed object memory by the JIT).
>>
>> So: Yes, I like this :-) and your mechanism is a nice way to get it easily integrated into the current
>> system.
>>
>> Q: what happens when code is moved by the GC?
>>
> Yeah, it will break the whole thing :)
> To avoid that, a native code should not issue any memory allocation,
> which may cause GC.
>
> Perhaps, there is a way to counter this , while still being able to
> move the code.
> A primitive could set a flag that its going to call a native code,
> embedded into compiled method,
> so, then, after GC, if this flag is set, VM knows, that memory
> allocation is issued from native code,
> and should fix the return address (1) on stack, before returning to
> native code, which moved to the new code location:
>
> primitive -> native code --(1)-> VM allocation procedure -> GC
>
> (1) - a return address , which should be fixed.
>
>> --
>> Marcus Denker  -- http://www.marcusdenker.de
>> INRIA Lille -- Nord Europe. Team RMoD.
>>
>>
>> _______________________________________________
>> Pharo-project mailing list
>> [hidden email]
>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>>
>
>
>
> --
> Best regards,
> Igor Stasenko AKA sig.
>


--
Best regards,
Igor Stasenko AKA sig.

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project

callgate.s (886 bytes) Download Attachment
calltest.c (1K) Download Attachment