heap_allocator.odin 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package runtime
  2. import "base:intrinsics"
  3. heap_allocator :: proc() -> Allocator {
  4. return Allocator{
  5. procedure = heap_allocator_proc,
  6. data = nil,
  7. }
  8. }
  9. heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
  10. size, alignment: int,
  11. old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
  12. //
  13. // NOTE(tetra, 2020-01-14): The heap doesn't respect alignment.
  14. // Instead, we overallocate by `alignment + size_of(rawptr) - 1`, and insert
  15. // padding. We also store the original pointer returned by heap_alloc right before
  16. // the pointer we return to the user.
  17. //
  18. aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr, old_size: int, zero_memory := true) -> ([]byte, Allocator_Error) {
  19. // Not(flysand): We need to reserve enough space for alignment, which
  20. // includes the user data itself, the space to store the pointer to
  21. // allocation start, as well as the padding required to align both
  22. // the user data and the pointer.
  23. a := max(alignment, align_of(rawptr))
  24. space := a-1 + size_of(rawptr) + size
  25. allocated_mem: rawptr
  26. force_copy := old_ptr != nil && alignment > align_of(rawptr)
  27. if old_ptr != nil && !force_copy {
  28. original_old_ptr := ([^]rawptr)(old_ptr)[-1]
  29. allocated_mem = heap_resize(original_old_ptr, space)
  30. } else {
  31. allocated_mem = heap_alloc(space, zero_memory)
  32. }
  33. aligned_mem := rawptr(([^]u8)(allocated_mem)[size_of(rawptr):])
  34. ptr := uintptr(aligned_mem)
  35. aligned_ptr := (ptr + uintptr(a)-1) & ~(uintptr(a)-1)
  36. if allocated_mem == nil {
  37. aligned_free(old_ptr)
  38. aligned_free(allocated_mem)
  39. return nil, .Out_Of_Memory
  40. }
  41. aligned_mem = rawptr(aligned_ptr)
  42. ([^]rawptr)(aligned_mem)[-1] = allocated_mem
  43. if force_copy {
  44. mem_copy_non_overlapping(aligned_mem, old_ptr, min(old_size, size))
  45. aligned_free(old_ptr)
  46. }
  47. return byte_slice(aligned_mem, size), nil
  48. }
  49. aligned_free :: proc(p: rawptr) {
  50. if p != nil {
  51. heap_free(([^]rawptr)(p)[-1])
  52. }
  53. }
  54. aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int, zero_memory := true) -> (new_memory: []byte, err: Allocator_Error) {
  55. if p == nil {
  56. return aligned_alloc(new_size, new_alignment, nil, old_size, zero_memory)
  57. }
  58. new_memory = aligned_alloc(new_size, new_alignment, p, old_size, zero_memory) or_return
  59. // NOTE: heap_resize does not zero the new memory, so we do it
  60. if zero_memory && new_size > old_size {
  61. new_region := raw_data(new_memory[old_size:])
  62. intrinsics.mem_zero(new_region, new_size - old_size)
  63. }
  64. return
  65. }
  66. switch mode {
  67. case .Alloc, .Alloc_Non_Zeroed:
  68. return aligned_alloc(size, alignment, nil, 0, mode == .Alloc)
  69. case .Free:
  70. aligned_free(old_memory)
  71. case .Free_All:
  72. return nil, .Mode_Not_Implemented
  73. case .Resize, .Resize_Non_Zeroed:
  74. return aligned_resize(old_memory, old_size, size, alignment, mode == .Resize)
  75. case .Query_Features:
  76. set := (^Allocator_Mode_Set)(old_memory)
  77. if set != nil {
  78. set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Resize, .Resize_Non_Zeroed, .Query_Features}
  79. }
  80. return nil, nil
  81. case .Query_Info:
  82. return nil, .Mode_Not_Implemented
  83. }
  84. return nil, nil
  85. }
  86. heap_alloc :: proc "contextless" (size: int, zero_memory := true) -> rawptr {
  87. return _heap_alloc(size, zero_memory)
  88. }
  89. heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr {
  90. return _heap_resize(ptr, new_size)
  91. }
  92. heap_free :: proc "contextless" (ptr: rawptr) {
  93. _heap_free(ptr)
  94. }