44// benefit.
55
66use std:: ptr:: NonNull ;
7-
7+ use crate :: cruby :: * ;
88use crate :: stats:: zjit_alloc_size;
99
10- #[ cfg( test) ]
11- use crate :: options:: get_option;
12-
13- #[ cfg( not( test) ) ]
1410pub type VirtualMem = VirtualMemory < sys:: SystemAllocator > ;
1511
16- #[ cfg( test) ]
17- pub type VirtualMem = VirtualMemory < tests:: TestingAllocator > ;
18-
1912/// Memory for generated executable machine code. When not testing, we reserve address space for
2013/// the entire region upfront and map physical memory into the reserved address space as needed. On
2114/// Linux, this is basically done using an `mmap` with `PROT_NONE` upfront and gradually using
@@ -33,7 +26,7 @@ pub struct VirtualMemory<A: Allocator> {
3326 region_size_bytes : usize ,
3427
3528 /// mapped_region_bytes + zjit_alloc_size may not increase beyond this limit.
36- memory_limit_bytes : usize ,
29+ memory_limit_bytes : Option < usize > ,
3730
3831 /// Number of bytes per "page", memory protection permission can only be controlled at this
3932 /// granularity.
@@ -113,14 +106,36 @@ pub enum WriteError {
113106
114107use WriteError :: * ;
115108
109+ impl VirtualMem {
110+ /// Allocate a VirtualMem insntace with a requested size
111+ pub fn alloc ( exec_mem_bytes : usize , mem_bytes : Option < usize > ) -> Self {
112+ let virt_block: * mut u8 = unsafe { rb_jit_reserve_addr_space ( exec_mem_bytes as u32 ) } ;
113+
114+ // Memory protection syscalls need page-aligned addresses, so check it here. Assuming
115+ // `virt_block` is page-aligned, `second_half` should be page-aligned as long as the
116+ // page size in bytes is a power of two 2¹⁹ or smaller. This is because the user
117+ // requested size is half of mem_option × 2²⁰ as it's in MiB.
118+ //
119+ // Basically, we don't support x86-64 2MiB and 1GiB pages. ARMv8 can do up to 64KiB
120+ // (2¹⁶ bytes) pages, which should be fine. 4KiB pages seem to be the most popular though.
121+ let page_size = unsafe { rb_jit_get_page_size ( ) } ;
122+ assert_eq ! (
123+ virt_block as usize % page_size as usize , 0 ,
124+ "Start of virtual address block should be page-aligned" ,
125+ ) ;
126+
127+ Self :: new ( sys:: SystemAllocator { } , page_size, NonNull :: new ( virt_block) . unwrap ( ) , exec_mem_bytes, mem_bytes)
128+ }
129+ }
130+
116131impl < A : Allocator > VirtualMemory < A > {
117132 /// Bring a part of the address space under management.
118133 pub fn new (
119134 allocator : A ,
120135 page_size : u32 ,
121136 virt_region_start : NonNull < u8 > ,
122137 region_size_bytes : usize ,
123- memory_limit_bytes : usize ,
138+ memory_limit_bytes : Option < usize > ,
124139 ) -> Self {
125140 assert_ne ! ( 0 , page_size) ;
126141 let page_size_bytes = page_size as usize ;
@@ -181,6 +196,12 @@ impl<A: Allocator> VirtualMemory<A> {
181196 let whole_region_end = start. wrapping_add ( self . region_size_bytes ) ;
182197 let alloc = & mut self . allocator ;
183198
199+ // Ignore zjit_alloc_size() if self.memory_limit_bytes is None for testing
200+ let mut required_region_bytes = page_addr + page_size - start as usize ;
201+ if self . memory_limit_bytes . is_some ( ) {
202+ required_region_bytes += zjit_alloc_size ( ) ;
203+ }
204+
184205 assert ! ( ( start..=whole_region_end) . contains( & mapped_region_end) ) ;
185206
186207 if ( start..mapped_region_end) . contains ( & raw ) {
@@ -193,7 +214,7 @@ impl<A: Allocator> VirtualMemory<A> {
193214
194215 self . current_write_page = Some ( page_addr) ;
195216 } else if ( start..whole_region_end) . contains ( & raw ) &&
196- ( page_addr + page_size - start as usize ) + zjit_alloc_size ( ) < self . memory_limit_bytes {
217+ required_region_bytes < self . memory_limit_bytes . unwrap_or ( self . region_size_bytes ) {
197218 // Writing to a brand new page
198219 let mapped_region_end_addr = mapped_region_end as usize ;
199220 let alloc_size = page_addr - mapped_region_end_addr + page_size;
@@ -279,7 +300,6 @@ impl<A: Allocator> CodePtrBase for VirtualMemory<A> {
279300}
280301
281302/// Requires linking with CRuby to work
282- #[ cfg( not( test) ) ]
283303pub mod sys {
284304 use crate :: cruby:: * ;
285305
@@ -387,7 +407,7 @@ pub mod tests {
387407 PAGE_SIZE . try_into ( ) . unwrap ( ) ,
388408 NonNull :: new ( mem_start as * mut u8 ) . unwrap ( ) ,
389409 mem_size,
390- get_option ! ( mem_bytes ) ,
410+ None ,
391411 )
392412 }
393413
0 commit comments