[dart2wasm] Remove synthesizing values from nothing

When there's no expression on the stack but we expect something on the
stack, then the code should be unreachable.

Though the current code would just synthesize a value that matches
the expected type (`convertType(voidMarker, <some type>)`). This
is problematic: If we ever used that synthesized value we may
have incorrect program behavior.

Now there were some valid uses where we synthesize values

* A function that has `void` return type but no explicit return
  => Here we should synthesize `null`
* Synthesize `null` in cases where we know it's not going to be used
  => e.g. for CFE desugaring of `a[i] = b` is roughly
     `let tmp = b in (let ignored = a.[]=(tmp) in b)`
     where we synthesize `null` as `a.[]=(tmp)` result,
     `ignored` isn't used.
* ...

With this CL we no longer allow synthesizing a value of a type
out of thin air, instead all the places where this occurs have
to do that explicitly.

There's some impurities around how setters and index setters
are handled today (and even after this CL). Those impurities
start all the way at CFE, which treats setters and index
setters very differently. See the CFE issue [0].

For those we have two choices:

* special case all call sites that require synthesizing
  null values
* special case all call sites that require dropping an
  auto synthesized null value

This CL now marks instance setter/index-setter methods as
requiring auto-synthesizeing null values on usage sites and
make code that doesn't need them explicitly drop them.

Somewhat related to this change is how we deal with `void`
on the Dart <-> Wasm Import / Wasm Export boundary: When we
call an imported wasm function that has `void` as return
type (meaning no return values) we have to synthesize a `null`
(as the caller may "use"/"observe" the `void`).

=> We now are more strict and instead use `WasmVoid` as type
   instead of allowing `void` as type on the import/export
   functions.

[0] https://github.com/dart-lang/sdk/issues/63360

