[ENH] Returning from context with sender == nil

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

[ENH] Returning from context with sender == nil

Igor Stasenko
 
Just an idea..

currently, when returning from bottom context, which has no sender, VM
generates a message #cannotReturn:

You can checking by invoking:

(thisContext privSender: nil). ^ 5

which is fine, except that i think we can extend this behavior for use
in cases when we leaving the normal "smalltalk" execution
back to some C caller, namely:

- callbacks
- a "message send" from C

upon return from method (or block) , an interpreter always checks if
sender of a context (a caller context) is valid MethodContext
instance.
i am thinking about very small change, which will provide additional
functionality:
 - if context's sender in non-valid MethodContext, but instance of
SmallInteger, then
   we just assume that given smallinteger is an address of C function
which should be called (by stripping the tag bit of course).

The function is of kind:

   void (fn*) (sqInt returnValue).

i.e. upon discovering sender is smallint, an interpreter will call
this function with return value as argument.

As an option for additional safety, we can avoid using pure function
address in small integer instance, but instead
use a registry of valid addresses (so that smallint will be an index
in a table, where cool hackers can register own "No-return" handlers).
Then VM should check if sender is small integer, and if it is a valid
registered index in  "No-return" handlers table, and if its ok, then
call that function,
otherwise, do as usual and raise "cannot return exception".

You may argue, that same functionality can be achieved by using
special primitive(s). Which is true for callbacks, since we definitely
control the
callback entry, and on return we can invoke special primitive to
return back to C caller.
But thinking about future, imagine that we have an API in VM, similar
to Objective-C, which allows you to send a message to any object
and get a result:

/* C code */
resultOop = vmSend(receiver, selector, 3 /*num args */ , arg1, arg2, arg3);

here, we cannot control the execution , since potentially a C caller
may pick any receiver , any selector, so the entry point, unlike
from callbacks are not controllable at smalltalk side. However if we
use the proposed trick, upon return from the context,
we can clearly detect that it is time to return to C caller and handle
it accordingly.

What you think?

--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: [ENH] Returning from context with sender == nil

David T. Lewis
 
On Mon, May 07, 2012 at 08:27:43AM +0200, Igor Stasenko wrote:

>  
> Just an idea..
>
> currently, when returning from bottom context, which has no sender, VM
> generates a message #cannotReturn:
>
> You can checking by invoking:
>
> (thisContext privSender: nil). ^ 5
>
> which is fine, except that i think we can extend this behavior for use
> in cases when we leaving the normal "smalltalk" execution
> back to some C caller, namely:
>
> - callbacks
> - a "message send" from C
>
> upon return from method (or block) , an interpreter always checks if
> sender of a context (a caller context) is valid MethodContext
> instance.
> i am thinking about very small change, which will provide additional
> functionality:
>  - if context's sender in non-valid MethodContext, but instance of
> SmallInteger, then
>    we just assume that given smallinteger is an address of C function
> which should be called (by stripping the tag bit of course).
>
> The function is of kind:
>
>    void (fn*) (sqInt returnValue).
>
> i.e. upon discovering sender is smallint, an interpreter will call
> this function with return value as argument.

If you are certain that you will never want your VM to run on a 64-bit
platform, then you can use usqInt to represent a machine address for
32-bit addressing. But it is dangerous to assume SmallInteger, which
is only 31 bits of address space, so this may not work even on a 32-bit
platform. You might be able to treat the 31-bit value as an offset
relative to some base address (i.e. a 32- or 64-bit base address plus
31 bit offset), which seems likely to work on most platforms but still
sounds risky to me.

(BTW, this is the kind of issue that currently causes FFI and all of
the plugins that depend on SurfacePlugin to be broken on 64-bit platforms.
It's an easy thing to do, and very hard to fix the problem once you have
an installed base of users.)

>
> As an option for additional safety, we can avoid using pure function
> address in small integer instance, but instead
> use a registry of valid addresses (so that smallint will be an index
> in a table, where cool hackers can register own "No-return" handlers).
> Then VM should check if sender is small integer, and if it is a valid
> registered index in  "No-return" handlers table, and if its ok, then
> call that function,
> otherwise, do as usual and raise "cannot return exception".

A table of handler addresses would work. You would of course need to
protect access to the table with a mutex.

