Page MenuHomec4science

index.js
No OneTemporary

File Metadata

Created
Mon, Oct 14, 14:02

index.js

// 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];
}
}

Event Timeline