[dart2wasm] Simplify handling of name section
Currently the IR has some serialization information attached to it (e.g.
it keeps track of the number of types that have names, etc).
This is redundant/derived information as it can be computed by looking
at the actual IR (e.g. iterate types and count the number of them that
have names).
=> We get rid of this impurity by making the serializer compute the
information it needs to serialize.
I suspect it has been done as an optimization, to avoid an extra pass
over the IR data structures. But this can be handled in another way
witout extra passes as well:
* a single pass traverses and writes the (index, name) pairs
* it keeps track of the number of (index, name) pairs written
* if the number is > 0 then we add the section, the count and the pairs
We do have to traverse all the functions, types, ..., at least once now,
but that's fine: Firstly we always assign names so in reality we cannot
skip these traversals (we instruct binaryen to emit or skip the names
when it runs). Secondly if we wanted to have core dart2wasm not emit
name section we can just skip serializing it if e.g. a
`--no-name-section` flag was passed.
We do a few more changes in this CL:
* We make `ir.DefType.name` be an optional string
=> This aligns it with `ir.Global.globalName`, `ir.BaseFunction.name`,
...
* Only assign `localNames[local] = ...` and `fieldNames[field] ` ...`
if name is not empty string
* We put the `sourceMapUrl` section behind the name section (to align
with the order used in binaryen)
* We remove redundancy in the section serializer: Instead of having
`isEmpty` that has to be kept in sync with `serializeContents` we
only have `serializeContents` and make the caller check if the bytes
are non empty.
Issue https://github.com/dart-lang/sdk/issues/60928
Change-Id: Ie9d153fefc25e8277fb30b83e45d2549731797c4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/452040
Reviewed-by: Ömer Ağacan <omersa@google.com>
diff --git a/pkg/dart2wasm/lib/class_info.dart b/pkg/dart2wasm/lib/class_info.dart
index cc76db6..f113eed 100644
--- a/pkg/dart2wasm/lib/class_info.dart
+++ b/pkg/dart2wasm/lib/class_info.dart
@@ -208,7 +208,7 @@
{int? expectedIndex, String? fieldName}) {
assert(expectedIndex == null || expectedIndex == struct.fields.length);
struct.fields.add(fieldType);
- if (fieldName != null) {
+ if (fieldName != null && fieldName.isNotEmpty) {
final fieldIndex = struct.fields.length - 1;
struct.fieldNames[fieldIndex] = fieldName;
}
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 8dfe0b6..264286e 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -259,7 +259,7 @@
final localIndex = implicitParams + index;
w.Local local = paramLocals[localIndex];
final variableName = variable.name;
- if (variableName != null) {
+ if (variableName != null && variableName.isNotEmpty) {
b.localNames[local.index] = variableName;
}
if (defaultValue == ParameterInfo.defaultValueSentinel) {
diff --git a/pkg/wasm_builder/lib/src/builder/functions.dart b/pkg/wasm_builder/lib/src/builder/functions.dart
index 9852b5f..22bbe19 100644
--- a/pkg/wasm_builder/lib/src/builder/functions.dart
+++ b/pkg/wasm_builder/lib/src/builder/functions.dart
@@ -12,7 +12,6 @@
final _functionBuilders = <FunctionBuilder>[];
final _importedFunctions = <ir.ImportedFunction>[];
final _declaredFunctions = <ir.BaseFunction>{};
- int _nameCount = 0;
ir.BaseFunction? _start;
FunctionsBuilder(this._moduleBuilder);
@@ -22,12 +21,6 @@
_start = init;
}
- void _addName(String? name, ir.BaseFunction function) {
- if (name != null) {
- _nameCount++;
- }
- }
-
void collectUsedTypes(Set<ir.DefType> usedTypes) {
for (final f in _functionBuilders) {
usedTypes.add(f.type);
@@ -46,7 +39,6 @@
final function =
FunctionBuilder(_moduleBuilder, ir.FinalizableIndex(), type, name);
_functionBuilders.add(function);
- _addName(name, function);
return function;
}
@@ -56,7 +48,6 @@
final function = ir.ImportedFunction(_moduleBuilder.module, module, name,
ir.FinalizableIndex(), type, functionName);
_importedFunctions.add(function);
- _addName(functionName, function);
return function;
}
@@ -72,6 +63,6 @@
final built = finalizeImportsAndBuilders<ir.DefinedFunction>(
_importedFunctions, _functionBuilders);
return ir.Functions(
- _start, _importedFunctions, built, [..._declaredFunctions], _nameCount);
+ _start, _importedFunctions, built, [..._declaredFunctions]);
}
}
diff --git a/pkg/wasm_builder/lib/src/builder/globals.dart b/pkg/wasm_builder/lib/src/builder/globals.dart
index 859f704..35019f0 100644
--- a/pkg/wasm_builder/lib/src/builder/globals.dart
+++ b/pkg/wasm_builder/lib/src/builder/globals.dart
@@ -11,9 +11,6 @@
final _importedGlobals = <ir.ImportedGlobal>[];
final _globalBuilders = <GlobalBuilder>[];
- /// Number of named globals.
- int _namedCount = 0;
-
GlobalsBuilder(this._moduleBuilder);
void collectUsedTypes(Set<ir.DefType> usedTypes) {
@@ -33,9 +30,6 @@
final global =
GlobalBuilder(_moduleBuilder, ir.FinalizableIndex(), type, name);
_globalBuilders.add(global);
- if (name != null) {
- _namedCount += 1;
- }
return global;
}
@@ -51,6 +45,6 @@
ir.Globals forceBuild() {
final built = finalizeImportsAndBuilders<ir.DefinedGlobal>(
_importedGlobals, _globalBuilders);
- return ir.Globals(_importedGlobals, built, _namedCount);
+ return ir.Globals(_importedGlobals, built);
}
}
diff --git a/pkg/wasm_builder/lib/src/builder/types.dart b/pkg/wasm_builder/lib/src/builder/types.dart
index 6302263..daed2b9 100644
--- a/pkg/wasm_builder/lib/src/builder/types.dart
+++ b/pkg/wasm_builder/lib/src/builder/types.dart
@@ -314,22 +314,7 @@
ir.Types forceBuild() {
final usedTypes = _collectUsedTypes();
final types = _recGroupBuilder.createGroupsForModule(usedTypes);
-
- int nameCount = 0;
- int typesWithNamedFieldsCount = 0;
-
- for (final recursionGroup in types) {
- for (final defType in recursionGroup) {
- if (defType is ir.DataType) {
- nameCount += 1;
- if (defType is ir.StructType && defType.fieldNames.isNotEmpty) {
- typesWithNamedFieldsCount += 1;
- }
- }
- }
- }
-
- return ir.Types(types, nameCount, typesWithNamedFieldsCount);
+ return ir.Types(types);
}
}
diff --git a/pkg/wasm_builder/lib/src/ir/functions.dart b/pkg/wasm_builder/lib/src/ir/functions.dart
index 3496138..80578e7 100644
--- a/pkg/wasm_builder/lib/src/ir/functions.dart
+++ b/pkg/wasm_builder/lib/src/ir/functions.dart
@@ -18,9 +18,5 @@
/// Declared functions.
final List<BaseFunction> declared;
- /// Named functions.
- final int namedCount;
-
- Functions(
- this.start, this.imported, this.defined, this.declared, this.namedCount);
+ Functions(this.start, this.imported, this.defined, this.declared);
}
diff --git a/pkg/wasm_builder/lib/src/ir/globals.dart b/pkg/wasm_builder/lib/src/ir/globals.dart
index 4349563..da3e415 100644
--- a/pkg/wasm_builder/lib/src/ir/globals.dart
+++ b/pkg/wasm_builder/lib/src/ir/globals.dart
@@ -11,8 +11,5 @@
/// Defined globals.
final List<DefinedGlobal> defined;
- /// Number of named globals.
- final int namedCount;
-
- Globals(this.imported, this.defined, this.namedCount);
+ Globals(this.imported, this.defined);
}
diff --git a/pkg/wasm_builder/lib/src/ir/module.dart b/pkg/wasm_builder/lib/src/ir/module.dart
index 7a318a6..fd8b673 100644
--- a/pkg/wasm_builder/lib/src/ir/module.dart
+++ b/pkg/wasm_builder/lib/src/ir/module.dart
@@ -104,24 +104,13 @@
DataCountSection(dataSegments.defined, watchPoints).serialize(s);
CodeSection(functions.defined, watchPoints).serialize(s);
DataSection(dataSegments.defined, watchPoints).serialize(s);
- if (sourceMapUrl != null) {
- SourceMapSection(sourceMapUrl.toString()).serialize(s);
- }
-
- if (functions.namedCount > 0 ||
- types.namedCount > 0 ||
- globals.namedCount > 0) {
- NameSection(
- moduleName,
- <BaseFunction>[...functions.imported, ...functions.defined],
- types.recursionGroups,
- <Global>[...globals.imported, ...globals.defined],
- watchPoints,
- functionNameCount: functions.namedCount,
- typeNameCount: types.namedCount,
- globalNameCount: globals.namedCount,
- typesWithNamedFieldsCount: types.typesWithNamedFieldsCount)
- .serialize(s);
- }
+ NameSection(
+ moduleName,
+ <BaseFunction>[...functions.imported, ...functions.defined],
+ types.recursionGroups,
+ <Global>[...globals.imported, ...globals.defined],
+ watchPoints)
+ .serialize(s);
+ SourceMapSection(sourceMapUrl).serialize(s);
}
}
diff --git a/pkg/wasm_builder/lib/src/ir/type.dart b/pkg/wasm_builder/lib/src/ir/type.dart
index 6eb63f0..28759bd 100644
--- a/pkg/wasm_builder/lib/src/ir/type.dart
+++ b/pkg/wasm_builder/lib/src/ir/type.dart
@@ -785,7 +785,7 @@
/// A named deftype, i.e. `struct` or `array`.
abstract class DataType extends DefType {
- final String name;
+ String? name;
DataType(this.name, {super.superType});
@@ -796,7 +796,7 @@
HeapType get bottomType => HeapType.none;
@override
- String toString() => name;
+ String toString() => name ?? '<unnamed>';
}
/// A custom `struct` type.
diff --git a/pkg/wasm_builder/lib/src/ir/types.dart b/pkg/wasm_builder/lib/src/ir/types.dart
index 3238fa1..afeb69d 100644
--- a/pkg/wasm_builder/lib/src/ir/types.dart
+++ b/pkg/wasm_builder/lib/src/ir/types.dart
@@ -8,11 +8,5 @@
/// Types defined in this module.
final List<List<DefType>> recursionGroups;
- /// Number of types with names.
- final int namedCount;
-
- /// Number of types with field names.
- final int typesWithNamedFieldsCount;
-
- Types(this.recursionGroups, this.namedCount, this.typesWithNamedFieldsCount);
+ Types(this.recursionGroups);
}
diff --git a/pkg/wasm_builder/lib/src/serialize/sections.dart b/pkg/wasm_builder/lib/src/serialize/sections.dart
index 05fa64c..c86b51f 100644
--- a/pkg/wasm_builder/lib/src/serialize/sections.dart
+++ b/pkg/wasm_builder/lib/src/serialize/sections.dart
@@ -12,11 +12,12 @@
@override
void serialize(Serializer s) {
- if (isNotEmpty) {
- final contents = Serializer();
- serializeContents(contents);
+ final contents = Serializer();
+ serializeContents(contents);
+ final data = contents.data;
+ if (data.isNotEmpty) {
s.writeByte(id);
- s.writeUnsigned(contents.data.length);
+ s.writeUnsigned(data.length);
s.sourceMapSerializer
.copyMappings(contents.sourceMapSerializer, s.offset);
s.writeData(contents, watchPoints);
@@ -25,8 +26,6 @@
int get id;
- bool get isNotEmpty;
-
void serializeContents(Serializer s);
}
@@ -41,37 +40,37 @@
int get id => 1;
@override
- bool get isNotEmpty => recursionGroups.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeUnsigned(types.recursionGroups.length);
- int typeIndex = 0;
+ if (types.recursionGroups.isNotEmpty) {
+ s.writeUnsigned(types.recursionGroups.length);
+ int typeIndex = 0;
- // Set all the indices first since types can be referenced before they are
- // serialized.
- for (final group in recursionGroups) {
- assert(group.isNotEmpty, 'Empty groups are not allowed.');
+ // Set all the indices first since types can be referenced before they are
+ // serialized.
+ for (final group in recursionGroups) {
+ assert(group.isNotEmpty, 'Empty groups are not allowed.');
- for (final type in group) {
- type.index = typeIndex++;
+ for (final type in group) {
+ type.index = typeIndex++;
+ }
}
- }
- for (final group in recursionGroups) {
- s.writeByte(0x4E); // -0x32
- s.writeUnsigned(group.length);
- for (final type in group) {
- assert(
- type.superType == null || type.superType!.index <= group.last.index,
- "Type '$type' has a supertype in a later recursion group");
- assert(
- type.constituentTypes
- .whereType<ir.RefType>()
- .map((t) => t.heapType)
- .whereType<ir.DefType>()
- .every((d) => d.index <= group.last.index),
- "Type '$type' depends on a type in a later recursion group");
- type.serializeDefinition(s);
+ for (final group in recursionGroups) {
+ s.writeByte(0x4E); // -0x32
+ s.writeUnsigned(group.length);
+ for (final type in group) {
+ assert(
+ type.superType == null ||
+ type.superType!.index <= group.last.index,
+ "Type '$type' has a supertype in a later recursion group");
+ assert(
+ type.constituentTypes
+ .whereType<ir.RefType>()
+ .map((t) => t.heapType)
+ .whereType<ir.DefType>()
+ .every((d) => d.index <= group.last.index),
+ "Type '$type' depends on a type in a later recursion group");
+ type.serializeDefinition(s);
+ }
}
}
}
@@ -86,11 +85,10 @@
int get id => 2;
@override
- bool get isNotEmpty => imports.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeList(imports);
+ if (imports.isNotEmpty) {
+ s.writeList(imports);
+ }
}
}
@@ -103,13 +101,12 @@
int get id => 3;
@override
- bool get isNotEmpty => functions.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeUnsigned(functions.length);
- for (final function in functions) {
- s.writeUnsigned(function.type.index);
+ if (functions.isNotEmpty) {
+ s.writeUnsigned(functions.length);
+ for (final function in functions) {
+ s.writeUnsigned(function.type.index);
+ }
}
}
}
@@ -123,11 +120,10 @@
int get id => 4;
@override
- bool get isNotEmpty => tables.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeList(tables);
+ if (tables.isNotEmpty) {
+ s.writeList(tables);
+ }
}
}
@@ -140,11 +136,10 @@
int get id => 5;
@override
- bool get isNotEmpty => memories.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeList(memories);
+ if (memories.isNotEmpty) {
+ s.writeList(memories);
+ }
}
}
@@ -157,11 +152,10 @@
int get id => 13;
@override
- bool get isNotEmpty => tags.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeList(tags);
+ if (tags.isNotEmpty) {
+ s.writeList(tags);
+ }
}
}
@@ -174,11 +168,10 @@
int get id => 6;
@override
- bool get isNotEmpty => globals.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeList(globals);
+ if (globals.isNotEmpty) {
+ s.writeList(globals);
+ }
}
}
@@ -191,11 +184,10 @@
int get id => 7;
@override
- bool get isNotEmpty => exports.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeList(exports);
+ if (exports.isNotEmpty) {
+ s.writeList(exports);
+ }
}
}
@@ -208,11 +200,10 @@
int get id => 8;
@override
- bool get isNotEmpty => startFunction != null;
-
- @override
void serializeContents(Serializer s) {
- s.writeUnsigned(startFunction!.index);
+ if (startFunction != null) {
+ s.writeUnsigned(startFunction!.index);
+ }
}
}
@@ -282,12 +273,6 @@
int get id => 9;
@override
- bool get isNotEmpty =>
- definedTables.any((table) => table.elements.any((e) => e != null)) ||
- importedTables.any((table) => table.setElements.isNotEmpty) ||
- declaredFunctions.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
// Group nonempty element entries into contiguous stretches and serialize
// each stretch as an element.
@@ -327,7 +312,9 @@
for (final func in declaredFunctions) {
elements.add(_DeclaredElement([func]));
}
- s.writeList(elements);
+ if (elements.isNotEmpty) {
+ s.writeList(elements);
+ }
}
}
@@ -340,11 +327,10 @@
int get id => 12;
@override
- bool get isNotEmpty => dataSegments.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeUnsigned(dataSegments.length);
+ if (dataSegments.isNotEmpty) {
+ s.writeUnsigned(dataSegments.length);
+ }
}
}
@@ -357,11 +343,10 @@
int get id => 10;
@override
- bool get isNotEmpty => functions.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeList(functions);
+ if (functions.isNotEmpty) {
+ s.writeList(functions);
+ }
}
}
@@ -374,11 +359,10 @@
int get id => 11;
@override
- bool get isNotEmpty => dataSegments.isNotEmpty;
-
- @override
void serializeContents(Serializer s) {
- s.writeList(dataSegments);
+ if (dataSegments.isNotEmpty) {
+ s.writeList(dataSegments);
+ }
}
}
@@ -394,142 +378,143 @@
final List<ir.BaseFunction> functions;
final List<List<ir.DefType>> types;
final List<ir.Global> globals;
- final int functionNameCount;
- final int typeNameCount;
- final int globalNameCount;
- final int typesWithNamedFieldsCount;
- NameSection(this.moduleName, this.functions, this.types, this.globals,
- super.watchPoints,
- {required this.functionNameCount,
- required this.typeNameCount,
- required this.globalNameCount,
- required this.typesWithNamedFieldsCount});
-
- @override
- bool get isNotEmpty => functionNameCount > 0 || typeNameCount > 0;
+ NameSection(
+ this.moduleName,
+ this.functions,
+ this.types,
+ this.globals,
+ super.watchPoints,
+ );
@override
void serializeContents(Serializer s) {
- s.writeName("name");
-
final moduleNameSubsection = Serializer();
moduleNameSubsection.writeName(moduleName);
- final functionNameSubsection = Serializer();
- functionNameSubsection.writeUnsigned(functionNameCount);
+ int functionNameCount = 0;
+ final functionNames = Serializer();
for (int i = 0; i < functions.length; i++) {
- String? functionName = functions[i].functionName;
+ final String? functionName = functions[i].functionName;
if (functionName != null) {
- functionNameSubsection.writeUnsigned(i);
- functionNameSubsection.writeName(functionName);
+ functionNames.writeUnsigned(i);
+ functionNames.writeName(functionName);
+ functionNameCount++;
}
}
- final typeNameSubsection = Serializer();
- typeNameSubsection.writeUnsigned(typeNameCount);
- {
- int typeIndex = 0;
- for (final recursionGroup in types) {
- for (final defType in recursionGroup) {
- if (defType is ir.DataType) {
- typeNameSubsection.writeUnsigned(typeIndex);
- typeNameSubsection.writeName(defType.name);
+ int typeIndex = 0;
+ int typeNameCount = 0;
+ final typeNames = Serializer();
+ int typesWithNamedFieldsCount = 0;
+ final fieldNames = Serializer();
+ for (final recursionGroup in types) {
+ for (final defType in recursionGroup) {
+ if (defType is ir.DataType) {
+ final name = defType.name;
+ if (name != null) {
+ typeNames.writeUnsigned(typeIndex);
+ typeNames.writeName(name);
+ typeNameCount++;
+ if (defType is ir.StructType && defType.fieldNames.isNotEmpty) {
+ fieldNames.writeUnsigned(typeIndex);
+ fieldNames.writeUnsigned(defType.fieldNames.length);
+ for (final entry in defType.fieldNames.entries) {
+ fieldNames.writeUnsigned(entry.key);
+ fieldNames.writeName(entry.value);
+ }
+ typesWithNamedFieldsCount++;
+ }
}
- typeIndex += 1;
}
+ typeIndex++;
}
}
- final globalNameSubsection = Serializer();
- globalNameSubsection.writeUnsigned(globalNameCount);
+ int globalNameCount = 0;
+ final globalNames = Serializer();
for (int i = 0; i < globals.length; i++) {
final globalName = globals[i].globalName;
if (globalName != null) {
- globalNameSubsection.writeUnsigned(i);
- globalNameSubsection.writeName(globalName);
+ globalNames.writeUnsigned(i);
+ globalNames.writeName(globalName);
+ globalNameCount++;
}
}
- final fieldNameSubsection = Serializer();
- fieldNameSubsection.writeUnsigned(typesWithNamedFieldsCount);
-
- if (typesWithNamedFieldsCount != 0) {
- int typeIndex = 0;
- for (final recursionGroup in types) {
- for (final defType in recursionGroup) {
- if (defType is ir.StructType && defType.fieldNames.isNotEmpty) {
- fieldNameSubsection.writeUnsigned(typeIndex);
- fieldNameSubsection.writeUnsigned(defType.fieldNames.length);
- for (final entry in defType.fieldNames.entries) {
- fieldNameSubsection.writeUnsigned(entry.key);
- fieldNameSubsection.writeName(entry.value);
- }
- }
- typeIndex += 1;
- }
- }
- }
-
- final localNameSubsection = Serializer();
- List<ir.DefinedFunction> functionsWithLocalNames = [];
+ int functionsWithLocalNamesCount = 0;
+ final localNames = Serializer();
for (final function in functions) {
if (function is ir.DefinedFunction) {
if (function.localNames.isNotEmpty) {
- functionsWithLocalNames.add(function);
+ localNames.writeUnsigned(function.finalizableIndex.value);
+ localNames.writeUnsigned(function.localNames.length);
+ for (final entry in function.localNames.entries) {
+ localNames.writeUnsigned(entry.key);
+ localNames.writeName(entry.value);
+ }
}
}
}
- localNameSubsection.writeUnsigned(functionsWithLocalNames.length);
- if (functionsWithLocalNames.isNotEmpty) {
- for (final function in functionsWithLocalNames) {
- localNameSubsection.writeUnsigned(function.finalizableIndex.value);
- localNameSubsection.writeUnsigned(function.localNames.length);
- for (final entry in function.localNames.entries) {
- localNameSubsection.writeUnsigned(entry.key);
- localNameSubsection.writeName(entry.value);
- }
- }
- }
+ s.writeName("name"); // Name of the custom section.
s.writeByte(0); // Module name subsection
s.writeUnsigned(moduleNameSubsection.data.length);
s.writeData(moduleNameSubsection);
- s.writeByte(1); // Function names subsection
- s.writeUnsigned(functionNameSubsection.data.length);
- s.writeData(functionNameSubsection);
+ if (functionNameCount > 0) {
+ s.writeByte(1); // Function names subsection
+ s.writeUnsigned(functionNames.data.length +
+ Serializer.writeUnsignedByteCount(functionNameCount));
+ s.writeUnsigned(functionNameCount);
+ s.writeData(functionNames);
+ }
- s.writeByte(2); // Local names substion
- s.writeUnsigned(localNameSubsection.data.length);
- s.writeData(localNameSubsection);
+ if (functionsWithLocalNamesCount > 0) {
+ s.writeByte(2); // Local names substion
+ s.writeUnsigned(localNames.data.length +
+ Serializer.writeUnsignedByteCount(functionsWithLocalNamesCount));
+ s.writeUnsigned(functionsWithLocalNamesCount);
+ s.writeData(localNames);
+ }
- s.writeByte(4); // Type names subsection
- s.writeUnsigned(typeNameSubsection.data.length);
- s.writeData(typeNameSubsection);
+ if (typeNameCount > 0) {
+ s.writeByte(4); // Type names subsection
+ s.writeUnsigned(typeNames.data.length +
+ Serializer.writeUnsignedByteCount(typeNameCount));
+ s.writeUnsigned(typeNameCount);
+ s.writeData(typeNames);
+ }
- s.writeByte(7); // Global names subsection
- s.writeUnsigned(globalNameSubsection.data.length);
- s.writeData(globalNameSubsection);
+ if (globalNameCount > 0) {
+ s.writeByte(7); // Global names subsection
+ s.writeUnsigned(globalNames.data.length +
+ Serializer.writeUnsignedByteCount(globalNameCount));
+ s.writeUnsigned(globalNameCount);
+ s.writeData(globalNames);
+ }
- s.writeByte(10); // Field names subsection
- s.writeUnsigned(fieldNameSubsection.data.length);
- s.writeData(fieldNameSubsection);
+ if (typesWithNamedFieldsCount > 0) {
+ s.writeByte(10); // Field names subsection
+ s.writeUnsigned(fieldNames.data.length +
+ Serializer.writeUnsignedByteCount(typesWithNamedFieldsCount));
+ s.writeUnsigned(typesWithNamedFieldsCount);
+ s.writeData(fieldNames);
+ }
}
}
class SourceMapSection extends CustomSection {
- final String url;
+ final Uri? url;
SourceMapSection(this.url) : super([]);
@override
- bool get isNotEmpty => true;
-
- @override
void serializeContents(Serializer s) {
- s.writeName("sourceMappingURL");
- s.writeName(url);
+ if (url != null) {
+ s.writeName("sourceMappingURL");
+ s.writeName(url!.toString());
+ }
}
}
diff --git a/pkg/wasm_builder/lib/src/serialize/serializer.dart b/pkg/wasm_builder/lib/src/serialize/serializer.dart
index 8ba6ba2..50734df 100644
--- a/pkg/wasm_builder/lib/src/serialize/serializer.dart
+++ b/pkg/wasm_builder/lib/src/serialize/serializer.dart
@@ -75,6 +75,17 @@
writeByte(value);
}
+ static int writeUnsignedByteCount(int value) {
+ assert(value >= 0);
+ int count = 0;
+ while (value >= 0x80) {
+ count++;
+ value >>= 7;
+ }
+ count++;
+ return count;
+ }
+
static final ByteData _f32ByteData = ByteData(4);
static final Uint8List _f32Uint8List = _f32ByteData.buffer.asUint8List();
void writeF32(double value) {