Skip to content

Commit

Permalink
feat: support some extended name subsections
Browse files Browse the repository at this point in the history
This adds initial support for extended "name" subsections, including
type, table, memory, and global names. While the proposal is currently
at Stage 1 only, it's already being implemented in Binaryen and thus
in Emscripten as well as wabt, so it makes sense to support this early
on.

As a drive-by-fix, this also removes some of the code duplication that
we had in the `NameSectionNameResolver` and the `DevToolsNameResolver`
classes.

Bug: https://crbug.com/1137335
Proposal: https://github.com/WebAssembly/extended-name-section
  • Loading branch information
bmeurer committed Oct 13, 2020
1 parent 4613c28 commit d3efc60
Show file tree
Hide file tree
Showing 3 changed files with 597 additions and 116 deletions.
296 changes: 187 additions & 109 deletions src/WasmDis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ import {
NULL_FUNCTION_INDEX,
isTypeIndex,
ILocalNameEntry,
ITypeNameEntry,
ITableNameEntry,
IMemoryNameEntry,
IGlobalNameEntry,
} from "./WasmParser.js";

const NAME_SECTION_NAME = "name";
Expand Down Expand Up @@ -346,68 +350,6 @@ class DevToolsExportMetadata implements IExportMetadata {
}
}

export class DevToolsNameResolver extends DefaultNameResolver {
private readonly _functionNames: string[];
private readonly _localNames: string[][];
private readonly _memoryNames: string[];
private readonly _tableNames: string[];
private readonly _globalNames: string[];

constructor(
functionNames: string[],
localNames: string[][],
memoryNames: string[],
tableNames: string[],
globalNames: string[]
) {
super();
this._functionNames = functionNames;
this._localNames = localNames;
this._memoryNames = memoryNames;
this._tableNames = tableNames;
this._globalNames = globalNames;
}

public getTableName(index: number, isRef: boolean): string {
const name = this._tableNames[index];
if (!name) return super.getTableName(index, isRef);
return isRef ? `$${name}` : `$${name} (;${index};)`;
}

public getMemoryName(index: number, isRef: boolean): string {
const name = this._memoryNames[index];
if (!name) return super.getMemoryName(index, isRef);
return isRef ? `$${name}` : `$${name} (;${index};)`;
}

public getGlobalName(index: number, isRef: boolean): string {
const name = this._globalNames[index];
if (!name) return super.getGlobalName(index, isRef);
return isRef ? `$${name}` : `$${name} (;${index};)`;
}

public getFunctionName(
index: number,
isImport: boolean,
isRef: boolean
): string {
const name = this._functionNames[index];
if (!name) return super.getFunctionName(index, isImport, isRef);
return isRef ? `$${name}` : `$${name} (;${index};)`;
}

public getVariableName(
funcIndex: number,
index: number,
isRef: boolean
): string {
const name =
this._localNames[funcIndex] && this._localNames[funcIndex][index];
if (!name) return super.getVariableName(funcIndex, index, isRef);
return isRef ? `$${name}` : `$${name} (;${index};)`;
}
}

