<html>
<head>
<style><!--
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
font-size: 12pt;
font-family:Calibri
}
--></style></head>
<body class='hmmessage'><div dir='ltr'> > Did you take a look at the LLVM IR I sent? T<br><BR>Sorry, I couldn't quickly make sense of it. :(<BR>I have to read up on LLVM or study your code more.<BR>(This is why I favor a C backend -- I'm already an expert and there is far more C expertise in the world than LLVM expertise..I think.. and other reasons like portability..)<BR> <BR> <BR>Mention of "trampolines" was worrisome though.<BR>That usually means "runtime generated code, often on the stack". True here?<BR> <BR> <BR>If not, nevermind<BR>If so:<BR> <BR> <BR> <BR>There is no good solution here, but I think runtime generated code is mostly a losing battle..at least on the stack. If you dedicate a little bit of special purpose platform-specific code to it, and you don't mind it being slow, and you deal with the lifetime management, then it becomes viable.<BR>e.g. on Windows, you use VirtualAlloc(MEM_EXECUTE).<BR>On other platforms you use mprotect I think. And/or mmap? mmap(PROT_EXEC)?<BR>But you end up allocating memory in large chunks, like at least 4K or 64K.<BR>(You can also write out little temporary .so/.dll files, but that is unnecessarily inefficient.)<BR> <BR> <BR>I've seen code that calls mprotect against the stack. Yuck.<BR>The stack is nonexecutable on purpose -- for security (assuming there is any C or C++ code in the process).<BR> <BR> <BR>If you read the libffi mailing list, you see they are constantly in this arms race.<BR>There is a slow steady trickle of problems making the libffi code executable.<BR>For Darwin/ARM they came up with a trick to avoid generating code, since the platform doesn't allow unsigned code to run.<BR> <BR> <BR> <BR>Pluses/minuses:<BR> <BR> <BR>runtime generated code:<BR>Producing the code is fast, on historical systems that don't make it difficult to execute memory, e.g. on the stack.<BR>Running the code is fast.<BR>Pointers to closures become compatible with C -- you can pass a pointer to a closure as a callback to or C++ and it works.<BR>Highly target-dependent.<BR> <BR> <BR>The unusual Modula-3 method:<BR>Also fast.<BR>Calling function pointers is different and larger and slower.<BR>C code cannot call function pointers to nested functions. That is the main downside.<BR>Only slightly target-dependent -- in its choice of closure marker.<BR>I think we should change the closure marker slightly -- its size should be target-dependent, it should only be 4 bytes on SPARC64, MIPS64, PPC64, Alpha, AMD64 -- so the alignment check can be skipped. And it should possibly be larger than 4 or 8 bytes on IA64.<BR>But someone needs to read up on all the various instruction encodings and verify that 4 or 8 0xFF bytes are really invalid and won't occur.<BR>But most likely if 4 bytes of 0xFF are a good marker on MIPS32, PPC32, SPARC32, I386, they are also probably a good marker on MIPS64, PPC64, SPARC64, AMD64. And Alpha.<BR>Another option is to use something like "jmp marker". i.e. a jump to an address that is used just be the marker. It might not be a constant though. Maybe it is relocated. But you want it to be the same across all dynamic linked code, actually.<BR> <BR> <BR>We might want to have calls through a function pointer go through a helper function, to keep it small.<BR> <BR> <BR><tangent><BR>Hm.. I wonder..maybe a closure can be generated fairly portably actually.<BR>Maybe you just need one little wrapper per function signature. And most would really be the same.<BR>Let me think on this..hm..well..you could do it if you have a special static link register probably. I need to think about this more. Do "all" the calling conventions provide a special extra register for "static link"? And is that often used for C++ "this"? In that case, there is a way..<BR> <BR> <BR><tangent><BR>Ultimately, I should point out, the idea of passing a closure to C is actually very useful.<BR>One should be able to pass an "object method pointer".<BR>So some language construct or pragma might be nice there -- to force down the runtime generated code path.<BR>But usually the C function that wants a function pointer also takes a "void* context", so maybe not so needed.<BR> <BR> <BR>Or maybe folks would just use "libffi" for that.<BR> <BR> <BR> <BR> - Jay<br> <BR><div><div id="SkyDrivePlaceholder"></div><hr id="stopSpelling">CC: m3devel@elegosoft.com<br>From: antony.hosking@gmail.com<br>Subject: Re: [M3devel] uplevel locals declared after function starts..<br>Date: Thu, 20 Sep 2012 19:38:27 -0400<br>To: jay.krell@cornell.edu<br><br><div>Agreed. You need to backpatch the uplevel locals. I would accumulate all of them. Did you take a look at the LLVM IR I sent? That's how I plan to so it. <br><br>Sent from my iPhone</div><div><br>On Sep 20, 2012, at 19:18, Jay K <<a href="mailto:jay.krell@cornell.edu">jay.krell@cornell.edu</a>> wrote:<br><br></div><blockquote><div>
<style><!--
.ExternalClass .ecxhmmessage P
{padding:0px;}
.ExternalClass body.ecxhmmessage
{font-size:12pt;font-family:Calibri;}
--></style>
<div dir="ltr"><div><font face="Calibri, sans-serif">We get uplevel locals declared while within a function.</font></div><div><font face="Calibri, sans-serif">So I think I'll bite the bullet and make multiple passes now.</font></div><div><font face="Calibri, sans-serif">Otherwise I build up the frame struct "too early".</font></div><div><font face="Calibri, sans-serif">I need to see all the locals -- all the uplevels, early in a function.</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">There is also a chance they don't all have unique names.</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">I do NOT expect I should have separate frames/static_links per-scope,</font></div><div><font face="Calibri, sans-serif">just per-function.</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">I could put structs inside the frame, named after the line they start</font></div><div><font face="Calibri, sans-serif">on or such.. that might be prettier and more readable, or not.</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">The structs could then be unioned at some point -- parallel scopes</font></div><div><font face="Calibri, sans-serif">can/should share storage.</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">M3C.m3:</font></div><div><font face="Calibri, sans-serif">PROCEDURE declare_local(...)</font></div><div><font face="Calibri, sans-serif">BEGIN</font></div><div><font face="Calibri, sans-serif">...</font></div><div><font face="Calibri, sans-serif">IF u.in_proc THEN</font></div><div><font face="Calibri, sans-serif"> ExtraScope_Open(u);</font></div><div><font face="Calibri, sans-serif"> print(u, var.Declare() & " M3_INIT;");</font></div><div><font face="Calibri, sans-serif"> <* ASSERT up_level = FALSE *> this fails</font></div><div><font face="Calibri, sans-serif"> ELSE</font></div><div><font face="Calibri, sans-serif"> IF up_level THEN</font></div><div><font face="Calibri, sans-serif"> u.current_proc.uplevels := TRUE;</font></div><div><font face="Calibri, sans-serif"> END;</font></div><div><font face="Calibri, sans-serif"> u.current_proc.locals.addhi(var);</font></div><div><font face="Calibri, sans-serif"> END;</font></div><div><font face="Calibri, sans-serif"> RETURN var;</font></div><div><font face="Calibri, sans-serif">END declare_local;</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">== package /Users/jay/dev2/cm3/m3-libs/m3tk-misc ==</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">...</font></div><div><font face="Calibri, sans-serif">new source -> compiling Args.m3</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">***</font></div><div><font face="Calibri, sans-serif">*** runtime error:</font></div><div><font face="Calibri, sans-serif">*** <*ASSERT*> failed.</font></div><div><font face="Calibri, sans-serif">*** file "../src/M3C.m3", line 1778</font></div><div><font face="Calibri, sans-serif">***</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"> m3_backend => 1536</font></div><div><font face="Calibri, sans-serif">m3cc (aka cm3cg) failed compiling: Args.mc</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">I'm guessing the code is here:</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">PROCEDURE Errors(h: Handle; indent: CARDINAL := 0): Text.T RAISES {}=</font></div><div><font face="Calibri, sans-serif"> BEGIN</font></div><div><font face="Calibri, sans-serif"> IF h.errors = 0 THEN</font></div><div><font face="Calibri, sans-serif"> <*FATAL Fatal*> BEGIN RAISE Fatal; END;</font></div><div><font face="Calibri, sans-serif"> ELSE</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"> VAR</font></div><div><font face="Calibri, sans-serif"> texts := NEW(REF ARRAY OF TEXT, h.errors * 2);</font></div><div><font face="Calibri, sans-serif"> (* allocates space for all the error messages + padding *)</font></div><div><font face="Calibri, sans-serif"> pos: CARDINAL := 0;</font></div><div><font face="Calibri, sans-serif"> padding := Fmt.Pad("", indent);</font></div><div><font face="Calibri, sans-serif"> fmt: Text.T;</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"> <*INLINE*> PROCEDURE Add(t: Text.T) RAISES {}=</font></div><div><font face="Calibri, sans-serif"> BEGIN texts[pos] := t; INC(pos) END Add;</font></div><div><font face="Calibri, sans-serif"> <*INLINE*> PROCEDURE PaddedAdd(t: Text.T) RAISES {}=</font></div><div><font face="Calibri, sans-serif"> BEGIN Add(padding); Add(t) END PaddedAdd;</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">see how "texts" is both uplevel and "not at the start" of the function.</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">This is going to take a few days to deal with.</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif">Compiler can compile itself, and a large swath of the system now.</font></div><div><font face="Calibri, sans-serif">I didn't use the self-built compiler, but I will do that next. It probably works.</font></div><div><font face="Calibri, sans-serif">Very good.</font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"><br></font></div><div><font face="Calibri, sans-serif"> - Jay</font></div><br> </div>
</div></blockquote></div> </div></body>
</html>