>
> You may argue, that same functionality can be achieved by using
> special primitive(s). Which is true for callbacks, since we definitely
> control the
> callback entry, and on return we can invoke special primitive to
> return back to C caller.
> But thinking about future, imagine that we have an API in VM, similar
> to Objective-C, which allows you to send a message to any object
> and get a result:
>
> /* C code */
> resultOop = vmSend(receiver, selector, 3 /*num args */ , arg1, arg2, arg3);
>
> here, we cannot control the execution , since potentially a C caller
> may pick any receiver , any selector, so the entry point, unlike
> from callbacks are not controllable at smalltalk side. However if we
> use the proposed trick, upon return from the context,
> we can clearly detect that it is time to return to C caller and handle
> it accordingly.
>
> What you think?

Interesting idea. Sounds dangerous too ;-)

>
> --
> Best regards,
> Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: [ENH] Returning from context with sender == nil

Igor Stasenko

On 7 May 2012 14:15, David T. Lewis <[hidden email]> wrote:

>
> On Mon, May 07, 2012 at 08:27:43AM +0200, Igor Stasenko wrote:
>>
>> Just an idea..
>>
>> currently, when returning from bottom context, which has no sender, VM
>> generates a message #cannotReturn:
>>
>> You can checking by invoking:
>>
>> (thisContext privSender: nil). ^ 5
>>
>> which is fine, except that i think we can extend this behavior for use
>> in cases when we leaving the normal "smalltalk" execution
>> back to some C caller, namely:
>>
>> - callbacks
>> - a "message send" from C
>>
>> upon return from method (or block) , an interpreter always checks if
>> sender of a context (a caller context) is valid MethodContext
>> instance.
>> i am thinking about very small change, which will provide additional
>> functionality:
>>  - if context's sender in non-valid MethodContext, but instance of
>> SmallInteger, then
>>    we just assume that given smallinteger is an address of C function
>> which should be called (by stripping the tag bit of course).
>>
>> The function is of kind:
>>
>>    void (fn*) (sqInt returnValue).
>>
>> i.e. upon discovering sender is smallint, an interpreter will call
>> this function with return value as argument.
>
> If you are certain that you will never want your VM to run on a 64-bit
> platform, then you can use usqInt to represent a machine address for
> 32-bit addressing. But it is dangerous to assume SmallInteger, which
> is only 31 bits of address space, so this may not work even on a 32-bit
> platform. You might be able to treat the 31-bit value as an offset
> relative to some base address (i.e. a 32- or 64-bit base address plus
> 31 bit offset), which seems likely to work on most platforms but still
> sounds risky to me.
>
> (BTW, this is the kind of issue that currently causes FFI and all of
> the plugins that depend on SurfacePlugin to be broken on 64-bit platforms.
> It's an easy thing to do, and very hard to fix the problem once you have
> an installed base of users.)
>
>>
>> As an option for additional safety, we can avoid using pure function
>> address in small integer instance, but instead
>> use a registry of valid addresses (so that smallint will be an index
>> in a table, where cool hackers can register own "No-return" handlers).
>> Then VM should check if sender is small integer, and if it is a valid
>> registered index in  "No-return" handlers table, and if its ok, then
>> call that function,
>> otherwise, do as usual and raise "cannot return exception".
>
> A table of handler addresses would work. You would of course need to
> protect access to the table with a mutex.
>

Yes, after thinking a bit, actually table is the only way. Because if
image will be snapshotted,
preserving such exotic context state(s), then on next session it may
simply crash, because
the address of given function may change, or it may simply not exist.

>>
>> You may argue, that same functionality can be achieved by using
>> special primitive(s). Which is true for callbacks, since we definitely
>> control the
>> callback entry, and on return we can invoke special primitive to
>> return back to C caller.
>> But thinking about future, imagine that we have an API in VM, similar
>> to Objective-C, which allows you to send a message to any object
>> and get a result:
>>
>> /* C code */
>> resultOop = vmSend(receiver, selector, 3 /*num args */ , arg1, arg2, arg3);
>>
>> here, we cannot control the execution , since potentially a C caller
>> may pick any receiver , any selector, so the entry point, unlike
>> from callbacks are not controllable at smalltalk side. However if we
>> use the proposed trick, upon return from the context,
>> we can clearly detect that it is time to return to C caller and handle
>> it accordingly.
>>
>> What you think?
>
> Interesting idea. Sounds dangerous too ;-)
>

