trv: mtortoise: Gave up on a reasonable type, abuse shrub fields
I think modern C simply doesn't let us do what we want to do here, so
I'm giving up, discarding the lfs3_mtortoise_t type, and just abusing
various unrelated shrub fields to implement the tortoise. This
sacrifices readability, but at least avoids undefined behavior without
a RAM penalty:
- shrub.blocks => tortoise blocks
- shrub.weight => cycle distance
- shrub.eoff => power-of-two bound
Note this keeps trunk=0, which is a nice safety net in case some code
ever tries to read from the shrub in the future.
Fortunately the mtortoise logic is fairly self-contained in
lfs3_mtree_traverse_, so with enough comments hopefully the code is not
too confusing.
---
Apparently shaves off a couple more bytes of code. I'm guessing this is
just because of the slightly different struct offsets (we're reusing the
root's rbyd instead of the leaf's rbyd now):
code stack ctx
before: 36852 2368 684
after: 36844 (-0.0%) 2368 (+0.0%) 684 (+0.0%)
This commit is contained in:
@@ -9783,13 +9783,6 @@ enum lfs3_tstate {
|
||||
LFS3_TSTATE_DONE = 8,
|
||||
};
|
||||
|
||||
// tortoise for cycle detection
|
||||
typedef struct lfs3_mtortoise {
|
||||
lfs3_block_t blocks[2];
|
||||
lfs3_block_t dist;
|
||||
uint8_t power;
|
||||
} lfs3_mtortoise_t;
|
||||
|
||||
static void lfs3_trv_init(lfs3_trv_t *trv, uint32_t flags) {
|
||||
trv->b.h.flags = lfs3_o_typeflags(LFS3_type_TRV)
|
||||
| lfs3_t_tstateflags(LFS3_TSTATE_MROOTANCHOR)
|
||||
@@ -9799,14 +9792,15 @@ static void lfs3_trv_init(lfs3_trv_t *trv, uint32_t flags) {
|
||||
trv->b.h.mdir.r.blocks[0] = -1;
|
||||
trv->b.h.mdir.r.blocks[1] = -1;
|
||||
lfs3_bshrub_init(&trv->b);
|
||||
// bit of a hack, but we reuse the shrub's leaf as a tortoise for
|
||||
// cycle detection to save memory, see lfs3_mtree_traverse_
|
||||
lfs3_mtortoise_t *mtortoise = (lfs3_mtortoise_t*)&trv->b.shrub.leaf.r;
|
||||
LFS3_ASSERT(sizeof(lfs3_mtortoise_t) <= sizeof(trv->b.shrub.leaf.r));
|
||||
mtortoise->blocks[0] = -1;
|
||||
mtortoise->blocks[1] = -1;
|
||||
mtortoise->dist = 0;
|
||||
mtortoise->power = 0;
|
||||
// reuse the shrub as a tortoise to save memory, see
|
||||
// lfs3_mtree_traverse_:
|
||||
// - shrub.blocks => tortoise blocks
|
||||
// - shrub.weight => cycle distance
|
||||
// - shrub.eoff => power-of-two bound
|
||||
trv->b.shrub.r.blocks[0] = -1;
|
||||
trv->b.shrub.r.blocks[1] = -1;
|
||||
trv->b.shrub.r.weight = 0;
|
||||
trv->b.shrub.r.eoff = 0;
|
||||
trv->h = NULL;
|
||||
trv->gcksum = 0;
|
||||
}
|
||||
@@ -9870,26 +9864,30 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv,
|
||||
// btree inner nodes require checksums of their pointers,
|
||||
// so creating a valid cycle is actually quite difficult
|
||||
//
|
||||
// a bit of a hack, but we reuse the shrub's leaf as a
|
||||
// tortoise to save memory
|
||||
lfs3_mtortoise_t *mtortoise
|
||||
= (lfs3_mtortoise_t*)&trv->b.shrub.leaf.r;
|
||||
// the big hack here is we repurpose our shrub as a tortoise
|
||||
// to save memory, unfortunately there's not an easy way to
|
||||
// union these in C:
|
||||
//
|
||||
// - shrub.blocks => tortoise blocks
|
||||
// - shrub.weight => cycle distance
|
||||
// - shrub.eoff => power-of-two bound
|
||||
//
|
||||
if (lfs3_mptr_cmp(
|
||||
trv->b.h.mdir.r.blocks,
|
||||
mtortoise->blocks) == 0) {
|
||||
trv->b.shrub.r.blocks) == 0) {
|
||||
LFS3_ERROR("Cycle detected during mtree traversal "
|
||||
"0x{%"PRIx32",%"PRIx32"}",
|
||||
trv->b.h.mdir.r.blocks[0],
|
||||
trv->b.h.mdir.r.blocks[1]);
|
||||
return LFS3_ERR_CORRUPT;
|
||||
}
|
||||
if (mtortoise->dist == (1U << mtortoise->power)) {
|
||||
mtortoise->blocks[0] = trv->b.h.mdir.r.blocks[0];
|
||||
mtortoise->blocks[1] = trv->b.h.mdir.r.blocks[1];
|
||||
mtortoise->dist = 0;
|
||||
mtortoise->power += 1;
|
||||
if (trv->b.shrub.r.weight == (1U << trv->b.shrub.r.eoff)) {
|
||||
trv->b.shrub.r.blocks[0] = trv->b.h.mdir.r.blocks[0];
|
||||
trv->b.shrub.r.blocks[1] = trv->b.h.mdir.r.blocks[1];
|
||||
trv->b.shrub.r.weight = 0;
|
||||
trv->b.shrub.r.eoff += 1;
|
||||
}
|
||||
mtortoise->dist += 1;
|
||||
trv->b.shrub.r.weight += 1;
|
||||
|
||||
bptr_->d.u.buffer = (const uint8_t*)&trv->b.h.mdir;
|
||||
return LFS3_TAG_MDIR;
|
||||
|
||||
Reference in New Issue
Block a user