forked from wingo/walloc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
test.js
129 lines (122 loc) · 4.28 KB
/
test.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
if (typeof read !== 'undefined') {
function readBinaryFile(f) { return read(f, 'binary'); }
} else if (typeof readFile !== 'undefined') {
function readBinaryFile(f) { return readFile(f); }
} else if (typeof require !== 'undefined') {
let fs = require('fs');
function readBinaryFile(f) { return fs.readFileSync(f); }
} else {
throw "no way to read a binary file";
}
function assert(c, msg) { if (!c) throw new Error(msg); }
function power_of_two(x) { return x && (x & (x - 1)) == 0; }
function assert_power_of_two(x) {
assert(power_of_two(x), `not power of two: ${x}`);
}
function aligned(x, y) {
assert_power_of_two(y);
return (x & (y - 1)) == 0;
}
function assert_aligned(x, y) {
assert(aligned(x, y), `bad alignment: ${x} % ${y}`);
}
function round_up(x, y) {
assert_power_of_two(y);
return (x + y - 1) & ~(y - 1);
}
let granule_size = 8;
let bits_per_byte = 8;
let bits_per_byte_log2 = 3;
class HeapVerifier {
constructor(maxbytes) {
this.maxwords = maxbytes / granule_size;
this.state = new Uint8Array(this.maxwords / bits_per_byte);
this.allocations = new Map;
}
acquire(offset, len) {
assert_aligned(offset, granule_size);
for (let i = 0; i < len; i += granule_size) {
let bit = (offset + i) / granule_size;
let byte = bit >> bits_per_byte_log2;
let mask = 1 << (bit & (bits_per_byte - 1));
assert((this.state[byte] & mask) == 0, "word in use");
this.state[byte] |= mask;
}
this.allocations.set(offset, len);
}
release(offset) {
assert(this.allocations.has(offset))
let len = this.allocations.get(offset);
this.allocations.delete(offset);
for (let i = 0; i < len; i += granule_size) {
let bit = (offset + i) / granule_size;
let byte = bit >> bits_per_byte_log2;
let mask = 1 << (bit & (bits_per_byte - 1));
this.state[byte] &= ~mask;
}
}
}
class LinearMemory {
constructor({initial = 256, maximum = 256}) {
this.memory = new WebAssembly.Memory({ initial, maximum });
this.verifier = new HeapVerifier(maximum * 65536);
}
record_malloc(ptr, len) { this.verifier.acquire(ptr, len); }
record_free(ptr) { this.verifier.release(ptr); }
read_string(offset) {
let view = new Uint8Array(this.memory.buffer);
let bytes = []
for (let byte = view[offset]; byte; byte = view[++offset])
bytes.push(byte);
return String.fromCharCode(...bytes);
}
log(str) { console.log(`wasm log: ${str}`) }
log_i(str, i) { console.log(`wasm log: ${str}: ${i}`) }
env() {
return {
memory: this.memory,
wasm_log: (off) => this.log(this.read_string(off)),
wasm_log_i: (off, i) => this.log_i(this.read_string(off), i)
}
}
}
function randu(x, max) { return Math.floor(x * max); }
function sys_rand32() { return randu(Math.random(), 2**32); }
function xoshiro128ss(a, b, c, d) {
console.log(`Seeding RNG with [${a}, ${b}, ${c}, ${d}].`)
return function() {
var t = b << 9, r = a * 5; r = (r << 7 | r >>> 25) * 9;
c ^= a; d ^= b;
b ^= c; a ^= d; c ^= t;
d = d << 11 | d >>> 21;
return (r >>> 0) / 4294967296;
}
}
let rand = xoshiro128ss(sys_rand32(), sys_rand32(), sys_rand32(),
sys_rand32());
let bytes = readBinaryFile("test.wasm", "binary");
let mod = new WebAssembly.Module(bytes);
let memory = new LinearMemory({ initial: 2, maximum: 256 });
let imports = { env: memory.env() }
let instance = new WebAssembly.Instance(mod, imports);
let {walloc, wfree} = instance.exports;
for (let j = 0; j < 40; j++) {
let allocs = [];
console.log(`Allocating 2 MB, iteration ${j}.`)
let count = 0;
for (let allocated = 0; allocated < 2e6; count++) {
let size = randu(rand(), 2000);
let free_priority = rand();
let ptr = walloc(size);
memory.record_malloc(ptr, size);
allocs.push([free_priority, ptr]);
allocated += size;
}
console.log(`Freeing ${count} allocations.`)
allocs.sort(([p1,ptr1], [p2,ptr2]) => (p1 - p2));
for (let [p, ptr] of allocs) {
memory.record_free(ptr);
wfree(ptr)
}
}
console.log(`Success.`)