Skip to content

Commit d6c34fd

Browse files
committed
---
yaml --- r: 2322 b: refs/heads/master c: a3ff02f h: refs/heads/master v: v3
1 parent ad1ef9c commit d6c34fd

File tree

3 files changed

+123
-28
lines changed

3 files changed

+123
-28
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: a919a3082d04a24a6aaa13ffcef98bb06307addc
2+
refs/heads/master: a3ff02f1266795691d6cb97dc0de886c613b39ed

trunk/src/rt/rust_task.cpp

Lines changed: 114 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,18 @@ rust_task::start(uintptr_t exit_task_glue,
141141
uintptr_t spawnee_fn,
142142
uintptr_t args,
143143
size_t callsz)
144+
{
145+
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL)
146+
start_rustboot(exit_task_glue, spawnee_fn, args, callsz);
147+
else
148+
start_rustc(exit_task_glue, spawnee_fn, args, callsz);
149+
}
150+
151+
void
152+
rust_task::start_rustboot(uintptr_t exit_task_glue,
153+
uintptr_t spawnee_fn,
154+
uintptr_t args,
155+
size_t callsz)
144156
{
145157
LOGPTR(dom, "exit-task glue", exit_task_glue);
146158
LOGPTR(dom, "from spawnee", spawnee_fn);
@@ -176,30 +188,25 @@ rust_task::start(uintptr_t exit_task_glue,
176188

177189
uintptr_t exit_task_frame_base = 0;
178190

179-
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL) {
180-
for (size_t j = 0; j < n_callee_saves; ++j) {
181-
182-
// We want 'frame_base' to point to the old fp in this (exit-task)
183-
// frame, because we're going to inject this frame-pointer into
184-
// the callee-save frame pointer value in the *next* (spawnee)
185-
// frame. A cheap trick, but this means the spawnee frame will
186-
// restore the proper frame pointer of the glue frame as it runs
187-
// its epilogue.
188-
if (j == callee_save_fp)
189-
exit_task_frame_base = (uintptr_t)spp;
191+
for (size_t j = 0; j < n_callee_saves; ++j) {
190192

191-
*spp-- = 0;
192-
}
193+
// We want 'frame_base' to point to the old fp in this (exit-task)
194+
// frame, because we're going to inject this frame-pointer into
195+
// the callee-save frame pointer value in the *next* (spawnee)
196+
// frame. A cheap trick, but this means the spawnee frame will
197+
// restore the proper frame pointer of the glue frame as it runs
198+
// its epilogue.
199+
if (j == callee_save_fp)
200+
exit_task_frame_base = (uintptr_t)spp;
193201

194-
*spp-- = (uintptr_t) dom->root_crate; // crate ptr
195-
*spp-- = (uintptr_t) 0; // frame_glue_fns
202+
*spp-- = 0;
196203
}
197204

205+
*spp-- = (uintptr_t) dom->root_crate; // crate ptr
206+
*spp-- = (uintptr_t) 0; // frame_glue_fns
207+
198208
I(dom, args);
199-
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL)
200-
make_aligned_room_for_bytes(spp, callsz - sizeof(uintptr_t));
201-
else
202-
make_aligned_room_for_bytes(spp, callsz - 3 * sizeof(uintptr_t));
209+
make_aligned_room_for_bytes(spp, callsz - sizeof(uintptr_t));
203210

204211
// Copy args from spawner to spawnee.
205212
uintptr_t *src = (uintptr_t *)args;
@@ -222,16 +229,96 @@ rust_task::start(uintptr_t exit_task_glue,
222229
// activating:
223230
*spp-- = (uintptr_t) 0x0; // closure-or-obj
224231

225-
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL) {
226-
// in CDECL mode we write the task + outptr to the spawnee stack.
227-
*spp-- = (uintptr_t) this; // task
228-
*spp-- = (uintptr_t) 0; // output addr
229-
} else {
230-
// in FASTCALL mode we don't, the outptr will be in ecx and the task
231-
// in edx, and the activate_glue will make sure to set that up.
232-
I(dom, spawnee_abi == ABI_X86_RUSTC_FASTCALL);
232+
// in CDECL mode we write the task + outptr to the spawnee stack.
233+
*spp-- = (uintptr_t) this; // task
234+
*spp-- = (uintptr_t) 0; // output addr
235+
236+
I(dom, spp+1 == align_down(spp+1));
237+
*spp-- = (uintptr_t) exit_task_glue; // retpc
238+
239+
// The context the activate_glue needs to switch stack.
240+
*spp-- = (uintptr_t) spawnee_fn; // instruction to start at
241+
for (size_t j = 0; j < n_callee_saves; ++j) {
242+
// callee-saves to carry in when we activate
243+
if (j == callee_save_fp)
244+
*spp-- = exit_task_frame_base;
245+
else
246+
*spp-- = (uintptr_t)NULL;
233247
}
234248

249+
// Back up one, we overshot where sp should be.
250+
rust_sp = (uintptr_t) (spp+1);
251+
252+
transition(&dom->newborn_tasks, &dom->running_tasks);
253+
}
254+
255+
void
256+
rust_task::start_rustc(uintptr_t exit_task_glue,
257+
uintptr_t spawnee_fn,
258+
uintptr_t args,
259+
size_t callsz)
260+
{
261+
LOGPTR(dom, "exit-task glue", exit_task_glue);
262+
LOGPTR(dom, "from spawnee", spawnee_fn);
263+
264+
// Set sp to last uintptr_t-sized cell of segment
265+
rust_sp -= sizeof(uintptr_t);
266+
267+
// NB: Darwin needs "16-byte aligned" stacks *at the point of the call
268+
// instruction in the caller*. This means that the address at which the
269+
// word before retpc is pushed must always be 16-byte aligned.
270+
//
271+
// see: "Mac OS X ABI Function Call Guide"
272+
273+
274+
// Begin synthesizing frames. There are two: a "fully formed"
275+
// exit-task frame at the top of the stack -- that pretends to be
276+
// mid-execution -- and a just-starting frame beneath it that
277+
// starts executing the first instruction of the spawnee. The
278+
// spawnee *thinks* it was called by the exit-task frame above
279+
// it. It wasn't; we put that fake frame in place here, but the
280+
// illusion is enough for the spawnee to return to the exit-task
281+
// frame when it's done, and exit.
282+
uintptr_t *spp = (uintptr_t *)rust_sp;
283+
284+
285+
// The exit_task_glue frame we synthesize above the frame we activate:
286+
make_aligned_room_for_bytes(spp, 2 * sizeof(uintptr_t));
287+
*spp-- = (uintptr_t) 0; // closure-or-obj
288+
*spp-- = (uintptr_t) this; // task
289+
I(dom, spp == align_down(spp));
290+
*spp-- = (uintptr_t) 0x0; // output
291+
*spp-- = (uintptr_t) 0x0; // retpc
292+
293+
uintptr_t exit_task_frame_base = 0;
294+
295+
I(dom, args);
296+
make_aligned_room_for_bytes(spp, callsz - 3 * sizeof(uintptr_t));
297+
298+
// Copy args from spawner to spawnee.
299+
uintptr_t *src = (uintptr_t *)args;
300+
src += 1; // spawn-call output slot
301+
src += 1; // spawn-call task slot
302+
src += 1; // spawn-call closure-or-obj slot
303+
304+
// Undo previous sp-- so we're pointing at the last word pushed.
305+
++spp;
306+
307+
// Memcpy all but the task, output and env pointers
308+
callsz -= (3 * sizeof(uintptr_t));
309+
spp = (uintptr_t*) (((uintptr_t)spp) - callsz);
310+
memcpy(spp, src, callsz);
311+
312+
// Move sp down to point to last implicit-arg cell (env).
313+
spp--;
314+
315+
// The *implicit* incoming args to the spawnee frame we're
316+
// activating:
317+
*spp-- = (uintptr_t) 0x0; // closure-or-obj
318+
319+
// in FASTCALL mode we don't, the outptr will be in ecx and the task
320+
// in edx, and the activate_glue will make sure to set that up.
321+
235322
I(dom, spp+1 == align_down(spp+1));
236323
*spp-- = (uintptr_t) exit_task_glue; // retpc
237324

trunk/src/rt/rust_task.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ rust_task : public maybe_proxy<rust_task>,
6060
uintptr_t spawnee_fn,
6161
uintptr_t args,
6262
size_t callsz);
63+
void start_rustboot(uintptr_t exit_task_glue,
64+
uintptr_t spawnee_fn,
65+
uintptr_t args,
66+
size_t callsz);
67+
void start_rustc(uintptr_t exit_task_glue,
68+
uintptr_t spawnee_fn,
69+
uintptr_t args,
70+
size_t callsz);
6371
void grow(size_t n_frame_bytes);
6472
bool running();
6573
bool blocked();

0 commit comments

Comments
 (0)