Ruby  3.1.4p223 (2023-03-30 revision HEAD)
Context.h
1 #ifndef COROUTINE_PPC64LE_CONTEXT_H
2 #define COROUTINE_PPC64LE_CONTEXT_H 1
3 
4 #pragma once
5 
6 #include <assert.h>
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <string.h>
10 
11 #define COROUTINE __attribute__((noreturn)) void
12 
13 enum {
14  COROUTINE_REGISTERS =
15  19 /* 18 general purpose registers (r14-r31) and 1 return address */
16  + 4 /* space for fiber_entry() to store the link register */
17 };
18 
19 struct coroutine_context
20 {
21  void **stack_pointer;
22  void *argument;
23 };
24 
25 typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
26 
27 static inline void coroutine_initialize_main(struct coroutine_context * context) {
28  context->stack_pointer = NULL;
29 }
30 
31 static inline void coroutine_initialize(
32  struct coroutine_context *context,
33  coroutine_start start,
34  void *stack,
35  size_t size
36 ) {
37  assert(start && stack && size >= 1024);
38 
39  // Stack grows down. Force 16-byte alignment.
40  char * top = (char*)stack + size;
41  context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
42 
43  context->stack_pointer -= COROUTINE_REGISTERS;
44  memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
45 
46  /* Skip a global prologue that sets the TOC register */
47  context->stack_pointer[18] = ((char*)start) + 8;
48 }
49 
50 struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
51 
52 static inline void coroutine_destroy(struct coroutine_context * context)
53 {
54  context->stack_pointer = NULL;
55 }
56 
57 #endif /* COROUTINE_PPC64LE_CONTEXT_H */