@@ -359,6 +359,7 @@ malloc:
359359 ld (hl) , e \ inc hl
360360 ld (hl) , d ; Pointer to footer
361361.finish:
362+ ; Note: Don't change this unless you also change realloc
362363 pop bc
363364 pop de
364365 pop hl
@@ -505,3 +506,180 @@ _: pop af
505506 ld (hl) , d
506507 ; Forward merge complete!
507508 jr .check_previous_block
509+
510+ ;; realloc [System]
511+ ;; Reallocates a block of memory at a different size and returns a new pointer.
512+ ;; Inputs:
513+ ;; IX: Block to resize
514+ ;; BC: New size
515+ ;; Outputs:
516+ ;; IX: New memory
517+ ;; Z: Reset on failure, set on success
518+ ;; A: Preserved if success, error code if failure
519+ ;; Notes:
520+ ;; This function may have to move the memory that you've allocated. Consider the old pointer invalid and use
521+ ;; the one returned from realloc instead.
522+ realloc:
523+ push af
524+ ld a , i
525+ push af
526+ di
527+ push hl
528+ push de
529+ push bc
530+ xor a \ cp b \ jr nz , _
531+ cp c \ jp z , .just_free_it ; Free if zero
532+ _: ld l , (ix + - 2 )
533+ ld h , (ix + - 1 )
534+ ; Check for what case we're handling
535+ or a
536+ sbc hl , bc
537+ jr z , .dont_resize
538+ jr c , .resize_grow
539+ .resize_shrink:
540+ ; BC is the leftover amount after we make it smaller
541+ ; If it's less than 5, don't bother because we'll get a dead spot
542+ xor a \ cp b
543+ jr nz , _
544+ ld a , 5 \ cp c
545+ jr z , .dont_resize
546+ ; Okay, we're fine. Continue.
547+ push ix
548+ add ix , bc
549+ pop hl \ push hl
550+ dec hl \ dec hl \ dec hl
551+ ld (ix) , l
552+ ld (ix + 1 ) , h
553+ ld a , 0xFE
554+ ld (ix + 2 ) , a ; Create to-be-freed block
555+ dec bc \ dec bc \ dec bc \ dec bc \ dec bc
556+ ld (ix + 3 ) , c ; Size of free block
557+ ld (ix + 4 ) , b
558+ ; Write free block footer
559+ push ix \ pop hl
560+ inc hl \ inc hl
561+ add ix , bc
562+ ; IX is now at footer-5
563+ ld (ix + 5 ) , l
564+ ld (ix + 6 ) , h
565+ push hl \ pop ix
566+ ld bc , 3 \ add ix , bc
567+ ; Join newly created free block with adjacent blocks if possible
568+ ; NOTE: This calls free while the state of memory is _invalid_!
569+ call free
570+ pop ix
571+ pop bc
572+ ld (ix + - 2 ) , c
573+ ld (ix + - 1 ) , b ; Write new size of original block
574+ jr _
575+ .dont_resize:
576+ ; Note: Don't change this unless you also change malloc
577+ pop bc
578+ _: pop de
579+ pop hl
580+ pop af
581+ jp po , _
582+ ei
583+ _: pop af
584+ ret
585+ .just_free_it:
586+ pop bc
587+ pop de
588+ pop hl
589+ pop af
590+ jp po , _
591+ ei
592+ _: pop af
593+ jp free
594+ .resize_grow:
595+ #define prev_block_ptr kernelGarbage
596+ #define next_block_ptr kernelGarbage + 2
597+ ; First, we check to see if we can fit it by expanding into a free block
598+ ; to the left of this one, and potentially including the block to the right
599+ ; If so, we do just that. If not, we just malloc it elsewhere and copy it
600+ ; over, then free the original block.
601+
602+ ld (prev_block_ptr) , ix
603+ ld (next_block_ptr) , ix ; In case can can't use them
604+ ld c , (ix + - 2 )
605+ ld b , (ix + - 1 ) ; Set BC to current size
606+ call .add_next_block
607+ call .add_prev_block
608+ pop de \ push de
609+ ; BC is now the maximum potential size, DE is the desired size, see if it'll fit
610+ call cpBCDE
611+ jr c , .manual_realloc
612+ ; We can expand!
613+ ; The procedure is to use the previous block as the new one
614+ ; We'll change its size to the desired one, and move the contents of memory over
615+ ; But we'll leave it marked as "free" and then hand it over to malloc, and that's it!
616+ ld c , (ix + - 2 )
617+ ld b , (ix + - 1 ) ; Set BC to current size
618+ push de
619+ ld hl , (prev_block_ptr)
620+ ex de , hl
621+ push ix \ pop hl
622+ call cpHLDE
623+ jr z , _ ; Skip memory move if we can't move backwards
624+ ldir
625+ jr ++ _
626+ _: pop de
627+ _: ld hl , (prev_block_ptr)
628+ jp do_allocate@malloc ; Hand it over to malloc to finish the job
629+ .manual_realloc:
630+ ; We can't expand into neighboring sections so we have to do a manual realloc/copy/free
631+ push ix \ pop hl
632+ ld c , (ix + - 2 )
633+ ld b , (ix + - 1 ) ; Set BC to current size
634+ push ix
635+ push bc
636+ ld b , d \ ld c , e
637+ call malloc
638+ pop bc
639+ ldir
640+ push ix \ pop de
641+ pop ix
642+ call free
643+ push de \ pop ix
644+ jp .dont_resize ; (we're done)
645+ .add_next_block:
646+ push ix \ pop hl
647+ add hl , bc
648+ inc hl \ inc hl
649+ ld a , 0x80
650+ cp h
651+ ret nc ; We went past the end of memory
652+ ld (next_block_ptr) , hl
653+ ld a , (hl)
654+ cp 0xFF
655+ ret nz ; Not free
656+ inc hl
657+ ; HL points to size of next block
658+ ld e , (hl) \ inc hl
659+ ld d , (hl) \ ex de , hl
660+ add hl , bc
661+ ld b , h \ ld c , l
662+ inc bc \ inc bc \ inc bc \ inc bc \ inc bc ; Factor in removed headers
663+ ret
664+ .add_prev_block:
665+ push ix \ pop hl
666+ dec hl \ ld d , (hl)
667+ dec hl \ ld e , (hl)
668+ ; DE points to header of previous block
669+ ld a , 0x80
670+ cp d
671+ ret nc ; We went past the start of memory
672+ ex de , hl
673+ ld (prev_block_ptr) , hl
674+ ld a , (hl)
675+ cp 0xFF
676+ ret nz ; Not free
677+ inc hl
678+ ld e , (hl) \ inc hl
679+ ld d , (hl) \ ex de , hl
680+ add hl , de
681+ ld c , h \ ld b , l
682+ inc bc \ inc bc \ inc bc \ inc bc \ inc bc ; Factor in removed headers
683+ ret
684+ #undefine prev_block_ptr
685+ #undefine next_block_ptr
0 commit comments