@@ -141,42 +141,162 @@ void exit(int status) {
141141}
142142
143143/*
144- non-optimal malloc
144+ malloc implementation
145+ - linear allocation based on first come first served
146+ - allocate first free block >= requested size
147+
148+ pros
149+ - easy to implement as the initial implementation
150+ cons
151+ - malloc is slow
152+ - as we are not using virtual addressing the physical
153+ allocated memory is limited slowly ness shouldn't be
154+ noticeable.
155+
156+ memory_layout
157+ -------------
158+ _heap_start: # static marker defined at link time
159+ heap_entry{is_free, size}
160+ heap_entry{is_free, size}
161+ heap_entry{is_free, size}
162+ ...
163+ ... heap_entry_count times
164+ ... unused memory
165+ _heap_end: # dynamic marker based on current esp
166+
145167*/
146168extern void * get_current_esp (); // defined in stdlib.asm
147169extern char _heap_start []; // defined in linker.ld
148- static int heap_head_offset = 0 ;
170+ static int heap_entry_count = 0 ;
149171static const int heap_stack_safety_gap = 1024 ; // keep 1 kb free between stack and heap
150172
151173// benchmarking
152174static int benchmark_heap_inuse = 0 ;
175+ static int benchmark_heap_area = 0 ;
153176
154177int benchmark_get_heap_usage () {
178+ // heap memory in use
155179 return benchmark_heap_inuse ;
156180}
157181
158- void * malloc (size_t size ) {
159- size = ((size + 3 ) >> 2 ) << 2 ;
160- size += 4 ; // 4 bytes to store size
182+ int benchmark_get_heap_area () {
183+ // overall memory area ever occupied by heap area
184+ return benchmark_heap_area ;
185+ }
161186
162- void * loc = _heap_start + heap_head_offset ;
187+ static union heap_entry {
188+ // header of each allocated or unallocated block
189+ struct {
190+ uint32_t size ; // including the header size
191+ uint8_t is_free ;
192+ } content ;
193+ uint32_t __padding [2 ]; // force heap_entry size to be 8 bytes.
194+ } ;
195+
196+ static union heap_entry * malloc_allocate_new_block (union heap_entry * block , size_t size ) {
163197 void * max_loc = get_current_esp ()- heap_stack_safety_gap - size ;
164- if (loc > max_loc ) {
198+ if ((void * )block > max_loc ) {
199+ // panic if no memory to allocate
165200 printf ("failed to allocate more memory\n" );
166201 exit (-1 );
167- return NULL ;
168202 }
169- heap_head_offset += size ;
170- benchmark_heap_inuse += size ;
203+ benchmark_heap_area = max (benchmark_heap_area , (int )(((void * )block ) + size - (void * )_heap_start ));
204+
205+ block -> content .size = size ;
206+ block -> content .is_free = 1 ; // new block is free at init.
207+ heap_entry_count ++ ;
208+ printf ("[log] malloc_allocate_new_block: %x, %d\n" , block , size );
209+ return block ;
210+ }
211+
212+ static union heap_entry * malloc_split_block (union heap_entry * block , size_t size ) {
213+
214+ // returns the first one of the two splitted blocks
215+
216+ // [ --------- old-free-block-------------- ]
217+ // [ allocating-block] [new-left-over-block]
218+ const int TODO_NEVER_SPLIT = 1 ;
219+ size_t left_over_size = block -> content .size - size ;
220+ if (TODO_NEVER_SPLIT || left_over_size < sizeof (union heap_entry )+8 ) {
221+ // do not split block if left-over block for less than 8 bytes allocation.
222+ // i.e. do not split block
223+ // printf("[log] malloc_split_block: %x, %d out of %d [no-split]\n", block, size, block->content.size);
224+ return block ;
225+ }
226+ // allocate new-left-over-block
227+ union heap_entry * block_second = malloc_allocate_new_block ((union heap_entry * )(((void * )block )+ size ), left_over_size );
228+ // resize first block
229+ block -> content .size = size ;
230+ printf ("[log] malloc_split_block: %x, %d [split]\n" , block , size );
231+ return block ;
232+ }
233+
234+ static void malloc_merge_onfree (union heap_entry * block ) {
235+ // merge recently free block to neighboring block
236+ // if they are free are also free to form large free
237+ // block.
238+ if (!block -> content .is_free ) return ;
171239
172- * ((uint32_t * )loc ) = size ;
173- return (loc + 4 );
240+ // TODO(scopeinfinity): implement
174241}
175242
243+ static union heap_entry * malloc_find_freeblock (size_t size ) {
244+ if (size > 200 )
245+ printf ("[log] malloc_find_freeblock: %d, block_count: %d\n" , size , heap_entry_count );
246+ // size includes header size
247+ void * loc = _heap_start ; // start
248+ int block_id = 0 ;
249+ while (1 ) {
250+ // printf("[log] searching %d at %x\n", block_id, loc);
251+
252+ union heap_entry * block = loc ;
253+ if (block_id == heap_entry_count ) {
254+ // create new node
255+ return malloc_allocate_new_block (block , size );
256+ }
257+ const int TODO_ALWAYS_ALLOCATE_LAST = 1 ;
258+ if (TODO_ALWAYS_ALLOCATE_LAST || (!block -> content .is_free ) || block -> content .size < size ) {
259+ // block is not free
260+ // not sufficient memory in this block
261+ loc += block -> content .size ;
262+ block_id ++ ;
263+ continue ;
264+ }
265+ // returns the block after split or no-split
266+ return malloc_split_block (block , size );
267+ }
268+ }
269+
270+ void * malloc (size_t size ) {
271+ // allocates in chunk of 4
272+ size = ((size + 3 ) >> 2 ) << 2 ;
273+ // allocate header
274+ size += sizeof (union heap_entry );
275+
276+ union heap_entry * header = malloc_find_freeblock (size );
277+
278+ benchmark_heap_inuse += size ;
279+ header -> content .size = size ;
280+ header -> content .is_free = 0 ; // false
281+ return (((void * )header )+ sizeof (union heap_entry ));
282+ }
283+
284+ // TODO(scopeinfinity): Cleanup before submit
285+ // - LOGO empty : 372 bytes
286+ // - Now: 188 bytes
287+
176288void free (void * ptr ) {
177289 if (ptr == NULL ) return ;
178290 // current version of malloc is non-optimal and doesn't
179291 // do any free operation.
180- size_t size = * ((uint32_t * )(ptr - 4 ));
292+ union heap_entry * header = ptr - sizeof (union heap_entry );
293+ if (header -> content .is_free != 0 ) {
294+ // trying to free unallocated memory
295+ printf ("[log] trying to free unallocated memory: %x" , ptr );
296+ return ;
297+ }
298+ header -> content .is_free = 1 ; // true
299+ size_t size = header -> content .size ;
181300 benchmark_heap_inuse -= size ;
301+ malloc_merge_onfree (header );
182302}
0 commit comments