[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:
Ryan Macnak 2021-06-08 19:15:38 +00:00 committed by commit-bot@chromium.org
parent 3ff71e0a47
commit 84e6d4a4e8
11 changed files with 123 additions and 335 deletions

View file

@ -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("];");

View file

@ -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()) {

View file

@ -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(); \
}

View file

@ -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) \

View file

@ -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));

View file

@ -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());
}

View file

@ -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) \

View file

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

View file

@ -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) {

View file

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

View file

@ -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")