[VM] Define layout of _*ArrayView/_ByteDataView in C+++

This removes the 3 fields from the classes in Dart and instead describes
the layout in C++ via a RawTypedDataView class (as already do with
normal RawTypedData). The existing "semi" TypedDataView handle class is
changed to be a real handle class.

This decreases performance of some microbenchmarks due to field guards
not being used anymore (before the JIT could add a field guard to view classes
guarding that only normal typed data is used as backing store (and not e.g. external
typed data)

Issue https://github.com/dart-lang/sdk/issues/35154
Issue https://github.com/dart-lang/sdk/issues/31954

Change-Id: I7a0022b843a4c0fa69f53dedcc4c7bd2117cdc37
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/96806
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc
index 5592f20..5402def 100644
--- a/runtime/lib/string.cc
+++ b/runtime/lib/string.cc
@@ -328,15 +328,15 @@
       Exceptions::ThrowByType(Exceptions::kArgument, args);
     }
     return OneByteString::New(array, start, length, space);
-  } else if (RawObject::IsTypedDataViewClassId(list.GetClassId())) {
-    const Instance& view = Instance::Cast(list);
-    if (end > Smi::Value(TypedDataView::Length(view))) {
+  } else if (list.IsTypedDataView()) {
+    const auto& view = TypedDataView::Cast(list);
+    if (end > Smi::Value(view.length())) {
       const Array& args = Array::Handle(Array::New(1));
       args.SetAt(0, end_obj);
       Exceptions::ThrowByType(Exceptions::kArgument, args);
     }
-    const Instance& data_obj = Instance::Handle(TypedDataView::Data(view));
-    intptr_t data_offset = Smi::Value(TypedDataView::OffsetInBytes(view));
+    const Instance& data_obj = Instance::Handle(view.typed_data());
+    intptr_t data_offset = Smi::Value(view.offset_in_bytes());
     if (data_obj.IsTypedData()) {
       const TypedData& array = TypedData::Cast(data_obj);
       return OneByteString::New(array, data_offset + start, length, space);
@@ -422,16 +422,16 @@
     }
     return TwoByteString::New(array, start * sizeof(uint16_t), length, space);
   } else if (RawObject::IsTypedDataViewClassId(list.GetClassId())) {
+    const auto& view = TypedDataView::Cast(list);
     const intptr_t cid = list.GetClassId();
     if (cid != kTypedDataUint16ArrayViewCid) {
       Exceptions::ThrowArgumentError(list);
     }
-    if (end > Smi::Value(TypedDataView::Length(list))) {
+    if (end > Smi::Value(view.length())) {
       Exceptions::ThrowArgumentError(end_obj);
     }
-    const Instance& data_obj =
-        Instance::Handle(zone, TypedDataView::Data(list));
-    intptr_t data_offset = Smi::Value(TypedDataView::OffsetInBytes(list));
+    const auto& data_obj = Instance::Handle(zone, view.typed_data());
+    const intptr_t data_offset = Smi::Value(view.offset_in_bytes());
     if (data_obj.IsTypedData()) {
       const TypedData& array = TypedData::Cast(data_obj);
       return TwoByteString::New(array, data_offset + start * sizeof(uint16_t),
diff --git a/runtime/lib/typed_data.cc b/runtime/lib/typed_data.cc
index 4a373fc..1c55247 100644
--- a/runtime/lib/typed_data.cc
+++ b/runtime/lib/typed_data.cc
@@ -28,6 +28,15 @@
   }
 }
 
+static void AlignmentCheck(intptr_t offset_in_bytes, intptr_t element_size) {
+  if ((offset_in_bytes % element_size) != 0) {
+    const auto& error = String::Handle(String::NewFormatted(
+        "Offset in bytes (%" Pd ") must be a multiple of %" Pd "",
+        offset_in_bytes, element_size));
+    Exceptions::ThrowArgumentError(error);
+  }
+}
+
 // Checks to see if a length will not result in an OOM error.
 static void LengthCheck(intptr_t len, intptr_t max) {
   if (len < 0 || len > max) {
@@ -53,6 +62,27 @@
   return Integer::null();
 }
 
+DEFINE_NATIVE_ENTRY(TypedDataView_offsetInBytes, 0, 1) {
+  // "this" is either a _*ArrayView class or _ByteDataView.
+  GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
+  ASSERT(instance.IsTypedDataView());
+  return TypedDataView::Cast(instance).offset_in_bytes();
+}
+
+DEFINE_NATIVE_ENTRY(TypedDataView_length, 0, 1) {
+  // "this" is either a _*ArrayView class or _ByteDataView.
+  GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
+  ASSERT(instance.IsTypedDataView());
+  return TypedDataView::Cast(instance).length();
+}
+
+DEFINE_NATIVE_ENTRY(TypedDataView_typedData, 0, 1) {
+  // "this" is either a _*ArrayView class or _ByteDataView.
+  GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
+  ASSERT(instance.IsTypedDataView());
+  return TypedDataView::Cast(instance).typed_data();
+}
+
 template <typename DstType, typename SrcType>
 static RawBool* CopyData(const Instance& dst,
                          const Instance& src,
@@ -160,9 +190,9 @@
 #define TYPED_DATA_NEW(name)                                                   \
   DEFINE_NATIVE_ENTRY(TypedData_##name##_new, 0, 2) {                          \
     GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(1));      \
-    intptr_t cid = kTypedData##name##Cid;                                      \
-    intptr_t len = length.Value();                                             \
-    intptr_t max = TypedData::MaxElements(cid);                                \
+    const intptr_t cid = kTypedData##name##Cid;                                \
+    const intptr_t len = length.Value();                                       \
+    const intptr_t max = TypedData::MaxElements(cid);                          \
     LengthCheck(len, max);                                                     \
     return TypedData::New(cid, len);                                           \
   }
@@ -170,6 +200,35 @@
 #define TYPED_DATA_NEW_NATIVE(name) TYPED_DATA_NEW(name)
 
 CLASS_LIST_TYPED_DATA(TYPED_DATA_NEW_NATIVE)
+#undef TYPED_DATA_NEW_NATIVE
+#undef TYPED_DATA_NEW
+
+#define TYPED_DATA_VIEW_NEW(native_name, cid_name)                             \
+  DEFINE_NATIVE_ENTRY(native_name, 0, 4) {                                     \
+    GET_NON_NULL_NATIVE_ARGUMENT(Instance, typed_data,                         \
+                                 arguments->NativeArgAt(1));                   \
+    GET_NON_NULL_NATIVE_ARGUMENT(Smi, offset, arguments->NativeArgAt(2));      \
+    GET_NON_NULL_NATIVE_ARGUMENT(Smi, len, arguments->NativeArgAt(3));         \
+    const intptr_t backing_length =                                            \
+        typed_data.IsTypedData()                                               \
+            ? TypedData::Cast(typed_data).LengthInBytes()                      \
+            : ExternalTypedData::Cast(typed_data).LengthInBytes();             \
+    const intptr_t cid = cid_name;                                             \
+    const intptr_t offset_in_bytes = offset.Value();                           \
+    const intptr_t length = len.Value();                                       \
+    const intptr_t element_size = TypedDataView::ElementSizeInBytes(cid);      \
+    AlignmentCheck(offset_in_bytes, element_size);                             \
+    LengthCheck(offset_in_bytes + length * element_size, backing_length);      \
+    return TypedDataView::New(cid, typed_data, offset_in_bytes, length);       \
+  }
+
+#define TYPED_DATA_NEW_NATIVE(name)                                            \
+  TYPED_DATA_VIEW_NEW(TypedDataView_##name##View_new, kTypedData##name##ViewCid)
+
+CLASS_LIST_TYPED_DATA(TYPED_DATA_NEW_NATIVE)
+TYPED_DATA_VIEW_NEW(TypedDataView_ByteDataView_new, kByteDataViewCid)
+#undef TYPED_DATA_NEW_NATIVE
+#undef TYPED_DATA_VIEW_NEW
 
 #define TYPED_DATA_GETTER(getter, object, ctor, access_size)                   \
   DEFINE_NATIVE_ENTRY(TypedData_##getter, 0, 2) {                              \
diff --git a/runtime/lib/typed_data_patch.dart b/runtime/lib/typed_data_patch.dart
index 56d4fe3..7af2181 100644
--- a/runtime/lib/typed_data_patch.dart
+++ b/runtime/lib/typed_data_patch.dart
@@ -1914,7 +1914,7 @@
     length ??= (this.lengthInBytes - offsetInBytes) ~/ Int8List.bytesPerElement;
     _rangeCheck(
         this.lengthInBytes, offsetInBytes, length * Int8List.bytesPerElement);
-    return new _Int8ArrayView(this, offsetInBytes, length);
+    return new _Int8ArrayView(this._data, offsetInBytes, length);
   }
 
   Uint8List asUint8List([int offsetInBytes = 0, int length]) {
@@ -1922,7 +1922,7 @@
         (this.lengthInBytes - offsetInBytes) ~/ Uint8List.bytesPerElement;
     _rangeCheck(
         this.lengthInBytes, offsetInBytes, length * Uint8List.bytesPerElement);
-    return new _Uint8ArrayView(this, offsetInBytes, length);
+    return new _Uint8ArrayView(this._data, offsetInBytes, length);
   }
 
   Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) {
@@ -1930,7 +1930,7 @@
         Uint8ClampedList.bytesPerElement;
     _rangeCheck(this.lengthInBytes, offsetInBytes,
         length * Uint8ClampedList.bytesPerElement);
-    return new _Uint8ClampedArrayView(this, offsetInBytes, length);
+    return new _Uint8ClampedArrayView(this._data, offsetInBytes, length);
   }
 
   Int16List asInt16List([int offsetInBytes = 0, int length]) {
@@ -1938,7 +1938,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Int16List.bytesPerElement;
     _rangeCheck(
         this.lengthInBytes, offsetInBytes, length * Int16List.bytesPerElement);
-    return new _Int16ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Int16List.bytesPerElement);
+    return new _Int16ArrayView(this._data, offsetInBytes, length);
   }
 
   Uint16List asUint16List([int offsetInBytes = 0, int length]) {
@@ -1946,7 +1947,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Uint16List.bytesPerElement;
     _rangeCheck(
         this.lengthInBytes, offsetInBytes, length * Uint16List.bytesPerElement);
-    return new _Uint16ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Uint16List.bytesPerElement);
+    return new _Uint16ArrayView(this._data, offsetInBytes, length);
   }
 
   Int32List asInt32List([int offsetInBytes = 0, int length]) {
@@ -1954,7 +1956,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Int32List.bytesPerElement;
     _rangeCheck(
         this.lengthInBytes, offsetInBytes, length * Int32List.bytesPerElement);
-    return new _Int32ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Int32List.bytesPerElement);
+    return new _Int32ArrayView(this._data, offsetInBytes, length);
   }
 
   Uint32List asUint32List([int offsetInBytes = 0, int length]) {
@@ -1962,7 +1965,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Uint32List.bytesPerElement;
     _rangeCheck(
         this.lengthInBytes, offsetInBytes, length * Uint32List.bytesPerElement);
-    return new _Uint32ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Uint32List.bytesPerElement);
+    return new _Uint32ArrayView(this._data, offsetInBytes, length);
   }
 
   Int64List asInt64List([int offsetInBytes = 0, int length]) {
@@ -1970,7 +1974,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Int64List.bytesPerElement;
     _rangeCheck(
         this.lengthInBytes, offsetInBytes, length * Int64List.bytesPerElement);
-    return new _Int64ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Int64List.bytesPerElement);
+    return new _Int64ArrayView(this._data, offsetInBytes, length);
   }
 
   Uint64List asUint64List([int offsetInBytes = 0, int length]) {
@@ -1978,7 +1983,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Uint64List.bytesPerElement;
     _rangeCheck(
         this.lengthInBytes, offsetInBytes, length * Uint64List.bytesPerElement);
-    return new _Uint64ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Uint64List.bytesPerElement);
+    return new _Uint64ArrayView(this._data, offsetInBytes, length);
   }
 
   Float32List asFloat32List([int offsetInBytes = 0, int length]) {
@@ -1986,7 +1992,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Float32List.bytesPerElement;
     _rangeCheck(this.lengthInBytes, offsetInBytes,
         length * Float32List.bytesPerElement);
-    return new _Float32ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Float32List.bytesPerElement);
+    return new _Float32ArrayView(this._data, offsetInBytes, length);
   }
 
   Float64List asFloat64List([int offsetInBytes = 0, int length]) {
@@ -1994,7 +2001,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Float64List.bytesPerElement;
     _rangeCheck(this.lengthInBytes, offsetInBytes,
         length * Float64List.bytesPerElement);
-    return new _Float64ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Float64List.bytesPerElement);
+    return new _Float64ArrayView(this._data, offsetInBytes, length);
   }
 
   Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) {
@@ -2002,7 +2010,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Float32x4List.bytesPerElement;
     _rangeCheck(this.lengthInBytes, offsetInBytes,
         length * Float32x4List.bytesPerElement);
-    return new _Float32x4ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Float32x4List.bytesPerElement);
+    return new _Float32x4ArrayView(this._data, offsetInBytes, length);
   }
 
   Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) {
@@ -2010,7 +2019,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Int32x4List.bytesPerElement;
     _rangeCheck(this.lengthInBytes, offsetInBytes,
         length * Int32x4List.bytesPerElement);
-    return new _Int32x4ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Int32x4List.bytesPerElement);
+    return new _Int32x4ArrayView(this._data, offsetInBytes, length);
   }
 
   Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) {
@@ -2018,7 +2028,8 @@
         (this.lengthInBytes - offsetInBytes) ~/ Float64x2List.bytesPerElement;
     _rangeCheck(this.lengthInBytes, offsetInBytes,
         length * Float64x2List.bytesPerElement);
-    return new _Float64x2ArrayView(this, offsetInBytes, length);
+    _offsetAlignmentCheck(offsetInBytes, Float64x2List.bytesPerElement);
+    return new _Float64x2ArrayView(this._data, offsetInBytes, length);
   }
 }
 
