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 ------------------------------------------------------------------------------ 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