Skip to content

Commit

Permalink
Version 3.5.0-126.0.dev
Browse files Browse the repository at this point in the history
Merge 73f5417 into dev
  • Loading branch information
Dart CI committed May 2, 2024
2 parents 040d3f6 + 73f5417 commit 0316fa4
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 111 deletions.
2 changes: 0 additions & 2 deletions pkg/dart2wasm/lib/async.dart
Original file line number Diff line number Diff line change
Expand Up @@ -580,8 +580,6 @@ class AsyncCodeGenerator extends CodeGenerator {
void generate() {
closures = Closures(translator, member);
setupParametersAndContexts(member.reference);
generateTypeChecks(member.function!.typeParameters, member.function!,
translator.paramInfoFor(reference));
_generateBodies(member.function!);
}

Expand Down
55 changes: 36 additions & 19 deletions pkg/dart2wasm/lib/class_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,9 @@ class ClassInfo {

/// The class whose struct is used as the type for variables of this type.
/// This is a type which is a superclass of all subtypes of this type.
late final ClassInfo repr = upperBound(
implementedBy.map((c) => identical(c, this) ? this : c.repr).toSet());
ClassInfo get repr => _repr!;

ClassInfo? _repr;

/// All classes which implement this class. This is used to compute `repr`.
final List<ClassInfo> implementedBy = [];
Expand Down Expand Up @@ -185,25 +186,22 @@ class ClassInfo {
];
}

ClassInfo upperBound(Set<ClassInfo> classes) {
while (classes.length > 1) {
Set<ClassInfo> newClasses = {};
int minDepth = 999999999;
int maxDepth = 0;
for (ClassInfo info in classes) {
minDepth = min(minDepth, info.depth);
maxDepth = max(maxDepth, info.depth);
ClassInfo upperBound(ClassInfo a, ClassInfo b) {
if (a.depth < b.depth) {
while (b.depth > a.depth) {
b = b.superInfo!;
}
int targetDepth = minDepth == maxDepth ? minDepth - 1 : minDepth;
for (ClassInfo info in classes) {
while (info.depth > targetDepth) {
info = info.superInfo!;
}
newClasses.add(info);
} else {
while (a.depth > b.depth) {
a = a.superInfo!;
}
classes = newClasses;
}
return classes.single;
assert(a.depth == b.depth);
while (a != b) {
a = a.superInfo!;
b = b.superInfo!;
}
return a;
}

/// Constructs the Wasm type hierarchy.
Expand Down Expand Up @@ -439,7 +437,7 @@ class ClassInfoCollector {
// `0` is occupied by artificial non-Dart top class.
const int firstClassId = 1;

translator.classIdNumbering =
final classIdNumbering = translator.classIdNumbering =
ClassIdNumbering._number(translator, masqueraded, firstClassId);
final classIds = translator.classIdNumbering.classIds;
final dfsOrder = translator.classIdNumbering.dfsOrder;
Expand Down Expand Up @@ -476,6 +474,25 @@ class ClassInfoCollector {
}
}

// Create representations of the classes (i.e. wasm representation used to
// represent objects of that dart type).
for (final cls in dfsOrder) {
ClassInfo? representation;
for (final range in classIdNumbering.getConcreteClassIdRanges(cls)) {
for (int classId = range.start; classId <= range.end; ++classId) {
final current = translator.classes[classId];
if (representation == null) {
representation = current;
continue;
}
representation = upperBound(representation, current);
}
}
final classId = classIdNumbering.classIds[cls]!;
final info = translator.classes[classId];
info._repr = representation ?? translator.classes[classId];
}

// Now that the representation types for all classes have been computed,
// fill in the types of the fields in the generated Wasm structs.
for (final info in translator.classesSupersFirst) {
Expand Down
11 changes: 8 additions & 3 deletions pkg/dart2wasm/lib/closures.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1041,14 +1041,20 @@ class Closures {
final Map<TreeNode, Capture> captures = {};
bool isThisCaptured = false;
final Map<FunctionNode, Lambda> lambdas = {};
late final w.RefType? nullableThisType;

// This [TreeNode] is the context owner, and can be a [FunctionNode],
// [Constructor], [ForStatement], [DoStatement] or a [WhileStatement].
final Map<TreeNode, Context> contexts = {};
final Set<FunctionDeclaration> closurizedFunctions = {};

Closures(this.translator, Member member)
: enclosingClass = member.enclosingClass;
: enclosingClass = member.enclosingClass {
final hasThis = member is Constructor || member.isInstanceMember;
nullableThisType = hasThis
? translator.preciseThisFor(member, nullable: true) as w.RefType
: null;
}

w.ModuleBuilder get m => translator.m;

Expand Down Expand Up @@ -1104,8 +1110,7 @@ class Closures {
}
if (context.containsThis) {
assert(enclosingClass != null);
struct.fields.add(
w.FieldType(translator.classInfo[enclosingClass!]!.nullableType));
struct.fields.add(w.FieldType(nullableThisType!));
}
for (VariableDeclaration variable in context.variables) {
int index = struct.fields.length;
Expand Down
119 changes: 44 additions & 75 deletions pkg/dart2wasm/lib/code_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,21 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
? member.enclosingClass.typeParameters
: member.function!.typeParameters;
for (int i = 0; i < typeParameters.length; i++) {
typeLocals[typeParameters[i]] = paramLocals[parameterOffset + i];
final typeParameter = typeParameters[i];
typeLocals[typeParameter] = paramLocals[parameterOffset + i];
}
if (!translator.options.omitImplicitTypeChecks) {
for (int i = 0; i < typeParameters.length; i++) {
final typeParameter = typeParameters[i];
if (typeParameter.isCovariantByClass &&
typeParameter.bound != translator.coreTypes.objectNullableRawType) {
_generateTypeArgumentBoundCheck(typeParameter.name!,
typeLocals[typeParameter]!, typeParameter.bound);
}
}
}

w.Local? tempLocalForType;

void setupParamLocal(
VariableDeclaration variable, int index, Constant? defaultValue) {
Expand All @@ -332,6 +345,20 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
b.local_set(local);
b.end();
}

if (!translator.options.omitImplicitTypeChecks) {
if (variable.isCovariantByClass || variable.isCovariantByDeclaration) {
final typeLocal = tempLocalForType ??= addLocal(
translator.classInfo[translator.typeClass]!.nonNullableType);
_generateArgumentTypeCheck(
variable.name!,
() => b.local_get(local),
() => types.makeType(this, variable.type),
local,
typeLocal,
);
}
}
}

List<VariableDeclaration> positional =
Expand Down Expand Up @@ -485,52 +512,6 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
return superclassFields.reversed.toList() + typeFields + orderedFieldLocals;
}

void generateTypeChecks(List<TypeParameter> typeParameters,
FunctionNode function, ParameterInfo paramInfo) {
if (translator.options.omitImplicitTypeChecks) {
return;
}

for (TypeParameter typeParameter in typeParameters) {
if (typeParameter.isCovariantByClass &&
typeParameter.bound != translator.coreTypes.objectNullableRawType) {
_generateTypeArgumentBoundCheck(typeParameter.name!,
typeLocals[typeParameter]!, typeParameter.bound);
}
}

// Local for the parameter type if any of the parameters need type checks
w.Local? parameterExpectedTypeLocal;

final int parameterOffset = thisLocal == null ? 0 : 1;
final int implicitParams = parameterOffset + paramInfo.typeParamCount;
void generateValueParameterCheck(VariableDeclaration variable, int index) {
if (!variable.isCovariantByClass && !variable.isCovariantByDeclaration) {
return;
}
final w.Local local = paramLocals[implicitParams + index];
final typeLocal = parameterExpectedTypeLocal ??=
addLocal(translator.classInfo[translator.typeClass]!.nonNullableType);
_generateArgumentTypeCheck(
variable.name!,
() => b.local_get(local),
() => types.makeType(this, variable.type),
local,
typeLocal,
);
}

final List<VariableDeclaration> positional = function.positionalParameters;
for (int i = 0; i < positional.length; i++) {
generateValueParameterCheck(positional[i], i);
}

final List<VariableDeclaration> named = function.namedParameters;
for (var param in named) {
generateValueParameterCheck(param, paramInfo.nameIndex[param.name]!);
}
}

List<w.Local> _getConstructorArgumentLocals(Reference target,
[reverse = false]) {
Constructor member = target.asConstructor;
Expand Down Expand Up @@ -571,10 +552,6 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
assert(member is! Constructor);
setupParametersAndContexts(member.reference);

final List<TypeParameter> typeParameters = member.function!.typeParameters;
generateTypeChecks(
typeParameters, member.function!, translator.paramInfoFor(reference));

Statement? body = member.function!.body;
if (body != null) {
visitStatement(body);
Expand All @@ -590,11 +567,6 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
void generateConstructorAllocator(Constructor member) {
setupParameters(member.reference);

final List<TypeParameter> typeParameters =
member.enclosingClass.typeParameters;
generateTypeChecks(
typeParameters, member.function, translator.paramInfoFor(reference));

w.FunctionType initializerMethodType =
translator.functions.getFunctionType(member.initializerReference);

Expand Down Expand Up @@ -724,23 +696,15 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
/// parameter if there are no type parameters).
int _initializeThis(Reference reference) {
Member member = reference.asMember;
bool hasThis =
final hasThis =
member.isInstanceMember || reference.isConstructorBodyReference;
if (hasThis) {
thisLocal = paramLocals[0];
assert(!thisLocal!.type.nullable);
Class cls = member.enclosingClass!;
w.StorageType? builtin = translator.builtinTypes[cls];
w.ValueType thisType = translator.boxedClasses.containsKey(builtin)
? builtin as w.ValueType
: translator.classInfo[cls]!.nonNullableType;
if (translator.needsConversion(thisLocal!.type, thisType) &&
!(cls == translator.objectInfo.cls ||
cls == translator.ffiPointerClass ||
translator.isWasmType(cls))) {
preciseThisLocal = addLocal(thisType);
final preciseThisType = translator.preciseThisFor(member);
if (translator.needsConversion(thisLocal!.type, preciseThisType)) {
preciseThisLocal = addLocal(preciseThisType);
b.local_get(thisLocal!);
translator.convertType(function, thisLocal!.type, thisType);
translator.convertType(function, thisLocal!.type, preciseThisType);
b.local_set(preciseThisLocal!);
} else {
preciseThisLocal = thisLocal!;
Expand Down Expand Up @@ -1739,14 +1703,19 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
w.ValueType preciseThisType = preciseThisLocal!.type;
assert(!thisType.nullable);
assert(!preciseThisType.nullable);
if (!thisType.isSubtypeOf(expectedType) &&
preciseThisType.isSubtypeOf(expectedType)) {
b.local_get(preciseThisLocal!);
return preciseThisType;
} else {
if (thisType.isSubtypeOf(expectedType)) {
b.local_get(thisLocal!);
return thisType;
}
if (preciseThisType.isSubtypeOf(expectedType)) {
b.local_get(preciseThisLocal!);
return preciseThisType;
}
// A user of `this` may have more precise type information, in which case
// we downcast it here.
b.local_get(thisLocal!);
translator.convertType(function, thisType, expectedType);
return expectedType;
}

@override
Expand Down Expand Up @@ -1787,7 +1756,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
_lookupSuperTarget(node.interfaceTarget, setter: false).reference;
w.FunctionType targetFunctionType =
translator.functions.getFunctionType(target);
w.ValueType receiverType = targetFunctionType.inputs[0];
final w.ValueType receiverType = translator.preciseThisFor(target.asMember);

// When calling `==` and the argument is potentially nullable, check if the
// argument is `null`.
Expand Down
12 changes: 4 additions & 8 deletions pkg/dart2wasm/lib/dynamic_forwarders.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,13 @@ class Forwarder {
if (targetMember.isAbstract) {
continue;
}
final targetClass = targetMember.enclosingClass!;
final targetClassInfo = translator.classInfo[targetClass]!;

b.local_get(receiverLocal);
b.struct_get(translator.topInfo.struct, FieldIndex.classId);
b.i32_const(classID);
b.i32_eq();
b.if_();

final w.ValueType receiverType = targetClassInfo.nonNullableType;
final Reference targetReference;
if (targetMember is Procedure) {
targetReference = targetMember.isGetter
Expand All @@ -128,7 +125,8 @@ class Forwarder {
final w.BaseFunction targetFunction =
translator.functions.getFunction(targetReference);
b.local_get(receiverLocal);
translator.convertType(function, receiverLocal.type, receiverType);
translator.convertType(
function, receiverLocal.type, targetFunction.type.inputs.first);
b.call(targetFunction);
// Box return value if needed
translator.convertType(function, targetFunction.type.outputs.single,
Expand Down Expand Up @@ -528,16 +526,13 @@ class Forwarder {
if (targetMember is Procedure && !targetMember.isGetter) {
continue;
}
final targetClass = targetMember.enclosingClass!;
final targetClassInfo = translator.classInfo[targetClass]!;

b.local_get(receiverLocal);
b.struct_get(translator.topInfo.struct, FieldIndex.classId);
b.i32_const(classID);
b.i32_eq();
b.if_();

final w.ValueType receiverType = targetClassInfo.nonNullableType;
final Reference targetReference;
if (targetMember is Procedure) {
assert(targetMember.isGetter); // methods are skipped above
Expand All @@ -553,7 +548,8 @@ class Forwarder {

// Get field value
b.local_get(receiverLocal);
translator.convertType(function, receiverLocal.type, receiverType);
translator.convertType(
function, receiverLocal.type, targetFunction.type.inputs.first);
b.call(targetFunction);
translator.convertType(function, targetFunction.type.outputs.single,
translator.topInfo.nullableType);
Expand Down
2 changes: 0 additions & 2 deletions pkg/dart2wasm/lib/sync_star.dart
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,6 @@ class SyncStarCodeGenerator extends CodeGenerator {
void generate() {
closures = Closures(translator, member);
setupParametersAndContexts(member.reference);
generateTypeChecks(member.function!.typeParameters, member.function!,
translator.paramInfoFor(reference));
generateBodies(member.function!);
}

Expand Down
18 changes: 18 additions & 0 deletions pkg/dart2wasm/lib/translator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,24 @@ class Translator with KernelNodes {
}
}

w.ValueType preciseThisFor(Member member, {bool nullable = false}) {
assert(member.isInstanceMember || member is Constructor);

Class cls = member.enclosingClass!;
final w.StorageType? builtin = builtinTypes[cls];
final boxClass = boxedClasses[builtin];
if (boxClass != null) {
// We represent `this` as an unboxed type.
if (!nullable) return builtin as w.ValueType;
// Otherwise we use [boxClass] to represent `this`.
cls = boxClass;
}
final representationClassInfo = classInfo[cls]!.repr;
return nullable
? representationClassInfo.nullableType
: representationClassInfo.nonNullableType;
}

/// Get the Wasm table declared by [field], or `null` if [field] is not a
/// declaration of a Wasm table.
///
Expand Down
Loading

0 comments on commit 0316fa4

Please sign in to comment.