@@ -3562,11 +3573,6 @@
 }
 
 abstract class _TypedListView extends _TypedListBase implements TypedData {
-  _TypedListView(_ByteBuffer _buffer, int _offset, int _length)
-      : _typedData = _buffer._data,
-        offsetInBytes = _offset,
-        length = _length;
-
   // Method(s) implementing the TypedData interface.
 
   int get lengthInBytes {
@@ -3578,13 +3584,13 @@
   }
 
   @pragma("vm:non-nullable-result-type")
-  final _TypedList _typedData;
+  _TypedList get _typedData native "TypedDataView_typedData";
 
   @pragma("vm:exact-result-type", "dart:core#_Smi")
-  final int offsetInBytes;
+  int get offsetInBytes native "TypedDataView_offsetInBytes";
 
   @pragma("vm:exact-result-type", "dart:core#_Smi")
-  final int length;
+  int get length native "TypedDataView_length";
 }
 
 @pragma("vm:entry-point")
@@ -3592,8 +3598,9 @@
     with _IntListMixin
     implements Int8List {
   // Constructor.
-  _Int8ArrayView(_ByteBuffer buffer, int offsetInBytes, int length)
-      : super(buffer, offsetInBytes, length);
+  @pragma("vm:exact-result-type", _Int8ArrayView)
+  factory _Int8ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Int8ArrayView_new";
 
   // Method(s) implementing List interface.
   int operator [](int index) {
@@ -3628,8 +3635,9 @@
     with _IntListMixin
     implements Uint8List {
   // Constructor.
-  _Uint8ArrayView(_ByteBuffer buffer, int offsetInBytes, int length)
-      : super(buffer, offsetInBytes, length);
+  @pragma("vm:exact-result-type", _Uint8ArrayView)
+  factory _Uint8ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Uint8ArrayView_new";
 
   // Method(s) implementing List interface.
   int operator [](int index) {
@@ -3664,8 +3672,9 @@
     with _IntListMixin
     implements Uint8ClampedList {
   // Constructor.
-  _Uint8ClampedArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length);
+  @pragma("vm:exact-result-type", _Uint8ClampedArrayView)
+  factory _Uint8ClampedArrayView(_TypedList buffer, int offsetInBytes,
+      int length) native "TypedDataView_Uint8ClampedArrayView_new";
 
   // Method(s) implementing List interface.
   int operator [](int index) {
@@ -3700,10 +3709,9 @@
     with _IntListMixin
     implements Int16List {
   // Constructor.
-  _Int16ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Int16List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Int16ArrayView)
+  factory _Int16ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Int16ArrayView_new";
 
   // Method(s) implementing List interface.
   int operator [](int index) {
@@ -3750,10 +3758,9 @@
     with _IntListMixin
     implements Uint16List {
   // Constructor.
-  _Uint16ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Uint16List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Uint16ArrayView)
+  factory _Uint16ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Uint16ArrayView_new";
 
   // Method(s) implementing List interface.
   int operator [](int index) {
@@ -3801,10 +3808,9 @@
     with _IntListMixin
     implements Int32List {
   // Constructor.
-  _Int32ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Int32List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Int32ArrayView)
+  factory _Int32ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Int32ArrayView_new";
 
   // Method(s) implementing List interface.
   int operator [](int index) {
@@ -3839,10 +3845,9 @@
     with _IntListMixin
     implements Uint32List {
   // Constructor.
-  _Uint32ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Uint32List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Uint32ArrayView)
+  factory _Uint32ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Uint32ArrayView_new";
 
   // Method(s) implementing List interface.
   int operator [](int index) {
@@ -3877,10 +3882,9 @@
     with _IntListMixin
     implements Int64List {
   // Constructor.
-  _Int64ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Int64List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Int64ArrayView)
+  factory _Int64ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Int64ArrayView_new";
 
   // Method(s) implementing List interface.
   int operator [](int index) {
@@ -3915,10 +3919,9 @@
     with _IntListMixin
     implements Uint64List {
   // Constructor.
-  _Uint64ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Uint64List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Uint64ArrayView)
+  factory _Uint64ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Uint64ArrayView_new";
 
   // Method(s) implementing List interface.
   int operator [](int index) {
@@ -3953,10 +3956,9 @@
     with _DoubleListMixin
     implements Float32List {
   // Constructor.
-  _Float32ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Float32List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Float32ArrayView)
+  factory _Float32ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Float32ArrayView_new";
 
   // Method(s) implementing List interface.
   double operator [](int index) {
@@ -3991,10 +3993,9 @@
     with _DoubleListMixin
     implements Float64List {
   // Constructor.
-  _Float64ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Float64List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Float64ArrayView)
+  factory _Float64ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Float64ArrayView_new";
 
   // Method(s) implementing List interface.
   double operator [](int index) {
@@ -4029,10 +4030,9 @@
     with _Float32x4ListMixin
     implements Float32x4List {
   // Constructor.
-  _Float32x4ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Float32x4List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Float32x4ArrayView)
+  factory _Float32x4ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Float32x4ArrayView_new";
 
   // Method(s) implementing List interface.
   Float32x4 operator [](int index) {
@@ -4067,10 +4067,9 @@
     with _Int32x4ListMixin
     implements Int32x4List {
   // Constructor.
-  _Int32x4ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Int32x4List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Int32x4ArrayView)
+  factory _Int32x4ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Int32x4ArrayView_new";
 
   // Method(s) implementing List interface.
   Int32x4 operator [](int index) {
@@ -4105,10 +4104,9 @@
     with _Float64x2ListMixin
     implements Float64x2List {
   // Constructor.
-  _Float64x2ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
-      : super(buffer, _offsetInBytes, _length) {
-    _offsetAlignmentCheck(_offsetInBytes, Float64x2List.bytesPerElement);
-  }
+  @pragma("vm:exact-result-type", _Float64x2ArrayView)
+  factory _Float64x2ArrayView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_Float64x2ArrayView_new";
 
   // Method(s) implementing List interface.
   Float64x2 operator [](int index) {
@@ -4140,7 +4138,9 @@
 
 @pragma("vm:entry-point")
 class _ByteDataView implements ByteData {
-  _ByteDataView(this._typedData, this._offset, this.length);
+  @pragma("vm:exact-result-type", _ByteDataView)
+  factory _ByteDataView(_TypedList buffer, int offsetInBytes, int length)
+      native "TypedDataView_ByteDataView_new";
 
   // Method(s) implementing TypedData interface.
   _ByteBuffer get buffer {
@@ -4151,10 +4151,6 @@
     return length;
   }
 
-  int get offsetInBytes {
-    return _offset;
-  }
-
   int get elementSizeInBytes {
     return 1;
   }
@@ -4165,35 +4161,35 @@
     if (byteOffset < 0 || byteOffset >= length) {
       throw new RangeError.index(byteOffset, this, "byteOffset");
     }
-    return _typedData._getInt8(_offset + byteOffset);
+    return _typedData._getInt8(offsetInBytes + byteOffset);
   }
 
   void setInt8(int byteOffset, int value) {
     if (byteOffset < 0 || byteOffset >= length) {
       throw new RangeError.index(byteOffset, this, "byteOffset");
     }
-    _typedData._setInt8(_offset + byteOffset, value);
+    _typedData._setInt8(offsetInBytes + byteOffset, value);
   }
 
   int getUint8(int byteOffset) {
     if (byteOffset < 0 || byteOffset >= length) {
       throw new RangeError.index(byteOffset, this, "byteOffset");
     }
-    return _typedData._getUint8(_offset + byteOffset);
+    return _typedData._getUint8(offsetInBytes + byteOffset);
   }
 
   void setUint8(int byteOffset, int value) {
     if (byteOffset < 0 || byteOffset >= length) {
       throw new RangeError.index(byteOffset, this, "byteOffset");
     }
-    _typedData._setUint8(_offset + byteOffset, value);
+    _typedData._setUint8(offsetInBytes + byteOffset, value);
   }
 
   int getInt16(int byteOffset, [Endian endian = Endian.big]) {
     if (byteOffset < 0 || byteOffset + 1 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 2, "byteOffset");
     }
-    var result = _typedData._getInt16(_offset + byteOffset);
+    var result = _typedData._getInt16(offsetInBytes + byteOffset);
     if (identical(endian, Endian.host)) {
       return result;
     }
@@ -4204,7 +4200,7 @@
     if (byteOffset < 0 || byteOffset + 1 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 2, "byteOffset");
     }
-    _typedData._setInt16(_offset + byteOffset,
+    _typedData._setInt16(offsetInBytes + byteOffset,
         identical(endian, Endian.host) ? value : _byteSwap16(value));
   }
 
@@ -4212,7 +4208,7 @@
     if (byteOffset < 0 || byteOffset + 1 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 2, "byteOffset");
     }
-    var result = _typedData._getUint16(_offset + byteOffset);
+    var result = _typedData._getUint16(offsetInBytes + byteOffset);
     if (identical(endian, Endian.host)) {
       return result;
     }
@@ -4223,7 +4219,7 @@
     if (byteOffset < 0 || byteOffset + 1 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 2, "byteOffset");
     }
-    _typedData._setUint16(_offset + byteOffset,
+    _typedData._setUint16(offsetInBytes + byteOffset,
         identical(endian, Endian.host) ? value : _byteSwap16(value));
   }
 
@@ -4231,7 +4227,7 @@
     if (byteOffset < 0 || byteOffset + 3 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 4, "byteOffset");
     }
-    var result = _typedData._getInt32(_offset + byteOffset);
+    var result = _typedData._getInt32(offsetInBytes + byteOffset);
     if (identical(endian, Endian.host)) {
       return result;
     }
@@ -4242,7 +4238,7 @@
     if (byteOffset < 0 || byteOffset + 3 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 4, "byteOffset");
     }
-    _typedData._setInt32(_offset + byteOffset,
+    _typedData._setInt32(offsetInBytes + byteOffset,
         identical(endian, Endian.host) ? value : _byteSwap32(value));
   }
 
@@ -4250,7 +4246,7 @@
     if (byteOffset < 0 || byteOffset + 3 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 4, "byteOffset");
     }
-    var result = _typedData._getUint32(_offset + byteOffset);
+    var result = _typedData._getUint32(offsetInBytes + byteOffset);
     if (identical(endian, Endian.host)) {
       return result;
     }
@@ -4261,7 +4257,7 @@
     if (byteOffset < 0 || byteOffset + 3 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 4, "byteOffset");
     }
-    _typedData._setUint32(_offset + byteOffset,
+    _typedData._setUint32(offsetInBytes + byteOffset,
         identical(endian, Endian.host) ? value : _byteSwap32(value));
   }
 
@@ -4269,7 +4265,7 @@
     if (byteOffset < 0 || byteOffset + 7 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 8, "byteOffset");
     }
-    var result = _typedData._getInt64(_offset + byteOffset);
+    var result = _typedData._getInt64(offsetInBytes + byteOffset);
     if (identical(endian, Endian.host)) {
       return result;
     }
@@ -4280,7 +4276,7 @@
     if (byteOffset < 0 || byteOffset + 7 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 8, "byteOffset");
     }
-    _typedData._setInt64(_offset + byteOffset,
+    _typedData._setInt64(offsetInBytes + byteOffset,
         identical(endian, Endian.host) ? value : _byteSwap64(value));
   }
 
@@ -4288,7 +4284,7 @@
     if (byteOffset < 0 || byteOffset + 7 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 8, "byteOffset");
     }
-    var result = _typedData._getUint64(_offset + byteOffset);
+    var result = _typedData._getUint64(offsetInBytes + byteOffset);
     if (identical(endian, Endian.host)) {
       return result;
     }
@@ -4299,7 +4295,7 @@
     if (byteOffset < 0 || byteOffset + 7 >= length) {
       throw new RangeError.range(byteOffset, 0, length - 8, "byteOffset");
     }
-    _typedData._setUint64(_offset + byteOffset,
+    _typedData._setUint64(offsetInBytes + byteOffset,
         identical(endian, Endian.host) ? value : _byteSwap64(value));
   }
 
@@ -4308,9 +4304,10 @@
       throw new RangeError.range(byteOffset, 0, length - 4, "byteOffset");
     }
     if (identical(endian, Endian.host)) {
-      return _typedData._getFloat32(_offset + byteOffset);
+      return _typedData._getFloat32(offsetInBytes + byteOffset);
     }
-    _convU32[0] = _byteSwap32(_typedData._getUint32(_offset + byteOffset));
+    _convU32[0] =
+        _byteSwap32(_typedData._getUint32(offsetInBytes + byteOffset));
     return _convF32[0];
   }
 
@@ -4319,11 +4316,11 @@
       throw new RangeError.range(byteOffset, 0, length - 4, "byteOffset");
     }
     if (identical(endian, Endian.host)) {
-      _typedData._setFloat32(_offset + byteOffset, value);
+      _typedData._setFloat32(offsetInBytes + byteOffset, value);
       return;
     }
     _convF32[0] = value;
-    _typedData._setUint32(_offset + byteOffset, _byteSwap32(_convU32[0]));
+    _typedData._setUint32(offsetInBytes + byteOffset, _byteSwap32(_convU32[0]));
   }
 
   double getFloat64(int byteOffset, [Endian endian = Endian.big]) {
@@ -4331,9 +4328,10 @@
       throw new RangeError.range(byteOffset, 0, length - 8, "byteOffset");
     }
     if (identical(endian, Endian.host)) {
-      return _typedData._getFloat64(_offset + byteOffset);
+      return _typedData._getFloat64(offsetInBytes + byteOffset);
     }
-    _convU64[0] = _byteSwap64(_typedData._getUint64(_offset + byteOffset));
+    _convU64[0] =
+        _byteSwap64(_typedData._getUint64(offsetInBytes + byteOffset));
     return _convF64[0];
   }
 
@@ -4342,11 +4340,11 @@
       throw new RangeError.range(byteOffset, 0, length - 8, "byteOffset");
     }
     if (identical(endian, Endian.host)) {
-      _typedData._setFloat64(_offset + byteOffset, value);
+      _typedData._setFloat64(offsetInBytes + byteOffset, value);
       return;
     }
     _convF64[0] = value;
-    _typedData._setUint64(_offset + byteOffset, _byteSwap64(_convU64[0]));
+    _typedData._setUint64(offsetInBytes + byteOffset, _byteSwap64(_convU64[0]));
   }
 
   Float32x4 getFloat32x4(int byteOffset, [Endian endian = Endian.big]) {
@@ -4354,7 +4352,7 @@
       throw new RangeError.range(byteOffset, 0, length - 4, "byteOffset");
     }
     // TODO(johnmccutchan) : Need to resolve this for endianity.
