asrt debugger, fixes

This commit is contained in:
dcode 2019-04-16 17:33:33 +02:00
parent ceffc18694
commit 3e08e5c2d6
14 changed files with 2751 additions and 4308 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
import "../../../compiler/runtime/asrt";
import "../../../runtime/assembly/index";
import { memory as builtin_memory } from "memory";
export namespace memory {
export function allocate(size: usize): usize {
@ -7,4 +8,7 @@ export namespace memory {
export function free(ptr: usize): void {
__mm_free(ptr);
}
export function fill(dst: usize, c: u8, n: usize): void {
builtin_memory.fill(dst, c, n);
}
}

View File

@ -8,17 +8,21 @@
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
(type $FUNCSIG$vi (func (param i32)))
(type $FUNCSIG$v (func))
(memory $0 0)
(global $../../compiler/runtime/asrt/ROOT (mut i32) (i32.const 0))
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
(memory $0 1)
(data (i32.const 8) "\10\00\00\00>")
(data (i32.const 24) ".\00.\00/\00.\00.\00/\00r\00u\00n\00t\00i\00m\00e\00/\00a\00s\00s\00e\00m\00b\00l\00y\00/\00i\00n\00d\00e\00x\00.\00t\00s")
(global $../../runtime/assembly/index/ROOT (mut i32) (i32.const 0))
(export "memory" (memory $0))
(export "memory.allocate" (func $assembly/index/memory.allocate))
(export "memory.free" (func $assembly/index/memory.free))
(func $../../compiler/runtime/asrt/setTail (; 0 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(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=1504
i32.store offset=1568
)
(func $../../compiler/runtime/asrt/setSLMap (; 1 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
(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
@ -27,7 +31,7 @@
local.get $2
i32.store offset=4
)
(func $../../compiler/runtime/asrt/setHead (; 2 ;) (type $FUNCSIG$viiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
(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
@ -40,7 +44,7 @@
local.get $3
i32.store offset=96
)
(func $../../compiler/runtime/asrt/getRight (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
(func $../../runtime/assembly/index/getRight (; 4 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
local.get $0
i32.const 16
i32.add
@ -50,13 +54,13 @@
i32.and
i32.add
)
(func $../../compiler/runtime/asrt/fls<usize> (; 4 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
(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 $../../compiler/runtime/asrt/getHead (; 5 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(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
@ -68,7 +72,7 @@
i32.add
i32.load offset=96
)
(func $../../compiler/runtime/asrt/getSLMap (; 6 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
(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
@ -76,7 +80,7 @@
i32.add
i32.load offset=4
)
(func $../../compiler/runtime/asrt/removeBlock (; 7 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(func $../../runtime/assembly/index/removeBlock (; 8 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
@ -97,7 +101,7 @@
else
local.get $2
local.get $2
call $../../compiler/runtime/asrt/fls<usize>
call $../../runtime/assembly/index/fls<usize>
local.tee $3
i32.const 4
i32.sub
@ -130,7 +134,7 @@
local.get $0
local.get $3
local.get $4
call $../../compiler/runtime/asrt/getHead
call $../../runtime/assembly/index/getHead
local.get $1
i32.eq
if
@ -138,7 +142,7 @@
local.get $3
local.get $4
local.get $2
call $../../compiler/runtime/asrt/setHead
call $../../runtime/assembly/index/setHead
local.get $2
i32.eqz
if
@ -146,7 +150,7 @@
local.get $3
local.get $0
local.get $3
call $../../compiler/runtime/asrt/getSLMap
call $../../runtime/assembly/index/getSLMap
i32.const 1
local.get $4
i32.shl
@ -154,7 +158,7 @@
i32.xor
i32.and
local.tee $1
call $../../compiler/runtime/asrt/setSLMap
call $../../runtime/assembly/index/setSLMap
local.get $1
i32.eqz
if
@ -172,42 +176,56 @@
end
end
)
(func $../../compiler/runtime/asrt/insertBlock (; 8 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(func $../../runtime/assembly/index/insertBlock (; 9 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
(local $5 i32)
(local $6 i32)
(local $7 i32)
local.get $1
i32.load
local.set $2
local.set $3
local.get $1
call $../../compiler/runtime/asrt/getRight
local.tee $3
i32.load
call $../../runtime/assembly/index/getRight
local.tee $4
i32.load
local.tee $5
i32.const 1
i32.and
if
local.get $0
local.get $3
call $../../compiler/runtime/asrt/removeBlock
local.get $1
local.get $2
local.get $4
i32.const -4
i32.and
i32.const 16
i32.add
local.get $5
i32.const -4
i32.and
i32.add
local.tee $2
i32.store
local.get $1
call $../../compiler/runtime/asrt/getRight
local.tee $3
i32.load
local.set $4
i32.const 1073741824
i32.lt_u
if
local.get $0
local.get $4
call $../../runtime/assembly/index/removeBlock
local.get $1
local.get $3
i32.const 3
i32.and
local.get $2
i32.or
local.tee $3
i32.store
local.get $1
call $../../runtime/assembly/index/getRight
local.tee $4
i32.load
local.set $5
end
end
local.get $2
local.get $3
i32.const 2
i32.and
if
@ -215,35 +233,48 @@
i32.const 4
i32.sub
i32.load
local.tee $1
local.tee $2
i32.load
local.set $5
local.get $0
local.get $1
call $../../compiler/runtime/asrt/removeBlock
local.get $1
local.get $5
local.get $2
local.tee $6
i32.const -4
i32.and
i32.const 16
i32.add
local.get $3
i32.const -4
i32.and
i32.add
local.tee $2
i32.store
local.tee $7
i32.const 1073741824
i32.lt_u
if
local.get $0
local.get $2
call $../../runtime/assembly/index/removeBlock
local.get $2
local.get $6
i32.const 3
i32.and
local.get $7
i32.or
local.tee $3
i32.store
local.get $2
local.set $1
end
end
local.get $3
local.get $4
local.get $5
i32.const 2
i32.or
i32.store
local.get $3
local.get $4
i32.const 4
i32.sub
local.get $1
i32.store
local.get $0
local.get $2
local.get $3
i32.const -4
i32.and
local.tee $2
@ -253,26 +284,26 @@
local.get $2
i32.const 16
i32.div_u
local.set $2
local.set $3
i32.const 0
else
local.get $2
local.get $2
call $../../compiler/runtime/asrt/fls<usize>
local.tee $3
call $../../runtime/assembly/index/fls<usize>
local.tee $2
i32.const 4
i32.sub
i32.shr_u
i32.const 16
i32.xor
local.set $2
local.get $3
local.set $3
local.get $2
i32.const 7
i32.sub
end
local.tee $3
local.get $2
call $../../compiler/runtime/asrt/getHead
local.tee $2
local.get $3
call $../../runtime/assembly/index/getHead
local.set $4
local.get $1
i32.const 0
@ -287,35 +318,35 @@
i32.store offset=16
end
local.get $0
local.get $3
local.get $2
local.get $3
local.get $1
call $../../compiler/runtime/asrt/setHead
call $../../runtime/assembly/index/setHead
local.get $0
local.get $0
i32.load
i32.const 1
local.get $3
local.get $2
i32.shl
i32.or
i32.store
local.get $0
local.get $3
local.get $0
local.get $3
call $../../compiler/runtime/asrt/getSLMap
i32.const 1
local.get $2
local.get $0
local.get $2
call $../../runtime/assembly/index/getSLMap
i32.const 1
local.get $3
i32.shl
i32.or
call $../../compiler/runtime/asrt/setSLMap
call $../../runtime/assembly/index/setSLMap
)
(func $../../compiler/runtime/asrt/addMemory (; 9 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
(func $../../runtime/assembly/index/addMemory (; 10 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
(local $3 i32)
local.get $2
block (result i32)
local.get $0
i32.load offset=1504
i32.load offset=1568
local.tee $2
if
local.get $1
@ -369,19 +400,19 @@
i32.store
local.get $0
local.get $2
call $../../compiler/runtime/asrt/setTail
call $../../runtime/assembly/index/setTail
local.get $0
local.get $1
call $../../compiler/runtime/asrt/insertBlock
call $../../runtime/assembly/index/insertBlock
)
(func $../../compiler/runtime/asrt/initialize (; 10 ;) (type $FUNCSIG$i) (result i32)
(func $../../runtime/assembly/index/initialize (; 11 ;) (type $FUNCSIG$i) (result i32)
(local $0 i32)
(local $1 i32)
(local $2 i32)
(local $3 i32)
i32.const 16
i32.const 96
local.tee $3
i32.const 67043
i32.const 67107
i32.add
i32.const -65536
i32.and
@ -410,17 +441,17 @@
i32.store
local.get $0
i32.const 0
call $../../compiler/runtime/asrt/setTail
call $../../runtime/assembly/index/setTail
loop $repeat|0
block $break|0
local.get $2
i32.const 22
i32.const 23
i32.ge_u
br_if $break|0
local.get $0
local.get $2
i32.const 0
call $../../compiler/runtime/asrt/setSLMap
call $../../runtime/assembly/index/setSLMap
i32.const 0
local.set $1
loop $repeat|1
@ -433,7 +464,7 @@
local.get $2
local.get $1
i32.const 0
call $../../compiler/runtime/asrt/setHead
call $../../runtime/assembly/index/setHead
local.get $1
i32.const 1
i32.add
@ -450,18 +481,19 @@
end
local.get $0
local.get $3
i32.const 1523
i32.const 1587
i32.add
i32.const -16
i32.and
current_memory
i32.const 16
i32.shl
call $../../compiler/runtime/asrt/addMemory
call $../../runtime/assembly/index/addMemory
local.get $0
)
(func $../../compiler/runtime/asrt/searchBlock (; 11 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
(func $../../runtime/assembly/index/searchBlock (; 12 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32)
local.get $0
local.get $1
i32.const 256
i32.lt_u
@ -469,11 +501,32 @@
local.get $1
i32.const 16
i32.div_u
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>
local.set $2
local.get $1
local.get $1
call $../../compiler/runtime/asrt/fls<usize>
local.tee $2
local.get $2
i32.const 4
i32.sub
i32.shr_u
@ -483,26 +536,9 @@
local.get $2
i32.const 7
i32.sub
local.set $2
local.get $1
i32.const 15
i32.lt_u
if (result i32)
local.get $1
i32.const 1
i32.add
else
local.get $2
i32.const 1
i32.add
local.set $2
i32.const 0
end
end
local.set $1
local.get $0
local.get $2
call $../../compiler/runtime/asrt/getSLMap
local.tee $2
call $../../runtime/assembly/index/getSLMap
i32.const -1
local.get $1
i32.shl
@ -513,7 +549,7 @@
local.get $2
local.get $1
i32.ctz
call $../../compiler/runtime/asrt/getHead
call $../../runtime/assembly/index/getHead
else
local.get $0
i32.load
@ -531,15 +567,15 @@
local.tee $1
local.get $0
local.get $1
call $../../compiler/runtime/asrt/getSLMap
call $../../runtime/assembly/index/getSLMap
i32.ctz
call $../../compiler/runtime/asrt/getHead
call $../../runtime/assembly/index/getHead
else
i32.const 0
end
end
)
(func $../../compiler/runtime/asrt/growMemory (; 12 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(func $../../runtime/assembly/index/growMemory (; 13 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
@ -578,9 +614,9 @@
current_memory
i32.const 16
i32.shl
call $../../compiler/runtime/asrt/addMemory
call $../../runtime/assembly/index/addMemory
)
(func $../../compiler/runtime/asrt/prepareBlock (; 13 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(func $../../runtime/assembly/index/prepareBlock (; 14 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32)
(local $4 i32)
local.get $1
@ -588,7 +624,7 @@
local.set $3
local.get $0
local.get $1
call $../../compiler/runtime/asrt/removeBlock
call $../../runtime/assembly/index/removeBlock
local.get $3
i32.const -4
i32.and
@ -619,7 +655,7 @@
i32.store
local.get $0
local.get $2
call $../../compiler/runtime/asrt/insertBlock
call $../../runtime/assembly/index/insertBlock
else
local.get $1
local.get $3
@ -627,9 +663,9 @@
i32.and
i32.store
local.get $1
call $../../compiler/runtime/asrt/getRight
call $../../runtime/assembly/index/getRight
local.get $1
call $../../compiler/runtime/asrt/getRight
call $../../runtime/assembly/index/getRight
i32.load
i32.const -3
i32.and
@ -639,21 +675,26 @@
i32.const 16
i32.add
)
(func $../../compiler/runtime/asrt/__mm_allocate (; 14 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
(func $../../runtime/assembly/index/__mm_allocate (; 15 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
(local $1 i32)
(local $2 i32)
global.get $../../compiler/runtime/asrt/ROOT
global.get $../../runtime/assembly/index/ROOT
local.tee $2
i32.eqz
if
call $../../compiler/runtime/asrt/initialize
call $../../runtime/assembly/index/initialize
local.tee $2
global.set $../../compiler/runtime/asrt/ROOT
global.set $../../runtime/assembly/index/ROOT
end
local.get $0
i32.const 1073741824
i32.gt_u
i32.ge_u
if
i32.const 0
i32.const 24
i32.const 498
i32.const 29
call $~lib/builtins/abort
unreachable
end
local.get $2
@ -670,16 +711,16 @@
i32.gt_u
select
local.tee $1
call $../../compiler/runtime/asrt/searchBlock
call $../../runtime/assembly/index/searchBlock
local.tee $0
i32.eqz
if
local.get $2
local.get $1
call $../../compiler/runtime/asrt/growMemory
call $../../runtime/assembly/index/growMemory
local.get $2
local.get $1
call $../../compiler/runtime/asrt/searchBlock
call $../../runtime/assembly/index/searchBlock
local.set $0
end
local.get $0
@ -694,17 +735,17 @@
local.get $2
local.get $0
local.get $1
call $../../compiler/runtime/asrt/prepareBlock
call $../../runtime/assembly/index/prepareBlock
)
(func $assembly/index/memory.allocate (; 15 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
(func $assembly/index/memory.allocate (; 16 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
local.get $0
call $../../compiler/runtime/asrt/__mm_allocate
call $../../runtime/assembly/index/__mm_allocate
)
(func $../../compiler/runtime/asrt/__mm_free (; 16 ;) (type $FUNCSIG$vi) (param $0 i32)
(func $../../runtime/assembly/index/__mm_free (; 17 ;) (type $FUNCSIG$vi) (param $0 i32)
(local $1 i32)
local.get $0
if
global.get $../../compiler/runtime/asrt/ROOT
global.get $../../runtime/assembly/index/ROOT
local.tee $1
if
local.get $0
@ -718,15 +759,251 @@
i32.store
local.get $1
local.get $0
call $../../compiler/runtime/asrt/insertBlock
call $../../runtime/assembly/index/insertBlock
end
end
)
(func $assembly/index/memory.free (; 17 ;) (type $FUNCSIG$vi) (param $0 i32)
(func $assembly/index/memory.free (; 18 ;) (type $FUNCSIG$vi) (param $0 i32)
local.get $0
call $../../compiler/runtime/asrt/__mm_free
call $../../runtime/assembly/index/__mm_free
)
(func $null (; 18 ;) (type $FUNCSIG$v)
(func $~lib/memory/memory.fill (; 19 ;) (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
local.get $2
i32.eqz
br_if $~lib/util/memory/memset|inlined.0
local.get $0
local.get $1
i32.store8
local.get $0
local.get $2
i32.add
i32.const 1
i32.sub
local.get $1
i32.store8
local.get $2
i32.const 2
i32.le_u
br_if $~lib/util/memory/memset|inlined.0
local.get $0
i32.const 1
i32.add
local.get $1
i32.store8
local.get $0
i32.const 2
i32.add
local.get $1
i32.store8
local.get $0
local.get $2
i32.add
i32.const 2
i32.sub
local.get $1
i32.store8
local.get $0
local.get $2
i32.add
i32.const 3
i32.sub
local.get $1
i32.store8
local.get $2
i32.const 6
i32.le_u
br_if $~lib/util/memory/memset|inlined.0
local.get $0
i32.const 3
i32.add
local.get $1
i32.store8
local.get $0
local.get $2
i32.add
i32.const 4
i32.sub
local.get $1
i32.store8
local.get $2
i32.const 8
i32.le_u
br_if $~lib/util/memory/memset|inlined.0
i32.const 0
local.get $0
i32.sub
i32.const 3
i32.and
local.tee $4
local.get $0
i32.add
local.tee $0
local.get $1
i32.const 255
i32.and
i32.const 16843009
i32.mul
local.tee $1
i32.store
local.get $2
local.get $4
i32.sub
i32.const -4
i32.and
local.tee $2
local.get $0
i32.add
i32.const 4
i32.sub
local.get $1
i32.store
local.get $2
i32.const 8
i32.le_u
br_if $~lib/util/memory/memset|inlined.0
local.get $0
i32.const 4
i32.add
local.get $1
i32.store
local.get $0
i32.const 8
i32.add
local.get $1
i32.store
local.get $0
local.get $2
i32.add
i32.const 12
i32.sub
local.get $1
i32.store
local.get $0
local.get $2
i32.add
i32.const 8
i32.sub
local.get $1
i32.store
local.get $2
i32.const 24
i32.le_u
br_if $~lib/util/memory/memset|inlined.0
local.get $0
i32.const 12
i32.add
local.get $1
i32.store
local.get $0
i32.const 16
i32.add
local.get $1
i32.store
local.get $0
i32.const 20
i32.add
local.get $1
i32.store
local.get $0
i32.const 24
i32.add
local.get $1
i32.store
local.get $0
local.get $2
i32.add
i32.const 28
i32.sub
local.get $1
i32.store
local.get $0
local.get $2
i32.add
i32.const 24
i32.sub
local.get $1
i32.store
local.get $0
local.get $2
i32.add
i32.const 20
i32.sub
local.get $1
i32.store
local.get $0
local.get $2
i32.add
i32.const 16
i32.sub
local.get $1
i32.store
local.get $0
i32.const 4
i32.and
i32.const 24
i32.add
local.tee $4
local.get $0
i32.add
local.set $0
local.get $2
local.get $4
i32.sub
local.set $2
local.get $1
i64.extend_i32_u
local.get $1
i64.extend_i32_u
i64.const 32
i64.shl
i64.or
local.set $3
loop $continue|0
local.get $2
i32.const 32
i32.ge_u
if
local.get $0
local.get $3
i64.store
local.get $0
i32.const 8
i32.add
local.get $3
i64.store
local.get $0
i32.const 16
i32.add
local.get $3
i64.store
local.get $0
i32.const 24
i32.add
local.get $3
i64.store
local.get $2
i32.const 32
i32.sub
local.set $2
local.get $0
i32.const 32
i32.add
local.set $0
br $continue|0
end
end
end
)
(func $assembly/index/memory.fill (; 20 ;) (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)
nop
)
)

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,3 @@
const useFill = false;
function runner(exports, runs, allocs) {
const alloc = exports["memory.allocate"];
const free = exports["memory.free"];
@ -16,7 +14,7 @@ function runner(exports, runs, allocs) {
if (!ptr) throw Error();
if ((ptr & 7) != 0) throw Error("invalid alignment: " + (ptr & 7) + " on " + ptr);
if (ptrs.indexOf(ptr) >= 0) throw Error("duplicate pointer");
if (useFill) fill(ptr, 0xdc, size);
if (fill) fill(ptr, ptr % 8, size);
ptrs.push(ptr);
return ptr;
}
@ -86,14 +84,14 @@ function runner(exports, runs, allocs) {
// SL+1 for allocations in TLSF
var size = ((exports.memory.buffer.byteLength - base) * 9 / 10) >>> 0;
var ptr = alloc(size);
if (useFill) fill(ptr, 0xac, size);
// if (fill) fill(ptr, 0xac, size);
if (ptr !== base) throw Error("expected " + base + " but got " + ptr);
free(ptr);
}
testMemChanged();
}
} finally {
// mem(allocator.memory, 0, 0x10000);
// mem(exports.memory, 0, 0x800);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@
// 3 2 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 bits
// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┼─┴─┴─┴─╫─┴─┴─┴─┤
// │ | FL │ SB = SL + AL │ ◄─ usize
// │ | FL │ SB = SL + AL │ ◄─ usize
// └───────────────────────────────────────────────┴───────╨───────┘
// FL: first level, SL: second level, AL: alignment, SB: small block
@ -35,10 +35,21 @@
// @ts-ignore: decorator
@inline
const FL_BITS: u32 = (sizeof<usize>() == sizeof<u32>()
? 30 // ^= up to 1GB per block
: 32 // ^= up to 4GB per block
) - SB_BITS;
const FL_BITS: u32 = 31 - SB_BITS;
// [00]: < 256B (SB) [12]: < 1M
// [01]: < 512B [13]: < 2M
// [02]: < 1K [14]: < 4M
// [03]: < 2K [15]: < 8M
// [04]: < 4K [16]: < 16M
// [05]: < 8K [17]: < 32M
// [06]: < 16K [18]: < 64M
// [07]: < 32K [19]: < 128M
// [08]: < 64K [20]: < 256M
// [09]: < 128K [21]: < 512M
// [10]: < 256K [22]: <= 1G - OVERHEAD
// [11]: < 512K
// VMs limit to 2GB total (currently), making one 1G block max (or three 512M etc.) due to block overhead
// Tags stored in otherwise unused alignment bits
@ -95,7 +106,7 @@ const FL_BITS: u32 = (sizeof<usize>() == sizeof<u32>()
// @ts-ignore: decorator
@inline const BLOCK_MINSIZE: usize = (3 * sizeof<usize>() + AL_MASK) & ~AL_MASK;// prev + next + back
// @ts-ignore: decorator
@inline const BLOCK_MAXSIZE: usize = 1 << (FL_BITS + SB_BITS); // 1GB if WASM32, 4GB if WASM64
@inline const BLOCK_MAXSIZE: usize = 1 << (FL_BITS + SB_BITS - 1); // exclusive
/** Gets the left block of a block. Only valid if the left block is free. */
function getLeft(block: Block): Block {
@ -200,11 +211,14 @@ function insertBlock(root: Root, block: Block): void {
// merge with right block if also free
if (rightInfo & FREE) {
removeBlock(root, right);
block.mmInfo = (blockInfo += BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK));
right = getRight(block);
rightInfo = right.mmInfo;
// 'back' is set below
let newSize = (blockInfo & ~TAGS_MASK) + BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK);
if (newSize < BLOCK_MAXSIZE) {
removeBlock(root, right);
block.mmInfo = blockInfo = (blockInfo & TAGS_MASK) | newSize;
right = getRight(block);
rightInfo = right.mmInfo;
// 'back' is set below
}
}
// merge with left block if also free
@ -212,11 +226,13 @@ function insertBlock(root: Root, block: Block): void {
let left = getLeft(block);
let leftInfo = left.mmInfo;
if (DEBUG) assert(leftInfo & FREE); // must be free according to right tags
removeBlock(root, left);
left.mmInfo = (leftInfo += BLOCK_OVERHEAD + (blockInfo & ~TAGS_MASK));
block = left;
blockInfo = leftInfo;
// 'back' is set below
let newSize = (leftInfo & ~TAGS_MASK) + BLOCK_OVERHEAD + (blockInfo & ~TAGS_MASK);
if (newSize < BLOCK_MAXSIZE) {
removeBlock(root, left);
left.mmInfo = blockInfo = (leftInfo & TAGS_MASK) | newSize;
block = left;
// 'back' is set below
}
}
right.mmInfo = rightInfo | LEFTFREE;
@ -305,13 +321,13 @@ function searchBlock(root: Root, size: usize): Block | null {
fl = 0;
sl = <u32>(size / AL_SIZE);
} else {
// (*) size += (1 << (fls<usize>(size) - SL_BITS)) - 1;
fl = fls<usize>(size);
sl = <u32>((size >> (fl - SL_BITS)) ^ (1 << SL_BITS));
const halfMaxSize = BLOCK_MAXSIZE >> 1; // don't round last fl
let requestSize = size < halfMaxSize
? size + (1 << fls<usize>(size) - SL_BITS) - 1
: size;
fl = fls<usize>(requestSize);
sl = <u32>((requestSize >> (fl - SL_BITS)) ^ (1 << SL_BITS));
fl -= SB_BITS - 1;
// (*) instead of rounding up, use next second level list for better fit
if (sl < SL_SIZE - 1) ++sl;
else ++fl, sl = 0;
}
// search second level
@ -422,7 +438,7 @@ function growMemory(root: Root, size: usize): void {
var pagesNeeded = <i32>(((size + 0xffff) & ~0xffff) >>> 16);
var pagesWanted = max(pagesBefore, pagesNeeded); // double memory
if (memory.grow(pagesWanted) < 0) {
if (memory.grow(pagesNeeded) < 0) unreachable(); // out of memory
if (memory.grow(pagesNeeded) < 0) unreachable();
}
var pagesAfter = memory.size();
addMemory(root, <usize>pagesBefore << 16, <usize>pagesAfter << 16);
@ -430,13 +446,6 @@ function growMemory(root: Root, size: usize): void {
/** Initilizes the root structure. */
function initialize(): Root {
if (DEBUG) {
assert(
SB_SIZE == 256 && // max size of a small block
FL_BITS == 22 && // number of second level maps
FL_BITS * SL_SIZE == 352 // number of heads
);
}
var rootOffset = (HEAP_BASE + AL_MASK) & ~AL_MASK;
var pagesBefore = memory.size();
var pagesNeeded = <i32>((((rootOffset + ROOT_SIZE) + 0xffff) & ~0xffff) >>> 16);
@ -486,8 +495,8 @@ function __mm_allocate(size: usize): usize {
if (!root) ROOT = root = initialize();
// search for a suitable block
if (size > BLOCK_MAXSIZE) unreachable();
size = max<usize>((size + AL_MASK) & ~AL_MASK, BLOCK_MINSIZE); // valid
if (size >= BLOCK_MAXSIZE) throw new Error("allocation too large");
size = max<usize>((size + AL_MASK) & ~AL_MASK, BLOCK_MINSIZE); // align and ensure min size
var block = searchBlock(root, size);
if (!block) {
growMemory(root, size);

View File

@ -0,0 +1,6 @@
{
"extends": "../../../std/assembly.json",
"include": [
"./**/*.ts"
]
}

196
tests/runtime/index.html Normal file
View File

@ -0,0 +1,196 @@
<script>
// Configuration - must match actual implementation
const AL_BITS = 4;
const SL_BITS = 4;
const OVERHEAD = 16;
const SL_SIZE = 1 << SL_BITS;
const SB_BITS = AL_BITS + SL_BITS;
const FL_BITS = 31 - SB_BITS;
const HL_SIZE = FL_BITS * SL_SIZE;
var exports;
var ROOT;
var U32;
fetch("untouched.wasm").then(result =>
result.arrayBuffer()
).then(buffer =>
WebAssembly.instantiate(buffer, {
env: {
abort: function(msg, file, line, column) {
console.log("abort: " + getString(msg) + " at " + getString(file) + ":" + line + ":" + column);
},
trace: function(msg, n, ...args) {
console.log("trace: " + getString(msg) + " " + args.slice(0, n).join(" "));
}
}
})
).then(result => {
exports = result.instance.exports;
U32 = new Uint32Array(exports.memory.buffer);
var first = exports.__mm_allocate(255);
exports.__mm_free(first);
ROOT = first - 17;
while (!U32[ROOT >> 2]) --ROOT; // find tail
ROOT -= (1 + FL_BITS + HL_SIZE) << 2;
init();
update();
});
function getString(ptr) {
if (!ptr) return "null";
var U32 = new Uint32Array(exports.memory.buffer);
var U16 = new Uint16Array(exports.memory.buffer);
var len16 = U32[(ptr - 12) >>> 2] >>> 1; // TODO: old header
var ptr16 = ptr >>> 1;
return String.fromCharCode.apply(String, U16.subarray(ptr16, ptr16 + len16));
}
var fl = [];
var sl = [];
var hl = [];
var flValue;
var slValue;
var hlValue;
var tailValue;
function toBits(n, l) {
var s = n.toString(2);
while (s.length < l) s = "0" + s;
return s;
}
function init() {
var fls = document.getElementById("fl");
var sls = document.getElementById("sl");
var hls = document.getElementById("hl");
for (let i = 0; i < FL_BITS; ++i) {
let el = document.createElement("span");
el.className = "fl";
el.innerText = i;
fls.appendChild(el);
fl[i] = el;
el.title = "< " + (1 << (8 + i));
el = document.createElement("span");
el.className = "sl";
el.innerHTML = '<span class="num">' + i + '</span>' + " " + toBits(0, HL_SIZE / FL_BITS);
sls.appendChild(el);
sl[i] = el;
}
for (let i = 0; i <= HL_SIZE; ++i) { // sic: last is tail
let el = document.createElement("span");
el.className = "hl";
el.innerHTML = '<span class="num">' + i + '</span> -';
hl[i] = el;
hls.appendChild(el);
}
}
function update() {
if (U32.buffer !== exports.memory.buffer) U32 = new Uint32Array(exports.memory.buffer);
var flv = U32[ROOT >> 2];
fl.forEach((el, i) => {
var isset = (flv >>> i) & 1;
el.className = isset ? "fl set" : "fl";
});
sl.forEach((el, i) => {
var map = U32[(ROOT + 4 + i * 4) >> 2];
el.className = map ? "sl set" : "sl";
el.innerHTML = '<span class="num">' + i + '</span>' + " " + toBits(map, (hl.length - 1) / fl.length);
});
hl.forEach((el, i) => {
var ptr = U32[(ROOT + 4 + fl.length * 4 + i * 4) >> 2];
el.className = ptr ? "hl set" : "hl";
el.innerHTML = '<span class="num">' + (i == hl.length - 1 ? "tail" : i) + '</span>' + " " + ptr.toString(16);
});
}
function allocate(size) {
var ptr = exports.__mm_allocate(size);
if (!ptr) {
alert("allocation failed");
return;
}
var el = document.createElement("div");
el.className = "seg";
var es = document.createElement("span");
es.innerText = size;
el.appendChild(es);
var ef = document.createElement("button");
ef.innerText = "free";
el.appendChild(ef);
ef.onclick = function() {
exports.__mm_free(ptr);
document.getElementById("segs").removeChild(el);
update();
};
document.getElementById("segs").appendChild(el);
}
</script>
<style>
/* General */
body { font-family: sans-serif; font-size: 0.8em; }
h1 { font-size: 1em; }
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; }
button:hover { background: #bbb; }
.clear { clear: both; }
/* 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; }
.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; }
</style>
<h1>AssemblyScript Runtime Visualizer</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>
</ul>
</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>
<div id="fl"></div>
<div class="clear"></div>
<h2>Second level maps</h2>
<p>Second level maps subdivide each first level into multiple lists of subsizes. Each one works similar to the first level bitmap.</p>
<div id="sl"></div>
<div class="clear"></div>
<h2>Heads</h2>
<p>The heads of the actual free lists, one per second level per first level. Values here are pointers into memory. Last item is the address of the special zero-size "used" tail block, which is usually the end of WASM memory minus block overhead.</p>
<div id="hl"></div>
<div class="clear"></div>
<h2>Allocator</h2>
<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>
</p>
<h2>Segments</h2>
<div id="segs"></div>
<div class="clear"></div>

1067
tests/runtime/optimized.wat Normal file

File diff suppressed because it is too large Load Diff

213
tests/runtime/package-lock.json generated Normal file
View File

@ -0,0 +1,213 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"async": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
"dev": true
},
"colors": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
"integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=",
"dev": true
},
"corser": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
"integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=",
"dev": true
},
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"ecstatic": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.1.tgz",
"integrity": "sha512-/rrctvxZ78HMI/tPIsqdvFKHHscxR3IJuKrZI2ZoUgkt2SiufyLFBmcco+aqQBIu6P1qBsUNG3drAAGLx80vTQ==",
"dev": true,
"requires": {
"he": "^1.1.1",
"mime": "^1.6.0",
"minimist": "^1.1.0",
"url-join": "^2.0.5"
}
},
"eventemitter3": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
"integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==",
"dev": true
},
"follow-redirects": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz",
"integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==",
"dev": true,
"requires": {
"debug": "^3.2.6"
}
},
"he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true
},
"http-proxy": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
"dev": true,
"requires": {
"eventemitter3": "^3.0.0",
"follow-redirects": "^1.0.0",
"requires-port": "^1.0.0"
}
},
"http-server": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz",
"integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==",
"dev": true,
"requires": {
"colors": "1.0.3",
"corser": "~2.0.0",
"ecstatic": "^3.0.0",
"http-proxy": "^1.8.1",
"opener": "~1.4.0",
"optimist": "0.6.x",
"portfinder": "^1.0.13",
"union": "~0.4.3"
}
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
"minimist": "0.0.8"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
}
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true
},
"opener": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz",
"integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=",
"dev": true
},
"optimist": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"dev": true,
"requires": {
"minimist": "~0.0.1",
"wordwrap": "~0.0.2"
},
"dependencies": {
"minimist": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
"dev": true
}
}
},
"portfinder": {
"version": "1.0.20",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz",
"integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==",
"dev": true,
"requires": {
"async": "^1.5.2",
"debug": "^2.2.0",
"mkdirp": "0.5.x"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
}
}
},
"qs": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz",
"integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=",
"dev": true
},
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
"dev": true
},
"union": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz",
"integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=",
"dev": true,
"requires": {
"qs": "~2.3.3"
}
},
"url-join": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
"integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=",
"dev": true
},
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
"dev": true
}
}
}

View File

@ -0,0 +1,12 @@
{
"private": true,
"scripts": {
"server": "http-server . -o -c-1",
"build": "npm run build:untouched && npm run build:optimized",
"build:untouched": "node ../../bin/asc assembly/index.ts -t untouched.wat -b untouched.wasm --runtime none --validate --sourceMap --measure",
"build:optimized": "node ../../bin/asc assembly/index.ts -t optimized.wat -b optimized.wasm --runtime none --validate --sourceMap --measure --noAssert --optimize"
},
"devDependencies": {
"http-server": "^0.11.1"
}
}