Skip to content

Commit

Permalink
feat: implement exnref type and try_table opcode. (#141)
Browse files Browse the repository at this point in the history
  • Loading branch information
yurydelendik authored Mar 14, 2024
1 parent 2c12c8e commit 5aa20fd
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 18 deletions.
43 changes: 40 additions & 3 deletions src/WasmDis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
IFieldNameEntry,
ElementMode,
RefType,
CatchHandlerKind,
} from "./WasmParser.js";

const NAME_SECTION_NAME = "name";
Expand Down Expand Up @@ -301,7 +302,7 @@ export class DefaultNameResolver implements INameResolver {
return `$elem${index}`;
}
public getTagName(index: number, isRef: boolean): string {
return `$event${index}`;
return `$tag${index}`;
}
public getFunctionName(
index: number,
Expand Down Expand Up @@ -577,6 +578,8 @@ export class WasmDisassembler {
return "eq";
case TypeKind.i31ref:
return "i31";
case TypeKind.exnref:
return "exnref";
case TypeKind.structref:
return "struct";
case TypeKind.arrayref:
Expand All @@ -587,6 +590,8 @@ export class WasmDisassembler {
return "noextern";
case TypeKind.nullref:
return "none";
case TypeKind.nullexnref:
return "noexnref";
}
}
private typeToString(type: Type): string {
Expand All @@ -609,6 +614,8 @@ export class WasmDisassembler {
return "funcref";
case TypeKind.externref:
return "externref";
case TypeKind.exnref:
return "exnref";
case TypeKind.anyref:
return "anyref";
case TypeKind.eqref:
Expand All @@ -623,6 +630,8 @@ export class WasmDisassembler {
return "nullfuncref";
case TypeKind.nullexternref:
return "nullexternref";
case TypeKind.nullexnref:
return "nullexnref";
case TypeKind.nullref:
return "nullref";
case TypeKind.ref:
Expand Down Expand Up @@ -754,6 +763,7 @@ export class WasmDisassembler {
case OperatorCode.loop:
case OperatorCode.if:
case OperatorCode.try:
case OperatorCode.try_table:
if (this._labelMode !== LabelMode.Depth) {
const backrefLabel = {
line: this._lines.length,
Expand All @@ -774,6 +784,34 @@ export class WasmDisassembler {
this._backrefLabels.push(backrefLabel);
}
this.printBlockType(operator.blockType);
if (operator.tryTable) {
for (var i = 0; i < operator.tryTable.length; i++) {
this.appendBuffer(" (");
switch (operator.tryTable[i].kind) {
case CatchHandlerKind.Catch:
this.appendBuffer("catch ");
break;
case CatchHandlerKind.CatchRef:
this.appendBuffer("catch_ref ");
break;
case CatchHandlerKind.CatchAll:
this.appendBuffer("catch_all ");
break;
case CatchHandlerKind.CatchAllRef:
this.appendBuffer("catch_all_ref ");
break;
}
if (operator.tryTable[i].tagIndex != null) {
var tagName = this._nameResolver.getTagName(
operator.tryTable[i].tagIndex,
true
);
this.appendBuffer(`${tagName} `);
}
this.appendBuffer(this.useLabel(operator.tryTable[i].depth + 1));
this.appendBuffer(")");
}
}
break;
case OperatorCode.end:
if (this._labelMode === LabelMode.Depth) {
Expand Down Expand Up @@ -1715,7 +1753,6 @@ export class WasmDisassembler {
case OperatorCode.else:
case OperatorCode.catch:
case OperatorCode.catch_all:
case OperatorCode.unwind:
case OperatorCode.delegate:
this.decreaseIndent();
break;
Expand All @@ -1729,9 +1766,9 @@ export class WasmDisassembler {
case OperatorCode.loop:
case OperatorCode.else:
case OperatorCode.try:
case OperatorCode.try_table:
case OperatorCode.catch:
case OperatorCode.catch_all:
case OperatorCode.unwind:
this.increaseIndent();
break;
}
Expand Down
64 changes: 60 additions & 4 deletions src/WasmParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const enum OperatorCode {
catch = 0x07,
throw = 0x08,
rethrow = 0x09,
unwind = 0x0a,
throw_ref = 0x0a,
end = 0x0b,
br = 0x0c,
br_if = 0x0d,
Expand All @@ -63,6 +63,7 @@ export const enum OperatorCode {
drop = 0x1a,
select = 0x1b,
select_with_type = 0x1c,
try_table = 0x1f,
local_get = 0x20,
local_set = 0x21,
local_tee = 0x22,
Expand Down Expand Up @@ -636,7 +637,7 @@ export const OperatorCodeNames = [
"catch",
"throw",
"rethrow",
"unwind",
"throw_ref",
"end",
"br",
"br_if",
Expand All @@ -657,7 +658,7 @@ export const OperatorCodeNames = [
"select", // with types.
undefined,
undefined,
undefined,
"try_table",
"local.get",
"local.set",
"local.tee",
Expand Down Expand Up @@ -1324,6 +1325,7 @@ export const enum TypeKind {
v128 = -0x05,
i8 = -0x08,
i16 = -0x09,
nullexnref = -0x0c,
nullfuncref = -0x0d,
nullref = -0x0f,
nullexternref = -0x0e,
Expand All @@ -1334,6 +1336,7 @@ export const enum TypeKind {
i31ref = -0x14,
structref = -0x15,
arrayref = -0x16,
exnref = -0x17,
ref = -0x1c,
ref_null = -0x1d,
func = -0x20,
Expand Down Expand Up @@ -1369,6 +1372,7 @@ export class Type {
// Convenience singletons.
static funcref: Type = new Type(TypeKind.funcref);
static externref: Type = new Type(TypeKind.externref);
static exnref: Type = new Type(TypeKind.exnref);
}
export class RefType extends Type {
public ref_index: number;
Expand All @@ -1384,6 +1388,18 @@ export class RefType extends Type {
}
}

export enum CatchHandlerKind {
Catch = 0,
CatchRef = 1,
CatchAll = 2,
CatchAllRef = 3,
}
export class CatchHandler {
kind: CatchHandlerKind;
depth: number;
tagIndex?: number;
}

export const enum RelocType {
FunctionIndex_LEB = 0,
TableIndex_SLEB = 1,
Expand Down Expand Up @@ -1703,6 +1719,7 @@ export interface IOperatorInformation {
srcType?: number; // "HeapType" format, a.k.a. s33
brDepth?: number;
brTable?: Array<number>;
tryTable?: Array<CatchHandler>;
relativeDepth?: number;
funcIndex?: number;
typeIndex?: number;
Expand Down Expand Up @@ -1974,11 +1991,13 @@ export class BinaryReader {
case TypeKind.i16:
case TypeKind.funcref:
case TypeKind.externref:
case TypeKind.exnref:
case TypeKind.anyref:
case TypeKind.eqref:
case TypeKind.i31ref:
case TypeKind.nullexternref:
case TypeKind.nullfuncref:
case TypeKind.nullexnref:
case TypeKind.structref:
case TypeKind.arrayref:
case TypeKind.nullref:
Expand Down Expand Up @@ -2146,6 +2165,7 @@ export class BinaryReader {
case TypeKind.i16:
case TypeKind.funcref:
case TypeKind.externref:
case TypeKind.exnref:
case TypeKind.anyref:
case TypeKind.eqref:
this.result = {
Expand Down Expand Up @@ -3294,6 +3314,7 @@ export class BinaryReader {
refType,
brDepth,
brTable,
tryTable,
relativeDepth,
funcIndex,
typeIndex,
Expand Down Expand Up @@ -3366,6 +3387,40 @@ export class BinaryReader {
case OperatorCode.throw:
tagIndex = this.readVarInt32();
break;
case OperatorCode.try_table:
blockType = this.readType();
var tableCount = this.readVarUint32();
if (!this.hasBytes(2 * tableCount)) {
// We need at least (2 * tableCount) bytes
this._pos = pos;
return false;
}
tryTable = [];
for (var i = 0; i < tableCount; i++) {
if (!this.hasVarIntBytes()) {
this._pos = pos;
return false;
}
var kind = this.readVarUint32();
var tagIndex;
if (
kind == CatchHandlerKind.Catch ||
kind == CatchHandlerKind.CatchRef
) {
if (!this.hasVarIntBytes()) {
this._pos = pos;
return false;
}
tagIndex = this.readVarUint32();
}
if (!this.hasVarIntBytes()) {
this._pos = pos;
return false;
}
var depth = this.readVarUint32();
tryTable.push({ kind, depth, tagIndex });
}
break;
case OperatorCode.ref_null:
refType = this.readHeapType();
break;
Expand Down Expand Up @@ -3479,7 +3534,6 @@ export class BinaryReader {
case OperatorCode.unreachable:
case OperatorCode.nop:
case OperatorCode.else:
case OperatorCode.unwind:
case OperatorCode.end:
case OperatorCode.return:
case OperatorCode.catch_all:
Expand Down Expand Up @@ -3616,6 +3670,7 @@ export class BinaryReader {
case OperatorCode.ref_is_null:
case OperatorCode.ref_as_non_null:
case OperatorCode.ref_eq:
case OperatorCode.throw_ref:
break;
default:
this.error = new Error(`Unknown operator: ${code}`);
Expand All @@ -3631,6 +3686,7 @@ export class BinaryReader {
srcType: undefined,
brDepth,
brTable,
tryTable,
relativeDepth,
tableIndex,
funcIndex,
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export {
OperatorCodeNames,
ExternalKind,
Type,
CatchHandlerKind,
CatchHandler,
RelocType,
LinkingType,
NameType,
Expand Down
22 changes: 11 additions & 11 deletions test/WasmDis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ describe("DevToolsNameGenerator", () => {
const nr = ng.getNameResolver();
expect(nr.getTagName(0, true)).toBe("$ex");
expect(nr.getTagName(0, false)).toBe("$ex (;0;)");
expect(nr.getTagName(1, true)).toBe("$event1");
expect(nr.getTagName(1, false)).toBe("$event1");
expect(nr.getTagName(1, true)).toBe("$tag1");
expect(nr.getTagName(1, false)).toBe("$tag1");
});
});

Expand Down Expand Up @@ -1596,26 +1596,26 @@ describe("Exception handling support", () => {

const expectedLines = [
"(module",
' (tag $event0 (import "m" "ex"))',
" (tag $event1 (param i32))",
' (export "ex" (tag $event0))',
' (tag $tag0 (import "m" "ex"))',
" (tag $tag1 (param i32))",
' (export "ex" (tag $tag0))',
" (func $func0 (param $var0 i32) (result i32)",
" try $label0 (result i32)",
" throw $event0",
" catch $event0",
" throw $tag0",
" catch $tag0",
" i32.const 0",
" catch $event1",
" catch $tag1",
" catch_all",
" rethrow $label0",
" end $label0",
" try",
" throw $event0",
" throw $tag0",
" delegate 0",
" try $label1",
" try",
" throw $event0",
" throw $tag0",
" delegate $label1",
" catch $event0",
" catch $tag0",
" end",
" )",
")",
Expand Down
Binary file added test/__fixtures__/exnref.wasm
Binary file not shown.
32 changes: 32 additions & 0 deletions test/__snapshots__/parse-and-disassemble.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4249,6 +4249,38 @@ exports[`Parsing and disassembling endianness.wast.0.wasm generates expected out
"
`;

exports[`Parsing and disassembling exnref.wasm generates expected output 1`] = `
"(module
(tag $tag0)
(export "test" (func $func0))
(func $func0 (param $var0 i32) (result i32)
(local $var1 exnref)
block $label0 (result exnref)
try_table (catch_ref $tag0 $label0)
throw $tag0
end
unreachable
end $label0
local.set $var1
block $label1 (result exnref)
try_table (result i32) (catch_ref $tag0 $label1)
local.get $var0
i32.eqz
if
local.get $var1
throw_ref
end
i32.const 2
end
return
end $label1
drop
i32.const 1
)
)
"
`;

exports[`Parsing and disassembling exports.wast.0.wasm generates expected output 1`] = `
"(module
(export "a" (func $func0))
Expand Down
Loading

0 comments on commit 5aa20fd

Please sign in to comment.