Skip to content

Commit 643d1ba

Browse files
osa1Commit Queue
authored andcommitted
[dart2wasm] Check const-ness of instructions added to const exprs
A constant expression in Wasm is an instruction sequence that consists of only the constant instructions. Currently if I generate a non-constant instruction in a constant expression I get an error during Wasm compilation. I then have to find where and how I generate the instruction, possibly by using `--watch <instruction offset>` passed to dart2wasm. With this change we check in an assertion that an instruction added to an instruction sequence for a constant expression can only be a constant expression. This helps with debugging as I notice the error earlier, and get a stack trace of the compiler function that generates the invalid instruction. Changes: - Add `bool get isConstant => false` member to `Instruction`. A method instead of field to avoid adding one more word to `Instruction` objects. - Override the member in constant instructions. - When creating an instructions builder, mark the builder as "constant", with an optional named constructor argument that defaults to `false`. - When adding an instruction to an instructions builder, check that if the instruction block is for a constant expression, the instruction is constant. Spec: https://webassembly.github.io/gc/core/valid/instructions.html#constant-expressions Change-Id: I59454f0634ab419a62f9455c84aa9ce631db8b63 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391440 Commit-Queue: Ömer Ağacan <[email protected]> Reviewed-by: Slava Egorov <[email protected]>
1 parent 2b899ad commit 643d1ba

File tree

3 files changed

+63
-3
lines changed

3 files changed

+63
-3
lines changed

