[dart2wasm] Add support for runtime types for function types.

Change-Id: I3c446b8ef7dd9b1edc612b9e27893870a25c54d4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/261160
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Joshua Litt <joshualitt@google.com>
This commit is contained in:
Joshua Litt 2022-09-27 20:44:35 +00:00 committed by Commit Queue
parent 0e2483cf64
commit 203344cf5d
9 changed files with 54 additions and 20 deletions

View file

@ -25,6 +25,7 @@ class FieldIndex {
static const hashBaseData = 4;
static const closureContext = 2;
static const closureVtable = 3;
static const closureRuntimeType = 4;
static const typeIsNullable = 2;
static const interfaceTypeTypeArguments = 4;
static const functionTypeNamedParameters = 6;

View file

@ -115,7 +115,6 @@ class ClosureLayouter extends RecursiveVisitor {
Set<Constant> visitedConstants = Set.identity();
// Base struct for vtables.
// TODO(joshualitt): Add function type metadata here.
late final w.StructType vtableBaseStruct = m.addStructType("#VtableBase");
// Base struct for closures.
@ -129,13 +128,15 @@ class ClosureLayouter extends RecursiveVisitor {
// - An identity hash
// - A context reference (used for `this` in tear-offs)
// - A vtable reference
// - A type
return m.addStructType("#ClosureBase",
fields: [
w.FieldType(w.NumType.i32),
w.FieldType(w.NumType.i32),
w.FieldType(w.RefType.data(nullable: false)),
w.FieldType(w.RefType.def(vtableStruct, nullable: false),
mutable: false)
mutable: false),
w.FieldType(typeType, mutable: false)
],
superType: superType);
}

View file

@ -177,6 +177,9 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
}
void generateTearOffGetter(Procedure procedure) {
_initializeThis(member);
DartType functionType =
procedure.function.computeThisFunctionType(Nullability.nonNullable);
ClosureImplementation closure = translator.getTearOffClosure(procedure);
w.StructType struct = closure.representation.closureStruct;
@ -187,6 +190,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
b.i32_const(initialIdentityHash);
b.local_get(paramLocals[0]);
b.global_get(closure.vtable);
types.makeType(this, functionType);
b.struct_new(struct);
b.end();
}
@ -1752,6 +1756,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
// Super tear-off
w.StructType closureStruct = _pushClosure(
translator.getTearOffClosure(target),
target.function.computeThisFunctionType(Nullability.nonNullable),
() => visitThis(w.RefType.data(nullable: false)));
return w.RefType.def(closureStruct, nullable: false);
}
@ -1948,10 +1953,14 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
lambda.function,
ParameterInfo.fromLocalFunction(functionNode),
"closure wrapper at ${functionNode.location}");
return _pushClosure(closure, () => _pushContext(functionNode));
return _pushClosure(
closure,
functionNode.computeThisFunctionType(Nullability.nonNullable),
() => _pushContext(functionNode));
}
w.StructType _pushClosure(ClosureImplementation closure, void pushContext()) {
w.StructType _pushClosure(ClosureImplementation closure,
DartType functionType, void pushContext()) {
w.StructType struct = closure.representation.closureStruct;
ClassInfo info = translator.classInfo[translator.functionClass]!;
@ -1961,6 +1970,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
b.i32_const(initialIdentityHash);
pushContext();
b.global_get(closure.vtable);
types.makeType(this, functionType);
b.struct_new(struct);
return struct;

View file

@ -12,7 +12,7 @@ import 'package:dart2wasm/translator.dart';
import 'package:dart2wasm/types.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/type_algebra.dart' show substitute;
import 'package:kernel/type_algebra.dart' show substitute, Substitution;
import 'package:wasm_builder/wasm_builder.dart' as w;
@ -698,6 +698,9 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?> {
@override
ConstantInfo? visitStaticTearOffConstant(StaticTearOffConstant constant) {
Procedure member = constant.targetReference.asProcedure;
Constant functionTypeConstant = TypeLiteralConstant(
member.function.computeThisFunctionType(Nullability.nonNullable));
ensureConstant(functionTypeConstant);
ClosureImplementation closure = translator.getTearOffClosure(member);
w.StructType struct = closure.representation.closureStruct;
w.RefType type = w.RefType.def(struct, nullable: false);
@ -709,6 +712,8 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?> {
b.i32_const(initialIdentityHash);
b.global_get(translator.globals.dummyGlobal); // Dummy context
b.global_get(closure.vtable);
constants.instantiateConstant(
function, b, functionTypeConstant, this.types.nonNullableTypeType);
b.struct_new(struct);
});
}
@ -720,8 +725,17 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?> {
List<ConstantInfo> types = constant.types
.map((c) => ensureConstant(TypeLiteralConstant(c))!)
.toList();
ClosureImplementation tearOffClosure = translator
.getTearOffClosure(tearOffConstant.targetReference.asProcedure);
Procedure tearOffProcedure = tearOffConstant.targetReference.asProcedure;
FunctionType tearOffFunctionType = tearOffProcedure.function
.computeThisFunctionType(Nullability.nonNullable);
FunctionType instantiatedFunctionType = Substitution.fromPairs(
tearOffFunctionType.typeParameters, constant.types)
.substituteType(tearOffFunctionType) as FunctionType;
Constant functionTypeConstant =
TypeLiteralConstant(instantiatedFunctionType);
ensureConstant(functionTypeConstant);
ClosureImplementation tearOffClosure =
translator.getTearOffClosure(tearOffProcedure);
int positionalCount = tearOffConstant.function.positionalParameters.length;
List<String> names =
tearOffConstant.function.namedParameters.map((p) => p.name!).toList();
@ -771,7 +785,6 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?> {
}
void makeVtable() {
// TODO(joshualitt): Generate function type metadata here.
for (int posArgCount = 0;
posArgCount <= positionalCount;
posArgCount++) {
@ -787,6 +800,8 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?> {
b.i32_const(initialIdentityHash);
b.global_get(translator.globals.dummyGlobal); // Dummy context
makeVtable();
constants.instantiateConstant(
function, b, functionTypeConstant, this.types.nonNullableTypeType);
b.struct_new(struct);
});
}

View file

@ -716,6 +716,13 @@ class Intrinsifier {
return translator.types.makeTypeRulesSubstitutions(b);
case "_getTypeNames":
return translator.types.makeTypeNames(b);
case "_getFunctionTypeRuntimeType":
Expression object = node.arguments.positional[0];
w.StructType closureBase =
translator.closureLayouter.closureBaseStruct;
codeGen.wrap(object, w.RefType.def(closureBase, nullable: true));
b.struct_get(closureBase, FieldIndex.closureRuntimeType);
return translator.types.typeClassInfo.nonNullableType;
case "_getInterfaceTypeRuntimeType":
Expression object = node.arguments.positional[0];
Expression typeArguments = node.arguments.positional[1];

View file

@ -801,7 +801,6 @@ class Translator {
w.RefType.def(representation.vtableStruct, nullable: false),
mutable: false));
w.Instructions ib = vtable.initializer;
// TODO(joshualitt): Generate function type metadata here.
for (int posArgCount = 0; posArgCount <= positionalCount; posArgCount++) {
fillVtableEntry(ib, posArgCount, const []);
}

View file

@ -431,10 +431,9 @@ class Types {
void emitTypeTest(CodeGenerator codeGen, DartType type, DartType operandType,
TreeNode node) {
w.Instructions b = codeGen.b;
if (type is FunctionType) {
// TODO(joshualitt): We can enable type tests for [FunctionType] after
// enabling `.runtimeType` for [FunctionType].
print("Not implemented: Type test with function type $type"
if (type is FunctionType && isGenericFunction(type)) {
// TODO(joshualitt): Finish generic function types.
print("Not implemented: Type test with generic function type $type"
" at ${node.location}");
b.drop();
b.i32_const(1);

View file

@ -11,6 +11,8 @@ external void _setHash(Object obj, int hash);
external _Type _getInterfaceTypeRuntimeType(
Object object, List<Type> typeArguments);
external _Type _getFunctionTypeRuntimeType(Object object);
@patch
class Object {
@patch
@ -47,7 +49,13 @@ class Object {
external Type get runtimeType;
@pragma("wasm:entry-point")
_Type get _runtimeType => _getInterfaceTypeRuntimeType(this, _typeArguments);
_Type get _runtimeType {
if (ClassID.getID(this) == ClassID.cid_Function) {
return _getFunctionTypeRuntimeType(this);
} else {
return _getInterfaceTypeRuntimeType(this, _typeArguments);
}
}
@patch
String toString() => _toString(this);

View file

@ -659,12 +659,6 @@ class _TypeUniverse {
return true;
}
// TODO(joshualitt): This is not correct, but it is necessary until we fully
// implement RTI for FunctionTypes.
if (isFunctionType(s) && (t.isFunction || t.isGenericFunction)) {
return true;
}
// Positional Function Types + Named Function Types:
if (s.isGenericFunction && t.isGenericFunction) {
// TODO(joshualitt): Implement case.