@@ -141,6 +141,18 @@ rust_task::start(uintptr_t exit_task_glue,
141
141
uintptr_t spawnee_fn,
142
142
uintptr_t args,
143
143
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)
144
156
{
145
157
LOGPTR (dom, " exit-task glue" , exit_task_glue);
146
158
LOGPTR (dom, " from spawnee" , spawnee_fn);
@@ -176,30 +188,25 @@ rust_task::start(uintptr_t exit_task_glue,
176
188
177
189
uintptr_t exit_task_frame_base = 0 ;
178
190
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) {
190
192
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;
193
201
194
- *spp-- = (uintptr_t ) dom->root_crate ; // crate ptr
195
- *spp-- = (uintptr_t ) 0 ; // frame_glue_fns
202
+ *spp-- = 0 ;
196
203
}
197
204
205
+ *spp-- = (uintptr_t ) dom->root_crate ; // crate ptr
206
+ *spp-- = (uintptr_t ) 0 ; // frame_glue_fns
207
+
198
208
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 ));
203
210
204
211
// Copy args from spawner to spawnee.
205
212
uintptr_t *src = (uintptr_t *)args;
@@ -222,16 +229,96 @@ rust_task::start(uintptr_t exit_task_glue,
222
229
// activating:
223
230
*spp-- = (uintptr_t ) 0x0 ; // closure-or-obj
224
231
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 ;
233
247
}
234
248
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
+
235
322
I (dom, spp+1 == align_down (spp+1 ));
236
323
*spp-- = (uintptr_t ) exit_task_glue; // retpc
237
324
0 commit comments