diff --git a/runtime/lib/typeddata.cc b/runtime/lib/typeddata.cc index 29e7af3d0c7..4a47d7123d6 100644 --- a/runtime/lib/typeddata.cc +++ b/runtime/lib/typeddata.cc @@ -78,25 +78,32 @@ DEFINE_NATIVE_ENTRY(TypedData_length, 1) { return Integer::null(); } - -#define COPY_DATA(type, dst, src) \ - const type& dst_array = type::Cast(dst); \ - const type& src_array = type::Cast(src); \ - intptr_t element_size_in_bytes = dst_array.ElementSizeInBytes(); \ - intptr_t length_in_bytes = length.Value() * element_size_in_bytes; \ - intptr_t src_offset_in_bytes = src_start.Value() * element_size_in_bytes; \ - intptr_t dst_offset_in_bytes = dst_start.Value() * element_size_in_bytes; \ - SetRangeCheck(src_offset_in_bytes, \ - length_in_bytes, \ - src_array.LengthInBytes(), \ - element_size_in_bytes); \ - SetRangeCheck(dst_offset_in_bytes, \ - length_in_bytes, \ - dst_array.LengthInBytes(), \ - element_size_in_bytes); \ - type::Copy(dst_array, dst_offset_in_bytes, \ - src_array, src_offset_in_bytes, \ - length_in_bytes); +template +static RawBool* CopyData(const Instance& dst, const Instance& src, + const Smi& dst_start, const Smi& src_start, + const Smi& length) { + const DstType& dst_array = DstType::Cast(dst); + const SrcType& src_array = SrcType::Cast(src); + intptr_t element_size_in_bytes = dst_array.ElementSizeInBytes(); + intptr_t dst_offset_in_bytes = dst_start.Value() * element_size_in_bytes; + intptr_t src_offset_in_bytes = src_start.Value() * element_size_in_bytes; + intptr_t length_in_bytes = length.Value() * element_size_in_bytes; + if (dst_array.ElementType() != src_array.ElementType()) { + return Bool::False().raw(); + } + SetRangeCheck(src_offset_in_bytes, + length_in_bytes, + src_array.LengthInBytes(), + element_size_in_bytes); + SetRangeCheck(dst_offset_in_bytes, + length_in_bytes, + dst_array.LengthInBytes(), + element_size_in_bytes); + TypedData::Copy(dst_array, dst_offset_in_bytes, + src_array, src_offset_in_bytes, + length_in_bytes); + return Bool::True().raw(); +} DEFINE_NATIVE_ENTRY(TypedData_setRange, 5) { GET_NON_NULL_NATIVE_ARGUMENT(Instance, dst, arguments->NativeArgAt(0)); @@ -112,17 +119,22 @@ DEFINE_NATIVE_ENTRY(TypedData_setRange, 5) { args.SetAt(0, error); Exceptions::ThrowByType(Exceptions::kArgument, args); } - if ((dst.IsTypedData() || dst.IsExternalTypedData()) && - (dst.clazz() == src.clazz())) { - if (dst.IsTypedData()) { - ASSERT(src.IsTypedData()); - COPY_DATA(TypedData, dst, src); - } else { - ASSERT(src.IsExternalTypedData()); - ASSERT(dst.IsExternalTypedData()); - COPY_DATA(ExternalTypedData, dst, src); + if (dst.IsTypedData()) { + if (src.IsTypedData()) { + return CopyData( + dst, src, dst_start, src_start, length); + } else if (src.IsExternalTypedData()) { + return CopyData( + dst, src, dst_start, src_start, length); + } + } else if (dst.IsExternalTypedData()) { + if (src.IsTypedData()) { + return CopyData( + dst, src, dst_start, src_start, length); + } else if (src.IsExternalTypedData()) { + return CopyData( + dst, src, dst_start, src_start, length); } - return Bool::True().raw(); } return Bool::False().raw(); } diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 3cf6c2d6a15..450ba1c0b4d 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -12689,28 +12689,6 @@ const intptr_t TypedData::element_size[] = { }; -void TypedData::Copy(const TypedData& dst, - intptr_t dst_offset_in_bytes, - const TypedData& src, - intptr_t src_offset_in_bytes, - intptr_t length_in_bytes) { - ASSERT(Utils::RangeCheck(src_offset_in_bytes, - length_in_bytes, - src.LengthInBytes())); - ASSERT(Utils::RangeCheck(dst_offset_in_bytes, - length_in_bytes, - dst.LengthInBytes())); - { - NoGCScope no_gc; - if (length_in_bytes > 0) { - memmove(dst.DataAddr(dst_offset_in_bytes), - src.DataAddr(src_offset_in_bytes), - length_in_bytes); - } - } -} - - RawTypedData* TypedData::New(intptr_t class_id, intptr_t len, Heap::Space space) { @@ -12748,28 +12726,6 @@ FinalizablePersistentHandle* ExternalTypedData::AddFinalizer( } -void ExternalTypedData::Copy(const ExternalTypedData& dst, - intptr_t dst_offset_in_bytes, - const ExternalTypedData& src, - intptr_t src_offset_in_bytes, - intptr_t length_in_bytes) { - ASSERT(Utils::RangeCheck(src_offset_in_bytes, - length_in_bytes, - src.LengthInBytes())); - ASSERT(Utils::RangeCheck(dst_offset_in_bytes, - length_in_bytes, - dst.LengthInBytes())); - { - NoGCScope no_gc; - if (length_in_bytes > 0) { - memmove(dst.DataAddr(dst_offset_in_bytes), - src.DataAddr(src_offset_in_bytes), - length_in_bytes); - } - } -} - - RawExternalTypedData* ExternalTypedData::New(intptr_t class_id, uint8_t* data, intptr_t len, diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 94af3a03623..c59095dfd2b 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -5043,6 +5043,12 @@ class TypedData : public Instance { return ElementSizeInBytes(cid); } + + TypeDataElementType ElementType() const { + intptr_t cid = raw()->GetClassId(); + return ElementType(cid); + } + intptr_t LengthInBytes() const { intptr_t cid = raw()->GetClassId(); return (ElementSizeInBytes(cid) * Length()); @@ -5092,7 +5098,13 @@ class TypedData : public Instance { static intptr_t ElementSizeInBytes(intptr_t class_id) { ASSERT(RawObject::IsTypedDataClassId(class_id)); - return element_size[class_id - kTypedDataInt8ArrayCid]; + return element_size[ElementType(class_id)]; + } + + static TypeDataElementType ElementType(intptr_t class_id) { + ASSERT(RawObject::IsTypedDataClassId(class_id)); + return static_cast( + class_id - kTypedDataInt8ArrayCid); } static intptr_t MaxElements(intptr_t class_id) { @@ -5104,11 +5116,26 @@ class TypedData : public Instance { intptr_t len, Heap::Space space = Heap::kNew); - static void Copy(const TypedData& dst, - intptr_t dst_offset_in_bytes, - const TypedData& src, - intptr_t src_offset_in_bytes, - intptr_t length_in_bytes); + template + static void Copy(const DstType& dst, intptr_t dst_offset_in_bytes, + const SrcType& src, intptr_t src_offset_in_bytes, + intptr_t length_in_bytes) { + ASSERT(dst.ElementType() == src.ElementType()); + ASSERT(Utils::RangeCheck(src_offset_in_bytes, + length_in_bytes, + src.LengthInBytes())); + ASSERT(Utils::RangeCheck(dst_offset_in_bytes, + length_in_bytes, + dst.LengthInBytes())); + { + NoGCScope no_gc; + if (length_in_bytes > 0) { + memmove(dst.DataAddr(dst_offset_in_bytes), + src.DataAddr(src_offset_in_bytes), + length_in_bytes); + } + } + } static bool IsTypedData(const Instance& obj) { ASSERT(!obj.IsNull()); @@ -5143,6 +5170,11 @@ class ExternalTypedData : public Instance { return ElementSizeInBytes(cid); } + TypeDataElementType ElementType() const { + intptr_t cid = raw()->GetClassId(); + return ElementType(cid); + } + intptr_t LengthInBytes() const { intptr_t cid = raw()->GetClassId(); return (ElementSizeInBytes(cid) * Length()); @@ -5193,7 +5225,13 @@ class ExternalTypedData : public Instance { static intptr_t ElementSizeInBytes(intptr_t class_id) { ASSERT(RawObject::IsExternalTypedDataClassId(class_id)); - return TypedData::element_size[class_id - kExternalTypedDataInt8ArrayCid]; + return TypedData::element_size[ElementType(class_id)]; + } + + static TypeDataElementType ElementType(intptr_t class_id) { + ASSERT(RawObject::IsExternalTypedDataClassId(class_id)); + return static_cast( + class_id - kExternalTypedDataInt8ArrayCid); } static intptr_t MaxElements(intptr_t class_id) { @@ -5206,12 +5244,6 @@ class ExternalTypedData : public Instance { intptr_t len, Heap::Space space = Heap::kNew); - static void Copy(const ExternalTypedData& dst, - intptr_t dst_offset_in_bytes, - const ExternalTypedData& src, - intptr_t src_offset_in_bytes, - intptr_t length_in_bytes); - static bool IsExternalTypedData(const Instance& obj) { ASSERT(!obj.IsNull()); intptr_t cid = obj.raw()->GetClassId(); diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 59fb1ec744f..25e644ce03c 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -172,6 +172,12 @@ enum { kSmiTagShift = 1, }; +enum TypeDataElementType { +#define V(name) k##name##Element, +CLASS_LIST_TYPED_DATA(V) +#undef V +}; + #define SNAPSHOT_WRITER_SUPPORT() \ void WriteTo( \ SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind); \