This commit is contained in:
dcode 2019-04-17 06:12:02 +02:00
parent 0ba0d8ae7a
commit 504e207184
8 changed files with 852 additions and 759 deletions

View File

@ -1,12 +1,12 @@
(module
(type $FUNCSIG$ii (func (param i32) (result i32)))
(type $FUNCSIG$i (func (result i32)))
(type $FUNCSIG$vii (func (param i32 i32)))
(type $FUNCSIG$viii (func (param i32 i32 i32)))
(type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
(type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
(type $FUNCSIG$vii (func (param i32 i32)))
(type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
(type $FUNCSIG$vi (func (param i32)))
(type $FUNCSIG$viii (func (param i32 i32 i32)))
(type $FUNCSIG$v (func))
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
(memory $0 1)
@ -17,70 +17,7 @@
(export "memory.allocate" (func $assembly/index/memory.allocate))
(export "memory.free" (func $assembly/index/memory.free))
(export "memory.fill" (func $assembly/index/memory.fill))
(func $../../runtime/assembly/index/setTail (; 1 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
local.get $0
local.get $1
i32.store offset=1568
)
(func $../../runtime/assembly/index/setSLMap (; 2 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
local.get $0
local.get $1
i32.const 2
i32.shl
i32.add
local.get $2
i32.store offset=4
)
(func $../../runtime/assembly/index/setHead (; 3 ;) (type $FUNCSIG$viiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
local.get $0
local.get $1
i32.const 4
i32.shl
local.get $2
i32.add
i32.const 2
i32.shl
i32.add
local.get $3
i32.store offset=96
)
(func $../../runtime/assembly/index/getRight (; 4 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
local.get $0
i32.const 16
i32.add
local.get $0
i32.load
i32.const -4
i32.and
i32.add
)
(func $../../runtime/assembly/index/fls<usize> (; 5 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
i32.const 31
local.get $0
i32.clz
i32.sub
)
(func $../../runtime/assembly/index/getHead (; 6 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
local.get $0
local.get $1
i32.const 4
i32.shl
local.get $2
i32.add
i32.const 2
i32.shl
i32.add
i32.load offset=96
)
(func $../../runtime/assembly/index/getSLMap (; 7 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
local.get $0
local.get $1
i32.const 2
i32.shl
i32.add
i32.load offset=4
)
(func $../../runtime/assembly/index/removeBlock (; 8 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(func $../../runtime/assembly/index/removeBlock (; 1 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
@ -100,8 +37,10 @@
i32.const 0
else
local.get $2
i32.const 31
local.get $2
call $../../runtime/assembly/index/fls<usize>
i32.clz
i32.sub
local.tee $3
i32.const 4
i32.sub
@ -131,26 +70,44 @@
local.get $5
i32.store offset=16
end
local.get $1
local.get $0
local.get $3
i32.const 4
i32.shl
local.get $4
call $../../runtime/assembly/index/getHead
local.get $1
i32.add
i32.const 2
i32.shl
i32.add
i32.load offset=96
i32.eq
if
local.get $0
local.get $3
i32.const 4
i32.shl
local.get $4
i32.add
i32.const 2
i32.shl
i32.add
local.get $2
call $../../runtime/assembly/index/setHead
i32.store offset=96
local.get $2
i32.eqz
if
local.get $0
local.get $3
i32.const 2
i32.shl
i32.add
local.get $0
local.get $3
call $../../runtime/assembly/index/getSLMap
i32.const 2
i32.shl
i32.add
i32.load offset=4
i32.const 1
local.get $4
i32.shl
@ -158,7 +115,7 @@
i32.xor
i32.and
local.tee $1
call $../../runtime/assembly/index/setSLMap
i32.store offset=4
local.get $1
i32.eqz
if
@ -176,7 +133,7 @@
end
end
)
(func $../../runtime/assembly/index/insertBlock (; 9 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(func $../../runtime/assembly/index/insertBlock (; 2 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
@ -185,16 +142,22 @@
(local $7 i32)
local.get $1
i32.load
local.set $3
local.set $2
local.get $1
call $../../runtime/assembly/index/getRight
i32.const 16
i32.add
local.get $1
i32.load
i32.const -4
i32.and
i32.add
local.tee $4
i32.load
local.tee $5
i32.const 1
i32.and
if
local.get $3
local.get $2
i32.const -4
i32.and
i32.const 16
@ -203,7 +166,7 @@
i32.const -4
i32.and
i32.add
local.tee $2
local.tee $3
i32.const 1073741824
i32.lt_u
if
@ -211,21 +174,27 @@
local.get $4
call $../../runtime/assembly/index/removeBlock
local.get $1
local.get $3
local.get $2
i32.const 3
i32.and
local.get $2
local.get $3
i32.or
local.tee $3
local.tee $2
i32.store
local.get $1
call $../../runtime/assembly/index/getRight
i32.const 16
i32.add
local.get $1
i32.load
i32.const -4
i32.and
i32.add
local.tee $4
i32.load
local.set $5
end
end
local.get $3
local.get $2
i32.const 2
i32.and
if
@ -233,14 +202,14 @@
i32.const 4
i32.sub
i32.load
local.tee $2
local.tee $3
i32.load
local.tee $6
i32.const -4
i32.and
i32.const 16
i32.add
local.get $3
local.get $2
i32.const -4
i32.and
i32.add
@ -249,17 +218,17 @@
i32.lt_u
if
local.get $0
local.get $2
local.get $3
call $../../runtime/assembly/index/removeBlock
local.get $2
local.get $3
local.get $6
i32.const 3
i32.and
local.get $7
i32.or
local.tee $3
local.tee $2
i32.store
local.get $2
local.get $3
local.set $1
end
end
@ -273,8 +242,7 @@
i32.sub
local.get $1
i32.store
local.get $0
local.get $3
local.get $2
i32.const -4
i32.and
local.tee $2
@ -284,26 +252,36 @@
local.get $2
i32.const 16
i32.div_u
local.set $3
local.set $2
i32.const 0
else
local.get $2
i32.const 31
local.get $2
call $../../runtime/assembly/index/fls<usize>
local.tee $2
i32.clz
i32.sub
local.tee $3
i32.const 4
i32.sub
i32.shr_u
i32.const 16
i32.xor
local.set $3
local.get $2
local.set $2
local.get $3
i32.const 7
i32.sub
end
local.tee $2
local.set $3
local.get $0
local.get $3
call $../../runtime/assembly/index/getHead
i32.const 4
i32.shl
local.get $2
i32.add
i32.const 2
i32.shl
i32.add
i32.load offset=96
local.set $4
local.get $1
i32.const 0
@ -318,30 +296,42 @@
i32.store offset=16
end
local.get $0
local.get $2
local.get $3
i32.const 4
i32.shl
local.get $2
i32.add
i32.const 2
i32.shl
i32.add
local.get $1
call $../../runtime/assembly/index/setHead
i32.store offset=96
local.get $0
local.get $0
i32.load
i32.const 1
local.get $2
local.get $3
i32.shl
i32.or
i32.store
local.get $0
local.get $2
local.get $0
local.get $2
call $../../runtime/assembly/index/getSLMap
i32.const 1
local.get $3
i32.const 2
i32.shl
i32.add
local.get $0
local.get $3
i32.const 2
i32.shl
i32.add
i32.load offset=4
i32.const 1
local.get $2
i32.shl
i32.or
call $../../runtime/assembly/index/setSLMap
i32.store offset=4
)
(func $../../runtime/assembly/index/addMemory (; 10 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
(func $../../runtime/assembly/index/addMemory (; 3 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
(local $3 i32)
local.get $2
block (result i32)
@ -400,12 +390,12 @@
i32.store
local.get $0
local.get $2
call $../../runtime/assembly/index/setTail
i32.store offset=1568
local.get $0
local.get $1
call $../../runtime/assembly/index/insertBlock
)
(func $../../runtime/assembly/index/initialize (; 11 ;) (type $FUNCSIG$i) (result i32)
(func $../../runtime/assembly/index/initialize (; 4 ;) (type $FUNCSIG$i) (result i32)
(local $0 i32)
(local $1 i32)
(local $2 i32)
@ -441,7 +431,7 @@
i32.store
local.get $0
i32.const 0
call $../../runtime/assembly/index/setTail
i32.store offset=1568
loop $repeat|0
block $break|0
local.get $2
@ -450,8 +440,11 @@
br_if $break|0
local.get $0
local.get $2
i32.const 2
i32.shl
i32.add
i32.const 0
call $../../runtime/assembly/index/setSLMap
i32.store offset=4
i32.const 0
local.set $1
loop $repeat|1
@ -462,9 +455,15 @@
br_if $break|1
local.get $0
local.get $2
i32.const 4
i32.shl
local.get $1
i32.add
i32.const 2
i32.shl
i32.add
i32.const 0
call $../../runtime/assembly/index/setHead
i32.store offset=96
local.get $1
i32.const 1
i32.add
@ -491,7 +490,7 @@
call $../../runtime/assembly/index/addMemory
local.get $0
)
(func $../../runtime/assembly/index/searchBlock (; 12 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
(func $../../runtime/assembly/index/searchBlock (; 5 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32)
local.get $0
local.get $1
@ -504,26 +503,25 @@
local.set $1
i32.const 0
else
block (result i32)
local.get $1
i32.const 536870912
i32.lt_u
if
local.get $1
i32.const 1
local.get $1
call $../../runtime/assembly/index/fls<usize>
i32.const 4
i32.sub
i32.shl
i32.add
i32.const 1
i32.sub
local.set $1
end
local.get $1
end
call $../../runtime/assembly/index/fls<usize>
i32.const 31
local.get $1
i32.const 1
i32.const 27
local.get $1
i32.clz
i32.sub
i32.shl
i32.add
i32.const 1
i32.sub
local.get $1
local.get $1
i32.const 536870912
i32.lt_u
select
local.tee $1
i32.clz
i32.sub
local.set $2
local.get $1
local.get $2
@ -538,7 +536,10 @@
i32.sub
end
local.tee $2
call $../../runtime/assembly/index/getSLMap
i32.const 2
i32.shl
i32.add
i32.load offset=4
i32.const -1
local.get $1
i32.shl
@ -546,10 +547,16 @@
local.tee $1
if (result i32)
local.get $0
local.get $2
local.get $1
i32.ctz
call $../../runtime/assembly/index/getHead
local.get $2
i32.const 4
i32.shl
i32.add
i32.const 2
i32.shl
i32.add
i32.load offset=96
else
local.get $0
i32.load
@ -561,21 +568,30 @@
i32.and
local.tee $1
if (result i32)
local.get $0
local.get $0
local.get $1
i32.ctz
local.tee $1
local.get $0
local.get $1
call $../../runtime/assembly/index/getSLMap
i32.const 2
i32.shl
i32.add
i32.load offset=4
i32.ctz
call $../../runtime/assembly/index/getHead
local.get $1
i32.const 4
i32.shl
i32.add
i32.const 2
i32.shl
i32.add
i32.load offset=96
else
i32.const 0
end
end
)
(func $../../runtime/assembly/index/growMemory (; 13 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(func $../../runtime/assembly/index/growMemory (; 6 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
@ -616,7 +632,7 @@
i32.shl
call $../../runtime/assembly/index/addMemory
)
(func $../../runtime/assembly/index/prepareBlock (; 14 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(func $../../runtime/assembly/index/prepareBlock (; 7 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32)
(local $4 i32)
local.get $1
@ -663,9 +679,21 @@
i32.and
i32.store
local.get $1
call $../../runtime/assembly/index/getRight
i32.const 16
i32.add
local.get $1
call $../../runtime/assembly/index/getRight
i32.load
i32.const -4
i32.and
i32.add
local.get $1
i32.const 16
i32.add
local.get $1
i32.load
i32.const -4
i32.and
i32.add
i32.load
i32.const -3
i32.and
@ -675,7 +703,7 @@
i32.const 16
i32.add
)
(func $../../runtime/assembly/index/__mm_allocate (; 15 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
(func $../../runtime/assembly/index/__mm_allocate (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
(local $1 i32)
(local $2 i32)
global.get $../../runtime/assembly/index/ROOT
@ -692,7 +720,7 @@
if
i32.const 0
i32.const 24
i32.const 498
i32.const 495
i32.const 29
call $~lib/builtins/abort
unreachable
@ -737,11 +765,11 @@
local.get $1
call $../../runtime/assembly/index/prepareBlock
)
(func $assembly/index/memory.allocate (; 16 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
(func $assembly/index/memory.allocate (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
local.get $0
call $../../runtime/assembly/index/__mm_allocate
)
(func $../../runtime/assembly/index/__mm_free (; 17 ;) (type $FUNCSIG$vi) (param $0 i32)
(func $../../runtime/assembly/index/__mm_free (; 10 ;) (type $FUNCSIG$vi) (param $0 i32)
(local $1 i32)
local.get $0
if
@ -763,11 +791,11 @@
end
end
)
(func $assembly/index/memory.free (; 18 ;) (type $FUNCSIG$vi) (param $0 i32)
(func $assembly/index/memory.free (; 11 ;) (type $FUNCSIG$vi) (param $0 i32)
local.get $0
call $../../runtime/assembly/index/__mm_free
)
(func $~lib/memory/memory.fill (; 19 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
(func $~lib/memory/memory.fill (; 12 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
(local $3 i64)
(local $4 i32)
block $~lib/util/memory/memset|inlined.0
@ -997,13 +1025,13 @@
end
end
)
(func $assembly/index/memory.fill (; 20 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
(func $assembly/index/memory.fill (; 13 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
local.get $0
local.get $1
local.get $2
call $~lib/memory/memory.fill
)
(func $null (; 21 ;) (type $FUNCSIG$v)
(func $null (; 14 ;) (type $FUNCSIG$v)
nop
)
)

File diff suppressed because it is too large Load Diff

1
tests/runtime/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
!optimized.wasm

View File

@ -15,22 +15,8 @@
/////////////////////// The TLSF (Two-Level Segregate Fit) memory allocator ///////////////////////
// see: http://www.gii.upv.es/tlsf/
/** Determines the first (LSB to MSB) set bit's index of a word. */
// @ts-ignore: decorator
@inline
function ffs<T extends number>(word: T): T {
return ctz<T>(word); // for word != 0
}
/** Determines the last (LSB to MSB) set bit's index of a word. */
// @ts-ignore: decorator
@inline
function fls<T extends number>(word: T): T {
// @ts-ignore: type
const inv: T = sizeof<T>() * 8 - 1;
// @ts-ignore: type
return inv - clz<T>(word);
}
// - `ffs(x)` is equivalent to `ctz(x)` with x != 0
// - `fls(x)` is equivalent to `sizeof(x) * 8 - clz(x) - 1`
// ╒══════════════ Block size interpretation (32-bit) ═════════════╕
// 3 2 1
@ -126,15 +112,13 @@ function fls<T extends number>(word: T): T {
/** Gets the left block of a block. Only valid if the left block is free. */
// @ts-ignore: decorator
@inline
function getLeft(block: Block): Block {
@inline function GETLEFT(block: Block): Block {
return load<Block>(changetype<usize>(block) - sizeof<usize>());
}
/** Gets the right block of of a block by advancing to the right by its size. */
// @ts-ignore: decorator
@inline
function getRight(block: Block): Block {
@inline function GETRIGHT(block: Block): Block {
return changetype<Block>(changetype<usize>(block) + BLOCK_OVERHEAD + (block.mmInfo & ~TAGS_MASK));
}
@ -179,21 +163,21 @@ function getRight(block: Block): Block {
var ROOT: Root;
/** Gets the second level map of the specified first level. */
// @ts-ignore: decorator
@inline
function getSLMap(root: Root, fl: usize): u32 {
@inline function GETSL(root: Root, fl: usize): u32 {
return load<u32>(changetype<usize>(root) + (fl << alignof<u32>()), SL_START);
}
/** Sets the second level map of the specified first level. */
// @ts-ignore: decorator
@inline
function setSLMap(root: Root, fl: usize, value: u32): void {
@inline function SETSL(root: Root, fl: usize, value: u32): void {
store<u32>(changetype<usize>(root) + (fl << alignof<u32>()), value, SL_START);
}
/** Gets the head of the free list for the specified combination of first and second level. */
// @ts-ignore: decorator
@inline
function getHead(root: Root, fl: usize, sl: u32): Block | null {
@inline function GETHEAD(root: Root, fl: usize, sl: u32): Block | null {
return changetype<Block>(
load<usize>(
changetype<usize>(root) + (fl * SL_SIZE + <usize>sl) * sizeof<usize>(),
@ -201,23 +185,23 @@ function getHead(root: Root, fl: usize, sl: u32): Block | null {
);
}
/** Sets the head of the free list for the specified combination of first and second level. */
// @ts-ignore: decorator
@inline
function setHead(root: Root, fl: usize, sl: u32, value: Block | null): void {
@inline function SETHEAD(root: Root, fl: usize, sl: u32, head: Block | null): void {
store<usize>(
changetype<usize>(root) + (fl * SL_SIZE + <usize>sl) * sizeof<usize>() , changetype<usize>(value),
changetype<usize>(root) + (fl * SL_SIZE + <usize>sl) * sizeof<usize>() , changetype<usize>(head),
HL_START);
}
/** Gets the tail block.. */
// @ts-ignore: decorator
@inline
function getTail(root: Root): Block {
@inline function GETTAIL(root: Root): Block {
return load<Block>(changetype<usize>(root), HL_END);
}
/** Sets the tail block. */
// @ts-ignore: decorator
@inline
function setTail(root: Root, tail: Block): void {
@inline function SETTAIL(root: Root, tail: Block): void {
store<Block>(changetype<usize>(root), tail, HL_END);
}
@ -227,7 +211,7 @@ function insertBlock(root: Root, block: Block): void {
var blockInfo = block.mmInfo;
if (DEBUG) assert(blockInfo & FREE); // must be free
var right = getRight(block);
var right = GETRIGHT(block);
var rightInfo = right.mmInfo;
// merge with right block if also free
@ -236,7 +220,7 @@ function insertBlock(root: Root, block: Block): void {
if (newSize < BLOCK_MAXSIZE) {
removeBlock(root, right);
block.mmInfo = blockInfo = (blockInfo & TAGS_MASK) | newSize;
right = getRight(block);
right = GETRIGHT(block);
rightInfo = right.mmInfo;
// 'back' is set below
}
@ -244,7 +228,7 @@ function insertBlock(root: Root, block: Block): void {
// merge with left block if also free
if (blockInfo & LEFTFREE) {
let left = getLeft(block);
let left = GETLEFT(block);
let leftInfo = left.mmInfo;
if (DEBUG) assert(leftInfo & FREE); // must be free according to right tags
let newSize = (leftInfo & ~TAGS_MASK) + BLOCK_OVERHEAD + (blockInfo & ~TAGS_MASK);
@ -273,22 +257,23 @@ function insertBlock(root: Root, block: Block): void {
fl = 0;
sl = <u32>(size / AL_SIZE);
} else {
fl = fls<usize>(size);
const inv: usize = sizeof<usize>() * 8 - 1;
fl = inv - clz<usize>(size);
sl = <u32>((size >> (fl - SL_BITS)) ^ (1 << SL_BITS));
fl -= SB_BITS - 1;
}
if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range
// perform insertion
var head = getHead(root, fl, sl);
var head = GETHEAD(root, fl, sl);
block.prev = null;
block.next = head;
if (head) head.prev = block;
setHead(root, fl, sl, block);
SETHEAD(root, fl, sl, block);
// update first and second level maps
root.flMap |= (1 << fl);
setSLMap(root, fl, getSLMap(root, fl) | (1 << sl));
SETSL(root, fl, GETSL(root, fl) | (1 << sl));
}
/** Removes a free block from internal lists. */
@ -304,7 +289,8 @@ function removeBlock(root: Root, block: Block): void {
fl = 0;
sl = <u32>(size / AL_SIZE);
} else {
fl = fls<usize>(size);
const inv: usize = sizeof<usize>() * 8 - 1;
fl = inv - clz<usize>(size);
sl = <u32>((size >> (fl - SL_BITS)) ^ (1 << SL_BITS));
fl -= SB_BITS - 1;
}
@ -317,13 +303,13 @@ function removeBlock(root: Root, block: Block): void {
if (next) next.prev = prev;
// update head if we are removing it
if (block == getHead(root, fl, sl)) {
setHead(root, fl, sl, next);
if (block == GETHEAD(root, fl, sl)) {
SETHEAD(root, fl, sl, next);
// clear second level map if head is empty now
if (!next) {
let slMap = getSLMap(root, fl);
setSLMap(root, fl, slMap &= ~(1 << sl));
let slMap = GETSL(root, fl);
SETSL(root, fl, slMap &= ~(1 << sl));
// clear first level map if second level is empty now
if (!slMap) root.flMap &= ~(1 << fl);
@ -345,17 +331,19 @@ function searchBlock(root: Root, size: usize): Block | null {
sl = <u32>(size / AL_SIZE);
} else {
const halfMaxSize = BLOCK_MAXSIZE >> 1; // don't round last fl
const inv: usize = sizeof<usize>() * 8 - 1;
const invRound = inv - SL_BITS;
let requestSize = size < halfMaxSize
? size + (1 << fls<usize>(size) - SL_BITS) - 1
? size + (1 << (invRound - clz<usize>(size))) - 1
: size;
fl = fls<usize>(requestSize);
fl = inv - clz<usize>(requestSize);
sl = <u32>((requestSize >> (fl - SL_BITS)) ^ (1 << SL_BITS));
fl -= SB_BITS - 1;
}
if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range
// search second level
var slMap = getSLMap(root, fl) & (~0 << sl);
var slMap = GETSL(root, fl) & (~0 << sl);
var head: Block | null;
if (!slMap) {
// search next larger first level
@ -363,13 +351,13 @@ function searchBlock(root: Root, size: usize): Block | null {
if (!flMap) {
head = null;
} else {
fl = ffs<usize>(flMap);
slMap = getSLMap(root, fl);
fl = ctz<usize>(flMap);
slMap = GETSL(root, fl);
if (DEBUG) assert(slMap); // can't be zero if fl points here
head = getHead(root, fl, ffs<u32>(slMap));
head = GETHEAD(root, fl, ctz<u32>(slMap));
}
} else {
head = getHead(root, fl, ffs<u32>(slMap));
head = GETHEAD(root, fl, ctz<u32>(slMap));
}
return head;
}
@ -399,7 +387,7 @@ function prepareBlock(root: Root, block: Block, size: usize): usize {
// otherwise tag block as no longer FREE and right as no longer LEFT_FREE
} else {
block.mmInfo = blockInfo & ~FREE;
getRight(block).mmInfo &= ~LEFTFREE;
GETRIGHT(block).mmInfo &= ~LEFTFREE;
}
return changetype<usize>(block) + BLOCK_OVERHEAD;
@ -415,7 +403,7 @@ function addMemory(root: Root, start: usize, end: usize): bool {
);
}
var tail = getTail(root);
var tail = GETTAIL(root);
var tailInfo: usize = 0;
if (tail) { // more memory
if (DEBUG) assert(start >= changetype<usize>(tail) + BLOCK_OVERHEAD);
@ -449,7 +437,7 @@ function addMemory(root: Root, start: usize, end: usize): bool {
// tail is a zero-length used block
tail = changetype<Block>(start + size - BLOCK_OVERHEAD);
tail.mmInfo = 0 | LEFTFREE;
setTail(root, tail);
SETTAIL(root, tail);
insertBlock(root, left); // also merges with free left before tail / sets 'back'
@ -476,11 +464,11 @@ function initialize(): Root {
if (pagesNeeded > pagesBefore && memory.grow(pagesNeeded - pagesBefore) < 0) unreachable();
var root = changetype<Root>(rootOffset);
root.flMap = 0;
setTail(root, changetype<Block>(0));
SETTAIL(root, changetype<Block>(0));
for (let fl: usize = 0; fl < FL_BITS; ++fl) {
setSLMap(root, fl, 0);
SETSL(root, fl, 0);
for (let sl: u32 = 0; sl < SL_SIZE; ++sl) {
setHead(root, fl, sl, null);
SETHEAD(root, fl, sl, null);
}
}
addMemory(root, (rootOffset + ROOT_SIZE + AL_MASK) & ~AL_MASK, memory.size() << 16);

View File

@ -12,7 +12,7 @@ const HL_SIZE = FL_BITS * SL_SIZE;
var exports;
var ROOT;
var U32;
fetch("untouched.wasm").then(result =>
fetch("optimized.wasm").then(result =>
result.arrayBuffer()
).then(buffer =>
WebAssembly.instantiate(buffer, {
@ -62,6 +62,11 @@ function toBits(n, l) {
}
function init() {
document.getElementById("albits").innerText = AL_BITS;
document.getElementById("flbits").innerText = FL_BITS;
document.getElementById("slbits").innerText = SL_BITS;
document.getElementById("overhead").innerText = OVERHEAD;
var fls = document.getElementById("fl");
var sls = document.getElementById("sl");
var hls = document.getElementById("hl");
@ -133,8 +138,8 @@ function allocate(size) {
<style>
/* General */
body { font-family: sans-serif; font-size: 0.8em; }
h1 { font-size: 1em; }
body { font-family: sans-serif; font-size: 0.8em; margin: 0; padding: 1em; }
h1 { font-size: 1em; margin: -1em -1em 0 -1em; padding: 1em; background: #7f7; }
h2 { background: #333; color: #ddd; font-size: 1em; padding: 0.5em; border-radius: 5px; }
input, button { border: 1px solid #999; border-radius: 0.2em; padding: 0.5em; }
button { cursor: pointer; background: #ddd; }
@ -143,25 +148,28 @@ button:hover { background: #bbb; }
/* Lists */
.fl, .sl, .hl, .seg { float: left; padding: 0.4em; margin: 0.2em; border: 1px solid #ddd; border-radius: 3px; }
.sl { min-width: 12em; }
.hl { min-width: 6em; font-size: 0.8em; }
.hl { min-width: 7em; font-size: 0.8em; }
.num { color: #fff; background: rgba(0, 0, 0, 0.3); padding: 0.4em; margin-left: -0.4em; border-radius: 0.2em; }
.set { background: #7f7; }
.seg button { margin-left: 0.5em; }
.sub { vertical-align: sub; font-size: 0.8em; }
</style>
<h1>AssemblyScript Runtime Visualizer</h1>
<h1>AssemblyScript Runtime Visualizer / TLSF</h1>
<p>
<strong>Notes:</strong>
<ul>
<li>It is expected that there is exactly one block on initialization. This is the remaining space (&lt; 64K) within the last page after static data.</li>
<li>It is expected that if two adjacent blocks of size K are freed, the merged block doesn't go into the first level list for K*2 because its size is actually larger than that (K + OVERHEAD + K).</li>
<li>It is expected that if memory grows beyond 1GB, that even if all blocks are free'd there are at least two (or even three if the largest block is in the middle) remaining blocks, because a single block must not be larger than 1GB.</li>
<li>It is expected that after other operations have already been performed, being able to allocate 1GB can't be guaranteed anymore, even if there should be enough space left in absolute terms, because prior subdivision prevents it.</li>
<li>It is expected that after other operations have already been performed, being able to allocate 1GB can't be guaranteed anymore, even if there should be enough space left in absolute terms, if prior subdivision prevents it.</li>
<li>It is expected that the second level 0 in first level 0 isn't ever used due to alignment guarantees. Smallest block is 32 bytes (16 bytes overhead + 16 bytes payload if used, respectively linking information if free) in this implementation.</li>
</ul>
</p>
<p><strong>Implementation constants:</strong> <span id="albits">?</span> bits alignment, <span id="flbits">?</span> bits first level, <span id="slbits">?</span> bits second level, <span id="overhead">?</span> B overhead</p>
<h2>First level bitmap</h2>
<p>The first level map is a bitmap determining whether free blocks exists in at least one of its respective second levels. In this implementation, the first bit indicates whether a small block (&lt; 256B) exists. Each bit doubles the size.</p>
<p>The first level map is a bitmap determining whether free blocks exist in at least one of its respective second levels. In this implementation, the first bit indicates whether a small block (&lt; 256B) exists. Each bit doubles the size.</p>
<div id="fl"></div>
<div class="clear"></div>
@ -176,21 +184,41 @@ button:hover { background: #bbb; }
<div class="clear"></div>
<h2>Allocator</h2>
<p>Chose a size to allocate. Annotated list indexes depend on implementation constants but match those of this implementation.</p>
<p>
Click to allocate:
<input type="text" value="1024" size="10" id="size" /> <button onclick="allocate(document.getElementById('size').value); update()">B</button> &nbsp;
<button onclick="allocate(1024); update()">1 KB</button>
<button onclick="allocate(10240); update()">10 KB</button>
<button onclick="allocate(102400); update()">100 KB</button> &nbsp;
<button onclick="allocate(1048576); update()">1 MB</button>
<button onclick="allocate(10485760); update()">10 MB</button>
<button onclick="allocate(104857600); update()">100 MB</button>
<button onclick="allocate(134217728-OVERHEAD); update()">128 MB - OVERHEAD</button>
<button onclick="allocate(268435456-OVERHEAD); update()">256 MB - OVERHEAD</button>
<button onclick="allocate(536870912-OVERHEAD); update()">512 MB - OVERHEAD</button> &nbsp;
<button onclick="allocate(1073741824-OVERHEAD); update()">1 GB - OVERHEAD</button>
<input type="text" value="1" size="10" id="size" /> <button onclick="allocate(document.getElementById('size').value); update()">B</button> &nbsp;
</p>
<p>
Small blocks:
<button onclick="allocate(0); update()">0 B</button>
<button onclick="allocate(16); update()">16 B <span class="sub">fl=0 sl=1</span></button>
<button onclick="allocate(32); update()">32 B <span class="sub">fl=0 sl=2</span></button>
<button onclick="allocate(48); update()">48 B <span class="sub">fl=0 sl=3</span></button>
<button onclick="allocate(64); update()">64 B <span class="sub">fl=0 sl=4</span></button>
...
<button onclick="allocate(256-OVERHEAD); update()">256 B - δ <span class="sub">fl=0 sl=MSB</span></button>
(δ ≙ block overhead)
</p>
<p>
Common blocks:
<button onclick="allocate(256); update()">256 B <span class="sub">fl=1 sl=0</span></button>
<button onclick="allocate(512-OVERHEAD); update()">512 B - δ <span class="sub">fl=1 sl=MSB</span></button>
<button onclick="allocate(1024-OVERHEAD); update()">1 KB - δ <span class="sub">fl=2 sl=MSB</span></button>
<button onclick="allocate(2048-OVERHEAD); update()">2 KB - δ <span class="sub">fl=3 sl=MSB</span></button>
<button onclick="allocate(4096-OVERHEAD); update()">4 KB - δ <span class="sub">fl=4 sl=MSB</span></button>
(e.g. allocate 3, free middle, check second level)
</p>
<p>
Large blocks:
<button onclick="allocate(67108864-OVERHEAD); update()">64 MB - δ <span class="sub">fl=MSB-4 sl=MSB</span></button>
<button onclick="allocate(134217728-OVERHEAD); update()">128 MB - δ <span class="sub">fl=MSB-3 sl=MSB</span></button>
<button onclick="allocate(268435456-OVERHEAD); update()">256 MB - δ <span class="sub">fl=MSB-2 sl=MSB</span></button>
<button onclick="allocate(536870912-OVERHEAD); update()">512 MB - δ <span class="sub">fl=MSB-1 sl=MSB</span></button>
<button onclick="allocate(1073741824-OVERHEAD); update()">1 GB - δ <span class="sub">fl=MSB sl=MSB</span></button>
</p>
</p>
<h2>Segments</h2>
<p>Allocations performed above are tracked here so you can free them again. Note that TLSF alone does not keep track of used blocks (unless free'd and put in a free list again). It is expected that adjacent free blocks become merged automatically.</p>
<div id="segs"></div>
<div class="clear"></div>

Binary file not shown.

View File

@ -727,7 +727,7 @@
if
i32.const 0
i32.const 24
i32.const 507
i32.const 495
i32.const 29
call $~lib/builtins/abort
unreachable

View File

@ -48,7 +48,7 @@
if
i32.const 0
i32.const 24
i32.const 297
i32.const 282
i32.const 13
call $~lib/builtins/abort
unreachable
@ -73,7 +73,7 @@
if
i32.const 0
i32.const 24
i32.const 299
i32.const 284
i32.const 13
call $~lib/builtins/abort
unreachable
@ -89,14 +89,10 @@
i32.div_u
local.set $5
else
block $assembly/index/fls<usize>|inlined.0 (result i32)
local.get $3
local.set $6
i32.const 31
local.get $6
i32.clz
i32.sub
end
i32.const 31
local.get $3
i32.clz
i32.sub
local.set $4
local.get $3
local.get $4
@ -129,42 +125,42 @@
if
i32.const 0
i32.const 24
i32.const 311
i32.const 297
i32.const 13
call $~lib/builtins/abort
unreachable
end
local.get $1
i32.load offset=16
local.set $7
local.set $6
local.get $1
i32.load offset=20
local.set $8
local.set $7
local.get $6
if
local.get $6
local.get $7
i32.store offset=20
end
local.get $7
if
local.get $7
local.get $8
i32.store offset=20
end
local.get $8
if
local.get $8
local.get $7
local.get $6
i32.store offset=16
end
local.get $1
block $assembly/index/getHead|inlined.1 (result i32)
block $assembly/index/GETHEAD|inlined.1 (result i32)
local.get $0
local.set $10
local.get $4
local.set $9
local.get $5
local.set $6
local.set $8
local.get $10
local.get $9
i32.const 16
i32.mul
local.get $6
local.get $8
i32.add
i32.const 4
i32.mul
@ -173,15 +169,15 @@
end
i32.eq
if
block $assembly/index/setHead|inlined.1
block $assembly/index/SETHEAD|inlined.1
local.get $0
local.set $11
local.get $4
local.set $10
local.get $5
local.set $9
local.get $8
local.set $6
local.get $7
local.set $8
local.get $11
local.get $10
i32.const 16
@ -191,38 +187,38 @@
i32.const 4
i32.mul
i32.add
local.get $6
local.get $8
i32.store offset=96
end
local.get $8
local.get $7
i32.eqz
if
block $assembly/index/getSLMap|inlined.0 (result i32)
block $assembly/index/GETSL|inlined.0 (result i32)
local.get $0
local.set $9
local.get $4
local.set $6
local.set $8
local.get $9
local.get $6
local.get $8
i32.const 2
i32.shl
i32.add
i32.load offset=4
end
local.set $6
block $assembly/index/setSLMap|inlined.1
local.set $8
block $assembly/index/SETSL|inlined.1
local.get $0
local.set $11
local.get $4
local.set $10
local.get $6
local.get $8
i32.const 1
local.get $5
i32.shl
i32.const -1
i32.xor
i32.and
local.tee $6
local.tee $8
local.set $9
local.get $11
local.get $10
@ -232,7 +228,7 @@
local.get $9
i32.store offset=4
end
local.get $6
local.get $8
i32.eqz
if
local.get $0
@ -267,7 +263,7 @@
if
i32.const 0
i32.const 24
i32.const 226
i32.const 210
i32.const 13
call $~lib/builtins/abort
unreachable
@ -282,12 +278,12 @@
if
i32.const 0
i32.const 24
i32.const 228
i32.const 212
i32.const 13
call $~lib/builtins/abort
unreachable
end
block $assembly/index/getRight|inlined.0 (result i32)
block $assembly/index/GETRIGHT|inlined.0 (result i32)
local.get $1
local.set $3
local.get $3
@ -338,7 +334,7 @@
i32.or
local.tee $2
i32.store
block $assembly/index/getRight|inlined.1 (result i32)
block $assembly/index/GETRIGHT|inlined.1 (result i32)
local.get $1
local.set $6
local.get $6
@ -362,7 +358,7 @@
i32.const 2
i32.and
if
block $assembly/index/getLeft|inlined.0 (result i32)
block $assembly/index/GETLEFT|inlined.0 (result i32)
local.get $1
local.set $3
local.get $3
@ -381,7 +377,7 @@
if
i32.const 0
i32.const 24
i32.const 249
i32.const 233
i32.const 15
call $~lib/builtins/abort
unreachable
@ -444,7 +440,7 @@
if
i32.const 0
i32.const 24
i32.const 264
i32.const 248
i32.const 13
call $~lib/builtins/abort
unreachable
@ -460,7 +456,7 @@
if
i32.const 0
i32.const 24
i32.const 265
i32.const 249
i32.const 13
call $~lib/builtins/abort
unreachable
@ -481,14 +477,10 @@
i32.div_u
local.set $10
else
block $assembly/index/fls<usize>|inlined.1 (result i32)
local.get $8
local.set $7
i32.const 31
local.get $7
i32.clz
i32.sub
end
i32.const 31
local.get $8
i32.clz
i32.sub
local.set $9
local.get $8
local.get $9
@ -521,12 +513,12 @@
if
i32.const 0
i32.const 24
i32.const 280
i32.const 265
i32.const 13
call $~lib/builtins/abort
unreachable
end
block $assembly/index/getHead|inlined.2 (result i32)
block $assembly/index/GETHEAD|inlined.2 (result i32)
local.get $0
local.set $3
local.get $9
@ -557,7 +549,7 @@
local.get $1
i32.store offset=16
end
block $assembly/index/setHead|inlined.2
block $assembly/index/SETHEAD|inlined.2
local.get $0
local.set $12
local.get $9
@ -586,8 +578,8 @@
i32.shl
i32.or
i32.store
block $assembly/index/setSLMap|inlined.2
block $assembly/index/getSLMap|inlined.1 (result i32)
block $assembly/index/SETSL|inlined.2
block $assembly/index/GETSL|inlined.1 (result i32)
local.get $0
local.set $13
local.get $9
@ -644,12 +636,12 @@
if
i32.const 0
i32.const 24
i32.const 411
i32.const 399
i32.const 4
call $~lib/builtins/abort
unreachable
end
block $assembly/index/getTail|inlined.0 (result i32)
block $assembly/index/GETTAIL|inlined.0 (result i32)
local.get $0
local.set $3
local.get $3
@ -669,7 +661,7 @@
if
i32.const 0
i32.const 24
i32.const 421
i32.const 409
i32.const 15
call $~lib/builtins/abort
unreachable
@ -700,7 +692,7 @@
if
i32.const 0
i32.const 24
i32.const 433
i32.const 421
i32.const 4
call $~lib/builtins/abort
unreachable
@ -755,7 +747,7 @@
i32.const 2
i32.or
i32.store
block $assembly/index/setTail|inlined.1
block $assembly/index/SETTAIL|inlined.1
local.get $0
local.set $9
local.get $4
@ -823,7 +815,7 @@
local.get $3
i32.const 0
i32.store
block $assembly/index/setTail|inlined.0
block $assembly/index/SETTAIL|inlined.0
local.get $3
local.set $5
i32.const 0
@ -842,7 +834,7 @@
i32.eqz
br_if $break|0
block
block $assembly/index/setSLMap|inlined.0
block $assembly/index/SETSL|inlined.0
local.get $3
local.set $7
local.get $4
@ -866,7 +858,7 @@
i32.lt_u
i32.eqz
br_if $break|1
block $assembly/index/setHead|inlined.0
block $assembly/index/SETHEAD|inlined.0
local.get $3
local.set $9
local.get $4
@ -932,7 +924,6 @@
(local $7 i32)
(local $8 i32)
(local $9 i32)
(local $10 i32)
local.get $1
i32.const 256
i32.lt_u
@ -950,15 +941,9 @@
if (result i32)
local.get $1
i32.const 1
block $assembly/index/fls<usize>|inlined.2 (result i32)
local.get $1
local.set $4
i32.const 31
local.get $4
i32.clz
i32.sub
end
i32.const 4
i32.const 27
local.get $1
i32.clz
i32.sub
i32.shl
i32.add
@ -968,14 +953,10 @@
local.get $1
end
local.set $4
block $assembly/index/fls<usize>|inlined.3 (result i32)
local.get $4
local.set $5
i32.const 31
local.get $5
i32.clz
i32.sub
end
i32.const 31
local.get $4
i32.clz
i32.sub
local.set $2
local.get $4
local.get $2
@ -1008,12 +989,12 @@
if
i32.const 0
i32.const 24
i32.const 355
i32.const 343
i32.const 13
call $~lib/builtins/abort
unreachable
end
block $assembly/index/getSLMap|inlined.2 (result i32)
block $assembly/index/GETSL|inlined.2 (result i32)
local.get $0
local.set $5
local.get $2
@ -1052,14 +1033,10 @@
i32.const 0
local.set $7
else
block $assembly/index/ffs<usize>|inlined.0 (result i32)
local.get $4
local.set $5
local.get $5
i32.ctz
end
local.get $4
i32.ctz
local.set $2
block $assembly/index/getSLMap|inlined.3 (result i32)
block $assembly/index/GETSL|inlined.3 (result i32)
local.get $0
local.set $8
local.get $2
@ -1077,22 +1054,18 @@
if
i32.const 0
i32.const 24
i32.const 368
i32.const 356
i32.const 17
call $~lib/builtins/abort
unreachable
end
block $assembly/index/getHead|inlined.3 (result i32)
block $assembly/index/GETHEAD|inlined.3 (result i32)
local.get $0
local.set $9
local.get $2
local.set $8
block $assembly/index/ffs<u32>|inlined.0 (result i32)
local.get $6
local.set $10
local.get $10
i32.ctz
end
local.get $6
i32.ctz
local.set $5
local.get $9
local.get $8
@ -1108,17 +1081,13 @@
local.set $7
end
else
block $assembly/index/getHead|inlined.4 (result i32)
block $assembly/index/GETHEAD|inlined.4 (result i32)
local.get $0
local.set $8
local.get $2
local.set $5
block $assembly/index/ffs<u32>|inlined.1 (result i32)
local.get $6
local.set $9
local.get $9
i32.ctz
end
local.get $6
i32.ctz
local.set $4
local.get $8
local.get $5
@ -1212,7 +1181,7 @@
if
i32.const 0
i32.const 24
i32.const 383
i32.const 371
i32.const 4
call $~lib/builtins/abort
unreachable
@ -1265,7 +1234,7 @@
i32.xor
i32.and
i32.store
block $assembly/index/getRight|inlined.3 (result i32)
block $assembly/index/GETRIGHT|inlined.3 (result i32)
local.get $1
local.set $5
local.get $5
@ -1279,7 +1248,7 @@
i32.and
i32.add
end
block $assembly/index/getRight|inlined.2 (result i32)
block $assembly/index/GETRIGHT|inlined.2 (result i32)
local.get $1
local.set $5
local.get $5
@ -1324,7 +1293,7 @@
if
i32.const 0
i32.const 24
i32.const 507
i32.const 495
i32.const 29
call $~lib/builtins/abort
unreachable
@ -1363,7 +1332,7 @@
if
i32.const 0
i32.const 24
i32.const 513
i32.const 501
i32.const 15
call $~lib/builtins/abort
unreachable
@ -1381,7 +1350,7 @@
if
i32.const 0
i32.const 24
i32.const 515
i32.const 503
i32.const 13
call $~lib/builtins/abort
unreachable
@ -1413,7 +1382,7 @@
if
i32.const 0
i32.const 24
i32.const 492
i32.const 480
i32.const 2
call $~lib/builtins/abort
unreachable
@ -1439,7 +1408,7 @@
if
i32.const 0
i32.const 24
i32.const 526
i32.const 514
i32.const 4
call $~lib/builtins/abort
unreachable
@ -1785,7 +1754,7 @@
if
i32.const 0
i32.const 24
i32.const 649
i32.const 637
i32.const 15
call $~lib/builtins/abort
unreachable
@ -1983,7 +1952,7 @@
if
i32.const 0
i32.const 24
i32.const 604
i32.const 592
i32.const 17
call $~lib/builtins/abort
unreachable
@ -2030,7 +1999,7 @@
if
i32.const 0
i32.const 24
i32.const 615
i32.const 603
i32.const 6
call $~lib/builtins/abort
unreachable
@ -2067,7 +2036,7 @@
if
i32.const 0
i32.const 24
i32.const 626
i32.const 614
i32.const 24
call $~lib/builtins/abort
unreachable
@ -2096,7 +2065,7 @@
if
i32.const 0
i32.const 24
i32.const 633
i32.const 621
i32.const 2
call $~lib/builtins/abort
unreachable