// File: /workspace/github_c_makefile_star2_O0/nh13[P]ksw/src/ksw2/kalloc.c
// Function: kfree
void kfree(void *_km, void *ap)
{
	size_t *p, *q;
	kmem_t *km = (kmem_t*)_km;
	
	if (!ap) return;
	if (km == 0) {
		free(ap);
		return;
	}
	p = (size_t*)ap - 1; /* *p is the size of the current block */
	/* 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 < PTR(q)); q = PTR(q))
		if (q >= PTR(q) && (p > q || p < PTR(q))) break;
	if (p + (*p) == PTR(q)) { /* two adjacent blocks, merge p and q->ptr (the 2nd and 4th cases) */
		*p += *PTR(q); /* this is the new q->ptr size */
		p[1] = (size_t)PTR(PTR(q)); /* this is the new q->ptr->ptr */
		/* p is actually the new q->ptr. The actual change happens a few lines below. */
	} else if (p + (*p) > PTR(q) && PTR(q) >= p) { /* the end of the allocated block is in the next free block */
		kerror("[kfree] The end of the allocated block enters a free block.");
	} else p[1] = (size_t)PTR(q); /* backup q->ptr */

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

// 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 0x19e414
jmp 0x19e5d6
cmpq $0x0, -0x28(%rbp)
jne 0x19e429
movq -0x10(%rbp), %rdi
callq 0x19e120
jmp 0x19e5d6
movq -0x10(%rbp), %rax
addq $-0x8, %rax
movq %rax, -0x18(%rbp)
movq -0x28(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rcx
xorl %eax, %eax
cmpq -0x20(%rbp), %rcx
movb %al, -0x29(%rbp)
jbe 0x19e465
movq -0x18(%rbp), %rax
movq -0x20(%rbp), %rcx
movq 0x8(%rcx), %rcx
cmpq %rcx, %rax
setb %al
movb %al, -0x29(%rbp)
movb -0x29(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x19e470
jmp 0x19e4ae
movq -0x20(%rbp), %rax
movq -0x20(%rbp), %rcx
movq 0x8(%rcx), %rcx
cmpq %rcx, %rax
jb 0x19e49e
movq -0x18(%rbp), %rax
cmpq -0x20(%rbp), %rax
ja 0x19e49c
movq -0x18(%rbp), %rax
movq -0x20(%rbp), %rcx
movq 0x8(%rcx), %rcx
cmpq %rcx, %rax
jae 0x19e49e
jmp 0x19e4ae
jmp 0x19e4a0
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x20(%rbp)
jmp 0x19e441
movq -0x18(%rbp), %rax
movq -0x18(%rbp), %rcx
movq (%rcx), %rcx
shlq $0x3, %rcx
addq %rcx, %rax
movq -0x20(%rbp), %rcx
movq 0x8(%rcx), %rcx
cmpq %rcx, %rax
jne 0x19e4f8
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 0x19e545
movq -0x18(%rbp), %rax
movq -0x18(%rbp), %rcx
movq (%rcx), %rcx
shlq $0x3, %rcx
addq %rcx, %rax
movq -0x20(%rbp), %rcx
movq 0x8(%rcx), %rcx
cmpq %rcx, %rax
jbe 0x19e533
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
cmpq -0x18(%rbp), %rax
jb 0x19e533
leaq 0xaeeaec(%rip), %rdi    # 0xc8d018
callq 0x19e5e0
jmp 0x19e543
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x8(%rax)
jmp 0x19e545
movq -0x20(%rbp), %rax
movq -0x20(%rbp), %rcx
movq (%rcx), %rcx
shlq $0x3, %rcx
addq %rcx, %rax
cmpq -0x18(%rbp), %rax
jne 0x19e58c
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, 0x10(%rax)
jmp 0x19e5d6
movq -0x20(%rbp), %rax
movq -0x20(%rbp), %rcx
movq (%rcx), %rcx
shlq $0x3, %rcx
addq %rcx, %rax
cmpq -0x18(%rbp), %rax
jbe 0x19e5bc
movq -0x18(%rbp), %rax
cmpq -0x20(%rbp), %rax
jb 0x19e5bc
leaq 0xaeea9f(%rip), %rdi    # 0xc8d054
callq 0x19e5e0
jmp 0x19e5d4
movq -0x18(%rbp), %rcx
movq -0x28(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x18(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x8(%rax)
jmp 0x19e5d6
addq $0x30, %rsp
popq %rbp
retq
nopl (%rax)