-    return _typedData._getFloat32x4(_offset + byteOffset);
+    return _typedData._getFloat32x4(offsetInBytes + byteOffset);
   }
 
   void setFloat32x4(int byteOffset, Float32x4 value,
@@ -4363,17 +4361,17 @@
       throw new RangeError.range(byteOffset, 0, length - 4, "byteOffset");
     }
     // TODO(johnmccutchan) : Need to resolve this for endianity.
-    _typedData._setFloat32x4(_offset + byteOffset, value);
+    _typedData._setFloat32x4(offsetInBytes + byteOffset, value);
   }
 
   @pragma("vm:non-nullable-result-type")
-  final _TypedList _typedData;
+  _TypedList get _typedData native "TypedDataView_typedData";
 
   @pragma("vm:exact-result-type", "dart:core#_Smi")
-  final int _offset;
+  int get offsetInBytes native "TypedDataView_offsetInBytes";
 
   @pragma("vm:exact-result-type", "dart:core#_Smi")
-  final int length;
+  int get length native "TypedDataView_length";
 }
 
 int _byteSwap16(int value) {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 194a86c..da9161f 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -211,6 +211,24 @@
   V(TypedData_SetInt32x4, 3)                                                   \
   V(TypedData_GetFloat64x2, 2)                                                 \
   V(TypedData_SetFloat64x2, 3)                                                 \
+  V(TypedDataView_ByteDataView_new, 4)                                         \
+  V(TypedDataView_Int8ArrayView_new, 4)                                        \
+  V(TypedDataView_Uint8ArrayView_new, 4)                                       \
+  V(TypedDataView_Uint8ClampedArrayView_new, 4)                                \
+  V(TypedDataView_Int16ArrayView_new, 4)                                       \
+  V(TypedDataView_Uint16ArrayView_new, 4)                                      \
+  V(TypedDataView_Int32ArrayView_new, 4)                                       \
+  V(TypedDataView_Uint32ArrayView_new, 4)                                      \
+  V(TypedDataView_Int64ArrayView_new, 4)                                       \
+  V(TypedDataView_Uint64ArrayView_new, 4)                                      \
+  V(TypedDataView_Float32ArrayView_new, 4)                                     \
+  V(TypedDataView_Float64ArrayView_new, 4)                                     \
+  V(TypedDataView_Float32x4ArrayView_new, 4)                                   \
+  V(TypedDataView_Int32x4ArrayView_new, 4)                                     \
+  V(TypedDataView_Float64x2ArrayView_new, 4)                                   \
+  V(TypedDataView_length, 1)                                                   \
+  V(TypedDataView_offsetInBytes, 1)                                            \
+  V(TypedDataView_typedData, 1)                                                \
   V(Float32x4_fromDoubles, 5)                                                  \
   V(Float32x4_splat, 2)                                                        \
   V(Float32x4_fromInt32x4Bits, 2)                                              \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 5b65f43..eb79223 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1400,52 +1400,6 @@
   Error& error = Error::Handle(zone);
   TypeParameter& type_param = TypeParameter::Handle(zone);
 
-  // First verify field offsets of all the TypedDataView classes.
-  for (intptr_t cid = kTypedDataInt8ArrayViewCid;
-       cid <= kTypedDataFloat32x4ArrayViewCid; cid++) {
-    cls = class_table.At(cid);  // Get the TypedDataView class.
-    error = cls.EnsureIsFinalized(thread);
-    ASSERT(error.IsNull());
-    cls = cls.SuperClass();  // Get it's super class '_TypedListView'.
-    cls = cls.SuperClass();
-    fields_array ^= cls.fields();
-    ASSERT(fields_array.Length() == TypedDataView::NumberOfFields());
-    field ^= fields_array.At(0);
-    ASSERT(field.Offset() == TypedDataView::data_offset());
-    name ^= field.name();
-    expected_name ^= String::New("_typedData");
-    ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name));
-    field ^= fields_array.At(1);
-    ASSERT(field.Offset() == TypedDataView::offset_in_bytes_offset());
-    name ^= field.name();
-    ASSERT(name.Equals("offsetInBytes"));
-    field ^= fields_array.At(2);
-    ASSERT(field.Offset() == TypedDataView::length_offset());
-    name ^= field.name();
-    ASSERT(name.Equals("length"));
-  }
-
-  // Now verify field offsets of '_ByteDataView' class.
-  cls = class_table.At(kByteDataViewCid);
-  error = cls.EnsureIsFinalized(thread);
-  ASSERT(error.IsNull());
-  fields_array ^= cls.fields();
-  ASSERT(fields_array.Length() == TypedDataView::NumberOfFields());
-  field ^= fields_array.At(0);
-  ASSERT(field.Offset() == TypedDataView::data_offset());
-  name ^= field.name();
-  expected_name ^= String::New("_typedData");
-  ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name));
-  field ^= fields_array.At(1);
-  ASSERT(field.Offset() == TypedDataView::offset_in_bytes_offset());
-  name ^= field.name();
-  expected_name ^= String::New("_offset");
-  ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name));
-  field ^= fields_array.At(2);
-  ASSERT(field.Offset() == TypedDataView::length_offset());
-  name ^= field.name();
-  ASSERT(name.Equals("length"));
-
   // Now verify field offsets of '_ByteBuffer' class.
   cls = class_table.At(kByteBufferCid);
   error = cls.EnsureIsFinalized(thread);
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index ddbd7a0..22cf733 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -66,6 +66,7 @@
   V(Float64x2)                                                                 \
   V(TypedData)                                                                 \
   V(ExternalTypedData)                                                         \
