summaryrefslogtreecommitdiff
path: root/vere/pkg/noun/v1/allocate.c
blob: 191e818de40e163108d28b07ad68c953f4b8425c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/// @file

#include "../allocate.h"
#include "v1/allocate.h"

#include "v1/hashtable.h"

/* _box_v1_slot(): select the right free list to search for a block.
*/
static c3_w
_box_v1_slot(c3_w siz_w)
{
  if ( siz_w < u3a_v1_minimum ) {
    return 0;
  }
  else {
    c3_w i_w = 1;

    while ( 1 ) {
      if ( i_w == u3a_v1_fbox_no ) {
        return (i_w - 1);
      }
      if ( siz_w < 16 ) {
        return i_w;
      }
      siz_w = (siz_w + 1) >> 1;
      i_w += 1;
    }
  }
}

/* _box_v1_make(): construct a box.
*/
static u3a_v1_box*
_box_v1_make(void* box_v, c3_w siz_w, c3_w use_w)
{
  u3a_v1_box* box_u = box_v;
  c3_w*    box_w = box_v;

  u3_assert(siz_w >= u3a_v1_minimum);

  box_w[0] = siz_w;
  box_w[siz_w - 1] = siz_w;
  box_u->use_w = use_w;

# ifdef  U3_MEMORY_DEBUG
    box_u->cod_w = u3_Code;
    box_u->eus_w = 0;
# endif

  return box_u;
}

/* _box_v1_attach(): attach a box to the free list.
*/
static void
_box_v1_attach(u3a_v1_box* box_u)
{
  u3_assert(box_u->siz_w >= (1 + c3_wiseof(u3a_v1_fbox)));
  u3_assert(0 != u3of(u3a_v1_fbox, box_u));

  {
    c3_w           sel_w = _box_v1_slot(box_u->siz_w);
    u3p(u3a_v1_fbox)  fre_p = u3of(u3a_v1_fbox, box_u);
    u3p(u3a_v1_fbox)* pfr_p = &u3R_v1->all.fre_p[sel_w];
    u3p(u3a_v1_fbox)  nex_p = *pfr_p;

    u3to(u3a_v1_fbox, fre_p)->pre_p = 0;
    u3to(u3a_v1_fbox, fre_p)->nex_p = nex_p;
    if ( u3to(u3a_v1_fbox, fre_p)->nex_p ) {
      u3to(u3a_v1_fbox, u3to(u3a_v1_fbox, fre_p)->nex_p)->pre_p = fre_p;
    }
    (*pfr_p) = fre_p;
  }
}

/* _box_v1_detach(): detach a box from the free list.
*/
static void
_box_v1_detach(u3a_v1_box* box_u)
{
  u3p(u3a_v1_fbox) fre_p = u3of(u3a_v1_fbox, box_u);
  u3p(u3a_v1_fbox) pre_p = u3to(u3a_v1_fbox, fre_p)->pre_p;
  u3p(u3a_v1_fbox) nex_p = u3to(u3a_v1_fbox, fre_p)->nex_p;


  if ( nex_p ) {
    if ( u3to(u3a_v1_fbox, nex_p)->pre_p != fre_p ) {
      u3_assert(!"loom: corrupt");
    }
    u3to(u3a_v1_fbox, nex_p)->pre_p = pre_p;
  }
  if ( pre_p ) {
    if( u3to(u3a_v1_fbox, pre_p)->nex_p != fre_p ) {
      u3_assert(!"loom: corrupt");
    }
    u3to(u3a_v1_fbox, pre_p)->nex_p = nex_p;
  }
  else {
    c3_w sel_w = _box_v1_slot(box_u->siz_w);

    if ( fre_p != u3R_v1->all.fre_p[sel_w] ) {
      u3_assert(!"loom: corrupt");
    }
    u3R_v1->all.fre_p[sel_w] = nex_p;
  }
}

/* _box_v1_free(): free and coalesce.
*/
static void
_box_v1_free(u3a_v1_box* box_u)
{
  c3_w* box_w = (c3_w *)(void *)box_u;

  u3_assert(box_u->use_w != 0);
  box_u->use_w -= 1;
  if ( 0 != box_u->use_w ) {
    return;
  }

  //  we're always migrating a north road, so no need to check for it
  {
    /* Try to coalesce with the block below.
    */
    if ( box_w != u3a_v1_into(u3R_v1->rut_p) ) {
      c3_w       laz_w = *(box_w - 1);
      u3a_v1_box* pox_u = (u3a_v1_box*)(void *)(box_w - laz_w);

      if ( 0 == pox_u->use_w ) {
        _box_v1_detach(pox_u);
        _box_v1_make(pox_u, (laz_w + box_u->siz_w), 0);

        box_u = pox_u;
        box_w = (c3_w*)(void *)pox_u;
      }
    }

    /* Try to coalesce with the block above, or the wilderness.
    */
    if ( (box_w + box_u->siz_w) == u3a_v1_into(u3R_v1->hat_p) ) {
      u3R_v1->hat_p = u3a_v1_outa(box_w);
    }
    else {
      u3a_v1_box* nox_u = (u3a_v1_box*)(void *)(box_w + box_u->siz_w);

      if ( 0 == nox_u->use_w ) {
        _box_v1_detach(nox_u);
        _box_v1_make(box_u, (box_u->siz_w + nox_u->siz_w), 0);
      }
      _box_v1_attach(box_u);
    }
  }
}

/* u3a_v1_wfree(): free storage.
*/
void
u3a_v1_wfree(void* tox_v)
{
  _box_v1_free(u3a_v1_botox(tox_v));
}

/* u3a_v1_free(): free for aligned malloc.
*/
void
u3a_v1_free(void* tox_v)
{
  if (NULL == tox_v)
    return;

  c3_w* tox_w = tox_v;
  c3_w  pad_w = tox_w[-1];
  c3_w* org_w = tox_w - (pad_w + 1);

  // u3l_log("free %p %p", org_w, tox_w);
  u3a_v1_wfree(org_w);
}

/* u3a_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory.
*/
void
u3a_v1_reclaim(void)
{
  //  clear the memoization cache
  //
  u3h_v1_free_nodes(u3R_v1->cax.har_p);
}

/* _me_v1_lose_north(): lose on a north road.
*/
static void
_me_v1_lose_north(u3_noun dog)
{
top:
  {
    c3_w* dog_w      = u3a_v1_to_ptr(dog);
    u3a_v1_box* box_u = u3a_v1_botox(dog_w);

    if ( box_u->use_w > 1 ) {
      box_u->use_w -= 1;
    }
    else {
      if ( 0 == box_u->use_w ) {
        u3m_v1_bail(c3__foul);
      }
      else {
        if ( _(u3a_v1_is_pom(dog)) ) {
          u3a_v1_cell* dog_u = (void *)dog_w;
          u3_noun     h_dog = dog_u->hed;
          u3_noun     t_dog = dog_u->tel;

          if ( !_(u3a_v1_is_cat(h_dog)) ) {
            _me_v1_lose_north(h_dog);
          }
          u3a_v1_wfree(dog_w);
          if ( !_(u3a_v1_is_cat(t_dog)) ) {
            dog = t_dog;
            goto top;
          }
        }
        else {
          u3a_v1_wfree(dog_w);
        }
      }
    }
  }
}

/* u3a_v1_lose(): lose a reference count.
*/
void
u3a_v1_lose(u3_noun som)
{
  if ( !_(u3a_v1_is_cat(som)) ) {
    _me_v1_lose_north(som);
  }
}