Skip to content

Commit d90a9d3

Browse files
committed
rt: Inline everything on the C-stack-switching path
1 parent dff256c commit d90a9d3

File tree

5 files changed

+155
-148
lines changed

5 files changed

+155
-148
lines changed

src/rt/rust_task.cpp

Lines changed: 0 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -673,19 +673,6 @@ rust_task::record_stack_limit() {
673673
record_sp(stk->data + LIMIT_OFFSET + RED_ZONE_SIZE);
674674
}
675675

676-
extern "C" uintptr_t get_sp();
677-
678-
static bool
679-
sp_in_stk_seg(uintptr_t sp, stk_seg *stk) {
680-
// Not positive these bounds for sp are correct. I think that the first
681-
// possible value for esp on a new stack is stk->end, which points to the
682-
// address before the first value to be pushed onto a new stack. The last
683-
// possible address we can push data to is stk->data. Regardless, there's
684-
// so much slop at either end that we should never hit one of these
685-
// boundaries.
686-
return (uintptr_t)stk->data <= sp && sp <= stk->end;
687-
}
688-
689676
/*
690677
Called by landing pads during unwinding to figure out which
691678
stack segment we are currently running on, delete the others,
@@ -702,25 +689,6 @@ rust_task::reset_stack_limit() {
702689
record_stack_limit();
703690
}
704691

705-
/*
706-
Returns true if we're currently running on the Rust stack
707-
*/
708-
bool
709-
rust_task::on_rust_stack() {
710-
uintptr_t sp = get_sp();
711-
bool in_first_segment = sp_in_stk_seg(sp, stk);
712-
if (in_first_segment) {
713-
return true;
714-
} else if (stk->next != NULL) {
715-
// This happens only when calling the upcall to delete
716-
// a stack segment
717-
bool in_second_segment = sp_in_stk_seg(sp, stk->next);
718-
return in_second_segment;
719-
} else {
720-
return false;
721-
}
722-
}
723-
724692
void
725693
rust_task::check_stack_canary() {
726694
::check_stack_canary(stk);
@@ -732,76 +700,6 @@ rust_task::config_notify(chan_handle chan) {
732700
notify_chan = chan;
733701
}
734702

735-
// This is the function that switches stacks by calling another function with
736-
// a single void* argument while changing the stack pointer. It has a funny
737-
// name because gdb doesn't normally like to backtrace through split stacks
738-
// (thinks it indicates a bug), but has a special case to allow functions
739-
// named __morestack to move the stack pointer around.
740-
extern "C" void __morestack(void *args, void *fn_ptr, uintptr_t stack_ptr);
741-
742-
static uintptr_t
743-
sanitize_next_sp(uintptr_t next_sp) {
744-
745-
// Since I'm not precisely sure where the next stack pointer sits in
746-
// relation to where the context switch actually happened, nor in relation
747-
// to the amount of stack needed for calling __morestack I've added some
748-
// extra bytes here.
749-
750-
// FIXME: On the rust stack this potentially puts is quite far into the
751-
// red zone. Might want to just allocate a new rust stack every time we
752-
// switch back to rust.
753-
const uintptr_t padding = 16;
754-
755-
return align_down(next_sp - padding);
756-
}
757-
758-
void
759-
rust_task::call_on_c_stack(void *args, void *fn_ptr) {
760-
I(thread, on_rust_stack());
761-
762-
next_rust_sp = get_sp();
763-
764-
bool borrowed_a_c_stack = false;
765-
uintptr_t sp;
766-
if (c_stack == NULL) {
767-
c_stack = thread->borrow_c_stack();
768-
next_c_sp = align_down(c_stack->end);
769-
sp = next_c_sp;
770-
borrowed_a_c_stack = true;
771-
} else {
772-
sp = sanitize_next_sp(next_c_sp);
773-
}
774-
775-
__morestack(args, fn_ptr, sp);
776-
777-
// Note that we may not actually get here if we threw an exception,
778-
// in which case we will return the c stack when the exception is caught.
779-
if (borrowed_a_c_stack) {
780-
return_c_stack();
781-
}
782-
}
783-
784-
void
785-
rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
786-
I(thread, !on_rust_stack());
787-
I(thread, next_rust_sp);
788-
789-
next_c_sp = get_sp();
790-
791-
uintptr_t sp = sanitize_next_sp(next_rust_sp);
792-
793-
__morestack(args, fn_ptr, sp);
794-
}
795-
796-
void
797-
rust_task::return_c_stack() {
798-
I(thread, on_rust_stack());
799-
I(thread, c_stack != NULL);
800-
thread->return_c_stack(c_stack);
801-
c_stack = NULL;
802-
next_c_sp = 0;
803-
}
804-
805703
//
806704
// Local Variables:
807705
// mode: C++

