[dart2wasm] Make implicit arguments check use optimized is/as helpers
The implicit covariance type checks are currently performed by always
calling out to RTT. Those can use our existing optimized implementation
for is/as checks.
This reduces code size of -O2 mode as well as makes certain
benchmarks significantly faster (e.g. UIMatrix* 2x faster)
Change-Id: Ib5224a310b2188b9edb2de1e800d2e60010d11f1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370280
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 5584f31..9973849 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -325,8 +325,6 @@
}
}
- w.Local? tempLocalForType;
-
void setupParamLocal(VariableDeclaration variable, int index,
Constant? defaultValue, bool isRequired) {
w.Local local = paramLocals[implicitParams + index];
@@ -362,9 +360,6 @@
}
if (!translator.options.omitImplicitTypeChecks) {
if (variable.isCovariantByClass || variable.isCovariantByDeclaration) {
- final typeLocal = tempLocalForType ??= addLocal(
- translator.classInfo[translator.typeClass]!.nonNullableType);
-
final boxedType = variable.type.isPotentiallyNullable
? translator.topInfo.nullableType
: translator.topInfo.nonNullableType;
@@ -379,9 +374,8 @@
_generateArgumentTypeCheck(
variable.name!,
() => b.local_get(operand),
- () => types.makeType(this, variable.type),
+ variable.type,
operand,
- typeLocal,
);
}
}
@@ -3348,11 +3342,6 @@
// Local for the argument.
final argLocal = addLocal(translator.topInfo.nullableType);
- // Local for the expected type of the argument.
- final typeType =
- translator.classInfo[translator.typeClass]!.nonNullableType;
- final argTypeLocal = addLocal(typeType);
-
final member_ = member;
DartType paramType;
if (member_ is Field) {
@@ -3361,13 +3350,14 @@
paramType = (member_ as Procedure).setterType;
}
- _generateArgumentTypeCheck(
- member.name.text,
- () => b.local_get(positionalArgLocal),
- () => types.makeType(this, paramType),
- argLocal,
- argTypeLocal,
- );
+ if (!translator.options.omitImplicitTypeChecks) {
+ _generateArgumentTypeCheck(
+ member.name.text,
+ () => b.local_get(positionalArgLocal),
+ paramType,
+ argLocal,
+ );
+ }
ClassInfo info = translator.classInfo[member_.enclosingClass]!;
if (member_ is Field) {
@@ -3465,14 +3455,10 @@
final List<VariableDeclaration> memberPositionalParams =
procedure.function.positionalParameters;
- // Local for the current argument being checked. Used to avoid indexing the
- // positional parameters array again when throwing type error.
+ // Local for the current argument being checked. Used to avoid indexing
+ // the positional parameters array again when throwing type error.
final argLocal = addLocal(translator.topInfo.nullableType);
- // Local for the expected type of the current positional arguments. Used to
- // avoid generating the type again when throwing type error.
- final argTypeLocal = addLocal(typeType);
-
for (int positionalParamIdx = 0;
positionalParamIdx < memberPositionalParams.length;
positionalParamIdx += 1) {
@@ -3484,11 +3470,8 @@
b.i32_const(positionalParamIdx);
b.array_get(translator.nullableObjectArrayType);
},
- () {
- types.makeType(this, param.type);
- },
+ param.type,
argLocal,
- argTypeLocal,
);
}
@@ -3519,11 +3502,8 @@
b.i32_const(mapNamedParameterToArrayIndex(param.name!));
b.array_get(translator.nullableObjectArrayType);
},
- () {
- types.makeType(this, param.type);
- },
+ param.type,
argLocal,
- argTypeLocal,
);
}
}
@@ -3582,39 +3562,42 @@
/// Does not expect any values on stack and does not leave any values on
/// stack.
///
- /// Locals [argLocal] and [argExpectedTypeLocal] are used to store values
- /// pushed by [pushArg] and [pushArgExpectedType] and reuse the values.
+ /// Locals [argLocal] are used to store values pushed by [pushArg]
+ /// and reuse the values.
///
/// [argName] is used in the type error as the name of the argument that
/// doesn't match the expected type.
void _generateArgumentTypeCheck(
String argName,
void Function() pushArg,
- void Function() pushArgExpectedType,
+ DartType testedAgainstType,
w.Local argLocal,
- w.Local argExpectedTypeLocal,
) {
- // Argument
- pushArg();
- b.local_tee(argLocal);
-
- // Expected type
- pushArgExpectedType();
- b.local_tee(argExpectedTypeLocal);
-
- // Check that argument type is subtype of expected type
- call(translator.isSubtype.reference);
-
- b.i32_eqz();
- b.if_();
- // Type check failed
- b.local_get(argLocal);
- b.local_get(argExpectedTypeLocal);
- _emitString(argName);
- call(translator.stackTraceCurrent.reference);
- call(translator.throwArgumentTypeCheckError.reference);
- b.unreachable();
- b.end();
+ if (translator.options.minify) {
+ // We don't need to include the name in the error message, so we can use
+ // the optimized `as` checks.
+ pushArg();
+ types.emitAsCheck(
+ this,
+ testedAgainstType,
+ translator.coreTypes.objectNullableRawType,
+ argLocal.type as w.RefType);
+ b.drop();
+ } else {
+ pushArg();
+ b.local_tee(argLocal);
+ types.emitIsTest(
+ this, testedAgainstType, translator.coreTypes.objectNullableRawType);
+ b.i32_eqz();
+ b.if_();
+ b.local_get(argLocal);
+ types.makeType(this, testedAgainstType);
+ _emitString(argName);
+ call(translator.stackTraceCurrent.reference);
+ call(translator.throwArgumentTypeCheckError.reference);
+ b.unreachable();
+ b.end();
+ }
}
void _generateTypeArgumentBoundCheck(