+  V(TypedDataView)                                                             \
   V(Pointer)                                                                   \
   V(DynamicLibrary)                                                            \
   V(Capability)                                                                \
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 0ffd5c1..3d2a546 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -2554,6 +2554,7 @@
   switch (slot().kind()) {
     case Slot::Kind::kArray_length:
     case Slot::Kind::kTypedData_length:
+    case Slot::Kind::kTypedDataView_length:
     case Slot::Kind::kString_length:
       return true;
     case Slot::Kind::kGrowableObjectArray_length:
@@ -2569,6 +2570,8 @@
     case Slot::Kind::kArgumentsDescriptor_positional_count:
     case Slot::Kind::kArgumentsDescriptor_count:
     case Slot::Kind::kTypeArguments:
+    case Slot::Kind::kTypedDataView_offset_in_bytes:
+    case Slot::Kind::kTypedDataView_data:
     case Slot::Kind::kGrowableObjectArray_data:
     case Slot::Kind::kContext_parent:
     case Slot::Kind::kClosure_context:
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 9920c06..a81b2cc 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -535,8 +535,11 @@
         if (!function.always_inline() && !function.IsRecognized()) {
           return false;
         }
-        static constexpr intptr_t kAvgListedMethodSize = 20;
-        instruction_count += (inl_size == 0 ? kAvgListedMethodSize : inl_size);
+        if (!function.always_inline()) {
+          static constexpr intptr_t kAvgListedMethodSize = 20;
+          instruction_count +=
+              (inl_size == 0 ? kAvgListedMethodSize : inl_size);
+        }
       }
     }
   }
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index a78e2fa..755ff5e 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -2605,6 +2605,8 @@
       break;
 
     case Slot::Kind::kTypedData_length:
+    case Slot::Kind::kTypedDataView_length:
+    case Slot::Kind::kTypedDataView_offset_in_bytes:
       *range = Range(RangeBoundary::FromConstant(0), RangeBoundary::MaxSmi());
       break;
 
@@ -2630,6 +2632,7 @@
     case Slot::Kind::kClosure_function_type_arguments:
     case Slot::Kind::kClosure_instantiator_type_arguments:
     case Slot::Kind::kPointer_c_memory_address:
+    case Slot::Kind::kTypedDataView_data:
       // Not an integer valued field.
       UNREACHABLE();
       break;
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index f1c01f9..695760d 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -73,6 +73,9 @@
       RawObject::IsTypedDataClassId(array_cid)) {
     return GetNativeSlot(Kind::kTypedData_length);
   }
