[dart2wasm] Use #ClosureBase as representation type for Function.

Also renamed the `_Function` class to `_Closure` and fixed the name of
closure structs so they aren't all called `#ClosureBase`.

Change-Id: I6b55cb9827fdffac751dfc3043f3a36e7a18f225
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279091
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
This commit is contained in:
Aske Simon Christensen 2023-01-17 11:58:16 +00:00 committed by Commit Queue
parent 5a5a83031b
commit 5d77ea8cfe
14 changed files with 57 additions and 53 deletions

View file

@ -61,7 +61,7 @@ class FieldIndex {
check(translator.listBaseClass, "_data", FieldIndex.listArray);
check(translator.hashFieldBaseClass, "_index", FieldIndex.hashBaseIndex);
check(translator.hashFieldBaseClass, "_data", FieldIndex.hashBaseData);
check(translator.functionClass, "context", FieldIndex.closureContext);
check(translator.closureClass, "context", FieldIndex.closureContext);
check(translator.typeClass, "isDeclaredNullable",
FieldIndex.typeIsDeclaredNullable);
check(translator.interfaceTypeClass, "typeArguments",
@ -322,10 +322,10 @@ class ClassInfoCollector {
void collect() {
initializeTop();
// Subclasses of the `_Function` class are generated on the fly as fields
// with function types are encountered. Therefore, `_Function` class must
// Subclasses of the `_Closure` class are generated on the fly as fields
// with function types are encountered. Therefore, `_Closure` class must
// be early in the initialization order.
initialize(translator.functionClass);
initialize(translator.closureClass);
// Similarly `_Type` is needed for type parameter fields in classes and
// needs to be initialized before we encounter a class with type

View file

@ -173,9 +173,7 @@ class ClosureLayouter extends RecursiveVisitor {
// Base struct for closures.
late final w.StructType closureBaseStruct = _makeClosureStruct(
"#ClosureBase",
_vtableBaseStructBare,
translator.classInfo[translator.functionClass]!.struct);
"#ClosureBase", _vtableBaseStructBare, translator.closureInfo.struct);
late final w.RefType typeType =
translator.classInfo[translator.typeClass]!.nonNullableType;
@ -185,12 +183,12 @@ class ClosureLayouter extends RecursiveVisitor {
w.StructType _makeClosureStruct(
String name, w.StructType vtableStruct, w.StructType superType) {
// A closure contains:
// - A class ID (always the `_Function` class ID)
// - A class ID (always the `_Closure` class ID)
// - An identity hash
// - A context reference (used for `this` in tear-offs)
// - A vtable reference
// - A `_FunctionType`
return m.addStructType("#ClosureBase",
return m.addStructType(name,
fields: [
w.FieldType(w.NumType.i32),
w.FieldType(w.NumType.i32),
@ -564,8 +562,6 @@ class ClosureLayouter extends RecursiveVisitor {
ib.struct_new(instantiatedRepresentation.vtableStruct);
ib.end();
ClassInfo info = translator.classInfo[translator.functionClass]!;
w.DefinedFunction instantiationFunction = m.addFunction(functionType, name);
w.Local preciseClosure = instantiationFunction.addLocal(genericClosureType);
w.Instructions b = instantiationFunction.body;
@ -575,7 +571,7 @@ class ClosureLayouter extends RecursiveVisitor {
w.Local typeParam(int i) => instantiationFunction.locals[1 + i];
// Header for the closure struct
b.i32_const(info.classId);
b.i32_const(translator.closureInfo.classId);
b.i32_const(initialIdentityHash);
// Context for the instantiated closure, containing the original closure and

View file

@ -204,7 +204,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
ClosureImplementation closure = translator.getTearOffClosure(procedure);
w.StructType struct = closure.representation.closureStruct;
ClassInfo info = translator.classInfo[translator.functionClass]!;
ClassInfo info = translator.closureInfo;
translator.functions.allocateClass(info.classId);
b.i32_const(info.classId);
@ -2345,7 +2345,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
DartType functionType, void pushContext()) {
w.StructType struct = closure.representation.closureStruct;
ClassInfo info = translator.classInfo[translator.functionClass]!;
ClassInfo info = translator.closureInfo;
translator.functions.allocateClass(info.classId);
b.i32_const(info.classId);

View file

@ -545,7 +545,7 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?> {
w.StructType struct = closure.representation.closureStruct;
w.RefType type = w.RefType.def(struct, nullable: false);
return createConstant(constant, type, (function, b) {
ClassInfo info = translator.classInfo[translator.functionClass]!;
ClassInfo info = translator.closureInfo;
translator.functions.allocateClass(info.classId);
b.i32_const(info.classId);
@ -614,7 +614,7 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?> {
final w.DefinedFunction dynamicCallEntry = makeDynamicCallEntry();
return createConstant(constant, type, (function, b) {
ClassInfo info = translator.classInfo[translator.functionClass]!;
ClassInfo info = translator.closureInfo;
translator.functions.allocateClass(info.classId);
w.DefinedFunction makeTrampoline(

View file

@ -524,7 +524,7 @@ class Forwarder {
// Invoke "call" if the value is not a closure
b.struct_get(translator.topInfo.struct, FieldIndex.classId);
b.i32_const(translator.classInfo[translator.functionClass]!.classId);
b.i32_const(translator.closureInfo.classId);
b.i32_ne();
b.if_();
// Value is not a closure
@ -539,8 +539,23 @@ class Forwarder {
b.return_();
b.end();
generateDynamicCall(translator, function, receiverLocal, typeArgsLocal,
positionalArgsLocal, namedArgsLocal, noSuchMethodBlock);
// Cast the closure to `#ClosureBase`
final closureBaseType = w.RefType.def(
translator.closureLayouter.closureBaseStruct,
nullable: false);
final closureLocal = function.addLocal(closureBaseType);
b.local_get(receiverLocal);
b.ref_cast(closureBaseType);
b.local_set(closureLocal);
generateDynamicFunctionCall(
translator,
function,
closureLocal,
typeArgsLocal,
positionalArgsLocal,
namedArgsLocal,
noSuchMethodBlock);
b.return_();
b.end(); // class ID
@ -592,15 +607,15 @@ enum _ForwarderKind {
/// Generate code that checks shape and type of the closure and generate a call
/// to its dynamic call vtable entry.
///
/// [closureLocal] should be a local with a closure value. Type of the local
/// does not matter as long as it can be cast to `ref #ClosureBase`.
/// [closureLocal] should be a local of type `ref #ClosureBase` containing a
/// closure value.
///
/// [typeArgsLocal], [posArgsLocal], [namedArgsLocal] are the locals for type,
/// positional, and named arguments, respectively. Types of these locals must
/// be `ref _ListBase`.
///
/// [noSuchMethodBlock] is used as the `br` target when the shape check fails.
void generateDynamicCall(
void generateDynamicFunctionCall(
Translator translator,
w.DefinedFunction function,
w.Local closureLocal,
@ -617,19 +632,10 @@ void generateDynamicCall(
final b = function.body;
// Cast the closure to `#ClosureBase`
final closureBaseType = w.RefType.def(
translator.closureLayouter.closureBaseStruct,
nullable: false);
final closureBaseLocal = function.addLocal(closureBaseType);
b.local_get(closureLocal);
b.ref_cast(closureBaseType);
b.local_set(closureBaseLocal);
// Read the `_FunctionType` field
final functionTypeLocal =
function.addLocal(translator.closureLayouter.functionTypeType);
b.local_get(closureBaseLocal);
b.local_get(closureLocal);
b.struct_get(translator.closureLayouter.closureBaseStruct,
FieldIndex.closureRuntimeType);
b.local_tee(functionTypeLocal);
@ -653,13 +659,13 @@ void generateDynamicCall(
translator.functions.getFunction(translator.checkClosureType.reference));
// Type check passed, call vtable entry
b.local_get(closureBaseLocal);
b.local_get(closureLocal);
b.local_get(typeArgsLocal);
b.local_get(posArgsLocal);
b.local_get(namedArgsLocal);
// Get vtable
b.local_get(closureBaseLocal);
b.local_get(closureLocal);
b.struct_get(
translator.closureLayouter.closureBaseStruct, FieldIndex.closureVtable);

View file

@ -1486,8 +1486,7 @@ class Intrinsifier {
}
}
if (member.enclosingClass == translator.functionClass &&
name == "_equals") {
if (member.enclosingClass == translator.closureClass && name == "_equals") {
// Function equality works like this:
//
// - Function literals and local functions are only equal if they're the
@ -1595,7 +1594,7 @@ class Intrinsifier {
name == "apply") {
assert(function.type.inputs.length == 3);
final closureLocal = function.locals[0]; // ref Object
final closureLocal = function.locals[0]; // ref #ClosureBase
final posArgsNullableLocal = function.locals[1]; // ref null Object,
final namedArgsLocal = function.locals[2]; // ref null Object
@ -1654,8 +1653,8 @@ class Intrinsifier {
final noSuchMethodBlock = b.block();
generateDynamicCall(translator, function, closureLocal, typeArgsLocal,
posArgsLocal, namedArgsListLocal, noSuchMethodBlock);
generateDynamicFunctionCall(translator, function, closureLocal,
typeArgsLocal, posArgsLocal, namedArgsListLocal, noSuchMethodBlock);
b.return_();
b.end(); // noSuchMethodBlock

View file

@ -36,7 +36,7 @@ mixin KernelNodes {
late final Class boxedDoubleClass =
index.getClass("dart:core", "_BoxedDouble");
late final Class boxedIntClass = index.getClass("dart:core", "_BoxedInt");
late final Class functionClass = index.getClass("dart:core", "_Function");
late final Class closureClass = index.getClass("dart:core", "_Closure");
late final Class listBaseClass = index.getClass("dart:core", "_ListBase");
late final Class fixedLengthListClass = index.getClass("dart:core", "_List");
late final Class growableListClass =

View file

@ -106,6 +106,7 @@ class Translator with KernelNodes {
// Some convenience accessors for commonly used values.
late final ClassInfo topInfo = classes[0];
late final ClassInfo objectInfo = classInfo[coreTypes.objectClass]!;
late final ClassInfo closureInfo = classInfo[closureClass]!;
late final ClassInfo stackTraceInfo = classInfo[stackTraceClass]!;
late final w.ArrayType listArrayType = (classInfo[listBaseClass]!
.struct
@ -468,6 +469,9 @@ class Translator with KernelNodes {
} else if (isFfiCompound(cls)) {
if (nullable) throw "FFI types can't be nullable";
return w.NumType.i32;
} else if (cls == coreTypes.functionClass) {
return w.RefType.def(closureLayouter.closureBaseStruct,
nullable: nullable);
}
}
return w.RefType.def(info.repr.struct, nullable: nullable);

View file

@ -526,8 +526,7 @@ class Types {
b.drop();
b.i32_const(1);
} else if (type.classNode == coreTypes.functionClass) {
ClassInfo functionInfo = translator.classInfo[translator.functionClass]!;
b.ref_test(functionInfo.nonNullableType);
b.ref_test(translator.closureInfo.nonNullableType);
} else if (concrete.isEmpty) {
b.drop();
b.i32_const(0);

View file

@ -32,8 +32,8 @@ class ClassID {
external static int get cidFuture;
@pragma("wasm:class-id", "dart.core#Function")
external static int get cidFunction;
@pragma("wasm:class-id", "dart.core#_Function")
external static int get cid_Function;
@pragma("wasm:class-id", "dart.core#_Closure")
external static int get cid_Closure;
@pragma("wasm:class-id", "dart.core#_List")
external static int get cidFixedLengthList;
@pragma("wasm:class-id", "dart.core#_ListBase")

View file

@ -1,26 +1,26 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of "core_patch.dart";
/// Base class for closure objects.
class _Function implements Function {
class _Closure implements Function {
@pragma("wasm:entry-point")
WasmStructRef context;
@pragma("wasm:entry-point")
_Function._(this.context);
_Closure._(this.context);
@override
bool operator ==(Object other) {
if (other is! _Function) {
if (other is! _Closure) {
return false;
}
return _equals(this, other);
}
external static bool _equals(_Function a, _Function b);
external static bool _equals(_Closure a, _Closure b);
// Simple hash code for now, we can optimize later
@override
@ -28,5 +28,5 @@ class _Function implements Function {
// Support dynamic tear-off of `.call` on functions
@pragma("wasm:entry-point")
_Function get call => this;
_Closure get call => this;
}

View file

@ -54,10 +54,10 @@ import "dart:typed_data" show Uint8List, Uint16List;
import 'dart:wasm';
part "bool.dart";
part "closure.dart";
part "date_patch.dart";
part "double.dart";
part "errors_patch.dart";
part "function.dart";
part "growable_list.dart";
part "identical_patch.dart";
part "int.dart";

View file

@ -50,7 +50,7 @@ class Object {
@pragma("wasm:entry-point")
_Type get _runtimeType {
if (ClassID.getID(this) == ClassID.cid_Function) {
if (ClassID.getID(this) == ClassID.cid_Closure) {
return _getFunctionTypeRuntimeType(this);
} else {
return _getInterfaceTypeRuntimeType(this, _typeArguments);

View file

@ -519,7 +519,7 @@ class _TypeUniverse {
static bool isFunctionType(_Type t) =>
isSpecificInterfaceType(t, ClassID.cidFunction) ||
isSpecificInterfaceType(t, ClassID.cid_Function);
isSpecificInterfaceType(t, ClassID.cid_Closure);
static _Type substituteInterfaceTypeParameter(
_InterfaceTypeParameterType typeParameter, List<_Type> substitutions) {