Files: 8fb216c62276f508a5fd349383be046d162baaa7 / injectGettersSetters.js
6737 bytesRaw
1 | const leb128 = require('leb128').unsigned |
2 | const Pipe = require('buffer-pipe') |
3 | const {Iterator, json2wasm} = require('wasm-json-toolkit') |
4 | |
5 | const EXTERNAL_KIND = json2wasm.EXTERNAL_KIND |
6 | |
7 | module.exports = function prepare (wasm, include, symbol) { |
8 | let globalI64SetterIndex, globalI32SetterIndex, globalGetterIndex, funcSection |
9 | let numOfFuncs = 0 |
10 | let numOfImports = 0 |
11 | const addedCodeEntries = [] |
12 | const globalsGetterSetters = [] |
13 | |
14 | const needExporting = { |
15 | 'function': [], |
16 | 'global': [] |
17 | } |
18 | |
19 | const it = new Iterator(wasm) |
20 | |
21 | for (const section of it) { |
22 | if (section.type === 'type') { |
23 | const numOfTypes = section.count |
24 | // form: func, 1 param, i32, no return |
25 | const globalI32SetterType = Buffer.from([0x60, 0x01, 0x7f, 0x0]) |
26 | // form: func, 2 param, i32, i32, no return |
27 | const globalI64SetterType = Buffer.from([0x60, 0x02, 0x7f, 0x7f, 0x0]) |
28 | // form: func, 0 param, i32, 1 return |
29 | const globalGetterType = Buffer.from([0x60, 0x00, 0x1, 0x7f]) |
30 | section.appendEntries([globalI32SetterType, globalI64SetterType, globalGetterType]) |
31 | |
32 | globalI32SetterIndex = leb128.encode(numOfTypes) |
33 | globalI64SetterIndex = leb128.encode(numOfTypes + 1) |
34 | globalGetterIndex = leb128.encode(numOfTypes + 2) |
35 | } else if (section.type === 'import') { |
36 | // parse the import section to build the function indexes |
37 | const json = section.toJSON() |
38 | numOfImports = json.entries.filter(entry => entry.kind === 'function').length |
39 | } else if (section.type === 'function') { |
40 | // mark functions to be exported |
41 | numOfFuncs = section.count |
42 | funcSection = section |
43 | needExporting['function'] = Array(section.count).fill(true) |
44 | } else if (section.type === 'table') { |
45 | needExporting['table'] = true && include.table |
46 | } else if (section.type === 'memory') { |
47 | needExporting['memory'] = true && include.memory |
48 | } else if (section.type === 'global') { |
49 | const json = section.toJSON() |
50 | const addedFuncs = [] |
51 | if (!include.globals) { |
52 | include.globals = new Array(json.entries.length).fill(true) |
53 | } |
54 | for (const i in json.entries) { |
55 | const type = json.entries[i].type |
56 | const lebIndex = leb128.encode(i) |
57 | if (type.mutability && include.globals[i]) { |
58 | if (type.contentType === 'i32') { |
59 | globalsGetterSetters.push(type.contentType) |
60 | addedFuncs.push(globalGetterIndex) |
61 | addedFuncs.push(globalI32SetterIndex) |
62 | // getter |
63 | // size, local count, get_global, index, end |
64 | addedCodeEntries.push(Buffer.concat([ |
65 | Buffer.from([0x03 + lebIndex.length, 0x00, 0x23]), |
66 | lebIndex, |
67 | Buffer.from([0x0b]) |
68 | ])) |
69 | // setter |
70 | // size, local count, get_local, index , set_global, index, end |
71 | addedCodeEntries.push(Buffer.concat([ |
72 | Buffer.from([0x05 + lebIndex.length, 0x00, 0x20, 0x0, 0x24]), |
73 | lebIndex, |
74 | Buffer.from([0x0b]) |
75 | ])) |
76 | } else { |
77 | globalsGetterSetters.push(type.contentType) |
78 | addedFuncs.push(globalGetterIndex) |
79 | addedFuncs.push(globalGetterIndex) |
80 | addedFuncs.push(globalI64SetterIndex) |
81 | // 64 bit |
82 | // getter high |
83 | addedCodeEntries.push(Buffer.concat([ |
84 | Buffer.from([0x07 + lebIndex.length, 0x00, 0x23]), |
85 | lebIndex, |
86 | Buffer.from([0x42, 0x20, 0x88, 0xa7, 0x0b]) |
87 | ])) |
88 | |
89 | // get low |
90 | addedCodeEntries.push(Buffer.concat([ |
91 | Buffer.from([0x04 + lebIndex.length, 0x00, 0x23]), |
92 | lebIndex, |
93 | Buffer.from([0xa7, 0x0b]) |
94 | ])) |
95 | // (set_global $b |
96 | // (i64.add |
97 | // (i64.shl (i64.extend_u/i32 (get_local 0)) (i64.const 32)) |
98 | // (i64.extend_u/i32 (get_local 1)))) |
99 | // setter |
100 | addedCodeEntries.push(Buffer.concat([ |
101 | Buffer.from([0x0d + lebIndex.length, 0x00, 0x20, 0x01, 0xad, 0x42, 0x20, 0x86, 0x20, 0x00, 0xad, 0x7c, 0x24]), |
102 | lebIndex, |
103 | Buffer.from([0x0b]) |
104 | ])) |
105 | } |
106 | } |
107 | } |
108 | funcSection.appendEntries(addedFuncs) |
109 | } else if (section.type === 'export') { |
110 | // export the memory |
111 | const addedExports = [] |
112 | if (needExporting['memory']) { |
113 | const funcExp = generateFuncExport(`${symbol}memory`, 0, 'memory') |
114 | addedExports.push(funcExp) |
115 | } |
116 | |
117 | // export the table |
118 | if (needExporting['table']) { |
119 | const funcExp = generateFuncExport(`${symbol}table`, 0, 'table') |
120 | addedExports.push(funcExp) |
121 | } |
122 | |
123 | // export functions |
124 | const funcs = needExporting['function'] |
125 | for (let index in funcs) { |
126 | index = Number(index) |
127 | const funcExp = generateFuncExport(`${symbol}func_${index + numOfImports}`, numOfImports + index, 'function') |
128 | addedExports.push(funcExp) |
129 | } |
130 | |
131 | // export globals |
132 | let globalFuncIndex = 0 |
133 | for (let index in globalsGetterSetters) { |
134 | const type = globalsGetterSetters[index] |
135 | const funcIndex = numOfImports + numOfFuncs + globalFuncIndex |
136 | if (type === 'i32') { |
137 | // getter |
138 | const getter = generateFuncExport(`${symbol}global_getter_${type}_${index}`, funcIndex, 'function') |
139 | addedExports.push(getter) |
140 | |
141 | // setter |
142 | const setter = generateFuncExport(`${symbol}global_setter_${type}_${index}`, funcIndex + 1, 'function') |
143 | addedExports.push(setter) |
144 | globalFuncIndex += 2 |
145 | } else { |
146 | // i64s |
147 | // setter high |
148 | const setterHigh = generateFuncExport(`${symbol}global_getter_${type}_${index}_high`, funcIndex, 'function') |
149 | addedExports.push(setterHigh) |
150 | // setter Low |
151 | const setterLow = generateFuncExport(`${symbol}global_getter_${type}_${index}_low`, funcIndex + 1, 'function') |
152 | addedExports.push(setterLow) |
153 | // getter |
154 | const getter = generateFuncExport(`${symbol}global_setter_${type}_${index}`, funcIndex + 2, 'function') |
155 | addedExports.push(getter) |
156 | globalFuncIndex += 3 |
157 | } |
158 | } |
159 | section.appendEntries(addedExports) |
160 | } else if (section.type === 'code') { |
161 | section.appendEntries(addedCodeEntries) |
162 | } |
163 | } |
164 | return it.wasm |
165 | } |
166 | |
167 | function generateFuncExport (name, index, type) { |
168 | const setterHigh = new Pipe() |
169 | const fieldString = Buffer.from(name) |
170 | leb128.write(fieldString.length, setterHigh) |
171 | setterHigh.write(fieldString) |
172 | setterHigh.write(Buffer.from([EXTERNAL_KIND[type]])) |
173 | leb128.write(index, setterHigh) |
174 | return setterHigh.buffer |
175 | } |
176 |
Built with git-ssb-web