Skip to content

Commit 7d1dd60

Browse files
authored
Merge pull request ruby#125 from Shopify/code_pages
Code page GC object
2 parents e8a5c7b + 34a0954 commit 7d1dd60

File tree

4 files changed

+69
-27
lines changed

4 files changed

+69
-27
lines changed

yjit_asm.c

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -224,18 +224,11 @@ uint8_t* alloc_exec_mem(uint32_t mem_size)
224224
// How many code pages to allocate at once
225225
#define PAGES_PER_ALLOC 512
226226

227-
typedef struct free_list_node
228-
{
229-
uint8_t* page_ptr;
230-
231-
struct free_list_node *next;
232-
233-
} freelist_t;
234-
235-
freelist_t *freelist = NULL;
227+
// Head of the list of free code pages
228+
code_page_t *freelist = NULL;
236229

237230
// Allocate a single code page from a pool of free pages
238-
uint8_t* alloc_code_page()
231+
code_page_t* alloc_code_page()
239232
{
240233
fprintf(stderr, "allocating code page\n");
241234

@@ -246,29 +239,25 @@ uint8_t* alloc_code_page()
246239

247240
// Do this in reverse order so we allocate our pages in order
248241
for (int i = PAGES_PER_ALLOC - 1; i >= 0; --i) {
249-
freelist_t* node = malloc(sizeof(freelist_t));
250-
node->page_ptr = code_chunk + i * CODE_PAGE_SIZE;
251-
node->next = freelist;
252-
freelist = node;
242+
code_page_t* code_page = malloc(sizeof(code_page_t));
243+
code_page->mem_block = code_chunk + i * CODE_PAGE_SIZE;
244+
code_page->page_size = CODE_PAGE_SIZE;
245+
code_page->_next = freelist;
246+
freelist = code_page;
253247
}
254248
}
255249

256-
freelist_t* free_node = freelist;
257-
uint8_t* page_ptr = freelist->page_ptr;
258-
259-
freelist = freelist->next;
260-
free(free_node);
250+
code_page_t* free_page = freelist;
251+
freelist = freelist->_next;
261252

262-
return page_ptr;
253+
return free_page;
263254
}
264255

265256
// Put a code page back into the allocation pool
266-
void free_code_page(uint8_t* page_ptr)
257+
void free_code_page(code_page_t* code_page)
267258
{
268-
freelist_t* node = malloc(sizeof(freelist_t));
269-
node->page_ptr = page_ptr;
270-
node->next = freelist;
271-
freelist = node;
259+
code_page->_next = freelist;
260+
freelist = code_page;
272261
}
273262

274263
// Initialize a code block object

yjit_asm.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,20 @@ typedef struct X86Opnd
131131

132132
} x86opnd_t;
133133

134+
// Struct representing a code page
135+
typedef struct code_page_struct
136+
{
137+
// Chunk of executable memory
138+
uint8_t* mem_block;
139+
140+
// Size of the executable memory chunk
141+
uint32_t page_size;
142+
143+
// Next node in the free list (private)
144+
struct code_page_struct* _next;
145+
146+
} code_page_t;
147+
134148
// Dummy none/null operand
135149
static const x86opnd_t NO_OPND = { OPND_NONE, 0, .as.imm = 0 };
136150

@@ -242,8 +256,8 @@ x86opnd_t const_ptr_opnd(const void *ptr);
242256

243257
// Machine code allocation
244258
uint8_t* alloc_exec_mem(uint32_t mem_size);
245-
uint8_t* alloc_code_page();
246-
void free_code_page(uint8_t* page_ptr);
259+
code_page_t* alloc_code_page(void);
260+
void free_code_page(code_page_t* code_page);
247261

248262
// Code block methods
249263
void cb_init(codeblock_t* cb, uint8_t* mem_block, uint32_t mem_size);

yjit_core.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,12 @@ typedef struct yjit_block_version
242242
VALUE receiver_klass;
243243
VALUE callee_cme;
244244

245+
// Code page this block lives on
246+
VALUE code_page;
247+
245248
// Index one past the last instruction in the iseq
246249
uint32_t end_idx;
250+
247251
} block_t;
248252

249253
// Context object methods

yjit_iface.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,9 @@ rb_yjit_iseq_mark(const struct rb_iseq_constant_body *body)
855855
memcpy(&object, value_address, SIZEOF_VALUE);
856856
rb_gc_mark_movable(object);
857857
}
858+
859+
// Mark the machine code page this block lives on
860+
rb_gc_mark_movable(block->code_page);
858861
}
859862
}
860863
}
@@ -895,6 +898,9 @@ rb_yjit_iseq_update_references(const struct rb_iseq_constant_body *body)
895898
memcpy(value_address, &possibly_moved, SIZEOF_VALUE);
896899
}
897900
}
901+
902+
// Update the machine code page this block lives on
903+
block->code_page = rb_gc_location(block->code_page);
898904
}
899905
}
900906
}
@@ -917,6 +923,35 @@ rb_yjit_iseq_free(const struct rb_iseq_constant_body *body)
917923
rb_darray_free(body->yjit_blocks);
918924
}
919925

926+
static void
927+
yjit_code_page_free(void *code_page)
928+
{
929+
free_code_page((code_page_t*)code_page);
930+
}
931+
932+
// Custom type for interacting with the GC
933+
static const rb_data_type_t yjit_code_page_type = {
934+
"yjit_code_page",
935+
{NULL, yjit_code_page_free, NULL, NULL},
936+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
937+
};
938+
939+
// Allocate a code page and wrap it into a Ruby object owned by the GC
940+
VALUE rb_yjit_code_page_alloc(void)
941+
{
942+
code_page_t* code_page = alloc_code_page();
943+
VALUE cp_obj = TypedData_Wrap_Struct(0, &yjit_code_page_type, code_page);
944+
return cp_obj;
945+
}
946+
947+
// Unwrap the Ruby object representing a code page
948+
code_page_t *rb_yjit_code_page_unwrap(VALUE cp_obj)
949+
{
950+
code_page_t * code_page;
951+
TypedData_Get_Struct(cp_obj, code_page_t, &yjit_code_page_type, code_page);
952+
return code_page;
953+
}
954+
920955
bool
921956
rb_yjit_enabled_p(void)
922957
{

0 commit comments

Comments
 (0)