Skip to content

Commit 293c4b9

Browse files
mkustermannCommit Queue
authored andcommitted
[dart2wasm] Some fixes for the binary wasm deserializer
* Assign type indices when deserializing the type section * Fix decoding of tag imports * Add data segment support to IR printer * Handle input+output variants of loop/if/try_table instructions This allows us to now read & print all wasm modules of ACX gallery when compiled in deferred loading mode. Change-Id: Iaba30a6337aa2afd5d4894ca73d305cd2b7befea Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/459480 Reviewed-by: Ömer Ağacan <omersa@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com>
1 parent 10f5f15 commit 293c4b9

File tree

4 files changed

+127
-65
lines changed

4 files changed

+127
-65
lines changed

pkg/wasm_builder/lib/src/ir/data_segment.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,20 @@
55
import 'dart:typed_data';
66

77
import '../serialize/serialize.dart';
8+
import '../serialize/printer.dart';
89
import 'ir.dart';
910

10-
class BaseDataSegment {
11+
abstract class BaseDataSegment {
1112
late final int index;
1213
late final Memory? memory;
1314
late final int? offset;
1415

1516
BaseDataSegment(this.index, this.memory, this.offset);
1617
BaseDataSegment.uninitialized();
18+
19+
void printTo(IrPrinter p) {
20+
throw UnimplementedError();
21+
}
1722
}
1823

1924
/// A data segment in a module.
@@ -43,4 +48,13 @@ class DataSegment extends BaseDataSegment implements Serializable {
4348
s.writeUnsigned(content.length);
4449
s.writeBytes(content);
4550
}
51+
52+
@override
53+
void printTo(IrPrinter p) {
54+
p.write('(data ');
55+
p.writeDataReference(this);
56+
p.write(' ');
57+
p.write('<... ${content.length} bytes ...>');
58+
p.write(')');
59+
}
4660
}

pkg/wasm_builder/lib/src/ir/instruction.dart

