Did you ever look at the "Cheney on the MTA" approach to continuations?
 This is how Chicken Scheme does things, they seem relatively happy with it.

http://home.pipeline.com/~hbaker1/CheneyMTA.html

It allows you to have full continuations in a fairly portable way, even for
functions.

One could imagine a system whereby functions are converted to "Cheney on
the MTA" style if they use the continuation related features, and continue
to be "normal" C/C++ functions if they don't.



On Mon, Nov 19, 2012 at 5:45 PM, john skaller <skal...@users.sourceforge.net
> wrote:

> I will post some of the relevant algorithms to see what
> can be done. If you missed it: there's an issue with
> service calls (needed to do synchronous channel I/O)
> in generators: in principle functions use the machine
> stack for return addresses and the C model of returning
> values, which conflicts with the ability to read or write
> an schannel because service calls currently require
> returning control to the scheduler (with an actual C level
> return). You cannot return to the scheduler unless you were
> called by the scheduler!
>
> This has been an ongoing thorn. The problem is created by a
> conflict between the desire for flexibility the spaghetti stack
> provides versus the performance and compatibility provided
> by the machine stack. Machine stack swapping cannot be
> done portably other than be use of pre-emptive threading.
>
> Inlining functions gets rid of the call/return boundary causing
> the machine stack barrier to evaporate. Here is the inlining
> rule for functions:
>
>           let inline_choice =
>             can_inline &&
>               not (mem `NoInline props) &&
>               (
>                 mem `Inline props ||
>                 length exes <= syms.compiler_options.max_inline_length
>               ) &&
>              (
>                 (* inline a non-recursive function *)
>                 not (Flx_call.is_recursive_call uses callee callee)
>                 ||
>
>                 (* inline a recursive call to a recursive child *)
>                 Flx_call.is_recursive_call uses caller callee &&
>                 Flx_bsym_table.is_child bsym_table caller callee
>              )
>           in
>
> The algorithm first checks if it is "possible" to inline the function.
> If it is, and inlining is not explicitly excluded by the programmer,
> then,  if inlining is explicitly requested by the programmer OR
> the current size of the callee is under the inline limit THEN
> if the function call is not recursive inline it, if it is recursive
> but the call is to a child, inline it, otherwise don't inline it.
>
> The can_inline flag checks is set by two things.
> If the call is to a virtual, it checks if there is a matching instance.
> [If there isn't, the call may get inlined later after further
> specialisation]
>
> It also checks if there is a yield instruction in the function.
> If there is, the function cannot be inlined.
>
> Note no conflicts with the "inline" tag put there by the programmer
> are reported as errors. Perhaps they should be, since inline
> has actual semantics.
>
> However all the above is only part the story!
> If the application was of a generator, none of the above is done
> at this point. Instead, the application is just replaced by a variable
> and the variable assigned the application. The variable gets the name
> "_genout_urv" + a unique integer.
>
> Elsewhere, we look for initialisations of the form:
>
>         v = f a;
>
> and do the "can_inline" check, and then call "inline_check" which says:
>
>   let inline_check caller callee props exes =
>     not (mem `NoInline props) &&
>     (
>         mem `Inline props ||
>         length exes <= syms.compiler_options.max_inline_length
>     ) &&
>     (
>       (* only inline a recursive call to a child *)
>       not (Flx_call.is_recursive_call uses caller callee) ||
>       Flx_bsym_table.is_child bsym_table caller callee
>     )
>   in
>
> which is slightly different (not sure why).
>
> So the bottom line is, if you put "inline" on a function, then a call to
> it will
> not be inlined if:
>
> (a) it contains "yield"
> (b) the call is recursive and it is not a child of the caller
>
> Condition (b) is suboptimal! Sibling calls are excluded.
> Ideally, recursive functions should be inlined once.
> However I just couldn't make either of these work.
>
> The reason for all this explanation: the following implementation of
> futures:
>
>
> var ch = mk_schannel[int]();
> spawn_fthread { write (ch,42); };
> var x:int;
> var flag = false;
> proc fetch() {
>   x = read ch;
>   flag = true;
> }
>
> gen get() = { if not flag do fetch; done return x; }
>
> println$ #get;
>
> actually works but only by "luck" that the #get call
> is inlined. For this to work reliably, the call must be
> inlined (I made a closure to prove it and sure enough it
> segfaulted). As you can see from the compiler code above
> adding "inline" to the definition greatly improves the
> chances of inlining -- for this definition it is forced.
>
> However there's no diagnostic if it isn't, and it never is
> if a closure is stored in a variable: inline adjective only applies to
> direct
> calls.
>
> The situation is more complex: not only must get() be inlined,
> but any "function like thing" it is contained in must be too,
> up to the closest enclosing top level procedure (meaning
> a procedure not called from inside a function).
>
> One must be conscious of the fact that C primitives like:
>
>         fun sin: double -> double = "sin($1)";
>
> are NOT functions, they're actually (typesafe) macros: the arguments
> replace the parameters as written. Most of Felix is built on such C
> bindings.
> Scrapping functions using the machine stack would force the hard
> distinction
> between functions and procedures to be moved from Felix abstract semantics
> to the binding level.
>
> Bindings could be fixed too: we could ban functional bindings: instead
> write:
>
>         proc sin : double * &double = "*$2 = sin ($1); ";
>
> Given a whole procedural language the only use of the machine stack
> would be in leaf calls to C bindings, and only transient: perfectly safe
> provided we never need closures for C binding arguments (since those
> closures would have to be functional because that's the kind of callback
> C expects).
>
> Of course -- you would not write proc sin. Felix would just translate
> your functional macro.
>
> The result would be safer -- the problem is that Felix actually does
> the translations now, just not for closures, that is, a variable of
> function type A -> B is not translated to A * &B -> 0.
>
> One major disadvantage of the procedural form is that because it
> uses pointers it is extremely hard to optimise: you need data flow
> analysis on sequences of instructions instead of recursive
> pattern matching on expressions.
>
>
> --
> john skaller
> skal...@users.sourceforge.net
> http://felix-lang.org
>
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Felix Language" group.
> To post to this group, send email to felix-langu...@googlegroups.com.
> To unsubscribe from this group, send email to
> felix-language+unsubscr...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/felix-language?hl=en.
>
>
------------------------------------------------------------------------------
Monitor your physical, virtual and cloud infrastructure from a single
web console. Get in-depth insight into apps, servers, databases, vmware,
SAP, cloud infrastructure, etc. Download 30-day Free Trial.
Pricing starts from $795 for 25 servers or applications!
http://p.sf.net/sfu/zoho_dev2dev_nov
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to