Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
native_type.h
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
5#ifndef RUNTIME_VM_COMPILER_FFI_NATIVE_TYPE_H_
6#define RUNTIME_VM_COMPILER_FFI_NATIVE_TYPE_H_
7
8#include "platform/assert.h"
9#include "platform/globals.h"
10#include "vm/allocation.h"
11#include "vm/constants_base.h"
12#include "vm/growable_array.h"
13
14#if !defined(DART_PRECOMPILED_RUNTIME)
16#endif
17#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
19#endif
20#if !defined(FFI_UNIT_TESTS)
21#include "vm/object.h"
22#endif
23
24#if !defined(FFI_UNIT_TESTS)
25#define UNREACHABLE_THIS() FATAL("Unreachable code with: %s", ToCString())
26#else
27// No Zone-less ToCString() in tests.
28#define UNREACHABLE_THIS() UNREACHABLE()
29#endif
30
31namespace dart {
32
33class BaseTextBuffer;
34
35namespace compiler {
36
37namespace ffi {
38
39class NativePrimitiveType;
40class NativeArrayType;
41class NativeCompoundType;
42class NativeStructType;
43
44// NativeTypes are the types used in calling convention specifications:
45// integers, floats, and compounds.
46//
47// NativeTypes exclude C types which are not discussed in calling conventions:
48// pointer types (they are lowered to integers).
49//
50// The NativeTypes are a partially overlapping with unboxed Representations.
51// NativeTypes do not have Dart representations such as the following:
52// * tagged
53// * untagged
54//
55// Instead, NativeTypes support representations not supported in Dart's unboxed
56// Representations, such as:
57// * Primitive types (https://en.cppreference.com/w/cpp/language/types):
58// * int8_t
59// * int16_t
60// * uint8_t
61// * uint16t
62// * void
63// * Compound types (https://en.cppreference.com/w/cpp/language/type):
64// * Struct
65// * Union
66class NativeType : public ZoneAllocated {
67 public:
68#if !defined(FFI_UNIT_TESTS)
69 static const NativeType* FromAbstractType(Zone* zone,
70 const AbstractType& type,
71 const char** error);
72#endif
73 static const NativeType& FromTypedDataClassId(Zone* zone, classid_t class_id);
74
75#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
77 Representation rep);
78#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
79
80 virtual bool IsPrimitive() const { return false; }
81 const NativePrimitiveType& AsPrimitive() const;
82 virtual bool IsArray() const { return false; }
83 const NativeArrayType& AsArray() const;
84 virtual bool IsCompound() const { return false; }
85 const NativeCompoundType& AsCompound() const;
86 virtual bool IsStruct() const { return false; }
87 const NativeStructType& AsStruct() const;
88
89 virtual bool IsInt() const { return false; }
90 virtual bool IsFloat() const { return false; }
91 virtual bool IsVoid() const { return false; }
92
93 virtual bool IsSigned() const { return false; }
94
95 // The size in bytes of this representation.
96 //
97 // Does not take into account padding required if repeating.
98 virtual intptr_t SizeInBytes() const = 0;
99
100 // The alignment in bytes of this representation on the stack.
101 virtual intptr_t AlignmentInBytesStack(bool is_vararg = false) const = 0;
102
103 // The alignment in bytes of this representation as member of a composite.
104 virtual intptr_t AlignmentInBytesField() const = 0;
105
106#if !defined(DART_PRECOMPILED_RUNTIME)
107 // Returns true iff a range within this type contains only floats.
108 //
109 // Useful for determining whether struct is passed in FP registers on x64.
110 virtual bool ContainsOnlyFloats(Range range) const = 0;
111#endif // !defined(DART_PRECOMPILED_RUNTIME)
112
113 // True iff any members are misaligned recursively due to packing.
114 virtual bool ContainsUnalignedMembers(intptr_t offset = 0) const = 0;
115
116#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
117 // NativeTypes which are available as unboxed Representations.
118 virtual bool IsExpressibleAsRepresentation() const { return false; }
119
120 // Unboxed Representation if it exists.
122
123 // Unboxed Representation, over approximates if needed.
125#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
126
127 virtual bool Equals(const NativeType& other) const { UNREACHABLE_THIS(); }
128
129 // Split representation in two.
130 virtual NativeType& Split(Zone* zone, intptr_t index) const {
132 }
133
134 // If this is a 8 or 16 bit int, returns a 32 bit container.
135 // Otherwise, return original representation.
136 const NativeType& WidenTo4Bytes(Zone* zone) const;
137 // If this is a 8, 16 or 32 bit int, returns a 64 bit container.
138 // Otherwise, return original representation.
139 const NativeType& WidenTo8Bytes(Zone* zone) const;
140 const NativeType& Extend(Zone* zone, ExtensionStrategy extension) const {
141 switch (extension) {
142 case kNotExtended:
143 return *this;
144 case kExtendedTo4:
145 return WidenTo4Bytes(zone);
146 case kExtendedTo8:
147 return WidenTo8Bytes(zone);
148 default:
149 UNREACHABLE();
150 }
151 }
152
153 virtual void PrintTo(BaseTextBuffer* f,
154 bool multi_line = false,
155 bool verbose = true) const;
156 const char* ToCString(Zone* zone,
157 bool multi_line = false,
158 bool verbose = true) const;
159#if !defined(FFI_UNIT_TESTS)
160 const char* ToCString() const;
161#endif
162
163 virtual intptr_t NumPrimitiveMembersRecursive() const = 0;
164 virtual const NativePrimitiveType& FirstPrimitiveMember() const = 0;
165
166 // Returns the number of primitive members when this aggregate is flattened
167 // out, and sets the out-parameters to the first two such primitive members.
168 virtual intptr_t PrimitivePairMembers(
169 const NativePrimitiveType** first,
170 const NativePrimitiveType** second,
171 intptr_t offset_in_members = 0) const = 0;
172
173 virtual ~NativeType() {}
174
175 protected:
177};
178
190 kHalfDouble, // When doubles are split over two 32 bit locations.
200 // TODO(37470): Add packed data structures.
201};
202
203// Used for the type representation of kUntagged (Pointer, where the untagged
204// pointer in the data field is extracted by IL) and kTagged (Handle, turned
205// into untagged pointers to the stack during the FfiCall) values. Should
206// be kept consistent with the Representation kUnboxedAddress.
207#if defined(TARGET_ARCH_IS_32_BIT)
208constexpr PrimitiveType kAddress = kUint32;
209#else
211#endif
212
214
215// Represents a primitive native type.
216//
217// These are called object types in the C standard (ISO/IEC 9899:2011) and
218// fundamental types in C++ (https://en.cppreference.com/w/cpp/language/types)
219// but more commonly these are called primitive types
220// (https://en.wikipedia.org/wiki/Primitive_data_type).
222 public:
223 explicit NativePrimitiveType(PrimitiveType rep) : representation_(rep) {}
224
225 PrimitiveType representation() const { return representation_; }
226
227 virtual bool IsPrimitive() const { return true; }
228
229 virtual bool IsInt() const;
230 virtual bool IsFloat() const;
231 virtual bool IsVoid() const;
232
233 virtual bool IsSigned() const;
234
235 virtual intptr_t SizeInBytes() const;
236 virtual intptr_t AlignmentInBytesStack(bool is_vararg = false) const;
237 virtual intptr_t AlignmentInBytesField() const;
238
239#if !defined(DART_PRECOMPILED_RUNTIME)
240 virtual bool ContainsOnlyFloats(Range range) const;
241#endif // !defined(DART_PRECOMPILED_RUNTIME)
242
243 virtual bool ContainsUnalignedMembers(intptr_t offset = 0) const;
244
245#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
246 virtual bool IsExpressibleAsRepresentation() const;
247 virtual Representation AsRepresentation() const;
248#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
249
250 virtual bool Equals(const NativeType& other) const;
251 virtual NativePrimitiveType& Split(Zone* zone, intptr_t part) const;
252
253 virtual void PrintTo(BaseTextBuffer* f,
254 bool multi_line = false,
255 bool verbose = true) const;
256
257 virtual intptr_t NumPrimitiveMembersRecursive() const;
258 virtual const NativePrimitiveType& FirstPrimitiveMember() const;
259 virtual intptr_t PrimitivePairMembers(const NativePrimitiveType** first,
260 const NativePrimitiveType** second,
261 intptr_t offset_in_members = 0) const;
262
264
265 private:
266 const PrimitiveType representation_;
267};
268
269// Fixed-length arrays.
271 public:
273 : element_type_(element_type), length_(length) {
275 ASSERT(length > 0);
276 }
277
278 const NativeType& element_type() const { return element_type_; }
279 intptr_t length() const { return length_; }
280
281 virtual bool IsArray() const { return true; }
282
283 virtual intptr_t SizeInBytes() const {
284 return element_type_.SizeInBytes() * length_;
285 }
286 virtual intptr_t AlignmentInBytesField() const {
287 return element_type_.AlignmentInBytesField();
288 }
289 virtual intptr_t AlignmentInBytesStack(bool is_vararg = false) const {
290 return element_type_.AlignmentInBytesStack();
291 }
292
293#if !defined(DART_PRECOMPILED_RUNTIME)
294 virtual bool ContainsOnlyFloats(Range range) const;
295#endif // !defined(DART_PRECOMPILED_RUNTIME)
296
297 virtual bool ContainsUnalignedMembers(intptr_t offset = 0) const;
298
299 virtual bool Equals(const NativeType& other) const;
300
301 virtual void PrintTo(BaseTextBuffer* f,
302 bool multi_line = false,
303 bool verbose = true) const;
304
305 virtual intptr_t NumPrimitiveMembersRecursive() const;
306 virtual const NativePrimitiveType& FirstPrimitiveMember() const;
307 virtual intptr_t PrimitivePairMembers(const NativePrimitiveType** first,
308 const NativePrimitiveType** second,
309 intptr_t offset_in_members = 0) const;
310
311 private:
312 const NativeType& element_type_;
313 const intptr_t length_;
314};
315
317
318// Compound native types: native arrays and native structs.
320 public:
321 const NativeTypes& members() const { return members_; }
322
323 virtual bool IsCompound() const { return true; }
324
325 virtual intptr_t SizeInBytes() const { return size_; }
326 virtual intptr_t AlignmentInBytesField() const { return alignment_field_; }
327 virtual intptr_t AlignmentInBytesStack(bool is_vararg = false) const {
328 return alignment_stack_;
329 }
330
331 virtual bool Equals(const NativeType& other) const;
332
333 virtual void PrintTo(BaseTextBuffer* f,
334 bool multi_line = false,
335 bool verbose = true) const;
336
337#if !defined(DART_PRECOMPILED_RUNTIME)
338 virtual bool ContainsOnlyFloats(Range range) const = 0;
339
340 // Returns how many word-sized chunks _only_ contain floats.
341 //
342 // Useful for determining whether struct is passed in FP registers on x64.
343 intptr_t NumberOfWordSizeChunksOnlyFloat() const;
344
345 // Returns how many word-sized chunks do not _only_ contain floats.
346 //
347 // Useful for determining whether struct is passed in FP registers on x64.
348 intptr_t NumberOfWordSizeChunksNotOnlyFloat() const;
349#endif // !defined(DART_PRECOMPILED_RUNTIME)
350
351 virtual bool ContainsUnalignedMembers(intptr_t offset = 0) const = 0;
352
353 // Whether this type has only same-size floating point members.
354 //
355 // Useful for determining whether struct is passed in FP registers in hardfp
356 // and arm64.
357 bool ContainsHomogeneousFloats() const;
358
359 virtual intptr_t NumPrimitiveMembersRecursive() const = 0;
360 virtual const NativePrimitiveType& FirstPrimitiveMember() const;
361 virtual intptr_t PrimitivePairMembers(const NativePrimitiveType** first,
362 const NativePrimitiveType** second,
363 intptr_t offset_in_members = 0) const;
364
365 protected:
367 intptr_t size,
368 intptr_t alignment_field,
369 intptr_t alignment_stack)
370 : members_(members),
371 size_(size),
372 alignment_field_(alignment_field),
373 alignment_stack_(alignment_stack) {}
374
376 const intptr_t size_;
377 const intptr_t alignment_field_;
378 const intptr_t alignment_stack_;
379
380 virtual void PrintCompoundType(BaseTextBuffer* f) const = 0;
382 intptr_t member_index) const {}
383};
384
385// Native structs.
387 public:
389 const NativeTypes& members,
390 intptr_t member_packing = kMaxInt32);
391
393 return member_offsets_;
394 }
395
396 virtual bool IsStruct() const { return true; }
397
398 virtual intptr_t AlignmentInBytesStack(bool is_vararg = false) const {
399 if (is_vararg) {
400 return alignment_stack_vararg_;
401 }
402 return alignment_stack_;
403 }
404
405#if !defined(DART_PRECOMPILED_RUNTIME)
406 virtual bool ContainsOnlyFloats(Range range) const;
407#endif // !defined(DART_PRECOMPILED_RUNTIME)
408
409 virtual bool ContainsUnalignedMembers(intptr_t offset = 0) const;
410
411 virtual intptr_t NumPrimitiveMembersRecursive() const;
412
413 protected:
414 virtual void PrintCompoundType(BaseTextBuffer* f) const;
415 virtual void PrintMemberOffset(BaseTextBuffer* f,
416 intptr_t member_index) const;
417
418 private:
421 intptr_t size,
422 intptr_t alignment_field,
423 intptr_t alignment_stack,
424 intptr_t alignment_stack_vararg)
425 : NativeCompoundType(members, size, alignment_field, alignment_stack),
426 alignment_stack_vararg_(alignment_stack_vararg),
427 member_offsets_(member_offsets) {}
428
429 const intptr_t alignment_stack_vararg_;
430 const ZoneGrowableArray<intptr_t>& member_offsets_;
431};
432
433// Native unions.
435 public:
437 const NativeTypes& members);
438
439#if !defined(DART_PRECOMPILED_RUNTIME)
440 virtual bool ContainsOnlyFloats(Range range) const;
441#endif // !defined(DART_PRECOMPILED_RUNTIME)
442
443 virtual bool ContainsUnalignedMembers(intptr_t offset = 0) const;
444
445 virtual intptr_t NumPrimitiveMembersRecursive() const;
446
447 protected:
448 virtual void PrintCompoundType(BaseTextBuffer* f) const;
449
450 private:
452 intptr_t size,
453 intptr_t alignment_field,
454 intptr_t alignment_stack)
455 : NativeCompoundType(members, size, alignment_field, alignment_stack) {}
456};
457
459 public:
461 const NativeType& return_type,
463 : argument_types_(argument_types),
464 return_type_(return_type),
465 variadic_arguments_index_(variadic_arguments_index) {}
466
467#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
469 Zone* zone,
470 Representation return_representation,
471 const ZoneGrowableArray<Representation>& argument_representations);
472#endif
473
474 const NativeTypes& argument_types() const { return argument_types_; }
475 const NativeType& return_type() const { return return_type_; }
476 intptr_t variadic_arguments_index() const {
477 return variadic_arguments_index_;
478 }
479
480 void PrintTo(BaseTextBuffer* f) const;
481 const char* ToCString(Zone* zone) const;
482#if !defined(FFI_UNIT_TESTS)
483 const char* ToCString() const;
484#endif
485
486 static constexpr intptr_t kNoVariadicArguments = INTPTR_MAX;
487
488 private:
489 const NativeTypes& argument_types_;
490 const NativeType& return_type_;
491 // If no variadic arguments, then kNoVariadicArguments.
492 const intptr_t variadic_arguments_index_;
493};
494
495} // namespace ffi
496
497} // namespace compiler
498
499} // namespace dart
500
501#endif // RUNTIME_VM_COMPILER_FFI_NATIVE_TYPE_H_
#define UNREACHABLE()
Definition assert.h:248
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 intptr_t AlignmentInBytesStack(bool is_vararg=false) 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 AlignmentInBytesField() const
NativeArrayType(const NativeType &element_type, intptr_t length)
const NativeType & element_type() const
virtual intptr_t NumPrimitiveMembersRecursive() const =0
const NativeTypes & members() const
virtual bool Equals(const NativeType &other) const
NativeCompoundType(const NativeTypes &members, intptr_t size, intptr_t alignment_field, intptr_t alignment_stack)
virtual bool ContainsUnalignedMembers(intptr_t offset=0) const =0
virtual intptr_t SizeInBytes() 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
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
static constexpr intptr_t kNoVariadicArguments
NativeFunctionType(const NativeTypes &argument_types, const NativeType &return_type, intptr_t variadic_arguments_index=kNoVariadicArguments)
virtual Representation AsRepresentation() 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
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 ContainsOnlyFloats(Range range) const
virtual intptr_t AlignmentInBytesStack(bool is_vararg=false) 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
Definition native_type.h:89
static const NativeType * FromAbstractType(Zone *zone, const AbstractType &type, const char **error)
virtual bool IsCompound() const
Definition native_type.h:84
virtual void PrintTo(BaseTextBuffer *f, bool multi_line=false, bool verbose=true) const
virtual bool IsExpressibleAsRepresentation() const
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
const NativePrimitiveType & AsPrimitive() const
virtual bool IsVoid() const
Definition native_type.h:91
virtual bool IsFloat() const
Definition native_type.h:90
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 Representation AsRepresentation() const
const NativeType & Extend(Zone *zone, ExtensionStrategy extension) const
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)
static NativePrimitiveType & FromRepresentation(Zone *zone, Representation rep)
virtual NativeType & Split(Zone *zone, intptr_t index) const
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
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
#define ASSERT(E)
const uint8_t uint32_t uint32_t GError ** error
PrimitiveType PrimitiveTypeFromSizeInBytes(intptr_t size)
constexpr PrimitiveType kAddress
ExtensionStrategy
@ kExtendedTo4
@ kNotExtended
@ kExtendedTo8
int32_t classid_t
Definition globals.h:524
Representation
Definition locations.h:66
constexpr int32_t kMaxInt32
Definition globals.h:483
#define UNREACHABLE_THIS()
Definition native_type.h:25
Point offset