@@ -58,6 +58,21 @@ align_down(uintptr_t sp)
58
58
return sp & ~(16 - 1 );
59
59
}
60
60
61
+ static uintptr_t *
62
+ align_down (uintptr_t * sp)
63
+ {
64
+ return (uintptr_t *) align_down ((uintptr_t )sp);
65
+ }
66
+
67
+
68
+ static void
69
+ make_aligned_room_for_bytes (uintptr_t *& sp, size_t n)
70
+ {
71
+ uintptr_t tmp = (uintptr_t ) sp;
72
+ tmp = align_down (tmp - n) + n;
73
+ sp = (uintptr_t *) tmp;
74
+ }
75
+
61
76
62
77
rust_task::rust_task (rust_dom *dom, rust_task_list *state,
63
78
rust_task *spawner, const char *name) :
@@ -131,9 +146,15 @@ rust_task::start(uintptr_t exit_task_glue,
131
146
dom->logptr (" exit-task glue" , exit_task_glue);
132
147
dom->logptr (" from spawnee" , spawnee_fn);
133
148
134
- // Set sp to last uintptr_t-sized cell of segment and align down.
149
+ // Set sp to last uintptr_t-sized cell of segment
135
150
rust_sp -= sizeof (uintptr_t );
136
- rust_sp = align_down (rust_sp);
151
+
152
+ // NB: Darwin needs "16-byte aligned" stacks *at the point of the call
153
+ // instruction in the caller*. This means that the address at which a
154
+ // retpc is pushed must always be 16-byte aligned.
155
+ //
156
+ // see: "Mac OS X ABI Function Call Guide"
157
+
137
158
138
159
// Begin synthesizing frames. There are two: a "fully formed"
139
160
// 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,
145
166
// frame when it's done, and exit.
146
167
uintptr_t *spp = (uintptr_t *)rust_sp;
147
168
169
+
148
170
// The exit_task_glue frame we synthesize above the frame we activate:
171
+ make_aligned_room_for_bytes (spp, 3 * sizeof (uintptr_t ));
149
172
*spp-- = (uintptr_t ) 0 ; // closure-or-obj
150
173
*spp-- = (uintptr_t ) this ; // task
151
174
*spp-- = (uintptr_t ) 0x0 ; // output
175
+ I (dom, spp == align_down (spp));
152
176
*spp-- = (uintptr_t ) 0x0 ; // retpc
153
177
154
178
uintptr_t exit_task_frame_base;
@@ -172,27 +196,28 @@ rust_task::start(uintptr_t exit_task_glue,
172
196
*spp-- = (uintptr_t ) 0 ; // frame_glue_fns
173
197
}
174
198
199
+ I (dom, args);
200
+ if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL)
201
+ make_aligned_room_for_bytes (spp, callsz);
202
+ else
203
+ make_aligned_room_for_bytes (spp, callsz - 2 * sizeof (uintptr_t ));
204
+
175
205
// Copy args from spawner to spawnee.
176
- if (args) {
177
- uintptr_t *src = (uintptr_t *)args;
178
- src += 1 ; // spawn-call output slot
179
- src += 1 ; // spawn-call task slot
180
- src += 1 ; // spawn-call closure-or-obj slot
181
-
182
- // Undo previous sp-- so we're pointing at the last word pushed.
183
- ++spp;
184
-
185
- // Memcpy all but the task, output and env pointers
186
- callsz -= (3 * sizeof (uintptr_t ));
187
- spp = (uintptr_t *) (((uintptr_t )spp) - callsz);
188
- memcpy (spp, src, callsz);
189
-
190
- // Move sp down to point to last implicit-arg cell (env).
191
- spp--;
192
- } else {
193
- // We're at root, starting up.
194
- I (dom, callsz==0 );
195
- }
206
+ uintptr_t *src = (uintptr_t *)args;
207
+ src += 1 ; // spawn-call output slot
208
+ src += 1 ; // spawn-call task slot
209
+ src += 1 ; // spawn-call closure-or-obj slot
210
+
211
+ // Undo previous sp-- so we're pointing at the last word pushed.
212
+ ++spp;
213
+
214
+ // Memcpy all but the task, output and env pointers
215
+ callsz -= (3 * sizeof (uintptr_t ));
216
+ spp = (uintptr_t *) (((uintptr_t )spp) - callsz);
217
+ memcpy (spp, src, callsz);
218
+
219
+ // Move sp down to point to last implicit-arg cell (env).
220
+ spp--;
196
221
197
222
// The *implicit* incoming args to the spawnee frame we're
198
223
// activating:
@@ -208,6 +233,7 @@ rust_task::start(uintptr_t exit_task_glue,
208
233
I (dom, spawnee_abi == ABI_X86_RUSTC_FASTCALL);
209
234
}
210
235
236
+ I (dom, spp == align_down (spp));
211
237
*spp-- = (uintptr_t ) exit_task_glue; // retpc
212
238
213
239
// The context the activate_glue needs to switch stack.
0 commit comments