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