pkg/wasm_builder/lib/src/builder/global.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ class GlobalBuilder extends ir.Global with IndexableBuilder<ir.DefinedGlobal> {
1010

1111
GlobalBuilder(super.enclosingModule, super.index, super.type,
1212
[super.globalName])
13-
: initializer = InstructionsBuilder(enclosingModule, [], [type.type]);
13+
: initializer = InstructionsBuilder(enclosingModule, [], [type.type],
14+
constantExpression: true);
1415

1516
@override
1617
ir.DefinedGlobal forceBuild() => ir.DefinedGlobal(

pkg/wasm_builder/lib/src/builder/instructions.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,16 @@ class InstructionsBuilder with Builder<ir.Instructions> {
146146
/// Stored stack traces leading to the instructions for watch points.
147147
final Map<ir.Instruction, StackTrace>? _stackTraces;
148148

149+
/// Whether the instruction block is for a Wasm constant expression.
150+
final bool _constantExpression;
151+
149152
/// Create a new instruction sequence.
150153
InstructionsBuilder(
151-
this.module, List<ir.ValueType> inputs, List<ir.ValueType> outputs)
154+
this.module, List<ir.ValueType> inputs, List<ir.ValueType> outputs,
155+
{bool constantExpression = false})
152156
: _stackTraces = module.watchPoints.isNotEmpty ? {} : null,
153-
_sourceMappings = module.sourceMapUrl == null ? null : [] {
157+
_sourceMappings = module.sourceMapUrl == null ? null : [],
158+
_constantExpression = constantExpression {
154159
_labelStack.add(Expression(const [], outputs));
155160
for (ir.ValueType paramType in inputs) {
156161
_addParameter(paramType);
@@ -184,6 +189,8 @@ class InstructionsBuilder with Builder<ir.Instructions> {
184189
locals, _instructions, _stackTraces, _traceLines, _sourceMappings);
185190

186191
void _add(ir.Instruction i) {
192+
assert(!_constantExpression || i.isConstant,
193+
"Non-constant instruction $i added to constant expression");
187194
if (!_reachable) return;
188195
_instructions.add(i);
189196
if (module.watchPoints.isNotEmpty) {

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ abstract class Instruction implements Serializable {
1616
List<DefType> get usedDefTypes => const [];
1717

1818
const Instruction();
19+
20+
/// Whether the instruction is a "constant instruction", as defined by the
21+
/// Wasm spec.
22+
///
23+
/// Constant instructions can be used in global initializers, element
24+
/// segments, data segments.
25+
bool get isConstant => false;
1926
}
2027

2128
abstract class SingleByteInstruction extends Instruction {
@@ -226,6 +233,9 @@ class Rethrow extends Instruction {
226233

227234
class End extends SingleByteInstruction {
228235
const End() : super(0x0B);
236+
237+
@override
238+
bool get isConstant => true;
229239
}
230240

231241
class Br extends Instruction {
@@ -382,6 +392,9 @@ class GlobalGet extends Instruction {
382392

383393
GlobalGet(this.global);
384394

395+
@override
396+
bool get isConstant => true;
397+
385398
@override
386399
void serialize(Serializer s) {
387400
s.writeByte(0x23);
@@ -597,6 +610,9 @@ class RefNull extends Instruction {
597610

598611
RefNull(this.heapType);
599612

613+
@override
614+
bool get isConstant => true;
615+
600616
@override
601617
void serialize(Serializer s) {
602618
s.writeByte(0xD0);
@@ -613,6 +629,9 @@ class RefFunc extends Instruction {
613629

614630
RefFunc(this.function);
615631

632+
@override
633+
bool get isConstant => true;
634+
616635
@override
617636
void serialize(Serializer s) {
618637
s.writeByte(0xD2);
@@ -728,6 +747,9 @@ class StructNew extends Instruction {
728747

729748
StructNew(this.structType);
730749

750+
@override
751+
bool get isConstant => true;
752+
731753
@override
732754
void serialize(Serializer s) {
733755
s.writeBytes(const [0xFB, 0x00]);
@@ -743,6 +765,9 @@ class StructNewDefault extends Instruction {
743765

744766
StructNewDefault(this.structType);
745767

768+
@override
769+
bool get isConstant => true;
770+
746771
@override
747772
void serialize(Serializer s) {
748773
s.writeBytes(const [0xFB, 0x01]);
@@ -823,6 +848,9 @@ class ArrayNewFixed extends Instruction {
823848

824849
ArrayNewFixed(this.arrayType, this.length);
825850

851+
@override
852+
bool get isConstant => true;
853+
826854
@override
827855
void serialize(Serializer s) {
828856
s.writeBytes(const [0xFB, 0x08]);
@@ -839,6 +867,9 @@ class ArrayNew extends Instruction {
839867

840868
ArrayNew(this.arrayType);
841869

870+
@override
871+
bool get isConstant => true;
872+
842873
@override
843874
void serialize(Serializer s) {
844875
s.writeBytes(const [0xFB, 0x06]);
@@ -854,6 +885,9 @@ class ArrayNewDefault extends Instruction {
854885

855886
ArrayNewDefault(this.arrayType);
856887

888+
@override
889+
bool get isConstant => true;
890+
857891
@override
858892
void serialize(Serializer s) {
859893
s.writeBytes(const [0xFB, 0x07]);
@@ -995,17 +1029,26 @@ class BrOnCastFail extends Instruction {
9951029

9961030
class ExternInternalize extends MultiByteInstruction {
9971031
const ExternInternalize() : super(const [0xFB, 0x1A]);
1032+
1033+
@override
1034+
bool get isConstant => true;
9981035
}
9991036

10001037
class ExternExternalize extends MultiByteInstruction {
10011038
const ExternExternalize() : super(const [0xFB, 0x1B]);
1039+
1040+
@override
1041+
bool get isConstant => true;
10021042
}
10031043

10041044
class I32Const extends Instruction {
10051045
final int value;
10061046

10071047
I32Const(this.value);
10081048

1049+
@override
1050+
bool get isConstant => true;
1051+
10091052
@override
10101053
void serialize(Serializer s) {
10111054
s.writeByte(0x41);
@@ -1018,6 +1061,9 @@ class I64Const extends Instruction {
10181061

10191062
I64Const(this.value);
10201063

1064+
@override
1065+
bool get isConstant => true;
1066+
10211067
@override
10221068
void serialize(Serializer s) {
10231069
s.writeByte(0x42);
@@ -1030,6 +1076,9 @@ class F32Const extends Instruction {
10301076

10311077
F32Const(this.value);
10321078

1079+
@override
1080+
bool get isConstant => true;
1081+
10331082
@override
10341083
void serialize(Serializer s) {
10351084
s.writeByte(0x43);
@@ -1042,6 +1091,9 @@ class F64Const extends Instruction {
10421091

10431092
F64Const(this.value);
10441093

1094+
@override
1095+
bool get isConstant => true;
1096+
10451097
@override
10461098
void serialize(Serializer s) {
10471099
s.writeByte(0x44);

0 commit comments

Comments
 (0)