Permalink
Browse files

Work out the kinks in the fiber stack setup

  • Loading branch information...
1 parent 5c86a26 commit 75dce8b34220cc817e0737fca9d00a9cf818802d @evanphx evanphx committed Jan 10, 2012
Showing with 285 additions and 120 deletions.
  1. +14 −101 vm/builtin/fiber.cpp
  2. +14 −1 vm/builtin/fiber.hpp
  3. +151 −0 vm/fiber_data.cpp
  4. +28 −3 vm/fiber_data.hpp
  5. +12 −1 vm/fiber_stack.cpp
  6. +12 −0 vm/fiber_stack.hpp
  7. +12 −8 vm/gc/gc.cpp
  8. +24 −2 vm/gc/gc.hpp
  9. +4 −4 vm/on_stack.hpp
  10. +8 −0 vm/vm.cpp
  11. +6 −0 vm/vm.hpp
View
@@ -22,85 +22,6 @@
namespace rubinius {
-#ifdef FIBER_ENABLED
-
-#if defined(FIBER_ASM_X8664)
-
-static void fiber_wrap_main(void) {
- __asm__ __volatile__ ("\tmovq %r13, %rdi\n\tjmpq *%r12\n");
-}
-
-static inline void fiber_switch(fiber_context_t* from, fiber_context_t* to) {
- __asm__ __volatile__ (
- "leaq 1f(%%rip), %%rax\n\t"
- "movq %%rax, (%0)\n\t" "movq %%rsp, 8(%0)\n\t" "movq %%rbp, 16(%0)\n\t"
- "movq %%rbx, 24(%0)\n\t" "movq %%r12, 32(%0)\n\t" "movq %%r13, 40(%0)\n\t"
- "movq %%r14, 48(%0)\n\t" "movq %%r15, 56(%0)\n\t"
- "movq 56(%1), %%r15\n\t" "movq 48(%1), %%r14\n\t" "movq 40(%1), %%r13\n\t"
- "movq 32(%1), %%r12\n\t" "movq 24(%1), %%rbx\n\t" "movq 16(%1), %%rbp\n\t"
- "movq 8(%1), %%rsp\n\t" "jmpq *(%1)\n" "1:\n"
- : "+S" (from), "+D" (to) :
- : "rax", "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
-}
-
-static void fiber_makectx(fiber_context_t* ctx, void* func, void** stack_bottom,
- int stack_size)
-{
- // Get a pointer to the highest address as stack that is properly aligned
- // with room for the fake return value.
- uintptr_t s = ((uintptr_t)stack_bottom) + stack_size;
- uintptr_t diff = s % 16;
-
- void** stack = (void**)(s - diff) - 1;
-
- *--stack = (void*)0xdeadcafedeadcafe; /* Dummy return address. */
- ctx->rip = (void*)fiber_wrap_main;
- ctx->rsp = stack;
- ctx->rbp = 0;
- ctx->rbx = 0;
- ctx->r12 = func;
- ctx->r13 = 0;
- ctx->r14 = 0;
- ctx->r15 = 0;
-
-}
-
-#elif defined(FIBER_ASM_X8632)
-
-static inline void fiber_switch(fiber_context_t* from, fiber_context_t* to) {
- __asm__ __volatile__ (
- "call 1f\n" "1:\tpopl %%eax\n\t" "addl $(2f-1b),%%eax\n\t"
- "movl %%eax, (%0)\n\t" "movl %%esp, 4(%0)\n\t"
- "movl %%ebp, 8(%0)\n\t" "movl %%ebx, 12(%0)\n\t"
- "movl 12(%1), %%ebx\n\t" "movl 8(%1), %%ebp\n\t"
- "movl 4(%1), %%esp\n\t" "jmp *(%1)\n" "2:\n"
- : "+S" (from), "+D" (to) : : "eax", "ecx", "edx", "memory", "cc");
-}
-
-static void fiber_makectx(fiber_context_t* ctx, void* func, void** stack_bottom,
- int stack_size)
-{
- // Get a pointer to the highest address as stack that is properly aligned
- // with room for the fake return value.
- uintptr_t s = ((uintptr_t)stack_bottom) + stack_size;
- uintptr_t diff = s % 16;
-
- void** stack = (void**)(s - diff) - 1;
-
- *--stack = (void*)0xdeadcafe;
-
- ctx->eip = func;
- ctx->esp = stack;
- ctx->ebp = 0;
-}
-#endif
-
-#endif
-
-}
-
-namespace rubinius {
-
void Fiber::init(STATE) {
GO(fiber).set(ontology::new_class(state, "Fiber", G(object), G(rubinius)));
G(fiber)->set_object_type(state, FiberType);
@@ -128,7 +49,7 @@ namespace rubinius {
fib->status_ = Fiber::eRunning;
fib->vm_ = state->vm();
- fib->data_ = new FiberData;
+ fib->data_ = new FiberData(true);
state->memory()->needs_finalization(fib, (FinalizerFunction)&Fiber::finalize);
@@ -178,14 +99,11 @@ namespace rubinius {
}
}
- fib->data_->orphan(&state);
-
dest->run();
dest->value(&state, result);
state.vm()->set_current_fiber(dest);
- fiber_context_t dummy;
- fiber_switch(&dummy, dest->ucontext());
+ dest->data_->switch_and_orphan(&state, fib->data_);
assert(0 && "fatal start_on_stack error");
#else
@@ -238,24 +156,12 @@ namespace rubinius {
Fiber* cur = Fiber::current(state);
prev(state, cur);
- if(data_->uninitialized_p()) {
- FiberStack* stack = data_->allocate_stack(state);
-
- data_->take_stack(state);
-
- fiber_makectx(ucontext(), (void*)start_on_stack,
- (void**)stack->address(),
- stack->size());
- } else {
- data_->take_stack(state);
- }
-
cur->sleep(calling_environment);
run();
state->vm()->set_current_fiber(this);
- fiber_switch(cur->ucontext(), ucontext());
+ data_->switch_to(state, cur->data_);
// Back here when someone yields back to us!
// Beware here, because the GC has probably run so GC pointers on the C++ stack
@@ -303,7 +209,7 @@ namespace rubinius {
run();
state->vm()->set_current_fiber(this);
- fiber_switch(cur->ucontext(), ucontext());
+ data_->switch_to(state, cur->data_);
// Back here when someone transfers back to us!
// Beware here, because the GC has probably run so GC pointers on the C++ stack
@@ -352,7 +258,7 @@ namespace rubinius {
dest_fib->run();
state->vm()->set_current_fiber(dest_fib);
- fiber_switch(cur->ucontext(), dest_fib->ucontext());
+ dest_fib->data_->switch_to(state, cur->data_);
// Back here when someone yields back to us!
// Beware here, because the GC has probably run so GC pointers on the C++ stack
@@ -377,8 +283,8 @@ namespace rubinius {
void Fiber::finalize(STATE, Fiber* fib) {
#ifdef FIBER_ENABLED
+ fib->data_->orphan(state);
delete fib->data_;
- // if(fib->stack_ && !fib->root_) free(fib->stack_);
#endif
}
@@ -388,9 +294,16 @@ namespace rubinius {
mark.remember_object(obj);
Fiber* fib = (Fiber*)obj;
+
+ AddressDisplacement dis(fib->data_->data_offset(),
+ fib->data_->data_lower_bound(),
+ fib->data_->data_upper_bound());
+
if(CallFrame* cf = fib->call_frame()) {
- mark.gc->walk_call_frame(cf, fib->data_->data_offset());
+ mark.gc->walk_call_frame(cf, &dis);
}
+
+ mark.gc->scan(fib->data_->variable_root_buffers(), false, &dis);
}
}
View
@@ -31,11 +31,16 @@ namespace rubinius {
bool root_;
FiberData* data_;
+
public:
attr_accessor(starter, Object);
attr_accessor(value, Array);
attr_accessor(prev, Fiber);
- attr_accessor(exception, Exception)
+ attr_accessor(exception, Exception);
+
+ bool root_p() {
+ return root_;
+ }
CallFrame* call_frame() {
return top_;
@@ -59,6 +64,10 @@ namespace rubinius {
return vm_;
}
+ FiberData* data() {
+ return data_;
+ }
+
void* stack() {
return data_->stack_address();
}
@@ -67,6 +76,10 @@ namespace rubinius {
return data_->stack_size();
}
+ VariableRootBuffers& variable_root_buffers() {
+ return data_->variable_root_buffers();
+ }
+
public:
static void init(STATE);
View
@@ -1,5 +1,96 @@
#include "vm/vm.hpp"
#include "vm/fiber_data.hpp"
+#include "builtin/fiber.hpp"
+
+namespace rubinius {
+
+#ifdef FIBER_ENABLED
+
+#if defined(FIBER_ASM_X8664)
+
+static void fiber_wrap_main(void) {
+ __asm__ __volatile__ ("\tmovq %r13, %rdi\n\tjmpq *%r12\n");
+}
+
+static inline void fiber_switch(fiber_context_t* from, fiber_context_t* to) {
+ __asm__ __volatile__ (
+ "leaq 1f(%%rip), %%rax\n\t"
+ "movq %%rax, (%0)\n\t"
+ "movq %%rsp, 8(%0)\n\t"
+ "movq %%rbp, 16(%0)\n\t"
+ "movq %%rbx, 24(%0)\n\t"
+ "movq %%r12, 32(%0)\n\t"
+ "movq %%r13, 40(%0)\n\t"
+ "movq %%r14, 48(%0)\n\t"
+ "movq %%r15, 56(%0)\n\t"
+ "movq 56(%1), %%r15\n\t"
+ "movq 48(%1), %%r14\n\t"
+ "movq 40(%1), %%r13\n\t"
+ "movq 32(%1), %%r12\n\t"
+ "movq 24(%1), %%rbx\n\t"
+ "movq 16(%1), %%rbp\n\t"
+ "movq 8(%1), %%rsp\n\t"
+ "jmpq *(%1)\n" "1:\n"
+
+ : "+S" (from), "+D" (to) :
+ : "rax", "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
+}
+
+static void fiber_makectx(fiber_context_t* ctx, void* func, void** stack_bottom,
+ int stack_size)
+{
+ // Get a pointer to the highest address as stack that is properly aligned
+ // with room for the fake return value.
+ uintptr_t s = ((uintptr_t)stack_bottom) + stack_size;
+ uintptr_t diff = s % 16;
+
+ void** stack = (void**)(s - diff) - 1;
+
+ *--stack = (void*)0xdeadcafedeadcafe; /* Dummy return address. */
+ ctx->rip = (void*)fiber_wrap_main;
+ ctx->rsp = stack;
+ ctx->rbp = 0;
+ ctx->rbx = 0;
+ ctx->r12 = func;
+ ctx->r13 = 0;
+ ctx->r14 = 0;
+ ctx->r15 = 0;
+
+}
+
+#elif defined(FIBER_ASM_X8632)
+
+static inline void fiber_switch(fiber_context_t* from, fiber_context_t* to) {
+ __asm__ __volatile__ (
+ "call 1f\n" "1:\tpopl %%eax\n\t" "addl $(2f-1b),%%eax\n\t"
+ "movl %%eax, (%0)\n\t" "movl %%esp, 4(%0)\n\t"
+ "movl %%ebp, 8(%0)\n\t" "movl %%ebx, 12(%0)\n\t"
+ "movl 12(%1), %%ebx\n\t" "movl 8(%1), %%ebp\n\t"
+ "movl 4(%1), %%esp\n\t" "jmp *(%1)\n" "2:\n"
+ : "+S" (from), "+D" (to) : : "eax", "ecx", "edx", "memory", "cc");
+}
+
+static void fiber_makectx(fiber_context_t* ctx, void* func, void** stack_bottom,
+ int stack_size)
+{
+ // Get a pointer to the highest address as stack that is properly aligned
+ // with room for the fake return value.
+ uintptr_t s = ((uintptr_t)stack_bottom) + stack_size;
+ uintptr_t diff = s % 16;
+
+ void** stack = (void**)(s - diff) - 1;
+
+ *--stack = (void*)0xdeadcafe;
+
+ ctx->eip = func;
+ ctx->esp = stack;
+ ctx->ebp = 0;
+}
+#endif
+
+#endif
+
+}
namespace rubinius {
void FiberData::take_stack(STATE) {
@@ -20,6 +111,9 @@ namespace rubinius {
}
void FiberData::copy_to_heap(STATE) {
+ assert(status_ != eDead);
+ assert(stack_);
+
heap_size_ = (uintptr_t)stack_->top_address() - (uintptr_t)stack_bottom();
if(heap_capacity_ < heap_size_) {
// Round to nearest 1k
@@ -42,7 +136,64 @@ namespace rubinius {
void FiberData::orphan(STATE) {
status_ = eDead;
+ if(!stack_) return;
+
stack_->orphan(state, this);
stack_ = 0;
}
+
+ static void save_and_switch() {
+ VM* vm = VM::current();
+ State state(vm);
+
+ Fiber* fib = Fiber::current(&state);
+
+ fib->data()->take_stack(&state);
+
+ fiber_context_t tmp;
+ fiber_switch(&tmp, fib->ucontext());
+ }
+
+ void FiberData::switch_to(STATE, FiberData* from) {
+ if(uninitialized_p()) {
+ FiberStack* stack = allocate_stack(state);
+
+ fiber_makectx(machine(), (void*)Fiber::start_on_stack,
+ (void**)stack->address(),
+ stack->size());
+ }
+
+ if(currently_on_stack_p(from)) {
+ fiber_context_t dest;
+
+ fiber_makectx(&dest, (void*)save_and_switch,
+ (void**)state->vm()->fiber_trampoline(),
+ 4096);
+
+ fiber_switch(from->machine(), &dest);
+ } else {
+ take_stack(state);
+ fiber_switch(from->machine(), machine());
+ }
+ }
+
+ void FiberData::switch_and_orphan(STATE, FiberData* from) {
+ fiber_context_t dummy;
+
+ if(currently_on_stack_p(from)) {
+ from->orphan(state);
+
+ fiber_context_t dest;
+
+ fiber_makectx(&dest, (void*)save_and_switch,
+ (void**)state->vm()->fiber_trampoline(),
+ 4096);
+
+ fiber_switch(&dummy, &dest);
+ } else {
+ from->orphan(state);
+ take_stack(state);
+ fiber_switch(&dummy, machine());
+ }
+ }
}
Oops, something went wrong.

0 comments on commit 75dce8b

Please sign in to comment.