// File: /workspace/github_c_makefile_star2_O2/johsteffens[P]beth/lib/bcore/bcore_spect.c
// Function: hmap_s_down
static void hmap_s_down( hmap_s* o )
{
    bcore_mutex_s_lock( &o->mutex );

    /// clear and lock all caches because shut down procedure can change perspective addresses (this includes o->cache)
    for( uz_t i = 0; i < o->cache_arr.size; i++ )
    {
        bcore_tp_fastmap_s* cache = o->cache_arr.data[ i ];
        bcore_tp_fastmap_s_clear( cache );
        bcore_tp_fastmap_s_set_locked( cache, true );
    }

    // shut down in reverse order of creation
    while( o->arr.size > 0 )
    {
        vd_t spect = bcore_arr_vd_s_pop( &o->arr );
        tp_t p_type = ( ( bcore_spect_header_s* )spect )->p_type;
        tp_t o_type = ( ( bcore_spect_header_s* )spect )->o_type;
        tp_t sig    = bcore_tp_fold_tp( p_type, o_type );
        bcore_hmap_u3vd_s_remove_h( &o->map, sig );

        /** During discard we lift the lock because the spect's destructor
         *  may retrieve (even recreate) perspective instances.
         *
         *  This could re-add perspectives that have already been destroyed, giving those a different address.
         *  Nevertheless, this is safe at this point for the following reasons:
         *    1. Non-perspective objects, possibly referencing perspectives, have already been taken down.
         *    2. Perspective B can only reference perspective A when A was added before B to the registry.
         *       Shutting down in reverse order ensures that A is never destroyed before B.
         *    3. (follows from 2) Cyclic references are not possible.
         *    4. Caches are cleared and locked.
         *
         *  Temporarily re-added perspectives reside at the tail-end of o->arr
         *  and are taken down again in this loop without cyclic re-instantiation.
         *  (Halting is guaranteed.)
         */
        bcore_mutex_s_unlock( &o->mutex );
        if( p_type == TYPEOF_bcore_inst_s )
        {
            bcore_inst_s_discard( spect );
        }
        else
        {
            bcore_inst_a_discard( spect );
        }
        bcore_mutex_s_lock( &o->mutex );
    }

    /// shut down all caches (this includes o->cache)
    for( uz_t i = 0; i < o->cache_arr.size; i++ )
    {
        bcore_tp_fastmap_s* cache = o->cache_arr.data[ i ];
        bcore_tp_fastmap_s_down( cache );
    }
    bcore_arr_vd_s_down( &o->cache_arr );

    bcore_hmap_u3vd_s_down( &o->map );
    bcore_arr_vd_s_down(    &o->arr );
    bcore_mutex_s_unlock( &o->mutex );
    bcore_mutex_s_down( &o->mutex );
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %r14
leaq 0x60(%rdi), %rbx
movq %rbx, %rdi
callq 0x97ae2
xorl %r12d, %r12d
pushq $0x1
popq %rbp
cmpq 0x2b0(%r14), %r12
jae 0x7b04a
movq 0x2a8(%r14), %rax
movq (%rax,%r12,8), %r15
movq %r15, %rdi
callq 0x98c0b
movq %r15, %rdi
movl %ebp, %esi
callq 0x98d21
incq %r12
jmp 0x7b01f
leaq 0x20(%r14), %r15
movabsq $0x782b96602f424981, %rbp # imm = 0x782B96602F424981
cmpq $0x0, 0x10(%r14)
je 0x7b0aa
movq %r14, %rdi
callq 0x5ccaf
movq %rax, %r12
movq (%rax), %r13
movq 0x8(%rax), %rsi
movq %r13, %rdi
callq 0x79b3e
movq %r15, %rdi
movq %rax, %rsi
callq 0x67117
movq %rbx, %rdi
callq 0x97b12
movq %r12, %rdi
cmpq %rbp, %r13
jne 0x7b09b
callq 0x83381
jmp 0x7b0a0
callq 0x7a289
movq %rbx, %rdi
callq 0x97ae2
jmp 0x7b058
xorl %r12d, %r12d
cmpq 0x2b0(%r14), %r12
jae 0x7b0cb
movq 0x2a8(%r14), %rax
movq (%rax,%r12,8), %rdi
callq 0x98c6d
incq %r12
jmp 0x7b0ad
leaq 0x2a0(%r14), %rdi
callq 0x5c9fd
movq %r15, %rdi
callq 0x668f8
movq %r14, %rdi
callq 0x5c9fd
movq %rbx, %rdi
callq 0x97b12
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x979f9
nopl (%rax)