Skip to content

Commit de2845b

Browse files
authored
fix: Handle blocks larger than MAXSIZE in TLSF (AssemblyScript#1763)
1 parent 07b9fb6 commit de2845b

File tree

145 files changed

+14671
-18781
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+14671
-18781
lines changed

std/assembly/rt/tlsf.ts

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -207,36 +207,30 @@ function insertBlock(root: Root, block: Block): void {
207207

208208
// merge with right block if also free
209209
if (rightInfo & FREE) {
210-
let newSize = (blockInfo & ~TAGS_MASK) + BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK);
211-
if (newSize < BLOCK_MAXSIZE) {
212-
removeBlock(root, right);
213-
block.mmInfo = blockInfo = (blockInfo & TAGS_MASK) | newSize;
214-
right = GETRIGHT(block);
215-
rightInfo = right.mmInfo;
216-
// 'back' is set below
217-
}
210+
removeBlock(root, right);
211+
block.mmInfo = blockInfo = blockInfo + BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK); // keep block tags
212+
right = GETRIGHT(block);
213+
rightInfo = right.mmInfo;
214+
// 'back' is set below
218215
}
219216

220217
// merge with left block if also free
221218
if (blockInfo & LEFTFREE) {
222219
let left = GETFREELEFT(block);
223220
let leftInfo = left.mmInfo;
224221
if (DEBUG) assert(leftInfo & FREE); // must be free according to right tags
225-
let newSize = (leftInfo & ~TAGS_MASK) + BLOCK_OVERHEAD + (blockInfo & ~TAGS_MASK);
226-
if (newSize < BLOCK_MAXSIZE) {
227-
removeBlock(root, left);
228-
left.mmInfo = blockInfo = (leftInfo & TAGS_MASK) | newSize;
229-
block = left;
230-
// 'back' is set below
231-
}
222+
removeBlock(root, left);
223+
block = left;
224+
block.mmInfo = blockInfo = leftInfo + BLOCK_OVERHEAD + (blockInfo & ~TAGS_MASK); // keep left tags
225+
// 'back' is set below
232226
}
233227

234228
right.mmInfo = rightInfo | LEFTFREE;
235229
// reference to right is no longer used now, hence rightInfo is not synced
236230

237231
// we now know the size of the block
238232
var size = blockInfo & ~TAGS_MASK;
239-
if (DEBUG) assert(size >= BLOCK_MINSIZE && size < BLOCK_MAXSIZE); // must be a valid size
233+
if (DEBUG) assert(size >= BLOCK_MINSIZE); // must be a valid size
240234
if (DEBUG) assert(changetype<usize>(block) + BLOCK_OVERHEAD + size == changetype<usize>(right)); // must match
241235

242236
// set 'back' to itself at the end of block
@@ -249,8 +243,9 @@ function insertBlock(root: Root, block: Block): void {
249243
sl = <u32>(size >> AL_BITS);
250244
} else {
251245
const inv: usize = sizeof<usize>() * 8 - 1;
252-
fl = inv - clz<usize>(size);
253-
sl = <u32>((size >> (fl - SL_BITS)) ^ (1 << SL_BITS));
246+
let boundedSize = min(size, BLOCK_MAXSIZE);
247+
fl = inv - clz<usize>(boundedSize);
248+
sl = <u32>((boundedSize >> (fl - SL_BITS)) ^ (1 << SL_BITS));
254249
fl -= SB_BITS - 1;
255250
}
256251
if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range
@@ -272,7 +267,7 @@ function removeBlock(root: Root, block: Block): void {
272267
var blockInfo = block.mmInfo;
273268
if (DEBUG) assert(blockInfo & FREE); // must be free
274269
var size = blockInfo & ~TAGS_MASK;
275-
if (DEBUG) assert(size >= BLOCK_MINSIZE && size < BLOCK_MAXSIZE); // must be valid
270+
if (DEBUG) assert(size >= BLOCK_MINSIZE); // must be valid
276271

277272
// mapping_insert
278273
var fl: usize, sl: u32;
@@ -281,8 +276,9 @@ function removeBlock(root: Root, block: Block): void {
281276
sl = <u32>(size >> AL_BITS);
282277
} else {
283278
const inv: usize = sizeof<usize>() * 8 - 1;
284-
fl = inv - clz<usize>(size);
285-
sl = <u32>((size >> (fl - SL_BITS)) ^ (1 << SL_BITS));
279+
let boundedSize = min(size, BLOCK_MAXSIZE);
280+
fl = inv - clz<usize>(boundedSize);
281+
sl = <u32>((boundedSize >> (fl - SL_BITS)) ^ (1 << SL_BITS));
286282
fl -= SB_BITS - 1;
287283
}
288284
if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range
@@ -528,8 +524,6 @@ export function reallocateBlock(root: Root, block: Block, size: usize): Block {
528524
let mergeSize = blockSize + BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK);
529525
if (mergeSize >= payloadSize) {
530526
removeBlock(root, right);
531-
// TODO: this can yield an intermediate block larger than BLOCK_MAXSIZE, which
532-
// is immediately split though. does this trigger any assertions / issues?
533527
block.mmInfo = (blockInfo & TAGS_MASK) | mergeSize;
534528
prepareBlock(root, block, payloadSize);
535529
if (isDefined(ASC_RTRACE)) onresize(block, BLOCK_OVERHEAD + blockSize);

0 commit comments

Comments
 (0)