[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(