src/rt/rust_task.h

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,109 @@ rust_task : public kernel_owned<rust_task>, rust_cond
198198
void call_on_rust_stack(void *args, void *fn_ptr);
199199
};
200200

201+
// Get a rough approximation of the current stack pointer
202+
extern "C" uintptr_t get_sp();
203+
204+
// This is the function that switches stacks by calling another function with
205+
// a single void* argument while changing the stack pointer. It has a funny
206+
// name because gdb doesn't normally like to backtrace through split stacks
207+
// (thinks it indicates a bug), but has a special case to allow functions
208+
// named __morestack to move the stack pointer around.
209+
extern "C" void __morestack(void *args, void *fn_ptr, uintptr_t stack_ptr);
210+
211+
inline static uintptr_t
212+
sanitize_next_sp(uintptr_t next_sp) {
213+
214+
// Since I'm not precisely sure where the next stack pointer sits in
215+
// relation to where the context switch actually happened, nor in relation
216+
// to the amount of stack needed for calling __morestack I've added some
217+
// extra bytes here.
218+
219+
// FIXME: On the rust stack this potentially puts is quite far into the
220+
// red zone. Might want to just allocate a new rust stack every time we
221+
// switch back to rust.
222+
const uintptr_t padding = 16;
223+
224+
return align_down(next_sp - padding);
225+
}
226+
227+
inline void
228+
rust_task::call_on_c_stack(void *args, void *fn_ptr) {
229+
I(thread, on_rust_stack());
230+
231+
next_rust_sp = get_sp();
232+
233+
bool borrowed_a_c_stack = false;
234+
uintptr_t sp;
235+
if (c_stack == NULL) {
236+
c_stack = thread->borrow_c_stack();
237+
next_c_sp = align_down(c_stack->end);
238+
sp = next_c_sp;
239+
borrowed_a_c_stack = true;
240+
} else {
241+
sp = sanitize_next_sp(next_c_sp);
242+
}
243+
244+
__morestack(args, fn_ptr, sp);
245+
246+
// Note that we may not actually get here if we threw an exception,
247+
// in which case we will return the c stack when the exception is caught.
248+
if (borrowed_a_c_stack) {
249+
return_c_stack();
250+
}
251+
}
252+
253+
inline void
254+
rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
255+
I(thread, !on_rust_stack());
256+
I(thread, next_rust_sp);
257+
258+
next_c_sp = get_sp();
259+
260+
uintptr_t sp = sanitize_next_sp(next_rust_sp);
261+
262+
__morestack(args, fn_ptr, sp);
263+
}
264+
265+
inline void
266+
rust_task::return_c_stack() {
267+
I(thread, on_rust_stack());
268+
I(thread, c_stack != NULL);
269+
thread->return_c_stack(c_stack);
270+
c_stack = NULL;
271+
next_c_sp = 0;
272+
}
273+
274+
inline bool
275+
sp_in_stk_seg(uintptr_t sp, stk_seg *stk) {
276+
// Not positive these bounds for sp are correct. I think that the first
277+
// possible value for esp on a new stack is stk->end, which points to the
278+
// address before the first value to be pushed onto a new stack. The last
279+
// possible address we can push data to is stk->data. Regardless, there's
280+
// so much slop at either end that we should never hit one of these
281+
// boundaries.
282+
return (uintptr_t)stk->data <= sp && sp <= stk->end;
283+
}
284+
285+
/*
286+
Returns true if we're currently running on the Rust stack
287+
*/
288+
inline bool
289+
rust_task::on_rust_stack() {
290+
uintptr_t sp = get_sp();
291+
bool in_first_segment = sp_in_stk_seg(sp, stk);
292+
if (in_first_segment) {
293+
return true;
294+
} else if (stk->next != NULL) {
295+
// This happens only when calling the upcall to delete
296+
// a stack segment
297+
bool in_second_segment = sp_in_stk_seg(sp, stk->next);
298+
return in_second_segment;
299+
} else {
300+
return false;
301+
}
302+
}
303+
201304
//
202305
// Local Variables:
203306
// mode: C++

