From e2216f61bfdb2ee6d843e4ff283fdfd63431571b Mon Sep 17 00:00:00 2001 From: "kustermann@google.com" Date: Mon, 22 Apr 2013 08:27:15 +0000 Subject: [PATCH] Fast copy between TypedData and ExternalTypedData Until now, copying data from TypedData to TypedData and from ExternalTypedData to ExternalTypedData was fast. But copying between TypedData and ExternalTypedData was not handled in a fast way. Review URL: https://codereview.chromium.org//14296006 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@21791 260f80e4-7a28-3924-810f-c04153c831b5 --- runtime/lib/typeddata.cc | 70 +++++++++++++++++++++++----------------- runtime/vm/object.cc | 44 ------------------------- runtime/vm/object.h | 58 +++++++++++++++++++++++++-------- runtime/vm/raw_object.h | 6 ++++ 4 files changed, 92 insertions(+), 86 deletions(-) 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); \