Hi,
Ian Piumarta <[EMAIL PROTECTED]> writes:
> Something like this is highly desirable, just like the splitting of
> self and state into two selves and making information about the
> method available to it through the closure. I'm sure better
> solutions for all of these can be found, solutions that do not depend
> on information being passed redundantly in the vast majority of
> sends. I'm still unhappy about all two (or three ;) additional
> arguments beyond the original 'self'.
After working on this for a little while, I came to the opinion that
now would be a good time to introduce the "stack frame" object, and
stuff all those additional arguments in there, to be optimised out of
existence when safe to do so.
Your suggestions are valuable, but they are beyond my capacity right
now (they require too much platform-specific tweaking, and I only
really know Linux/i386). I'm more interested in first getting the API
right than in the optimal implementation, though. I did have an idea
for a portable prototype of the "stack frame" object, so I've
implemented that. The overview follows:
As with my other patchset, I introduced the following macros to
preserve my sanity by avoiding dependency on the argument layout (as
much as possible). These eliminate API changes in the *.st client
code, and there are only a handful of places to change in the *.k
files:
#define _imp_decl(ARG...) \
oop frame, oop state, oop self, ##ARG
_imp_decl is for use in function prototypes:
oop my_method(_imp_decl(int first_arg, char *second))
{
...
}
#define _imp_defframe(NAME, CLOSURE, SELF) \
_imp_defframe2(NAME, CLOSURE, SELF, SELF)
#define _imp_args2(FRAME, STATE, SELF, ARG...) \
(oop)FRAME, STATE, SELF, ##ARG
#define _imp_args(FRAME, SELF, ARG...) \
_imp_args2(FRAME, SELF, SELF, ##ARG)
typedef oop (*_imp_t)(_imp_decl(...));
Then, _send is defined as follows (_send2, _super, and other macros
follow naturally from this example):
#define _send(MSG, RCV, ARG...) ({ \
oop _r= (RCV); \
struct __closure *_c= _libid_bind((MSG), _r); \
_imp_defframe(_f, _c, r); \
(_c->method)(_imp_args(_f, _r, ##ARG));\
})
The _imp_defframe2 macro creates a stack frame object (or whatever
kind of first argument you want to send to _imp_args). If the current
calling convention is desired (passing through the closure), then you
would use:
#define _imp_defframe2(NAME, CLOSURE, STATE, SELF) \
oop NAME = (oop)(CLOSURE)
For my stack frame object patch, I use the following:
#define _imp_defframe2(NAME, CLOSURE, STATE, SELF) \
struct oop_frame NAME##_struct = {_frame_vtable, {CLOSURE}}; \
oop NAME = (oop)& NAME##_struct.frame
where the relevant data structures are:
struct t__frame
{
_closure_t *_closure;
};
struct oop_frame
{
oop vtable;
_frame_t frame;
};
The other optimisations you suggest could be implemented by changing
the compiler and macros, then adapting the methods exposed by the
_frame object. Currently, the frame's methods are only #_closure in
libid.c, with #_closure: and #new:state:self: in _object.st.
If you like this approach, I can easily push stateful_self into the
frame object as well.
> So rather than adding 'argc' to the implicit arguments in the
> signature of every method, I'd be tempted to remove '_closure' from
> the implicit args and build a different mechanism to supply both
> _closure' and 'argc' (and anything else you cannot predict needing
> beforehand) to just those methods that care about them. A first
> approximation could probably be done trivially, and safely, by saving
> this information in a thread-local variable.
If you consider "as a method argument" to be a highly optimised
version of thread-local storage, then I think I've done this. ;)
Looking forward to your comments,
--
Michael FIG <[EMAIL PROTECTED]> //\
http://michael.fig.org/ \//
_______________________________________________
fonc mailing list
[email protected]
http://vpri.org/mailman/listinfo/fonc