default_temporary_allocator.odin 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package runtime
  2. DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22)
  3. when ODIN_OS == "freestanding" {
  4. Default_Temp_Allocator :: struct {
  5. }
  6. default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {
  7. }
  8. default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {
  9. }
  10. default_temp_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
  11. size, alignment: int,
  12. old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
  13. return nil, nil
  14. }
  15. } else {
  16. Default_Temp_Allocator :: struct {
  17. data: []byte,
  18. curr_offset: int,
  19. prev_allocation: rawptr,
  20. backup_allocator: Allocator,
  21. leaked_allocations: [dynamic][]byte,
  22. }
  23. default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {
  24. s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator)
  25. s.curr_offset = 0
  26. s.prev_allocation = nil
  27. s.backup_allocator = backup_allocator
  28. s.leaked_allocations.allocator = backup_allocator
  29. }
  30. default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {
  31. if s == nil {
  32. return
  33. }
  34. for ptr in s.leaked_allocations {
  35. free(raw_data(ptr), s.backup_allocator)
  36. }
  37. delete(s.leaked_allocations)
  38. delete(s.data, s.backup_allocator)
  39. s^ = {}
  40. }
  41. @(private)
  42. default_temp_allocator_alloc :: proc(s: ^Default_Temp_Allocator, size, alignment: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
  43. size := size
  44. size = align_forward_int(size, alignment)
  45. switch {
  46. case s.curr_offset+size <= len(s.data):
  47. start := uintptr(raw_data(s.data))
  48. ptr := start + uintptr(s.curr_offset)
  49. ptr = align_forward_uintptr(ptr, uintptr(alignment))
  50. mem_zero(rawptr(ptr), size)
  51. s.prev_allocation = rawptr(ptr)
  52. offset := int(ptr - start)
  53. s.curr_offset = offset + size
  54. return byte_slice(rawptr(ptr), size), .None
  55. case size <= len(s.data):
  56. start := uintptr(raw_data(s.data))
  57. ptr := align_forward_uintptr(start, uintptr(alignment))
  58. mem_zero(rawptr(ptr), size)
  59. s.prev_allocation = rawptr(ptr)
  60. offset := int(ptr - start)
  61. s.curr_offset = offset + size
  62. return byte_slice(rawptr(ptr), size), .None
  63. }
  64. a := s.backup_allocator
  65. if a.procedure == nil {
  66. a = context.allocator
  67. s.backup_allocator = a
  68. }
  69. data, err := mem_alloc_bytes(size, alignment, a, loc)
  70. if err != nil {
  71. return data, err
  72. }
  73. if s.leaked_allocations == nil {
  74. s.leaked_allocations = make([dynamic][]byte, a)
  75. }
  76. append(&s.leaked_allocations, data)
  77. // TODO(bill): Should leaks be notified about?
  78. if logger := context.logger; logger.lowest_level <= .Warning {
  79. if logger.procedure != nil {
  80. logger.procedure(logger.data, .Warning, "default temp allocator resorted to backup_allocator" , logger.options, loc)
  81. }
  82. }
  83. return data, .None
  84. }
  85. @(private)
  86. default_temp_allocator_free :: proc(s: ^Default_Temp_Allocator, old_memory: rawptr, loc := #caller_location) -> Allocator_Error {
  87. if old_memory == nil {
  88. return .None
  89. }
  90. start := uintptr(raw_data(s.data))
  91. end := start + uintptr(len(s.data))
  92. old_ptr := uintptr(old_memory)
  93. if s.prev_allocation == old_memory {
  94. s.curr_offset = int(uintptr(s.prev_allocation) - start)
  95. s.prev_allocation = nil
  96. return .None
  97. }
  98. if start <= old_ptr && old_ptr < end {
  99. // NOTE(bill): Cannot free this pointer but it is valid
  100. return .None
  101. }
  102. if len(s.leaked_allocations) != 0 {
  103. for data, i in s.leaked_allocations {
  104. ptr := raw_data(data)
  105. if ptr == old_memory {
  106. free(ptr, s.backup_allocator)
  107. ordered_remove(&s.leaked_allocations, i)
  108. return .None
  109. }
  110. }
  111. }
  112. return .Invalid_Pointer
  113. // panic("invalid pointer passed to default_temp_allocator");
  114. }
  115. @(private)
  116. default_temp_allocator_free_all :: proc(s: ^Default_Temp_Allocator, loc := #caller_location) {
  117. s.curr_offset = 0
  118. s.prev_allocation = nil
  119. for data in s.leaked_allocations {
  120. free(raw_data(data), s.backup_allocator)
  121. }
  122. clear(&s.leaked_allocations)
  123. }
  124. @(private)
  125. default_temp_allocator_resize :: proc(s: ^Default_Temp_Allocator, old_memory: rawptr, old_size, size, alignment: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
  126. begin := uintptr(raw_data(s.data))
  127. end := begin + uintptr(len(s.data))
  128. old_ptr := uintptr(old_memory)
  129. if old_memory == s.prev_allocation && old_ptr & uintptr(alignment)-1 == 0 {
  130. if old_ptr+uintptr(size) < end {
  131. s.curr_offset = int(old_ptr-begin)+size
  132. return byte_slice(old_memory, size), .None
  133. }
  134. }
  135. data, err := default_temp_allocator_alloc(s, size, alignment, loc)
  136. if err == .None {
  137. copy(data, byte_slice(old_memory, old_size))
  138. err = default_temp_allocator_free(s, old_memory, loc)
  139. }
  140. return data, err
  141. }
  142. default_temp_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
  143. size, alignment: int,
  144. old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
  145. s := (^Default_Temp_Allocator)(allocator_data)
  146. if s.data == nil {
  147. default_temp_allocator_init(s, DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, default_allocator())
  148. }
  149. switch mode {
  150. case .Alloc:
  151. data, err = default_temp_allocator_alloc(s, size, alignment, loc)
  152. case .Free:
  153. err = default_temp_allocator_free(s, old_memory, loc)
  154. case .Free_All:
  155. default_temp_allocator_free_all(s, loc)
  156. case .Resize:
  157. data, err = default_temp_allocator_resize(s, old_memory, old_size, size, alignment, loc)
  158. case .Query_Features:
  159. set := (^Allocator_Mode_Set)(old_memory)
  160. if set != nil {
  161. set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features}
  162. }
  163. case .Query_Info:
  164. // Nothing to give
  165. }
  166. return
  167. }
  168. }
  169. default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator {
  170. return Allocator{
  171. procedure = default_temp_allocator_proc,
  172. data = allocator,
  173. }
  174. }