Lines changed: 63 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -102,51 +102,19 @@ abstract class Instruction implements Serializable {
102102
case 0x01:
103103
return Nop.deserialize(d);
104104
case 0x02:
105-
{
106-
if (d.peekByte() == 0x40) {
107-
return BeginNoEffectBlock.deserialize(d);
108-
}
109-
110-
final oldOffset = d.offset;
111-
final value = d.readSigned();
112-
d.offset = oldOffset;
113-
if (value >= 0) {
114-
return BeginFunctionBlock.deserialize(d, types);
115-
}
116-
117-
return BeginOneOutputBlock.deserialize(d, types);
118-
}
105+
return d.deserializeBlock(types, tags, BeginNoEffectBlock.deserialize,
106+
BeginOneOutputBlock.deserialize, BeginFunctionBlock.deserialize);
119107
case 0x03:
120-
{
121-
if (d.peekByte() == 0x40) {
122-
return BeginNoEffectLoop.deserialize(d);
123-
}
124-
return BeginOneOutputLoop.deserialize(d, types);
125-
}
108+
return d.deserializeBlock(types, tags, BeginNoEffectLoop.deserialize,
109+
BeginOneOutputLoop.deserialize, BeginFunctionLoop.deserialize);
126110
case 0x04:
127-
{
128-
if (d.peekByte() == 0x40) {
129-
return BeginNoEffectIf.deserialize(d);
130-
}
131-
return BeginOneOutputIf.deserialize(d, types);
132-
}
111+
return d.deserializeBlock(types, tags, BeginNoEffectIf.deserialize,
112+
BeginOneOutputIf.deserialize, BeginFunctionIf.deserialize);
133113
case 0x05:
134114
return Else.deserialize(d);
135115
case 0x06:
136-
{
137-
if (d.peekByte() == 0x40) {
138-
return BeginNoEffectTry.deserialize(d);
139-
}
140-
141-
final oldOffset = d.offset;
142-
final value = d.readSigned();
143-
d.offset = oldOffset;
144-
if (value >= 0) {
145-
return BeginFunctionTry.deserialize(d, types);
146-
}
147-
148-
return BeginOneOutputTry.deserialize(d, types);
149-
}
116+
return d.deserializeBlock(types, tags, BeginNoEffectTry.deserialize,
117+
BeginOneOutputTry.deserialize, BeginFunctionTry.deserialize);
150118
case 0x07:
151119
return CatchLegacy.deserialize(d, tags);
152120
case 0x08:
@@ -178,12 +146,12 @@ abstract class Instruction implements Serializable {
178146
case 0x1C:
179147
return SelectWithType.deserialize(d, types);
180148
case 0x1F:
181-
{
182-
if (d.peekByte() == 0x40) {
183-
return BeginNoEffectTryTable.deserialize(d, tags);
184-
}
185-
return BeginOneOutputTryTable.deserialize(d, types, tags);
186-
}
149+
return d.deserializeBlock(
150+
types,
151+
tags,
152+
BeginNoEffectTryTable.deserialize,
153+
BeginOneOutputTryTable.deserialize,
154+
BeginFunctionTryTable.deserialize);
187155
case 0x20:
188156
return LocalGet.deserialize(d);
189157
case 0x21:
@@ -628,7 +596,7 @@ class Nop extends SingleByteInstruction {
628596
class BeginNoEffectBlock extends Instruction {
629597
const BeginNoEffectBlock();
630598

631-
static BeginNoEffectBlock deserialize(Deserializer d) {
599+
static BeginNoEffectBlock deserialize(Deserializer d, Tags _) {
632600
d.readByte();
633601
return const BeginNoEffectBlock();
634602
}
@@ -658,7 +626,7 @@ class BeginOneOutputBlock extends Instruction {
658626

659627
BeginOneOutputBlock(this.type);
660628

661-
static BeginOneOutputBlock deserialize(Deserializer d, Types types) {
629+
static BeginOneOutputBlock deserialize(Deserializer d, Tags _, Types types) {
662630
final type = ValueType.deserialize(d, types.defined);
663631
assert(type is! FunctionType);
664632
return BeginOneOutputBlock(type);
@@ -693,7 +661,7 @@ class BeginFunctionBlock extends Instruction {
693661

694662
BeginFunctionBlock(this.type);
695663

696-
static BeginFunctionBlock deserialize(Deserializer d, Types types) {
664+
static BeginFunctionBlock deserialize(Deserializer d, Tags _, Types types) {
697665
return BeginFunctionBlock(types.defined[d.readSigned()] as FunctionType);
698666
}
699667

@@ -725,7 +693,7 @@ class BeginNoEffectLoop extends Instruction {
725693
s.writeByte(0x40);
726694
}
727695

728-
static BeginNoEffectLoop deserialize(Deserializer d) {
696+
static BeginNoEffectLoop deserialize(Deserializer d, Tags _) {
729697
d.readByte();
730698
return const BeginNoEffectLoop();
731699
}
@@ -749,7 +717,7 @@ class BeginOneOutputLoop extends Instruction {
749717

750718
BeginOneOutputLoop(this.type);
751719

752-
static BeginOneOutputLoop deserialize(Deserializer d, Types types) {
720+
static BeginOneOutputLoop deserialize(Deserializer d, Tags _, Types types) {
753721
final type = ValueType.deserialize(d, types.defined);
754722
return BeginOneOutputLoop(type);
755723
}
@@ -781,6 +749,10 @@ class BeginFunctionLoop extends Instruction {
781749

782750
BeginFunctionLoop(this.type);
783751

752+
static BeginFunctionLoop deserialize(Deserializer d, Tags _, Types types) {
753+
return BeginFunctionLoop(types.defined[d.readSigned()] as FunctionType);
754+
}
755+
784756
@override
785757
void serialize(Serializer s) {
786758
s.writeByte(0x03);
@@ -809,7 +781,7 @@ class BeginNoEffectIf extends Instruction {
809781
s.writeByte(0x40);
810782
}
811783

812-
static BeginNoEffectIf deserialize(Deserializer d) {
784+
static BeginNoEffectIf deserialize(Deserializer d, Tags _) {
813785
d.readByte();
814786
return const BeginNoEffectIf();
815787
}
@@ -826,7 +798,7 @@ class BeginOneOutputIf extends Instruction {
826798

827799
BeginOneOutputIf(this.type);
828800

829-
static BeginOneOutputIf deserialize(Deserializer d, Types types) {
801+
static BeginOneOutputIf deserialize(Deserializer d, Tags _, Types types) {
830802
final type = ValueType.deserialize(d, types.defined);
831803
return BeginOneOutputIf(type);
832804
}
@@ -857,6 +829,10 @@ class BeginFunctionIf extends Instruction {
857829

858830
BeginFunctionIf(this.type);
859831

832+
static BeginFunctionIf deserialize(Deserializer d, Tags _, Types types) {
833+
return BeginFunctionIf(types.defined[d.readSigned()] as FunctionType);
834+
}
835+
860836
@override
861837
void serialize(Serializer s) {
862838
s.writeByte(0x04);
@@ -886,7 +862,7 @@ class Else extends SingleByteInstruction {
886862
class BeginNoEffectTry extends Instruction {
887863
const BeginNoEffectTry();
888864

889-
static BeginNoEffectTry deserialize(Deserializer d) {
865+
static BeginNoEffectTry deserialize(Deserializer d, Tags _) {
890866
d.readByte();
891867
return const BeginNoEffectTry();
892868
}
@@ -916,7 +892,7 @@ class BeginOneOutputTry extends Instruction {
916892

917893
BeginOneOutputTry(this.type);
918894

919-
static BeginOneOutputTry deserialize(Deserializer d, Types types) {
895+
static BeginOneOutputTry deserialize(Deserializer d, Tags _, Types types) {
920896
final type = ValueType.deserialize(d, types.defined);
921897
assert(type is! FunctionType);
922898
return BeginOneOutputTry(type);
@@ -949,7 +925,7 @@ class BeginFunctionTry extends Instruction {
949925

950926
BeginFunctionTry(this.type);
951927

952-
static BeginFunctionTry deserialize(Deserializer d, Types types) {
928+
static BeginFunctionTry deserialize(Deserializer d, Tags _, Types types) {
953929
return BeginFunctionTry(types.defined[d.readSigned()] as FunctionType);
954930
}
955931

@@ -4348,7 +4324,7 @@ class BeginOneOutputTryTable extends Instruction {
43484324
BeginOneOutputTryTable(this.type, this.catches);
43494325

43504326
static BeginOneOutputTryTable deserialize(
4351-
Deserializer d, Types types, Tags tags) {
4327+
Deserializer d, Tags tags, Types types) {
43524328
final type = ValueType.deserialize(d, types.defined);
43534329
final catches = d.readList((d) => TryTableCatch.deserialize(d, tags));
43544330
return BeginOneOutputTryTable(type, catches);
@@ -4374,6 +4350,13 @@ class BeginFunctionTryTable extends Instruction {
43744350

43754351
BeginFunctionTryTable(this.type, this.catches);
43764352

4353+
static BeginFunctionTryTable deserialize(
4354+
Deserializer d, Tags tags, Types types) {
4355+
final type = types.defined[d.readSigned()] as FunctionType;
4356+
final catches = d.readList((d) => TryTableCatch.deserialize(d, tags));
4357+
return BeginFunctionTryTable(type, catches);
4358+
}
4359+
43774360
@override
43784361
List<DefType> get usedDefTypes => [type];
43794362

@@ -4473,4 +4456,27 @@ extension on Serializer {
44734456

44744457
extension on Deserializer {
44754458
int readTypeIndex() => readUnsigned();
4459+
4460+
Instruction deserializeBlock(
4461+
Types types,
4462+
Tags tags,
4463+
Instruction Function(Deserializer, Tags) deserializeNoInputNoOutput,
4464+
Instruction Function(Deserializer, Tags, Types) deserializeOneOutput,
4465+
Instruction Function(Deserializer, Tags, Types) deserializeGeneral) {
4466+
if (peekByte() == 0x40) {
4467+
// 0x40 means empty type, the block has neither inputs nor outputs.
4468+
return deserializeNoInputNoOutput(this, tags);
4469+
}
4470+
final oldOffset = offset;
4471+
final value = readSigned();
4472+
offset = oldOffset;
4473+
if (value < 0) {
4474+
// not positive signed integer, the block has no inputs and exactly one
4475+
// output.
4476+
return deserializeOneOutput(this, tags, types);
4477+
}
4478+
// positive signed integer is index into defined types and must be a
4479+
// function type representing the input & output types.
4480+
return deserializeGeneral(this, tags, types);
4481+
}
44764482
}

pkg/wasm_builder/lib/src/serialize/printer.dart

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@ class ModulePrinter {
2020
_TagNamer(settings.scrubAbsoluteUris, _module, enqueueTag);
2121
late final tableNamer =
2222
_TableNamer(settings.scrubAbsoluteUris, _module, enqueueTable);
23+
late final dataNamer =
24+
_DataNamer(settings.scrubAbsoluteUris, _module, enqueueDataSegment);
2325

2426
final _types = <ir.DefType, String>{};
2527
final _tags = <ir.Tag, String>{};
2628
final _tables = <ir.Table, String>{};
2729
final _globals = <ir.Global, String>{};
2830
final _functions = <ir.BaseFunction, String>{};
31+
final _dataSegments = <ir.BaseDataSegment, String>{};
2932

3033
final _typeQueue = Queue<ir.DefType>();
3134
final _functionsQueue = Queue<ir.DefinedFunction>();
@@ -37,7 +40,7 @@ class ModulePrinter {
3740
ModulePrinter(this._module, {this.settings = const ModulePrintSettings()});
3841

3942
IrPrinter newIrPrinter() => IrPrinter._(settings.preferMultiline, _module,
40-
typeNamer, globalNamer, functionNamer, tagNamer, tableNamer);
43+
typeNamer, globalNamer, functionNamer, tagNamer, tableNamer, dataNamer);
4144

4245
void enqueueType(ir.DefType type) {
4346
if (!_types.containsKey(type)) {
@@ -84,6 +87,17 @@ class ModulePrinter {
8487
}
8588
}
8689

90+
void enqueueDataSegment(ir.BaseDataSegment dataSegment) {
91+
if (!_dataSegments.containsKey(dataSegment)) {
92+
// Since below `printTo` will call namer to name the data segment which
93+
// will trigger this callback again if not pre-initialized to ''.
94+
_dataSegments[dataSegment] = '';
95+
final ip = newIrPrinter();
96+
dataSegment.printTo(ip);
97+
_dataSegments[dataSegment] = ip.getText();
98+
}
99+
}
100+
87101
String print() {
88102
while (_functionsQueue.isNotEmpty || _typeQueue.isNotEmpty) {
89103
while (_functionsQueue.isNotEmpty) {
@@ -165,6 +179,13 @@ class ModulePrinter {
165179
mp.writeln();
166180
}
167181
}
182+
for (final d in _module.dataSegments.defined) {
183+
final s = _dataSegments[d];
184+
if (s != null) {
185+
mp.write(s);
186+
mp.writeln();
187+
}
188+
}
168189
});
169190
mp.write(')');
170191
return mp.getText();
@@ -343,17 +364,25 @@ class IrPrinter extends IndentPrinter {
343364
final _FunctionNamer _functionNamer;
344365
final _TagNamer _tagNamer;
345366
final _TableNamer _tableNamer;
367+
final _DataNamer _dataNamer;
346368

347369
_LocalNamer? _localNamer;
348370
final _labelNamer = _LabelNamer();
349371

350-
IrPrinter._(this.preferMultiline, this.module, this._typeNamer,
351-
this._globalNamer, this._functionNamer, this._tagNamer, this._tableNamer);
372+
IrPrinter._(
373+
this.preferMultiline,
374+
this.module,
375+
this._typeNamer,
376+
this._globalNamer,
377+
this._functionNamer,
378+
this._tagNamer,
379+
this._tableNamer,
380+
this._dataNamer);
352381

353382
/// Returns a new [IrPrinter] with same settings, but empty indentation,
354383
/// empty text content and no local namer.
355384
IrPrinter dup() => IrPrinter._(preferMultiline, module, _typeNamer,
356-
_globalNamer, _functionNamer, _tagNamer, _tableNamer);
385+
_globalNamer, _functionNamer, _tagNamer, _tableNamer, _dataNamer);
357386

358387
void beginLabeledBlock(ir.Instruction? instruction) {
359388
_labelNamer.stack.add(LabelInfo(instruction));
@@ -480,7 +509,7 @@ class IrPrinter extends IndentPrinter {
480509
}
481510

482511
void writeDataReference(ir.BaseDataSegment dataSegment) {
483-
throw UnimplementedError();
512+
write(_dataNamer.nameDataSegment(dataSegment));
484513
}
485514

486515
void writeMemoryReference(ir.Memory memory) {
@@ -612,6 +641,14 @@ class _GlobalNamer extends _Namer<ir.Global> {
612641
}
613642
}
614643

644+
class _DataNamer extends _Namer<ir.BaseDataSegment> {
645+
_DataNamer(super.scubUris, super.module, super.onReference);
646+
647+
String nameDataSegment(ir.BaseDataSegment data) {
648+
return super._name(data, null, 'data', true);
649+
}
650+
}
651+
615652
class _LabelNamer {
616653
int _nextId = 0;
617654
final stack = <LabelInfo>[];

0 commit comments

Comments
 (0)