mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-29 17:02:16 +00:00
TLSF: Cache repeated load/stores in locals (registers)
This commit is contained in:
parent
4ce8c7a6b0
commit
6fb7a0c59f
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
const AL_BITS: u32 = sizeof<usize>() == sizeof<u32>() ? 2 : 3;
|
const AL_BITS: u32 = sizeof<usize>() == sizeof<u32>() ? 2 : 3;
|
||||||
const AL_SIZE: usize = 1 << <usize>AL_BITS;
|
const AL_SIZE: usize = 1 << <usize>AL_BITS;
|
||||||
const AL_MASK: usize = (1 << <usize>AL_BITS) - 1;
|
const AL_MASK: usize = AL_SIZE - 1;
|
||||||
|
|
||||||
const SL_BITS: u32 = 5;
|
const SL_BITS: u32 = 5;
|
||||||
const SL_SIZE: usize = 1 << <usize>SL_BITS;
|
const SL_SIZE: usize = 1 << <usize>SL_BITS;
|
||||||
@ -72,7 +72,7 @@ class Block {
|
|||||||
|
|
||||||
/** Gets this block's left (free) block in memory. */
|
/** Gets this block's left (free) block in memory. */
|
||||||
get left(): Block {
|
get left(): Block {
|
||||||
assert(this.info & LEFT_FREE); // must be free to host a jump
|
assert(this.info & LEFT_FREE); // must be free to contain a jump
|
||||||
return assert(
|
return assert(
|
||||||
load<Block>(changetype<usize>(this) - sizeof<usize>())
|
load<Block>(changetype<usize>(this) - sizeof<usize>())
|
||||||
); // can't be null
|
); // can't be null
|
||||||
@ -80,7 +80,7 @@ class Block {
|
|||||||
|
|
||||||
/** Gets this block's right block in memory. */
|
/** Gets this block's right block in memory. */
|
||||||
get right(): Block {
|
get right(): Block {
|
||||||
assert(this.info & ~TAGS); // can't skip over the tail block
|
assert(this.info & ~TAGS); // can't skip beyond the tail block
|
||||||
return assert(
|
return assert(
|
||||||
changetype<Block>(
|
changetype<Block>(
|
||||||
changetype<usize>(this) + Block.INFO + (this.info & ~TAGS)
|
changetype<usize>(this) + Block.INFO + (this.info & ~TAGS)
|
||||||
@ -173,36 +173,42 @@ class Root {
|
|||||||
insert(block: Block): void {
|
insert(block: Block): void {
|
||||||
// check as much as possible here to prevent invalid free blocks
|
// check as much as possible here to prevent invalid free blocks
|
||||||
assert(block); // cannot be null
|
assert(block); // cannot be null
|
||||||
assert(block.info & FREE); // must be free
|
var blockInfo = block.info;
|
||||||
|
assert(blockInfo & FREE); // must be free
|
||||||
var size: usize;
|
var size: usize;
|
||||||
assert(
|
assert(
|
||||||
(size = block.info & ~TAGS) >= Block.MIN_SIZE && size < Block.MAX_SIZE
|
(size = block.info & ~TAGS) >= Block.MIN_SIZE && size < Block.MAX_SIZE
|
||||||
); // must be valid, not necessary to compute yet if noAssert=true
|
); // must be valid, not necessary to compute yet if noAssert=true
|
||||||
|
|
||||||
var right: Block = assert(block.right); // can't be null
|
var right: Block = assert(block.right); // can't be null
|
||||||
|
var rightInfo = right.info;
|
||||||
|
|
||||||
// merge with right block if also free
|
// merge with right block if also free
|
||||||
if (right.info & FREE) {
|
if (rightInfo & FREE) {
|
||||||
this.remove(right);
|
this.remove(right);
|
||||||
block.info += Block.INFO + (right.info & ~TAGS);
|
block.info = (blockInfo += Block.INFO + (rightInfo & ~TAGS));
|
||||||
right = block.right;
|
right = block.right;
|
||||||
|
rightInfo = right.info;
|
||||||
// jump is set below
|
// jump is set below
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge with left block if also free
|
// merge with left block if also free
|
||||||
if (block.info & LEFT_FREE) {
|
if (blockInfo & LEFT_FREE) {
|
||||||
var left: Block = assert(block.left); // can't be null
|
var left: Block = assert(block.left); // can't be null
|
||||||
assert(left.info & FREE); // must be free according to tags
|
var leftInfo = left.info;
|
||||||
|
assert(leftInfo & FREE); // must be free according to tags
|
||||||
this.remove(left);
|
this.remove(left);
|
||||||
left.info += Block.INFO + (block.info & ~TAGS);
|
left.info = (leftInfo += Block.INFO + (blockInfo & ~TAGS));
|
||||||
block = left;
|
block = left;
|
||||||
|
blockInfo = leftInfo;
|
||||||
// jump is set below
|
// jump is set below
|
||||||
}
|
}
|
||||||
|
|
||||||
right.info |= LEFT_FREE;
|
right.info = rightInfo | LEFT_FREE;
|
||||||
this.setJump(block, right);
|
this.setJump(block, right);
|
||||||
|
// right is no longer used now, hence rightInfo is not synced
|
||||||
|
|
||||||
size = block.info & ~TAGS;
|
size = blockInfo & ~TAGS;
|
||||||
assert(size >= Block.MIN_SIZE && size < Block.MAX_SIZE); // must be valid
|
assert(size >= Block.MIN_SIZE && size < Block.MAX_SIZE); // must be valid
|
||||||
|
|
||||||
// mapping_insert
|
// mapping_insert
|
||||||
@ -234,8 +240,9 @@ class Root {
|
|||||||
* again.
|
* again.
|
||||||
*/
|
*/
|
||||||
private remove(block: Block): void {
|
private remove(block: Block): void {
|
||||||
assert(block.info & FREE); // must be free
|
var blockInfo = block.info;
|
||||||
var size = block.info & ~TAGS;
|
assert(blockInfo & FREE); // must be free
|
||||||
|
var size = blockInfo & ~TAGS;
|
||||||
assert(size >= Block.MIN_SIZE && size < Block.MAX_SIZE); // must be valid
|
assert(size >= Block.MIN_SIZE && size < Block.MAX_SIZE); // must be valid
|
||||||
|
|
||||||
// mapping_insert
|
// mapping_insert
|
||||||
@ -326,17 +333,17 @@ class Root {
|
|||||||
* splitting it if possible, and returns its data pointer.
|
* splitting it if possible, and returns its data pointer.
|
||||||
*/
|
*/
|
||||||
use(block: Block, size: usize): usize {
|
use(block: Block, size: usize): usize {
|
||||||
assert(block.info & FREE); // must be free so we can use it
|
var blockInfo = block.info;
|
||||||
|
assert(blockInfo & FREE); // must be free so we can use it
|
||||||
assert(size >= Block.MIN_SIZE && size < Block.MAX_SIZE); // must be valid
|
assert(size >= Block.MIN_SIZE && size < Block.MAX_SIZE); // must be valid
|
||||||
assert(!(size & AL_MASK)); // size must be aligned so the new block is
|
assert(!(size & AL_MASK)); // size must be aligned so the new block is
|
||||||
|
|
||||||
this.remove(block);
|
this.remove(block);
|
||||||
block.info &= ~FREE;
|
|
||||||
|
|
||||||
// split if the block can hold another MIN_SIZE block
|
// split if the block can hold another MIN_SIZE block
|
||||||
var remaining = (block.info & ~TAGS) - size;
|
var remaining = (blockInfo & ~TAGS) - size;
|
||||||
if (remaining >= Block.INFO + Block.MIN_SIZE) {
|
if (remaining >= Block.INFO + Block.MIN_SIZE) {
|
||||||
block.info = size | (block.info & TAGS);
|
block.info = size | (blockInfo & LEFT_FREE); // also discards FREE
|
||||||
|
|
||||||
var spare = changetype<Block>(
|
var spare = changetype<Block>(
|
||||||
changetype<usize>(block) + Block.INFO + size
|
changetype<usize>(block) + Block.INFO + size
|
||||||
@ -344,8 +351,9 @@ class Root {
|
|||||||
spare.info = (remaining - Block.INFO) | FREE; // not LEFT_FREE
|
spare.info = (remaining - Block.INFO) | FREE; // not LEFT_FREE
|
||||||
this.insert(spare); // also sets jump
|
this.insert(spare); // also sets jump
|
||||||
|
|
||||||
// otherwise just tag right block as no longer LEFT_FREE
|
// otherwise tag block as no longer FREE and right as no longer LEFT_FREE
|
||||||
} else {
|
} else {
|
||||||
|
block.info = blockInfo & ~FREE;
|
||||||
var right: Block = assert(block.right); // can't be null (tail)
|
var right: Block = assert(block.right); // can't be null (tail)
|
||||||
right.info &= ~LEFT_FREE;
|
right.info &= ~LEFT_FREE;
|
||||||
}
|
}
|
||||||
@ -449,8 +457,9 @@ export function free_memory(data: usize): void {
|
|||||||
var root = ROOT;
|
var root = ROOT;
|
||||||
if (root && data) {
|
if (root && data) {
|
||||||
var block = changetype<Block>(data - Block.INFO);
|
var block = changetype<Block>(data - Block.INFO);
|
||||||
assert(!(block.info & FREE)); // must be used
|
var blockInfo = block.info;
|
||||||
block.info |= FREE;
|
assert(!(blockInfo & FREE)); // must be used
|
||||||
|
block.info = blockInfo | FREE;
|
||||||
root.insert(changetype<Block>(data - Block.INFO));
|
root.insert(changetype<Block>(data - Block.INFO));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user