diff --git a/runtime/Cargo.lock b/runtime/Cargo.lock index 9ebfa90..bf845f6 100644 --- a/runtime/Cargo.lock +++ b/runtime/Cargo.lock @@ -8,30 +8,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - [[package]] name = "cfg-if" version = "1.0.1" @@ -39,32 +21,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] -name = "combine" -version = "4.6.7" +name = "crossbeam-utils" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] -name = "enum-as-inner" -version = "0.6.1" +name = "dashmap" +version = "7.0.0-rc2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +checksum = "e4a1e35a65fe0538a60167f0ada6e195ad5d477f6ddae273943596d4a1a5730b" dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", + "cfg-if", + "crossbeam-utils", + "equivalent", + "hashbrown", + "lock_api", + "parking_lot_core", ] [[package]] -name = "heck" -version = "0.5.0" +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "hashbrown" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "libc" @@ -79,218 +65,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7222002e5385b4d9327755661e3847c970e8fbf9dea6da8c57f16e8cfbff53a8" [[package]] -name = "mach2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" -dependencies = [ - "libc 0.2.174", -] - -[[package]] -name = "memchr" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "memmap2" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28" -dependencies = [ - "libc 0.2.174", -] - -[[package]] -name = "memoffset" -version = "0.7.1" +name = "lock_api" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", + "scopeguard", ] [[package]] -name = "mmap-rs" -version = "0.6.1" +name = "parking_lot_core" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86968d85441db75203c34deefd0c88032f275aaa85cee19a1dcfff6ae9df56da" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ - "bitflags 1.3.2", - "combine", - "libc 0.2.174", - "mach2", - "nix", - "sysctl", - "thiserror", - "widestring", - "windows", -] - -[[package]] -name = "nix" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" -dependencies = [ - "bitflags 1.3.2", "cfg-if", "libc 0.2.174", - "memoffset", - "pin-utils", -] - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", + "redox_syscall", + "smallvec", + "windows-targets", ] [[package]] -name = "quote" -version = "1.0.40" +name = "redox_syscall" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "proc-macro2", + "bitflags", ] [[package]] name = "runtime" version = "0.1.0" dependencies = [ + "dashmap", "libc 1.0.0-alpha.1", - "memmap2", - "mmap-rs", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "syn" -version = "2.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sysctl" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" -dependencies = [ - "bitflags 2.9.1", - "byteorder", - "enum-as-inner", - "libc 0.2.174", - "thiserror", - "walkdir", ] [[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "widestring" +name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "windows-sys" -version = "0.59.0" +name = "smallvec" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "windows-targets" @@ -298,46 +122,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -350,48 +156,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 0a80828..9fb5eae 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -5,5 +5,4 @@ edition = "2024" [dependencies] libc = "1.0.0-alpha.1" -mmap-rs = "0.6.1" -memmap2 = "0.9.7" +dashmap = "7.0.0-rc2" diff --git a/runtime/src/alloca/allocator.rs b/runtime/src/alloca/allocator.rs index 48acfd3..9088260 100644 --- a/runtime/src/alloca/allocator.rs +++ b/runtime/src/alloca/allocator.rs @@ -1,24 +1,21 @@ -use crate::alloca::{ptr, Object}; use crate::alloca::arena::Arena3; +use crate::alloca::{Cfg, ptr}; +use crate::utils::Object; -pub trait ArenaAllocator3 { - const LOG_CAPACITY_SIZE: usize; - - const LOG_BLOCK_SIZE: usize; - - const LOG_START_ARENA_SIZE: usize; - - const LOG_MAX_ARENA_SIZE: usize; - - fn new(max_size: usize) -> Self; - - fn alloc(&mut self, o: &T) -> ptr; - - fn mark_white(&mut self); - - fn arena_by_ptr(&mut self, ptr: usize) -> &mut U; - - fn mark_gray(&mut self, ptr: ptr); - - fn mark_black(&mut self, ptr: ptr); -} \ No newline at end of file +pub trait ArenaAllocator3 { + fn new(config: &Cfg) -> Self; + + fn alloc(&mut self, o: &Object) -> (ptr, bool); + + fn mark_white(&mut self); + + fn arena_by_ptr(&self, ptr: usize) -> Option<&U>; + + fn mut_arena_by_ptr(&mut self, ptr: usize) -> Option<&mut U>; + + fn mark_gray(&mut self, ptr: ptr) -> Option<&mut U>; + + fn mark_black(&mut self, ptr: ptr) -> Option<&mut U>; + + fn sweep(&mut self); +} diff --git a/runtime/src/alloca/arena.rs b/runtime/src/alloca/arena.rs index 9e25d22..1e3b79a 100644 --- a/runtime/src/alloca/arena.rs +++ b/runtime/src/alloca/arena.rs @@ -1,31 +1,39 @@ use crate::alloca::ptr; pub trait Arena3 { - fn new(start: ptr, size: usize) -> Self; - - fn start(&self) -> ptr; - - fn cur(&self) -> ptr; - - fn add(&mut self, size: usize); - - fn size(&self) -> usize; - - fn how_much(&self) -> usize; - - fn gray_map(&self) ->(ptr, usize); - - fn black_map(&self) ->(ptr, usize); - - fn clear_mark(&mut self); - - fn live(&self) -> bool; - - fn on(&mut self); - - fn off(&mut self); - - fn mark_gray(&mut self, ptr: ptr); - - fn mark_black(&mut self, ptr: ptr); -} \ No newline at end of file + fn new(start: ptr, size: usize) -> Self; + + fn span_start(&self) -> ptr; + + fn cur(&self) -> ptr; + + fn add(&mut self, size: usize); + + fn size(&self) -> usize; + + fn how_much(&self) -> usize; + + fn gray_map(&self) -> (ptr, usize); + + fn black_map(&self) -> (ptr, usize); + + fn clear_mark(&mut self); + + fn live(&self) -> bool; + + fn alive(&mut self); + + fn kill(&mut self); + + fn make_live(&mut self); + + fn temp_kill(&mut self); + + fn mark_gray(&mut self, ptr: ptr); + + fn mark_black(&mut self, ptr: ptr); + + fn fetch_and_add_in_queue(&mut self) -> bool; + + fn fetch_and_take_from_queue(&mut self) -> bool; +} diff --git a/runtime/src/alloca/cfg.rs b/runtime/src/alloca/cfg.rs new file mode 100644 index 0000000..b906638 --- /dev/null +++ b/runtime/src/alloca/cfg.rs @@ -0,0 +1,43 @@ +pub struct Cfg { + pub log_capacity_size: usize, + pub log_block_size: usize, + pub log_start_arena_size: usize, + pub step_arena_size: usize, + pub log_max_arena_size: usize, + pub count_of_tiers: usize, + pub max_size: usize, + pub max_object_size_by_size: fn(usize) -> usize, + + pub count_gc_workers: usize, +} + +impl Cfg { + pub fn new( + log_capacity_size: usize, + log_block_size: usize, + log_start_arena_size: usize, + log_max_arena_size: usize, + step_arena_size: usize, + max_size: usize, + max_object_size_by_size: fn(usize) -> usize, + count_gc_workers: usize, + ) -> Self { + assert!(log_capacity_size > log_block_size); + assert!(log_block_size > log_max_arena_size); + assert!(log_max_arena_size > log_start_arena_size); + assert!(step_arena_size < log_max_arena_size - log_start_arena_size); + assert!(count_gc_workers > 0); + + Self { + log_capacity_size, + log_block_size, + log_start_arena_size, + step_arena_size, + log_max_arena_size, + count_of_tiers: ((log_max_arena_size - log_start_arena_size) / step_arena_size) + 1, + max_size, + max_object_size_by_size, + count_gc_workers, + } + } +} diff --git a/runtime/src/alloca/hallocator.rs b/runtime/src/alloca/hallocator.rs index f7f6d28..caab101 100644 --- a/runtime/src/alloca/hallocator.rs +++ b/runtime/src/alloca/hallocator.rs @@ -1,220 +1,349 @@ -use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering}; -use crate::alloca::{ptr, Object}; use crate::alloca::allocator::ArenaAllocator3; use crate::alloca::arena::Arena3; -use crate::alloca::heapedarena::{Heap, HeapedArena}; - -pub(crate) struct HAllocator { - start: ptr, - max_size: usize, - used_memory: AtomicUsize, - - heap: Heap, - - blocks: Box<[Option>]>, - count_of_blocks: AtomicUsize, - large_objects: Vec>, - - _marker: std::marker::PhantomData, +use crate::alloca::cfg::Cfg; +use crate::alloca::ptr; +use crate::utils::Object; +use libc::malloc; +use std::collections::LinkedList; +use std::sync::atomic::{AtomicUsize, Ordering}; + +pub struct HAllocator { + start: ptr, + used_memory: AtomicUsize, + + blocks: Vec>, + num_of_blocks_by_tier: Vec>, + + large_objects: LinkedList, + + log_capacity_size: usize, + log_block_size: usize, + log_start_arena_size: usize, + step_arena_size: usize, + log_max_arena_size: usize, + count_of_tiers: usize, + max_size: usize, + max_object_size_by_tier: Box usize + Send + Sync>, } -impl HAllocator { - fn block_by_ptr(&mut self, ptr: ptr) -> &mut HedgeBlock { - assert!(self.start <= ptr); - assert!(ptr < self.start + (1 << Self::LOG_CAPACITY_SIZE)); - self.blocks[ptr >> Self::LOG_BLOCK_SIZE] - .as_mut() - .expect(&format!("block_by_ptr: \ - index: {}\n", ptr >> Self::LOG_BLOCK_SIZE)) - } - - fn add_new_needed_block(&mut self, size: usize) -> &mut HedgeBlock { - for power in (Self::LOG_START_ARENA_SIZE..=Self::LOG_MAX_ARENA_SIZE).step_by(2) { - if 1 << power > size { - let index = self.count_of_blocks.fetch_add(1, Ordering::Relaxed); - self.blocks[index] = Some(HedgeBlock::new - (self.start + (index << Self::LOG_BLOCK_SIZE), - 1 << Self::LOG_BLOCK_SIZE, power, index)); - - return self.blocks[index] - .as_mut() - .expect(&format!("arena_by_heaped:\n\ - num_of_block: {}\n", index)); - } - } - unreachable!(); - } - - fn arena_by_heaped(&mut self, arena_from_heap: HeapedArena) -> &mut U { - &mut self.blocks[arena_from_heap.num_of_block] - .as_mut() - .expect(&format!("arena_by_heaped:\n\ - num_of_block: {}\n", arena_from_heap.num_of_block)) - .items[arena_from_heap.num_of_arena] - } +impl HAllocator { + fn block_by_ptr(&self, ptr: ptr) -> Option<&HedgeBlock> { + if ptr < self.start || ptr >= self.start + (1 << self.log_capacity_size) { + None + } else { + Some(&self.blocks[(ptr - self.start) >> self.log_block_size]) + } + } + + fn mut_block_by_ptr(&mut self, ptr: ptr) -> Option<&mut HedgeBlock> { + if ptr < self.start || ptr >= self.start + (1 << self.log_capacity_size) { + None + } else { + Some(&mut self.blocks[(ptr - self.start) >> self.log_block_size]) + } + } + + fn add_new_needed_block(&mut self, size: usize) -> &mut U { + for tier in 0..self.count_of_tiers { + if (self.max_object_size_by_tier)(tier) >= size { + let index = self.blocks.len(); + let new_block = HedgeBlock::new( + self.start + (index << self.log_block_size), + 1 << self.log_block_size, + self.log_start_arena_size + tier * self.step_arena_size, + index, // number_of_block + tier, // tier + (self.max_object_size_by_tier)(tier), + ); + + self.blocks.push(new_block); + + let mut new_block = self.blocks.last_mut().unwrap(); + let index_of_new_arena = new_block.archive.pop().unwrap(); + let ref_arena: &mut U = new_block + .items + .get_mut(index_of_new_arena.num_of_arena) + .expect("index out of bounds in add_new_needed_block"); + ref_arena.alive(); + new_block.current = Some(index_of_new_arena); + + self.num_of_blocks_by_tier[tier].push(index); + return ref_arena; + } + } + unreachable!(); + } + + fn arena_tier_by_size(&self, size: usize) -> Option { + for tier in 0..self.count_of_tiers { + if (self.max_object_size_by_tier)(tier) >= size { + return Some(tier); + } + } + None + } + + fn find(&mut self, size: usize) -> (Option<&mut U>, bool) { + let tier = match self.arena_tier_by_size(size) { + Some(tier) => tier, + None => return (None, true), + }; + let mut found = None; + + for &num_of_block in &self.num_of_blocks_by_tier[tier] { + let block = &self.blocks[num_of_block]; + if let Some(current) = block.current { + found = Some((num_of_block, current.num_of_arena)); + break; + } + } + + if let Some((block_idx, arena_idx)) = found { + let block = &mut self.blocks[block_idx]; + return (Some(&mut block.items[arena_idx]), true); + } + + (None, true) + } + + fn for_each_arena(&mut self, mut f: F) + where + F: FnMut(&mut U), + { + let current_count = self.blocks.len(); + + for i in 0..current_count { + let mut block = &mut self.blocks[i]; + for index_arena in block.active.iter() { + let arena = &mut block.items[index_arena.num_of_arena]; + f(arena); + } + } + } } +impl ArenaAllocator3 for HAllocator { + fn new(config: &Cfg) -> Self { + unsafe { + let start = libc::mmap( + std::ptr::null_mut(), + 1 << config.log_capacity_size, + libc::PROT_NONE, + libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, + -1, + 0, + ) as ptr; + + if start == 0 { + panic!("reserve mmap failed"); + } + + let mosns = config.max_object_size_by_size; + let lsas = config.log_start_arena_size; + let sas = config.step_arena_size; + Self { + start, + max_size: config.max_size, + used_memory: AtomicUsize::new(0), + blocks: Vec::new(), + num_of_blocks_by_tier: vec![Vec::new(); config.count_of_tiers], + large_objects: LinkedList::new(), + + log_capacity_size: config.log_capacity_size, + log_block_size: config.log_block_size, + log_start_arena_size: config.log_start_arena_size, + step_arena_size: config.step_arena_size, + log_max_arena_size: config.log_max_arena_size, + count_of_tiers: config.count_of_tiers, + max_object_size_by_tier: Box::new(move |tier| mosns(1 << (lsas + sas * tier))), + } + } + } + + fn alloc(&mut self, o: &Object) -> (ptr, bool) { + let real_size = o.size + 8; + + let mut ptr = 0; // result + + let (maybe_ref_arena, big_object_flag) = self.find(real_size); + if big_object_flag { + ptr = unsafe { malloc(real_size) } as usize; + } else { + let ref_arena = match maybe_ref_arena { + Some(a) => a, + None => self.add_new_needed_block(real_size), + }; + ptr = ref_arena.cur(); + + ref_arena.add(real_size); + let empty_space = ref_arena.how_much(); + + let block_of_arena = self.mut_block_by_ptr(ptr).expect("something went wrong"); -impl ArenaAllocator3 for HAllocator { - const LOG_CAPACITY_SIZE: usize = 37; - const LOG_BLOCK_SIZE: usize = 26; - const LOG_START_ARENA_SIZE: usize = 12; - const LOG_MAX_ARENA_SIZE: usize = 16; - - fn new(max_size: usize) -> Self { - assert!(Self::LOG_CAPACITY_SIZE > Self::LOG_BLOCK_SIZE); - assert!(Self::LOG_BLOCK_SIZE > Self::LOG_MAX_ARENA_SIZE); - assert!(Self::LOG_MAX_ARENA_SIZE > Self::LOG_START_ARENA_SIZE); - - unsafe { - let start = libc::mmap( - std::ptr::null_mut(), - 1 << Self::LOG_CAPACITY_SIZE, - libc::PROT_NONE, - libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, - -1, - 0 - ) as ptr; - - - if start == 0 { - panic!("reserve mmap failed"); - } - - Self { - start, - max_size, - used_memory: AtomicUsize::new(0), - heap: Heap::new(), - blocks: Box::new([const {None}; 1 << (>::LOG_CAPACITY_SIZE - >::LOG_BLOCK_SIZE)]), - count_of_blocks: AtomicUsize::new(0), - large_objects: vec![], - _marker: Default::default(), - } - } - - } - - - fn alloc(&mut self, o: &T) -> ptr { - let mut maybe_heaped_arena = self.heap.get_min_more_then(o.size()); - if maybe_heaped_arena.is_none() { - - } - let heaped_arena = maybe_heaped_arena.unwrap_or_else(|| { - let heaped_version_of_first_arena = self - .add_new_needed_block(o.size()) - .slots - .pop() - .expect("In new needed_block len(slots)==0\n"); - - self.arena_by_heaped(heaped_version_of_first_arena).on(); - heaped_version_of_first_arena - }); - let ref_arena = self.arena_by_heaped(heaped_arena); - ref_arena.add(o.size()); - let ptr = ref_arena.cur(); - - if ptr == ref_arena.start() { - let mut block = self.block_by_ptr(ptr); - match block.slots.pop() { - Some(heaped_arena_from_slots) => { - self.arena_by_heaped(heaped_arena_from_slots).on(); - self.heap.insert(heaped_arena_from_slots); - } - None => { - let new_heaped_arena = self - .add_new_needed_block(o.size()) - .slots - .pop() - .expect("In new needed_block (when a last arena of the block is not empty) len(slots)==0\n"); - self.arena_by_heaped(new_heaped_arena).on(); - self.heap.insert(new_heaped_arena); - } - } - } - - self.used_memory.fetch_add(o.size(), Ordering::Relaxed); - self.heap.insert(heaped_arena); - ptr - } - - fn mark_white(&mut self) { - let locked = self.heap.items.lock().expect("lock in white"); - let copy = locked.clone(); - drop(locked); - for heaped_arena_from_slots in copy.iter() { - if let arena = self.arena_by_heaped(heaped_arena_from_slots.clone()) && arena.live() { - arena.clear_mark(); - } - }; - } - - fn arena_by_ptr(&mut self, ptr: usize) -> &mut U { - self.block_by_ptr(ptr) - .arena_by_ptr(ptr) - } - - - fn mark_gray(&mut self, ptr: ptr) { - self.arena_by_ptr(ptr) - .mark_gray(ptr); - } - - fn mark_black(&mut self, ptr: ptr) { - self.arena_by_ptr(ptr) - .mark_black(ptr); - } + if empty_space < block_of_arena.max_object_size { + block_of_arena.active.push(block_of_arena.current.unwrap()); + block_of_arena.current = block_of_arena.archive.pop(); + if block_of_arena.current.is_some() { + block_of_arena.items[block_of_arena.current.unwrap().num_of_arena].alive(); + } + } + } + + unsafe { + *(ptr as *mut *const Object) = o as *const Object; + } + + // this is shit, but pohuy + let used = self.used_memory.fetch_add(real_size, Ordering::Relaxed); + + if used > self.max_size { + (ptr + 8, true) + } else { + (ptr + 8, false) + } + } + + fn mark_white(&mut self) { + self.for_each_arena(|arena| { + arena.temp_kill(); + }); + + for large in self.large_objects.iter_mut() { + *large >>= 2; + *large <<= 2; + } + } + + fn arena_by_ptr(&self, ptr: usize) -> Option<&U> { + Some(self.block_by_ptr(ptr)?.arena_by_ptr(ptr)) + } + + fn mut_arena_by_ptr(&mut self, ptr: usize) -> Option<&mut U> { + Some(self.mut_block_by_ptr(ptr)?.mut_arena_by_ptr(ptr)) + } + + fn mark_gray(&mut self, ptr: ptr) -> Option<&mut U> { + match self.arena_by_ptr(ptr) { + Some(_) => { + let arena = self.mut_arena_by_ptr(ptr).unwrap(); + arena.mark_gray(ptr); + Some(arena) + } + None => { + *self + .large_objects + .iter_mut() + .find(|p| (**p >> 2) == (ptr >> 2)) + .expect("mark_gray") |= 1; + None + } + } + } + + fn mark_black(&mut self, ptr: ptr) -> Option<&mut U> { + match self.arena_by_ptr(ptr) { + Some(_) => { + let arena = self.mut_arena_by_ptr(ptr).unwrap(); + arena.mark_gray(ptr); + Some(arena) + } + None => { + *self + .large_objects + .iter_mut() + .find(|p| (**p >> 2) == (ptr >> 2)) + .expect("mark_black") |= 2; + None + } + } + } + + fn sweep(&mut self) { + self.for_each_arena(|arena| { + if !arena.live() { + arena.kill(); + }; + }); + } +} + +#[derive(Debug, Clone, Copy)] +pub struct IndexArena { + pub num_of_block: usize, + pub num_of_arena: usize, } #[derive(Debug)] struct HedgeBlock { - start: ptr, - - size: usize, - - log_arena_size: usize, - - // only for find object by ref. - // const - items: Box<[U]>, - - // dynamic - slots: Vec, + start: ptr, + + size: usize, + + tier: usize, // the tier define log_arena_size and max_object_size + + log_arena_size: usize, + max_object_size: usize, + + // only for find Object by ref. + // const + items: Box<[U]>, + + // dynamic + archive: Vec, + current: Option, + active: Vec, } impl HedgeBlock { - fn new(start: ptr, size: usize, log_arena_size: usize, number_of_block: usize) -> Self { - let count = size >> log_arena_size; - - let mut arenas = Vec::with_capacity(count); - let mut slots = Vec::with_capacity(count); - for i in 0..count { - arenas.push(U::new(start + (i << log_arena_size), 1 << log_arena_size)); - slots.push(HeapedArena { - num_of_block: number_of_block, - num_of_arena: i, - param: 1 << log_arena_size, - }) - } - - let box_arenas = arenas.into_boxed_slice(); - - - Self { - start, - size, - log_arena_size, - items: box_arenas, - slots, - } - } - - fn arena_by_ptr(&mut self, ptr: ptr) -> &mut U { - assert!(self.log_arena_size > 0); - assert!(self.start <= ptr); - assert!(ptr < self.start + self.size); - &mut self.items[(ptr - self.start) >> self.log_arena_size] - } + fn new( + start: ptr, + size: usize, + log_arena_size: usize, + number_of_block: usize, + tier: usize, + max_object_size: usize, + ) -> Self { + let count = size >> log_arena_size; + + let mut arenas = Vec::with_capacity(count); + let mut archive = Vec::with_capacity(count); + for i in 0..count { + arenas.push(U::new( + start + ((count - i - 1) << log_arena_size), + 1 << log_arena_size, + )); + archive.push(IndexArena { + num_of_block: number_of_block, + num_of_arena: count - i - 1, // literally for good debug + }) + } + + let box_arenas = arenas.into_boxed_slice(); + + Self { + start, + size, + tier, + log_arena_size, + max_object_size, + items: box_arenas, + archive, + current: None, + active: Vec::new(), + } + } + + fn mut_arena_by_ptr(&mut self, ptr: ptr) -> &mut U { + assert!(self.log_arena_size > 0); + assert!(self.start <= ptr); + assert!(ptr < self.start + self.size); + &mut self.items[(ptr - self.start) >> self.log_arena_size] + } + + fn arena_by_ptr(&self, ptr: ptr) -> &U { + assert!(self.log_arena_size > 0); + assert!(self.start <= ptr); + assert!(ptr < self.start + self.size); + &self.items[(ptr - self.start) >> self.log_arena_size] + } } diff --git a/runtime/src/alloca/heapedarena.rs b/runtime/src/alloca/heapedarena.rs deleted file mode 100644 index cc98541..0000000 --- a/runtime/src/alloca/heapedarena.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::sync::Mutex; -use crate::alloca::arena::Arena3; - -#[derive(Debug, Clone, Copy)] -pub(crate) struct HeapedArena { - pub(crate) num_of_block: usize, - pub(crate) num_of_arena: usize, - pub(crate) param: usize -} - -impl Eq for HeapedArena {} - -impl PartialEq for HeapedArena { - fn eq(&self, other: &Self) -> bool { - false - } -} - -impl PartialOrd for HeapedArena { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for HeapedArena { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.param.cmp(&other.param) - } -} - - -pub(crate) struct Heap { - pub(crate) items: Mutex> -} - -impl Heap { - pub(crate) fn new() -> Self { - Self { - items: Mutex::new(std::collections::BTreeSet::new()) - } - } - - pub(crate) fn insert(&mut self, item: HeapedArena) { - self.items.lock().unwrap().insert(item); - } - - - pub(crate) fn get_min_more_then(&mut self, n: usize) -> Option { - assert!(n > 0); - - let etalon = HeapedArena { - num_of_block: 0, - num_of_arena: 0, - param: n - 1, - }; - - let mut guarded = self.items.lock().expect("lock poisoned"); - - let key = guarded.range(etalon..).next().map(|k| k.clone())?; - - Some(guarded.take(&key).expect("error take\n")) - } -} diff --git a/runtime/src/alloca/hedgearena.rs b/runtime/src/alloca/hedgearena.rs index 024da5f..3b3a9a9 100644 --- a/runtime/src/alloca/hedgearena.rs +++ b/runtime/src/alloca/hedgearena.rs @@ -1,132 +1,160 @@ +use crate::alloca::arena::Arena3; +use crate::alloca::ptr; use std::ffi::c_void; use std::sync::atomic::{AtomicBool, Ordering}; -use crate::alloca::ptr; -use crate::alloca::arena::Arena3; #[derive(Debug)] -pub(crate) struct HedgeArena { - start: ptr, - cur: ptr, - size: usize, // = 32x - - span_start: ptr, - - // gray: Box<[u8]>, - // black: Box<[u8]>, - - live: AtomicBool, // хз пока нужен ли, мб оставлю только map, юуду смотреть на None - - /// dbg only - objects: Vec, +pub struct HedgeArena { + start: ptr, + cur: ptr, + size: usize, // = 32x + + span_start: ptr, + + // gray: Box<[u8]>, + // black: Box<[u8]>, + live: AtomicBool, // хз пока нужен ли, мб оставлю только map, юуду смотреть на None + + /// dbg only + objects: Vec, + + in_queue: AtomicBool, } impl Arena3 for HedgeArena { - fn new(start: ptr, size: usize) -> Self { - Self { - start, - cur: start, - size, - span_start: start + (size >> 5), - live: Default::default(), - objects: vec![] - } - } - - fn start(&self) -> ptr { - self.start - } - - fn cur(&self) -> ptr { - self.cur - } - - fn add(&mut self, size: usize) { - self.cur += size - } - - fn size(&self) -> usize { - self.size - } - - fn how_much(&self) -> usize { - self.start + self.size - self.cur - } - - fn gray_map(&self) -> (ptr, usize) { - (self.start, self.size >> 6) - } - - fn black_map(&self) -> (ptr, usize) { - (self.start + self.size >> 6, self.size >> 6) - } - - fn clear_mark(&mut self) { - let size_mark = self.span_start - self.start; - assert!(size_mark > 0); - unsafe { - std::ptr::write_bytes(self.start as *mut u8, 0, size_mark as usize); - } - } - - fn live(&self) -> bool { - self.live.load(Ordering::Relaxed) - } - - fn on(&mut self) { - self.live.store(true, Ordering::Relaxed); - - unsafe { - let res = libc::mmap(self.start as *mut c_void, self.size, - libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_FIXED, - -1, 0); - assert_ne!(res, libc::MAP_FAILED); - } - unsafe { *(self.start as *mut u8) = 1 }; - self.clear_mark(); - } - - fn off(&mut self) { - self.live.store(false, Ordering::Relaxed); - } - - fn mark_gray(&mut self, ptr: ptr) { - let offset = ptr - self.span_start; - let index = offset >> 3; - unsafe { - std::ptr::write((self.start + (index >> 3)) as *mut u8, (index % 8) as u8); - } - } - - fn mark_black(&mut self, ptr: ptr) { - let offset = ptr - self.span_start; - let index = offset >> 3; - unsafe { - std::ptr::write(((self.start + self.span_start >> 1) + (index >> 3)) as *mut u8, (index % 8) as u8); - } - } + fn new(start: ptr, size: usize) -> Self { + Self { + start, + cur: start, + size, + span_start: start + (size >> 5), + live: Default::default(), + objects: vec![], + in_queue: Default::default(), + } + } + + fn span_start(&self) -> ptr { + self.span_start + } + + fn cur(&self) -> ptr { + self.cur + } + + fn add(&mut self, size: usize) { + self.cur += size + } + + fn size(&self) -> usize { + self.size + } + + fn how_much(&self) -> usize { + self.start + self.size - self.cur + } + + fn gray_map(&self) -> (ptr, usize) { + (self.start, self.size >> 6) + } + + fn black_map(&self) -> (ptr, usize) { + (self.start + (self.size >> 6), self.size >> 6) + } + + fn clear_mark(&mut self) { + let size_mark = self.span_start - self.start; + assert!(size_mark > 0); + unsafe { + std::ptr::write_bytes(self.start as *mut u8, 0, size_mark as usize); + } + } + + fn live(&self) -> bool { + self.live.load(Ordering::Relaxed) + } + + fn alive(&mut self) { + self.make_live(); + + unsafe { + let res = libc::mmap( + self.start as *mut c_void, + self.size, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_FIXED, + -1, + 0, + ); + assert_ne!(res, libc::MAP_FAILED); + } + self.clear_mark(); + } + + fn kill(&mut self) { + unsafe { + let res = libc::munmap(self.start as *mut c_void, self.size); + assert_eq!(res, 0); + } + } + + fn make_live(&mut self) { + self.live.store(true, Ordering::Relaxed); + } + + fn temp_kill(&mut self) { + self.live.store(false, Ordering::Relaxed); + self.clear_mark(); + } + + fn mark_gray(&mut self, ptr: ptr) { + let offset = ptr - self.span_start; + let index = offset >> 3; + unsafe { + std::ptr::write((self.start + (index >> 3)) as *mut u8, (index % 8) as u8); + } + } + + fn mark_black(&mut self, ptr: ptr) { + let offset = ptr - self.span_start; + let index = offset >> 3; + unsafe { + std::ptr::write( + ((self.start + self.span_start >> 1) + (index >> 3)) as *mut u8, + (index % 8) as u8, + ); + } + } + + fn fetch_and_add_in_queue(&mut self) -> bool { + self.in_queue.fetch_or(true, Ordering::SeqCst) + } + + fn fetch_and_take_from_queue(&mut self) -> bool { + self.in_queue.fetch_and(false, Ordering::SeqCst) + } } impl Eq for HedgeArena {} impl PartialEq for HedgeArena { - fn eq(&self, other: &Self) -> bool { - false - } + fn eq(&self, other: &Self) -> bool { + false + } } impl PartialOrd for HedgeArena { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } } impl Ord for HedgeArena { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - if self.how_much() == other.how_much() { - self.start().cmp(&other.start()) - } else { - self.how_much().cmp(&other.how_much()) - } - } -} \ No newline at end of file + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + if self.how_much() == other.how_much() { + self.span_start().cmp(&other.span_start()) + } else { + self.how_much().cmp(&other.how_much()) + } + } +} diff --git a/runtime/src/alloca/mod.rs b/runtime/src/alloca/mod.rs index 5dd1fc7..e5ba866 100644 --- a/runtime/src/alloca/mod.rs +++ b/runtime/src/alloca/mod.rs @@ -1,71 +1,108 @@ mod allocator; mod arena; +mod cfg; mod hallocator; mod hedgearena; -mod heapedarena; -pub(crate) type ptr = usize; - -pub trait Object { - fn size(&self) -> usize; - fn get_bitset_of_ref(&self) -> &'static [u8]; -} +pub use allocator::ArenaAllocator3; +pub use arena::Arena3; +pub use cfg::Cfg; +pub use hallocator::{HAllocator, IndexArena}; +pub use hedgearena::HedgeArena; +pub(crate) type ptr = usize; #[cfg(test)] mod tests { - use crate::alloca::allocator::ArenaAllocator3; - use crate::alloca::hallocator::HAllocator; - use crate::alloca::hedgearena::HedgeArena; - use super::*; - - struct TestObj { - size: usize, - } - - impl Object for TestObj { - fn size(&self) -> usize { - self.size + use super::*; + use crate::alloca::allocator::ArenaAllocator3; + use crate::alloca::cfg::Cfg; + use crate::alloca::hallocator::HAllocator; + use crate::alloca::hedgearena::HedgeArena; + use crate::utils::Object; + + fn config1() -> &'static Cfg { + Box::leak(Box::new(Cfg::new( + 37, + 26, + 12, + 20, + 2, + 8/*GB*/<< 30, + |size| size / 64, + 3, + ))) + } + + fn test_alloc(object: &Object, aa: &mut HAllocator) { + unsafe { + let (ptr, pred) = aa.alloc(object); + assert_eq!(pred, false); + assert_ne!(ptr, 0); + std::ptr::write_bytes(ptr as *mut u8, 126, object.size / 8); + } + } + + #[test] + fn create_allocator() { + let aa: HAllocator = HAllocator::new(config1()); } - - fn get_bitset_of_ref(&self) -> &'static [u8] { - todo!() + + #[test] + fn first_alloc() { + let mut aa = HAllocator::new(config1()); + + let inst_1 = Object { + size: 24, + bitset: &[0], + }; + test_alloc(&inst_1, &mut aa); } - } - - #[test] - fn create_allocator() { - let aa: HAllocator = HAllocator::new(1<<30); - } - - #[test] - fn first_alloc() { - let mut aa: HAllocator = HAllocator::new(1<<30); - - let inst_1 = TestObj { size: 24 }; - unsafe { - let ptr = aa.alloc(&inst_1); - assert_ne!(ptr, 0); - std::ptr::write_bytes(ptr as *mut u8, 126, inst_1.size / 8); + + #[test] + fn alloc2() { + let mut aa = HAllocator::new(config1()); + + let inst_1 = Object { + size: 1024, + bitset: &[0], + }; + test_alloc(&inst_1, &mut aa); + let inst_2 = Object { + size: 512, + bitset: &[0], + }; + test_alloc(&inst_2, &mut aa); } - - } - - #[test] - fn alloc2() { - let mut aa: HAllocator = HAllocator::new(1<<30); - - let inst_1 = TestObj { size: 1024 }; - let inst_2 = TestObj { size: 512 }; - unsafe { - let ptr = aa.alloc(&inst_1); - assert_ne!(ptr, 0); - std::ptr::write_bytes(ptr as *mut u8, 126, inst_1.size / 8); - - let ptr = aa.alloc(&inst_2); - assert_ne!(ptr, 0); - std::ptr::write_bytes(ptr as *mut u8, 126, inst_2.size / 8); + + #[test] + fn alloc3() { + let mut aa = HAllocator::new(config1()); + let inst = Object { + size: 32, + bitset: &[0], + }; + for i in 0..1_000_000 { + test_alloc(&inst, &mut aa); + } } - } - -} \ No newline at end of file + + #[test] + fn alloc4() { + let cfg = config1(); + let mut aa = HAllocator::new(cfg); + + for i in 0..cfg.count_of_tiers { + for j in 0..(0x100000 >> (i * cfg.step_arena_size)) { + let max_size_for_this_tier = (cfg.max_object_size_by_size)( + 1 << (cfg.log_start_arena_size + i * cfg.step_arena_size), + ); + let inst = Object { + size: max_size_for_this_tier - 8 - (j % 4) * max_size_for_this_tier / 8, + bitset: &[0], + }; + test_alloc(&inst, &mut aa); + } + } + } +} diff --git a/runtime/src/gc/markqueue.rs b/runtime/src/gc/markqueue.rs new file mode 100644 index 0000000..b898e69 --- /dev/null +++ b/runtime/src/gc/markqueue.rs @@ -0,0 +1,44 @@ +pub use crate::alloca::*; +use std::cmp::min; +use std::collections::VecDeque; + +#[derive(Copy, Clone)] +pub enum MarkQueueElement { + Arena(ptr), // start of Arena lol + Object(ptr), + End, +} + +pub struct MarkQueue { + queue: std::sync::RwLock>, +} + +impl MarkQueue { + pub fn new() -> MarkQueue { + Self { + queue: std::sync::RwLock::new(VecDeque::new()), + } + } + + pub fn pushn(&self, elements: &mut VecDeque) { + self.queue.write().expect("pushn1").append(elements); + } + + pub fn popn(&self, n: usize) -> VecDeque { + let mut lock = self.queue.write().expect("popn"); + let bound = min(lock.len(), n); + let mut result = VecDeque::new(); + for _ in 0..bound { + result.push_back(lock.pop_front().expect("popn copy")); + } + result + } + + pub fn last(&self) -> Option { + self.queue.read() + .expect("last_is_end") + .iter() + .last() + .copied() + } +} diff --git a/runtime/src/gc/mod.rs b/runtime/src/gc/mod.rs new file mode 100644 index 0000000..63a53e5 --- /dev/null +++ b/runtime/src/gc/mod.rs @@ -0,0 +1,282 @@ +mod markqueue; + +use crate::{alloca, gc, threads, utils}; +use alloca::{Arena3, ArenaAllocator3, Cfg, ptr}; +use gc::markqueue::{MarkQueue, MarkQueueElement}; +use std::cmp::min; +use std::collections::VecDeque; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::thread::JoinHandle; +use threads::ThreadPhase; +use utils::object::Object; +use utils::reg; + +pub struct Gc { + pub alloca: Arc>>, + + threads: Arc>, + + stw_is_done: Arc>, + stw_cv: Arc, + + heap_is_done: Arc>, + heap_cv: Arc, + + mark_is_done: Arc>, + mark_cv: Arc, + + root_is_done: Arc>, + root_cv: Arc, + + workers: Vec>, + count_active_workers: Arc, + + root: Arc>, + mark_queue: Arc, +} + +impl Gc { + pub fn new(threads: Arc>, config: &Cfg) -> Self { + Self { + alloca: Arc::new(Mutex::new(alloca::HAllocator::::new(config))), + threads, + stw_is_done: Arc::new(Mutex::new(false)), + stw_cv: Arc::new(Default::default()), + + heap_is_done: Arc::new(Mutex::new(false)), + heap_cv: Arc::new(Default::default()), + + mark_is_done: Arc::new(Mutex::new(false)), + mark_cv: Arc::new(Default::default()), + + root_is_done: Arc::new(Mutex::new(false)), + root_cv: Arc::new(Default::default()), + + workers: Vec::new(), + count_active_workers: Arc::new(AtomicUsize::new(config.count_gc_workers)), + + root: Arc::new(Vec::new()), + mark_queue: Arc::new(MarkQueue::new()), + } + } + + pub fn init_workers(&self, count: usize) { + assert_ne!(self.workers.len(), 0); + + let mut workers = Vec::with_capacity(count); + for i in 0..count { + let thread_root_is_done = self.root_is_done.clone(); + let thread_root_cv = self.root_cv.clone(); + let mut thread_root = self.root.clone(); + let thread_alloca = self.alloca.clone(); + let thread_mark_queue = self.mark_queue.clone().clone(); + let thread_count_active_workers = self.count_active_workers.clone(); + let thread_mark_is_done = self.mark_is_done.clone(); + let thread_mark_cv = self.mark_cv.clone(); + workers.push(thread::spawn(move || { + loop { + { + let mut root_is_done_flag = thread_root_is_done.lock().unwrap(); + + while !*root_is_done_flag { + root_is_done_flag = thread_root_cv.wait(root_is_done_flag).unwrap() + } + } + let mut local_queue = VecDeque::new(); + + let count_for_scan = thread_root.len() / count + 1; + let start_j = i * count_for_scan; + let end_j = min(start_j + count_for_scan, thread_root.len()); + for j in start_j..end_j { + Self::mark_gray_el_from_ptr( + thread_alloca.clone(), + thread_root[j], + &mut local_queue, + ); + + if local_queue.len() > /* TODO: add to cfg*/ 15 { + (*thread_mark_queue).pushn(&mut local_queue); + } + } + + 'external: loop { + while !local_queue.is_empty() { + Self::mark(thread_alloca.clone(), local_queue.pop_front().unwrap()); + } + + local_queue = (*thread_mark_queue).popn(16); + if local_queue.is_empty() { + if thread_count_active_workers.fetch_sub(1, Ordering::SeqCst) == 1 { + (*thread_mark_queue) + .pushn(&mut VecDeque::from([MarkQueueElement::End])); + { + let mut root_is_done_flag = thread_root_is_done.lock().unwrap(); + thread_root = Arc::new(Vec::new()); + *root_is_done_flag = false; + + let mut mark_is_done_flag = thread_mark_is_done.lock().unwrap(); + assert!(!*mark_is_done_flag); + *mark_is_done_flag = true; + + thread_mark_cv.notify_all(); + } + + break 'external; + } else { + loop { + match (*thread_mark_queue).last() { + Some(MarkQueueElement::End) => { + thread_count_active_workers + .fetch_add(1, Ordering::SeqCst); + { + let mut mark_is_done_flag = + thread_mark_is_done.lock().unwrap(); + while !*mark_is_done_flag { + mark_is_done_flag = thread_mark_cv + .wait(mark_is_done_flag) + .unwrap() + } + } + break 'external; + } + None => {} + _ => { + local_queue = (*thread_mark_queue).popn(16); + break; + } + } + } + } + } + } + } + })) + } + } + + pub fn go_gc(&mut self, rbp: reg) { + if self.threads.lock().unwrap().go_immut(rbp) == 0 { + self.notify_master(); + } + + let mut stw_is_done_flag = self.stw_is_done.lock().unwrap(); + while !*stw_is_done_flag { + stw_is_done_flag = self.stw_cv.wait(stw_is_done_flag).unwrap() + } + + // TODO + } + + pub fn master(&mut self) { + loop { + { + let mut heap_is_done_flag = self.heap_is_done.lock().unwrap(); + while !*heap_is_done_flag { + heap_is_done_flag = self.heap_cv.wait(heap_is_done_flag).unwrap() + } + } + *self.heap_is_done.lock().unwrap() = false; + + let threads = self.threads.clone(); + let guard_threads = threads.lock().unwrap(); + for item in guard_threads.pool.thread_map.iter() { + let nthread = item.value(); + match nthread.phase { + ThreadPhase::Mutable => { + unreachable!(); + } + ThreadPhase::Immutable(cntxt) => { + self.add_to_root(cntxt.rbp); + } + } + } + + *self.root_is_done.lock().unwrap() = true; + self.root_cv.notify_all(); + + let mut mark_is_done_flag = self.mark_is_done.lock().unwrap(); + while !*mark_is_done_flag { + mark_is_done_flag = self.mark_cv.wait(mark_is_done_flag).unwrap() + } + // TODO SWEEP + } + } + + pub fn notify_master(&self) { + *self.heap_is_done.lock().unwrap() = true; + self.heap_cv.notify_all(); + } + + fn add_to_root(&mut self, rbp: reg) { + // TODO + } + + fn mark(mut alloca: Arc>>, el: MarkQueueElement) { + let mut local_queue = VecDeque::new(); + match el { + MarkQueueElement::Arena(ptr_on_arena) => { + let mut alloca_guard = alloca.lock().unwrap(); + let arena = alloca_guard.mut_arena_by_ptr(ptr_on_arena).unwrap(); + arena.make_live(); + let (black, size) = arena.black_map(); + let (gray, size) = arena.gray_map(); + let mut diff_bits = vec![]; + // byte-iter + for i in (0..size).step_by(8) { + unsafe { + diff_bits.push(*((gray + i) as *const u64) ^ *((black + i) as *const u64)); + } + } + // bit-iter + for i in 0..(size * 8) { + if (diff_bits[i / 64] & (1 << (i % 64))) != 0 { + unsafe { + *((black + (i / 64)) as *mut u64) |= (1 << (i % 64)); + } + let ptr_to_obj = arena.span_start() + i * 8; + let ptr_to_header = (ptr_to_obj - 8) as *const Object; + let size_of_object = unsafe { ptr_to_header.as_ref_unchecked().size }; + for j in 0..size_of_object / 8 { + if (unsafe { ptr_to_header.as_ref_unchecked().bitset }[j / 8] + & (1 << (j % 8))) + != 0 + { + let field_ptr = ptr_to_obj + j * 8; + Self::mark_gray_el_from_ptr( + alloca.clone(), + field_ptr, + &mut local_queue, + ); + } + } + } + } + } + MarkQueueElement::Object(ptr) => { + todo!(); + // делать мне нехуй чтоли + // TODO + } + MarkQueueElement::End => { + panic!("something went wrong in mark"); + } + } + } + + fn mark_gray_el_from_ptr( + mut alloca: Arc>>, + ptr: ptr, + source: &mut VecDeque, + ) { + match alloca.lock().unwrap().mark_gray(ptr) { + None => source.push_back(MarkQueueElement::Object(ptr)), + Some(a) => { + if !a.fetch_and_add_in_queue() { + source.push_back(MarkQueueElement::Arena(a.span_start())) + } + } + } + } +} diff --git a/runtime/src/lib.nasm b/runtime/src/lib.nasm new file mode 100644 index 0000000..968578c --- /dev/null +++ b/runtime/src/lib.nasm @@ -0,0 +1,120 @@ + +extern go_native +extern go_back + +section .text + +unsafe_state: + mov rdi, rbp + mov rsi, rsp + call go_native + ret + +safe_state: + call go_back + ret + + + + + + + + + +seq: + + push rbp + mov rbp, rsp + sub rsp, 32 + mov DWORD PTR [rbp-20], edi + mov edi, 4 + call malloc + mov QWORD PTR [rbp-8], rax + mov eax, DWORD PTR [rbp-20] + sub eax, 1 + mov edi, eax + call seq + mov rdx, QWORD PTR [rbp-8] + mov DWORD PTR [rdx], eax + mov rax, QWORD PTR [rbp-8] + mov edx, DWORD PTR [rax] + mov eax, DWORD PTR [rbp-20] + add eax, edx + leave + safepoint //rbp сейчас + + ret + + +фрейм функции +--------------- +/ число +/ птр +/ ra +/ число +/ птр + + + + + +func: + push 0b1010 + + push rbp + mov rbp, rsp + mov [rbp], число + call alloc + mov [rbp-8], ptr + sub rsp, 16 + call foo + + +foo: + push 0 + push 0 + push rbp + mov rbp, rsp + leave + ret + + + + + + + + + + + +/ old_rbp /8 +/ edi /4 -4 +/ nop /4 -8 +/ ptr /8 -16 + +sseq: + push 0 + push 16 + push rbp + mov rbp, rsp + sub rsp, 16 + mov dword ptr [rbp - 4], edi + cmp dword ptr [rbp - 4], 5 + jle .LBB0_2 + mov edi, 4 + call malloc@PLT + mov qword ptr [rbp - 16], rax + mov [rbp+...], + .LBB0_2: + mov rax, qword ptr [rbp - 16] + cmp + add rsp, 16 + pop rbp + ret + + + + + diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index fb39644..541a2f7 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1,30 +1,80 @@ #![feature(let_chains)] +#![feature(ptr_as_ref_unchecked)] mod alloca; +mod gc; +mod nni; +mod threads; +mod utils; -// static mut ALLOCA: Option> = None; - -// pub extern "C" fn init(main: fn()) { -// unsafe { -// ALLOCA = Some(alloca::ArenaAllocator3::new(8 << 40)); -// } -// main(); -// } -// -// pub extern "C" fn alloc(t: &dyn alloca::Object) -> alloca::ptr { -// unsafe { -// match ALLOCA.as_mut() { -// None => { panic!("ALLOCA is None")} -// Some(mut alloca) => { alloca.alloc(t)} -// } -// } -// } - -type reg = usize; - -pub extern "C" fn go(func: fn(reg, reg, reg, reg, reg), - r1: reg, r2: reg, r3: reg, r4: reg, r5: reg) { - func(r1, r2, r3, r4, r5); +use crate::alloca::ArenaAllocator3; +use crate::alloca::Cfg; +use std::sync::{Arc, Mutex, OnceLock}; +use utils::*; + +static THREADS: OnceLock>> = OnceLock::new(); + +static GC: OnceLock>> = OnceLock::new(); + +pub extern "C" fn init(main: fn(reg, reg, reg, reg, reg), stw: &'static bool) { + let athreads = Arc::new(Mutex::new(threads::Threads::new(stw))); + THREADS.get_or_init(|| athreads.clone()); + GC.get_or_init(|| { + Mutex::new(gc::Gc::new( + athreads, + &Cfg::new(37, 26, 12, 20, 2, 1 << 20, |size| size / 64, 3), + )) + }); + THREADS + .get() + .unwrap() + .lock() + .unwrap() + .append(main, 0, 0, 0, 0, 0); + + GC.get().unwrap().lock().unwrap().master() +} + +pub extern "C" fn alloc(t: &Object) -> alloca::ptr { + let gc = GC.get().expect("gc is none (alloc)"); + let (ptr, heap_is_overflow) = gc.lock().unwrap().alloca.lock().unwrap().alloc(t); + if heap_is_overflow { + gc.lock().unwrap().notify_master(); + } + ptr +} + +pub extern "C" fn go( + func: fn(reg, reg, reg, reg, reg), + r1: reg, + r2: reg, + r3: reg, + r4: reg, + r5: reg, +) { + func(r1, r2, r3, r4, r5); +} + +pub extern "C" fn go_gc(rbp: reg) { + GC.get().expect("gc is None").lock().unwrap().go_gc(rbp); +} + +pub extern "C" fn go_native(rbp: reg) { + THREADS + .get() + .expect("thrds is None") + .lock() + .unwrap() + .go_immut(rbp); +} + +pub extern "C" fn go_back() { + THREADS + .get() + .expect("thrds is None") + .lock() + .unwrap() + .go_mut(); } #[cfg(test)] diff --git a/runtime/src/nni/mod.rs b/runtime/src/nni/mod.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/runtime/src/nni/mod.rs @@ -0,0 +1 @@ + diff --git a/runtime/src/threads/mod.rs b/runtime/src/threads/mod.rs new file mode 100644 index 0000000..1fbd0ef --- /dev/null +++ b/runtime/src/threads/mod.rs @@ -0,0 +1,44 @@ +use crate::threads::nthread::NThread; +use crate::threads::threadpool::ThreadPool; +use crate::utils::*; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread::ThreadId; +mod nthread; +mod threadpool; +pub use nthread::ThreadPhase; + +pub struct Threads { + pub pool: ThreadPool, + stw: &'static bool, +} + +impl Threads { + pub fn new(stw: &'static bool) -> Self { + Self { + pool: ThreadPool::new(), + stw, + } + } + + pub fn append( + &mut self, + func: fn(reg, reg, reg, reg, reg), + r1: reg, + r2: reg, + r3: reg, + r4: reg, + r5: reg, + ) { + self.pool.append(func, r1, r2, r3, r4, r5); + } + + pub fn go_immut(&self, rbp: reg) -> usize { + self.pool.go_immut(rbp) + } + + pub fn go_mut(&mut self) { + while *self.stw {} + + self.pool.go_mut(); + } +} diff --git a/runtime/src/threads/nthread.rs b/runtime/src/threads/nthread.rs new file mode 100644 index 0000000..b48c446 --- /dev/null +++ b/runtime/src/threads/nthread.rs @@ -0,0 +1,32 @@ +use crate::utils::reg; +use std::sync::{Arc, RwLock}; + +pub struct NThread { + pub routine: std::thread::JoinHandle<()>, + pub state: Arc>, // i guess arc or rw or rw and arc id redundant + pub phase: ThreadPhase, +} + +#[derive(Debug, Clone, Copy)] +pub enum ThreadPhase { + Mutable, + Immutable(ThreadCntxt), +} + +impl ThreadPhase { + pub fn new(rbp: reg) -> Self { + ThreadPhase::Immutable(ThreadCntxt { rbp }) + } +} + +#[derive(Debug, Clone, Copy)] +pub struct ThreadCntxt { + pub rbp: reg, +} + +pub(crate) enum ThreadState { + Runnable, + Waiting, + Blocked, + Terminated, +} diff --git a/runtime/src/threads/threadpool.rs b/runtime/src/threads/threadpool.rs new file mode 100644 index 0000000..d2d9f2e --- /dev/null +++ b/runtime/src/threads/threadpool.rs @@ -0,0 +1,77 @@ +use crate::threads::nthread::{NThread, ThreadPhase, ThreadState}; +use crate::utils::reg; +use dashmap::DashMap; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::thread::ThreadId; + +pub struct ThreadPool { + pub thread_map: Arc>, + pub count_of_mutable: AtomicUsize, +} + +impl ThreadPool { + pub fn new() -> ThreadPool { + Self { + thread_map: Arc::new(DashMap::new()), + count_of_mutable: AtomicUsize::new(0), + } + } + + pub fn append( + &mut self, + func: fn(reg, reg, reg, reg, reg), + r1: reg, + r2: reg, + r3: reg, + r4: reg, + r5: reg, + ) { + let i = std::thread::current().id(); + let id = Arc::new(std::sync::Mutex::new(i)); + let id2 = Arc::clone(&id); + + let main_in_process = Arc::new(AtomicBool::new(true)); + let main_in_process2 = Arc::clone(&main_in_process); + + let routine = std::thread::spawn(move || { + *id2.lock().unwrap() = std::thread::current().id(); + + while main_in_process2.load(Ordering::SeqCst) {} + func(r1, r2, r3, r4, r5); + }); + + while i == *id.lock().unwrap() {} + self.count_of_mutable.fetch_add(1, Ordering::Relaxed); + self.thread_map.insert( + *id.lock().unwrap(), + NThread { + routine, + state: Arc::new(std::sync::RwLock::new(ThreadState::Runnable)), + phase: ThreadPhase::Mutable, + }, + ); + + main_in_process.store(false, Ordering::SeqCst); + } + + pub fn go_immut(&self, rbp: reg) -> usize { + assert_ne!(self.count_of_mutable.load(Ordering::Relaxed), 0); + + self.thread_map + .get_mut(&std::thread::current().id()) + .expect("fantom thread") + .phase = ThreadPhase::new(rbp); + + self.count_of_mutable.fetch_sub(1, Ordering::Relaxed) - 1 + } + + pub fn go_mut(&self) { + self.thread_map + .get_mut(&std::thread::current().id()) + .expect("fantom thread") + .phase = ThreadPhase::Mutable; + + self.count_of_mutable.fetch_add(1, Ordering::Relaxed); + } +} diff --git a/runtime/src/utils/mod.rs b/runtime/src/utils/mod.rs new file mode 100644 index 0000000..1f8486b --- /dev/null +++ b/runtime/src/utils/mod.rs @@ -0,0 +1,5 @@ +pub mod object; + +pub type reg = usize; + +pub use object::*; diff --git a/runtime/src/utils/object.rs b/runtime/src/utils/object.rs new file mode 100644 index 0000000..22a3053 --- /dev/null +++ b/runtime/src/utils/object.rs @@ -0,0 +1,4 @@ +pub struct Object { + pub size: usize, + pub bitset: &'static [u8], +}