+  if (RawObject::IsTypedDataViewClassId(array_cid)) {
+    return GetNativeSlot(Kind::kTypedDataView_length);
+  }
 
   switch (array_cid) {
     case kGrowableObjectArrayCid:
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index 2a45084..fc82584 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -59,6 +59,9 @@
   V(GrowableObjectArray, length, Smi, VAR)                                     \
   V(GrowableObjectArray, data, Array, VAR)                                     \
   V(TypedData, length, Smi, FINAL)                                             \
+  V(TypedDataView, length, Smi, FINAL)                                         \
+  V(TypedDataView, offset_in_bytes, Smi, FINAL)                                \
+  V(TypedDataView, data, Dynamic, FINAL)                                       \
   V(String, length, Smi, FINAL)                                                \
   V(LinkedHashMap, index, TypedDataUint32Array, VAR)                           \
   V(LinkedHashMap, data, Array, VAR)                                           \
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index fece005..15b989b 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -748,6 +748,65 @@
   const MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
   bool omit_result_type_check = true;
   switch (kind) {
+    case MethodRecognizer::kTypedData_ByteDataView_factory:
+      body += BuildTypedDataViewFactoryConstructor(function, kByteDataViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Int8ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(function,
+                                                   kTypedDataInt8ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Uint8ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(function,
+                                                   kTypedDataUint8ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Uint8ClampedArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(
+          function, kTypedDataUint8ClampedArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Int16ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(function,
+                                                   kTypedDataInt16ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Uint16ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(
+          function, kTypedDataUint16ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Int32ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(function,
+                                                   kTypedDataInt32ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Uint32ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(
+          function, kTypedDataUint32ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Int64ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(function,
+                                                   kTypedDataInt64ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Uint64ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(
+          function, kTypedDataUint64ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Float32ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(
+          function, kTypedDataFloat32ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Float64ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(
+          function, kTypedDataFloat64ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Float32x4ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(
+          function, kTypedDataFloat32x4ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Int32x4ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(
+          function, kTypedDataInt32x4ArrayViewCid);
+      break;
+    case MethodRecognizer::kTypedData_Float64x2ArrayView_factory:
+      body += BuildTypedDataViewFactoryConstructor(
+          function, kTypedDataFloat64x2ArrayViewCid);
+      break;
     case MethodRecognizer::kObjectEquals:
       body += LoadLocal(parsed_function_->receiver_var());
       body += LoadLocal(first_parameter);
@@ -775,6 +834,21 @@
       body += LoadLocal(parsed_function_->receiver_var());
       body += LoadNativeField(Slot::TypedData_length());
       break;
+    case MethodRecognizer::kByteDataViewLength:
+    case MethodRecognizer::kTypedDataViewLength:
+      body += LoadLocal(parsed_function_->receiver_var());
+      body += LoadNativeField(Slot::TypedDataView_length());
+      break;
+    case MethodRecognizer::kByteDataViewOffsetInBytes:
+    case MethodRecognizer::kTypedDataViewOffsetInBytes:
+      body += LoadLocal(parsed_function_->receiver_var());
+      body += LoadNativeField(Slot::TypedDataView_offset_in_bytes());
+      break;
+    case MethodRecognizer::kByteDataViewTypedData:
+    case MethodRecognizer::kTypedDataViewTypedData:
+      body += LoadLocal(parsed_function_->receiver_var());
+      body += LoadNativeField(Slot::TypedDataView_data());
+      break;
     case MethodRecognizer::kClassIDgetID:
       body += LoadLocal(first_parameter);
       body += LoadClassId();
@@ -930,6 +1004,39 @@
   return body + Return(TokenPosition::kNoSource, omit_result_type_check);
 }
 
+Fragment FlowGraphBuilder::BuildTypedDataViewFactoryConstructor(
+    const Function& function,
+    classid_t cid) {
+  auto token_pos = function.token_pos();
+  auto class_table = Thread::Current()->isolate()->class_table();
+
+  ASSERT(class_table->HasValidClassAt(cid));
+  const auto& view_class = Class::ZoneHandle(H.zone(), class_table->At(cid));
+
+  LocalVariable* typed_data = parsed_function_->RawParameterVariable(1);
+  LocalVariable* offset_in_bytes = parsed_function_->RawParameterVariable(2);
+  LocalVariable* length = parsed_function_->RawParameterVariable(3);
+
+  Fragment body;
+
+  body += AllocateObject(token_pos, view_class, /*arg_count=*/0);
+  LocalVariable* view_object = MakeTemporary();
+
+  body += LoadLocal(view_object);
+  body += LoadLocal(typed_data);
+  body += StoreInstanceField(token_pos, Slot::TypedDataView_data());
+
+  body += LoadLocal(view_object);
+  body += LoadLocal(offset_in_bytes);
+  body += StoreInstanceField(token_pos, Slot::TypedDataView_offset_in_bytes());
+
+  body += LoadLocal(view_object);
+  body += LoadLocal(length);
+  body += StoreInstanceField(token_pos, Slot::TypedDataView_length());
+
+  return body;
+}
+
 static const LocalScope* MakeImplicitClosureScope(Zone* Z, const Class& klass) {
   ASSERT(!klass.IsNull());
   // Note that if klass is _Closure, DeclarationType will be _Closure,
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index 6e15186..1e76f9a 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -105,6 +105,9 @@
   Fragment NativeFunctionBody(const Function& function,
                               LocalVariable* first_parameter);
 
+  Fragment BuildTypedDataViewFactoryConstructor(const Function& function,
+                                                classid_t cid);
+
   Fragment EnterScope(intptr_t kernel_offset,
                       const LocalScope** scope = nullptr);
   Fragment ExitScope(intptr_t kernel_offset);
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index fa35d7c..a0baa73 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -8,7 +8,7 @@
 namespace dart {
 
 // clang-format off
-// (class-name, function-name, recognized enum, result type, fingerprint).
+// (class-name, function-name, recognized enum, fingerprint).
 // When adding a new function add a 0 as fingerprint, build and run to get the
 // correct fingerprint from the mismatch error (or use Library::GetFunction()
 // and print func.SourceFingerprint()).
@@ -42,6 +42,27 @@
   V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x38a80b0d)              \
   V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x40052c4e)          \
   V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x07b89f54)              \
+  V(_ByteDataView, get:length, ByteDataViewLength, 0x0)                        \
+  V(_ByteDataView, get:offsetInBytes, ByteDataViewOffsetInBytes, 0x0)          \
+  V(_ByteDataView, get:_typedData, ByteDataViewTypedData, 0x0)                 \
+  V(_TypedListView, get:length, TypedDataViewLength, 0x0)                      \
+  V(_TypedListView, get:offsetInBytes, TypedDataViewOffsetInBytes, 0x0)        \
+  V(_TypedListView, get:_typedData, TypedDataViewTypedData, 0x0)               \
+  V(_ByteDataView, ., TypedData_ByteDataView_factory, 0x0)                     \
+  V(_Int8ArrayView, ., TypedData_Int8ArrayView_factory, 0x0)                   \
+  V(_Uint8ArrayView, ., TypedData_Uint8ArrayView_factory, 0x0)                 \
+  V(_Uint8ClampedArrayView, ., TypedData_Uint8ClampedArrayView_factory, 0x0)   \
+  V(_Int16ArrayView, ., TypedData_Int16ArrayView_factory, 0x0)                 \
+  V(_Uint16ArrayView, ., TypedData_Uint16ArrayView_factory, 0x0)               \
+  V(_Int32ArrayView, ., TypedData_Int32ArrayView_factory, 0x0)                 \
+  V(_Uint32ArrayView, ., TypedData_Uint32ArrayView_factory, 0x0)               \
+  V(_Int64ArrayView, ., TypedData_Int64ArrayView_factory, 0x0)                 \
+  V(_Uint64ArrayView, ., TypedData_Uint64ArrayView_factory, 0x0)               \
+  V(_Float32ArrayView, ., TypedData_Float32ArrayView_factory, 0x0)             \
+  V(_Float64ArrayView, ., TypedData_Float64ArrayView_factory, 0x0)             \
+  V(_Float32x4ArrayView, ., TypedData_Float32x4ArrayView_factory, 0x0)         \
+  V(_Int32x4ArrayView, ., TypedData_Int32x4ArrayView_factory, 0x0)             \
+  V(_Float64x2ArrayView, ., TypedData_Float64x2ArrayView_factory, 0x0)         \
   V(::, _toClampedUint8, ConvertIntToClampedUint8, 0x564b0435)                 \
   V(_StringBase, _interpolate, StringBaseInterpolate, 0x01ecb15a)              \
   V(_IntegerImplementation, toDouble, IntegerToDouble, 0x05da96ed)             \
@@ -352,6 +373,9 @@
   V(_List, get:length, ObjectArrayLength, 0x25952390)                          \
   V(_ImmutableList, get:length, ImmutableArrayLength, 0x25952390)              \
   V(_TypedList, get:length, TypedDataLength, 0x2091c4d8)                       \
+  V(_TypedListView, get:length, TypedDataViewLength, 0x0)                      \
+  V(_TypedListView, get:offsetInBytes, TypedDataViewOffsetInBytes, 0x0)        \
+  V(_TypedListView, get:_typedData, TypedDataViewTypedData, 0x0)               \
   V(_GrowableList, get:length, GrowableArrayLength, 0x18dd86b4)                \
   V(_GrowableList, get:_capacity, GrowableArrayCapacity, 0x2e04be60)           \
   V(_GrowableList, add, GrowableListAdd, 0x40b490b8)                           \
@@ -390,6 +414,9 @@
   V(_Float32ArrayView, []=, Float32ArrayViewSetIndexed, 0xc9b691bd)            \
   V(_Float64ArrayView, [], Float64ArrayViewGetIndexed, 0x9d83f585)             \
   V(_Float64ArrayView, []=, Float64ArrayViewSetIndexed, 0x3c1adabd)            \
+  V(_ByteDataView, get:length, ByteDataViewLength, 0x0)                        \
+  V(_ByteDataView, get:offsetInBytes, ByteDataViewOffsetInBytes, 0x0)          \
+  V(_ByteDataView, get:_typedData, ByteDataViewTypedData, 0x0)                 \
   V(_ByteDataView, setInt8, ByteDataViewSetInt8, 0x6395293e)                   \
   V(_ByteDataView, setUint8, ByteDataViewSetUint8, 0x79979d1f)                 \
   V(_ByteDataView, setInt16, ByteDataViewSetInt16, 0x525ec534)                 \
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 0939522..0c51e1a 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -3087,19 +3087,19 @@
     }
   }
   if (RawObject::IsTypedDataViewClassId(obj.GetClassId())) {
-    const Instance& view = Instance::Cast(obj);
+    const auto& view = TypedDataView::Cast(obj);
     if (TypedDataView::ElementSizeInBytes(view) == 1) {
-      intptr_t view_length = Smi::Value(TypedDataView::Length(view));
+      const intptr_t view_length = Smi::Value(view.length());
       if (!Utils::RangeCheck(offset, length, view_length)) {
         return Api::NewError(
             "Invalid length passed in to access list elements");
       }
-      const Instance& data = Instance::Handle(TypedDataView::Data(view));
+      const auto& data = Instance::Handle(view.typed_data());
       if (data.IsTypedData()) {
         const TypedData& array = TypedData::Cast(data);
         if (array.ElementSizeInBytes() == 1) {
-          intptr_t data_offset =
-              Smi::Value(TypedDataView::OffsetInBytes(view)) + offset;
+          const intptr_t data_offset =
+              Smi::Value(view.offset_in_bytes()) + offset;
           // Range check already performed on the view object.
           ASSERT(Utils::RangeCheck(data_offset, length, array.Length()));
           return CopyBytes(array, data_offset, native_array, length);
@@ -3389,10 +3389,9 @@
   if (RawObject::IsTypedDataViewClassId(class_id)) {
     // Check if data object of the view is external.
     Zone* zone = thread->zone();
-    const Instance& view_obj = Api::UnwrapInstanceHandle(zone, object);
+    const auto& view_obj = Api::UnwrapTypedDataViewHandle(zone, object);
     ASSERT(!view_obj.IsNull());
-    const Instance& data_obj =
-        Instance::Handle(zone, TypedDataView::Data(view_obj));
+    const auto& data_obj = Instance::Handle(zone, view_obj.typed_data());
     if (ExternalTypedData::IsExternalTypedData(data_obj)) {
       return GetType(class_id);
     }
@@ -3744,15 +3743,15 @@
     data_tmp = obj.DataAddr(0);
   } else {
     ASSERT(RawObject::IsTypedDataViewClassId(class_id));
-    const Instance& view_obj = Api::UnwrapInstanceHandle(Z, object);
+    const auto& view_obj = Api::UnwrapTypedDataViewHandle(Z, object);
     ASSERT(!view_obj.IsNull());
     Smi& val = Smi::Handle();
-    val ^= TypedDataView::Length(view_obj);
+    val ^= view_obj.length();
     length = val.Value();
     size_in_bytes = length * TypedDataView::ElementSizeInBytes(class_id);
-    val ^= TypedDataView::OffsetInBytes(view_obj);
+    val ^= view_obj.offset_in_bytes();
     intptr_t offset_in_bytes = val.Value();
-    const Instance& obj = Instance::Handle(TypedDataView::Data(view_obj));
+    const auto& obj = Instance::Handle(view_obj.typed_data());
     T->IncrementNoSafepointScopeDepth();
     START_NO_CALLBACK_SCOPE(T);
     if (TypedData::IsTypedData(obj)) {
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 6b4b612..88c6c92 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -243,39 +243,6 @@
   return value;
 }
 
-static Dart_TypedData_Type GetTypedDataTypeFromView(
-    Dart_CObject_Internal* object,
-    char* class_name) {
-  struct {
-    const char* name;
-    Dart_TypedData_Type type;
-  } view_class_names[] = {
-      {"_Int8ArrayView", Dart_TypedData_kInt8},
-      {"_Uint8ArrayView", Dart_TypedData_kUint8},
-      {"_Uint8ClampedArrayView", Dart_TypedData_kUint8Clamped},
-      {"_Int16ArrayView", Dart_TypedData_kInt16},
-      {"_Uint16ArrayView", Dart_TypedData_kUint16},
-      {"_Int32ArrayView", Dart_TypedData_kInt32},
-      {"_Uint32ArrayView", Dart_TypedData_kUint32},
-      {"_Int64ArrayView", Dart_TypedData_kInt64},
-      {"_Uint64ArrayView", Dart_TypedData_kUint64},
-      {"_ByteDataView", Dart_TypedData_kUint8},
-      {"_Float32ArrayView", Dart_TypedData_kFloat32},
-      {"_Float64ArrayView", Dart_TypedData_kFloat64},
-      {NULL, Dart_TypedData_kInvalid},
-  };
-
-  int i = 0;
-  while (view_class_names[i].name != NULL) {
-    if (strncmp(view_class_names[i].name, class_name,
-                strlen(view_class_names[i].name)) == 0) {
-      return view_class_names[i].type;
-    }
-    i++;
-  }
-  return Dart_TypedData_kInvalid;
-}
-
 Dart_CObject* ApiMessageReader::ReadInlinedObject(intptr_t object_id) {
   // Read the class header information and lookup the class.
   intptr_t class_header = Read<int32_t>();
@@ -299,46 +266,6 @@
     }
     ASSERT(object->type == static_cast<Dart_CObject_Type>(
                                Dart_CObject_Internal::kUninitialized));
-
-    char* library_uri =
-        object->cls->internal.as_class.library_url->value.as_string;
-    char* class_name =
-        object->cls->internal.as_class.class_name->value.as_string;
-
-    // Handle typed data views.
-    if (strcmp("dart:typed_data", library_uri) == 0) {
-      Dart_TypedData_Type type = GetTypedDataTypeFromView(object, class_name);
-      if (type != Dart_TypedData_kInvalid) {
-        object->type =
-            static_cast<Dart_CObject_Type>(Dart_CObject_Internal::kView);
-        Dart_CObject_Internal* cls =
-            reinterpret_cast<Dart_CObject_Internal*>(ReadObjectImpl());
-        ASSERT(cls == object->cls);
-        object->internal.as_view.buffer = ReadObjectImpl();
-        object->internal.as_view.offset_in_bytes = ReadSmiValue();
-        object->internal.as_view.length = ReadSmiValue();
-
-        // The buffer is fully read now as typed data objects are
-        // serialized in-line.
-        Dart_CObject* buffer = object->internal.as_view.buffer;
-        ASSERT(buffer->type == Dart_CObject_kTypedData);
-
-        // Now turn the view into a byte array.
-        object->type = Dart_CObject_kTypedData;
-        object->value.as_typed_data.type = type;
-        object->value.as_typed_data.length =
-            object->internal.as_view.length * GetTypedDataSizeInBytes(type);
-        object->value.as_typed_data.values =
-            buffer->value.as_typed_data.values +
-            object->internal.as_view.offset_in_bytes;
-      } else {
-        // TODO(sgjesse): Handle other instances. Currently this will
-        // skew the reading as the fields of the instance is not read.
-      }
-    } else {
-      // TODO(sgjesse): Handle other instances. Currently this will
-      // skew the reading as the fields of the instance is not read.
-    }
     return object;
   }
 
@@ -531,7 +458,6 @@
       return value;
     }
     case kTypeParameterCid: {
-      // TODO(sgjesse): Fix this workaround ignoring the type parameter.
       Dart_CObject* value = &dynamic_type_marker;
       AddBackRef(object_id, value, kIsDeserialized);
       intptr_t index = Read<int32_t>();
@@ -657,60 +583,59 @@
     return object;                                                             \
   }
 
-    case kTypedDataInt8ArrayCid:
-      READ_TYPED_DATA(Int8, int8_t);
-    case kExternalTypedDataInt8ArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Int8, int8_t);
+#define READ_TYPED_DATA_VIEW(tname, ctype)                                     \
+  {                                                                            \
+    Dart_CObject_Internal* object =                                            \
+        AllocateDartCObjectInternal(Dart_CObject_Internal::kUninitialized);    \
+    AddBackRef(object_id, object, kIsDeserialized);                            \
+    object->type =                                                             \
+        static_cast<Dart_CObject_Type>(Dart_CObject_Internal::kView);          \
+    object->internal.as_view.offset_in_bytes = ReadSmiValue();                 \
+    object->internal.as_view.length = ReadSmiValue();                          \
+    object->internal.as_view.buffer = ReadObjectImpl();                        \
+    Dart_CObject* buffer = object->internal.as_view.buffer;                    \
+    RELEASE_ASSERT(buffer->type == Dart_CObject_kTypedData);                   \
+                                                                               \
+    /* Now turn the view into a byte array.*/                                  \
+    const Dart_TypedData_Type type = Dart_TypedData_k##tname;                  \
+    object->type = Dart_CObject_kTypedData;                                    \
+    object->value.as_typed_data.type = type;                                   \
+    object->value.as_typed_data.length =                                       \
+        object->internal.as_view.length * GetTypedDataSizeInBytes(type);       \
+    object->value.as_typed_data.values =                                       \
+        buffer->value.as_typed_data.values +                                   \
+        object->internal.as_view.offset_in_bytes;                              \
+    return object;                                                             \
+  }
 
-    case kTypedDataUint8ArrayCid:
-      READ_TYPED_DATA(Uint8, uint8_t);
-    case kExternalTypedDataUint8ArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Uint8, uint8_t);
+#define TYPED_DATA_LIST(V)                                                     \
+  V(Int8, int8_t)                                                              \
+  V(Uint8, uint8_t)                                                            \
+  V(Uint8Clamped, uint8_t)                                                     \
+  V(Int16, int16_t)                                                            \
+  V(Uint16, uint16_t)                                                          \
+  V(Int32, int32_t)                                                            \
+  V(Uint32, uint32_t)                                                          \
+  V(Int64, int64_t)                                                            \
+  V(Uint64, uint64_t)                                                          \
+  V(Float32, float)                                                            \
+  V(Float64, double)
 
-    case kTypedDataUint8ClampedArrayCid:
-      READ_TYPED_DATA(Uint8Clamped, uint8_t);
-    case kExternalTypedDataUint8ClampedArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Uint8Clamped, uint8_t);
+#define EMIT_TYPED_DATA_CASES(type, c_type)                                    \
+  case kTypedData##type##ArrayCid:                                             \
+    READ_TYPED_DATA(type, c_type);                                             \
+  case kExternalTypedData##type##ArrayCid:                                     \
+    READ_EXTERNAL_TYPED_DATA(type, c_type);                                    \
+  case kTypedData##type##ArrayViewCid:                                         \
+    READ_TYPED_DATA_VIEW(type, c_type);
 
-    case kTypedDataInt16ArrayCid:
-      READ_TYPED_DATA(Int16, int16_t);
-    case kExternalTypedDataInt16ArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Int16, int16_t);
-
-    case kTypedDataUint16ArrayCid:
-      READ_TYPED_DATA(Uint16, uint16_t);
-    case kExternalTypedDataUint16ArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Uint16, uint16_t);
-
-    case kTypedDataInt32ArrayCid:
-      READ_TYPED_DATA(Int32, int32_t);
-    case kExternalTypedDataInt32ArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Int32, int32_t);
-
-    case kTypedDataUint32ArrayCid:
-      READ_TYPED_DATA(Uint32, uint32_t);
-    case kExternalTypedDataUint32ArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Uint32, uint32_t);
-
-    case kTypedDataInt64ArrayCid:
-      READ_TYPED_DATA(Int64, int64_t);
-    case kExternalTypedDataInt64ArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Int64, int64_t);
-
-    case kTypedDataUint64ArrayCid:
-      READ_TYPED_DATA(Uint64, uint64_t);
-    case kExternalTypedDataUint64ArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Uint64, uint64_t);
-
-    case kTypedDataFloat32ArrayCid:
-      READ_TYPED_DATA(Float32, float);
-    case kExternalTypedDataFloat32ArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Float32, float);
-
-    case kTypedDataFloat64ArrayCid:
-      READ_TYPED_DATA(Float64, double);
-    case kExternalTypedDataFloat64ArrayCid:
-      READ_EXTERNAL_TYPED_DATA(Float64, double);
+      TYPED_DATA_LIST(EMIT_TYPED_DATA_CASES)
+#undef EMIT_TYPED_DATA_CASES
+#undef TYPED_DATA_LIST
+#undef READ_TYPED_DATA
+#undef READ_EXTERNAL_TYPED_DATA
+#undef READ_TYPED_DATA_VIEW
+#undef READ_TYPED_DATA_HEADER
 
     case kGrowableObjectArrayCid: {
       // A GrowableObjectArray is serialized as its type arguments and
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index 38c2fd7..76ca7b7 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -303,7 +303,11 @@
                        value.ToCString());
         }
       } else {
-        ASSERT(offset.Value() == cls.type_arguments_field_offset());
+        // In addition to the type arguments vector we can also have lazy
+        // materialization of e.g. _ByteDataView objects which don't have
+        // explicit fields in Dart (all accesses to the fields are done via
+        // recognized native methods).
+        ASSERT(offset.Value() < cls.instance_size());
         obj.SetFieldAtOffset(offset.Value(), value);
         if (FLAG_trace_deoptimization_verbose) {
           OS::PrintErr("    null Field @ offset(%" Pd ") <- %s\n",
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 06faf7f..86b63a5 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1642,9 +1642,11 @@
   pending_classes.Add(cls);
 
     CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
+
     cls = Class::NewTypedDataViewClass(kByteDataViewCid);
     RegisterPrivateClass(cls, Symbols::_ByteDataView(), lib);
     pending_classes.Add(cls);
+
 #undef REGISTER_TYPED_DATA_VIEW_CLASS
 #define REGISTER_EXT_TYPED_DATA_CLASS(clazz)                                   \
   cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid);      \
@@ -3709,9 +3711,11 @@
 
 RawClass* Class::NewTypedDataViewClass(intptr_t class_id) {
   ASSERT(RawObject::IsTypedDataViewClassId(class_id));
-  Class& result = Class::Handle(New<Instance>(class_id));
-  result.set_instance_size(0);
-  result.set_next_field_offset(-kWordSize);
+  const intptr_t instance_size = TypedDataView::InstanceSize();
+  Class& result = Class::Handle(New<TypedDataView>(class_id));
+  result.set_instance_size(instance_size);
+  result.set_next_field_offset(TypedDataView::NextFieldOffset());
+  result.set_is_prefinalized();
   return result.raw();
 }
 
@@ -20897,6 +20901,37 @@
   return result.raw();
 }
 
+RawTypedDataView* TypedDataView::New(intptr_t class_id, Heap::Space space) {
+  auto& result = TypedDataView::Handle();
+  {
+    RawObject* raw =
+        Object::Allocate(class_id, TypedDataView::InstanceSize(), space);
+    NoSafepointScope no_safepoint;
+    result ^= raw;
+    result.clear_typed_data();
+    result.set_offset_in_bytes(0);
+    result.set_length(0);
+  }
+  return result.raw();
+}
+
+RawTypedDataView* TypedDataView::New(intptr_t class_id,
+                                     const Instance& typed_data,
+                                     intptr_t offset_in_bytes,
+                                     intptr_t length,
+                                     Heap::Space space) {
+  auto& result = TypedDataView::Handle(TypedDataView::New(class_id, space));
+  result.set_typed_data(typed_data);
+  result.set_offset_in_bytes(offset_in_bytes);
+  result.set_length(length);
+  return result.raw();
+}
+
+const char* TypedDataView::ToCString() const {
+  auto zone = Thread::Current()->zone();
+  return OS::SCreate(zone, "TypedDataView(cid: %" Pd ")", GetClassId());
+}
+
 const char* ExternalTypedData::ToCString() const {
   return "ExternalTypedData";
 }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index da18f6a..044ecc5 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1256,7 +1256,7 @@
   // Allocate the raw TypedData classes.
   static RawClass* NewTypedDataClass(intptr_t class_id);
 
-  // Allocate the raw TypedDataView classes.
+  // Allocate the raw TypedDataView/ByteDataView classes.
   static RawClass* NewTypedDataViewClass(intptr_t class_id);
 
   // Allocate the raw ExternalTypedData classes.
@@ -8466,49 +8466,55 @@
   friend class Class;
 };
 
-class TypedDataView : public AllStatic {
+class TypedDataView : public Instance {
  public:
-  static intptr_t ElementSizeInBytes(const Instance& view_obj) {
+  static RawTypedDataView* New(intptr_t class_id,
+                               Heap::Space space = Heap::kNew);
+  static RawTypedDataView* New(intptr_t class_id,
+                               const Instance& typed_data,
+                               intptr_t offset_in_bytes,
+                               intptr_t length,
+                               Heap::Space space = Heap::kNew);
+
+  static intptr_t InstanceSize() {
+    return RoundedAllocationSize(sizeof(RawTypedDataView));
+  }
+
+  static intptr_t ElementSizeInBytes(const TypedDataView& view_obj) {
     ASSERT(!view_obj.IsNull());
     intptr_t cid = view_obj.raw()->GetClassId();
     return ElementSizeInBytes(cid);
   }
 
-  static RawInstance* Data(const Instance& view_obj) {
-    ASSERT(!view_obj.IsNull());
-    return *reinterpret_cast<RawInstance* const*>(view_obj.raw_ptr() +
-                                                  kDataOffset);
+  static RawInstance* Data(const TypedDataView& view) {
+    return view.typed_data();
   }
 
-  static RawSmi* OffsetInBytes(const Instance& view_obj) {
-    ASSERT(!view_obj.IsNull());
-    return *reinterpret_cast<RawSmi* const*>(view_obj.raw_ptr() +
-                                             kOffsetInBytesOffset);
+  static RawSmi* OffsetInBytes(const TypedDataView& view) {
+    return view.offset_in_bytes();
   }
 
-  static RawSmi* Length(const Instance& view_obj) {
-    ASSERT(!view_obj.IsNull());
-    return *reinterpret_cast<RawSmi* const*>(view_obj.raw_ptr() +
-                                             kLengthOffset);
-  }
+  static RawSmi* Length(const TypedDataView& view) { return view.length(); }
 
-  static bool IsExternalTypedDataView(const Instance& view_obj) {
-    const Instance& data = Instance::Handle(Data(view_obj));
+  static bool IsExternalTypedDataView(const TypedDataView& view_obj) {
+    const auto& data = Instance::Handle(Data(view_obj));
     intptr_t cid = data.raw()->GetClassId();
     ASSERT(RawObject::IsTypedDataClassId(cid) ||
            RawObject::IsExternalTypedDataClassId(cid));
     return RawObject::IsExternalTypedDataClassId(cid);
   }
 
-  static intptr_t NumberOfFields() { return kLengthOffset; }
-
-  static intptr_t data_offset() { return kWordSize * kDataOffset; }
-
-  static intptr_t offset_in_bytes_offset() {
-    return kWordSize * kOffsetInBytesOffset;
+  static intptr_t data_offset() {
+    return OFFSET_OF(RawTypedDataView, typed_data_);
   }
 
-  static intptr_t length_offset() { return kWordSize * kLengthOffset; }
+  static intptr_t length_offset() {
+    return OFFSET_OF(RawTypedDataView, length_);
+  }
+
+  static intptr_t offset_in_bytes_offset() {
+    return OFFSET_OF(RawTypedDataView, offset_in_bytes_);
+  }
 
   static intptr_t ElementSizeInBytes(intptr_t class_id) {
     ASSERT(RawObject::IsTypedDataViewClassId(class_id));
@@ -8517,12 +8523,34 @@
                : TypedData::element_size(class_id - kTypedDataInt8ArrayViewCid);
   }
 
+  RawInstance* typed_data() const { return raw_ptr()->typed_data_; }
+
+  void set_typed_data(const Instance& typed_data) {
+    const classid_t cid = typed_data.GetClassId();
+    ASSERT(RawObject::IsTypedDataClassId(cid) ||
+           RawObject::IsExternalTypedDataClassId(cid));
+    StorePointer(&raw_ptr()->typed_data_, typed_data.raw());
+  }
+
+  void set_length(intptr_t value) {
+    StorePointer(&raw_ptr()->length_, Smi::New(value));
+  }
+
+  void set_offset_in_bytes(intptr_t value) {
+    StorePointer(&raw_ptr()->offset_in_bytes_, Smi::New(value));
+  }
+
+  RawSmi* offset_in_bytes() const { return raw_ptr()->offset_in_bytes_; }
+
+  RawSmi* length() const { return raw_ptr()->length_; }
+
  private:
-  enum {
-    kDataOffset = 1,
-    kOffsetInBytesOffset = 2,
-    kLengthOffset = 3,
-  };
+  void clear_typed_data() {
+    StorePointer(&raw_ptr()->typed_data_, Instance::RawCast(Object::null()));
+  }
+
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(TypedDataView, Instance);
+  friend class Class;
 };
 
 class ByteBuffer : public AllStatic {
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 1562714..8157ccf 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -1389,6 +1389,10 @@
   }
 }
 
+void TypedDataView::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Instance::PrintJSONImpl(stream, ref);
+}
+
 void ExternalTypedData::PrintJSONImpl(JSONStream* stream, bool ref) const {
   JSONObject jsobj(stream);
   PrintSharedInstanceJSON(&jsobj, ref);
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 7735f4d..1e933eb 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -269,22 +269,25 @@
 #undef RAW_VISITPOINTERS
 #define RAW_VISITPOINTERS(clazz) case kExternalTypedData##clazz##Cid:
     CLASS_LIST_TYPED_DATA(RAW_VISITPOINTERS) {
-      RawExternalTypedData* raw_obj =
-          reinterpret_cast<RawExternalTypedData*>(this);
+      auto raw_obj = reinterpret_cast<RawExternalTypedData*>(this);
       size = RawExternalTypedData::VisitExternalTypedDataPointers(raw_obj,
                                                                   visitor);
       break;
     }
 #undef RAW_VISITPOINTERS
-#define RAW_VISITPOINTERS(clazz) case kTypedData##clazz##ViewCid:
-    CLASS_LIST_TYPED_DATA(RAW_VISITPOINTERS)
     case kByteDataViewCid:
+#define RAW_VISITPOINTERS(clazz) case kTypedData##clazz##ViewCid:
+      CLASS_LIST_TYPED_DATA(RAW_VISITPOINTERS) {
+        auto raw_obj = reinterpret_cast<RawTypedDataView*>(this);
+        size = RawTypedDataView::VisitTypedDataViewPointers(raw_obj, visitor);
+        break;
+      }
+#undef RAW_VISITPOINTERS
     case kByteBufferCid: {
       RawInstance* raw_obj = reinterpret_cast<RawInstance*>(this);
       size = RawInstance::VisitInstancePointers(raw_obj, visitor);
       break;
     }
-#undef RAW_VISITPOINTERS
     case kFfiPointerCid: {
       RawPointer* raw_obj = reinterpret_cast<RawPointer*>(this);
       size = RawPointer::VisitPointerPointers(raw_obj, visitor);
@@ -427,6 +430,7 @@
 COMPRESSED_VISITOR(GrowableObjectArray)
 COMPRESSED_VISITOR(LinkedHashMap)
 COMPRESSED_VISITOR(ExternalTypedData)
+REGULAR_VISITOR(TypedDataView)
 REGULAR_VISITOR(ReceivePort)
 REGULAR_VISITOR(StackTrace)
 REGULAR_VISITOR(RegExp)
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 09df2e30..79372ea 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -712,6 +712,7 @@
   friend class RawInstance;
   friend class RawString;
   friend class RawTypedData;
+  friend class RawTypedDataView;
   friend class Scavenger;
   friend class ScavengerVisitor;
   friend class SizeExcludingClassVisitor;  // GetClassId
@@ -2081,6 +2082,25 @@
   friend class String;
 };
 
+// All _*ArrayView/_ByteDataView classes share the same layout.
+class RawTypedDataView : public RawInstance {
+  RAW_HEAP_OBJECT_IMPLEMENTATION(TypedDataView);
+
+ protected:
+  VISIT_FROM(RawObject*, typed_data_)
+  RawInstance* typed_data_;
+  RawSmi* offset_in_bytes_;
+  RawSmi* length_;
+  VISIT_TO(RawObject*, length_)
+
+  friend class Api;
+  friend class Object;
+  friend class ObjectPoolDeserializationCluster;
+  friend class ObjectPoolSerializationCluster;
+  friend class RawObjectPool;
+  friend class SnapshotReader;
+};
+
 class RawExternalOneByteString : public RawString {
   RAW_HEAP_OBJECT_IMPLEMENTATION(ExternalOneByteString);
 
@@ -2639,7 +2659,7 @@
 // is defined by the VM but are used in the VM code by computing the
 // implicit field offsets of the various fields in the dart object.
 inline bool RawObject::IsImplicitFieldClassId(intptr_t index) {
-  return (IsTypedDataViewClassId(index) || index == kByteBufferCid);
+  return index == kByteBufferCid;
 }
 
 inline intptr_t RawObject::NumberOfTypedDataClasses() {
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index f743ea6..58ec79e 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1964,6 +1964,45 @@
       IsolateMessageTypedDataFinalizer);
 }
 
+void RawTypedDataView::WriteTo(SnapshotWriter* writer,
+                               intptr_t object_id,
+                               Snapshot::Kind kind,
+                               bool as_reference) {
+  // Write out the serialization header value for this object.
+  writer->WriteInlinedObjectHeader(object_id);
+
+  // Write out the class and tags information.
+  writer->WriteIndexedObject(GetClassId());
+  writer->WriteTags(writer->GetObjectTags(this));
+
+  // Write members.
+  writer->Write<RawObject*>(ptr()->offset_in_bytes_);
+  writer->Write<RawObject*>(ptr()->length_);
+  writer->WriteObjectImpl(ptr()->typed_data_, as_reference);
+}
+
+RawTypedDataView* TypedDataView::ReadFrom(SnapshotReader* reader,
+                                          intptr_t object_id,
+                                          intptr_t tags,
+                                          Snapshot::Kind kind,
+                                          bool as_reference) {
+  auto& typed_data = *reader->InstanceHandle();
+  const classid_t cid = RawObject::ClassIdTag::decode(tags);
+
+  auto& view = *reader->TypedDataViewHandle();
+  view = TypedDataView::New(cid);
+  reader->AddBackRef(object_id, &view, kIsDeserialized);
+
+  const intptr_t offset_in_bytes = reader->ReadSmiValue();
+  const intptr_t length = reader->ReadSmiValue();
+  typed_data ^= reader->ReadObjectImpl(as_reference);
+  view.set_offset_in_bytes(offset_in_bytes);
+  view.set_length(length);
+  view.set_typed_data(typed_data);
+
+  return view.raw();
+}
+
 RawPointer* Pointer::ReadFrom(SnapshotReader* reader,
                               intptr_t object_id,
                               intptr_t tags,
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 0b9df59..58b38e3 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -37,15 +37,15 @@
           (class_id >= kNullCid && class_id <= kVoidCid));
 }
 
-static bool IsObjectStoreClassId(intptr_t class_id) {
-  // Check if this is a class which is stored in the object store.
+static bool IsBootstrapedClassId(intptr_t class_id) {
+  // Check if this is a class which is created during bootstrapping.
   return (class_id == kObjectCid ||
           (class_id >= kInstanceCid && class_id <= kUserTagCid) ||
           class_id == kArrayCid || class_id == kImmutableArrayCid ||
           RawObject::IsStringClassId(class_id) ||
           RawObject::IsTypedDataClassId(class_id) ||
           RawObject::IsExternalTypedDataClassId(class_id) ||
-          class_id == kNullCid);
+          RawObject::IsTypedDataViewClassId(class_id) || class_id == kNullCid);
 }
 
 static bool IsObjectStoreTypeId(intptr_t index) {
@@ -70,7 +70,6 @@
 
 static intptr_t ObjectIdFromClassId(intptr_t class_id) {
   ASSERT((class_id > kIllegalCid) && (class_id < kNumPredefinedCids));
-  ASSERT(!(RawObject::IsImplicitFieldClassId(class_id)));
   return (class_id + kClassIdsOffset);
 }
 
@@ -209,6 +208,7 @@
       old_space_(thread_->isolate()->heap()->old_space()),
       cls_(Class::Handle(zone_)),
       code_(Code::Handle(zone_)),
+      instance_(Instance::Handle(zone_)),
       instructions_(Instructions::Handle(zone_)),
       obj_(Object::Handle(zone_)),
       pobj_(PassiveObject::Handle(zone_)),
@@ -221,6 +221,7 @@
       tokens_(GrowableObjectArray::Handle(zone_)),
       data_(ExternalTypedData::Handle(zone_)),
       typed_data_(TypedData::Handle(zone_)),
+      typed_data_view_(TypedDataView::Handle(zone_)),
       function_(Function::Handle(zone_)),
       error_(UnhandledException::Handle(zone_)),
       set_class_(Class::ZoneHandle(
@@ -315,7 +316,7 @@
   ASSERT(!IsVMIsolateObject(class_header) ||
          !IsSingletonClassId(GetVMIsolateObjectId(class_header)));
   ASSERT((SerializedHeaderTag::decode(class_header) != kObjectId) ||
-         !IsObjectStoreClassId(SerializedHeaderData::decode(class_header)));
+         !IsBootstrapedClassId(SerializedHeaderData::decode(class_header)));
   Class& cls = Class::ZoneHandle(zone(), Class::null());
   AddBackRef(object_id, &cls, kIsDeserialized);
   // Read the library/class information and lookup the class.
@@ -479,6 +480,15 @@
       break;
     }
 #undef SNAPSHOT_READ
+#define SNAPSHOT_READ(clazz) case kTypedData##clazz##ViewCid:
+
+    case kByteDataViewCid:
+      CLASS_LIST_TYPED_DATA(SNAPSHOT_READ) {
+        tags = RawObject::ClassIdTag::update(class_id, tags);
+        pobj_ = TypedDataView::ReadFrom(this, object_id, tags, kind_, true);
+        break;
+      }
+#undef SNAPSHOT_READ
 #define SNAPSHOT_READ(clazz) case kFfi##clazz##Cid:
 
     CLASS_LIST_FFI(SNAPSHOT_READ) { UNREACHABLE(); }
@@ -688,7 +698,7 @@
   }
   ASSERT(SerializedHeaderTag::decode(class_header) == kObjectId);
   intptr_t class_id = SerializedHeaderData::decode(class_header);
-  ASSERT(IsObjectStoreClassId(class_id) || IsSingletonClassId(class_id));
+  ASSERT(IsBootstrapedClassId(class_id) || IsSingletonClassId(class_id));
   return class_id;
 }
 
@@ -758,7 +768,7 @@
 
 RawObject* SnapshotReader::ReadIndexedObject(intptr_t object_id) {
   intptr_t class_id = ClassIdFromObjectId(object_id);
-  if (IsObjectStoreClassId(class_id)) {
+  if (IsBootstrapedClassId(class_id)) {
     return isolate()->class_table()->At(class_id);  // get singleton class.
   }
   if (IsObjectStoreTypeId(object_id)) {
@@ -1025,7 +1035,7 @@
   if (cid == kClassCid) {
     RawClass* raw_class = reinterpret_cast<RawClass*>(rawobj);
     intptr_t class_id = raw_class->ptr()->id_;
-    if (IsObjectStoreClassId(class_id)) {
+    if (IsBootstrapedClassId(class_id)) {
       intptr_t object_id = ObjectIdFromClassId(class_id);
       WriteIndexedObject(object_id);
       return true;
@@ -1110,6 +1120,16 @@
       return;
     }
 #undef SNAPSHOT_WRITE
+#define SNAPSHOT_WRITE(clazz) case kTypedData##clazz##ViewCid:
+
+    case kByteDataViewCid:
+      CLASS_LIST_TYPED_DATA(SNAPSHOT_WRITE) {
+        auto* raw_obj = reinterpret_cast<RawTypedDataView*>(raw);
+        raw_obj->WriteTo(this, object_id, kind_, as_reference);
+        return;
+      }
+#undef SNAPSHOT_WRITE
+
 #define SNAPSHOT_WRITE(clazz) case kFfi##clazz##Cid:
 
     CLASS_LIST_FFI(SNAPSHOT_WRITE) { UNREACHABLE(); }
@@ -1171,7 +1191,7 @@
 void SnapshotWriter::WriteClassId(RawClass* cls) {
   ASSERT(!Snapshot::IsFull(kind_));
   int class_id = cls->ptr()->id_;
-  ASSERT(!IsSingletonClassId(class_id) && !IsObjectStoreClassId(class_id));
+  ASSERT(!IsSingletonClassId(class_id) && !IsBootstrapedClassId(class_id));
 
   // Write out the library url and class name.
   RawLibrary* library = cls->ptr()->library_;
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 5a4ab63..248127c 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -28,6 +28,7 @@
 class ExternalTypedData;
 class GrowableObjectArray;
 class Heap;
+class Instance;
 class Instructions;
 class LanguageError;
 class Library;
@@ -37,6 +38,7 @@
 class ObjectStore;
 class MegamorphicCache;
 class PageSpace;
+class TypedDataView;
 class RawApiError;
 class RawArray;
 class RawCapability;
@@ -86,6 +88,7 @@
 class RawType;
 class RawTypeArguments;
 class RawTypedData;
+class RawTypedDataView;
 class RawTypeParameter;
 class RawTypeRef;
 class RawUnhandledException;
@@ -98,8 +101,8 @@
 // Serialized object header encoding is as follows:
 // - Smi: the Smi value is written as is (last bit is not tagged).
 // - VM object (from VM isolate): (object id in vm isolate | 0x3)
-//   This valus is serialized as a negative number.
-//   (note VM objects are never serialized they are expected to be found
+//   This value is serialized as a negative number.
+//   (note VM objects are never serialized, they are expected to be found
 //    using ths unique ID assigned to them).
 // - Reference to object that has already been written: (object id | 0x3)
 //   This valus is serialized as a positive number.
@@ -300,6 +303,7 @@
   Array* ArrayHandle() { return &array_; }
   Class* ClassHandle() { return &cls_; }
   Code* CodeHandle() { return &code_; }
+  Instance* InstanceHandle() { return &instance_; }
   Instructions* InstructionsHandle() { return &instructions_; }
   String* StringHandle() { return &str_; }
   AbstractType* TypeHandle() { return &type_; }
@@ -307,6 +311,7 @@
   GrowableObjectArray* TokensHandle() { return &tokens_; }
   ExternalTypedData* DataHandle() { return &data_; }
   TypedData* TypedDataHandle() { return &typed_data_; }
+  TypedDataView* TypedDataViewHandle() { return &typed_data_view_; }
   Function* FunctionHandle() { return &function_; }
   Snapshot::Kind kind() const { return kind_; }
 
@@ -386,6 +391,7 @@
   PageSpace* old_space_;           // Old space of the current isolate.
   Class& cls_;                     // Temporary Class handle.
   Code& code_;                     // Temporary Code handle.
+  Instance& instance_;             // Temporary Instance handle
   Instructions& instructions_;     // Temporary Instructions handle
   Object& obj_;                    // Temporary Object handle.
   PassiveObject& pobj_;            // Temporary PassiveObject handle.
@@ -398,6 +404,7 @@
   GrowableObjectArray& tokens_;    // Temporary tokens handle.
   ExternalTypedData& data_;        // Temporary stream data handle.
   TypedData& typed_data_;          // Temporary typed data handle.
+  TypedDataView& typed_data_view_;  // Temporary typed data view handle.
   Function& function_;             // Temporary function handle.
   UnhandledException& error_;      // Error handle.
   const Class& set_class_;         // The LinkedHashSet class.
@@ -433,6 +440,7 @@
   friend class SignatureData;
   friend class SubtypeTestCache;
   friend class Type;
+  friend class TypedDataView;
   friend class TypeArguments;
   friend class TypeParameter;
   friend class TypeRef;
@@ -705,6 +713,7 @@
   friend class RawStackTrace;
   friend class RawSubtypeTestCache;
   friend class RawType;
+  friend class RawTypedDataView;
   friend class RawTypeRef;
   friend class RawTypeArguments;
   friend class RawTypeParameter;