mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 04:27:17 +00:00
[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:
parent
0e2483cf64
commit
203344cf5d
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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 []);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue