diff options
Diffstat (limited to 'node_modules/@webassemblyjs/helper-module-context/src/index.js')
-rw-r--r-- | node_modules/@webassemblyjs/helper-module-context/src/index.js | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/node_modules/@webassemblyjs/helper-module-context/src/index.js b/node_modules/@webassemblyjs/helper-module-context/src/index.js new file mode 100644 index 0000000..e3171de --- /dev/null +++ b/node_modules/@webassemblyjs/helper-module-context/src/index.js @@ -0,0 +1,287 @@ +// TODO(sven): add flow in here + +import { isSignature, isNumberLiteral } from "@webassemblyjs/ast"; +import { assert } from "mamacro"; + +export function moduleContextFromModuleAST(m) { + const moduleContext = new ModuleContext(); + + assert(m.type === "Module"); + + m.fields.forEach(field => { + switch (field.type) { + case "Start": { + moduleContext.setStart(field.index); + break; + } + case "TypeInstruction": { + moduleContext.addType(field); + break; + } + case "Func": { + moduleContext.addFunction(field); + break; + } + case "Global": { + moduleContext.defineGlobal(field); + break; + } + case "ModuleImport": { + switch (field.descr.type) { + case "GlobalType": { + moduleContext.importGlobal( + field.descr.valtype, + field.descr.mutability + ); + break; + } + case "Memory": { + moduleContext.addMemory( + field.descr.limits.min, + field.descr.limits.max + ); + break; + } + case "FuncImportDescr": { + moduleContext.importFunction(field.descr); + break; + } + + case "Table": { + // FIXME(sven): not implemented yet + break; + } + + default: + throw new Error( + "Unsupported ModuleImport of type " + + JSON.stringify(field.descr.type) + ); + } + break; + } + case "Memory": { + moduleContext.addMemory(field.limits.min, field.limits.max); + break; + } + } + }); + + return moduleContext; +} + +/** + * Module context for type checking + */ +export class ModuleContext { + constructor() { + this.funcs = []; + this.funcsOffsetByIdentifier = []; + + this.types = []; + + this.globals = []; + this.globalsOffsetByIdentifier = []; + + this.mems = []; + + // Current stack frame + this.locals = []; + this.labels = []; + this.return = []; + + this.debugName = "unknown"; + + this.start = null; + } + + /** + * Set start segment + */ + setStart(index) { + this.start = index.value; + } + + /** + * Get start function + */ + getStart() { + return this.start; + } + + /** + * Reset the active stack frame + */ + newContext(debugName, expectedResult) { + this.locals = []; + this.labels = [expectedResult]; + this.return = expectedResult; + this.debugName = debugName; + } + + /** + * Functions + */ + addFunction(func /*: Func*/) { + // eslint-disable-next-line prefer-const + let { params: args = [], results: result = [] } = func.signature || {}; + + args = args.map(arg => arg.valtype); + + this.funcs.push({ args, result }); + + if (typeof func.name !== "undefined") { + this.funcsOffsetByIdentifier[func.name.value] = this.funcs.length - 1; + } + } + + importFunction(funcimport) { + if (isSignature(funcimport.signature)) { + // eslint-disable-next-line prefer-const + let { params: args, results: result } = funcimport.signature; + args = args.map(arg => arg.valtype); + + this.funcs.push({ args, result }); + } else { + assert(isNumberLiteral(funcimport.signature)); + + const typeId = funcimport.signature.value; + assert(this.hasType(typeId)); + + const signature = this.getType(typeId); + this.funcs.push({ + args: signature.params.map(arg => arg.valtype), + result: signature.results + }); + } + + if (typeof funcimport.id !== "undefined") { + // imports are first, we can assume their index in the array + this.funcsOffsetByIdentifier[funcimport.id.value] = this.funcs.length - 1; + } + } + + hasFunction(index) { + return typeof this.getFunction(index) !== "undefined"; + } + + getFunction(index) { + if (typeof index !== "number") { + throw new Error("getFunction only supported for number index"); + } + + return this.funcs[index]; + } + + getFunctionOffsetByIdentifier(name) { + assert(typeof name === "string"); + + return this.funcsOffsetByIdentifier[name]; + } + + /** + * Labels + */ + addLabel(result) { + this.labels.unshift(result); + } + + hasLabel(index) { + return this.labels.length > index && index >= 0; + } + + getLabel(index) { + return this.labels[index]; + } + + popLabel() { + this.labels.shift(); + } + + /** + * Locals + */ + hasLocal(index) { + return typeof this.getLocal(index) !== "undefined"; + } + + getLocal(index) { + return this.locals[index]; + } + + addLocal(type) { + this.locals.push(type); + } + + /** + * Types + */ + addType(type) { + assert(type.functype.type === "Signature"); + this.types.push(type.functype); + } + + hasType(index) { + return this.types[index] !== undefined; + } + + getType(index) { + return this.types[index]; + } + + /** + * Globals + */ + hasGlobal(index) { + return this.globals.length > index && index >= 0; + } + + getGlobal(index) { + return this.globals[index].type; + } + + getGlobalOffsetByIdentifier(name) { + assert(typeof name === "string"); + + return this.globalsOffsetByIdentifier[name]; + } + + defineGlobal(global /*: Global*/) { + const type = global.globalType.valtype; + const mutability = global.globalType.mutability; + + this.globals.push({ type, mutability }); + + if (typeof global.name !== "undefined") { + this.globalsOffsetByIdentifier[global.name.value] = + this.globals.length - 1; + } + } + + importGlobal(type, mutability) { + this.globals.push({ type, mutability }); + } + + isMutableGlobal(index) { + return this.globals[index].mutability === "var"; + } + + isImmutableGlobal(index) { + return this.globals[index].mutability === "const"; + } + + /** + * Memories + */ + hasMemory(index) { + return this.mems.length > index && index >= 0; + } + + addMemory(min, max) { + this.mems.push({ min, max }); + } + + getMemory(index) { + return this.mems[index]; + } +} |