mem.odin 6.3 KB

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