Skip to content

Commit 7593a90

Browse files
author
Mauro Bringolf
committed
Move isConst into validation, check mutability of globals
1 parent f47b672 commit 7593a90

File tree

10 files changed

+50
-74
lines changed

10 files changed

+50
-74
lines changed

packages/helper-module-context/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ export class ModuleContext {
207207

208208
defineGlobal(global /*: Global*/) {
209209
const type = global.globalType.valtype;
210-
const mutability = global.mutability;
210+
const mutability = global.globalType.mutability;
211211

212212
this.globals.push({ type, mutability });
213213

packages/validation/src/index.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
// @flow
22

33
import importOrderValidate from "./import-order";
4+
import isConst from "./is-const";
45
import typeChecker from "./type-checker";
6+
import { moduleContextFromModuleAST } from "@webassemblyjs/helper-module-context";
57

68
export default function validateAST(ast: Program) {
7-
const errors = [];
8-
9-
errors.push(...importOrderValidate(ast));
10-
errors.push(...typeChecker(ast));
9+
const errors = getValidationErrors(ast);
1110

1211
if (errors.length !== 0) {
1312
const errorMessage = "Validation errors:\n" + errors.join("\n");
@@ -16,7 +15,18 @@ export default function validateAST(ast: Program) {
1615
}
1716
}
1817

19-
export { isConst } from "./is-const";
18+
export function getValidationErrors(ast: Program): Array<string> {
19+
const errors = [];
20+
const moduleContext = moduleContextFromModuleAST(ast.body[0]);
21+
22+
errors.push(...isConst(ast, moduleContext));
23+
errors.push(...importOrderValidate(ast));
24+
errors.push(...typeChecker(ast, moduleContext));
25+
26+
return errors;
27+
}
28+
2029
export { getType, typeEq } from "./type-inference";
30+
export { isConst };
2131

2232
export const stack = typeChecker;
Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// @flow
22

3+
import { traverse } from "@webassemblyjs/ast";
4+
35
/**
46
* Determine if a sequence of instructions form a constant expression
57
*
@@ -8,23 +10,18 @@
810
* TODO(sven): get_global x should check the mutability of x, but we don't have
911
* access to the program at this point.
1012
*/
11-
export function isConst(instrs: Array<Instruction>): boolean {
12-
if (instrs.length === 0) {
13-
return false;
14-
}
15-
16-
return instrs.reduce((acc, instr) => {
17-
// Bailout
18-
if (acc === false) {
19-
return acc;
20-
}
21-
13+
export default function isConst(
14+
ast: Program,
15+
moduleContext: Object
16+
): Array<string> {
17+
function isConstInstruction(instr): boolean {
2218
if (instr.id === "const") {
2319
return true;
2420
}
2521

2622
if (instr.id === "get_global") {
27-
return true;
23+
const index = instr.args[0].value;
24+
return !moduleContext.isMutableGlobal(index);
2825
}
2926

3027
// FIXME(sven): this shoudln't be needed, we need to inject our end
@@ -34,5 +31,21 @@ export function isConst(instrs: Array<Instruction>): boolean {
3431
}
3532

3633
return false;
37-
}, true);
34+
}
35+
36+
const errors = [];
37+
38+
traverse(ast, {
39+
Global(path) {
40+
const isValid = path.node.init.reduce(
41+
(acc, instr) => acc && isConstInstruction(instr),
42+
true
43+
);
44+
if (!isValid) {
45+
errors.push("initializer expression cannot reference mutable global");
46+
}
47+
}
48+
});
49+
50+
return errors;
3851
}

packages/validation/src/type-checker.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { traverse, isInstruction } from "@webassemblyjs/ast";
22

3-
import { moduleContextFromModuleAST } from "@webassemblyjs/helper-module-context";
43
import getType from "./type-checker/get-type.js";
54
import { ANY, POLYMORPHIC } from "./type-checker/types.js";
65

@@ -30,14 +29,11 @@ function checkTypes(a, b) {
3029
}
3130
}
3231

33-
export default function validate(ast) {
32+
export default function validate(ast, moduleContext) {
3433
if (!ast.body || !ast.body[0] || !ast.body[0].fields) {
3534
return [];
3635
}
3736

38-
// Module context
39-
const moduleContext = moduleContextFromModuleAST(ast.body[0]);
40-
4137
errors = [];
4238

4339
// Simulate stack types throughout all function bodies
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
(module
22
(global (mut i32) (i32.const 1))
33
(global i32 (get_global 0))
4+
5+
(global i32 (i32.const 0))
6+
(global i32 (get_global 1))
47
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
initializer expression cannot reference mutable global

packages/validation/test/fixtures/global-initilizer/output.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/validation/test/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ describe("validation", () => {
2222

2323
describe("wast", () => {
2424
const pre = f => {
25-
const errors = validations.stack(parse(f));
25+
const errors = validations.getValidationErrors(parse(f));
2626

2727
return errorsToString(errors);
2828
};
@@ -35,7 +35,7 @@ describe("validation", () => {
3535
const module = wabt.parseWat(suite, f);
3636
const { buffer } = module.toBinary({ write_debug_names: false });
3737

38-
const errors = validations.stack(decode(buffer));
38+
const errors = validations.getValidationErrors(decode(buffer));
3939

4040
return errorsToString(errors);
4141
};

packages/validation/test/is-const.js

Lines changed: 0 additions & 42 deletions
This file was deleted.

packages/webassemblyjs/src/interpreter/runtime/values/global.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @flow
22

3-
import { isConst, getType, typeEq } from "@webassemblyjs/validation";
3+
import { getType, typeEq } from "@webassemblyjs/validation";
44

55
const { evaluate } = require("../../partial-evaluation");
66
const { CompileError } = require("../../../errors");
@@ -12,10 +12,6 @@ export function createInstance(
1212
let value;
1313
const { valtype, mutability } = node.globalType;
1414

15-
if (node.init.length > 0 && isConst(node.init) === false) {
16-
throw new CompileError("constant expression required");
17-
}
18-
1915
// None or multiple constant expressions in the initializer seems not possible
2016
// TODO(sven): find a specification reference for that
2117
// FIXME(sven): +1 because of the implicit end, change the order of validations

0 commit comments

Comments
 (0)