Change-Id: Ie30df3bd68553724437607bab3163c98f5467efe
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/501061
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Martin Kustermann
2026-05-13 00:22:52 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 96a4dd4c19
commit d0e0290702
12 changed files with 156 additions and 95 deletions
+27 -14
View File
@@ -8,6 +8,7 @@ import 'package:collection/collection.dart';
import 'package:front_end/src/api_prototype/external_effect.dart'
show ExternalEffect;
import 'package:kernel/ast.dart';
import 'package:kernel/names.dart';
import 'package:kernel/type_environment.dart';
import 'package:wasm_builder/wasm_builder.dart' as w;
@@ -1332,7 +1333,7 @@ abstract class AstCodeGenerator
if (expression != null) {
translateExpression(expression, returnType);
} else {
translator.convertType(b, voidMarker, returnType);
_implicitReturn();
}
// If we are wrapped in a [TryFinally] node then we have to run finalizers
@@ -1666,7 +1667,7 @@ abstract class AstCodeGenerator
// When calling `==` and the argument is potentially nullable, check if the
// argument is `null`.
if (node.name.text == '==') {
if (node.name == equalsName) {
assert(node.arguments.positional.length == 1);
assert(node.arguments.named.isEmpty);
final argument = node.arguments.positional[0];
@@ -1783,7 +1784,7 @@ abstract class AstCodeGenerator
// accesses on constant lists (see https://dartbug.com/60313)
if (singleTarget == null &&
target.kind == ProcedureKind.Operator &&
target.name.text == '[]') {
target.name == indexGetName) {
final receiver = node.receiver;
if (receiver is ConstantExpression && receiver.constant is ListConstant) {
singleTarget = translator.listBaseIndexOperator;
@@ -1872,6 +1873,9 @@ abstract class AstCodeGenerator
}
translator.callFunction(forwarder.function, b);
if (callShape.isIndexSet) {
b.ref_null(w.HeapType.none);
}
return translator.topType;
}
@@ -2163,12 +2167,14 @@ abstract class AstCodeGenerator
translateExpression(node.value, paramType);
if (!preserved) {
call(node.targetReference);
b.drop(); // Drop `null` from setter call.
return voidMarker;
}
w.Local temp = addLocal(paramType);
b.local_tee(temp);
call(reference);
b.drop(); // Drop `null` from setter call.
b.local_get(temp);
return temp.type;
}
@@ -2416,6 +2422,7 @@ abstract class AstCodeGenerator
},
useUncheckedEntry: useUncheckedEntry,
);
b.drop(); // Drop `null` from setter call.
if (preserved) {
b.local_get(temp!);
return temp!.type;
@@ -2450,6 +2457,7 @@ abstract class AstCodeGenerator
b.local_tee(temp);
}
call(reference);
b.drop(); // Drop `null` from setter call.
if (preserved) {
b.local_get(temp!);
return temp.type;
@@ -3810,7 +3818,7 @@ class DynamicForwarderCodeGenerator extends AstCodeGenerator {
targetProcedure.reference,
uncheckedEntry: false,
);
final targetSignature = translator.signatureForDirectCall(target);
final callTarget = translator.directCallTarget(target);
_initializeThis(reference);
@@ -3821,7 +3829,11 @@ class DynamicForwarderCodeGenerator extends AstCodeGenerator {
// Load the receiver
final receiverLocal = paramLocals[argReceiverOffset];
b.local_get(receiverLocal);
translator.convertType(b, receiverLocal.type, targetSignature.inputs[0]);
translator.convertType(
b,
receiverLocal.type,
callTarget.signature.inputs[0],
);
// Load type parameters for target.
final targetTypeParams = targetFunction.typeParameters;
@@ -3862,7 +3874,7 @@ class DynamicForwarderCodeGenerator extends AstCodeGenerator {
final targetPositionalParams = targetFunction.positionalParameters;
for (int i = 0; i < targetParamInfo.positional.length; i++) {
final targetParamType =
targetSignature.inputs[1 + targetParamInfo.typeParamCount + i];
callTarget.signature.inputs[1 + targetParamInfo.typeParamCount + i];
if (i < callShape.positionalCount) {
// Provided by the caller.
final paramValue = paramLocals[argPositionalsOffset + i];
@@ -3898,7 +3910,7 @@ class DynamicForwarderCodeGenerator extends AstCodeGenerator {
final targetNamedParams = targetFunction.namedParameters;
for (int i = 0; i < targetParamInfo.names.length; ++i) {
final targetParamType =
targetSignature.inputs[1 +
callTarget.signature.inputs[1 +
targetParamInfo.typeParamCount +
targetParamInfo.positional.length +
i];
@@ -3935,12 +3947,10 @@ class DynamicForwarderCodeGenerator extends AstCodeGenerator {
}
}
call(target);
translator.convertType(
b,
translator.outputOrVoid(targetSignature.outputs),
translator.topType,
);
final outputs = translator.callTarget(callTarget, b);
if (outputs.isNotEmpty) {
translator.convertType(b, outputs.single, returnType);
}
b.return_();
b.end();
}
@@ -4026,6 +4036,7 @@ class DynamicForwarderCodeGenerator extends AstCodeGenerator {
b.local_get(positionalArgLocal);
translator.convertType(b, positionalArgLocal.type, setterInputs[1]);
call(target);
b.drop(); // Drop `null` from setter call.
}
b.end(); // end function
@@ -4868,7 +4879,7 @@ class StaticFieldImplicitAccessorCodeGenerator extends AstCodeGenerator {
if (initFunction == null) {
// Statically initialized
definition.read(translator, b);
// b.ref_cast(functionType.outputs.single as w.RefType);
translator.convertType(b, definition.type, returnType);
} else {
if (flag != null) {
// Explicit initialization flag
@@ -4878,6 +4889,7 @@ class StaticFieldImplicitAccessorCodeGenerator extends AstCodeGenerator {
b.else_();
translator.callFunction(initFunction, b);
b.end();
translator.convertType(b, definition.type, returnType);
} else {
// Null signals uninitialized
w.Label block = b.block(const [], [initFunction.type.outputs.single]);
@@ -4885,6 +4897,7 @@ class StaticFieldImplicitAccessorCodeGenerator extends AstCodeGenerator {
b.br_on_non_null(block);
translator.callFunction(initFunction, b);
b.end();
translator.convertType(b, initFunction.type.outputs.single, returnType);
}
}
}
+5 -3
View File
@@ -5,6 +5,7 @@
import 'dart:math' show min;
import 'package:kernel/ast.dart';
import 'package:kernel/names.dart';
import 'package:vm/metadata/procedure_attributes.dart';
import 'package:vm/metadata/table_selector.dart';
import 'package:vm/metadata/unreachable.dart';
@@ -110,7 +111,8 @@ class SelectorInfo {
/// returns are subtypes (resp. supertypes) of the types in the signature.
w.FunctionType _computeSignature() {
var nameIndex = paramInfo.nameIndex;
final int returnCount = (isSetter || isIndexSetter) ? 0 : 1;
final bool isSetterOrIndexSetter = (isSetter || isIndexSetter);
final int returnCount = isSetterOrIndexSetter ? 0 : 1;
List<Set<w.ValueType>> inputSets = List.generate(
1 + paramInfo.paramCount,
(_) => {},
@@ -215,7 +217,7 @@ class SelectorInfo {
outputs.clear();
synthesizeNullReturnValue = true;
} else {
synthesizeNullReturnValue = false;
synthesizeNullReturnValue = isSetterOrIndexSetter;
}
return translator.typesBuilder.defineFunction([
inputs[0],
@@ -444,7 +446,7 @@ class DispatchTable {
Member member = target.asMember;
bool isGetter = target.isGetter || target.isTearOffReference;
bool isSetter = target.isSetter;
bool isIndexSetter = member.name.text == '[]=';
bool isIndexSetter = member.name == indexSetName;
ProcedureAttributesMetadata metadata = procedureAttributeMetadata[member]!;
int selectorId = isGetter
? metadata.getterSelectorId
+22 -8
View File
@@ -61,6 +61,7 @@ void transformLibraries(
}
class WasmFfiNativeTransformer extends FfiNativeTransformer {
final Class wasmVoidClass;
final Class wasmI32Class;
final Class wasmI64Class;
final Class wasmF32Class;
@@ -90,7 +91,8 @@ class WasmFfiNativeTransformer extends FfiNativeTransformer {
super.hierarchy,
super.diagnosticReporter,
super.referenceFromIndex,
) : wasmI32Class = index.getClass('dart:_wasm', 'WasmI32'),
) : wasmVoidClass = index.getClass('dart:_wasm', 'WasmVoid'),
wasmI32Class = index.getClass('dart:_wasm', 'WasmI32'),
wasmI64Class = index.getClass('dart:_wasm', 'WasmI64'),
wasmF32Class = index.getClass('dart:_wasm', 'WasmF32'),
wasmF64Class = index.getClass('dart:_wasm', 'WasmF64'),
@@ -149,6 +151,11 @@ class WasmFfiNativeTransformer extends FfiNativeTransformer {
),
pointerAddressField = index.getField('dart:ffi', 'Pointer', '_address');
late final wasmVoidType = InterfaceType(
wasmVoidClass,
Nullability.nonNullable,
);
@override
visitProcedure(Procedure node) {
// Only transform functions that are external and have Native annotation:
@@ -229,7 +236,7 @@ class WasmFfiNativeTransformer extends FfiNativeTransformer {
}
final retWasmType = _convertFfiTypeToWasmType(ffiFunctionType.returnType);
final retWasmType_ = retWasmType ?? VoidType();
final isVoidReturn = retWasmType == null;
final wasmImportProcedure = Procedure(
wasmImportName,
@@ -237,7 +244,7 @@ class WasmFfiNativeTransformer extends FfiNativeTransformer {
FunctionNode(
null,
positionalParameters: wasmImportProcedureArgs,
returnType: retWasmType_,
returnType: isVoidReturn ? wasmVoidType : retWasmType,
),
fileUri: node.fileUri,
isExternal: true,
@@ -274,12 +281,19 @@ class WasmFfiNativeTransformer extends FfiNativeTransformer {
}
// Convert return value
node.function.body = ReturnStatement(
_ffiValueToDartValue(
ffiFunctionType.returnType,
StaticInvocation(wasmImportProcedure, Arguments(ffiCallArgs)),
),
final resultExpression = _ffiValueToDartValue(
ffiFunctionType.returnType,
StaticInvocation(wasmImportProcedure, Arguments(ffiCallArgs)),
);
if (isVoidReturn) {
node.function.body = Block([
ExpressionStatement(resultExpression),
ReturnStatement(NullLiteral()),
])..parent = node.function.body;
} else {
node.function.body = ReturnStatement(resultExpression)
..parent = node.function.body;
}
return node;
}
+21 -19
View File
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:kernel/ast.dart';
import 'package:kernel/names.dart';
import 'package:wasm_builder/wasm_builder.dart' as w;
import 'closures.dart';
@@ -272,7 +273,8 @@ class FunctionCollector {
bool synthesizeNullReturnValue(Reference target) {
final member = target.asMember;
if (member is! Procedure) return false;
if (target.isSetter) return true;
if (member.name == indexSetName) return true;
final returnType = translator.typeOfReturnValue(member);
final wasmType = translator.translateType(returnType);
@@ -756,9 +758,7 @@ w.FunctionType makeFunctionTypeForBody(
translator.translateType(translator.typeOfCheckedParameterVariable(p)),
];
final hasNoReturnValue =
member is Procedure && (member.isSetter || member.name.text == '[]=') ||
synthesizeNullReturnValue;
final hasNoReturnValue = synthesizeNullReturnValue;
final outputs = [
if (!hasNoReturnValue)
translator.translateReturnType(translator.typeOfReturnValue(member)),
@@ -796,16 +796,13 @@ w.FunctionType _makeDynamicSignature(
], []);
case MethodCallShape():
return translator.typesBuilder.defineFunction(
[
nullableReceiver ? translator.topType : translator.topTypeNonNullable,
for (int i = 0; i < shape.typeCount; ++i)
translator.translateType(translator.types.typeType),
for (int i = 0; i < shape.positionalCount; ++i) translator.topType,
for (int i = 0; i < shape.named.length; ++i) translator.topType,
],
[translator.topType],
);
return translator.typesBuilder.defineFunction([
nullableReceiver ? translator.topType : translator.topTypeNonNullable,
for (int i = 0; i < shape.typeCount; ++i)
translator.translateType(translator.types.typeType),
for (int i = 0; i < shape.positionalCount; ++i) translator.topType,
for (int i = 0; i < shape.named.length; ++i) translator.topType,
], shape.isIndexSet ? [] : [translator.topType]);
}
}
@@ -850,7 +847,13 @@ w.FunctionType _makeFunctionType(
if (member is Field && !member.isInstanceMember) {
final fieldType = translator.translateTypeOfField(member);
if (target.isImplicitGetter || target.isStaticFieldInitializer) {
if (target.isImplicitGetter) {
return translator.typesBuilder.defineFunction(
const [],
synthesizeNullReturnValue ? [] : [fieldType],
);
}
if (target.isStaticFieldInitializer) {
return translator.typesBuilder.defineFunction(const [], [fieldType]);
}
assert(target.isImplicitSetter);
@@ -878,11 +881,8 @@ w.FunctionType _makeFunctionType(
(t is InterfaceType && t.classNode == translator.wasmVoidClass);
final List<w.ValueType> outputs;
final hasNoReturnValue =
target.isSetter || member.name.text == '[]=' || synthesizeNullReturnValue;
final hasNoReturnValue = target.isSetter || synthesizeNullReturnValue;
if (hasNoReturnValue) {
// Setters and []= are the only functions without any returned values. All
// other functions can return values (even `void` returning functions).
outputs = const [];
} else {
final DartType returnType = translator.typeOfReturnValue(member);
@@ -910,6 +910,8 @@ final class MethodCallShape extends CallShape {
MethodCallShape(super.name, this.typeCount, this.positionalCount, this.named);
bool get isIndexSet => name == indexSetName;
@override
bool get isGetter => false;
@override
+32 -16
View File
@@ -878,7 +878,8 @@ class Intrinsifier {
assert(name == '[]=');
codeGen.translateExpression(node.arguments.positional[1], table.type);
b.table_set(table);
return codeGen.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
}
}
@@ -1188,7 +1189,8 @@ class Intrinsifier {
b.i32_wrap_i64();
codeGen.translateExpression(value, typeOfExp(value));
b.array_set(arrayType);
return codeGen.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.wasmArrayCopy:
assert(fieldType.mutable);
final destArray = node.arguments.positional[0];
@@ -1212,7 +1214,8 @@ class Intrinsifier {
codeGen.translateExpression(size, w.NumType.i64);
b.i32_wrap_i64();
b.array_copy(arrayType, arrayType);
return codeGen.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.wasmArrayFill:
assert(fieldType.mutable);
final array = node.arguments.positional[0];
@@ -1233,7 +1236,8 @@ class Intrinsifier {
codeGen.translateExpression(size, w.NumType.i64);
b.i32_wrap_i64();
b.array_fill(arrayType);
return codeGen.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.wasmArrayClone:
assert(fieldType.mutable);
// Until `array.new_copy` we need a special case for empty arrays.
@@ -1339,7 +1343,8 @@ class Intrinsifier {
}
}
b.array_set(arrayType);
return codeGen.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.identical:
// We can use reference equality for `identical()` except if one of the
@@ -1445,7 +1450,8 @@ class Intrinsifier {
codeGen.translateExpression(hash, w.NumType.i64);
b.i32_wrap_i64();
b.struct_set(translator.objectInfo.struct, FieldIndex.identityHash);
return codeGen.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
// dart:_internal static functions
case StaticIntrinsic.unsafeCast:
@@ -1612,7 +1618,8 @@ class Intrinsifier {
w.NumType.i64,
);
b.i64_store8(translator.ffiMemory, offset);
return translator.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeInt16:
case StaticIntrinsic.storeUint16:
codeGen.translateExpression(
@@ -1620,7 +1627,8 @@ class Intrinsifier {
w.NumType.i64,
);
b.i64_store16(translator.ffiMemory, offset);
return translator.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeInt32:
case StaticIntrinsic.storeUint32:
codeGen.translateExpression(
@@ -1628,7 +1636,8 @@ class Intrinsifier {
w.NumType.i64,
);
b.i64_store32(translator.ffiMemory, offset);
return translator.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeInt64:
case StaticIntrinsic.storeUint64:
codeGen.translateExpression(
@@ -1636,7 +1645,8 @@ class Intrinsifier {
w.NumType.i64,
);
b.i64_store(translator.ffiMemory, offset);
return translator.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeFloat:
codeGen.translateExpression(
node.arguments.positional[2],
@@ -1644,7 +1654,8 @@ class Intrinsifier {
);
b.f32_demote_f64();
b.f32_store(translator.ffiMemory, offset);
return translator.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeFloatUnaligned:
codeGen.translateExpression(
node.arguments.positional[2],
@@ -1652,21 +1663,24 @@ class Intrinsifier {
);
b.f32_demote_f64();
b.f32_store(translator.ffiMemory, offset, 0);
return translator.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeDouble:
codeGen.translateExpression(
node.arguments.positional[2],
w.NumType.f64,
);
b.f64_store(translator.ffiMemory, offset);
return translator.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeDoubleUnaligned:
codeGen.translateExpression(
node.arguments.positional[2],
w.NumType.f64,
);
b.f64_store(translator.ffiMemory, offset, 0);
return translator.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
default:
throw StateError('Unhandled ffi intrinsic: $intrinsic');
}
@@ -2554,7 +2568,8 @@ class Intrinsifier {
codeGen.translateExpression(length, w.NumType.i64);
b.i32_wrap_i64();
b.memory_fill(memory);
return codeGen.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.wasmMemoryLoadFloat32:
case StaticIntrinsic.wasmMemoryLoadFloat64:
case StaticIntrinsic.wasmMemoryLoadInt8:
@@ -2641,7 +2656,8 @@ class Intrinsifier {
throw AssertionError('unreachable');
}
return codeGen.voidMarker;
b.ref_null(w.HeapType.none);
return translator.topType;
}
}
@@ -4,6 +4,7 @@
import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/names.dart';
import 'records.dart';
import 'util.dart';
@@ -177,7 +178,7 @@ class _RecordClassGenerator {
.extensions
.singleWhere((e) => e.name == 'WasmArrayExt')
.memberDescriptors
.singleWhere((member) => member.name.text == '[]')
.singleWhere((member) => member.name == indexGetName)
.memberReference!
.node
as Procedure;
+23 -16
View File
@@ -9,6 +9,7 @@ import 'package:kernel/class_hierarchy.dart'
show ClassHierarchy, ClassHierarchySubtypes, ClosedWorldClassHierarchy;
import 'package:kernel/core_types.dart';
import 'package:kernel/library_index.dart';
import 'package:kernel/names.dart';
import 'package:kernel/src/printer.dart';
import 'package:kernel/type_environment.dart';
import 'package:vm/metadata/direct_call.dart';
@@ -1507,11 +1508,8 @@ class Translator with KernelNodes {
}
if (to != voidMarker) {
// This can happen e.g. when a `return;` is guaranteed to be never taken
// but TFA didn't remove the dead code. In that case we synthesize a
// dummy value.
getDummyValuesCollectorForModule(
b.moduleBuilder,
).instantiateLocalDummyValue(b, to);
// but TFA didn't remove the dead code.
b.unreachable();
return;
}
}
@@ -1956,7 +1954,7 @@ class Translator with KernelNodes {
// If [node] is a parameter of a `operator==` method, then the argument to
// it cannot be nullable.
final member = node.parent!.parent;
if (member is Procedure && member.name.text == '==') {
if (member is Procedure && member.name == equalsName) {
return coreTypes.objectNonNullableRawType;
}
// The type argument of a static type is not required to conform
@@ -2721,11 +2719,14 @@ class _ClosureTrampolineGenerator implements CodeGenerator {
assert(targetIndex == target.signature.inputs.length);
assert(argNameIndex == argNames.length);
translator.convertType(
b,
translator.callTarget(target, b).single,
translator.outputOrVoid(trampoline.type.outputs),
);
final outputs = translator.callTarget(target, b);
if (outputs.isNotEmpty) {
translator.convertType(
b,
outputs.single,
translator.outputOrVoid(trampoline.type.outputs),
);
}
b.end();
}
}
@@ -2912,11 +2913,17 @@ class _ClosureDynamicEntryGenerator implements CodeGenerator {
inputIdx += 1;
}
translator.convertType(
b,
translator.callTarget(target, b).single,
translator.outputOrVoid(function.type.outputs),
);
final outputs = translator.callTarget(target, b);
if (outputs.isNotEmpty) {
translator.convertType(
b,
outputs.single,
translator.outputOrVoid(function.type.outputs),
);
} else if (function.type.outputs.isNotEmpty) {
assert(target.synthesizeNullReturnValue);
b.ref_null(w.HeapType.none);
}
b.end(); // end function
}
+4 -4
View File
@@ -25,7 +25,7 @@
(i32.const 0)
(global.get $global0)
(ref.func $"bar tear-off trampoline")
(ref.func $"bar tear-off trampoline_115")
(ref.func $"bar tear-off trampoline_116")
(struct.new $#Vtable-0-2)
(i32.const 11)
(i32.const 0)
@@ -50,7 +50,7 @@
(i32.const 0)
(global.get $global0)
(ref.func $"foo tear-off trampoline")
(ref.func $"foo tear-off trampoline_113")
(ref.func $"foo tear-off trampoline_114")
(struct.new $#Vtable-0-2)
(i32.const 11)
(i32.const 0)
@@ -74,7 +74,7 @@
(global $_TopType_290 (ref $_TopType) <...>)
(global $global0 (ref $"dummy struct") <...>)
(func $bar tear-off trampoline (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $bar tear-off trampoline_115 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $bar tear-off trampoline_116 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $foo tear-off trampoline (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $foo tear-off trampoline_113 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $foo tear-off trampoline_114 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
)
@@ -25,7 +25,7 @@
(i32.const 0)
(global.get $global0)
(ref.func $"bar tear-off trampoline")
(ref.func $"bar tear-off trampoline_118")
(ref.func $"bar tear-off trampoline_119")
(struct.new $#Vtable-0-2)
(i32.const 11)
(i32.const 0)
@@ -50,7 +50,7 @@
(i32.const 0)
(global.get $global0)
(ref.func $"foo tear-off trampoline")
(ref.func $"foo tear-off trampoline_114")
(ref.func $"foo tear-off trampoline_115")
(struct.new $#Vtable-0-2)
(i32.const 11)
(i32.const 0)
@@ -74,7 +74,7 @@
(global $_TopType_290 (ref $_TopType) <...>)
(global $global0 (ref $"dummy struct") <...>)
(func $bar tear-off trampoline (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $bar tear-off trampoline_118 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $bar tear-off trampoline_119 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $foo tear-off trampoline (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $foo tear-off trampoline_114 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $foo tear-off trampoline_115 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
)
@@ -29,7 +29,7 @@
(i32.const 0)
(global.get $global0)
(ref.func $"bar tear-off dynamic call entry")
(ref.func $"bar tear-off trampoline_121")
(ref.func $"bar tear-off trampoline_122")
(struct.new $#Vtable-0-2)
(i32.const 11)
(i32.const 0)
@@ -49,7 +49,7 @@
(i32.const 0)
(global.get $global0)
(ref.func $"foo tear-off dynamic call entry")
(ref.func $"foo tear-off trampoline_116")
(ref.func $"foo tear-off trampoline_117")
(struct.new $#Vtable-0-2)
(i32.const 11)
(i32.const 0)
@@ -74,7 +74,7 @@
(global $_TopType_290 (ref $_TopType) <...>)
(global $global0 (ref $"dummy struct") <...>)
(func $bar tear-off dynamic call entry (param $var0 (ref $#Closure-0-0)) (param $var1 (ref $Array<_Type>)) (param $var2 (ref $Array<Object?>)) (param $var3 (ref $Array<Object?>)) (result (ref null $#Top)) <...>)
(func $bar tear-off trampoline_121 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $bar tear-off trampoline_122 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $foo tear-off dynamic call entry (param $var0 (ref $#Closure-0-0)) (param $var1 (ref $Array<_Type>)) (param $var2 (ref $Array<Object?>)) (param $var3 (ref $Array<Object?>)) (result (ref null $#Top)) <...>)
(func $foo tear-off trampoline_116 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $foo tear-off trampoline_117 (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (param $var2 (ref null $#Top)) (result (ref null $#Top)) <...>)
)
@@ -41,9 +41,10 @@ external void _invokeMainInternal(WasmExternRef jsArray);
/// Used to invoke the `main` function from JS, printing any exceptions that
/// escape.
@pragma("wasm:export", "\$invokeMain")
void _invokeMain(WasmExternRef jsArrayRef) {
WasmVoid _invokeMain(WasmExternRef jsArrayRef) {
try {
_invokeMainInternal(jsArrayRef);
return WasmVoid();
} catch (e, s) {
print(e);
print(s);
@@ -455,11 +455,12 @@ WasmI32 _wasmI8ArrayGet(WasmExternRef? ref, WasmI32 index) {
}
@pragma("wasm:weak-export", "\$wasmI8ArraySet")
void _wasmI8ArraySet(WasmExternRef? ref, WasmI32 index, WasmI32 value) {
WasmVoid _wasmI8ArraySet(WasmExternRef? ref, WasmI32 index, WasmI32 value) {
final array = unsafeCastOpaque<WasmArray<WasmI8>>(
unsafeCast<WasmExternRef>(ref).internalize(),
);
array.write(index.toIntUnsigned(), value.toIntUnsigned());
return WasmVoid();
}
@pragma("wasm:export", "\$wasmI16ArrayGet")
@@ -471,11 +472,12 @@ WasmI32 _wasmI16ArrayGet(WasmExternRef? ref, WasmI32 index) {
}
@pragma("wasm:export", "\$wasmI16ArraySet")
void _wasmI16ArraySet(WasmExternRef? ref, WasmI32 index, WasmI32 value) {
WasmVoid _wasmI16ArraySet(WasmExternRef? ref, WasmI32 index, WasmI32 value) {
final array = unsafeCastOpaque<WasmArray<WasmI16>>(
unsafeCast<WasmExternRef>(ref).internalize(),
);
array.write(index.toIntUnsigned(), value.toIntUnsigned());
return WasmVoid();
}
@pragma("wasm:weak-export", "\$wasmI32ArrayGet")
@@ -487,11 +489,12 @@ WasmI32 _wasmI32ArrayGet(WasmExternRef? ref, WasmI32 index) {
}
@pragma("wasm:weak-export", "\$wasmI32ArraySet")
void _wasmI32ArraySet(WasmExternRef? ref, WasmI32 index, WasmI32 value) {
WasmVoid _wasmI32ArraySet(WasmExternRef? ref, WasmI32 index, WasmI32 value) {
final array = unsafeCastOpaque<WasmArray<WasmI32>>(
unsafeCast<WasmExternRef>(ref).internalize(),
);
array.write(index.toIntUnsigned(), value.toIntUnsigned());
return WasmVoid();
}
@pragma("wasm:weak-export", "\$wasmF32ArrayGet")
@@ -503,11 +506,12 @@ WasmF32 _wasmF32ArrayGet(WasmExternRef? ref, WasmI32 index) {
}
@pragma("wasm:weak-export", "\$wasmF32ArraySet")
void _wasmF32ArraySet(WasmExternRef? ref, WasmI32 index, WasmF32 value) {
WasmVoid _wasmF32ArraySet(WasmExternRef? ref, WasmI32 index, WasmF32 value) {
final array = unsafeCastOpaque<WasmArray<WasmF32>>(
unsafeCast<WasmExternRef>(ref).internalize(),
);
array[index.toIntUnsigned()] = value;
return WasmVoid();
}
@pragma("wasm:weak-export", "\$wasmF64ArrayGet")
@@ -519,9 +523,10 @@ WasmF64 _wasmF64ArrayGet(WasmExternRef? ref, WasmI32 index) {
}
@pragma("wasm:weak-export", "\$wasmF64ArraySet")
void _wasmF64ArraySet(WasmExternRef? ref, WasmI32 index, WasmF64 value) {
WasmVoid _wasmF64ArraySet(WasmExternRef? ref, WasmI32 index, WasmF64 value) {
final array = unsafeCastOpaque<WasmArray<WasmF64>>(
unsafeCast<WasmExternRef>(ref).internalize(),
);
array[index.toIntUnsigned()] = value;
return WasmVoid();
}