[vm] Implement typed data view GetIndexed in flow graph builder

Typed data view 'operator []' is now implemented in the flow
graph builder. This unifies all typed data GetIndexed operations
and removes unnecessary address calculations.

TEST=ci

Change-Id: I8d2ca6e7c7bf18b2590536a643f92cad5beb6d95
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/361283
Reviewed-by: Tess Strickland <sstrickl@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
diff --git a/runtime/tests/vm/dart/typed_list_index_checkbound_il_test.dart b/runtime/tests/vm/dart/typed_list_index_checkbound_il_test.dart
index eab8e80..404dae7 100644
--- a/runtime/tests/vm/dart/typed_list_index_checkbound_il_test.dart
+++ b/runtime/tests/vm/dart/typed_list_index_checkbound_il_test.dart
@@ -17,69 +17,13 @@
 
 @pragma('vm:never-inline')
 @pragma('vm:testing:print-flow-graph')
-int retrieveFromBase(Int8List src, int n) => src[n];
+int retrieveFromInternal(Int8List src, int n) => src[n];
 
 @pragma('vm:never-inline')
 @pragma('vm:testing:print-flow-graph')
 int retrieveFromExternal(Int8List src, int n) => src[n];
 
-void matchIL$retrieveFromView(FlowGraph graph) {
-  graph.match([
-    match.block('Graph'),
-    match.block('Function', [
-      'src' << match.Parameter(index: 0),
-      'n' << match.Parameter(index: 1),
-      'len' << match.LoadField('src', slot: 'TypedDataBase.length'),
-      if (is32BitConfiguration) ...[
-        'boxed_n' << match.BoxInt64('n'),
-        match.GenericCheckBound('len', 'boxed_n'),
-      ] else ...[
-        'unboxed_len' << match.UnboxInt64('len'),
-        match.GenericCheckBound('unboxed_len', 'n'),
-      ],
-      'typed_data' << match.LoadField('src', slot: 'TypedDataView.typed_data'),
-      'boxed_offset' <<
-          match.LoadField('src', slot: 'TypedDataView.offset_in_bytes'),
-      'offset' << match.UnboxInt64('boxed_offset'),
-      'index' << match.BinaryInt64Op('offset', 'n', op_kind: '+'),
-      if (is32BitConfiguration) ...[
-        'boxed_index' << match.BoxInt64('index'),
-      ],
-      'data' << match.LoadField('typed_data', slot: 'PointerBase.data'),
-      if (is32BitConfiguration) ...[
-        'retval32' << match.LoadIndexed('data', 'boxed_index'),
-        'retval' << match.IntConverter('retval32', from: 'int32', to: 'int64'),
-      ] else ...[
-        'retval' << match.LoadIndexed('data', 'index'),
-      ],
-      match.DartReturn('retval'),
-    ]),
-  ]);
-}
-
-void matchIL$retrieveFromBase(FlowGraph graph) {
-  graph.match([
-    match.block('Graph'),
-    match.block('Function', [
-      'src' << match.Parameter(index: 0),
-      'n' << match.Parameter(index: 1),
-      'len' << match.LoadField('src', slot: 'TypedDataBase.length'),
-      if (is32BitConfiguration) ...[
-        'boxed_n' << match.BoxInt64('n'),
-        match.GenericCheckBound('len', 'boxed_n'),
-        'retval32' << match.LoadIndexed('src', 'boxed_n'),
-        'retval' << match.IntConverter('retval32', from: 'int32', to: 'int64'),
-      ] else ...[
-        'unboxed_len' << match.UnboxInt64('len'),
-        match.GenericCheckBound('unboxed_len', 'n'),
-        'retval' << match.LoadIndexed('src', 'n'),
-      ],
-      match.DartReturn('retval'),
-    ]),
-  ]);
-}
-
-void matchIL$retrieveFromExternal(FlowGraph graph) {
+void matchILRetrieveFromNonInternal(FlowGraph graph) {
   graph.match([
     match.block('Graph'),
     match.block('Function', [
@@ -105,10 +49,40 @@
   ]);
 }
 
+void matchIL$retrieveFromView(FlowGraph graph) {
+  matchILRetrieveFromNonInternal(graph);
+}
+
+void matchIL$retrieveFromExternal(FlowGraph graph) {
+  matchILRetrieveFromNonInternal(graph);
+}
+
+void matchIL$retrieveFromInternal(FlowGraph graph) {
+  graph.match([
+    match.block('Graph'),
+    match.block('Function', [
+      'src' << match.Parameter(index: 0),
+      'n' << match.Parameter(index: 1),
+      'len' << match.LoadField('src', slot: 'TypedDataBase.length'),
+      if (is32BitConfiguration) ...[
+        'boxed_n' << match.BoxInt64('n'),
+        match.GenericCheckBound('len', 'boxed_n'),
+        'retval32' << match.LoadIndexed('src', 'boxed_n'),
+        'retval' << match.IntConverter('retval32', from: 'int32', to: 'int64'),
+      ] else ...[
+        'unboxed_len' << match.UnboxInt64('len'),
+        match.GenericCheckBound('unboxed_len', 'n'),
+        'retval' << match.LoadIndexed('src', 'n'),
+      ],
+      match.DartReturn('retval'),
+    ]),
+  ]);
+}
+
 void main(List<String> args) {
   final n = args.isEmpty ? 0 : int.parse(args.first);
   final list = Int8List.fromList([1, 2, 3, 4]);
-  print(retrieveFromBase(list, n));
+  print(retrieveFromInternal(list, n));
   print(retrieveFromView(Int8List.sublistView(list), n));
   if (!isSimulator) {
     using((arena) {
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc
index b650e43..c001277 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination.cc
@@ -1110,31 +1110,41 @@
       } else if (UseIsARedefinition(use) &&
                  AnyUseCreatesAlias(instr->Cast<Definition>())) {
         return true;
-      } else if ((instr->IsStoreField() &&
-                  (use->use_index() != StoreFieldInstr::kInstancePos))) {
-        ASSERT(use->use_index() == StoreFieldInstr::kValuePos);
-        // If we store this value into an object that is not aliased itself
-        // and we never load again then the store does not create an alias.
+      } else if (instr->IsStoreField()) {
         StoreFieldInstr* store = instr->AsStoreField();
-        Definition* instance =
-            store->instance()->definition()->OriginalDefinition();
-        if (Place::IsAllocation(instance) &&
-            !instance->Identity().IsAliased()) {
-          bool is_load, is_store;
-          Place store_place(instr, &is_load, &is_store);
 
-          if (!HasLoadsFromPlace(instance, &store_place)) {
-            // No loads found that match this store. If it is yet unknown if
-            // the object is not aliased then optimistically assume this but
-            // add it to the worklist to check its uses transitively.
-            if (instance->Identity().IsUnknown()) {
-              instance->SetIdentity(AliasIdentity::NotAliased());
-              aliasing_worklist_.Add(instance);
-            }
-            continue;
-          }
+        if (store->slot().kind() == Slot::Kind::kTypedDataView_typed_data) {
+          // Initialization of TypedDataView.typed_data field creates
+          // aliasing between the view and original typed data,
+          // as the same data can now be accessed via both typed data
+          // view and the original typed data.
+          return true;
         }
-        return true;
+
+        if (use->use_index() != StoreFieldInstr::kInstancePos) {
+          ASSERT(use->use_index() == StoreFieldInstr::kValuePos);
+          // If we store this value into an object that is not aliased itself
+          // and we never load again then the store does not create an alias.
+          Definition* instance =
+              store->instance()->definition()->OriginalDefinition();
+          if (Place::IsAllocation(instance) &&
+              !instance->Identity().IsAliased()) {
+            bool is_load, is_store;
+            Place store_place(instr, &is_load, &is_store);
+
+            if (!HasLoadsFromPlace(instance, &store_place)) {
+              // No loads found that match this store. If it is yet unknown if
+              // the object is not aliased then optimistically assume this but
+              // add it to the worklist to check its uses transitively.
+              if (instance->Identity().IsUnknown()) {
+                instance->SetIdentity(AliasIdentity::NotAliased());
+                aliasing_worklist_.Add(instance);
+              }
+              continue;
+            }
+          }
+          return true;
+        }
       } else if (auto* const alloc = instr->AsAllocation()) {
         // Treat inputs to an allocation instruction exactly as if they were
         // manually stored using a StoreField instruction.
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 78117d9..2538f63 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -960,36 +960,17 @@
   const MethodRecognizer::Kind kind = function.recognized_kind();
 
   switch (kind) {
+#define TYPED_DATA_GET_INDEXED_CASES(clazz)                                    \
+  case MethodRecognizer::k##clazz##ArrayGetIndexed:                            \
+    FALL_THROUGH;                                                              \
+  case MethodRecognizer::kExternal##clazz##ArrayGetIndexed:                    \
+    FALL_THROUGH;                                                              \
+  case MethodRecognizer::k##clazz##ArrayViewGetIndexed:                        \
+    FALL_THROUGH;
+    DART_CLASS_LIST_TYPED_DATA(TYPED_DATA_GET_INDEXED_CASES);
+#undef TYPED_DATA_GET_INDEXED_CASES
     case MethodRecognizer::kObjectArrayGetIndexed:
     case MethodRecognizer::kGrowableArrayGetIndexed:
-    case MethodRecognizer::kInt8ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt8ArrayGetIndexed:
-    case MethodRecognizer::kUint8ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint8ArrayGetIndexed:
-    case MethodRecognizer::kUint8ClampedArrayGetIndexed:
-    case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
-    case MethodRecognizer::kInt16ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt16ArrayGetIndexed:
-    case MethodRecognizer::kUint16ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint16ArrayGetIndexed:
-    case MethodRecognizer::kInt32ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt32ArrayGetIndexed:
-    case MethodRecognizer::kUint32ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint32ArrayGetIndexed:
-    case MethodRecognizer::kInt64ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt64ArrayGetIndexed:
-    case MethodRecognizer::kUint64ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint64ArrayGetIndexed:
-    case MethodRecognizer::kFloat32ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat32ArrayGetIndexed:
-    case MethodRecognizer::kFloat64ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat64ArrayGetIndexed:
-    case MethodRecognizer::kFloat32x4ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat32x4ArrayGetIndexed:
-    case MethodRecognizer::kFloat64x2ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat64x2ArrayGetIndexed:
-    case MethodRecognizer::kInt32x4ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt32x4ArrayGetIndexed:
     case MethodRecognizer::kRecord_fieldAt:
     case MethodRecognizer::kRecord_fieldNames:
     case MethodRecognizer::kRecord_numFields:
@@ -1214,36 +1195,17 @@
 
   const MethodRecognizer::Kind kind = function.recognized_kind();
   switch (kind) {
+#define TYPED_DATA_GET_INDEXED_CASES(clazz)                                    \
+  case MethodRecognizer::k##clazz##ArrayGetIndexed:                            \
+    FALL_THROUGH;                                                              \
+  case MethodRecognizer::kExternal##clazz##ArrayGetIndexed:                    \
+    FALL_THROUGH;                                                              \
+  case MethodRecognizer::k##clazz##ArrayViewGetIndexed:                        \
+    FALL_THROUGH;
+    DART_CLASS_LIST_TYPED_DATA(TYPED_DATA_GET_INDEXED_CASES);
+#undef TYPED_DATA_GET_INDEXED_CASES
     case MethodRecognizer::kObjectArrayGetIndexed:
-    case MethodRecognizer::kGrowableArrayGetIndexed:
-    case MethodRecognizer::kInt8ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt8ArrayGetIndexed:
-    case MethodRecognizer::kUint8ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint8ArrayGetIndexed:
-    case MethodRecognizer::kUint8ClampedArrayGetIndexed:
-    case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
-    case MethodRecognizer::kInt16ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt16ArrayGetIndexed:
-    case MethodRecognizer::kUint16ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint16ArrayGetIndexed:
-    case MethodRecognizer::kInt32ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt32ArrayGetIndexed:
-    case MethodRecognizer::kUint32ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint32ArrayGetIndexed:
-    case MethodRecognizer::kInt64ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt64ArrayGetIndexed:
-    case MethodRecognizer::kUint64ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint64ArrayGetIndexed:
-    case MethodRecognizer::kFloat32ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat32ArrayGetIndexed:
-    case MethodRecognizer::kFloat64ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat64ArrayGetIndexed:
-    case MethodRecognizer::kFloat32x4ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat32x4ArrayGetIndexed:
-    case MethodRecognizer::kFloat64x2ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat64x2ArrayGetIndexed:
-    case MethodRecognizer::kInt32x4ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt32x4ArrayGetIndexed: {
+    case MethodRecognizer::kGrowableArrayGetIndexed: {
       ASSERT_EQUAL(function.NumParameters(), 2);
       intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind);
       const Representation elem_rep =
diff --git a/runtime/vm/compiler/method_recognizer.cc b/runtime/vm/compiler/method_recognizer.cc
index 146ad46..f100bad 100644
--- a/runtime/vm/compiler/method_recognizer.cc
+++ b/runtime/vm/compiler/method_recognizer.cc
@@ -104,106 +104,24 @@
     case kGrowableArraySetIndexedUnchecked:
       return kGrowableObjectArrayCid;
 
-    case kFloat32ArrayGetIndexed:
-    case kFloat32ArraySetIndexed:
-      return kTypedDataFloat32ArrayCid;
+#define TYPED_DATA_GET_SET_INDEXED_CASES(clazz)                                \
+  case k##clazz##ArrayGetIndexed:                                              \
+  case k##clazz##ArraySetIndexed:                                              \
+    return kTypedData##clazz##ArrayCid;                                        \
+  case kExternal##clazz##ArrayGetIndexed:                                      \
+    return kExternalTypedData##clazz##ArrayCid;                                \
+  case k##clazz##ArrayViewGetIndexed:                                          \
+    return kTypedData##clazz##ArrayViewCid;
 
-    case kExternalFloat32ArrayGetIndexed:
-      return kExternalTypedDataFloat32ArrayCid;
+      DART_CLASS_LIST_TYPED_DATA(TYPED_DATA_GET_SET_INDEXED_CASES);
+#undef TYPED_DATA_GET_SET_INDEXED_CASES
 
-    case kFloat64ArrayGetIndexed:
-    case kFloat64ArraySetIndexed:
-      return kTypedDataFloat64ArrayCid;
-
-    case kExternalFloat64ArrayGetIndexed:
-      return kExternalTypedDataFloat64ArrayCid;
-
-    case kInt8ArrayGetIndexed:
-    case kInt8ArraySetIndexed:
-      return kTypedDataInt8ArrayCid;
-
-    case kExternalInt8ArrayGetIndexed:
-      return kExternalTypedDataInt8ArrayCid;
-
-    case kUint8ArrayGetIndexed:
-    case kUint8ArraySetIndexed:
-      return kTypedDataUint8ArrayCid;
-
-    case kUint8ClampedArrayGetIndexed:
-    case kUint8ClampedArraySetIndexed:
-      return kTypedDataUint8ClampedArrayCid;
-
-    case kExternalUint8ArrayGetIndexed:
     case kExternalUint8ArraySetIndexed:
       return kExternalTypedDataUint8ArrayCid;
 
-    case kExternalUint8ClampedArrayGetIndexed:
     case kExternalUint8ClampedArraySetIndexed:
       return kExternalTypedDataUint8ClampedArrayCid;
 
-    case kInt16ArrayGetIndexed:
-    case kInt16ArraySetIndexed:
-      return kTypedDataInt16ArrayCid;
-
-    case kExternalInt16ArrayGetIndexed:
-      return kExternalTypedDataInt16ArrayCid;
-
-    case kUint16ArrayGetIndexed:
-    case kUint16ArraySetIndexed:
-      return kTypedDataUint16ArrayCid;
-
-    case kExternalUint16ArrayGetIndexed:
-      return kExternalTypedDataUint16ArrayCid;
-
-    case kInt32ArrayGetIndexed:
-    case kInt32ArraySetIndexed:
-      return kTypedDataInt32ArrayCid;
-
-    case kExternalInt32ArrayGetIndexed:
-      return kExternalTypedDataInt32ArrayCid;
-
-    case kUint32ArrayGetIndexed:
-    case kUint32ArraySetIndexed:
-      return kTypedDataUint32ArrayCid;
-
-    case kExternalUint32ArrayGetIndexed:
-      return kExternalTypedDataUint32ArrayCid;
-
-    case kInt64ArrayGetIndexed:
-    case kInt64ArraySetIndexed:
-      return kTypedDataInt64ArrayCid;
-
-    case kExternalInt64ArrayGetIndexed:
-      return kExternalTypedDataInt64ArrayCid;
-
-    case kUint64ArrayGetIndexed:
-    case kUint64ArraySetIndexed:
-      return kTypedDataUint64ArrayCid;
-
-    case kExternalUint64ArrayGetIndexed:
-      return kExternalTypedDataUint64ArrayCid;
-
-    case kFloat32x4ArrayGetIndexed:
-    case kFloat32x4ArraySetIndexed:
-      return kTypedDataFloat32x4ArrayCid;
-
-    case kExternalFloat32x4ArrayGetIndexed:
-      return kExternalTypedDataFloat32x4ArrayCid;
-
-    case kInt32x4ArrayGetIndexed:
-    case kInt32x4ArraySetIndexed:
-      return kTypedDataInt32x4ArrayCid;
-
-    case kExternalInt32x4ArrayGetIndexed:
-      return kExternalTypedDataInt32x4ArrayCid;
-
-    case kFloat64x2ArrayGetIndexed:
-    case kFloat64x2ArraySetIndexed:
-      return kTypedDataFloat64x2ArrayCid;
-
-    case kExternalFloat64x2ArrayGetIndexed:
-      return kExternalTypedDataFloat64x2ArrayCid;
-
     default:
       break;
   }
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index d877349..a272f4d 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -19,33 +19,47 @@
   V(_GrowableList, [], GrowableArrayGetIndexed, 0x78d7e092)                    \
   V(_Int8List, [], Int8ArrayGetIndexed, 0x23133682)                            \
   V(_ExternalInt8Array, [], ExternalInt8ArrayGetIndexed, 0x23133682)           \
+  V(_Int8ArrayView, [], Int8ArrayViewGetIndexed, 0x23133682)                   \
   V(_Uint8List, [], Uint8ArrayGetIndexed, 0x23133682)                          \
   V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 0x23133682)         \
+  V(_Uint8ArrayView, [], Uint8ArrayViewGetIndexed, 0x23133682)                 \
   V(_Uint8ClampedList, [], Uint8ClampedArrayGetIndexed, 0x23133682)            \
   V(_ExternalUint8ClampedArray, [], ExternalUint8ClampedArrayGetIndexed,       \
     0x23133682)                                                                \
+  V(_Uint8ClampedArrayView, [], Uint8ClampedArrayViewGetIndexed, 0x23133682)   \
   V(_Int16List, [], Int16ArrayGetIndexed, 0x23133682)                          \
   V(_ExternalInt16Array, [], ExternalInt16ArrayGetIndexed, 0x23133682)         \
+  V(_Int16ArrayView, [], Int16ArrayViewGetIndexed, 0x23133682)                 \
   V(_Uint16List, [], Uint16ArrayGetIndexed, 0x23133682)                        \
   V(_ExternalUint16Array, [], ExternalUint16ArrayGetIndexed, 0x23133682)       \
+  V(_Uint16ArrayView, [], Uint16ArrayViewGetIndexed, 0x23133682)               \
   V(_Int32List, [], Int32ArrayGetIndexed, 0x231332c1)                          \
   V(_ExternalInt32Array, [], ExternalInt32ArrayGetIndexed, 0x231332c1)         \
+  V(_Int32ArrayView, [], Int32ArrayViewGetIndexed, 0x231332c1)                 \
   V(_Uint32List, [], Uint32ArrayGetIndexed, 0x231332c1)                        \
   V(_ExternalUint32Array, [], ExternalUint32ArrayGetIndexed, 0x231332c1)       \
+  V(_Uint32ArrayView, [], Uint32ArrayViewGetIndexed, 0x231332c1)               \
   V(_Int64List, [], Int64ArrayGetIndexed, 0x231332c1)                          \
   V(_ExternalInt64Array, [], ExternalInt64ArrayGetIndexed, 0x231332c1)         \
+  V(_Int64ArrayView, [], Int64ArrayViewGetIndexed, 0x231332c1)                 \
   V(_Uint64List, [], Uint64ArrayGetIndexed, 0x231332c1)                        \
   V(_ExternalUint64Array, [], ExternalUint64ArrayGetIndexed, 0x231332c1)       \
+  V(_Uint64ArrayView, [], Uint64ArrayViewGetIndexed, 0x231332c1)               \
   V(_Float32List, [], Float32ArrayGetIndexed, 0x07764e5c)                      \
   V(_ExternalFloat32Array, [], ExternalFloat32ArrayGetIndexed, 0x07764e5c)     \
+  V(_Float32ArrayView, [], Float32ArrayViewGetIndexed, 0x07764e5c)             \
   V(_Float64List, [], Float64ArrayGetIndexed, 0x07764e5c)                      \
   V(_ExternalFloat64Array, [], ExternalFloat64ArrayGetIndexed, 0x07764e5c)     \
+  V(_Float64ArrayView, [], Float64ArrayViewGetIndexed, 0x07764e5c)             \
   V(_Float32x4List, [], Float32x4ArrayGetIndexed, 0xb0e90a43)                  \
   V(_ExternalFloat32x4Array, [], ExternalFloat32x4ArrayGetIndexed, 0xb0e90a43) \
+  V(_Float32x4ArrayView, [], Float32x4ArrayViewGetIndexed, 0xb0e90a43)         \
   V(_Float64x2List, [], Float64x2ArrayGetIndexed, 0x5fc75359)                  \
   V(_ExternalFloat64x2Array, [], ExternalFloat64x2ArrayGetIndexed, 0x5fc75359) \
+  V(_Float64x2ArrayView, [], Float64x2ArrayViewGetIndexed, 0x5fc75359)         \
   V(_Int32x4List, [], Int32x4ArrayGetIndexed, 0x4959642b)                      \
   V(_ExternalInt32x4Array, [], ExternalInt32x4ArrayGetIndexed, 0x4959642b)     \
+  V(_Int32x4ArrayView, [], Int32x4ArrayViewGetIndexed, 0x4959642b)             \
   V(_List, ., ObjectArrayAllocate, 0x4c802222)                                 \
   V(_List, []=, ObjectArraySetIndexed, 0x3a23c6fa)                             \
   V(_GrowableList, ._withData, GrowableArrayAllocateWithData, 0x192ac0e1)      \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 0258413..fb78e1e 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -9151,34 +9151,15 @@
     // arrays, which requires optimization for payload extraction.
     case MethodRecognizer::kObjectArrayGetIndexed:
     case MethodRecognizer::kGrowableArrayGetIndexed:
-    case MethodRecognizer::kInt8ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt8ArrayGetIndexed:
-    case MethodRecognizer::kUint8ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint8ArrayGetIndexed:
-    case MethodRecognizer::kUint8ClampedArrayGetIndexed:
-    case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
-    case MethodRecognizer::kInt16ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt16ArrayGetIndexed:
-    case MethodRecognizer::kUint16ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint16ArrayGetIndexed:
-    case MethodRecognizer::kInt32ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt32ArrayGetIndexed:
-    case MethodRecognizer::kUint32ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint32ArrayGetIndexed:
-    case MethodRecognizer::kInt64ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt64ArrayGetIndexed:
-    case MethodRecognizer::kUint64ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint64ArrayGetIndexed:
-    case MethodRecognizer::kFloat32ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat32ArrayGetIndexed:
-    case MethodRecognizer::kFloat64ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat64ArrayGetIndexed:
-    case MethodRecognizer::kFloat32x4ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat32x4ArrayGetIndexed:
-    case MethodRecognizer::kFloat64x2ArrayGetIndexed:
-    case MethodRecognizer::kExternalFloat64x2ArrayGetIndexed:
-    case MethodRecognizer::kInt32x4ArrayGetIndexed:
-    case MethodRecognizer::kExternalInt32x4ArrayGetIndexed:
+#define TYPED_DATA_GET_INDEXED_CASES(clazz)                                    \
+  case MethodRecognizer::k##clazz##ArrayGetIndexed:                            \
+    FALL_THROUGH;                                                              \
+  case MethodRecognizer::kExternal##clazz##ArrayGetIndexed:                    \
+    FALL_THROUGH;                                                              \
+  case MethodRecognizer::k##clazz##ArrayViewGetIndexed:                        \
+    FALL_THROUGH;
+      DART_CLASS_LIST_TYPED_DATA(TYPED_DATA_GET_INDEXED_CASES);
+#undef TYPED_DATA_GET_INDEXED_CASES
     case MethodRecognizer::kCopyRangeFromUint8ListToOneByteString:
     case MethodRecognizer::kFinalizerBase_getIsolateFinalizers:
     case MethodRecognizer::kFinalizerBase_setIsolate:
diff --git a/sdk/lib/_internal/vm/lib/typed_data_patch.dart b/sdk/lib/_internal/vm/lib/typed_data_patch.dart
index 5eda03d..a7edc94 100644
--- a/sdk/lib/_internal/vm/lib/typed_data_patch.dart
+++ b/sdk/lib/_internal/vm/lib/typed_data_patch.dart
@@ -4160,12 +4160,11 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  int operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getInt8(offsetInBytes + (index * Int8List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  @pragma("vm:exact-result-type", "dart:core#_Smi")
+  external int operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, int value) {
@@ -4206,12 +4205,11 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  int operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getUint8(offsetInBytes + (index * Uint8List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  @pragma("vm:exact-result-type", "dart:core#_Smi")
+  external int operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, int value) {
@@ -4255,12 +4253,11 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  int operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getUint8(offsetInBytes + (index * Uint8List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  @pragma("vm:exact-result-type", "dart:core#_Smi")
+  external int operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, int value) {
@@ -4307,12 +4304,11 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  int operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getInt16(offsetInBytes + (index * Int16List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  @pragma("vm:exact-result-type", "dart:core#_Smi")
+  external int operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, int value) {
@@ -4367,12 +4363,11 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  int operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getUint16(offsetInBytes + (index * Uint16List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  @pragma("vm:exact-result-type", "dart:core#_Smi")
+  external int operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, int value) {
@@ -4427,12 +4422,10 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  int operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getInt32(offsetInBytes + (index * Int32List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  external int operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, int value) {
@@ -4473,12 +4466,10 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  int operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getUint32(offsetInBytes + (index * Uint32List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  external int operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, int value) {
@@ -4519,12 +4510,10 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  int operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getInt64(offsetInBytes + (index * Int64List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  external int operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, int value) {
@@ -4565,12 +4554,10 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  int operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getUint64(offsetInBytes + (index * Uint64List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  external int operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, int value) {
@@ -4611,12 +4598,11 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  double operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getFloat32(offsetInBytes + (index * Float32List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  @pragma("vm:exact-result-type", "dart:core#_Double")
+  external double operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, double value) {
@@ -4657,12 +4643,11 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
+  @pragma("vm:recognized", "other")
   @pragma("vm:prefer-inline")
-  double operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getFloat64(offsetInBytes + (index * Float64List.bytesPerElement));
-  }
+  @pragma("vm:idempotent")
+  @pragma("vm:exact-result-type", "dart:core#_Double")
+  external double operator [](int index);
 
   @pragma("vm:prefer-inline")
   void operator []=(int index, double value) {
@@ -4703,11 +4688,11 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
-  Float32x4 operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getFloat32x4(offsetInBytes + (index * Float32x4List.bytesPerElement));
-  }
+  @pragma("vm:recognized", "other")
+  @pragma("vm:prefer-inline")
+  @pragma("vm:idempotent")
+  @pragma("vm:exact-result-type", _Float32x4)
+  external Float32x4 operator [](int index);
 
   void operator []=(int index, Float32x4 value) {
     index = _typedDataIndexCheck(this, index, length);
@@ -4747,11 +4732,11 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
-  Int32x4 operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getInt32x4(offsetInBytes + (index * Int32x4List.bytesPerElement));
-  }
+  @pragma("vm:recognized", "other")
+  @pragma("vm:prefer-inline")
+  @pragma("vm:idempotent")
+  @pragma("vm:exact-result-type", _Int32x4)
+  external Int32x4 operator [](int index);
 
   void operator []=(int index, Int32x4 value) {
     index = _typedDataIndexCheck(this, index, length);
@@ -4791,11 +4776,11 @@
       _TypedList buffer, int offsetInBytes, int length);
 
   // Method(s) implementing the List interface.
-  Float64x2 operator [](int index) {
-    index = _typedDataIndexCheck(this, index, length);
-    return _typedData
-        ._getFloat64x2(offsetInBytes + (index * Float64x2List.bytesPerElement));
-  }
+  @pragma("vm:recognized", "other")
+  @pragma("vm:prefer-inline")
+  @pragma("vm:idempotent")
+  @pragma("vm:exact-result-type", _Float64x2)
+  external Float64x2 operator [](int index);
 
   void operator []=(int index, Float64x2 value) {
     index = _typedDataIndexCheck(this, index, length);