src/rt/rust_task_thread.cpp

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -337,16 +337,6 @@ rust_task_thread::place_task_in_tls(rust_task *task) {
337337
assert(!result && "Couldn't place the task in TLS!");
338338
task->record_stack_limit();
339339
}
340-
341-
rust_task *
342-
rust_task_thread::get_task() {
343-
if (!tls_initialized)
344-
return NULL;
345-
rust_task *task = reinterpret_cast<rust_task *>
346-
(pthread_getspecific(task_key));
347-
assert(task && "Couldn't get the task from TLS!");
348-
return task;
349-
}
350340
#else
351341
void
352342
rust_task_thread::init_tls() {
@@ -361,15 +351,6 @@ rust_task_thread::place_task_in_tls(rust_task *task) {
361351
assert(result && "Couldn't place the task in TLS!");
362352
task->record_stack_limit();
363353
}
364-
365-
rust_task *
366-
rust_task_thread::get_task() {
367-
if (!tls_initialized)
368-
return NULL;
369-
rust_task *task = reinterpret_cast<rust_task *>(TlsGetValue(task_key));
370-
assert(task && "Couldn't get the task from TLS!");
371-
return task;
372-
}
373354
#endif
374355

375356
void
@@ -402,32 +383,6 @@ rust_task_thread::unprepare_c_stack() {
402383
}
403384
}
404385

405-
// NB: Runs on the Rust stack
406-
stk_seg *
407-
rust_task_thread::borrow_c_stack() {
408-
I(this, cached_c_stack);
409-
stk_seg *your_stack;
410-
if (extra_c_stack) {
411-
your_stack = extra_c_stack;
412-
extra_c_stack = NULL;
413-
} else {
414-
your_stack = cached_c_stack;
415-
cached_c_stack = NULL;
416-
}
417-
return your_stack;
418-
}
419-
420-
// NB: Runs on the Rust stack
421-
void
422-
rust_task_thread::return_c_stack(stk_seg *stack) {
423-
I(this, !extra_c_stack);
424-
if (!cached_c_stack) {
425-
cached_c_stack = stack;
426-
} else {
427-
extra_c_stack = stack;
428-
}
429-
}
430-
431386
//
432387
// Local Variables:
433388
// mode: C++

src/rt/rust_task_thread.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,58 @@ rust_task_thread::get_log() {
150150
return _log;
151151
}
152152

153+
#ifndef __WIN32__
154+
155+
inline rust_task *
156+
rust_task_thread::get_task() {
157+
if (!tls_initialized)
158+
return NULL;
159+
rust_task *task = reinterpret_cast<rust_task *>
160+
(pthread_getspecific(task_key));
161+
assert(task && "Couldn't get the task from TLS!");
162+
return task;
163+
}
164+
165+
#else
166+
167+
inline rust_task *
168+
rust_task_thread::get_task() {
169+
if (!tls_initialized)
170+
return NULL;
171+
rust_task *task = reinterpret_cast<rust_task *>(TlsGetValue(task_key));
172+
assert(task && "Couldn't get the task from TLS!");
173+
return task;
174+
}
175+
176+
#endif
177+
178+
// NB: Runs on the Rust stack
179+
inline stk_seg *
180+
rust_task_thread::borrow_c_stack() {
181+
I(this, cached_c_stack);
182+
stk_seg *your_stack;
183+
if (extra_c_stack) {
184+
your_stack = extra_c_stack;
185+
extra_c_stack = NULL;
186+
} else {
187+
your_stack = cached_c_stack;
188+
cached_c_stack = NULL;
189+
}
190+
return your_stack;
191+
}
192+
193+
// NB: Runs on the Rust stack
194+
inline void
195+
rust_task_thread::return_c_stack(stk_seg *stack) {
196+
I(this, !extra_c_stack);
197+
if (!cached_c_stack) {
198+
cached_c_stack = stack;
199+
} else {
200+
extra_c_stack = stack;
201+
}
202+
}
203+
204+
153205
//
154206
// Local Variables:
155207
// mode: C++

src/rt/rust_upcall.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
7575
abort();
7676
}
7777

78-
task = rust_task_thread::get_task();
7978
task->record_stack_limit();
8079
}
8180

0 commit comments

Comments
 (0)