Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Restructure how fiber stacks are allocated

  • Loading branch information...
commit e38045b65a3801402b468fe32c13a10305c1f1a7 1 parent 73ff4b6
@evanphx evanphx authored
View
104 vm/builtin/fiber.cpp
@@ -20,20 +20,11 @@
#include "on_stack.hpp"
-#ifdef FIBER_NATIVE
+namespace rubinius {
-#if defined(FIBER_ASM_X8664)
+#ifdef FIBER_ENABLED
-struct fiber_context_t {
- void* rip;
- void* rsp;
- void* rbp;
- void* rbx;
- void* r12;
- void* r13;
- void* r14;
- void* r15;
-};
+#if defined(FIBER_ASM_X8664)
static void fiber_wrap_main(void) {
__asm__ __volatile__ ("\tmovq %r13, %rdi\n\tjmpq *%r12\n");
@@ -76,13 +67,6 @@ static void fiber_makectx(fiber_context_t* ctx, void* func, void** stack_bottom,
#elif defined(FIBER_ASM_X8632)
-struct fiber_context_t {
- void* eip;
- void* esp;
- void* ebp;
- void* ebx;
-};
-
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"
@@ -111,15 +95,9 @@ static void fiber_makectx(fiber_context_t* ctx, void* func, void** stack_bottom,
}
#endif
-#else // FIBER_NATIVE
-
-#ifndef FIBER_ENABLED
-struct fiber_context_t {
- int dummy;
-}
#endif
-#endif
+}
namespace rubinius {
@@ -149,14 +127,8 @@ namespace rubinius {
fib->root_ = true;
fib->status_ = Fiber::eRunning;
fib->vm_ = state->vm();
- fib->stack_size_ = state->vm()->stack_size();
- fib->stack_ = state->vm()->stack_start();
-#ifdef FIBER_NATIVE
- fib->context_ = new fiber_context_t;
-#else
- fib->context_ = new ucontext_t;
-#endif
+ fib->data_ = new FiberData;
state->memory()->needs_finalization(fib, (FinalizerFunction)&Fiber::finalize);
@@ -206,17 +178,14 @@ namespace rubinius {
}
}
+ fib->data_->orphan(&state);
+
dest->run();
dest->value(&state, result);
state.vm()->set_current_fiber(dest);
-#ifdef FIBER_NATIVE
fiber_context_t dummy;
fiber_switch(&dummy, dest->ucontext());
-#else
- if(setcontext(dest->ucontext()) != 0)
- assert(0 && "fatal swapcontext() error");
-#endif
assert(0 && "fatal start_on_stack error");
#else
@@ -242,28 +211,10 @@ namespace rubinius {
fib->root_ = false;
fib->vm_ = 0;
fib->status_ = Fiber::eSleeping;
- fib->stack_size_ = stack_size;
- fib->stack_ = malloc(stack_size);
-
- state->memory()->needs_finalization(fib, (FinalizerFunction)&Fiber::finalize);
-#ifdef FIBER_NATIVE
- fib->context_ = new fiber_context_t;
- fiber_makectx(fib->ucontext(), (void*)start_on_stack, (void**)fib->stack_,
- stack_size);
-#else
- fib->context_ = new ucontext_t;
- ucontext_t* ctx = fib->ucontext();
-
- if(getcontext(ctx) != 0) assert(0 && "fatal getcontext() error");
+ fib->data_ = new FiberData;
- ctx->uc_link = 0;
- ctx->uc_stack.ss_sp = (char *) fib->stack_;
- ctx->uc_stack.ss_size = stack_size;
- ctx->uc_stack.ss_flags = 0;
-
- makecontext(ctx, start_on_stack, 0);
-#endif
+ state->memory()->needs_finalization(fib, (FinalizerFunction)&Fiber::finalize);
return fib;
#else
@@ -287,17 +238,24 @@ 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);
-#ifdef FIBER_NATIVE
- fiber_switch(cur->ucontext(), context_);
-#else
- if(swapcontext(cur->ucontext(), context_) != 0)
- assert(0 && "fatal swapcontext() error");
-#endif
+ fiber_switch(cur->ucontext(), ucontext());
// Back here when someone yields back to us!
// Beware here, because the GC has probably run so GC pointers on the C++ stack
@@ -345,12 +303,7 @@ namespace rubinius {
run();
state->vm()->set_current_fiber(this);
-#ifdef FIBER_NATIVE
- fiber_switch(cur->ucontext(), context_);
-#else
- if(swapcontext(cur->ucontext(), context_) != 0)
- assert(0 && "fatal swapcontext() error");
-#endif
+ fiber_switch(cur->ucontext(), ucontext());
// Back here when someone transfers back to us!
// Beware here, because the GC has probably run so GC pointers on the C++ stack
@@ -399,12 +352,7 @@ namespace rubinius {
dest_fib->run();
state->vm()->set_current_fiber(dest_fib);
-#ifdef FIBER_NATIVE
fiber_switch(cur->ucontext(), dest_fib->ucontext());
-#else
- if(swapcontext(cur->ucontext(), dest_fib->ucontext()) != 0)
- assert(0 && "fatal swapcontext() error");
-#endif
// Back here when someone yields back to us!
// Beware here, because the GC has probably run so GC pointers on the C++ stack
@@ -429,8 +377,8 @@ namespace rubinius {
void Fiber::finalize(STATE, Fiber* fib) {
#ifdef FIBER_ENABLED
- delete fib->context_;
- if(fib->stack_ && !fib->root_) free(fib->stack_);
+ delete fib->data_;
+ // if(fib->stack_ && !fib->root_) free(fib->stack_);
#endif
}
@@ -441,7 +389,7 @@ namespace rubinius {
Fiber* fib = (Fiber*)obj;
if(CallFrame* cf = fib->call_frame()) {
- mark.gc->walk_call_frame(cf);
+ mark.gc->walk_call_frame(cf, fib->data_->data_offset());
}
}
}
View
37 vm/builtin/fiber.hpp
@@ -1,36 +1,15 @@
#ifndef RBX_BUILTIN_FIBER
#define RBX_BUILTIN_FIBER
-#include "vm/config.h"
-
-#if defined(IS_X86)
-#define FIBER_ENABLED
-#define FIBER_NATIVE
-#define FIBER_ASM_X8632
-struct fiber_context_t;
-
-#elif defined(IS_X8664)
-#define FIBER_ENABLED
-#define FIBER_NATIVE
-#define FIBER_ASM_X8664
-struct fiber_context_t;
-
-#elif defined(HAS_UCONTEXT)
-#define FIBER_ENABLED
-#include <ucontext.h>
-typedef ucontext_t fiber_context_t;
-
-#else
-struct fiber_context_t;
-#endif
-
-
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include "prelude.hpp"
#include "builtin/object.hpp"
+#include "fiber_data.hpp"
+
namespace rubinius {
class Fiber : public Object {
public:
@@ -50,10 +29,8 @@ namespace rubinius {
VM* vm_;
bool root_;
- void* stack_;
- int stack_size_;
- fiber_context_t* context_;
+ FiberData* data_;
public:
attr_accessor(starter, Object);
attr_accessor(value, Array);
@@ -75,7 +52,7 @@ namespace rubinius {
}
fiber_context_t* ucontext() {
- return context_;
+ return data_->machine();
}
VM* vm() {
@@ -83,11 +60,11 @@ namespace rubinius {
}
void* stack() {
- return stack_;
+ return data_->stack_address();
}
int stack_size() {
- return stack_size_;
+ return data_->stack_size();
}
public:
View
48 vm/fiber_data.cpp
@@ -0,0 +1,48 @@
+#include "vm/vm.hpp"
+#include "vm/fiber_data.hpp"
+
+namespace rubinius {
+ void FiberData::take_stack(STATE) {
+ assert(stack_);
+
+ assert(status_ != eDead);
+
+ if(status_ == eOnStack || status_ == eRunning) return;
+
+ if(stack_->shared_p()) stack_->flush(state);
+ stack_->set_user(this);
+
+ if(status_ == eOnHeap) {
+ memcpy(stack_bottom(), heap_, heap_size_);
+ }
+
+ status_ = eOnStack;
+ }
+
+ void FiberData::copy_to_heap(STATE) {
+ heap_size_ = (uintptr_t)stack_->top_address() - (uintptr_t)stack_bottom();
+ if(heap_capacity_ < heap_size_) {
+ // Round to nearest 1k
+ heap_capacity_ = (heap_size_ + 1023) & ~1023;
+
+ if(heap_) free(heap_);
+ heap_ = malloc(heap_capacity_);
+ }
+
+ memcpy(heap_, stack_bottom(), heap_size_);
+
+ status_ = eOnHeap;
+ }
+
+ FiberStack* FiberData::allocate_stack(STATE) {
+ assert(!stack_);
+ stack_ = state->vm()->allocate_fiber_stack();
+ return stack_;
+ }
+
+ void FiberData::orphan(STATE) {
+ status_ = eDead;
+ stack_->orphan(state, this);
+ stack_ = 0;
+ }
+}
View
108 vm/fiber_data.hpp
@@ -0,0 +1,108 @@
+#ifndef RBX_VM_FIBER_DATA_HPP
+#define RBX_VM_FIBER_DATA_HPP
+
+#include "vm/config.h"
+#include "prelude.hpp"
+
+namespace rubinius {
+
+#if defined(IS_X86)
+#define FIBER_ENABLED
+#define FIBER_ASM_X8632
+ struct fiber_context_t {
+ void* eip;
+ void* esp;
+ void* ebp;
+ void* ebx;
+ };
+
+#elif defined(IS_X8664)
+#define FIBER_ENABLED
+#define FIBER_ASM_X8664
+ struct fiber_context_t {
+ void* rip;
+ void* rsp;
+ void* rbp;
+ void* rbx;
+ void* r12;
+ void* r13;
+ void* r14;
+ void* r15;
+ };
+
+#else
+ struct fiber_context_t {
+ int dummy;
+ }
+#endif
+
+ class FiberStack;
+
+ class FiberData {
+ fiber_context_t machine_;
+
+ enum Status {
+ eInitial = 1,
+ eRunning,
+ eOnStack,
+ eOnHeap,
+ eDead
+ } status_;
+
+ FiberStack* stack_;
+
+ void* heap_;
+ size_t heap_size_;
+ size_t heap_capacity_;
+
+ public:
+
+ FiberData()
+ : status_(eInitial)
+ , stack_(0)
+ , heap_(0)
+ , heap_size_(0)
+ , heap_capacity_(0)
+ {}
+
+ bool uninitialized_p() {
+ return stack_ == 0;
+ }
+
+ fiber_context_t* machine() {
+ return &machine_;
+ }
+
+ void* stack_address() {
+ return stack_ ? stack_->address() : 0;
+ }
+
+ size_t stack_size() {
+ return stack_ ? stack_->size() : 0;
+ }
+
+ void* stack_bottom() {
+#if defined(FIBER_ASM_X8632)
+ return machine_.esp;
+#elif defined(FIBER_ASM_X8664)
+ return machine_.rsp;
+#else
+#error "not supported, you shouldn't be here"
+#endif
+ }
+
+ intptr_t data_offset() {
+ if(status_ != eOnHeap) return 0;
+ return (intptr_t)heap_ - (intptr_t)stack_bottom();
+ }
+
+ FiberStack* allocate_stack(STATE);
+ void take_stack(STATE);
+ void copy_stack(STATE, void* addr, size_t size);
+ void copy_to_heap(STATE);
+
+ void orphan(STATE);
+ };
+
+}
+#endif
View
76 vm/fiber_stack.cpp
@@ -0,0 +1,76 @@
+#include "vm.hpp"
+#include "fiber_stack.hpp"
+#include "fiber_data.hpp"
+
+#include "bug.hpp"
+
+#include <stdlib.h>
+
+namespace rubinius {
+
+ FiberStack::FiberStack(size_t size)
+ : address_(0)
+ , size_(size)
+ , refs_(0)
+ , user_(0)
+ {}
+
+ void FiberStack::allocate() {
+ assert(!address_);
+ address_ = malloc(size_);
+ }
+
+ void FiberStack::free() {
+ if(!address_) return;
+ ::free(address_);
+ address_ = 0;
+ }
+
+ void FiberStack::flush(STATE) {
+ if(!user_) return;
+
+ // TODO assumes higher to lower stack growth.
+ user_->copy_to_heap(state);
+ }
+
+ void FiberStack::orphan(STATE, FiberData* user) {
+ assert(user_ == user);
+ dec_ref();
+ }
+
+ FiberStack* FiberStacks::allocate() {
+ for(Stacks::iterator i = stacks_.begin();
+ i != stacks_.end();
+ ++i)
+ {
+ if(i->unused_p()) {
+ i->inc_ref();
+ return &*i;
+ }
+ }
+
+ FiberStack* stack = 0;
+
+ if(stacks_.size() < cMaxStacks) {
+ stacks_.push_back(FiberStack(cStackSize));
+ stack = &stacks_.back();
+
+ stack->allocate();
+ } else {
+ for(Stacks::iterator i = stacks_.begin();
+ i != stacks_.end();
+ ++i)
+ {
+ if(!stack || i->refs() < stack->refs()) {
+ stack = &*i;
+ }
+ }
+
+ assert(stack);
+ }
+
+ stack->inc_ref();
+
+ return stack;
+ }
+}
View
70 vm/fiber_stack.hpp
@@ -0,0 +1,70 @@
+#ifndef RBX_VM_FIBER_STACK_HPP
+#define RBX_VM_FIBER_STACK_HPP
+
+namespace rubinius {
+ class FiberData;
+
+ class FiberStack {
+ void* address_;
+ size_t size_;
+ int refs_;
+ FiberData* user_;
+
+ public:
+ FiberStack(size_t size);
+
+ void* address() {
+ return address_;
+ }
+
+ void* top_address() {
+ return (void*)((char*)address_ + size_);
+ }
+
+ size_t size() {
+ return size_;
+ }
+
+ void inc_ref() {
+ refs_++;
+ }
+
+ void dec_ref() {
+ refs_--;
+ }
+
+ int refs() {
+ return refs_;
+ }
+
+ bool unused_p() {
+ return refs_ == 0;
+ }
+
+ bool shared_p() {
+ return user_ && refs_ > 1;
+ }
+
+ void set_user(FiberData* d) {
+ user_ = d;
+ }
+
+ void allocate();
+ void free();
+ void flush(STATE);
+ void orphan(STATE, FiberData* user);
+ };
+
+ class FiberStacks {
+ typedef std::list<FiberStack> Stacks;
+ const static size_t cStackSize = 128 * 1024;
+ const static size_t cMaxStacks = 1;
+
+ Stacks stacks_;
+
+ public:
+ FiberStack* allocate();
+ };
+}
+
+#endif
View
16 vm/gc/gc.cpp
@@ -148,13 +148,22 @@ namespace rubinius {
}
}
+ template <typename T>
+ T displace(T ptr, intptr_t by) {
+ return (T)((char*)ptr + by);
+ }
/**
* Walks the chain of objects accessible from the specified CallFrame.
*/
- void GarbageCollector::walk_call_frame(CallFrame* top_call_frame) {
+ void GarbageCollector::walk_call_frame(CallFrame* top_call_frame,
+ intptr_t offset)
+ {
CallFrame* call_frame = top_call_frame;
+
while(call_frame) {
+ call_frame = displace(call_frame, offset);
+
// Skip synthetic, non CompiledMethod frames
if(!call_frame->cm) {
call_frame = call_frame->previous;
@@ -182,8 +191,7 @@ namespace rubinius {
}
}
- if(call_frame->multiple_scopes_p() &&
- call_frame->top_scope_) {
+ if(call_frame->multiple_scopes_p() && call_frame->top_scope_) {
call_frame->top_scope_ = (VariableScope*)mark_object(call_frame->top_scope_);
}
@@ -222,7 +230,7 @@ namespace rubinius {
}
#endif
- saw_variable_scope(call_frame, call_frame->scope);
+ saw_variable_scope(call_frame, displace(call_frame->scope, offset));
call_frame = static_cast<CallFrame*>(call_frame->previous);
}
View
2  vm/gc/gc.hpp
@@ -124,7 +124,7 @@ namespace rubinius {
// Scans the specified Object for references to other Objects.
void scan_object(Object* obj);
void delete_object(Object* obj);
- void walk_call_frame(CallFrame* top_call_frame);
+ void walk_call_frame(CallFrame* top_call_frame, intptr_t offset=0);
void saw_variable_scope(CallFrame* call_frame, StackVariables* scope);
/**
View
7 vm/vm.hpp
@@ -19,6 +19,8 @@
#include "shared_state.hpp"
+#include "fiber_stack.hpp"
+
#include <vector>
#include <setjmp.h>
@@ -94,6 +96,7 @@ namespace rubinius {
rbxti::Env* tooling_env_;
bool tooling_;
bool allocation_tracking_;
+ FiberStacks fiber_stacks_;
public:
/* Data members */
@@ -258,6 +261,10 @@ namespace rubinius {
allocation_tracking_ = false;
}
+ FiberStack* allocate_fiber_stack() {
+ return fiber_stacks_.allocate();
+ }
+
public:
static void init_stack_size();
Please sign in to comment.
Something went wrong with that request. Please try again.