about summary refs log tree commit diff
path: root/src/rt
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-02-10 16:13:50 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-02-13 20:31:17 -0800
commit301ff0c2df3d26a5b287ab61d80f5ca7845e827b (patch)
treea051d9b5683c6a522b4900abfad65356f6d73a50 /src/rt
parent21a064d5a340a00042c81745cc7d2a65691e84be (diff)
downloadrust-301ff0c2df3d26a5b287ab61d80f5ca7845e827b.tar.gz
rust-301ff0c2df3d26a5b287ab61d80f5ca7845e827b.zip
Remove two allocations from spawning a green task
Two unfortunate allocations were wrapping a proc() in a proc() with
GreenTask::build_start_wrapper, and then boxing this proc in a ~proc() inside of
Context::new(). Both of these allocations were a direct result from two
conditions:

1. The Context::new() function has a nice api of taking a procedure argument to
   start up a new context with. This inherently required an allocation by
   build_start_wrapper because extra code needed to be run around the edges of a
   user-provided proc() for a new task.

2. The initial bootstrap code only understood how to pass one argument to the
   next function. By modifying the assembly and entry points to understand more
   than one argument, more information is passed through in registers instead of
   allocating a pointer-sized context.

This is sadly where I end up throwing mips under a bus because I have no idea
what's going on in the mips context switching code and don't know how to modify
it.

Closes #7767
cc #11389
Diffstat (limited to 'src/rt')
-rw-r--r--src/rt/arch/arm/_context.S8
-rw-r--r--src/rt/arch/x86_64/_context.S33
2 files changed, 41 insertions, 0 deletions
diff --git a/src/rt/arch/arm/_context.S b/src/rt/arch/arm/_context.S
index 4ab463d968e..fb6db57414a 100644
--- a/src/rt/arch/arm/_context.S
+++ b/src/rt/arch/arm/_context.S
@@ -51,3 +51,11 @@ rust_swap_registers:
 	msr cpsr_cxsf, r2
 
 	mov pc, lr
+
+// For reasons of this existence, see the comments in x86_64/_context.S
+.globl rust_bootstrap_green_task
+rust_bootstrap_green_task:
+        mov r0, r0
+        mov r1, r3
+        mov r2, r4
+        mov pc, r5
diff --git a/src/rt/arch/x86_64/_context.S b/src/rt/arch/x86_64/_context.S
index 74f20650f30..36caf7720c4 100644
--- a/src/rt/arch/x86_64/_context.S
+++ b/src/rt/arch/x86_64/_context.S
@@ -157,3 +157,36 @@ SWAP_REGISTERS:
         // Jump to the instruction pointer
         // found in regs:
         jmp *(RUSTRT_IP*8)(ARG1)
+
+// This function below, rust_bootstrap_green_task, is used to initialize a green
+// task. This code is the very first code that is run whenever a green task
+// starts. The only assumptions that this code makes is that it has a register
+// context previously set up by Context::new() and some values are in some
+// special registers.
+//
+// In theory the register context could be set up and then the context switching
+// would plop us directly into some 'extern "C" fn', but not all platforms have
+// the argument registers saved throughout a context switch (linux doesn't save
+// rdi/rsi, the first two argument registers). Instead of modifying all context
+// switches, instead the initial data for starting a green thread is shoved into
+// unrelated registers (r12/13, etc) which always need to be saved on context
+// switches anyway.
+//
+// With this strategy we get the benefit of being able to pass a fair bit of
+// contextual data from the start of a green task to its init function, as well
+// as not hindering any context switches.
+//
+// If you alter this code in any way, you likely need to update
+// src/libgreen/context.rs as well.
+
+#if defined(__APPLE__)
+#define BOOTSTRAP _rust_bootstrap_green_task
+#else
+#define BOOTSTRAP rust_bootstrap_green_task
+#endif
+.globl BOOTSTRAP
+BOOTSTRAP:
+    mov %r12, RUSTRT_ARG0_S
+    mov %r13, RUSTRT_ARG1_S
+    mov %r14, RUSTRT_ARG2_S
+    jmpq *%r15