mem.odin 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import (
  2. "fmt.odin";
  3. "os.odin";
  4. "raw.odin";
  5. )
  6. foreign __llvm_core {
  7. swap :: proc(b: u16) -> u16 #link_name "llvm.bswap.i16" ---;
  8. swap :: proc(b: u32) -> u32 #link_name "llvm.bswap.i32" ---;
  9. swap :: proc(b: u64) -> u64 #link_name "llvm.bswap.i64" ---;
  10. }
  11. set :: proc(data: rawptr, value: i32, len: int) -> rawptr #cc_contextless {
  12. return __mem_set(data, value, len);
  13. }
  14. zero :: proc(data: rawptr, len: int) -> rawptr #cc_contextless {
  15. return __mem_zero(data, len);
  16. }
  17. copy :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
  18. return __mem_copy(dst, src, len);
  19. }
  20. copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
  21. return __mem_copy_non_overlapping(dst, src, len);
  22. }
  23. compare :: proc(a, b: []u8) -> int #cc_contextless {
  24. return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
  25. }
  26. slice_ptr :: proc(ptr: ^$T, len: int) -> []T #cc_contextless {
  27. assert(len >= 0);
  28. slice := raw.Slice{data = ptr, len = len, cap = len};
  29. return (cast(^[]T)&slice)^;
  30. }
  31. slice_ptr :: proc(ptr: ^$T, len, cap: int) -> []T #cc_contextless {
  32. assert(0 <= len && len <= cap);
  33. slice := raw.Slice{data = ptr, len = len, cap = cap};
  34. return (cast(^[]T)&slice)^;
  35. }
  36. slice_to_bytes :: proc(slice: []$T) -> []u8 #cc_contextless {
  37. s := cast(^raw.Slice)&slice;
  38. s.len *= size_of(T);
  39. s.cap *= size_of(T);
  40. return (cast(^[]u8)s)^;
  41. }
  42. kilobytes :: proc(x: int) -> int #inline #cc_contextless { return (x) * 1024; }
  43. megabytes :: proc(x: int) -> int #inline #cc_contextless { return kilobytes(x) * 1024; }
  44. gigabytes :: proc(x: int) -> int #inline #cc_contextless { return megabytes(x) * 1024; }
  45. terabytes :: proc(x: int) -> int #inline #cc_contextless { return gigabytes(x) * 1024; }
  46. is_power_of_two :: proc(x: int) -> bool {
  47. if x <= 0 do return false;
  48. return (x & (x-1)) == 0;
  49. }
  50. align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
  51. assert(is_power_of_two(align));
  52. a := uint(align);
  53. p := uint(ptr);
  54. modulo := p & (a-1);
  55. if modulo != 0 do p += a - modulo;
  56. return rawptr(p);
  57. }
  58. AllocationHeader :: struct {
  59. size: int;
  60. }
  61. allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
  62. header.size = size;
  63. ptr := cast(^uint)(header+1);
  64. n := cast(^uint)data - ptr;
  65. for i in 0..n {
  66. (ptr+i)^ = ~uint(0);
  67. }
  68. }
  69. allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
  70. if data == nil do return nil;
  71. p := cast(^uint)data;
  72. for (p-1)^ == ~uint(0) do p = (p-1);
  73. return cast(^AllocationHeader)(p-1);
  74. }
  75. // Custom allocators
  76. Arena :: struct {
  77. backing: Allocator;
  78. offset: int;
  79. memory: []u8;
  80. temp_count: int;
  81. }
  82. ArenaTempMemory :: struct {
  83. arena: ^Arena;
  84. original_count: int;
  85. }
  86. init_arena_from_memory :: proc(using a: ^Arena, data: []u8) {
  87. backing = Allocator{};
  88. memory = data[..0];
  89. temp_count = 0;
  90. }
  91. init_arena_from_context :: proc(using a: ^Arena, size: int) {
  92. backing = context.allocator;
  93. memory = make([]u8, size);
  94. temp_count = 0;
  95. }
  96. destroy_arena :: proc(using a: ^Arena) {
  97. if backing.procedure != nil {
  98. push_allocator backing {
  99. free(memory);
  100. memory = nil;
  101. offset = 0;
  102. }
  103. }
  104. }
  105. arena_allocator :: proc(arena: ^Arena) -> Allocator {
  106. return Allocator{
  107. procedure = arena_allocator_proc,
  108. data = arena,
  109. };
  110. }
  111. arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
  112. size, alignment: int,
  113. old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
  114. using Allocator.Mode;
  115. arena := cast(^Arena)allocator_data;
  116. match mode {
  117. case Alloc:
  118. total_size := size + alignment;
  119. if arena.offset + total_size > len(arena.memory) {
  120. fmt.fprintln(os.stderr, "Arena out of memory");
  121. return nil;
  122. }
  123. #no_bounds_check end := &arena.memory[arena.offset];
  124. ptr := align_forward(end, alignment);
  125. arena.offset += total_size;
  126. return zero(ptr, size);
  127. case Free:
  128. // NOTE(bill): Free all at once
  129. // Use ArenaTempMemory if you want to free a block
  130. case FreeAll:
  131. arena.offset = 0;
  132. case Resize:
  133. return default_resize_align(old_memory, old_size, size, alignment);
  134. }
  135. return nil;
  136. }
  137. begin_arena_temp_memory :: proc(a: ^Arena) -> ArenaTempMemory {
  138. tmp: ArenaTempMemory;
  139. tmp.arena = a;
  140. tmp.original_count = len(a.memory);
  141. a.temp_count += 1;
  142. return tmp;
  143. }
  144. end_arena_temp_memory :: proc(using tmp: ArenaTempMemory) {
  145. assert(len(arena.memory) >= original_count);
  146. assert(arena.temp_count > 0);
  147. arena.memory = arena.memory[..original_count];
  148. arena.temp_count -= 1;
  149. }
  150. align_of_type_info :: proc(type_info: ^TypeInfo) -> int {
  151. prev_pow2 :: proc(n: i64) -> i64 {
  152. if n <= 0 do return 0;
  153. n |= n >> 1;
  154. n |= n >> 2;
  155. n |= n >> 4;
  156. n |= n >> 8;
  157. n |= n >> 16;
  158. n |= n >> 32;
  159. return n - (n >> 1);
  160. }
  161. WORD_SIZE :: size_of(int);
  162. MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
  163. using TypeInfo;
  164. match info in type_info.variant {
  165. case Named:
  166. return align_of_type_info(info.base);
  167. case Integer:
  168. return type_info.align;
  169. case Rune:
  170. return type_info.align;
  171. case Float:
  172. return type_info.align;
  173. case String:
  174. return WORD_SIZE;
  175. case Boolean:
  176. return 1;
  177. case Any:
  178. return WORD_SIZE;
  179. case Pointer:
  180. return WORD_SIZE;
  181. case Procedure:
  182. return WORD_SIZE;
  183. case Array:
  184. return align_of_type_info(info.elem);
  185. case DynamicArray:
  186. return WORD_SIZE;
  187. case Slice:
  188. return WORD_SIZE;
  189. case Vector:
  190. size := size_of_type_info(info.elem);
  191. count := int(max(prev_pow2(i64(info.count)), 1));
  192. total := size * count;
  193. return clamp(total, 1, MAX_ALIGN);
  194. case Tuple:
  195. return type_info.align;
  196. case Struct:
  197. return type_info.align;
  198. case Union:
  199. return type_info.align;
  200. case Enum:
  201. return align_of_type_info(info.base);
  202. case Map:
  203. return align_of_type_info(info.generated_struct);
  204. }
  205. return 0;
  206. }
  207. align_formula :: proc(size, align: int) -> int {
  208. result := size + align-1;
  209. return result - result%align;
  210. }
  211. size_of_type_info :: proc(type_info: ^TypeInfo) -> int {
  212. WORD_SIZE :: size_of(int);
  213. using TypeInfo;
  214. match info in type_info.variant {
  215. case Named:
  216. return size_of_type_info(info.base);
  217. case Integer:
  218. return type_info.size;
  219. case Rune:
  220. return type_info.size;
  221. case Float:
  222. return type_info.size;
  223. case String:
  224. return 2*WORD_SIZE;
  225. case Boolean:
  226. return 1;
  227. case Any:
  228. return 2*WORD_SIZE;
  229. case Pointer:
  230. return WORD_SIZE;
  231. case Procedure:
  232. return WORD_SIZE;
  233. case Array:
  234. count := info.count;
  235. if count == 0 do return 0;
  236. size := size_of_type_info(info.elem);
  237. align := align_of_type_info(info.elem);
  238. alignment := align_formula(size, align);
  239. return alignment*(count-1) + size;
  240. case DynamicArray:
  241. return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
  242. case Slice:
  243. return 2*WORD_SIZE;
  244. case Vector:
  245. count := info.count;
  246. if count == 0 do return 0;
  247. size := size_of_type_info(info.elem);
  248. align := align_of_type_info(info.elem);
  249. alignment := align_formula(size, align);
  250. return alignment*(count-1) + size;
  251. case Struct:
  252. return type_info.size;
  253. case Union:
  254. return type_info.size;
  255. case Enum:
  256. return size_of_type_info(info.base);
  257. case Map:
  258. return size_of_type_info(info.generated_struct);
  259. }
  260. return 0;
  261. }