Flutter Engine
The Flutter Engine
native_type.cc
Go to the documentation of this file.
1// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
6
7#include "platform/assert.h"
8#include "platform/globals.h"
9#include "vm/class_id.h"
10#include "vm/compiler/ffi/abi.h"
12#include "vm/constants.h"
13#include "vm/zone_text_buffer.h"
14
15#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
17#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
18
19#if !defined(FFI_UNIT_TESTS)
20#include "vm/symbols.h"
21#endif
22
23namespace dart {
24
25namespace compiler {
26
27namespace ffi {
28
30 ASSERT(size <= 8);
31 ASSERT(size > 0);
32 switch (size) {
33 case 1:
34 return kUint8;
35 case 2:
36 return kUint16;
37 case 4:
38 return kUint32;
39 case 8:
40 // Dart unboxed Representation for unsigned and signed is equal.
41 return kInt64;
42 }
44}
45
48 return static_cast<const NativePrimitiveType&>(*this);
49}
50
52 ASSERT(IsArray());
53 return static_cast<const NativeArrayType&>(*this);
54}
55
58 return static_cast<const NativeCompoundType&>(*this);
59}
60
63 return static_cast<const NativeStructType&>(*this);
64}
65
67 switch (representation_) {
68 case kInt8:
69 case kUint8:
70 case kInt16:
71 case kUint16:
72 case kInt24:
73 case kUint24:
74 case kInt32:
75 case kUint32:
76 case kInt40:
77 case kUint40:
78 case kInt48:
79 case kUint48:
80 case kInt56:
81 case kUint56:
82 case kInt64:
83 case kUint64:
84 return true;
85 default:
86 return false;
87 }
88}
89
91 return representation_ == kFloat || representation_ == kDouble ||
92 representation_ == kHalfDouble;
93}
94
96 return representation_ == kVoid;
97}
98
100 ASSERT(IsInt() || IsFloat());
101 switch (representation_) {
102 case kInt8:
103 case kInt16:
104 case kInt24:
105 case kInt32:
106 case kInt40:
107 case kInt48:
108 case kInt56:
109 case kInt64:
110 case kFloat:
111 case kDouble:
112 case kHalfDouble:
113 return true;
114 case kUint8:
115 case kUint16:
116 case kUint24:
117 case kUint32:
118 case kUint40:
119 case kUint48:
120 case kUint56:
121 case kUint64:
122 default:
123 return false;
124 }
125}
126
127static const intptr_t fundamental_size_in_bytes[kVoid + 1] = {
128 1, // kInt8,
129 1, // kUint8,
130 2, // kInt16,
131 2, // kUint16,
132 4, // kInt32,
133 4, // kUint32,
134 8, // kInt64,
135 8, // kUint64,
136 4, // kFloat,
137 8, // kDouble,
138 4, // kHalfDouble
139 3, // kInt24,
140 3, // kUint24,
141 5, // kInt40,
142 5, // kUint40,
143 6, // kInt48,
144 6, // kUint48,
145 7, // kInt56,
146 7, // kUint56,
147 0, // kVoid,
148};
149
151 return fundamental_size_in_bytes[representation_];
152}
153
154intptr_t NativePrimitiveType::AlignmentInBytesStack(bool is_vararg) const {
155 const auto alignment =
158 switch (alignment) {
160 // The default is to align stack arguments to word size.
163 // However, arm32+riscv32 align to the greater of word size or value size.
165 static_cast<intptr_t>(compiler::target::kWordSize));
167 // iOS on arm64 only aligns to size.
168 return SizeInBytes();
169 default:
171 }
172}
173
177 // The default is to align fields to their own size.
178 return SizeInBytes();
180 // However, on some 32-bit architectures, 8-byte fields are only aligned
181 // to 4 bytes.
182 if (SizeInBytes() == 8) {
183 return 4;
184 }
185 return SizeInBytes();
186 }
187 default:
189 }
190}
191
192static bool ContainsHomogeneousFloatsInternal(const NativeTypes& types);
193
194// Keep consistent with
195// pkg/vm/lib/transformations/ffi_definitions.dart:StructLayout:_calculateLayout.
197 const NativeTypes& members,
198 intptr_t member_packing) {
199 intptr_t offset = 0;
200
201 const intptr_t kAtLeast1ByteAligned = 1;
202 // If this struct is nested in another struct, it should be aligned to the
203 // largest alignment of its members.
204 intptr_t alignment_field = kAtLeast1ByteAligned;
205 // If this struct is passed on the stack, it should be aligned to the largest
206 // alignment of its members when passing those members on the stack.
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)
211 // On iOS64 and MacOS arm64 stack values can be less aligned than wordSize,
212 // which deviates from the arm64 ABI.
214 // Because the arm64 ABI aligns primitives to word size on the stack, every
215 // struct will be automatically aligned to word size. iOS64 does not align
216 // the primitives to word size, so we set structs to align to word size for
217 // iOS64.
218 // However, homogenous structs are treated differently. They are aligned to
219 // their member alignment. (Which is 4 in case of a homogenous float).
220 // Source: manual testing.
222 alignment_stack = compiler::target::kWordSize;
223 }
224 alignment_stack_vararg = compiler::target::kWordSize;
225#endif
226
227 auto& member_offsets =
228 *new (zone) ZoneGrowableArray<intptr_t>(zone, members.length());
229 for (intptr_t i = 0; i < members.length(); i++) {
230 const NativeType& member = *members[i];
231 const intptr_t member_size = member.SizeInBytes();
232 const intptr_t member_align_field =
233 Utils::Minimum(member.AlignmentInBytesField(), member_packing);
234 intptr_t member_align_stack = member.AlignmentInBytesStack();
235 if (member_align_stack > member_packing &&
236 member_packing < compiler::target::kWordSize) {
237 member_align_stack = compiler::target::kWordSize;
238 }
239 offset = Utils::RoundUp(offset, member_align_field);
241 offset += member_size;
242 alignment_field = Utils::Maximum(alignment_field, member_align_field);
243 alignment_stack = Utils::Maximum(alignment_stack, member_align_stack);
244 alignment_stack_vararg =
245 Utils::Maximum(alignment_stack_vararg, member_align_stack);
246 }
247 const intptr_t size = Utils::RoundUp(offset, alignment_field);
248
249 return *new (zone)
250 NativeStructType(members, member_offsets, size, alignment_field,
251 alignment_stack, alignment_stack_vararg);
252}
253
254// Keep consistent with
255// pkg/vm/lib/transformations/ffi_definitions.dart:StructLayout:_calculateLayout.
257 const NativeTypes& members) {
258 intptr_t size = 0;
259
260 const intptr_t kAtLeast1ByteAligned = 1;
261 // If this union is nested in a struct, it should be aligned to the
262 // largest alignment of its members.
263 intptr_t alignment_field = kAtLeast1ByteAligned;
264 // If this union is passed on the stack, it should be aligned to the largest
265 // alignment of its members when passing those members on the stack.
266 intptr_t alignment_stack = kAtLeast1ByteAligned;
267
268 for (intptr_t i = 0; i < members.length(); i++) {
269 const NativeType& member = *members[i];
270 const intptr_t member_size = member.SizeInBytes();
271 const intptr_t member_align_field = member.AlignmentInBytesField();
272 const intptr_t member_align_stack = member.AlignmentInBytesStack();
273 size = Utils::Maximum(size, member_size);
274 alignment_field = Utils::Maximum(alignment_field, member_align_field);
275 alignment_stack = Utils::Maximum(alignment_stack, member_align_stack);
276 }
277 size = Utils::RoundUp(size, alignment_field);
278
279 return *new (zone)
280 NativeUnionType(members, size, alignment_field, alignment_stack);
281}
282
283#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
285 switch (representation_) {
286 case kInt24:
287 case kUint24:
288 case kInt40:
289 case kUint40:
290 case kInt48:
291 case kUint48:
292 case kInt56:
293 case kUint56:
294 case kHalfDouble:
295 return false;
296 case kInt8:
297 case kUint8:
298 case kInt16:
299 case kUint16:
300 case kInt32:
301 case kUint32:
302 case kInt64:
303 case kUint64: // We don't actually have a kUnboxedUint64.
304 case kFloat:
305 case kDouble:
306 case kVoid:
307 return true;
308 default:
309 UNREACHABLE_THIS(); // Make MSVC happy.
310 }
311}
312
315 switch (representation_) {
316 case kInt8:
317 return kUnboxedInt8;
318 case kUint8:
319 return kUnboxedUint8;
320 case kInt16:
321 return kUnboxedInt16;
322 case kUint16:
323 return kUnboxedUint16;
324 case kInt32:
325 return kUnboxedInt32;
326 case kUint32:
327 return kUnboxedUint32;
328 case kInt64:
329 case kUint64:
330 return kUnboxedInt64;
331 case kFloat:
332 return kUnboxedFloat;
333 case kDouble:
334 return kUnboxedDouble;
335 case kVoid:
336 return kUnboxedIntPtr;
337 default:
339 }
340}
341#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
342
343bool NativePrimitiveType::Equals(const NativeType& other) const {
344 if (!other.IsPrimitive()) {
345 return false;
346 }
347 return other.AsPrimitive().representation_ == representation_;
348}
349
350bool NativeArrayType::Equals(const NativeType& other) const {
351 if (!other.IsArray()) {
352 return false;
353 }
354 return other.AsArray().length_ == length_ &&
355 other.AsArray().element_type_.Equals(element_type_);
356}
357
358bool NativeCompoundType::Equals(const NativeType& other) const {
359 if (!other.IsCompound()) {
360 return false;
361 }
362 const auto& other_compound = other.AsCompound();
363 const auto& other_members = other_compound.members_;
364 if (other_members.length() != members_.length()) {
365 return false;
366 }
367 for (intptr_t i = 0; i < members_.length(); i++) {
368 if (!members_[i]->Equals(*other_members[i])) {
369 return false;
370 }
371 }
372 return true;
373}
374
376 switch (in) {
377 case kInt16:
378 return kInt8;
379 case kInt32:
380 return kInt16;
381 case kInt64:
382 return kInt32;
383 case kUint16:
384 return kUint8;
385 case kUint32:
386 return kUint16;
387 case kUint64:
388 return kUint32;
389 case kDouble:
390 return kHalfDouble;
391 default:
392 UNREACHABLE();
393 }
394}
395
397 intptr_t index) const {
398 ASSERT(index == 0 || index == 1);
399 auto new_rep = split_fundamental(representation());
400 return *new (zone) NativePrimitiveType(new_rep);
401}
402
404 switch (class_id) {
405 case kFfiInt8Cid:
406 return kInt8;
407 case kFfiInt16Cid:
408 return kInt16;
409 case kFfiInt32Cid:
410 return kInt32;
411 case kFfiBoolCid:
412 case kFfiUint8Cid:
413 return kUint8;
414 case kFfiUint16Cid:
415 return kUint16;
416 case kFfiUint32Cid:
417 return kUint32;
418 case kFfiInt64Cid:
419 case kFfiUint64Cid:
420 return kInt64;
421 case kFfiFloatCid:
422 return kFloat;
423 case kFfiDoubleCid:
424 return kDouble;
425 case kPointerCid:
426 case kFfiHandleCid:
427 return kAddress;
428 case kFfiVoidCid:
429 return kVoid;
430 default:
431 UNREACHABLE();
432 }
433}
434
436 classid_t class_id) {
438 const auto fundamental_rep = TypeRepresentation(class_id);
439 return *new (zone) NativePrimitiveType(fundamental_rep);
440}
441
442#if !defined(FFI_UNIT_TESTS)
444 const Instance& pragma,
445 bool is_struct,
446 const char** error) {
447 const auto& struct_layout = pragma;
448 const auto& clazz = Class::Handle(zone, struct_layout.clazz());
449 ASSERT(String::Handle(zone, clazz.UserVisibleName())
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 =
454 Field::Handle(zone, Field::RawCast(struct_layout_fields.At(0)));
455 ASSERT(String::Handle(zone, types_field.name())
456 .Equals(Symbols::FfiFieldTypes()));
457 const auto& field_types =
458 Array::Handle(zone, Array::RawCast(struct_layout.GetField(types_field)));
459 const auto& packed_field =
460 Field::Handle(zone, Field::RawCast(struct_layout_fields.At(1)));
461 ASSERT(String::Handle(zone, packed_field.name())
462 .Equals(Symbols::FfiFieldPacking()));
463 const auto& packed_value = Integer::Handle(
464 zone, Integer::RawCast(struct_layout.GetField(packed_field)));
465 const intptr_t member_packing =
466 packed_value.IsNull() ? kMaxInt32 : packed_value.AsInt64Value();
467
468 auto& field_instance = Instance::Handle(zone);
469 auto& field_type = AbstractType::Handle(zone);
470 auto& field_native_types = *new (zone) ZoneGrowableArray<const NativeType*>(
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()) {
475 // Subtype of NativeType: Struct, native integer or native float.
476 field_type ^= field_types.At(i);
477 const auto& field_native_type =
478 NativeType::FromAbstractType(zone, field_type, error);
479 if (*error != nullptr) {
480 return nullptr;
481 }
482 field_native_types.Add(field_native_type);
483 } else {
484 // Inline array.
485 const auto& struct_layout_array_class =
486 Class::Handle(zone, field_instance.clazz());
487 ASSERT(String::Handle(zone, struct_layout_array_class.UserVisibleName())
488 .Equals(Symbols::FfiStructLayoutArray()));
489 const auto& struct_layout_array_fields =
490 Array::Handle(zone, struct_layout_array_class.fields());
491 ASSERT(struct_layout_array_fields.Length() == 2);
492 const auto& element_type_field =
493 Field::Handle(zone, Field::RawCast(struct_layout_array_fields.At(0)));
494 ASSERT(String::Handle(zone, element_type_field.UserVisibleName())
495 .Equals(Symbols::FfiElementType()));
496 field_type ^= field_instance.GetField(element_type_field);
497 const auto& length_field =
498 Field::Handle(zone, Field::RawCast(struct_layout_array_fields.At(1)));
499 ASSERT(String::Handle(zone, length_field.UserVisibleName())
500 .Equals(Symbols::Length()));
501 const auto& length = Smi::Handle(
502 zone, Smi::RawCast(field_instance.GetField(length_field)));
503 const auto element_type =
504 NativeType::FromAbstractType(zone, field_type, error);
505 if (*error != nullptr) {
506 return nullptr;
507 }
508 const auto field_native_type =
509 new (zone) NativeArrayType(*element_type, length.AsInt64Value());
510 field_native_types.Add(field_native_type);
511 }
512 }
513
514 if (is_struct) {
515 return &NativeStructType::FromNativeTypes(zone, field_native_types,
516 member_packing);
517 } else {
518 return &NativeUnionType::FromNativeTypes(zone, field_native_types);
519 }
520}
521
523 const Instance& pragma,
524 const Class& abi_specific_int,
525 const char** error) {
526 const auto& clazz = Class::Handle(zone, pragma.clazz());
527 const auto& fields = Array::Handle(zone, clazz.fields());
528 ASSERT(fields.Length() == 1);
529 const auto& native_types_field =
530 Field::Handle(zone, Field::RawCast(fields.At(0)));
531 ASSERT(String::Handle(zone, native_types_field.name())
532 .Equals(Symbols::FfiNativeTypes()));
533 const auto& native_types =
534 Array::Handle(zone, Array::RawCast(pragma.GetField(native_types_field)));
535
536 ASSERT(native_types.Length() == num_abis);
537 const int64_t abi_index = static_cast<int64_t>(TargetAbi());
538 const auto& abi_abstract_type = AbstractType::Handle(
539 zone, AbstractType::RawCast(native_types.At(abi_index)));
540 if (abi_abstract_type.IsNull()) {
541 *error = zone->PrintToString(
542 "AbiSpecificInteger '%s' is missing mapping for '%s'.",
543 abi_specific_int.UserVisibleNameCString(), target_abi_name);
544 return nullptr;
545 }
546 return NativeType::FromAbstractType(zone, abi_abstract_type, error);
547}
548
550 const AbstractType& type,
551 const char** error) {
552 const classid_t class_id = type.type_class_id();
553 if (IsFfiPredefinedClassId(class_id)) {
554 return &NativeType::FromTypedDataClassId(zone, class_id);
555 }
556
557 // User-defined structs, unions, or Abi-specific integers.
558 const auto& cls = Class::Handle(zone, type.type_class());
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 =
565 String::Handle(zone, superClass.UserVisibleName())
566 .Equals(Symbols::AbiSpecificInteger());
567 RELEASE_ASSERT(is_struct || is_union || is_abi_specific_int);
568
569 auto& pragmas = Object::Handle(zone);
570 String& pragma_name = String::Handle(zone);
571 if (is_struct || is_union) {
572 pragma_name = Symbols::vm_ffi_struct_fields().ptr();
573 } else {
574 ASSERT(is_abi_specific_int);
575 pragma_name = Symbols::vm_ffi_abi_specific_mapping().ptr();
576 }
577 Library::FindPragma(dart::Thread::Current(), /*only_core=*/false, cls,
578 pragma_name, /*multiple=*/true, &pragmas);
579 ASSERT(!pragmas.IsNull());
580 ASSERT(pragmas.IsGrowableObjectArray());
581 const auto& pragmas_array = GrowableObjectArray::Cast(pragmas);
582 auto& pragma = Instance::Handle(zone);
583 auto& clazz = Class::Handle(zone);
584 auto& library = Library::Handle(zone);
585 String& class_symbol = String::Handle(zone);
586 if (is_struct || is_union) {
587 class_symbol = Symbols::FfiStructLayout().ptr();
588 } else {
589 ASSERT(is_abi_specific_int);
590 class_symbol = Symbols::FfiAbiSpecificMapping().ptr();
591 }
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) &&
597 String::Handle(zone, library.url()).Equals(Symbols::DartFfi())) {
598 break;
599 }
600 }
601
602 if (is_struct || is_union) {
603 return CompoundFromPragma(zone, pragma, is_struct, error);
604 }
605 ASSERT(is_abi_specific_int);
606 return AbiSpecificFromPragma(zone, pragma, cls, error);
607}
608#endif
609
610#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
612 switch (rep) {
613 case kUnboxedDouble:
614 return kDouble;
615 case kUnboxedFloat:
616 return kFloat;
617 case kUnboxedInt32:
618 return kInt32;
619 case kUnboxedUint32:
620 return kUint32;
621 case kUnboxedInt64:
622 return kInt64;
623 case kUntagged:
624 case kTagged:
625 return TypeRepresentation(kPointerCid);
626 default:
627 break;
628 }
629 FATAL("Unhandled representation %u", rep);
630}
631
633 Representation rep) {
634 return *new (zone) NativePrimitiveType(fundamental_rep(rep));
635}
636
638 Zone* zone,
639 Representation return_representation,
640 const ZoneGrowableArray<Representation>& argument_representations) {
641 const auto& return_type =
642 NativePrimitiveType::FromRepresentation(zone, return_representation);
643 auto& argument_types =
645 zone, argument_representations.length());
646 for (intptr_t i = 0; i < argument_representations.length(); i++) {
648 zone, argument_representations.At(i)));
649 }
651}
652#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
653
654const char* NativeType::ToCString(Zone* zone,
655 bool multi_line,
656 bool verbose) const {
657 ZoneTextBuffer textBuffer(zone);
658 PrintTo(&textBuffer, multi_line, verbose);
659 return textBuffer.buffer();
660}
661
662#if !defined(FFI_UNIT_TESTS)
663const char* NativeType::ToCString() const {
664 return ToCString(Thread::Current()->zone());
665}
666#endif
667
668static const char* PrimitiveTypeToCString(PrimitiveType rep) {
669 switch (rep) {
670 case kInt8:
671 return "int8";
672 case kUint8:
673 return "uint8";
674 case kInt16:
675 return "int16";
676 case kUint16:
677 return "uint16";
678 case kInt32:
679 return "int32";
680 case kUint32:
681 return "uint32";
682 case kInt64:
683 return "int64";
684 case kUint64:
685 return "uint64";
686 case kFloat:
687 return "float";
688 case kDouble:
689 return "double";
690 case kHalfDouble:
691 return "half-double";
692 case kInt24:
693 return "int24";
694 case kUint24:
695 return "uint24";
696 case kInt40:
697 return "int40";
698 case kUint40:
699 return "uint40";
700 case kInt48:
701 return "int48";
702 case kUint48:
703 return "uint48";
704 case kInt56:
705 return "int56";
706 case kUint56:
707 return "uint56";
708 case kVoid:
709 return "void";
710 default:
711 UNREACHABLE();
712 }
713}
714
716 bool multi_line,
717 bool verbose) const {
718 f->AddString("I");
719}
720
722 bool multi_line,
723 bool verbose) const {
724 f->Printf("%s", PrimitiveTypeToCString(representation_));
725}
726
727const char* NativeFunctionType::ToCString(Zone* zone) const {
728 ZoneTextBuffer textBuffer(zone);
729 PrintTo(&textBuffer);
730 return textBuffer.buffer();
731}
732
734 bool multi_line,
735 bool verbose) const {
736 f->AddString("Array(");
737 f->Printf("element type: ");
738 element_type_.PrintTo(f, /*multi_line*/ false, verbose);
739 f->Printf(", length: %" Pd "", length_);
740 f->AddString(")");
741}
742
744 bool multi_line,
745 bool verbose) const {
747 f->AddString("(");
748 f->Printf("size: %" Pd "", SizeInBytes());
749 if (verbose) {
750 f->Printf(", field alignment: %" Pd ", ", AlignmentInBytesField());
751 f->Printf("stack alignment: %" Pd ", ", AlignmentInBytesStack());
752 f->AddString("members: {");
753 if (multi_line) {
754 f->AddString("\n ");
755 }
756 for (intptr_t i = 0; i < members_.length(); i++) {
757 if (i > 0) {
758 if (multi_line) {
759 f->AddString(",\n ");
760 } else {
761 f->AddString(", ");
762 }
763 }
765 members_[i]->PrintTo(f);
766 }
767 if (multi_line) {
768 f->AddString("\n");
769 }
770 f->AddString("}");
771 }
772 f->AddString(")");
773 if (multi_line) {
774 f->AddString("\n");
775 }
776}
777
779 f->AddString("Struct");
780}
781
783 f->AddString("Union");
784}
785
787 intptr_t member_index) const {
788 f->Printf("%" Pd ": ", member_offsets_[member_index]);
789}
790
791#if !defined(FFI_UNIT_TESTS)
792const char* NativeFunctionType::ToCString() const {
793 return ToCString(Thread::Current()->zone());
794}
795#endif
796
798 f->AddString("(");
799 for (intptr_t i = 0; i < argument_types_.length(); i++) {
800 if (i > 0) {
801 f->AddString(", ");
802 }
803 if (i == variadic_arguments_index_) {
804 f->AddString("varargs: ");
805 }
806 argument_types_[i]->PrintTo(f);
807 }
808 f->AddString(") => ");
809 return_type_.PrintTo(f);
810}
811
813 return 1;
814}
815
817 return element_type_.NumPrimitiveMembersRecursive() * length_;
818}
819
821 intptr_t count = 0;
822 for (intptr_t i = 0; i < members_.length(); i++) {
823 count += members_[i]->NumPrimitiveMembersRecursive();
824 }
825 return count;
826}
827
829 intptr_t count = 0;
830 for (intptr_t i = 0; i < members_.length(); i++) {
832 }
833 return count;
834}
835
837 return *this;
838}
839
841 return element_type_.FirstPrimitiveMember();
842}
843
846 for (intptr_t i = 0; i < members().length(); i++) {
848 return members_[i]->FirstPrimitiveMember();
849 }
850 }
852}
853
855 const NativePrimitiveType** first,
856 const NativePrimitiveType** second,
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;
861}
862
864 const NativePrimitiveType** first,
865 const NativePrimitiveType** second,
866 intptr_t offset_in_members) const {
867 for (intptr_t i = 0; i < length_; i++) {
868 offset_in_members =
869 element_type_.PrimitivePairMembers(first, second, offset_in_members);
870 }
871 return offset_in_members;
872}
873
875 const NativePrimitiveType** first,
876 const NativePrimitiveType** second,
877 intptr_t offset_in_members) const {
878 for (intptr_t i = 0; i < members().length(); i++) {
879 offset_in_members =
880 members_[i]->PrimitivePairMembers(first, second, offset_in_members);
881 }
882 return offset_in_members;
883}
884
885#if !defined(DART_PRECOMPILED_RUNTIME)
887 const auto this_range = Range::StartAndEnd(0, SizeInBytes());
888 ASSERT(this_range.Contains(range));
889
890 return IsFloat();
891}
892
894 const auto this_range = Range::StartAndEnd(0, SizeInBytes());
895 ASSERT(this_range.Contains(range));
896
897 const intptr_t element_size_in_bytes = element_type_.SizeInBytes();
898
899 // Assess how many elements are (partially) covered by the range.
900 const intptr_t first_element_start = range.start() / element_size_in_bytes;
901 const intptr_t last_element_index =
902 range.end_inclusive() / element_size_in_bytes;
903 const intptr_t num_elements = last_element_index - first_element_start + 1;
904 ASSERT(num_elements >= 1);
905
906 if (num_elements > 2) {
907 // At least one full element covered.
908 return element_type_.ContainsOnlyFloats(
909 Range::StartAndLength(0, element_size_in_bytes));
910 }
911
912 // Check first element, which falls (partially) in range.
913 const intptr_t first_start = first_element_start * element_size_in_bytes;
914 const auto first_range =
915 Range::StartAndLength(first_start, element_size_in_bytes);
916 const auto first_range_clipped = range.Intersect(first_range);
917 const auto range_in_first = first_range_clipped.Translate(-first_start);
918 if (!element_type_.ContainsOnlyFloats(range_in_first)) {
919 // First element contains not only floats in specified range.
920 return false;
921 }
922
923 if (num_elements == 2) {
924 // Check the second (and last) element, which falls (partially) in range.
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 =
928 Range::StartAndLength(second_start, element_size_in_bytes);
929 const auto second_range_clipped = range.Intersect(second_range);
930 const auto range_in_second = second_range_clipped.Translate(-second_start);
931 return element_type_.ContainsOnlyFloats(range_in_second);
932 }
933
934 return true;
935}
936
938 const auto this_range = Range::StartAndEnd(0, SizeInBytes());
939 ASSERT(this_range.Contains(range));
940
941 for (intptr_t i = 0; i < members_.length(); i++) {
942 const auto& member = *members_[i];
943 const intptr_t member_offset = member_offsets_[i];
944 const intptr_t member_size = member.SizeInBytes();
945 const auto member_range = Range::StartAndLength(member_offset, member_size);
946 if (range.Overlaps(member_range)) {
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)) {
951 // Member contains not only floats in specified range.
952 return false;
953 }
954 }
955 if (member_range.After(range)) {
956 // None of the remaining members fits the range.
957 break;
958 }
959 }
960 return true;
961}
962
964 for (intptr_t i = 0; i < members_.length(); i++) {
965 const auto& member = *members_[i];
966 const intptr_t member_size = member.SizeInBytes();
967 const auto member_range = Range::StartAndLength(0, member_size);
968 if (member_range.Overlaps(range)) {
969 const auto member_range_clipped = member_range.Intersect(range);
970 if (!member.ContainsOnlyFloats(member_range_clipped)) {
971 return false;
972 }
973 }
974 }
975 return true;
976}
977
979 // O(n^2) implementation, but only invoked for small structs.
980 ASSERT(SizeInBytes() <= 16);
981 const auto this_range = Range::StartAndEnd(0, SizeInBytes());
982 const intptr_t size = SizeInBytes();
983 intptr_t float_only_chunks = 0;
984 for (intptr_t offset = 0; offset < size;
986 const auto chunk_range =
988 if (ContainsOnlyFloats(chunk_range.Intersect(this_range))) {
989 float_only_chunks++;
990 }
991 }
992 return float_only_chunks;
993}
994
996 const intptr_t total_chunks =
999 return total_chunks - NumberOfWordSizeChunksOnlyFloat();
1000}
1001#endif // !defined(DART_PRECOMPILED_RUNTIME)
1002
1004 return offset % AlignmentInBytesField() != 0;
1005}
1006
1008 const intptr_t element_size = element_type_.SizeInBytes();
1009 // We're only checking the first two elements of the array.
1010 //
1011 // If the element size is divisible by the alignment of the largest type
1012 // contained within the element type, the alignment of all elements is the
1013 // same. If not, either the first or the second element is unaligned.
1014 const intptr_t max_check = 2;
1015 for (intptr_t i = 0; i < Utils::Minimum(length_, max_check); i++) {
1016 const intptr_t element_offset = i * element_size;
1017 if (element_type_.ContainsUnalignedMembers(offset + element_offset)) {
1018 return true;
1019 }
1020 }
1021 return false;
1022}
1023
1025 for (intptr_t i = 0; i < members_.length(); i++) {
1026 const auto& member = *members_.At(i);
1027 const intptr_t member_offset = member_offsets_.At(i);
1028 if (member.ContainsUnalignedMembers(offset + member_offset)) {
1029 return true;
1030 }
1031 }
1032 return false;
1033}
1034
1036 for (intptr_t i = 0; i < members_.length(); i++) {
1037 const auto& member = *members_.At(i);
1038 if (member.ContainsUnalignedMembers(offset)) {
1039 return true;
1040 }
1041 }
1042 return false;
1043}
1044
1046 bool* only_float,
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 =
1051 type.IsArray() ? type.AsArray().element_type() : type;
1052 if (member_type.IsPrimitive()) {
1053 PrimitiveType type = member_type.AsPrimitive().representation();
1054 *only_float = *only_float && (type == kFloat);
1055 *only_double = *only_double && (type == kDouble);
1056 }
1057 if (member_type.IsCompound()) {
1058 ContainsHomogeneousFloatsRecursive(member_type.AsCompound().members(),
1059 only_float, only_double);
1060 }
1061 }
1062}
1063
1065 bool only_float = true;
1066 bool only_double = true;
1067 ContainsHomogeneousFloatsRecursive(types, &only_float, &only_double);
1068 return (only_double || only_float) && types.length() > 0;
1069}
1070
1073}
1074
1075#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
1077 if (IsPrimitive()) {
1078 switch (AsPrimitive().representation()) {
1079 case kInt24:
1080 return kUnboxedInt32;
1081 case kUint24:
1082 return kUnboxedUint32;
1083 case kInt40:
1084 case kUint40:
1085 case kInt48:
1086 case kUint48:
1087 case kInt56:
1088 case kUint56:
1089 return kUnboxedInt64;
1090 default:
1091 break;
1092 }
1093 }
1094 const auto& widened = WidenTo4Bytes(zone_);
1095 return widened.AsRepresentation();
1096}
1097#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
1098
1100 if (IsInt() && SizeInBytes() <= 2) {
1101 if (IsSigned()) {
1102 return *new (zone) NativePrimitiveType(kInt32);
1103 } else {
1104 return *new (zone) NativePrimitiveType(kUint32);
1105 }
1106 }
1107 return *this;
1108}
1109
1111 if (IsInt() && SizeInBytes() <= 4) {
1112 if (IsSigned()) {
1113 return *new (zone) NativePrimitiveType(kInt64);
1114 } else {
1115 return *new (zone) NativePrimitiveType(kUint64);
1116 }
1117 }
1118 return *this;
1119}
1120
1121} // namespace ffi
1122
1123} // namespace compiler
1124
1125} // namespace dart
int count
Definition: FontMgrTest.cpp:50
static void Union(SkRegion *rgn, const SkIRect &rect)
Definition: RegionTest.cpp:27
static size_t element_size(Layout layout, SkSLType type)
#define UNREACHABLE()
Definition: assert.h:248
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
GLenum type
void Add(const T &value)
const T & At(intptr_t index) const
intptr_t length() const
char * buffer() const
Definition: text_buffer.h:35
static constexpr AlignmentStrategy kFieldAlignment
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs
static constexpr AlignmentStrategy kArgumentStackAlignment
const char * UserVisibleNameCString() const
Definition: object.cc:2998
ObjectPtr GetField(const Field &field) const
Definition: object.cc:20475
static bool FindPragma(Thread *T, bool only_core, const Object &object, const String &pragma_name, bool multiple=false, Object *options=nullptr)
Definition: object.cc:4151
ObjectPtr ptr() const
Definition: object.h:332
static Object & Handle()
Definition: object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition: object.h:325
ClassPtr clazz() const
Definition: object.h:13218
static Thread * Current()
Definition: thread.h:362
static constexpr T Maximum(T x, T y)
Definition: utils.h:41
static T Minimum(T x, T y)
Definition: utils.h:36
static constexpr T RoundUp(T x, uintptr_t alignment, uintptr_t offset=0)
Definition: utils.h:120
char * PrintToString(const char *format,...) PRINTF_ATTRIBUTE(2
Definition: zone.cc:313
virtual void PrintTo(BaseTextBuffer *f, bool multi_line=false, bool verbose=true) const
Definition: native_type.cc:733
virtual intptr_t SizeInBytes() const
Definition: native_type.h:283
virtual bool Equals(const NativeType &other) const
Definition: native_type.cc:350
virtual bool ContainsOnlyFloats(Range range) const
Definition: native_type.cc:893
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
Definition: native_type.cc:863
virtual const NativePrimitiveType & FirstPrimitiveMember() const
Definition: native_type.cc:840
virtual intptr_t NumPrimitiveMembersRecursive() const
Definition: native_type.cc:816
virtual intptr_t NumPrimitiveMembersRecursive() const =0
const NativeTypes & members() const
Definition: native_type.h:321
virtual bool Equals(const NativeType &other) const
Definition: native_type.cc:358
virtual intptr_t SizeInBytes() const
Definition: native_type.h:325
intptr_t NumberOfWordSizeChunksOnlyFloat() const
Definition: native_type.cc:978
virtual intptr_t AlignmentInBytesStack(bool is_vararg=false) const
Definition: native_type.h:327
virtual intptr_t PrimitivePairMembers(const NativePrimitiveType **first, const NativePrimitiveType **second, intptr_t offset_in_members=0) const
Definition: native_type.cc:874
virtual const NativePrimitiveType & FirstPrimitiveMember() const
Definition: native_type.cc:844
virtual bool ContainsOnlyFloats(Range range) const =0
intptr_t NumberOfWordSizeChunksNotOnlyFloat() const
Definition: native_type.cc:995
virtual void PrintMemberOffset(BaseTextBuffer *f, intptr_t member_index) const
Definition: native_type.h:381
virtual intptr_t AlignmentInBytesField() const
Definition: native_type.h:326
virtual void PrintTo(BaseTextBuffer *f, bool multi_line=false, bool verbose=true) const
Definition: native_type.cc:743
virtual void PrintCompoundType(BaseTextBuffer *f) const =0
static const NativeFunctionType * FromRepresentations(Zone *zone, Representation return_representation, const ZoneGrowableArray< Representation > &argument_representations)
Definition: native_type.cc:637
const NativeTypes & argument_types() const
Definition: native_type.h:474
void PrintTo(BaseTextBuffer *f) const
Definition: native_type.cc:797
const NativeType & return_type() const
Definition: native_type.h:475
NativeFunctionType(const NativeTypes &argument_types, const NativeType &return_type, intptr_t variadic_arguments_index=kNoVariadicArguments)
Definition: native_type.h:460
virtual Representation AsRepresentation() const
Definition: native_type.cc:313
virtual const NativePrimitiveType & FirstPrimitiveMember() const
Definition: native_type.cc:836
virtual NativePrimitiveType & Split(Zone *zone, intptr_t part) const
Definition: native_type.cc:396
virtual bool ContainsOnlyFloats(Range range) const
Definition: native_type.cc:886
virtual bool Equals(const NativeType &other) const
Definition: native_type.cc:343
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
Definition: native_type.cc:854
virtual bool IsExpressibleAsRepresentation() const
Definition: native_type.cc:284
virtual intptr_t NumPrimitiveMembersRecursive() const
Definition: native_type.cc:812
virtual intptr_t AlignmentInBytesStack(bool is_vararg=false) const
Definition: native_type.cc:154
virtual intptr_t AlignmentInBytesField() const
Definition: native_type.cc:174
virtual void PrintTo(BaseTextBuffer *f, bool multi_line=false, bool verbose=true) const
Definition: native_type.cc:721
virtual intptr_t SizeInBytes() const
Definition: native_type.cc:150
virtual bool ContainsOnlyFloats(Range range) const
Definition: native_type.cc:937
static NativeStructType & FromNativeTypes(Zone *zone, const NativeTypes &members, intptr_t member_packing=kMaxInt32)
Definition: native_type.cc:196
virtual bool ContainsUnalignedMembers(intptr_t offset=0) const
virtual void PrintMemberOffset(BaseTextBuffer *f, intptr_t member_index) const
Definition: native_type.cc:786
virtual intptr_t NumPrimitiveMembersRecursive() const
Definition: native_type.cc:820
virtual void PrintCompoundType(BaseTextBuffer *f) const
Definition: native_type.cc:778
const ZoneGrowableArray< intptr_t > & member_offsets() const
Definition: native_type.h:392
const NativeCompoundType & AsCompound() const
Definition: native_type.cc:56
Representation AsRepresentationOverApprox(Zone *zone_) const
virtual bool IsInt() const
Definition: native_type.h:89
static const NativeType * FromAbstractType(Zone *zone, const AbstractType &type, const char **error)
Definition: native_type.cc:549
virtual bool IsCompound() const
Definition: native_type.h:84
virtual void PrintTo(BaseTextBuffer *f, bool multi_line=false, bool verbose=true) const
Definition: native_type.cc:715
virtual intptr_t PrimitivePairMembers(const NativePrimitiveType **first, const NativePrimitiveType **second, intptr_t offset_in_members=0) const =0
virtual bool IsSigned() const
Definition: native_type.h:93
const NativeArrayType & AsArray() const
Definition: native_type.cc:51
const NativePrimitiveType & AsPrimitive() const
Definition: native_type.cc:46
const char * ToCString() const
Definition: native_type.cc:663
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
Definition: native_type.h:82
const NativeType & WidenTo4Bytes(Zone *zone) const
virtual bool ContainsOnlyFloats(Range range) const =0
virtual bool IsPrimitive() const
Definition: native_type.h:80
const NativeType & WidenTo8Bytes(Zone *zone) const
static const NativeType & FromTypedDataClassId(Zone *zone, classid_t class_id)
Definition: native_type.cc:435
static NativePrimitiveType & FromRepresentation(Zone *zone, Representation rep)
Definition: native_type.cc:632
virtual intptr_t AlignmentInBytesField() const =0
virtual bool IsStruct() const
Definition: native_type.h:86
virtual bool ContainsUnalignedMembers(intptr_t offset=0) const =0
virtual bool Equals(const NativeType &other) const
Definition: native_type.h:127
const NativeStructType & AsStruct() const
Definition: native_type.cc:61
virtual intptr_t NumPrimitiveMembersRecursive() const =0
static NativeUnionType & FromNativeTypes(Zone *zone, const NativeTypes &members)
Definition: native_type.cc:256
virtual bool ContainsUnalignedMembers(intptr_t offset=0) const
virtual intptr_t NumPrimitiveMembersRecursive() const
Definition: native_type.cc:828
virtual void PrintCompoundType(BaseTextBuffer *f) const
Definition: native_type.cc:782
virtual bool ContainsOnlyFloats(Range range) const
Definition: native_type.cc:963
static Range StartAndLength(intptr_t start_inclusive, intptr_t length)
Definition: range.h:28
intptr_t start() const
Definition: range.h:39
const Range Intersect(const Range &other) const
Definition: range.h:68
bool Overlaps(const Range &other) const
Definition: range.h:61
static Range StartAndEnd(intptr_t start_inclusive, intptr_t end_exclusive)
Definition: range.h:35
intptr_t end_inclusive() const
Definition: range.h:41
const Range Translate(intptr_t delta) const
Definition: range.h:77
#define ASSERT(E)
#define FATAL(error)
const uint8_t uint32_t uint32_t GError ** error
size_t length
PrimitiveType PrimitiveTypeFromSizeInBytes(intptr_t size)
Definition: native_type.cc:29
static const char * PrimitiveTypeToCString(PrimitiveType rep)
Definition: native_type.cc:668
static const intptr_t fundamental_size_in_bytes[kVoid+1]
Definition: native_type.cc:127
static PrimitiveType split_fundamental(PrimitiveType in)
Definition: native_type.cc:375
static const NativeType * CompoundFromPragma(Zone *zone, const Instance &pragma, bool is_struct, const char **error)
Definition: native_type.cc:443
const int64_t num_abis
Definition: abi.h:47
static bool ContainsHomogeneousFloatsInternal(const NativeTypes &types)
const char * target_abi_name
Definition: abi.cc:92
static PrimitiveType TypeRepresentation(classid_t class_id)
Definition: native_type.cc:403
static PrimitiveType fundamental_rep(Representation rep)
Definition: native_type.cc:611
Abi TargetAbi()
Definition: abi.cc:88
constexpr PrimitiveType kAddress
Definition: native_type.h:210
static const NativeType * AbiSpecificFromPragma(Zone *zone, const Instance &pragma, const Class &abi_specific_int, const char **error)
Definition: native_type.cc:522
static void ContainsHomogeneousFloatsRecursive(const NativeTypes &types, bool *only_float, bool *only_double)
static constexpr intptr_t kWordSize
Definition: runtime_api.h:274
Definition: dart_vm.cc:33
bool IsFfiPredefinedClassId(classid_t class_id)
Definition: class_id.h:527
int32_t classid_t
Definition: globals.h:524
Representation
Definition: locations.h:66
constexpr int32_t kMaxInt32
Definition: globals.h:483
static constexpr Representation kUnboxedIntPtr
Definition: locations.h:176
@ kAlignedToWordSizeAndValueSize
@ kAlignedToValueSizeBut8AlignedTo4
@ kAlignedToValueSize
@ kAlignedToWordSize
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
#define UNREACHABLE_THIS()
Definition: native_type.h:25
#define Pd
Definition: globals.h:408
SeparatedVector2 offset