default_temporary_allocator.odin 5.5 KB

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