@@ -82,6 +82,9 @@ pub struct CodeBlock {
8282 // for example, when there is not enough space or when a jump
8383 // target is too far away.
8484 dropped_bytes : bool ,
85+
86+ // The number of bytes that have been freed by code GC
87+ pub freed_bytes : usize ,
8588}
8689
8790/// Set of CodeBlock label states. Used for recovering the previous state.
@@ -108,6 +111,7 @@ impl CodeBlock {
108111 asm_comments : BTreeMap :: new ( ) ,
109112 outlined,
110113 dropped_bytes : false ,
114+ freed_bytes : 0 ,
111115 } ;
112116 cb. write_pos = cb. page_start ( ) ;
113117 cb
@@ -124,6 +128,7 @@ impl CodeBlock {
124128 let next_page_idx = self . write_pos / self . page_size + 1 ;
125129 if !self . set_page ( next_page_idx, & jmp_ptr) {
126130 self . set_write_ptr ( old_write_ptr) ; // rollback if there are no more pages
131+ self . code_gc ( ) ; // TODO: return true if there's a freed page once we implement freed page reuse
127132 return false ;
128133 }
129134
@@ -293,6 +298,11 @@ impl CodeBlock {
293298 self . mem_block . borrow ( ) . start_ptr ( ) . add_bytes ( offset)
294299 }
295300
301+ pub fn addrs_to_pages ( & self , start_addr : CodePtr , end_addr : CodePtr ) -> Vec < usize > {
302+ // TODO: move page management to codeblock
303+ self . mem_block . borrow ( ) . addrs_to_pages ( start_addr, end_addr)
304+ }
305+
296306 /// Get a (possibly dangling) direct pointer to the current write position
297307 pub fn get_write_ptr ( & self ) -> CodePtr {
298308 self . get_ptr ( self . write_pos )
@@ -431,6 +441,44 @@ impl CodeBlock {
431441 self . mem_block . borrow_mut ( ) . mark_all_executable ( ) ;
432442 }
433443
444+ /// Free unused code pages
445+ fn code_gc ( & mut self ) {
446+ //println!("code_gc");
447+ let iseq_payloads = CodegenGlobals :: get_iseq_payloads ( ) ;
448+
449+ // Check which pages are still in use
450+ let num_pages = self . mem_block . borrow ( ) . num_pages ( ) ;
451+ let mut alive_pages = vec ! [ false ; num_pages] ; // TODO: consider using a bitmap
452+ for iseq_payload in iseq_payloads. iter ( ) {
453+ let iseq_payload = unsafe { iseq_payload. as_ref ( ) } . unwrap ( ) ;
454+ for page in & iseq_payload. pages {
455+ alive_pages[ * page] = true ;
456+ }
457+ }
458+
459+ // Ask VirtualMem to free unused pages
460+ for ( page, alive) in alive_pages. iter ( ) . enumerate ( ) {
461+ if !alive {
462+ // TODO: reduce the number of syscalls by merging them for consecutive pages
463+ let freed_bytes = self . mem_block . borrow_mut ( ) . free_page ( page) ;
464+ //println!("free_page: {}", page);
465+ self . freed_bytes += freed_bytes;
466+ }
467+ }
468+
469+ let mut cb = CodegenGlobals :: get_inline_cb ( ) ;
470+ cb. dropped_bytes = true ;
471+ let mut ocb = CodegenGlobals :: get_outlined_cb ( ) . unwrap ( ) ;
472+ cb. dropped_bytes = true ;
473+
474+ // TODO: Implement start-over; allow reusing freed pages
475+ // 1. scan cfp stack of all Fibers and list up which JIT payloads are still in use
476+ // 2. invalidate existing in-use code
477+ // 3. list up pages used by invalidation code
478+ // 4. make vector of freed pages + free existing pages
479+ // 5. move write_pos back to first freed page
480+ }
481+
434482 pub fn inline ( & self ) -> bool {
435483 !self . outlined
436484 }
0 commit comments