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