15#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
19#if !defined(FFI_UNIT_TESTS)
67 switch (representation_) {
91 return representation_ ==
kFloat || representation_ ==
kDouble ||
96 return representation_ ==
kVoid;
101 switch (representation_) {
155 const auto alignment =
161 return compiler::target::kWordSize;
165 static_cast<intptr_t
>(compiler::target::kWordSize));
198 intptr_t member_packing) {
201 const intptr_t kAtLeast1ByteAligned = 1;
204 intptr_t alignment_field = kAtLeast1ByteAligned;
207 intptr_t alignment_stack = kAtLeast1ByteAligned;
208 intptr_t alignment_stack_vararg = kAtLeast1ByteAligned;
209#if (defined(DART_TARGET_OS_MACOS_IOS) || defined(DART_TARGET_OS_MACOS)) && \
210 defined(TARGET_ARCH_ARM64)
222 alignment_stack = compiler::target::kWordSize;
224 alignment_stack_vararg = compiler::target::kWordSize;
232 const intptr_t member_align_field =
235 if (member_align_stack > member_packing &&
236 member_packing < compiler::target::kWordSize) {
237 member_align_stack = compiler::target::kWordSize;
242 alignment_field =
Utils::Maximum(alignment_field, member_align_field);
243 alignment_stack =
Utils::Maximum(alignment_stack, member_align_stack);
244 alignment_stack_vararg =
251 alignment_stack, alignment_stack_vararg);
260 const intptr_t kAtLeast1ByteAligned = 1;
263 intptr_t alignment_field = kAtLeast1ByteAligned;
266 intptr_t alignment_stack = kAtLeast1ByteAligned;
274 alignment_field =
Utils::Maximum(alignment_field, member_align_field);
275 alignment_stack =
Utils::Maximum(alignment_stack, member_align_stack);
283#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
285 switch (representation_) {
315 switch (representation_) {
319 return kUnboxedUint8;
321 return kUnboxedInt16;
323 return kUnboxedUint16;
325 return kUnboxedInt32;
327 return kUnboxedUint32;
330 return kUnboxedInt64;
332 return kUnboxedFloat;
334 return kUnboxedDouble;
347 return other.
AsPrimitive().representation_ == representation_;
354 return other.
AsArray().length_ == length_ &&
362 const auto& other_compound = other.
AsCompound();
363 const auto& other_members = other_compound.
members_;
397 intptr_t index)
const {
398 ASSERT(index == 0 || index == 1);
442#if !defined(FFI_UNIT_TESTS)
446 const char**
error) {
447 const auto& struct_layout = pragma;
448 const auto& clazz =
Class::Handle(zone, struct_layout.clazz());
450 .Equals(Symbols::FfiStructLayout()));
451 const auto& struct_layout_fields =
Array::Handle(zone, clazz.fields());
452 ASSERT(struct_layout_fields.Length() == 2);
453 const auto& types_field =
456 .Equals(Symbols::FfiFieldTypes()));
457 const auto& field_types =
459 const auto& packed_field =
462 .Equals(Symbols::FfiFieldPacking()));
465 const intptr_t member_packing =
466 packed_value.IsNull() ?
kMaxInt32 : packed_value.AsInt64Value();
471 zone, field_types.Length());
472 for (intptr_t i = 0; i < field_types.Length(); i++) {
473 field_instance ^= field_types.
At(i);
474 if (field_instance.IsAbstractType()) {
476 field_type ^= field_types.At(i);
477 const auto& field_native_type =
479 if (*
error !=
nullptr) {
482 field_native_types.Add(field_native_type);
485 const auto& struct_layout_array_class =
488 .Equals(Symbols::FfiStructLayoutArray()));
489 const auto& struct_layout_array_fields =
491 ASSERT(struct_layout_array_fields.Length() == 2);
492 const auto& element_type_field =
495 .Equals(Symbols::FfiElementType()));
496 field_type ^= field_instance.GetField(element_type_field);
497 const auto& length_field =
500 .Equals(Symbols::Length()));
502 zone,
Smi::RawCast(field_instance.GetField(length_field)));
503 const auto element_type =
505 if (*
error !=
nullptr) {
508 const auto field_native_type =
510 field_native_types.Add(field_native_type);
524 const Class& abi_specific_int,
525 const char**
error) {
528 ASSERT(fields.Length() == 1);
529 const auto& native_types_field =
532 .Equals(Symbols::FfiNativeTypes()));
533 const auto& native_types =
537 const int64_t abi_index =
static_cast<int64_t
>(
TargetAbi());
540 if (abi_abstract_type.IsNull()) {
542 "AbiSpecificInteger '%s' is missing mapping for '%s'.",
551 const char**
error) {
559 const auto& superClass =
Class::Handle(zone, cls.SuperClass());
560 const bool is_struct =
String::Handle(zone, superClass.UserVisibleName())
561 .Equals(Symbols::Struct());
562 const bool is_union =
String::Handle(zone, superClass.UserVisibleName())
563 .Equals(Symbols::Union());
564 const bool is_abi_specific_int =
566 .Equals(Symbols::AbiSpecificInteger());
571 if (is_struct || is_union) {
572 pragma_name = Symbols::vm_ffi_struct_fields().
ptr();
574 ASSERT(is_abi_specific_int);
575 pragma_name = Symbols::vm_ffi_abi_specific_mapping().
ptr();
578 pragma_name,
true, &pragmas);
579 ASSERT(!pragmas.IsNull());
580 ASSERT(pragmas.IsGrowableObjectArray());
581 const auto& pragmas_array = GrowableObjectArray::Cast(pragmas);
586 if (is_struct || is_union) {
587 class_symbol = Symbols::FfiStructLayout().
ptr();
589 ASSERT(is_abi_specific_int);
590 class_symbol = Symbols::FfiAbiSpecificMapping().
ptr();
592 for (intptr_t i = 0; i < pragmas_array.Length(); i++) {
593 pragma ^= pragmas_array.At(i);
594 clazz ^= pragma.clazz();
595 library ^= clazz.library();
596 if (
String::Handle(zone, clazz.UserVisibleName()).Equals(class_symbol) &&
602 if (is_struct || is_union) {
605 ASSERT(is_abi_specific_int);
610#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
629 FATAL(
"Unhandled representation %u", rep);
645 zone, argument_representations.
length());
646 for (intptr_t i = 0; i < argument_representations.
length(); i++) {
648 zone, argument_representations.
At(i)));
656 bool verbose)
const {
658 PrintTo(&textBuffer, multi_line, verbose);
659 return textBuffer.
buffer();
662#if !defined(FFI_UNIT_TESTS)
691 return "half-double";
717 bool verbose)
const {
723 bool verbose)
const {
730 return textBuffer.
buffer();
735 bool verbose)
const {
736 f->AddString(
"Array(");
737 f->Printf(
"element type: ");
738 element_type_.
PrintTo(f,
false, verbose);
739 f->Printf(
", length: %" Pd "", length_);
745 bool verbose)
const {
752 f->AddString(
"members: {");
759 f->AddString(
",\n ");
779 f->AddString(
"Struct");
783 f->AddString(
"Union");
787 intptr_t member_index)
const {
788 f->Printf(
"%" Pd ": ", member_offsets_[member_index]);
791#if !defined(FFI_UNIT_TESTS)
799 for (intptr_t i = 0; i < argument_types_.
length(); i++) {
803 if (i == variadic_arguments_index_) {
804 f->AddString(
"varargs: ");
806 argument_types_[i]->PrintTo(f);
808 f->AddString(
") => ");
848 return members_[i]->FirstPrimitiveMember();
857 intptr_t offset_in_members)
const {
858 if (offset_in_members == 0) *first =
this;
859 if (offset_in_members == 1) *second =
this;
860 return offset_in_members + 1;
866 intptr_t offset_in_members)
const {
867 for (intptr_t i = 0; i < length_; i++) {
871 return offset_in_members;
877 intptr_t offset_in_members)
const {
880 members_[i]->PrimitivePairMembers(first, second, offset_in_members);
882 return offset_in_members;
885#if !defined(DART_PRECOMPILED_RUNTIME)
888 ASSERT(this_range.Contains(range));
895 ASSERT(this_range.Contains(range));
897 const intptr_t element_size_in_bytes = element_type_.
SizeInBytes();
900 const intptr_t first_element_start = range.
start() / element_size_in_bytes;
901 const intptr_t last_element_index =
903 const intptr_t num_elements = last_element_index - first_element_start + 1;
904 ASSERT(num_elements >= 1);
906 if (num_elements > 2) {
913 const intptr_t first_start = first_element_start * element_size_in_bytes;
914 const auto first_range =
916 const auto first_range_clipped = range.
Intersect(first_range);
917 const auto range_in_first = first_range_clipped.
Translate(-first_start);
923 if (num_elements == 2) {
925 const intptr_t second_element_index = first_element_start + 1;
926 const intptr_t second_start = second_element_index * element_size_in_bytes;
927 const auto second_range =
929 const auto second_range_clipped = range.
Intersect(second_range);
930 const auto range_in_second = second_range_clipped.
Translate(-second_start);
939 ASSERT(this_range.Contains(range));
943 const intptr_t member_offset = member_offsets_[i];
944 const intptr_t member_size = member.SizeInBytes();
947 const auto member_range_clipped = member_range.Intersect(range);
948 const auto range_in_member =
949 member_range_clipped.Translate(-member_offset);
950 if (!member.ContainsOnlyFloats(range_in_member)) {
955 if (member_range.After(range)) {
966 const intptr_t member_size = member.SizeInBytes();
968 if (member_range.Overlaps(range)) {
969 const auto member_range_clipped = member_range.Intersect(range);
970 if (!member.ContainsOnlyFloats(member_range_clipped)) {
983 intptr_t float_only_chunks = 0;
985 offset += compiler::target::kWordSize) {
986 const auto chunk_range =
992 return float_only_chunks;
996 const intptr_t total_chunks =
998 compiler::target::kWordSize;
1014 const intptr_t max_check = 2;
1015 for (intptr_t i = 0; i <
Utils::Minimum(length_, max_check); i++) {
1027 const intptr_t member_offset = member_offsets_.
At(i);
1028 if (member.ContainsUnalignedMembers(
offset + member_offset)) {
1038 if (member.ContainsUnalignedMembers(
offset)) {
1047 bool* only_double) {
1048 for (intptr_t i = 0; i < types.
length(); i++) {
1049 const auto&
type = *types.
At(i);
1050 const auto& member_type =
1052 if (member_type.IsPrimitive()) {
1054 *only_float = *only_float && (
type ==
kFloat);
1057 if (member_type.IsCompound()) {
1059 only_float, only_double);
1065 bool only_float =
true;
1066 bool only_double =
true;
1068 return (only_double || only_float) && types.
length() > 0;
1075#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
1080 return kUnboxedInt32;
1082 return kUnboxedUint32;
1089 return kUnboxedInt64;
1095 return widened.AsRepresentation();
#define RELEASE_ASSERT(cond)
const T & At(intptr_t index) const
static constexpr AlignmentStrategy kFieldAlignment
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs
static constexpr AlignmentStrategy kArgumentStackAlignment
const char * UserVisibleNameCString() const
ObjectPtr GetField(const Field &field) const
static bool FindPragma(Thread *T, bool only_core, const Object &object, const String &pragma_name, bool multiple=false, Object *options=nullptr)
static ObjectPtr RawCast(ObjectPtr obj)
static Thread * Current()
static constexpr T Maximum(T x, T y)
static T Minimum(T x, T y)
static constexpr T RoundUp(T x, uintptr_t alignment, uintptr_t offset=0)
char * PrintToString(const char *format,...) PRINTF_ATTRIBUTE(2
virtual void PrintTo(BaseTextBuffer *f, bool multi_line=false, bool verbose=true) const
virtual intptr_t SizeInBytes() const
virtual bool Equals(const NativeType &other) const
virtual bool ContainsOnlyFloats(Range range) const
virtual bool ContainsUnalignedMembers(intptr_t offset=0) const
virtual intptr_t PrimitivePairMembers(const NativePrimitiveType **first, const NativePrimitiveType **second, intptr_t offset_in_members=0) const
virtual const NativePrimitiveType & FirstPrimitiveMember() const
virtual intptr_t NumPrimitiveMembersRecursive() const
virtual intptr_t NumPrimitiveMembersRecursive() const =0
const NativeTypes & members() const
virtual bool Equals(const NativeType &other) const
bool ContainsHomogeneousFloats() const
virtual intptr_t SizeInBytes() const
intptr_t NumberOfWordSizeChunksOnlyFloat() const
virtual intptr_t AlignmentInBytesStack(bool is_vararg=false) const
virtual intptr_t PrimitivePairMembers(const NativePrimitiveType **first, const NativePrimitiveType **second, intptr_t offset_in_members=0) const
virtual const NativePrimitiveType & FirstPrimitiveMember() const
const NativeTypes & members_
virtual bool ContainsOnlyFloats(Range range) const =0
intptr_t NumberOfWordSizeChunksNotOnlyFloat() const
virtual void PrintMemberOffset(BaseTextBuffer *f, intptr_t member_index) const
virtual intptr_t AlignmentInBytesField() const
virtual void PrintTo(BaseTextBuffer *f, bool multi_line=false, bool verbose=true) const
virtual void PrintCompoundType(BaseTextBuffer *f) const =0
static const NativeFunctionType * FromRepresentations(Zone *zone, Representation return_representation, const ZoneGrowableArray< Representation > &argument_representations)
const NativeTypes & argument_types() const
void PrintTo(BaseTextBuffer *f) const
const NativeType & return_type() const
const char * ToCString() const
virtual bool IsFloat() const
virtual Representation AsRepresentation() const
virtual bool IsVoid() const
virtual const NativePrimitiveType & FirstPrimitiveMember() const
virtual NativePrimitiveType & Split(Zone *zone, intptr_t part) const
virtual bool ContainsOnlyFloats(Range range) const
virtual bool Equals(const NativeType &other) const
virtual bool ContainsUnalignedMembers(intptr_t offset=0) const
virtual intptr_t PrimitivePairMembers(const NativePrimitiveType **first, const NativePrimitiveType **second, intptr_t offset_in_members=0) const
virtual bool IsExpressibleAsRepresentation() const
PrimitiveType representation() const
virtual bool IsSigned() const
virtual intptr_t NumPrimitiveMembersRecursive() const
virtual intptr_t AlignmentInBytesStack(bool is_vararg=false) const
virtual intptr_t AlignmentInBytesField() const
virtual void PrintTo(BaseTextBuffer *f, bool multi_line=false, bool verbose=true) const
virtual bool IsInt() const
virtual intptr_t SizeInBytes() const
virtual bool ContainsOnlyFloats(Range range) const
static NativeStructType & FromNativeTypes(Zone *zone, const NativeTypes &members, intptr_t member_packing=kMaxInt32)
virtual bool ContainsUnalignedMembers(intptr_t offset=0) const
virtual void PrintMemberOffset(BaseTextBuffer *f, intptr_t member_index) const
virtual intptr_t NumPrimitiveMembersRecursive() const
virtual void PrintCompoundType(BaseTextBuffer *f) const
const ZoneGrowableArray< intptr_t > & member_offsets() const
const NativeCompoundType & AsCompound() const
Representation AsRepresentationOverApprox(Zone *zone_) const
virtual bool IsInt() const
static const NativeType * FromAbstractType(Zone *zone, const AbstractType &type, const char **error)
virtual bool IsCompound() const
virtual void PrintTo(BaseTextBuffer *f, bool multi_line=false, bool verbose=true) const
virtual intptr_t PrimitivePairMembers(const NativePrimitiveType **first, const NativePrimitiveType **second, intptr_t offset_in_members=0) const =0
virtual bool IsSigned() const
const NativeArrayType & AsArray() const
const NativePrimitiveType & AsPrimitive() const
const char * ToCString() const
virtual intptr_t AlignmentInBytesStack(bool is_vararg=false) const =0
virtual intptr_t SizeInBytes() const =0
virtual const NativePrimitiveType & FirstPrimitiveMember() const =0
virtual bool IsArray() const
const NativeType & WidenTo4Bytes(Zone *zone) const
virtual bool ContainsOnlyFloats(Range range) const =0
virtual bool IsPrimitive() const
const NativeType & WidenTo8Bytes(Zone *zone) const
static const NativeType & FromTypedDataClassId(Zone *zone, classid_t class_id)
static NativePrimitiveType & FromRepresentation(Zone *zone, Representation rep)
virtual intptr_t AlignmentInBytesField() const =0
virtual bool IsStruct() const
virtual bool ContainsUnalignedMembers(intptr_t offset=0) const =0
virtual bool Equals(const NativeType &other) const
const NativeStructType & AsStruct() const
virtual intptr_t NumPrimitiveMembersRecursive() const =0
static NativeUnionType & FromNativeTypes(Zone *zone, const NativeTypes &members)
virtual bool ContainsUnalignedMembers(intptr_t offset=0) const
virtual intptr_t NumPrimitiveMembersRecursive() const
virtual void PrintCompoundType(BaseTextBuffer *f) const
virtual bool ContainsOnlyFloats(Range range) const
static Range StartAndLength(intptr_t start_inclusive, intptr_t length)
const Range Intersect(const Range &other) const
bool Overlaps(const Range &other) const
static Range StartAndEnd(intptr_t start_inclusive, intptr_t end_exclusive)
intptr_t end_inclusive() const
const Range Translate(intptr_t delta) const
const uint8_t uint32_t uint32_t GError ** error
PrimitiveType PrimitiveTypeFromSizeInBytes(intptr_t size)
static const char * PrimitiveTypeToCString(PrimitiveType rep)
static const intptr_t fundamental_size_in_bytes[kVoid+1]
static PrimitiveType split_fundamental(PrimitiveType in)
static const NativeType * CompoundFromPragma(Zone *zone, const Instance &pragma, bool is_struct, const char **error)
static bool ContainsHomogeneousFloatsInternal(const NativeTypes &types)
const char * target_abi_name
static PrimitiveType TypeRepresentation(classid_t class_id)
static PrimitiveType fundamental_rep(Representation rep)
constexpr PrimitiveType kAddress
static const NativeType * AbiSpecificFromPragma(Zone *zone, const Instance &pragma, const Class &abi_specific_int, const char **error)
static void ContainsHomogeneousFloatsRecursive(const NativeTypes &types, bool *only_float, bool *only_double)
bool IsFfiPredefinedClassId(classid_t class_id)
constexpr int32_t kMaxInt32
static constexpr Representation kUnboxedIntPtr
@ kAlignedToWordSizeAndValueSize
@ kAlignedToValueSizeBut8AlignedTo4
#define UNREACHABLE_THIS()