mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 18:31:32 +00:00
Make _FunctionType fields use WasmObjectArray instead of List
This reduces flute's complex.dart slightly complex.wasm: 1601793 -> 1596131 (-0.35%) complex.wasm.unopt: 3570856 -> 3562573 (-0.23%) And makes the code probably slightly faster Change-Id: I5b5cb8f95509930ce23c7d4bc0385740ad9f429b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340562 Reviewed-by: Ömer Ağacan <omersa@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
9d949a2498
commit
e0485a4fc0
|
@ -664,21 +664,11 @@ class ClosureLayouter extends RecursiveVisitor {
|
|||
b.local_get(preciseClosure);
|
||||
b.struct_get(genericClosureStruct, FieldIndex.closureRuntimeType);
|
||||
|
||||
// Put type arguments into a `List<_Type>`.
|
||||
ClassInfo listInfo = translator.classInfo[translator.fixedLengthListClass]!;
|
||||
translator.functions.allocateClass(listInfo.classId);
|
||||
Constant typeConstant = TypeLiteralConstant(
|
||||
InterfaceType(translator.typeClass, Nullability.nonNullable));
|
||||
b.i32_const(listInfo.classId);
|
||||
b.i32_const(initialIdentityHash);
|
||||
translator.constants
|
||||
.instantiateConstant(instantiationFunction, b, typeConstant, typeType);
|
||||
b.i64_const(typeCount);
|
||||
// Put type arguments into a `WasmObjectArray<_Type>`.
|
||||
for (int i = 0; i < typeCount; i++) {
|
||||
b.local_get(typeParam(i));
|
||||
}
|
||||
b.array_new_fixed(translator.listArrayType, typeCount);
|
||||
b.struct_new(listInfo.struct);
|
||||
b.array_new_fixed(translator.typeArrayType, typeCount);
|
||||
|
||||
// Call [_TypeUniverse.substituteFunctionTypeArgument].
|
||||
b.call(translator.functions
|
||||
|
|
|
@ -2930,6 +2930,16 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
(w.ValueType elementType, int i) => wrap(expressions[i], elementType),
|
||||
isGrowable: isGrowable);
|
||||
|
||||
w.ValueType makeArrayFromExpressions(
|
||||
List<Expression> expressions, InterfaceType elementType) {
|
||||
return translator.makeArray(
|
||||
function,
|
||||
translator.arrayTypeForDartType(elementType),
|
||||
expressions.length, (w.ValueType elementType, int i) {
|
||||
wrap(expressions[i], elementType);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
w.ValueType visitMapLiteral(MapLiteral node, w.ValueType expectedType) {
|
||||
types.makeType(this, node.keyType);
|
||||
|
|
|
@ -60,37 +60,38 @@ class Constants {
|
|||
|
||||
/// Makes a type list [ListConstant].
|
||||
ListConstant makeTypeList(Iterable<DartType> types) => ListConstant(
|
||||
InterfaceType(translator.typeClass, Nullability.nonNullable),
|
||||
types.map((t) => TypeLiteralConstant(t)).toList());
|
||||
translator.typeType, types.map((t) => TypeLiteralConstant(t)).toList());
|
||||
|
||||
InstanceConstant makeTypeArray(Iterable<DartType> types) =>
|
||||
InstanceConstant(translator.wasmObjectArrayClass.reference, [
|
||||
InterfaceType(translator.typeClass, Nullability.nonNullable)
|
||||
], {
|
||||
translator.wasmObjectArrayValueField.fieldReference: makeTypeList(types)
|
||||
});
|
||||
/// Makes a `WasmObjectArray<_Type>` [InstanceConstant].
|
||||
InstanceConstant makeTypeArray(Iterable<DartType> types) => makeArrayOf(
|
||||
translator.typeType, types.map((t) => TypeLiteralConstant(t)).toList());
|
||||
|
||||
/// Makes a `_NamedParameter` [InstanceConstant].
|
||||
InstanceConstant makeNamedParameterConstant(NamedType n) {
|
||||
Class namedParameter = translator.namedParameterClass;
|
||||
assert(namedParameter.fields[0].name.text == 'name' &&
|
||||
namedParameter.fields[1].name.text == 'type' &&
|
||||
namedParameter.fields[2].name.text == 'isRequired');
|
||||
Reference namedParameterName = namedParameter.fields[0].fieldReference;
|
||||
Reference namedParameterType = namedParameter.fields[1].fieldReference;
|
||||
Reference namedParameterIsRequired =
|
||||
namedParameter.fields[2].fieldReference;
|
||||
return InstanceConstant(namedParameter.reference, [], {
|
||||
namedParameterName: StringConstant(n.name),
|
||||
namedParameterType: TypeLiteralConstant(n.type),
|
||||
namedParameterIsRequired: BoolConstant(n.isRequired)
|
||||
});
|
||||
}
|
||||
InstanceConstant makeNamedParameterConstant(NamedType n) =>
|
||||
InstanceConstant(translator.namedParameterClass.reference, const [], {
|
||||
translator.namedParameterNameField.fieldReference:
|
||||
StringConstant(n.name),
|
||||
translator.namedParameterTypeField.fieldReference:
|
||||
TypeLiteralConstant(n.type),
|
||||
translator.namedParameterIsRequiredField.fieldReference:
|
||||
BoolConstant(n.isRequired),
|
||||
});
|
||||
|
||||
/// Makes a [ListConstant] of `_NamedParameters` to initialize a [FunctionType].
|
||||
ListConstant makeNamedParametersList(FunctionType type) => ListConstant(
|
||||
translator.types.namedParameterType,
|
||||
type.namedParameters.map(makeNamedParameterConstant).toList());
|
||||
/// Creates a `WasmObjectArray<_NamedParameter>` to be used as field of
|
||||
/// `_FunctionType`.
|
||||
InstanceConstant makeNamedParametersArray(FunctionType type) => makeArrayOf(
|
||||
translator.namedParameterType,
|
||||
[for (final n in type.namedParameters) makeNamedParameterConstant(n)]);
|
||||
|
||||
/// Creates a `WasmObjectArray<T>` with the given [Constant]s
|
||||
InstanceConstant makeArrayOf(
|
||||
InterfaceType elementType, List<Constant> entries) =>
|
||||
InstanceConstant(translator.wasmObjectArrayClass.reference, [
|
||||
elementType,
|
||||
], {
|
||||
translator.wasmObjectArrayValueField.fieldReference:
|
||||
ListConstant(elementType, entries),
|
||||
});
|
||||
|
||||
/// Ensure that the constant has a Wasm global assigned.
|
||||
///
|
||||
|
@ -771,18 +772,18 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?>
|
|||
ConstantInfo? _makeFunctionType(
|
||||
TypeLiteralConstant constant, FunctionType type, ClassInfo info) {
|
||||
int typeParameterOffset = types.computeFunctionTypeParameterOffset(type);
|
||||
ListConstant typeParameterBoundsConstant =
|
||||
constants.makeTypeList(type.typeParameters.map((p) => p.bound));
|
||||
ListConstant typeParameterDefaultsConstant =
|
||||
constants.makeTypeList(type.typeParameters.map((p) => p.defaultType));
|
||||
InstanceConstant typeParameterBoundsConstant =
|
||||
constants.makeTypeArray(type.typeParameters.map((p) => p.bound));
|
||||
InstanceConstant typeParameterDefaultsConstant =
|
||||
constants.makeTypeArray(type.typeParameters.map((p) => p.defaultType));
|
||||
TypeLiteralConstant returnTypeConstant =
|
||||
TypeLiteralConstant(type.returnType);
|
||||
ListConstant positionalParametersConstant =
|
||||
constants.makeTypeList(type.positionalParameters);
|
||||
InstanceConstant positionalParametersConstant =
|
||||
constants.makeTypeArray(type.positionalParameters);
|
||||
IntConstant requiredParameterCountConstant =
|
||||
IntConstant(type.requiredParameterCount);
|
||||
ListConstant namedParametersConstant =
|
||||
constants.makeNamedParametersList(type);
|
||||
InstanceConstant namedParametersConstant =
|
||||
constants.makeNamedParametersArray(type);
|
||||
ensureConstant(typeParameterBoundsConstant);
|
||||
ensureConstant(typeParameterDefaultsConstant);
|
||||
ensureConstant(returnTypeConstant);
|
||||
|
@ -794,14 +795,14 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?>
|
|||
b.i32_const(initialIdentityHash);
|
||||
b.i32_const(types.encodedNullability(type));
|
||||
b.i64_const(typeParameterOffset);
|
||||
constants.instantiateConstant(
|
||||
function, b, typeParameterBoundsConstant, types.typeListExpectedType);
|
||||
constants.instantiateConstant(function, b, typeParameterBoundsConstant,
|
||||
types.typeArrayExpectedType);
|
||||
constants.instantiateConstant(function, b, typeParameterDefaultsConstant,
|
||||
types.typeListExpectedType);
|
||||
types.typeArrayExpectedType);
|
||||
constants.instantiateConstant(
|
||||
function, b, returnTypeConstant, types.nonNullableTypeType);
|
||||
constants.instantiateConstant(function, b, positionalParametersConstant,
|
||||
types.typeListExpectedType);
|
||||
types.typeArrayExpectedType);
|
||||
constants.instantiateConstant(
|
||||
function, b, requiredParameterCountConstant, w.NumType.i64);
|
||||
constants.instantiateConstant(function, b, namedParametersConstant,
|
||||
|
|
|
@ -65,6 +65,8 @@ mixin KernelNodes {
|
|||
|
||||
// dart:core runtime type classes
|
||||
late final Class typeClass = index.getClass("dart:core", "_Type");
|
||||
late final InterfaceType typeType =
|
||||
InterfaceType(typeClass, Nullability.nonNullable);
|
||||
late final Class abstractFunctionTypeClass =
|
||||
index.getClass("dart:core", "_AbstractFunctionType");
|
||||
late final Class functionTypeClass =
|
||||
|
@ -79,6 +81,14 @@ mixin KernelNodes {
|
|||
index.getClass("dart:core", "_InterfaceTypeParameterType");
|
||||
late final Class namedParameterClass =
|
||||
index.getClass("dart:core", "_NamedParameter");
|
||||
late final Field namedParameterNameField =
|
||||
index.getField("dart:core", "_NamedParameter", "name");
|
||||
late final Field namedParameterTypeField =
|
||||
index.getField("dart:core", "_NamedParameter", "type");
|
||||
late final Field namedParameterIsRequiredField =
|
||||
index.getField("dart:core", "_NamedParameter", "isRequired");
|
||||
late final InterfaceType namedParameterType =
|
||||
InterfaceType(namedParameterClass, Nullability.nonNullable);
|
||||
late final Class bottomTypeClass = index.getClass("dart:core", "_BottomType");
|
||||
late final Class topTypeClass = index.getClass("dart:core", "_TopType");
|
||||
late final Class stackTraceClass = index.getClass("dart:core", "StackTrace");
|
||||
|
|
|
@ -120,6 +120,8 @@ class Translator with KernelNodes {
|
|||
late final ClassInfo closureInfo = classInfo[closureClass]!;
|
||||
late final ClassInfo stackTraceInfo = classInfo[stackTraceClass]!;
|
||||
late final ClassInfo recordInfo = classInfo[coreTypes.recordClass]!;
|
||||
late final w.ArrayType typeArrayType =
|
||||
arrayTypeForDartType(InterfaceType(typeClass, Nullability.nonNullable));
|
||||
late final w.ArrayType listArrayType = (classInfo[listBaseClass]!
|
||||
.struct
|
||||
.fields[FieldIndex.listArray]
|
||||
|
@ -977,19 +979,30 @@ class Translator with KernelNodes {
|
|||
final ClassInfo info = classInfo[cls]!;
|
||||
functions.allocateClass(info.classId);
|
||||
final w.ArrayType arrayType = listArrayType;
|
||||
final w.ValueType elementType = arrayType.elementType.type.unpacked;
|
||||
|
||||
b.i32_const(info.classId);
|
||||
b.i32_const(initialIdentityHash);
|
||||
generateType(b);
|
||||
b.i64_const(length);
|
||||
makeArray(function, arrayType, length, generateItem);
|
||||
b.struct_new(info.struct);
|
||||
|
||||
return info.nonNullableType;
|
||||
}
|
||||
|
||||
w.ValueType makeArray(w.FunctionBuilder function, w.ArrayType arrayType,
|
||||
int length, void Function(w.ValueType, int) generateItem) {
|
||||
final b = function.body;
|
||||
|
||||
final w.ValueType elementType = arrayType.elementType.type.unpacked;
|
||||
final arrayTypeRef = w.RefType.def(arrayType, nullable: false);
|
||||
|
||||
if (length > maxArrayNewFixedLength) {
|
||||
// Too long for `array.new_fixed`. Set elements individually.
|
||||
b.i32_const(length);
|
||||
b.array_new_default(arrayType);
|
||||
if (length > 0) {
|
||||
final w.Local arrayLocal =
|
||||
function.addLocal(w.RefType.def(arrayType, nullable: false));
|
||||
final w.Local arrayLocal = function.addLocal(arrayTypeRef);
|
||||
b.local_set(arrayLocal);
|
||||
for (int i = 0; i < length; i++) {
|
||||
b.local_get(arrayLocal);
|
||||
|
@ -1005,9 +1018,7 @@ class Translator with KernelNodes {
|
|||
}
|
||||
b.array_new_fixed(arrayType, length);
|
||||
}
|
||||
b.struct_new(info.struct);
|
||||
|
||||
return info.nonNullableType;
|
||||
return arrayTypeRef;
|
||||
}
|
||||
|
||||
/// Indexes a Dart `List` on the stack.
|
||||
|
|
|
@ -68,7 +68,7 @@ class Types {
|
|||
late final w.ValueType typeArrayExpectedType =
|
||||
w.RefType.def(typeArrayArrayType, nullable: false);
|
||||
|
||||
/// Wasm value type of `List<_NamedParameter>`
|
||||
/// Wasm value type of `WasmObjectArray<_NamedParameter>`
|
||||
late final w.ValueType namedParametersExpectedType = classAndFieldToType(
|
||||
translator.functionTypeClass, FieldIndex.functionTypeNamedParameters);
|
||||
|
||||
|
@ -501,27 +501,27 @@ class Types {
|
|||
b.i32_const(encodedNullability(type));
|
||||
b.i64_const(typeParameterOffset);
|
||||
|
||||
// List<_Type> typeParameterBounds
|
||||
_makeTypeList(codeGen, type.typeParameters.map((p) => p.bound));
|
||||
// WasmObjectArray<_Type> typeParameterBounds
|
||||
_makeTypeArray(codeGen, type.typeParameters.map((p) => p.bound));
|
||||
|
||||
// List<_Type> typeParameterDefaults
|
||||
_makeTypeList(codeGen, type.typeParameters.map((p) => p.defaultType));
|
||||
// WasmObjectArray<_Type> typeParameterDefaults
|
||||
_makeTypeArray(codeGen, type.typeParameters.map((p) => p.defaultType));
|
||||
|
||||
// _Type returnType
|
||||
makeType(codeGen, type.returnType);
|
||||
|
||||
// List<_Type> positionalParameters
|
||||
_makeTypeList(codeGen, type.positionalParameters);
|
||||
// WasmObjectArray<_Type> positionalParameters
|
||||
_makeTypeArray(codeGen, type.positionalParameters);
|
||||
|
||||
// int requiredParameterCount
|
||||
b.i64_const(type.requiredParameterCount);
|
||||
|
||||
// List<_NamedParameter> namedParameters
|
||||
// WasmObjectArray<_NamedParameter> namedParameters
|
||||
if (type.namedParameters.every((n) => _isTypeConstant(n.type))) {
|
||||
translator.constants.instantiateConstant(
|
||||
codeGen.function,
|
||||
b,
|
||||
translator.constants.makeNamedParametersList(type),
|
||||
translator.constants.makeNamedParametersArray(type),
|
||||
namedParametersExpectedType);
|
||||
} else {
|
||||
Class namedParameterClass = translator.namedParameterClass;
|
||||
|
@ -542,7 +542,7 @@ class Types {
|
|||
])));
|
||||
}
|
||||
w.ValueType namedParametersListType =
|
||||
codeGen.makeListFromExpressions(expressions, namedParameterType);
|
||||
codeGen.makeArrayFromExpressions(expressions, namedParameterType);
|
||||
translator.convertType(codeGen.function, namedParametersListType,
|
||||
namedParametersExpectedType);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ part of 'core_patch.dart';
|
|||
@pragma("wasm:prefer-inline")
|
||||
_Type _literal<T>() => unsafeCast(T);
|
||||
|
||||
extension _IndexWasmArrayOfTypes on WasmObjectArray<_Type> {
|
||||
extension on WasmObjectArray<_Type> {
|
||||
@pragma("wasm:prefer-inline")
|
||||
_Type operator [](int index) => read(index);
|
||||
|
||||
|
@ -26,6 +26,56 @@ extension _IndexWasmArrayOfTypes on WasmObjectArray<_Type> {
|
|||
|
||||
@pragma("wasm:prefer-inline")
|
||||
bool get isNotEmpty => length != 0;
|
||||
|
||||
@pragma("wasm:prefer-inline")
|
||||
WasmObjectArray<_Type> map(_Type Function(_Type) fun) {
|
||||
if (isEmpty) return const WasmObjectArray<_Type>.literal(<_Type>[]);
|
||||
final mapped = WasmObjectArray<_Type>(length, fun(this[0]));
|
||||
for (int i = 1; i < length; ++i) {
|
||||
mapped[i] = fun(this[i]);
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
}
|
||||
|
||||
extension on WasmObjectArray<_NamedParameter> {
|
||||
@pragma("wasm:prefer-inline")
|
||||
_NamedParameter operator [](int index) => read(index);
|
||||
|
||||
@pragma("wasm:prefer-inline")
|
||||
void operator []=(int index, _NamedParameter value) => write(index, value);
|
||||
|
||||
@pragma("wasm:prefer-inline")
|
||||
bool get isEmpty => length == 0;
|
||||
|
||||
@pragma("wasm:prefer-inline")
|
||||
bool get isNotEmpty => length != 0;
|
||||
|
||||
@pragma("wasm:prefer-inline")
|
||||
WasmObjectArray<_NamedParameter> map(
|
||||
_NamedParameter Function(_NamedParameter) fun) {
|
||||
if (isEmpty)
|
||||
return const WasmObjectArray<_NamedParameter>.literal(
|
||||
<_NamedParameter>[]);
|
||||
final mapped = WasmObjectArray<_NamedParameter>(length, this[0]);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
mapped[i] = fun(this[i]);
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove any occurence of `List`s in this file.
|
||||
extension on List<_Type> {
|
||||
@pragma("wasm:prefer-inline")
|
||||
WasmObjectArray<_Type> toWasmArray() {
|
||||
if (isEmpty) return const WasmObjectArray<_Type>.literal(<_Type>[]);
|
||||
final result = WasmObjectArray<_Type>(length, this[0]);
|
||||
for (int i = 1; i < length; ++i) {
|
||||
result[i] = this[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Direct getter to bypass the covariance check and the bounds check when
|
||||
|
@ -359,12 +409,12 @@ class _FunctionType extends _Type {
|
|||
// an `i64` in every function type object for this. Consider alternative
|
||||
// representations that don't have this overhead in the common case.
|
||||
final int typeParameterOffset;
|
||||
final List<_Type> typeParameterBounds;
|
||||
final List<_Type> typeParameterDefaults;
|
||||
final WasmObjectArray<_Type> typeParameterBounds;
|
||||
final WasmObjectArray<_Type> typeParameterDefaults;
|
||||
final _Type returnType;
|
||||
final List<_Type> positionalParameters;
|
||||
final WasmObjectArray<_Type> positionalParameters;
|
||||
final int requiredParameterCount;
|
||||
final List<_NamedParameter> namedParameters;
|
||||
final WasmObjectArray<_NamedParameter> namedParameters;
|
||||
|
||||
@pragma("wasm:entry-point")
|
||||
const _FunctionType(
|
||||
|
@ -409,20 +459,17 @@ class _FunctionType extends _Type {
|
|||
if (requiredParameterCount != other.requiredParameterCount) return false;
|
||||
if (namedParameters.length != other.namedParameters.length) return false;
|
||||
for (int i = 0; i < typeParameterBounds.length; i++) {
|
||||
if (typeParameterBounds._getUnchecked(i) !=
|
||||
other.typeParameterBounds._getUnchecked(i)) {
|
||||
if (typeParameterBounds[i] != other.typeParameterBounds[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < positionalParameters.length; i++) {
|
||||
if (positionalParameters._getUnchecked(i) !=
|
||||
other.positionalParameters._getUnchecked(i)) {
|
||||
if (positionalParameters[i] != other.positionalParameters[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < namedParameters.length; i++) {
|
||||
if (namedParameters._getUnchecked(i) !=
|
||||
other.namedParameters._getUnchecked(i)) {
|
||||
if (namedParameters[i] != other.namedParameters[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -433,16 +480,16 @@ class _FunctionType extends _Type {
|
|||
int get hashCode {
|
||||
int hash = mix64(ClassID.cidFunctionType);
|
||||
for (int i = 0; i < typeParameterBounds.length; i++) {
|
||||
hash = mix64(hash ^ typeParameterBounds._getUnchecked(i).hashCode);
|
||||
hash = mix64(hash ^ typeParameterBounds[i].hashCode);
|
||||
}
|
||||
hash = mix64(hash ^ (isDeclaredNullable ? 1 : 0));
|
||||
hash = mix64(hash ^ returnType.hashCode);
|
||||
for (int i = 0; i < positionalParameters.length; i++) {
|
||||
hash = mix64(hash ^ positionalParameters._getUnchecked(i).hashCode);
|
||||
hash = mix64(hash ^ positionalParameters[i].hashCode);
|
||||
}
|
||||
hash = mix64(hash ^ requiredParameterCount);
|
||||
for (int i = 0; i < namedParameters.length; i++) {
|
||||
hash = mix64(hash ^ namedParameters._getUnchecked(i).hashCode);
|
||||
hash = mix64(hash ^ namedParameters[i].hashCode);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
@ -455,7 +502,7 @@ class _FunctionType extends _Type {
|
|||
for (int i = 0; i < typeParameterBounds.length; i++) {
|
||||
if (i > 0) s.write(", ");
|
||||
s.write("X${typeParameterOffset + i}");
|
||||
final bound = typeParameterBounds._getUnchecked(i);
|
||||
final bound = typeParameterBounds[i];
|
||||
if (!(bound.isTop && bound.isDeclaredNullable)) {
|
||||
s.write(" extends ");
|
||||
s.write(bound);
|
||||
|
@ -467,7 +514,7 @@ class _FunctionType extends _Type {
|
|||
for (int i = 0; i < positionalParameters.length; i++) {
|
||||
if (i > 0) s.write(", ");
|
||||
if (i == requiredParameterCount) s.write("[");
|
||||
s.write(positionalParameters._getUnchecked(i));
|
||||
s.write(positionalParameters[i]);
|
||||
}
|
||||
if (requiredParameterCount < positionalParameters.length) s.write("]");
|
||||
if (namedParameters.isNotEmpty) {
|
||||
|
@ -475,7 +522,7 @@ class _FunctionType extends _Type {
|
|||
s.write("{");
|
||||
for (int i = 0; i < namedParameters.length; i++) {
|
||||
if (i > 0) s.write(", ");
|
||||
s.write(namedParameters._getUnchecked(i));
|
||||
s.write(namedParameters[i]);
|
||||
}
|
||||
s.write("}");
|
||||
}
|
||||
|
@ -628,8 +675,7 @@ class _Environment {
|
|||
|
||||
/// Look up the bound of a type parameter in its adjusted environment.
|
||||
_Type lookupAdjusted(_FunctionTypeParameterType param) {
|
||||
return type.typeParameterBounds
|
||||
._getUnchecked(param.index - type.typeParameterOffset);
|
||||
return type.typeParameterBounds[param.index - type.typeParameterOffset];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -648,26 +694,26 @@ class _TypeUniverse {
|
|||
}
|
||||
|
||||
static _Type substituteInterfaceTypeParameter(
|
||||
_InterfaceTypeParameterType typeParameter, List<_Type> substitutions) {
|
||||
_InterfaceTypeParameterType typeParameter,
|
||||
WasmObjectArray<_Type> substitutions) {
|
||||
// If the type parameter is non-nullable, or the substitution type is
|
||||
// nullable, then just return the substitution type. Otherwise, we return
|
||||
// [type] as nullable.
|
||||
// Note: This will throw if the required nullability is impossible to
|
||||
// generate.
|
||||
_Type substitution =
|
||||
substitutions._getUnchecked(typeParameter.environmentIndex);
|
||||
_Type substitution = substitutions[typeParameter.environmentIndex];
|
||||
if (typeParameter.isDeclaredNullable) return substitution.asNullable;
|
||||
return substitution;
|
||||
}
|
||||
|
||||
static _Type substituteFunctionTypeParameter(
|
||||
_FunctionTypeParameterType typeParameter,
|
||||
List<_Type> substitutions,
|
||||
WasmObjectArray<_Type> substitutions,
|
||||
_FunctionType? rootFunction) {
|
||||
if (rootFunction != null &&
|
||||
typeParameter.index >= rootFunction.typeParameterOffset) {
|
||||
_Type substitution = substitutions._getUnchecked(
|
||||
typeParameter.index - rootFunction.typeParameterOffset);
|
||||
_Type substitution =
|
||||
substitutions[typeParameter.index - rootFunction.typeParameterOffset];
|
||||
if (typeParameter.isDeclaredNullable) return substitution.asNullable;
|
||||
return substitution;
|
||||
} else {
|
||||
|
@ -677,7 +723,7 @@ class _TypeUniverse {
|
|||
|
||||
@pragma("wasm:entry-point")
|
||||
static _FunctionType substituteFunctionTypeArgument(
|
||||
_FunctionType functionType, List<_Type> substitutions) {
|
||||
_FunctionType functionType, WasmObjectArray<_Type> substitutions) {
|
||||
return substituteTypeArgument(functionType, substitutions, functionType)
|
||||
.as<_FunctionType>();
|
||||
}
|
||||
|
@ -690,8 +736,8 @@ class _TypeUniverse {
|
|||
/// are being substituted, or `null` when inside a nested function type that
|
||||
/// is guaranteed not to contain any type parameter types that are to be
|
||||
/// substituted.
|
||||
static _Type substituteTypeArgument(
|
||||
_Type type, List<_Type> substitutions, _FunctionType? rootFunction) {
|
||||
static _Type substituteTypeArgument(_Type type,
|
||||
WasmObjectArray<_Type> substitutions, _FunctionType? rootFunction) {
|
||||
if (type.isBottom || type.isTop) {
|
||||
return type;
|
||||
} else if (type.isFutureOr) {
|
||||
|
@ -728,34 +774,45 @@ class _TypeUniverse {
|
|||
// type parameter types as referring to the root function.
|
||||
rootFunction = null;
|
||||
}
|
||||
|
||||
final WasmObjectArray<_Type> bounds;
|
||||
if (isRoot) {
|
||||
bounds = const WasmObjectArray<_Type>.literal(<_Type>[]);
|
||||
} else {
|
||||
bounds = functionType.typeParameterBounds.map((_Type type) =>
|
||||
substituteTypeArgument(type, substitutions, rootFunction));
|
||||
}
|
||||
|
||||
final WasmObjectArray<_Type> defaults;
|
||||
if (isRoot) {
|
||||
defaults = const WasmObjectArray<_Type>.literal(<_Type>[]);
|
||||
} else {
|
||||
defaults = functionType.typeParameterDefaults.map((_Type type) =>
|
||||
substituteTypeArgument(type, substitutions, rootFunction));
|
||||
}
|
||||
|
||||
final WasmObjectArray<_Type> positionals =
|
||||
functionType.positionalParameters.map((_Type type) =>
|
||||
substituteTypeArgument(type, substitutions, rootFunction));
|
||||
|
||||
final WasmObjectArray<_NamedParameter> named = functionType
|
||||
.namedParameters
|
||||
.map((_NamedParameter named) => _NamedParameter(
|
||||
named.name,
|
||||
substituteTypeArgument(named.type, substitutions, rootFunction),
|
||||
named.isRequired));
|
||||
|
||||
final returnType = substituteTypeArgument(
|
||||
functionType.returnType, substitutions, rootFunction);
|
||||
|
||||
return _FunctionType(
|
||||
functionType.typeParameterOffset,
|
||||
isRoot
|
||||
? const []
|
||||
: functionType.typeParameterBounds
|
||||
.map((type) =>
|
||||
substituteTypeArgument(type, substitutions, rootFunction))
|
||||
.toList(),
|
||||
isRoot
|
||||
? const []
|
||||
: functionType.typeParameterDefaults
|
||||
.map((type) =>
|
||||
substituteTypeArgument(type, substitutions, rootFunction))
|
||||
.toList(),
|
||||
substituteTypeArgument(
|
||||
functionType.returnType, substitutions, rootFunction),
|
||||
functionType.positionalParameters
|
||||
.map((type) =>
|
||||
substituteTypeArgument(type, substitutions, rootFunction))
|
||||
.toList(),
|
||||
bounds,
|
||||
defaults,
|
||||
returnType,
|
||||
positionals,
|
||||
functionType.requiredParameterCount,
|
||||
functionType.namedParameters
|
||||
.map((named) => _NamedParameter(
|
||||
named.name,
|
||||
substituteTypeArgument(
|
||||
named.type, substitutions, rootFunction),
|
||||
named.isRequired))
|
||||
.toList(),
|
||||
named,
|
||||
functionType.isDeclaredNullable);
|
||||
} else if (type.isFunctionTypeParameterType) {
|
||||
return substituteFunctionTypeParameter(
|
||||
|
@ -834,12 +891,10 @@ class _TypeUniverse {
|
|||
|
||||
// If we have empty type arguments then create a list of dynamic type
|
||||
// arguments.
|
||||
// TODO(askesc): Use Wasm arrays more widely to avoid creating a
|
||||
// temporary list here.
|
||||
List<_Type> typeArgumentsForSubstitution =
|
||||
WasmObjectArray<_Type> typeArgumentsForSubstitution =
|
||||
substitutions.isNotEmpty && sTypeArguments.isEmpty
|
||||
? List.filled(substitutions.length, _literal<dynamic>())
|
||||
: List.generate(sTypeArguments.length, (i) => sTypeArguments[i]);
|
||||
? WasmObjectArray<_Type>(substitutions.length, _literal<dynamic>())
|
||||
: sTypeArguments;
|
||||
|
||||
// Finally substitute arguments. We must do this upfront so we can normalize
|
||||
// the type.
|
||||
|
@ -866,8 +921,8 @@ class _TypeUniverse {
|
|||
int tTypeParameterCount = t.typeParameterBounds.length;
|
||||
if (sTypeParameterCount != tTypeParameterCount) return false;
|
||||
for (int i = 0; i < sTypeParameterCount; i++) {
|
||||
if (!areEquivalent(s.typeParameterBounds._getUnchecked(i), sEnv,
|
||||
t.typeParameterBounds._getUnchecked(i), tEnv)) {
|
||||
if (!areEquivalent(
|
||||
s.typeParameterBounds[i], sEnv, t.typeParameterBounds[i], tEnv)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -883,8 +938,8 @@ class _TypeUniverse {
|
|||
|
||||
// Check [s] has enough required and optional positional arguments to
|
||||
// potentially be a valid subtype of [t].
|
||||
List<_Type> sPositional = s.positionalParameters;
|
||||
List<_Type> tPositional = t.positionalParameters;
|
||||
WasmObjectArray<_Type> sPositional = s.positionalParameters;
|
||||
WasmObjectArray<_Type> tPositional = t.positionalParameters;
|
||||
int sPositionalLength = sPositional.length;
|
||||
int tPositionalLength = tPositional.length;
|
||||
if (sPositionalLength < tPositionalLength) {
|
||||
|
@ -894,8 +949,8 @@ class _TypeUniverse {
|
|||
// Check all [t] positional arguments are subtypes of [s] positional
|
||||
// arguments.
|
||||
for (int i = 0; i < tPositionalLength; i++) {
|
||||
_Type sParameter = sPositional._getUnchecked(i);
|
||||
_Type tParameter = tPositional._getUnchecked(i);
|
||||
_Type sParameter = sPositional[i];
|
||||
_Type tParameter = tPositional[i];
|
||||
if (!isSubtype(tParameter, tEnv, sParameter, sEnv)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -903,17 +958,17 @@ class _TypeUniverse {
|
|||
|
||||
// Check that [t]'s named arguments are subtypes of [s]'s named arguments.
|
||||
// This logic assumes the named arguments are stored in sorted order.
|
||||
List<_NamedParameter> sNamed = s.namedParameters;
|
||||
List<_NamedParameter> tNamed = t.namedParameters;
|
||||
WasmObjectArray<_NamedParameter> sNamed = s.namedParameters;
|
||||
WasmObjectArray<_NamedParameter> tNamed = t.namedParameters;
|
||||
int sNamedLength = sNamed.length;
|
||||
int tNamedLength = tNamed.length;
|
||||
int sIndex = 0;
|
||||
for (int tIndex = 0; tIndex < tNamedLength; tIndex++) {
|
||||
_NamedParameter tNamedParameter = tNamed._getUnchecked(tIndex);
|
||||
_NamedParameter tNamedParameter = tNamed[tIndex];
|
||||
String tName = tNamedParameter.name;
|
||||
while (true) {
|
||||
if (sIndex >= sNamedLength) return false;
|
||||
_NamedParameter sNamedParameter = sNamed._getUnchecked(sIndex);
|
||||
_NamedParameter sNamedParameter = sNamed[sIndex];
|
||||
String sName = sNamedParameter.name;
|
||||
sIndex++;
|
||||
int sNameComparedToTName = sName.compareTo(tName);
|
||||
|
@ -933,7 +988,7 @@ class _TypeUniverse {
|
|||
}
|
||||
}
|
||||
while (sIndex < sNamedLength) {
|
||||
if (sNamed._getUnchecked(sIndex).isRequired) return false;
|
||||
if (sNamed[sIndex].isRequired) return false;
|
||||
sIndex++;
|
||||
}
|
||||
return true;
|
||||
|
@ -1133,7 +1188,10 @@ bool _checkClosureShape(_FunctionType functionType, List<_Type> typeArguments,
|
|||
List<Object?> positionalArguments, List<dynamic> namedArguments) {
|
||||
// Check type args, add default types to the type list if its empty
|
||||
if (typeArguments.isEmpty) {
|
||||
typeArguments.addAll(functionType.typeParameterDefaults);
|
||||
final defaults = functionType.typeParameterDefaults;
|
||||
for (int i = 0; i < defaults.length; ++i) {
|
||||
typeArguments.add(defaults[i]);
|
||||
}
|
||||
} else if (typeArguments.length !=
|
||||
functionType.typeParameterDefaults.length) {
|
||||
return false;
|
||||
|
@ -1150,8 +1208,7 @@ bool _checkClosureShape(_FunctionType functionType, List<_Type> typeArguments,
|
|||
int namedParamIdx = 0;
|
||||
int namedArgIdx = 0;
|
||||
while (namedParamIdx < functionType.namedParameters.length) {
|
||||
_NamedParameter param =
|
||||
functionType.namedParameters._getUnchecked(namedParamIdx);
|
||||
_NamedParameter param = functionType.namedParameters[namedParamIdx];
|
||||
|
||||
if (namedArgIdx * 2 >= namedArguments.length) {
|
||||
if (param.isRequired) {
|
||||
|
@ -1204,12 +1261,11 @@ void _checkClosureType(_FunctionType functionType, List<_Type> typeArguments,
|
|||
assert(functionType.typeParameterBounds.length == typeArguments.length);
|
||||
|
||||
if (!typeArguments.isEmpty) {
|
||||
for (int i = 0; i < typeArguments.length; i += 1) {
|
||||
final typeArgument = typeArguments._getUnchecked(i);
|
||||
final typesAsArray = typeArguments.toWasmArray();
|
||||
for (int i = 0; i < typesAsArray.length; i += 1) {
|
||||
final typeArgument = typesAsArray[i];
|
||||
final paramBound = _TypeUniverse.substituteTypeArgument(
|
||||
functionType.typeParameterBounds._getUnchecked(i),
|
||||
typeArguments,
|
||||
functionType);
|
||||
functionType.typeParameterBounds[i], typesAsArray, functionType);
|
||||
if (!_typeUniverse.isSubtype(typeArgument, null, paramBound, null)) {
|
||||
final stackTrace = StackTrace.current;
|
||||
final typeError = _TypeError.fromMessageAndStackTrace(
|
||||
|
@ -1221,13 +1277,13 @@ void _checkClosureType(_FunctionType functionType, List<_Type> typeArguments,
|
|||
}
|
||||
|
||||
functionType = _TypeUniverse.substituteFunctionTypeArgument(
|
||||
functionType, typeArguments);
|
||||
functionType, typesAsArray);
|
||||
}
|
||||
|
||||
// Check positional arguments
|
||||
for (int i = 0; i < positionalArguments.length; i += 1) {
|
||||
final Object? arg = positionalArguments._getUnchecked(i);
|
||||
final _Type paramTy = functionType.positionalParameters._getUnchecked(i);
|
||||
final _Type paramTy = functionType.positionalParameters[i];
|
||||
if (!_isSubtype(arg, paramTy)) {
|
||||
// TODO(50991): Positional parameter names not available in runtime
|
||||
_TypeError._throwArgumentTypeCheckError(
|
||||
|
@ -1242,11 +1298,9 @@ void _checkClosureType(_FunctionType functionType, List<_Type> typeArguments,
|
|||
while (namedArgIdx * 2 < namedArguments.length) {
|
||||
final String argName = _symbolToString(
|
||||
namedArguments._getUnchecked(namedArgIdx * 2) as Symbol);
|
||||
if (argName ==
|
||||
functionType.namedParameters._getUnchecked(namedParamIdx).name) {
|
||||
if (argName == functionType.namedParameters[namedParamIdx].name) {
|
||||
final arg = namedArguments._getUnchecked(namedArgIdx * 2 + 1);
|
||||
final paramTy =
|
||||
functionType.namedParameters._getUnchecked(namedParamIdx).type;
|
||||
final paramTy = functionType.namedParameters[namedParamIdx].type;
|
||||
if (!_isSubtype(arg, paramTy)) {
|
||||
_TypeError._throwArgumentTypeCheckError(
|
||||
arg, paramTy, argName, StackTrace.current);
|
||||
|
|
Loading…
Reference in a new issue