// File: UTSASRG[P]Guarder/./bibopheap.hh
// Function: BibopHeap::freeSmallObject(void*)
void freeSmallObject(void * addr) {
		void * objectStartAddr;
		PerThreadBag * bag;
		#ifdef USE_CANARY
		PerThreadBag * ownerBag;
		shadowObjectInfo * shadowinfo = getShadowObjectInfo(addr, &bag, &objectStartAddr, &ownerBag);
		#else
		shadowObjectInfo * shadowinfo = getShadowObjectInfo(addr, &bag, &objectStartAddr);
		#endif

		BibopFreeCache * freeCache = bag->freeCache;

		PRDBG("\tfree(%p): smAddr %p (value=%d), threadIndex=%d, bagNum=%d, classSize=%zu, objectStart=%p",
						addr, shadowinfo, *shadowinfo, bag->threadIndex, bag->bagNum, bag->classSize, objectStartAddr);

		if(isObjectFree(shadowinfo)) {
			PRERR("Double free or invalid free problem found on object %p (sm %p)", addr, shadowinfo);
      printCallStack();
      exit(EXIT_FAILURE);
		} 

		#ifdef DESTROY_ON_FREE
		#ifdef USE_CANARY
		size_t objectSizeNoCanary = bag->classSize - 1;
		#else
		size_t objectSizeNoCanary = bag->classSize;
		#endif
		#endif

		#ifdef USE_CANARY
		char * canary = (char *)objectStartAddr + bag->classSize - 1;
		if(*canary != CANARY_SENTINEL) {
				FATAL("canary value for object %p not intact; canary @ %p, value=0x%x",
								addr, canary, (unsigned)*canary);
		}
		#if (NUM_MORE_CANARIES_TO_CHECK > 0)
		for(int move = LEFT; move <= RIGHT; move++) {
				shadowObjectInfo * canaryShadow = shadowinfo;
				for(int pos = 0; pos < NUM_MORE_CANARIES_TO_CHECK; pos++) {
						if((canaryShadow = getNextCanaryNeighbor(canaryShadow, ownerBag, (direction)move))) {
								char * neighborAddr = (char *)getAddrFromShadowInfo(canaryShadow, ownerBag);
								char * canary = neighborAddr + bag->classSize - 1;
								// We will only inspect the canary of objects currently in-use; if the
								// object is free, then it has already been checked previously.
								PRDBG("checking canary value for object %p (neighbor of %p); classSize=%zu, canary @ %p",
												neighborAddr, objectStartAddr, bag->classSize, canary);
								if(!isObjectFree(canaryShadow) && (*canary != CANARY_SENTINEL)) {
										FATAL("canary value for object %p (neighbor of %p) not intact; canary @ %p, value=0x%x",
														neighborAddr, objectStartAddr, canary, (unsigned)*canary);
								}
						} else {
								// getNextCanaryNeighbor will only return null when we attempt to move
								// left or right from the first or last object in a bag.
								break;
						}
				}
		}
		#endif
		#endif
		#ifdef DESTROY_ON_FREE
		destroyObject(objectStartAddr, objectSizeNoCanary);
		#endif

		markObjectFree(shadowinfo);

		//#pragma message "madvise turned off"
		if(bag->classSize >= 16 * PAGESIZE) {
				madvise(objectStartAddr, bag->classSize, MADV_DONTNEED);
		}

		freeCache->add(objectStartAddr);
	}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x90, %rsp
movq %rdi, -0x28(%rbp)
movq %rsi, -0x30(%rbp)
movq -0x28(%rbp), %rdi
movq %rdi, -0x58(%rbp)
movq -0x30(%rbp), %rsi
leaq -0x40(%rbp), %rdx
leaq -0x38(%rbp), %rcx
xorl %eax, %eax
movl %eax, %r8d
callq 0x58d0
movq %rax, -0x48(%rbp)
movq -0x40(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x50(%rbp)
callq 0x52d0
movq %rax, -0x68(%rbp)
callq 0x5400
movq -0x68(%rbp), %rdi
movq %rax, %rcx
movq -0x30(%rbp), %r12
movq -0x48(%rbp), %r15
movq -0x48(%rbp), %rax
movsbl (%rax), %r14d
movq -0x40(%rbp), %rax
movl 0x18(%rax), %ebx
movq -0x40(%rbp), %rax
movl 0x14(%rax), %r11d
movq -0x40(%rbp), %rax
movq 0x20(%rax), %r10
movq -0x38(%rbp), %rax
movl $0x1000, %esi           # imm = 0x1000
leaq 0x58c2(%rip), %rdx      # 0xd3c6
leaq 0x4a57(%rip), %r8       # 0xc562
movl $0x416, %r9d            # imm = 0x416
movq %r12, (%rsp)
movq %r15, 0x8(%rsp)
movl %r14d, 0x10(%rsp)
movl %ebx, 0x18(%rsp)
movl %r11d, 0x20(%rsp)
movq %r10, 0x28(%rsp)
movq %rax, 0x30(%rsp)
movb $0x0, %al
callq 0x57e0
callq 0x52d0
movq %rax, -0x60(%rbp)
callq 0x52d0
movq %rax, %rdi
callq 0x51e0
movq -0x60(%rbp), %rsi
movq %rax, %rdx
movl $0x2, %edi
callq 0x5160
movq -0x58(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x58f0
testb $0x1, %al
jne 0x7b73
jmp 0x7bef
callq 0x52d0
movq %rax, -0x78(%rbp)
callq 0x5400
movq -0x78(%rbp), %rdi
movq %rax, %rcx
movq -0x30(%rbp), %r10
movq -0x48(%rbp), %rax
movl $0x1000, %esi           # imm = 0x1000
leaq 0x58a4(%rip), %rdx      # 0xd440
leaq 0x49bf(%rip), %r8       # 0xc562
movl $0x419, %r9d            # imm = 0x419
movq %r10, (%rsp)
movq %rax, 0x8(%rsp)
movb $0x0, %al
callq 0x57e0
callq 0x52d0
movq %rax, -0x70(%rbp)
callq 0x52d0
movq %rax, %rdi
callq 0x51e0
movq -0x70(%rbp), %rsi
movq %rax, %rdx
movl $0x2, %edi
callq 0x5160
callq 0x5920
movl $0x1, %edi
callq 0x55b0
movq -0x58(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x5050
movq -0x40(%rbp), %rax
cmpq $0x10000, 0x20(%rax)    # imm = 0x10000
jb 0x7c20
movq -0x38(%rbp), %rdi
movq -0x40(%rbp), %rax
movq 0x20(%rax), %rsi
movl $0x4, %edx
callq 0x55a0
movq -0x50(%rbp), %rdi
movq -0x38(%rbp), %rsi
callq 0x54d0
addq $0x90, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
popq %rbp
retq
nopl (%rax)