Well, an alternative is boring:
 - another way of implementing a vmSend() functionality
is to create a fresh context with message sent to fixed point at language side,
like Alien callback enter code does. But this means adding more
entries to special objects array
which is IMO a much more heavyweight contract between VM and image,
comparing to what i propose.


--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: [ENH] Returning from context with sender == nil

Eliot Miranda-2
In reply to this post by Igor Stasenko
 


On Sun, May 6, 2012 at 11:27 PM, Igor Stasenko <[hidden email]> wrote:

Just an idea..

currently, when returning from bottom context, which has no sender, VM
generates a message #cannotReturn:

You can checking by invoking:

(thisContext privSender: nil). ^ 5

which is fine, except that i think we can extend this behavior for use
in cases when we leaving the normal "smalltalk" execution
back to some C caller, namely:

- callbacks
- a "message send" from C

upon return from method (or block) , an interpreter always checks if
sender of a context (a caller context) is valid MethodContext
instance.
i am thinking about very small change, which will provide additional
functionality:
 - if context's sender in non-valid MethodContext, but instance of
SmallInteger, then
  we just assume that given smallinteger is an address of C function
which should be called (by stripping the tag bit of course).

This completely breaks context-to-stack mapping in the COg VM where a SmallInteger in the sender field is used to identify a context's frame's frame pointer.  This is hidden from the image by the VM.  Whenever one accesses the sender field form the image the VM computes the actual sender object (nil or a context).

It is also unnecessary; return from callback can be performed by invoking a primitive, as happens in the Alien callbacks.  It is easy to establish an activation as the sender of the callback activation which receives the result of the callback activation and returns it to the callback via the primitive.  i.e.

Alien class>>invokeCallbackContext: vmCallbackContextAddress "<Integer>" "^<FFICallbackReturnValue>"
"The low-level entry-point for callbacks sent from the VM/IA32ABI plugin.
Return via primReturnFromContext:through:.  thisContext's sender is the
call-out context."
| callbackAlien type |
callbackAlien := (Smalltalk wordSize = 4
ifTrue: [VMCallbackContext32]
ifFalse: [VMCallbackContext64])
atAddress: vmCallbackContextAddress.
[type := Callback evaluateCallbackForContext: callbackAlien]
ifCurtailed: [self error: 'attempt to non-local return across a callback'].
type ifNil:
[type := 1. callbackAlien wordResult: -1].
callbackAlien primReturnAs: type fromContext: thisContext

VMCallbackContext32/VMCallbackContext64>>primReturnAs: typeCode "<SmallInteger>" fromContext: context "<MethodContext>"
<primitive: 'primReturnAsFromContextThrough' module: 'IA32ABI' error: ec>
^self primitiveFailed

So please, no.
 

The function is of kind:

  void (fn*) (sqInt returnValue).

i.e. upon discovering sender is smallint, an interpreter will call
this function with return value as argument.

As an option for additional safety, we can avoid using pure function
address in small integer instance, but instead
use a registry of valid addresses (so that smallint will be an index
in a table, where cool hackers can register own "No-return" handlers).
Then VM should check if sender is small integer, and if it is a valid
registered index in  "No-return" handlers table, and if its ok, then
call that function,
otherwise, do as usual and raise "cannot return exception".

You may argue, that same functionality can be achieved by using
special primitive(s). Which is true for callbacks, since we definitely
control the
callback entry, and on return we can invoke special primitive to
return back to C caller.
But thinking about future, imagine that we have an API in VM, similar
to Objective-C, which allows you to send a message to any object
and get a result:

/* C code */
resultOop = vmSend(receiver, selector, 3 /*num args */ , arg1, arg2, arg3);

here, we cannot control the execution , since potentially a C caller
may pick any receiver , any selector, so the entry point, unlike
from callbacks are not controllable at smalltalk side. However if we
use the proposed trick, upon return from the context,
we can clearly detect that it is time to return to C caller and handle
it accordingly.

What you think?

--
Best regards,
Igor Stasenko.



--
best,
Eliot