summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorReimer Behrends <behrends@gmail.com>2014-07-23 03:20:50 +0200
committerReimer Behrends <behrends@gmail.com>2014-07-23 03:20:50 +0200
commit15734009ca9077cfc8c4139b8258b2db2d7492dd (patch)
treebf57ccd859e64dfd2bd86709585f903e33771a09
parentdcf1425eb996db5d39a23c0360573f1addd4a850 (diff)
downloadNim-15734009ca9077cfc8c4139b8258b2db2d7492dd.tar.gz
More robust implementation for finding the beginning of the stack.
This patch inserts an extra stack frame above the function that
calls the actual Nimrod code and ensures that a reference to this
frame is stored as the stack bottom.
-rw-r--r--compiler/cgen.nim25
-rw-r--r--lib/system.nim6
2 files changed, 23 insertions, 8 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index e2f3b5ab0..d7a9d3c9d 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -954,8 +954,7 @@ proc genMainProc(m: BModule) =
       "\tsystemInit();$N" &
       "$1" &
       "$2" &
-      "$3" &
-      "$4"
+      "$3"
 
     MainProcs =
       "\tNimMain();$N"
@@ -963,10 +962,19 @@ proc genMainProc(m: BModule) =
     MainProcsWithResult =
       MainProcs & "\treturn nim_program_result;$N"
 
+    # The use of a volatile function pointer to call NimMainInner
+    # prevents inlining of the NimMainInner function and dependent
+    # functions, which might otherwise merge their stack frames.
     NimMainBody =
-      "N_CDECL(void, NimMain)(void) {$N" &
+      "N_CDECL(void, NimMainInner)(void) {$N" &
         "\tPreMain();$N" &
         "$1" &
+      "}$N$N" &
+      "N_CDECL(void, NimMain)(void) {$N" &
+        "\tvoid (*volatile inner)();$N" &
+        "\tinner = NimMainInner;$N" &
+        "$2" &
+        "\t(*inner)();$N" &
       "}$N$N"
 
     PosixNimMain =
@@ -1034,14 +1042,15 @@ proc genMainProc(m: BModule) =
   if optEndb in gOptions:
     gBreakpoints.app(m.genFilenames)
   
-  let initStackBottomCall = if emulatedThreadVars() or
-                              platform.targetOS == osStandalone: "".toRope
-                            else: ropecg(m, "\t#initStackBottom();$N")
+  let initStackBottomCall =
+    if emulatedThreadVars() or
+      platform.targetOS == osStandalone: "".toRope
+    else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
   inc(m.labels)
   appcg(m, m.s[cfsProcs], "void PreMain() {$N" & PreMainBody & "}$N$N", [
-    mainDatInit, initStackBottomCall, gBreakpoints, otherModsInit])
+    mainDatInit, gBreakpoints, otherModsInit])
 
-  appcg(m, m.s[cfsProcs], nimMain, [mainModInit, toRope(m.labels)])
+  appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, toRope(m.labels)])
   if optNoMain notin gGlobalOptions:
     appcg(m, m.s[cfsProcs], otherMain, [])
 
diff --git a/lib/system.nim b/lib/system.nim
index 753205777..361e94462 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2115,6 +2115,12 @@ when not defined(JS): #and not defined(NimrodVM):
         locals = addr(locals)
         setStackBottom(locals)
 
+    proc initStackBottomWith(locals: pointer) {.inline, compilerproc.} =
+      # We need to keep initStackBottom around for now to avoid
+      # bootstrapping problems.
+      when defined(setStackBottom):
+        setStackBottom(locals)
+
     var
       strDesc: TNimType