about summary refs log tree commit diff
path: root/src/rt/rust_task.cpp
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-03-30 13:04:18 -0700
committerGraydon Hoare <graydon@mozilla.com>2011-03-30 13:04:18 -0700
commit3e7b991d4957a13e8049c1a4d1893a685f47d9ae (patch)
tree16a3dee79f7ac50c4c9e68e5932ff5a587f9f7af /src/rt/rust_task.cpp
parentb5a43364872dbfa8e036e51599c73e882dfd13c2 (diff)
downloadrust-3e7b991d4957a13e8049c1a4d1893a685f47d9ae.tar.gz
rust-3e7b991d4957a13e8049c1a4d1893a685f47d9ae.zip
Ensure task stacks start out with a 16-byte aligned entry frame. Should make OSX behave a bit better.
Diffstat (limited to 'src/rt/rust_task.cpp')
-rw-r--r--src/rt/rust_task.cpp70
1 files changed, 48 insertions, 22 deletions
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 1afbfdd6b3b..febfd85162c 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -58,6 +58,21 @@ align_down(uintptr_t sp)
     return sp & ~(16 - 1);
 }
 
+static uintptr_t*
+align_down(uintptr_t* sp)
+{
+    return (uintptr_t*) align_down((uintptr_t)sp);
+}
+
+
+static void
+make_aligned_room_for_bytes(uintptr_t*& sp, size_t n)
+{
+    uintptr_t tmp = (uintptr_t) sp;
+    tmp = align_down(tmp - n) + n;
+    sp = (uintptr_t*) tmp;
+}
+
 
 rust_task::rust_task(rust_dom *dom, rust_task_list *state,
                      rust_task *spawner, const char *name) :
@@ -131,9 +146,15 @@ rust_task::start(uintptr_t exit_task_glue,
     dom->logptr("exit-task glue", exit_task_glue);
     dom->logptr("from spawnee", spawnee_fn);
 
-    // Set sp to last uintptr_t-sized cell of segment and align down.
+    // Set sp to last uintptr_t-sized cell of segment
     rust_sp -= sizeof(uintptr_t);
-    rust_sp = align_down(rust_sp);
+
+    // NB: Darwin needs "16-byte aligned" stacks *at the point of the call
+    // instruction in the caller*. This means that the address at which a
+    // retpc is pushed must always be 16-byte aligned.
+    //
+    // see: "Mac OS X ABI Function Call Guide"
+
 
     // Begin synthesizing frames. There are two: a "fully formed"
     // exit-task frame at the top of the stack -- that pretends to be
@@ -145,10 +166,13 @@ rust_task::start(uintptr_t exit_task_glue,
     // frame when it's done, and exit.
     uintptr_t *spp = (uintptr_t *)rust_sp;
 
+
     // The exit_task_glue frame we synthesize above the frame we activate:
+    make_aligned_room_for_bytes(spp, 3 * sizeof(uintptr_t));
     *spp-- = (uintptr_t) 0;          // closure-or-obj
     *spp-- = (uintptr_t) this;       // task
     *spp-- = (uintptr_t) 0x0;        // output
+    I(dom, spp == align_down(spp));
     *spp-- = (uintptr_t) 0x0;        // retpc
 
     uintptr_t exit_task_frame_base;
@@ -172,27 +196,28 @@ rust_task::start(uintptr_t exit_task_glue,
         *spp-- = (uintptr_t) 0;                // frame_glue_fns
     }
 
+    I(dom, args);
+    if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL)
+        make_aligned_room_for_bytes(spp, callsz);
+    else
+        make_aligned_room_for_bytes(spp, callsz - 2 * sizeof(uintptr_t));
+
     // Copy args from spawner to spawnee.
-    if (args)  {
-        uintptr_t *src = (uintptr_t *)args;
-        src += 1;                  // spawn-call output slot
-        src += 1;                  // spawn-call task slot
-        src += 1;                  // spawn-call closure-or-obj slot
-
-        // Undo previous sp-- so we're pointing at the last word pushed.
-        ++spp;
-
-        // Memcpy all but the task, output and env pointers
-        callsz -= (3 * sizeof(uintptr_t));
-        spp = (uintptr_t*) (((uintptr_t)spp) - callsz);
-        memcpy(spp, src, callsz);
-
-        // Move sp down to point to last implicit-arg cell (env).
-        spp--;
-    } else {
-        // We're at root, starting up.
-        I(dom, callsz==0);
-    }
+    uintptr_t *src = (uintptr_t *)args;
+    src += 1;                  // spawn-call output slot
+    src += 1;                  // spawn-call task slot
+    src += 1;                  // spawn-call closure-or-obj slot
+
+    // Undo previous sp-- so we're pointing at the last word pushed.
+    ++spp;
+
+    // Memcpy all but the task, output and env pointers
+    callsz -= (3 * sizeof(uintptr_t));
+    spp = (uintptr_t*) (((uintptr_t)spp) - callsz);
+    memcpy(spp, src, callsz);
+
+    // Move sp down to point to last implicit-arg cell (env).
+    spp--;
 
     // The *implicit* incoming args to the spawnee frame we're
     // activating:
@@ -208,6 +233,7 @@ rust_task::start(uintptr_t exit_task_glue,
         I(dom, spawnee_abi == ABI_X86_RUSTC_FASTCALL);
     }
 
+    I(dom, spp == align_down(spp));
     *spp-- = (uintptr_t) exit_task_glue;  // retpc
 
     // The context the activate_glue needs to switch stack.