diff --git a/src/compiler/crystal/interpreter/context.cr b/src/compiler/crystal/interpreter/context.cr index 987781c4aefb..06a67c456370 100644 --- a/src/compiler/crystal/interpreter/context.cr +++ b/src/compiler/crystal/interpreter/context.cr @@ -106,10 +106,10 @@ class Crystal::Repl::Context # Once the block returns, the stack is returned to the pool. # The stack is not cleared after or before it's used. def checkout_stack(& : UInt8* -> _) - stack, _ = @stack_pool.checkout + stack = @stack_pool.checkout begin - yield stack.as(UInt8*) + yield stack.pointer.as(UInt8*) ensure @stack_pool.release(stack) end diff --git a/src/fiber.cr b/src/fiber.cr index 67643202c8c1..d3144af8cbec 100644 --- a/src/fiber.cr +++ b/src/fiber.cr @@ -98,7 +98,14 @@ class Fiber # # *name* is an optional and used only as an internal reference. def self.new(name : String? = nil, &proc : ->) - new(name, Stack.new, &proc) + stack = + {% if flag?(:interpreted) %} + # the interpreter is managing the stacks + Stack.new(Pointer(Void).null, 0) + {% else %} + Crystal::Scheduler.stack_pool.checkout + {% end %} + new(name, stack, &proc) end # :nodoc: @@ -159,7 +166,7 @@ class Fiber @alive = false {% unless flag?(:interpreted) %} - @stack.release + Crystal::Scheduler.stack_pool.release(@stack) {% end %} Fiber.suspend end diff --git a/src/fiber/stack.cr b/src/fiber/stack.cr index 963db2a4f40f..fb0384ab3445 100644 --- a/src/fiber/stack.cr +++ b/src/fiber/stack.cr @@ -2,29 +2,24 @@ class Fiber # :nodoc: struct Stack getter pointer : Void* - getter bottom : Void* + getter bytesize : Int32 getter? reusable : Bool - def self.new : self - {% if flag?(:interpreted) %} - new Pointer(Void).null, Pointer(Void).null - {% else %} - stack, stack_bottom = Crystal::Scheduler.stack_pool.checkout - new(stack, stack_bottom, reusable: true) - {% end %} + def initialize(@pointer, bottom : Void*, *, @reusable = false) + @bytesize = (bottom - @pointer).to_i32 end - def initialize(@pointer, @bottom, *, @reusable = false) + def initialize(@pointer, @bytesize, *, @reusable = false) + end + + def bottom : Void* + @pointer + @bytesize end def first_addressable_pointer : Void** - ptr = @bottom # stacks grow down + ptr = bottom # stacks grow down ptr -= sizeof(Void*) # point to first addressable pointer Pointer(Void*).new(ptr.address & ~15_u64) # align to 16 bytes end - - def release : Nil - Crystal::Scheduler.stack_pool.release(@pointer) if @reusable - end end end diff --git a/src/fiber/stack_pool.cr b/src/fiber/stack_pool.cr index 8f809335f46c..09475d55da41 100644 --- a/src/fiber/stack_pool.cr +++ b/src/fiber/stack_pool.cr @@ -12,12 +12,12 @@ class Fiber # Interpreter stacks grow upwards (pushing values increases the stack # pointer value) rather than downwards, so *protect* must be false. def initialize(@protect : Bool = true) - @deque = Deque(Void*).new + @deque = Deque(Stack).new end def finalize @deque.each do |stack| - Crystal::System::Fiber.free_stack(stack, STACK_SIZE) + Crystal::System::Fiber.free_stack(stack.pointer, stack.bytesize) end end @@ -26,7 +26,7 @@ class Fiber def collect(count = lazy_size // 2) : Nil count.times do if stack = @deque.shift? - Crystal::System::Fiber.free_stack(stack, STACK_SIZE) + Crystal::System::Fiber.free_stack(stack.pointer, stack.bytesize) else return end @@ -41,18 +41,19 @@ class Fiber end # Removes a stack from the bottom of the pool, or allocates a new one. - def checkout : {Void*, Void*} + def checkout : Stack if stack = @deque.pop? - Crystal::System::Fiber.reset_stack(stack, STACK_SIZE, @protect) + Crystal::System::Fiber.reset_stack(stack.pointer, stack.bytesize, @protect) + stack else - stack = Crystal::System::Fiber.allocate_stack(STACK_SIZE, @protect) + pointer = Crystal::System::Fiber.allocate_stack(STACK_SIZE, @protect) + Stack.new(pointer, STACK_SIZE) end - {stack, stack + STACK_SIZE} end # Appends a stack to the bottom of the pool. - def release(stack) : Nil - @deque.push(stack) + def release(stack : Stack) : Nil + @deque.push(stack) if stack.reusable? end # Returns the approximated size of the pool. It may be equal or slightly