export class NumericNameResolver implements INameResolver {
public getTypeName(index: number, isRef: boolean): string {
return isRef ? "" + index : `(;${index};)`;
Expand Down Expand Up @@ -1428,22 +1370,69 @@ export class WasmDisassembler {
const UNKNOWN_FUNCTION_PREFIX = "unknown";

class NameSectionNameResolver extends DefaultNameResolver {
private _names: string[];
private _localNames: string[][];
protected readonly _functionNames: string[];
protected readonly _localNames: string[][];
protected readonly _typeNames: string[];
protected readonly _tableNames: string[];
protected readonly _memoryNames: string[];
protected readonly _globalNames: string[];

constructor(names: string[], localNames: string[][]) {
constructor(
functionNames: string[],
localNames: string[][],
typeNames: string[],
tableNames: string[],
memoryNames: string[],
globalNames: string[]
) {
super();
this._names = names;
this._functionNames = functionNames;
this._localNames = localNames;
this._typeNames = typeNames;
this._tableNames = tableNames;
this._memoryNames = memoryNames;
this._globalNames = globalNames;
}

public getTypeName(index: number, isRef: boolean): string {
const name = this._typeNames[index];
if (!name) return super.getTypeName(index, isRef);
return isRef ? `$${name}` : `$${name} (;${index};)`;
}

public getTableName(index: number, isRef: boolean): string {
const name = this._tableNames[index];
if (!name) return super.getTableName(index, isRef);
return isRef ? `$${name}` : `$${name} (;${index};)`;
}

getFunctionName(index: number, isImport: boolean, isRef: boolean): string {
const name = this._names[index];
public getMemoryName(index: number, isRef: boolean): string {
const name = this._memoryNames[index];
if (!name) return super.getMemoryName(index, isRef);
return isRef ? `$${name}` : `$${name} (;${index};)`;
}

public getGlobalName(index: number, isRef: boolean): string {
const name = this._globalNames[index];
if (!name) return super.getGlobalName(index, isRef);
return isRef ? `$${name}` : `$${name} (;${index};)`;
}

public getFunctionName(
index: number,
isImport: boolean,
isRef: boolean
): string {
const name = this._functionNames[index];
if (!name) return `$${UNKNOWN_FUNCTION_PREFIX}${index}`;
return isRef ? `$${name}` : `$${name} (;${index};)`;
}

getVariableName(funcIndex: number, index: number, isRef: boolean): string {
public getVariableName(
funcIndex: number,
index: number,
isRef: boolean
): string {
const name =
this._localNames[funcIndex] && this._localNames[funcIndex][index];
if (!name) return super.getVariableName(funcIndex, index, isRef);
Expand All @@ -1452,21 +1441,16 @@ class NameSectionNameResolver extends DefaultNameResolver {
}

export class NameSectionReader {
private _done: boolean;
private _functionsCount: number;
private _functionImportsCount: number;
private _functionNames: string[];
private _functionLocalNames: string[][];
private _hasNames: boolean;

constructor() {
this._done = false;
this._functionsCount = 0;
this._functionImportsCount = 0;
this._functionNames = null;
this._functionLocalNames = null;
this._hasNames = false;
}
private _done = false;
private _functionsCount = 0;
private _functionImportsCount = 0;
private _functionNames: string[] = null;
private _functionLocalNames: string[][] = null;
private _typeNames: string[] = null;
private _tableNames: string[] = null;
private _memoryNames: string[] = null;
private _globalNames: string[] = null;
private _hasNames = false;

public read(reader: BinaryReader): boolean {
if (this._done)
Expand All @@ -1489,6 +1473,10 @@ export class NameSectionReader {
this._functionImportsCount = 0;
this._functionNames = [];
this._functionLocalNames = [];
this._typeNames = [];
this._tableNames = [];
this._memoryNames = [];
this._globalNames = [];
this._hasNames = false;
break;
case BinaryReaderState.END_SECTION:
Expand Down Expand Up @@ -1518,24 +1506,46 @@ export class NameSectionReader {
this._functionsCount++;
break;
case BinaryReaderState.NAME_SECTION_ENTRY:
var nameInfo = <INameEntry>reader.result;
const nameInfo = <INameEntry>reader.result;
if (nameInfo.type === NameType.Function) {
var functionNameInfo = <IFunctionNameEntry>nameInfo;
functionNameInfo.names.forEach((naming: INaming) => {
this._functionNames[naming.index] = bytesToString(naming.name);
const { names } = <IFunctionNameEntry>nameInfo;
names.forEach(({ index, name }) => {
this._functionNames[index] = bytesToString(name);
});
this._hasNames = true;
} else if (nameInfo.type === NameType.Local) {
var localNameInfo = <ILocalNameEntry>nameInfo;
localNameInfo.funcs.forEach((localName) => {
this._functionLocalNames[localName.index] = [];
localName.locals.forEach((naming: INaming) => {
this._functionLocalNames[localName.index][
naming.index
] = bytesToString(naming.name);
const { funcs } = <ILocalNameEntry>nameInfo;
funcs.forEach(({ index, locals }) => {
const localNames = (this._functionLocalNames[index] = []);
locals.forEach(({ index, name }) => {
localNames[index] = bytesToString(name);
});
});
this._hasNames = true;
} else if (nameInfo.type === NameType.Type) {
const { names } = <ITypeNameEntry>nameInfo;
names.forEach(({ index, name }) => {
this._typeNames[index] = bytesToString(name);
});
this._hasNames = true;
} else if (nameInfo.type === NameType.Table) {
const { names } = <ITableNameEntry>nameInfo;
names.forEach(({ index, name }) => {
this._tableNames[index] = bytesToString(name);
});
this._hasNames = true;
} else if (nameInfo.type === NameType.Memory) {
const { names } = <IMemoryNameEntry>nameInfo;
names.forEach(({ index, name }) => {
this._memoryNames[index] = bytesToString(name);
});
this._hasNames = true;
} else if (nameInfo.type === NameType.Global) {
const { names } = <IGlobalNameEntry>nameInfo;
names.forEach(({ index, name }) => {
this._globalNames[index] = bytesToString(name);
});
this._hasNames = true;
}
break;
default:
Expand Down Expand Up @@ -1575,7 +1585,44 @@ export class NameSectionReader {
usedNameAt[name] = i;
}

return new NameSectionNameResolver(functionNames, this._functionLocalNames);
return new NameSectionNameResolver(
functionNames,
this._functionLocalNames,
this._typeNames,
this._tableNames,
this._memoryNames,
this._globalNames
);
}
}

export class DevToolsNameResolver extends NameSectionNameResolver {
constructor(
functionNames: string[],
localNames: string[][],
typeNames: string[],
tableNames: string[],
memoryNames: string[],
globalNames: string[]
) {
super(
functionNames,
localNames,
typeNames,
tableNames,
memoryNames,
globalNames
);
}

public getFunctionName(
index: number,
isImport: boolean,
isRef: boolean
): string {
const name = this._functionNames[index];
if (!name) return isImport ? `$import${index}` : `$func${index}`;
return isRef ? `$${name}` : `$${name} (;${index};)`;
}
}

Expand All @@ -1589,6 +1636,7 @@ export class DevToolsNameGenerator {
private _functionNames: string[] = null;
private _functionLocalNames: string[][] = null;
private _memoryNames: string[] = null;
private _typeNames: string[] = null;
private _tableNames: string[] = null;
private _globalNames: string[] = null;

Expand Down Expand Up @@ -1646,6 +1694,7 @@ export class DevToolsNameGenerator {
this._functionNames = [];
this._functionLocalNames = [];
this._memoryNames = [];
this._typeNames = [];
this._tableNames = [];
this._globalNames = [];
this._functionExportNames = [];
Expand Down Expand Up @@ -1716,27 +1765,55 @@ export class DevToolsNameGenerator {
}
break;
case BinaryReaderState.NAME_SECTION_ENTRY:
var nameInfo = <INameEntry>reader.result;
const nameInfo = <INameEntry>reader.result;
if (nameInfo.type === NameType.Function) {
var functionNameInfo = <IFunctionNameEntry>nameInfo;
functionNameInfo.names.forEach((naming: INaming) => {
const { names } = <IFunctionNameEntry>nameInfo;
names.forEach(({ index, name }) => {
this._setName(
this._functionNames,
naming.index,
bytesToString(naming.name),
index,
bytesToString(name),
true
);
});
} else if (nameInfo.type === NameType.Local) {
var localNameInfo = <ILocalNameEntry>nameInfo;
localNameInfo.funcs.forEach((localName) => {
this._functionLocalNames[localName.index] = [];
localName.locals.forEach((naming: INaming) => {
this._functionLocalNames[localName.index][
naming.index
] = bytesToString(naming.name);
const { funcs } = <ILocalNameEntry>nameInfo;
funcs.forEach(({ index, locals }) => {
const localNames = (this._functionLocalNames[index] = []);
locals.forEach(({ index, name }) => {
localNames[index] = bytesToString(name);
});
});
} else if (nameInfo.type === NameType.Type) {
const { names } = <ITypeNameEntry>nameInfo;
names.forEach(({ index, name }) => {
this._setName(this._typeNames, index, bytesToString(name), true);
});
} else if (nameInfo.type === NameType.Table) {
const { names } = <ITableNameEntry>nameInfo;
names.forEach(({ index, name }) => {
this._setName(this._tableNames, index, bytesToString(name), true);
});
} else if (nameInfo.type === NameType.Memory) {
const { names } = <IMemoryNameEntry>nameInfo;
names.forEach(({ index, name }) => {
this._setName(
this._memoryNames,
index,
bytesToString(name),
true
);
});
} else if (nameInfo.type === NameType.Global) {
const { names } = <IGlobalNameEntry>nameInfo;
names.forEach(({ index, name }) => {
this._setName(
this._globalNames,
index,
bytesToString(name),
true
);
});
}
break;
case BinaryReaderState.EXPORT_SECTION_ENTRY:
Expand Down Expand Up @@ -1818,8 +1895,9 @@ export class DevToolsNameGenerator {
return new DevToolsNameResolver(
this._functionNames,
this._functionLocalNames,
this._memoryNames,
this._typeNames,
this._tableNames,
this._memoryNames,
this._globalNames
);
}
Expand Down
Loading

0 comments on commit d3efc60

Please sign in to comment.