[dart2wasm] Don't add dispatch table entries for _WasmBase methods

Some of the `_WasmBase` subtypes are represented as unboxed Wasm values
and cannot be used as virutal method receivers.

Previously we added methods for `_WasmBase` subtypes to the dispatch
table and considered those types as receivers in dynamic invocations.
This causes bad code generation as these types do not represent Dart
objects.

With this CL we don't add `_WasmBase` subtype methods to dispatch
tables, and in dynamic invocations we don't consider `_WasmBase` types
as receivers.

New passing tests:

- language/variable/inference_captured_variable_test
- lib/typed_data/typed_data_list_test

Change-Id: I4f4145db12652133aa55dcce75acad72bb4ec48b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/268761
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
diff --git a/pkg/dart2wasm/lib/dispatch_table.dart b/pkg/dart2wasm/lib/dispatch_table.dart
index 1e151e6..0db7d98 100644
--- a/pkg/dart2wasm/lib/dispatch_table.dart
+++ b/pkg/dart2wasm/lib/dispatch_table.dart
@@ -235,9 +235,14 @@
         ? 1
         : 0;
 
-    bool calledDynamically =
+    // _WasmBase and its subclass methods cannot be called dynamically
+    final cls = member.enclosingClass;
+    final isWasmType = cls != null && translator.isWasmType(cls);
+
+    final calledDynamically = !isWasmType &&
         translator.dynamics.maybeCalledDynamically(member, metadata);
-    var selector = selectorInfo.putIfAbsent(
+
+    final selector = selectorInfo.putIfAbsent(
         selectorId,
         () => SelectorInfo(
             translator,
@@ -277,11 +282,16 @@
 
   void build() {
     // Collect class/selector combinations
+
+    // Maps class IDs to selector IDs of the class
     List<List<int>> selectorsInClass = [];
+
     for (ClassInfo info in translator.classes) {
       List<int> selectorIds = [];
       ClassInfo? superInfo = info.superInfo;
-      if (superInfo != null) {
+
+      // _WasmBase does not inherit from Object
+      if (superInfo != null && info.cls != translator.wasmTypesBaseClass) {
         int superId = superInfo.classId;
         selectorIds = List.of(selectorsInClass[superId]);
         for (int selectorId in selectorIds) {
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 00a241a..e972490 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -540,7 +540,8 @@
     return false;
   }
 
-  bool isWasmType(Class cls) => _hasSuperclass(cls, wasmTypesBaseClass);
+  bool isWasmType(Class cls) =>
+      cls == wasmTypesBaseClass || _hasSuperclass(cls, wasmTypesBaseClass);
 
   bool isFfiCompound(Class cls) => _hasSuperclass(cls, ffiCompoundClass);
 
diff --git a/sdk/lib/wasm/wasm_types.dart b/sdk/lib/wasm/wasm_types.dart
index 142bc07..5c71a03 100644
--- a/sdk/lib/wasm/wasm_types.dart
+++ b/sdk/lib/wasm/wasm_types.dart
@@ -11,6 +11,7 @@
 //   parameter/return of static functions. No other uses of the types are valid.
 // - They are not assignable to or from any ordinary Dart types.
 // - The integer and float types can't be nullable.
+// - Their instance methods cannot be called virtually or dynamically.
 //
 // TODO(askesc): Give an error message if any of these constraints are violated.