// File: chhylp123[P]hifiasm/kalloc.cpp
// Function: kfree
void kfree(void *_km, void *ap) /* kfree() also adds a new core to the circular list */
{
	header_t *p, *q;
	kmem_t *km = (kmem_t*)_km;
	
	if (!ap) return;
	if (km == NULL) {
		free(ap);
		return;
	}
	p = (header_t*)((size_t*)ap - 1);
	p->size = *((size_t*)ap - 1);
	/* Find the pointer that points to the block to be freed. The following loop can stop on two conditions:
	 *
	 * a) "p>q && p<q->ptr": @------#++++++++#+++++++@-------    @---------------#+++++++@-------
	 *    (can also be in    |      |                |        -> |                       |
	 *     two cores)        q      p           q->ptr           q                  q->ptr
	 *
	 *                       @--------    #+++++++++@--------    @--------    @------------------
	 *                       |            |         |         -> |            |
	 *                       q            p    q->ptr            q       q->ptr
	 *
	 * b) "q>=q->ptr && (p>q || p<q->ptr)":  @-------#+++++   @--------#+++++++     @-------#+++++   @----------------
	 *                                       |                |        |         -> |                |
	 *                                  q->ptr                q        p       q->ptr                q
	 *
	 *                                       #+++++++@-----   #++++++++@-------     @-------------   #++++++++@-------
	 *                                       |       |                 |         -> |                         |
	 *                                       p  q->ptr                 q       q->ptr                         q
	 */
	for (q = km->loop_head; !(p > q && p < q->ptr); q = q->ptr)
		if (q >= q->ptr && (p > q || p < q->ptr)) break;
	if (p + p->size == q->ptr) { /* two adjacent blocks, merge p and q->ptr (the 2nd and 4th cases) */
		p->size += q->ptr->size;
		p->ptr = q->ptr->ptr;
	} else if (p + p->size > q->ptr && q->ptr >= p) {
		panic("[kfree] The end of the allocated block enters a free block.");
	} else p->ptr = q->ptr; /* backup q->ptr */

	if (q + q->size == p) { /* two adjacent blocks, merge q and p (the other two cases) */
		q->size += p->size;
		q->ptr = p->ptr;
		km->loop_head = q;
	} else if (q + q->size > p && p >= q) {
		panic("[kfree] The end of a free block enters the allocated block.");
	} else km->loop_head = p, q->ptr = p; /* in two cores, cannot be merged; create a new block in the list */
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x30, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x10(%rbp)
jne 0x30e2f4
jmp 0x30e4b6
cmpq $0x0, -0x28(%rbp)
jne 0x30e309
movq -0x10(%rbp), %rdi
callq 0x2210
jmp 0x30e4b6
movq -0x10(%rbp), %rax
addq $-0x8, %rax
movq %rax, -0x18(%rbp)
movq -0x10(%rbp), %rax
movq -0x8(%rax), %rcx
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
movq -0x28(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rcx
xorl %eax, %eax
cmpq -0x20(%rbp), %rcx
movb %al, -0x29(%rbp)
jbe 0x30e351
movq -0x18(%rbp), %rax
movq -0x20(%rbp), %rcx
cmpq 0x8(%rcx), %rax
setb %al
movb %al, -0x29(%rbp)
movb -0x29(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x30e35c
jmp 0x30e394
movq -0x20(%rbp), %rax
movq -0x20(%rbp), %rcx
cmpq 0x8(%rcx), %rax
jb 0x30e384
movq -0x18(%rbp), %rax
cmpq -0x20(%rbp), %rax
ja 0x30e382
movq -0x18(%rbp), %rax
movq -0x20(%rbp), %rcx
cmpq 0x8(%rcx), %rax
jae 0x30e384
jmp 0x30e394
jmp 0x30e386
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x20(%rbp)
jmp 0x30e330
movq -0x18(%rbp), %rax
movq -0x18(%rbp), %rcx
movq (%rcx), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq -0x20(%rbp), %rcx
cmpq 0x8(%rcx), %rax
jne 0x30e3db
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq (%rax), %rcx
movq -0x18(%rbp), %rax
addq (%rax), %rcx
movq %rcx, (%rax)
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x8(%rax), %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x8(%rax)
jmp 0x30e425
movq -0x18(%rbp), %rax
movq -0x18(%rbp), %rcx
movq (%rcx), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq -0x20(%rbp), %rcx
cmpq 0x8(%rcx), %rax
jbe 0x30e413
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
cmpq -0x18(%rbp), %rax
jb 0x30e413
leaq 0x87bb4(%rip), %rdi     # 0x395fc0
callq 0x30e4c0
jmp 0x30e423
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x8(%rax)
jmp 0x30e425
movq -0x20(%rbp), %rax
movq -0x20(%rbp), %rcx
movq (%rcx), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
cmpq -0x18(%rbp), %rax
jne 0x30e46c
movq -0x18(%rbp), %rax
movq (%rax), %rcx
movq -0x20(%rbp), %rax
addq (%rax), %rcx
movq %rcx, (%rax)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x20(%rbp), %rcx
movq -0x28(%rbp), %rax
movq %rcx, 0x20(%rax)
jmp 0x30e4b6
movq -0x20(%rbp), %rax
movq -0x20(%rbp), %rcx
movq (%rcx), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
cmpq -0x18(%rbp), %rax
jbe 0x30e49c
movq -0x18(%rbp), %rax
cmpq -0x20(%rbp), %rax
jb 0x30e49c
leaq 0x87b67(%rip), %rdi     # 0x395ffc
callq 0x30e4c0
jmp 0x30e4b4
movq -0x18(%rbp), %rcx
movq -0x28(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x18(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x8(%rax)
jmp 0x30e4b6
addq $0x30, %rsp
popq %rbp
retq
nopl (%rax)