mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 16:41:07 +00:00
[vm] Make use of the new TypedDataBase to avoid redundant code in the runtime.
Reduces VM code size by about 18k. TEST=ci Change-Id: Ic0dbdb6a7807a0f0d37333c6f32bed5cb3e7b905 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/202543 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
3ff71e0a47
commit
84e6d4a4e8
|
@ -27,8 +27,8 @@ static method main() → dynamic {
|
|||
} =>#t1;
|
||||
final typ::Uint8List* buffer = [@vm.direct-call.metadata=protobuf::GeneratedMessage.writeToBuffer] [@vm.inferred-type.metadata=dart.typed_data::_Uint8List (skip check)] foo.{pro::GeneratedMessage::writeToBuffer}(){() →* typ::Uint8List*};
|
||||
core::print("List<int> buffer = <int>[");
|
||||
for (core::int* i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation.<] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i.{core::num::<}([@vm.direct-call.metadata=dart.typed_data::_TypedList.length] [@vm.inferred-type.metadata=dart.core::_Smi] buffer.{core::List::length}{core::int*}){(core::num*) →* core::bool*}; i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(5){(core::num*) →* core::int*}) {
|
||||
final core::String* numbers = [@vm.direct-call.metadata=dart.typed_data::_TypedListBase.join] [@vm.inferred-type.metadata=!? (skip check)] [@vm.direct-call.metadata=dart.typed_data::__Uint8List&_TypedList&_IntListMixin&_TypedIntListMixin.sublist] [@vm.inferred-type.metadata=dart.typed_data::_Uint8List (skip check)] buffer.{typ::Uint8List::sublist}(i, [@vm.inferred-type.metadata=int] math::min<core::int*>([@vm.direct-call.metadata=dart.typed_data::_TypedList.length] [@vm.inferred-type.metadata=dart.core::_Smi] buffer.{core::List::length}{core::int*}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(5){(core::num*) →* core::int*})){(core::int*, [core::int*]) →* typ::Uint8List*}.{core::Iterable::join}(", "){([core::String*]) →* core::String*};
|
||||
for (core::int* i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation.<] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i.{core::num::<}([@vm.direct-call.metadata=dart.typed_data::_TypedListBase.length] [@vm.inferred-type.metadata=dart.core::_Smi] buffer.{core::List::length}{core::int*}){(core::num*) →* core::bool*}; i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(5){(core::num*) →* core::int*}) {
|
||||
final core::String* numbers = [@vm.direct-call.metadata=dart.typed_data::_TypedListBase.join] [@vm.inferred-type.metadata=!? (skip check)] [@vm.direct-call.metadata=dart.typed_data::__Uint8List&_TypedList&_IntListMixin&_TypedIntListMixin.sublist] [@vm.inferred-type.metadata=dart.typed_data::_Uint8List (skip check)] buffer.{typ::Uint8List::sublist}(i, [@vm.inferred-type.metadata=int] math::min<core::int*>([@vm.direct-call.metadata=dart.typed_data::_TypedListBase.length] [@vm.inferred-type.metadata=dart.core::_Smi] buffer.{core::List::length}{core::int*}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(5){(core::num*) →* core::int*})){(core::int*, [core::int*]) →* typ::Uint8List*}.{core::Iterable::join}(", "){([core::String*]) →* core::String*};
|
||||
core::print(" ${numbers},${[@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i =={core::num::==}{(core::Object*) →* core::bool*} 0 ?{core::String*} " //" : ""}");
|
||||
}
|
||||
core::print("];");
|
||||
|
|
|
@ -322,57 +322,28 @@ DEFINE_NATIVE_ENTRY(OneByteString_allocateFromOneByteList, 0, 3) {
|
|||
intptr_t start = start_obj.Value();
|
||||
intptr_t end = end_obj.Value();
|
||||
if (start < 0) {
|
||||
const Array& args = Array::Handle(Array::New(1));
|
||||
args.SetAt(0, start_obj);
|
||||
Exceptions::ThrowByType(Exceptions::kArgument, args);
|
||||
Exceptions::ThrowArgumentError(start_obj);
|
||||
}
|
||||
intptr_t length = end - start;
|
||||
if (length < 0) {
|
||||
const Array& args = Array::Handle(Array::New(1));
|
||||
args.SetAt(0, end_obj);
|
||||
Exceptions::ThrowByType(Exceptions::kArgument, args);
|
||||
Exceptions::ThrowArgumentError(end_obj);
|
||||
}
|
||||
ASSERT(length >= 0);
|
||||
|
||||
Heap::Space space = Heap::kNew;
|
||||
if (list.IsTypedData()) {
|
||||
const TypedData& array = TypedData::Cast(list);
|
||||
if (end > array.LengthInBytes()) {
|
||||
const Array& args = Array::Handle(Array::New(1));
|
||||
args.SetAt(0, end_obj);
|
||||
Exceptions::ThrowByType(Exceptions::kArgument, args);
|
||||
if (list.IsTypedDataBase()) {
|
||||
const TypedDataBase& array = TypedDataBase::Cast(list);
|
||||
if (array.ElementType() != kUint8ArrayElement) {
|
||||
Exceptions::ThrowArgumentError(list);
|
||||
}
|
||||
if (end > array.Length()) {
|
||||
Exceptions::ThrowArgumentError(end_obj);
|
||||
}
|
||||
return OneByteString::New(array, start, length, space);
|
||||
} else if (list.IsExternalTypedData()) {
|
||||
const ExternalTypedData& array = ExternalTypedData::Cast(list);
|
||||
if (end > array.LengthInBytes()) {
|
||||
const Array& args = Array::Handle(Array::New(1));
|
||||
args.SetAt(0, end_obj);
|
||||
Exceptions::ThrowByType(Exceptions::kArgument, args);
|
||||
}
|
||||
return OneByteString::New(array, start, length, space);
|
||||
} 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(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);
|
||||
} else if (data_obj.IsExternalTypedData()) {
|
||||
const ExternalTypedData& array = ExternalTypedData::Cast(data_obj);
|
||||
return OneByteString::New(array, data_offset + start, length, space);
|
||||
}
|
||||
} else if (list.IsArray()) {
|
||||
const Array& array = Array::Cast(list);
|
||||
if (end > array.Length()) {
|
||||
const Array& args = Array::Handle(Array::New(1));
|
||||
args.SetAt(0, end_obj);
|
||||
Exceptions::ThrowByType(Exceptions::kArgument, args);
|
||||
Exceptions::ThrowArgumentError(end_obj);
|
||||
}
|
||||
String& string = String::Handle(OneByteString::New(length, space));
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
@ -383,9 +354,7 @@ DEFINE_NATIVE_ENTRY(OneByteString_allocateFromOneByteList, 0, 3) {
|
|||
} else if (list.IsGrowableObjectArray()) {
|
||||
const GrowableObjectArray& array = GrowableObjectArray::Cast(list);
|
||||
if (end > array.Length()) {
|
||||
const Array& args = Array::Handle(Array::New(1));
|
||||
args.SetAt(0, end_obj);
|
||||
Exceptions::ThrowByType(Exceptions::kArgument, args);
|
||||
Exceptions::ThrowArgumentError(end_obj);
|
||||
}
|
||||
String& string = String::Handle(OneByteString::New(length, space));
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
@ -434,8 +403,8 @@ DEFINE_NATIVE_ENTRY(TwoByteString_allocateFromTwoByteList, 0, 3) {
|
|||
}
|
||||
|
||||
Heap::Space space = Heap::kNew;
|
||||
if (list.IsTypedData()) {
|
||||
const TypedData& array = TypedData::Cast(list);
|
||||
if (list.IsTypedDataBase()) {
|
||||
const TypedDataBase& array = TypedDataBase::Cast(list);
|
||||
if (array.ElementType() != kUint16ArrayElement) {
|
||||
Exceptions::ThrowArgumentError(list);
|
||||
}
|
||||
|
@ -443,35 +412,6 @@ DEFINE_NATIVE_ENTRY(TwoByteString_allocateFromTwoByteList, 0, 3) {
|
|||
Exceptions::ThrowArgumentError(end_obj);
|
||||
}
|
||||
return TwoByteString::New(array, start * sizeof(uint16_t), length, space);
|
||||
} else if (list.IsExternalTypedData()) {
|
||||
const ExternalTypedData& array = ExternalTypedData::Cast(list);
|
||||
if (array.ElementType() != kUint16ArrayElement) {
|
||||
Exceptions::ThrowArgumentError(list);
|
||||
}
|
||||
if (end > array.Length()) {
|
||||
Exceptions::ThrowArgumentError(end_obj);
|
||||
}
|
||||
return TwoByteString::New(array, start * sizeof(uint16_t), length, space);
|
||||
} else if (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(view.length())) {
|
||||
Exceptions::ThrowArgumentError(end_obj);
|
||||
}
|
||||
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),
|
||||
length, space);
|
||||
} else if (data_obj.IsExternalTypedData()) {
|
||||
const ExternalTypedData& array = ExternalTypedData::Cast(data_obj);
|
||||
return TwoByteString::New(array, data_offset + start * sizeof(uint16_t),
|
||||
length, space);
|
||||
}
|
||||
} else if (list.IsArray()) {
|
||||
const Array& array = Array::Cast(list);
|
||||
if (end > array.Length()) {
|
||||
|
|
|
@ -47,20 +47,9 @@ static void LengthCheck(intptr_t len, intptr_t max) {
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(TypedData_length, 0, 1) {
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
|
||||
if (instance.IsTypedData()) {
|
||||
const TypedData& array = TypedData::Cast(instance);
|
||||
return Smi::New(array.Length());
|
||||
}
|
||||
if (instance.IsExternalTypedData()) {
|
||||
const ExternalTypedData& array = ExternalTypedData::Cast(instance);
|
||||
return Smi::New(array.Length());
|
||||
}
|
||||
const String& error = String::Handle(String::NewFormatted(
|
||||
"Expected a TypedData object but found %s", instance.ToCString()));
|
||||
Exceptions::ThrowArgumentError(error);
|
||||
return Integer::null();
|
||||
DEFINE_NATIVE_ENTRY(TypedDataBase_length, 0, 1) {
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, array, arguments->NativeArgAt(0));
|
||||
return Smi::New(array.Length());
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(TypedDataView_offsetInBytes, 0, 1) {
|
||||
|
@ -70,13 +59,6 @@ DEFINE_NATIVE_ENTRY(TypedDataView_offsetInBytes, 0, 1) {
|
|||
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));
|
||||
|
@ -84,15 +66,12 @@ DEFINE_NATIVE_ENTRY(TypedDataView_typedData, 0, 1) {
|
|||
return TypedDataView::Cast(instance).typed_data();
|
||||
}
|
||||
|
||||
template <typename DstType, typename SrcType>
|
||||
static BoolPtr CopyData(const Instance& dst,
|
||||
const Instance& src,
|
||||
static BoolPtr CopyData(const TypedDataBase& dst_array,
|
||||
const TypedDataBase& src_array,
|
||||
const Smi& dst_start,
|
||||
const Smi& src_start,
|
||||
const Smi& length,
|
||||
bool clamped) {
|
||||
const DstType& dst_array = DstType::Cast(dst);
|
||||
const SrcType& src_array = SrcType::Cast(src);
|
||||
const intptr_t dst_offset_in_bytes = dst_start.Value();
|
||||
const intptr_t src_offset_in_bytes = src_start.Value();
|
||||
const intptr_t length_in_bytes = length.Value();
|
||||
|
@ -101,12 +80,11 @@ static BoolPtr CopyData(const Instance& dst,
|
|||
ASSERT(Utils::RangeCheck(dst_offset_in_bytes, length_in_bytes,
|
||||
dst_array.LengthInBytes()));
|
||||
if (clamped) {
|
||||
TypedData::ClampedCopy<DstType, SrcType>(dst_array, dst_offset_in_bytes,
|
||||
src_array, src_offset_in_bytes,
|
||||
length_in_bytes);
|
||||
TypedData::ClampedCopy(dst_array, dst_offset_in_bytes, src_array,
|
||||
src_offset_in_bytes, length_in_bytes);
|
||||
} else {
|
||||
TypedData::Copy<DstType, SrcType>(dst_array, dst_offset_in_bytes, src_array,
|
||||
src_offset_in_bytes, length_in_bytes);
|
||||
TypedData::Copy(dst_array, dst_offset_in_bytes, src_array,
|
||||
src_offset_in_bytes, length_in_bytes);
|
||||
}
|
||||
return Bool::True().ptr();
|
||||
}
|
||||
|
@ -136,13 +114,13 @@ static bool IsUint8(intptr_t cid) {
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(TypedData_setRange, 0, 7) {
|
||||
const Instance& dst =
|
||||
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
|
||||
DEFINE_NATIVE_ENTRY(TypedDataBase_setRange, 0, 7) {
|
||||
const TypedDataBase& dst =
|
||||
TypedDataBase::CheckedHandle(zone, arguments->NativeArgAt(0));
|
||||
const Smi& dst_start = Smi::CheckedHandle(zone, arguments->NativeArgAt(1));
|
||||
const Smi& length = Smi::CheckedHandle(zone, arguments->NativeArgAt(2));
|
||||
const Instance& src =
|
||||
Instance::CheckedHandle(zone, arguments->NativeArgAt(3));
|
||||
const TypedDataBase& src =
|
||||
TypedDataBase::CheckedHandle(zone, arguments->NativeArgAt(3));
|
||||
const Smi& src_start = Smi::CheckedHandle(zone, arguments->NativeArgAt(4));
|
||||
const Smi& to_cid_smi = Smi::CheckedHandle(zone, arguments->NativeArgAt(5));
|
||||
const Smi& from_cid_smi = Smi::CheckedHandle(zone, arguments->NativeArgAt(6));
|
||||
|
@ -156,25 +134,7 @@ DEFINE_NATIVE_ENTRY(TypedData_setRange, 0, 7) {
|
|||
const intptr_t from_cid = from_cid_smi.Value();
|
||||
|
||||
const bool needs_clamping = IsClamped(to_cid) && !IsUint8(from_cid);
|
||||
if (dst.IsTypedData()) {
|
||||
if (src.IsTypedData()) {
|
||||
return CopyData<TypedData, TypedData>(dst, src, dst_start, src_start,
|
||||
length, needs_clamping);
|
||||
} else if (src.IsExternalTypedData()) {
|
||||
return CopyData<TypedData, ExternalTypedData>(
|
||||
dst, src, dst_start, src_start, length, needs_clamping);
|
||||
}
|
||||
} else if (dst.IsExternalTypedData()) {
|
||||
if (src.IsTypedData()) {
|
||||
return CopyData<ExternalTypedData, TypedData>(
|
||||
dst, src, dst_start, src_start, length, needs_clamping);
|
||||
} else if (src.IsExternalTypedData()) {
|
||||
return CopyData<ExternalTypedData, ExternalTypedData>(
|
||||
dst, src, dst_start, src_start, length, needs_clamping);
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return Bool::False().ptr();
|
||||
return CopyData(dst, src, dst_start, src_start, length, needs_clamping);
|
||||
}
|
||||
|
||||
// Native methods for typed data allocation are recognized and implemented
|
||||
|
@ -203,19 +163,26 @@ CLASS_LIST_TYPED_DATA(TYPED_DATA_NEW_NATIVE)
|
|||
// into a _Smi.
|
||||
//
|
||||
// Argument 0 is type arguments and is ignored.
|
||||
static InstancePtr NewTypedDataView(intptr_t cid,
|
||||
intptr_t element_size,
|
||||
Zone* zone,
|
||||
NativeArguments* arguments) {
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, 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.LengthInBytes();
|
||||
const intptr_t offset_in_bytes = offset.Value();
|
||||
const intptr_t length = len.Value();
|
||||
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_VIEW_NEW(native_name, cid) \
|
||||
DEFINE_NATIVE_ENTRY(native_name, 0, 4) { \
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, 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.LengthInBytes(); \
|
||||
const intptr_t offset_in_bytes = offset.Value(); \
|
||||
const intptr_t length = len.Value(); \
|
||||
const intptr_t element_size = TypedDataBase::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); \
|
||||
return NewTypedDataView(cid, TypedDataBase::ElementSizeInBytes(cid), zone, \
|
||||
arguments); \
|
||||
}
|
||||
|
||||
#define TYPED_DATA_NEW_NATIVE(name) \
|
||||
|
@ -228,53 +195,27 @@ TYPED_DATA_VIEW_NEW(TypedDataView_ByteDataView_new, kByteDataViewCid)
|
|||
|
||||
#define TYPED_DATA_GETTER(getter, object, ctor, access_size) \
|
||||
DEFINE_NATIVE_ENTRY(TypedData_##getter, 0, 2) { \
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, \
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, array, \
|
||||
arguments->NativeArgAt(0)); \
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, \
|
||||
arguments->NativeArgAt(1)); \
|
||||
if (instance.IsTypedData()) { \
|
||||
const TypedData& array = TypedData::Cast(instance); \
|
||||
RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(), \
|
||||
access_size); \
|
||||
return object::ctor(array.getter(offsetInBytes.Value())); \
|
||||
} \
|
||||
if (instance.IsExternalTypedData()) { \
|
||||
const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
|
||||
RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(), \
|
||||
access_size); \
|
||||
return object::ctor(array.getter(offsetInBytes.Value())); \
|
||||
} \
|
||||
const String& error = String::Handle(String::NewFormatted( \
|
||||
"Expected a TypedData object but found %s", instance.ToCString())); \
|
||||
Exceptions::ThrowArgumentError(error); \
|
||||
return object::null(); \
|
||||
RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(), \
|
||||
access_size); \
|
||||
return object::ctor(array.getter(offsetInBytes.Value())); \
|
||||
}
|
||||
|
||||
#define TYPED_DATA_SETTER(setter, object, get_object_value, access_size, \
|
||||
access_type) \
|
||||
DEFINE_NATIVE_ENTRY(TypedData_##setter, 0, 3) { \
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, \
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, array, \
|
||||
arguments->NativeArgAt(0)); \
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, \
|
||||
arguments->NativeArgAt(1)); \
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(object, value, arguments->NativeArgAt(2)); \
|
||||
if (instance.IsTypedData()) { \
|
||||
const TypedData& array = TypedData::Cast(instance); \
|
||||
RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(), \
|
||||
access_size); \
|
||||
array.setter(offsetInBytes.Value(), \
|
||||
static_cast<access_type>(value.get_object_value())); \
|
||||
} else if (instance.IsExternalTypedData()) { \
|
||||
const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
|
||||
RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(), \
|
||||
access_size); \
|
||||
array.setter(offsetInBytes.Value(), \
|
||||
static_cast<access_type>(value.get_object_value())); \
|
||||
} else { \
|
||||
const String& error = String::Handle(String::NewFormatted( \
|
||||
"Expected a TypedData object but found %s", instance.ToCString())); \
|
||||
Exceptions::ThrowArgumentError(error); \
|
||||
} \
|
||||
RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(), \
|
||||
access_size); \
|
||||
array.setter(offsetInBytes.Value(), \
|
||||
static_cast<access_type>(value.get_object_value())); \
|
||||
return Object::null(); \
|
||||
}
|
||||
|
||||
|
|
|
@ -190,8 +190,8 @@ namespace dart {
|
|||
V(TypedData_Float32x4Array_new, 2) \
|
||||
V(TypedData_Int32x4Array_new, 2) \
|
||||
V(TypedData_Float64x2Array_new, 2) \
|
||||
V(TypedData_length, 1) \
|
||||
V(TypedData_setRange, 7) \
|
||||
V(TypedDataBase_length, 1) \
|
||||
V(TypedDataBase_setRange, 7) \
|
||||
V(TypedData_GetInt8, 2) \
|
||||
V(TypedData_SetInt8, 3) \
|
||||
V(TypedData_GetUint8, 2) \
|
||||
|
@ -233,7 +233,6 @@ namespace dart {
|
|||
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, 4) \
|
||||
|
|
|
@ -856,8 +856,7 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
|
|||
case MethodRecognizer::kGrowableArrayLength:
|
||||
case MethodRecognizer::kObjectArrayLength:
|
||||
case MethodRecognizer::kImmutableArrayLength:
|
||||
case MethodRecognizer::kTypedListLength:
|
||||
case MethodRecognizer::kTypedListViewLength:
|
||||
case MethodRecognizer::kTypedListBaseLength:
|
||||
case MethodRecognizer::kByteDataViewLength:
|
||||
case MethodRecognizer::kByteDataViewOffsetInBytes:
|
||||
case MethodRecognizer::kTypedDataViewOffsetInBytes:
|
||||
|
@ -1054,8 +1053,7 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
|
|||
body += LoadLocal(parsed_function_->RawParameterVariable(0));
|
||||
body += LoadNativeField(Slot::Array_length());
|
||||
break;
|
||||
case MethodRecognizer::kTypedListLength:
|
||||
case MethodRecognizer::kTypedListViewLength:
|
||||
case MethodRecognizer::kTypedListBaseLength:
|
||||
case MethodRecognizer::kByteDataViewLength:
|
||||
ASSERT(function.NumParameters() == 1);
|
||||
body += LoadLocal(parsed_function_->RawParameterVariable(0));
|
||||
|
|
|
@ -760,11 +760,7 @@ bool GraphIntrinsifier::Build_StringBaseLength(FlowGraph* flow_graph) {
|
|||
return BuildLoadField(flow_graph, Slot::String_length());
|
||||
}
|
||||
|
||||
bool GraphIntrinsifier::Build_TypedListLength(FlowGraph* flow_graph) {
|
||||
return BuildLoadField(flow_graph, Slot::TypedDataBase_length());
|
||||
}
|
||||
|
||||
bool GraphIntrinsifier::Build_TypedListViewLength(FlowGraph* flow_graph) {
|
||||
bool GraphIntrinsifier::Build_TypedListBaseLength(FlowGraph* flow_graph) {
|
||||
return BuildLoadField(flow_graph, Slot::TypedDataBase_length());
|
||||
}
|
||||
|
||||
|
|
|
@ -318,8 +318,7 @@ namespace dart {
|
|||
V(_Int32x4List, []=, Int32x4ArraySetIndexed, 0x17a2cbc0) \
|
||||
V(_Float64x2List, [], Float64x2ArrayGetIndexed, 0xea0577df) \
|
||||
V(_Float64x2List, []=, Float64x2ArraySetIndexed, 0x8af8aa58) \
|
||||
V(_TypedList, get:length, TypedListLength, 0x5850f06b) \
|
||||
V(_TypedListView, get:length, TypedListViewLength, 0x5850f06b) \
|
||||
V(_TypedListBase, get:length, TypedListBaseLength, 0x5850f06b) \
|
||||
V(_ByteDataView, get:length, ByteDataViewLength, 0x5850f06b) \
|
||||
V(_Float32x4, get:x, Float32x4ShuffleX, 0x3a398530) \
|
||||
V(_Float32x4, get:y, Float32x4ShuffleY, 0x27cae053) \
|
||||
|
|
|
@ -3211,8 +3211,8 @@ DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* len) {
|
|||
// Pass through errors.
|
||||
return list;
|
||||
}
|
||||
if (obj.IsTypedData()) {
|
||||
GET_LIST_LENGTH(Z, TypedData, obj, len);
|
||||
if (obj.IsTypedDataBase()) {
|
||||
GET_LIST_LENGTH(Z, TypedDataBase, obj, len);
|
||||
}
|
||||
if (obj.IsArray()) {
|
||||
GET_LIST_LENGTH(Z, Array, obj, len);
|
||||
|
@ -3220,9 +3220,6 @@ DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* len) {
|
|||
if (obj.IsGrowableObjectArray()) {
|
||||
GET_LIST_LENGTH(Z, GrowableObjectArray, obj, len);
|
||||
}
|
||||
if (obj.IsExternalTypedData()) {
|
||||
GET_LIST_LENGTH(Z, ExternalTypedData, obj, len);
|
||||
}
|
||||
CHECK_CALLBACK_STATE(T);
|
||||
|
||||
// Now check and handle a dart object that implements the List interface.
|
||||
|
@ -3464,63 +3461,22 @@ static ObjectPtr ThrowArgumentError(const char* exception_message) {
|
|||
} \
|
||||
return Api::NewError("Invalid length passed in to access array elements");
|
||||
|
||||
template <typename T>
|
||||
static Dart_Handle CopyBytes(const T& array,
|
||||
intptr_t offset,
|
||||
uint8_t* native_array,
|
||||
intptr_t length) {
|
||||
ASSERT(array.ElementSizeInBytes() == 1);
|
||||
NoSafepointScope no_safepoint;
|
||||
memmove(native_array, reinterpret_cast<uint8_t*>(array.DataAddr(offset)),
|
||||
length);
|
||||
return Api::Success();
|
||||
}
|
||||
|
||||
DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list,
|
||||
intptr_t offset,
|
||||
uint8_t* native_array,
|
||||
intptr_t length) {
|
||||
DARTSCOPE(Thread::Current());
|
||||
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
|
||||
if (obj.IsTypedData()) {
|
||||
const TypedData& array = TypedData::Cast(obj);
|
||||
if (obj.IsTypedDataBase()) {
|
||||
const TypedDataBase& array = TypedDataBase::Cast(obj);
|
||||
if (array.ElementSizeInBytes() == 1) {
|
||||
if (!Utils::RangeCheck(offset, length, array.Length())) {
|
||||
return Api::NewError(
|
||||
"Invalid length passed in to access list elements");
|
||||
}
|
||||
return CopyBytes(array, offset, native_array, length);
|
||||
}
|
||||
}
|
||||
if (obj.IsExternalTypedData()) {
|
||||
const ExternalTypedData& external_array = ExternalTypedData::Cast(obj);
|
||||
if (external_array.ElementSizeInBytes() == 1) {
|
||||
if (!Utils::RangeCheck(offset, length, external_array.Length())) {
|
||||
return Api::NewError(
|
||||
"Invalid length passed in to access list elements");
|
||||
}
|
||||
return CopyBytes(external_array, offset, native_array, length);
|
||||
}
|
||||
}
|
||||
if (IsTypedDataViewClassId(obj.GetClassId())) {
|
||||
const auto& view = TypedDataView::Cast(obj);
|
||||
if (view.ElementSizeInBytes() == 1) {
|
||||
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 auto& data = Instance::Handle(view.typed_data());
|
||||
if (data.IsTypedData()) {
|
||||
const TypedData& array = TypedData::Cast(data);
|
||||
if (array.ElementSizeInBytes() == 1) {
|
||||
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);
|
||||
}
|
||||
if (Utils::RangeCheck(offset, length, array.Length())) {
|
||||
NoSafepointScope no_safepoint;
|
||||
memmove(native_array,
|
||||
reinterpret_cast<uint8_t*>(array.DataAddr(offset)), length);
|
||||
return Api::Success();
|
||||
}
|
||||
return Api::NewError("Invalid length passed in to access list elements");
|
||||
}
|
||||
}
|
||||
if (obj.IsArray()) {
|
||||
|
@ -3590,8 +3546,8 @@ DART_EXPORT Dart_Handle Dart_ListSetAsBytes(Dart_Handle list,
|
|||
intptr_t length) {
|
||||
DARTSCOPE(Thread::Current());
|
||||
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
|
||||
if (obj.IsTypedData()) {
|
||||
const TypedData& array = TypedData::Cast(obj);
|
||||
if (obj.IsTypedDataBase()) {
|
||||
const TypedDataBase& array = TypedDataBase::Cast(obj);
|
||||
if (array.ElementSizeInBytes() == 1) {
|
||||
if (Utils::RangeCheck(offset, length, array.Length())) {
|
||||
NoSafepointScope no_safepoint;
|
||||
|
|
|
@ -11103,8 +11103,7 @@ ObjectPtr Field::EvaluateInitializer() const {
|
|||
}
|
||||
|
||||
static intptr_t GetListLength(const Object& value) {
|
||||
if (value.IsTypedData() || value.IsTypedDataView() ||
|
||||
value.IsExternalTypedData()) {
|
||||
if (value.IsTypedDataBase()) {
|
||||
return TypedDataBase::Cast(value).Length();
|
||||
} else if (value.IsArray()) {
|
||||
return Array::Cast(value).Length();
|
||||
|
@ -23571,21 +23570,7 @@ OneByteStringPtr OneByteString::New(const String& other_one_byte_string,
|
|||
return OneByteString::raw(result);
|
||||
}
|
||||
|
||||
OneByteStringPtr OneByteString::New(const TypedData& other_typed_data,
|
||||
intptr_t other_start_index,
|
||||
intptr_t other_len,
|
||||
Heap::Space space) {
|
||||
const String& result = String::Handle(OneByteString::New(other_len, space));
|
||||
ASSERT(other_typed_data.ElementSizeInBytes() == 1);
|
||||
if (other_len > 0) {
|
||||
NoSafepointScope no_safepoint;
|
||||
memmove(OneByteString::DataStart(result),
|
||||
other_typed_data.DataAddr(other_start_index), other_len);
|
||||
}
|
||||
return OneByteString::raw(result);
|
||||
}
|
||||
|
||||
OneByteStringPtr OneByteString::New(const ExternalTypedData& other_typed_data,
|
||||
OneByteStringPtr OneByteString::New(const TypedDataBase& other_typed_data,
|
||||
intptr_t other_start_index,
|
||||
intptr_t other_len,
|
||||
Heap::Space space) {
|
||||
|
@ -23765,21 +23750,7 @@ TwoByteStringPtr TwoByteString::New(const String& str, Heap::Space space) {
|
|||
return TwoByteString::raw(result);
|
||||
}
|
||||
|
||||
TwoByteStringPtr TwoByteString::New(const TypedData& other_typed_data,
|
||||
intptr_t other_start_index,
|
||||
intptr_t other_len,
|
||||
Heap::Space space) {
|
||||
const String& result = String::Handle(TwoByteString::New(other_len, space));
|
||||
if (other_len > 0) {
|
||||
NoSafepointScope no_safepoint;
|
||||
memmove(TwoByteString::DataStart(result),
|
||||
other_typed_data.DataAddr(other_start_index),
|
||||
other_len * sizeof(uint16_t));
|
||||
}
|
||||
return TwoByteString::raw(result);
|
||||
}
|
||||
|
||||
TwoByteStringPtr TwoByteString::New(const ExternalTypedData& other_typed_data,
|
||||
TwoByteStringPtr TwoByteString::New(const TypedDataBase& other_typed_data,
|
||||
intptr_t other_start_index,
|
||||
intptr_t other_len,
|
||||
Heap::Space space) {
|
||||
|
|
|
@ -9486,12 +9486,7 @@ class OneByteString : public AllStatic {
|
|||
intptr_t other_len,
|
||||
Heap::Space space);
|
||||
|
||||
static OneByteStringPtr New(const TypedData& other_typed_data,
|
||||
intptr_t other_start_index,
|
||||
intptr_t other_len,
|
||||
Heap::Space space = Heap::kNew);
|
||||
|
||||
static OneByteStringPtr New(const ExternalTypedData& other_typed_data,
|
||||
static OneByteStringPtr New(const TypedDataBase& other_typed_data,
|
||||
intptr_t other_start_index,
|
||||
intptr_t other_len,
|
||||
Heap::Space space = Heap::kNew);
|
||||
|
@ -9622,12 +9617,7 @@ class TwoByteString : public AllStatic {
|
|||
Heap::Space space);
|
||||
static TwoByteStringPtr New(const String& str, Heap::Space space);
|
||||
|
||||
static TwoByteStringPtr New(const TypedData& other_typed_data,
|
||||
intptr_t other_start_index,
|
||||
intptr_t other_len,
|
||||
Heap::Space space = Heap::kNew);
|
||||
|
||||
static TwoByteStringPtr New(const ExternalTypedData& other_typed_data,
|
||||
static TwoByteStringPtr New(const TypedDataBase& other_typed_data,
|
||||
intptr_t other_start_index,
|
||||
intptr_t other_len,
|
||||
Heap::Space space = Heap::kNew);
|
||||
|
@ -10408,6 +10398,32 @@ class TypedDataBase : public PointerBase {
|
|||
return reinterpret_cast<void*>(Validate(untag()->data_) + byte_offset);
|
||||
}
|
||||
|
||||
#define TYPED_GETTER_SETTER(name, type) \
|
||||
type Get##name(intptr_t byte_offset) const { \
|
||||
NoSafepointScope no_safepoint; \
|
||||
return LoadUnaligned(reinterpret_cast<type*>(DataAddr(byte_offset))); \
|
||||
} \
|
||||
void Set##name(intptr_t byte_offset, type value) const { \
|
||||
NoSafepointScope no_safepoint; \
|
||||
StoreUnaligned(reinterpret_cast<type*>(DataAddr(byte_offset)), value); \
|
||||
}
|
||||
|
||||
TYPED_GETTER_SETTER(Int8, int8_t)
|
||||
TYPED_GETTER_SETTER(Uint8, uint8_t)
|
||||
TYPED_GETTER_SETTER(Int16, int16_t)
|
||||
TYPED_GETTER_SETTER(Uint16, uint16_t)
|
||||
TYPED_GETTER_SETTER(Int32, int32_t)
|
||||
TYPED_GETTER_SETTER(Uint32, uint32_t)
|
||||
TYPED_GETTER_SETTER(Int64, int64_t)
|
||||
TYPED_GETTER_SETTER(Uint64, uint64_t)
|
||||
TYPED_GETTER_SETTER(Float32, float)
|
||||
TYPED_GETTER_SETTER(Float64, double)
|
||||
TYPED_GETTER_SETTER(Float32x4, simd128_value_t)
|
||||
TYPED_GETTER_SETTER(Int32x4, simd128_value_t)
|
||||
TYPED_GETTER_SETTER(Float64x2, simd128_value_t)
|
||||
|
||||
#undef TYPED_GETTER_SETTER
|
||||
|
||||
protected:
|
||||
void SetLength(intptr_t value) const {
|
||||
ASSERT(value <= Smi::kMaxValue);
|
||||
|
@ -10500,10 +10516,9 @@ class TypedData : public TypedDataBase {
|
|||
intptr_t len,
|
||||
Heap::Space space = Heap::kNew);
|
||||
|
||||
template <typename DstType, typename SrcType>
|
||||
static void Copy(const DstType& dst,
|
||||
static void Copy(const TypedDataBase& dst,
|
||||
intptr_t dst_offset_in_bytes,
|
||||
const SrcType& src,
|
||||
const TypedDataBase& src,
|
||||
intptr_t src_offset_in_bytes,
|
||||
intptr_t length_in_bytes) {
|
||||
ASSERT(Utils::RangeCheck(src_offset_in_bytes, length_in_bytes,
|
||||
|
@ -10519,10 +10534,9 @@ class TypedData : public TypedDataBase {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename DstType, typename SrcType>
|
||||
static void ClampedCopy(const DstType& dst,
|
||||
static void ClampedCopy(const TypedDataBase& dst,
|
||||
intptr_t dst_offset_in_bytes,
|
||||
const SrcType& src,
|
||||
const TypedDataBase& src,
|
||||
intptr_t src_offset_in_bytes,
|
||||
intptr_t length_in_bytes) {
|
||||
ASSERT(Utils::RangeCheck(src_offset_in_bytes, length_in_bytes,
|
||||
|
@ -10580,29 +10594,6 @@ class ExternalTypedData : public TypedDataBase {
|
|||
// snapshot. Should be independent of word size.
|
||||
static const int kDataSerializationAlignment = 8;
|
||||
|
||||
#define TYPED_GETTER_SETTER(name, type) \
|
||||
type Get##name(intptr_t byte_offset) const { \
|
||||
return LoadUnaligned(reinterpret_cast<type*>(DataAddr(byte_offset))); \
|
||||
} \
|
||||
void Set##name(intptr_t byte_offset, type value) const { \
|
||||
StoreUnaligned(reinterpret_cast<type*>(DataAddr(byte_offset)), value); \
|
||||
}
|
||||
TYPED_GETTER_SETTER(Int8, int8_t)
|
||||
TYPED_GETTER_SETTER(Uint8, uint8_t)
|
||||
TYPED_GETTER_SETTER(Int16, int16_t)
|
||||
TYPED_GETTER_SETTER(Uint16, uint16_t)
|
||||
TYPED_GETTER_SETTER(Int32, int32_t)
|
||||
TYPED_GETTER_SETTER(Uint32, uint32_t)
|
||||
TYPED_GETTER_SETTER(Int64, int64_t)
|
||||
TYPED_GETTER_SETTER(Uint64, uint64_t)
|
||||
TYPED_GETTER_SETTER(Float32, float)
|
||||
TYPED_GETTER_SETTER(Float64, double)
|
||||
TYPED_GETTER_SETTER(Float32x4, simd128_value_t)
|
||||
TYPED_GETTER_SETTER(Int32x4, simd128_value_t)
|
||||
TYPED_GETTER_SETTER(Float64x2, simd128_value_t)
|
||||
|
||||
#undef TYPED_GETTER_SETTER
|
||||
|
||||
FinalizablePersistentHandle* AddFinalizer(void* peer,
|
||||
Dart_HandleFinalizer callback,
|
||||
intptr_t external_size) const;
|
||||
|
|
|
@ -58,7 +58,11 @@ class ByteData implements TypedData {
|
|||
// to instances of _TypeListBase. Instead the subclasses use type specific
|
||||
// mixins (like _IntListMixin, _DoubleListMixin) to implement ListBase<T>.
|
||||
abstract class _TypedListBase {
|
||||
int get length;
|
||||
@pragma("vm:recognized", "graph-intrinsic")
|
||||
@pragma("vm:exact-result-type", "dart:core#_Smi")
|
||||
@pragma("vm:prefer-inline")
|
||||
int get length native "TypedDataBase_length";
|
||||
|
||||
int get elementSizeInBytes;
|
||||
int get offsetInBytes;
|
||||
_ByteBuffer get buffer;
|
||||
|
@ -108,8 +112,13 @@ abstract class _TypedListBase {
|
|||
// match the cids of 'this' and 'from'.
|
||||
// Uses toCid and fromCid to decide if clamping is necessary.
|
||||
// Element size of toCid and fromCid must match (test at caller).
|
||||
bool _setRange(int startInBytes, int lengthInBytes, _TypedListBase from,
|
||||
int startFromInBytes, int toCid, int fromCid) native "TypedData_setRange";
|
||||
bool _setRange(
|
||||
int startInBytes,
|
||||
int lengthInBytes,
|
||||
_TypedListBase from,
|
||||
int startFromInBytes,
|
||||
int toCid,
|
||||
int fromCid) native "TypedDataBase_setRange";
|
||||
}
|
||||
|
||||
mixin _IntListMixin implements List<int> {
|
||||
|
@ -2035,13 +2044,6 @@ abstract class _TypedList extends _TypedListBase {
|
|||
|
||||
_ByteBuffer get buffer => new _ByteBuffer(this);
|
||||
|
||||
// Methods implementing the collection interface.
|
||||
|
||||
@pragma("vm:recognized", "graph-intrinsic")
|
||||
@pragma("vm:exact-result-type", "dart:core#_Smi")
|
||||
@pragma("vm:prefer-inline")
|
||||
int get length native "TypedData_length";
|
||||
|
||||
// Internal utility methods.
|
||||
|
||||
@pragma("vm:recognized", "other")
|
||||
|
@ -4009,11 +4011,6 @@ abstract class _TypedListView extends _TypedListBase implements TypedData {
|
|||
@pragma("vm:exact-result-type", "dart:core#_Smi")
|
||||
@pragma("vm:prefer-inline")
|
||||
int get offsetInBytes native "TypedDataView_offsetInBytes";
|
||||
|
||||
@pragma("vm:recognized", "graph-intrinsic")
|
||||
@pragma("vm:exact-result-type", "dart:core#_Smi")
|
||||
@pragma("vm:prefer-inline")
|
||||
int get length native "TypedDataView_length";
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
|
@ -4859,7 +4856,7 @@ class _ByteDataView implements ByteData {
|
|||
@pragma("vm:recognized", "graph-intrinsic")
|
||||
@pragma("vm:exact-result-type", "dart:core#_Smi")
|
||||
@pragma("vm:prefer-inline")
|
||||
int get length native "TypedDataView_length";
|
||||
int get length native "TypedDataBase_length";
|
||||
}
|
||||
|
||||
@pragma("vm:prefer-inline")
|
||||
|
|
Loading…
Reference in a new issue