mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:09:49 +00:00
[dart2wasm] Put function types of imports in singleton rec groups
Starting from ba6be821c99db09b0ef2689dea8f0cb863c47ff5 (11.0.194), V8 enforces type equivalence according to the canonical iso-recursive types for functions imported from other modules or constructed using `WebAssembly.Function`, which means that to match such a type, a function type declared in a Wasm module must be declared in a singleton rec group. To be compatible with this new canonicalization scheme, we define the function types for all imported functions each in their own rec group separately from other types. Change-Id: I166b4b7d1c8fa48638f816f874f737536a61f15d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274388 Commit-Queue: Aske Simon Christensen <askesc@google.com> Reviewed-by: Joshua Litt <joshualitt@google.com>
This commit is contained in:
parent
905b913a77
commit
f053d2170d
|
@ -66,9 +66,14 @@ class FunctionCollector {
|
|||
String module = importName.substring(0, dot);
|
||||
String name = importName.substring(dot + 1);
|
||||
if (member is Procedure) {
|
||||
// Define the function type in a singular recursion group to enable it
|
||||
// to be unified with function types defined in FFI modules or using
|
||||
// `WebAssembly.Function`.
|
||||
m.splitRecursionGroup();
|
||||
w.FunctionType ftype = _makeFunctionType(
|
||||
translator, member.reference, member.function.returnType, null,
|
||||
isImportOrExport: true);
|
||||
m.splitRecursionGroup();
|
||||
_functions[member.reference] =
|
||||
m.importFunction(module, name, ftype, "$importName (import)");
|
||||
}
|
||||
|
@ -242,34 +247,29 @@ w.FunctionType _makeFunctionType(Translator translator, Reference target,
|
|||
function.positionalParameters.map((p) => p.type);
|
||||
}
|
||||
|
||||
List<w.ValueType> typeParameters = List.filled(typeParamCount,
|
||||
translator.classInfo[translator.typeClass]!.nonNullableType);
|
||||
// Translate types differently for imports and exports.
|
||||
w.ValueType translateType(DartType type) => isImportOrExport
|
||||
? translator.translateExternalType(type)
|
||||
: translator.translateType(type);
|
||||
|
||||
// The only reference types allowed as parameters and returns on imported or
|
||||
// exported functions for JS interop are `externref` and `funcref`.
|
||||
w.ValueType adjustExternalType(w.ValueType type) {
|
||||
if (isImportOrExport && type is w.RefType) {
|
||||
if (type.heapType.isSubtypeOf(w.HeapType.func)) {
|
||||
return w.RefType.func(nullable: true);
|
||||
}
|
||||
return w.RefType.extern(nullable: true);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
List<w.ValueType> typeParameters = List.filled(
|
||||
typeParamCount,
|
||||
translateType(
|
||||
InterfaceType(translator.typeClass, Nullability.nonNullable)));
|
||||
|
||||
List<w.ValueType> inputs = [];
|
||||
if (receiverType != null) {
|
||||
inputs.add(adjustExternalType(receiverType));
|
||||
assert(!isImportOrExport);
|
||||
inputs.add(receiverType);
|
||||
}
|
||||
inputs.addAll(typeParameters.map(adjustExternalType));
|
||||
inputs.addAll(
|
||||
params.map((t) => adjustExternalType(translator.translateType(t))));
|
||||
inputs.addAll(typeParameters);
|
||||
inputs.addAll(params.map(translateType));
|
||||
|
||||
List<w.ValueType> outputs = returnType is VoidType
|
||||
? member.function?.asyncMarker == AsyncMarker.Async
|
||||
? [adjustExternalType(translator.topInfo.nullableType)]
|
||||
? [translateType(translator.coreTypes.objectNullableRawType)]
|
||||
: const []
|
||||
: [adjustExternalType(translator.translateType(returnType))];
|
||||
: [translateType(returnType)];
|
||||
|
||||
return translator.m.addFunctionType(inputs, outputs);
|
||||
}
|
||||
|
|
|
@ -196,9 +196,12 @@ class Translator with KernelNodes {
|
|||
voidMarker = w.RefType.def(w.StructType("void"), nullable: true);
|
||||
mainFunction = _findMainMethod(libraries.first);
|
||||
|
||||
// Collect imports and exports as the very first thing so the function types
|
||||
// for the imports can be places in singleton recursion groups.
|
||||
functions.collectImportsAndExports();
|
||||
|
||||
closureLayouter.collect([mainFunction.function]);
|
||||
classInfoCollector.collect();
|
||||
functions.collectImportsAndExports();
|
||||
|
||||
initFunction =
|
||||
m.addFunction(m.addFunctionType(const [], const []), "#init");
|
||||
|
@ -495,6 +498,30 @@ class Translator with KernelNodes {
|
|||
() => m.addArrayType("Array<$name>", elementType: w.FieldType(type)));
|
||||
}
|
||||
|
||||
/// Translate a Dart type as it should appear on parameters and returns of
|
||||
/// imported and exported functions. The only reference types allowed here
|
||||
/// for JS interop are `externref` and `funcref`.
|
||||
///
|
||||
/// This function can be called before the class info is built.
|
||||
w.ValueType translateExternalType(DartType type) {
|
||||
if (type is InterfaceType) {
|
||||
Class cls = type.classNode;
|
||||
if (cls == wasmFuncRefClass || cls == wasmFunctionClass) {
|
||||
return w.RefType.func(nullable: true);
|
||||
}
|
||||
if (!type.isPotentiallyNullable) {
|
||||
w.StorageType? builtin = builtinTypes[cls];
|
||||
if (builtin != null && builtin.isPrimitive) {
|
||||
return builtin as w.ValueType;
|
||||
}
|
||||
if (isFfiCompound(cls)) {
|
||||
return w.NumType.i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
return w.RefType.extern(nullable: true);
|
||||
}
|
||||
|
||||
w.DefinedGlobal makeFunctionRef(w.BaseFunction f) {
|
||||
return functionRefCache.putIfAbsent(f, () {
|
||||
w.DefinedGlobal global = m.addGlobal(
|
||||
|
|
|
@ -121,7 +121,12 @@ class Module with SerializerMixin {
|
|||
/// Insert a recursion group split in the list of type definitions. Types can
|
||||
/// only reference other types in the same or earlier recursion groups.
|
||||
void splitRecursionGroup() {
|
||||
recursionGroupSplits.add(defTypes.length);
|
||||
int typeCount = defTypes.length;
|
||||
if (typeCount > 0 &&
|
||||
(recursionGroupSplits.isEmpty ||
|
||||
recursionGroupSplits.last != typeCount)) {
|
||||
recursionGroupSplits.add(typeCount);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a new function to the module with the given function type.
|
||||
|
|
Loading…
Reference in a new issue