Projekt

Obecné

Profil

Stáhnout (5.79 KB) Statistiky
| Větev: | Revize:
1
// TODO(sven): add flow in here
2

    
3
import { isSignature, isNumberLiteral } from "@webassemblyjs/ast";
4
import { assert } from "mamacro";
5

    
6
export function moduleContextFromModuleAST(m) {
7
  const moduleContext = new ModuleContext();
8

    
9
  assert(m.type === "Module");
10

    
11
  m.fields.forEach(field => {
12
    switch (field.type) {
13
      case "Start": {
14
        moduleContext.setStart(field.index);
15
        break;
16
      }
17
      case "TypeInstruction": {
18
        moduleContext.addType(field);
19
        break;
20
      }
21
      case "Func": {
22
        moduleContext.addFunction(field);
23
        break;
24
      }
25
      case "Global": {
26
        moduleContext.defineGlobal(field);
27
        break;
28
      }
29
      case "ModuleImport": {
30
        switch (field.descr.type) {
31
          case "GlobalType": {
32
            moduleContext.importGlobal(
33
              field.descr.valtype,
34
              field.descr.mutability
35
            );
36
            break;
37
          }
38
          case "Memory": {
39
            moduleContext.addMemory(
40
              field.descr.limits.min,
41
              field.descr.limits.max
42
            );
43
            break;
44
          }
45
          case "FuncImportDescr": {
46
            moduleContext.importFunction(field.descr);
47
            break;
48
          }
49

    
50
          case "Table": {
51
            // FIXME(sven): not implemented yet
52
            break;
53
          }
54

    
55
          default:
56
            throw new Error(
57
              "Unsupported ModuleImport of type " +
58
                JSON.stringify(field.descr.type)
59
            );
60
        }
61
        break;
62
      }
63
      case "Memory": {
64
        moduleContext.addMemory(field.limits.min, field.limits.max);
65
        break;
66
      }
67
    }
68
  });
69

    
70
  return moduleContext;
71
}
72

    
73
/**
74
 * Module context for type checking
75
 */
76
export class ModuleContext {
77
  constructor() {
78
    this.funcs = [];
79
    this.funcsOffsetByIdentifier = [];
80

    
81
    this.types = [];
82

    
83
    this.globals = [];
84
    this.globalsOffsetByIdentifier = [];
85

    
86
    this.mems = [];
87

    
88
    // Current stack frame
89
    this.locals = [];
90
    this.labels = [];
91
    this.return = [];
92

    
93
    this.debugName = "unknown";
94

    
95
    this.start = null;
96
  }
97

    
98
  /**
99
   * Set start segment
100
   */
101
  setStart(index) {
102
    this.start = index.value;
103
  }
104

    
105
  /**
106
   * Get start function
107
   */
108
  getStart() {
109
    return this.start;
110
  }
111

    
112
  /**
113
   * Reset the active stack frame
114
   */
115
  newContext(debugName, expectedResult) {
116
    this.locals = [];
117
    this.labels = [expectedResult];
118
    this.return = expectedResult;
119
    this.debugName = debugName;
120
  }
121

    
122
  /**
123
   * Functions
124
   */
125
  addFunction(func /*: Func*/) {
126
    // eslint-disable-next-line prefer-const
127
    let { params: args = [], results: result = [] } = func.signature || {};
128

    
129
    args = args.map(arg => arg.valtype);
130

    
131
    this.funcs.push({ args, result });
132

    
133
    if (typeof func.name !== "undefined") {
134
      this.funcsOffsetByIdentifier[func.name.value] = this.funcs.length - 1;
135
    }
136
  }
137

    
138
  importFunction(funcimport) {
139
    if (isSignature(funcimport.signature)) {
140
      // eslint-disable-next-line prefer-const
141
      let { params: args, results: result } = funcimport.signature;
142
      args = args.map(arg => arg.valtype);
143

    
144
      this.funcs.push({ args, result });
145
    } else {
146
      assert(isNumberLiteral(funcimport.signature));
147

    
148
      const typeId = funcimport.signature.value;
149
      assert(this.hasType(typeId));
150

    
151
      const signature = this.getType(typeId);
152
      this.funcs.push({
153
        args: signature.params.map(arg => arg.valtype),
154
        result: signature.results
155
      });
156
    }
157

    
158
    if (typeof funcimport.id !== "undefined") {
159
      // imports are first, we can assume their index in the array
160
      this.funcsOffsetByIdentifier[funcimport.id.value] = this.funcs.length - 1;
161
    }
162
  }
163

    
164
  hasFunction(index) {
165
    return typeof this.getFunction(index) !== "undefined";
166
  }
167

    
168
  getFunction(index) {
169
    if (typeof index !== "number") {
170
      throw new Error("getFunction only supported for number index");
171
    }
172

    
173
    return this.funcs[index];
174
  }
175

    
176
  getFunctionOffsetByIdentifier(name) {
177
    assert(typeof name === "string");
178

    
179
    return this.funcsOffsetByIdentifier[name];
180
  }
181

    
182
  /**
183
   * Labels
184
   */
185
  addLabel(result) {
186
    this.labels.unshift(result);
187
  }
188

    
189
  hasLabel(index) {
190
    return this.labels.length > index && index >= 0;
191
  }
192

    
193
  getLabel(index) {
194
    return this.labels[index];
195
  }
196

    
197
  popLabel() {
198
    this.labels.shift();
199
  }
200

    
201
  /**
202
   * Locals
203
   */
204
  hasLocal(index) {
205
    return typeof this.getLocal(index) !== "undefined";
206
  }
207

    
208
  getLocal(index) {
209
    return this.locals[index];
210
  }
211

    
212
  addLocal(type) {
213
    this.locals.push(type);
214
  }
215

    
216
  /**
217
   * Types
218
   */
219
  addType(type) {
220
    assert(type.functype.type === "Signature");
221
    this.types.push(type.functype);
222
  }
223

    
224
  hasType(index) {
225
    return this.types[index] !== undefined;
226
  }
227

    
228
  getType(index) {
229
    return this.types[index];
230
  }
231

    
232
  /**
233
   * Globals
234
   */
235
  hasGlobal(index) {
236
    return this.globals.length > index && index >= 0;
237
  }
238

    
239
  getGlobal(index) {
240
    return this.globals[index].type;
241
  }
242

    
243
  getGlobalOffsetByIdentifier(name) {
244
    assert(typeof name === "string");
245

    
246
    return this.globalsOffsetByIdentifier[name];
247
  }
248

    
249
  defineGlobal(global /*: Global*/) {
250
    const type = global.globalType.valtype;
251
    const mutability = global.globalType.mutability;
252

    
253
    this.globals.push({ type, mutability });
254

    
255
    if (typeof global.name !== "undefined") {
256
      this.globalsOffsetByIdentifier[global.name.value] =
257
        this.globals.length - 1;
258
    }
259
  }
260

    
261
  importGlobal(type, mutability) {
262
    this.globals.push({ type, mutability });
263
  }
264

    
265
  isMutableGlobal(index) {
266
    return this.globals[index].mutability === "var";
267
  }
268

    
269
  isImmutableGlobal(index) {
270
    return this.globals[index].mutability === "const";
271
  }
272

    
273
  /**
274
   * Memories
275
   */
276
  hasMemory(index) {
277
    return this.mems.length > index && index >= 0;
278
  }
279

    
280
  addMemory(min, max) {
281
    this.mems.push({ min, max });
282
  }
283

    
284
  getMemory(index) {
285
    return this.mems[index];
286
  }
287
}
    (1-1/1)