Flutter Engine
The Flutter Engine
native_type_test.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/syslog.h"
10
11namespace dart {
12namespace compiler {
13namespace ffi {
14
16 const char* name,
17 const NativeTypes& member_types,
18 intptr_t packing = kMaxInt32) {
19 const auto& struct_type =
20 NativeStructType::FromNativeTypes(zone, member_types, packing);
21
22 const char* test_result = struct_type.ToCString(zone, /*multi_line=*/true);
23
24 const int kFilePathLength = 100;
25 char expectation_file_path[kFilePathLength];
26 Utils::SNPrint(expectation_file_path, kFilePathLength,
27 "runtime/vm/compiler/ffi/unit_tests/%s/%s_%s.expect", name,
28 kTargetArchitectureName, kOs);
29
31 Syslog::Print("Updating %s\n", expectation_file_path);
32 WriteToFile(expectation_file_path, test_result);
33 }
34
35 char* expectation_file_contents = nullptr;
36 ReadFromFile(expectation_file_path, &expectation_file_contents);
37 EXPECT_NOTNULL(expectation_file_contents);
38 if (expectation_file_contents != nullptr) {
39 EXPECT_STREQ(expectation_file_contents, test_result);
40 free(expectation_file_contents);
41 }
42
43 return struct_type;
44}
45
47 const auto& native_type = *new (Z) NativePrimitiveType(kInt8);
48
49 EXPECT_EQ(1, native_type.SizeInBytes());
50 EXPECT(native_type.IsInt());
51 EXPECT(native_type.IsPrimitive());
52
53 EXPECT_STREQ("int8", native_type.ToCString(Z));
54}
55
56UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_int8x10) {
57 const auto& int8type = *new (Z) NativePrimitiveType(kInt8);
58
59 auto& members = *new (Z) NativeTypes(Z, 10);
60 members.Add(&int8type);
61 members.Add(&int8type);
62 members.Add(&int8type);
63 members.Add(&int8type);
64 members.Add(&int8type);
65 members.Add(&int8type);
66 members.Add(&int8type);
67 members.Add(&int8type);
68 members.Add(&int8type);
69 members.Add(&int8type);
70
71 const auto& struct_type = RunStructTest(Z, "struct_int8x10", members);
72
73 EXPECT(!struct_type.ContainsHomogeneousFloats());
74 EXPECT(!struct_type.ContainsOnlyFloats(Range::StartAndEnd(0, 8)));
75 EXPECT_EQ(0, struct_type.NumberOfWordSizeChunksOnlyFloat());
76 EXPECT_EQ(
77 Utils::RoundUp(struct_type.SizeInBytes(), compiler::target::kWordSize) /
79 struct_type.NumberOfWordSizeChunksNotOnlyFloat());
80}
81
82UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_floatx4) {
83 const auto& float_type = *new (Z) NativePrimitiveType(kFloat);
84
85 auto& members = *new (Z) NativeTypes(Z, 4);
86 members.Add(&float_type);
87 members.Add(&float_type);
88 members.Add(&float_type);
89 members.Add(&float_type);
90
91 const auto& struct_type = RunStructTest(Z, "struct_floatx4", members);
92
93 // This is a homogenous float in the arm and arm64 ABIs.
94 //
95 // On Arm64 iOS stack alignment of homogenous floats is not word size see
96 // runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_ios.expect.
97 EXPECT(struct_type.ContainsHomogeneousFloats());
98
99 // On x64, 8-byte parts of the chunks contain only floats and will be passed
100 // in FPU registers.
101 EXPECT(struct_type.ContainsOnlyFloats(Range::StartAndEnd(0, 8)));
102 EXPECT(struct_type.ContainsOnlyFloats(Range::StartAndEnd(8, 16)));
103 EXPECT_EQ(struct_type.SizeInBytes() / compiler::target::kWordSize,
104 struct_type.NumberOfWordSizeChunksOnlyFloat());
105 EXPECT_EQ(0, struct_type.NumberOfWordSizeChunksNotOnlyFloat());
106}
107
108// A struct designed to exercise all kinds of alignment rules.
109// Note that offset32A (System V ia32, iOS arm) aligns doubles on 4 bytes while
110// offset32B (Arm 32 bit and MSVC ia32) aligns on 8 bytes.
111// TODO(37271): Support nested structs.
112// TODO(37470): Add uncommon primitive data types when we want to support them.
114 // size32 size64 offset32A offset32B offset64
115 int8_t a; // 1 0 0 0
116 int16_t b; // 2 2 2 2
117 int32_t c; // 4 4 4 4
118 int64_t d; // 8 8 8 8
119 uint8_t e; // 1 16 16 16
120 uint16_t f; // 2 18 18 18
121 uint32_t g; // 4 20 20 20
122 uint64_t h; // 8 24 24 24
123 intptr_t i; // 4 8 32 32 32
124 double j; // 8 36 40 40
125 float k; // 4 44 48 48
126 VeryLargeStruct* parent; // 4 8 48 52 56
127 intptr_t numChildren; // 4 8 52 56 64
128 VeryLargeStruct* children; // 4 8 56 60 72
129 int8_t smallLastField; // 1 60 64 80
130 // sizeof 64 72 88
131};
132
133UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_VeryLargeStruct) {
134 const auto& intptr_type = *new (Z) NativePrimitiveType(
136
137 auto& members = *new (Z) NativeTypes(Z, 15);
138 members.Add(new (Z) NativePrimitiveType(kInt8));
139 members.Add(new (Z) NativePrimitiveType(kInt16));
140 members.Add(new (Z) NativePrimitiveType(kInt32));
141 members.Add(new (Z) NativePrimitiveType(kInt64));
142 members.Add(new (Z) NativePrimitiveType(kUint8));
143 members.Add(new (Z) NativePrimitiveType(kUint16));
144 members.Add(new (Z) NativePrimitiveType(kUint32));
145 members.Add(new (Z) NativePrimitiveType(kUint64));
146 members.Add(&intptr_type);
147 members.Add(new (Z) NativePrimitiveType(kDouble));
148 members.Add(new (Z) NativePrimitiveType(kFloat));
149 members.Add(&intptr_type);
150 members.Add(&intptr_type);
151 members.Add(&intptr_type);
152 members.Add(new (Z) NativePrimitiveType(kInt8));
153
154 RunStructTest(Z, "struct_VeryLargeStruct", members);
155}
156
157UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_int8array) {
158 const auto& int8type = *new (Z) NativePrimitiveType(kInt8);
159 const auto& array_type = *new (Z) NativeArrayType(int8type, 8);
160
161 auto& members = *new (Z) NativeTypes(Z, 1);
162 members.Add(&array_type);
163
164 const auto& struct_type = RunStructTest(Z, "struct_int8array", members);
165
166 EXPECT_EQ(8, struct_type.SizeInBytes());
167 EXPECT(!struct_type.ContainsHomogeneousFloats());
168 EXPECT(!struct_type.ContainsOnlyFloats(Range::StartAndEnd(0, 8)));
169 EXPECT_EQ(0, struct_type.NumberOfWordSizeChunksOnlyFloat());
170 EXPECT_EQ(
171 Utils::RoundUp(struct_type.SizeInBytes(), compiler::target::kWordSize) /
173 struct_type.NumberOfWordSizeChunksNotOnlyFloat());
174}
175
176UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_floatarray) {
177 const auto& float_type = *new (Z) NativePrimitiveType(kFloat);
178
179 const auto& inner_array_type = *new (Z) NativeArrayType(float_type, 2);
180
181 auto& inner_struct_members = *new (Z) NativeTypes(Z, 1);
182 inner_struct_members.Add(&inner_array_type);
183 const auto& inner_struct =
184 NativeStructType::FromNativeTypes(Z, inner_struct_members);
185
186 const auto& array_type = *new (Z) NativeArrayType(inner_struct, 2);
187
188 auto& members = *new (Z) NativeTypes(Z, 1);
189 members.Add(&array_type);
190
191 const auto& struct_type = RunStructTest(Z, "struct_floatarray", members);
192
193 EXPECT_EQ(16, struct_type.SizeInBytes());
194 EXPECT(struct_type.ContainsHomogeneousFloats());
195 EXPECT(struct_type.ContainsOnlyFloats(Range::StartAndEnd(0, 8)));
196 EXPECT_EQ(16 / compiler::target::kWordSize,
197 struct_type.NumberOfWordSizeChunksOnlyFloat());
198}
199
200UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_packed) {
201 const auto& uint8_type = *new (Z) NativePrimitiveType(kUint8);
202 const auto& uint16_type = *new (Z) NativePrimitiveType(kUint16);
203
204 auto& members = *new (Z) NativeTypes(Z, 2);
205 members.Add(&uint8_type);
206 members.Add(&uint16_type);
207 const intptr_t packing = 1;
208
209 const auto& struct_type =
210 NativeStructType::FromNativeTypes(Z, members, packing);
211
212 // Should be 3 bytes on every platform.
213 EXPECT_EQ(3, struct_type.SizeInBytes());
214 EXPECT(struct_type.ContainsUnalignedMembers());
215}
216
217UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_packed_array) {
218 const auto& uint8_type = *new (Z) NativePrimitiveType(kUint8);
219 const auto& uint16_type = *new (Z) NativePrimitiveType(kUint16);
220
221 auto& inner_members = *new (Z) NativeTypes(Z, 2);
222 inner_members.Add(&uint16_type);
223 inner_members.Add(&uint8_type);
224 const intptr_t packing = 1;
225 const auto& inner_struct_type =
226 NativeStructType::FromNativeTypes(Z, inner_members, packing);
227
228 EXPECT_EQ(3, inner_struct_type.SizeInBytes());
229 // Non-windows x64 considers this struct as all members aligned, even though
230 // its size is not a multiple of its individual member alignment.
231 EXPECT(!inner_struct_type.ContainsUnalignedMembers());
232
233 const auto& array_type = *new (Z) NativeArrayType(inner_struct_type, 2);
234
235 auto& members = *new (Z) NativeTypes(Z, 1);
236 members.Add(&array_type);
237 const auto& struct_type = NativeStructType::FromNativeTypes(Z, members);
238
239 EXPECT_EQ(6, struct_type.SizeInBytes());
240 // Non-windows x64 passes this as a struct with unaligned members, because
241 // the second element of the array contains unaligned members.
242 EXPECT(struct_type.ContainsUnalignedMembers());
243}
244
245UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_packed_nested) {
246 const auto& uint8_type = *new (Z) NativePrimitiveType(kUint8);
247 const auto& uint32_type = *new (Z) NativePrimitiveType(kUint32);
248
249 auto& inner_members = *new (Z) NativeTypes(Z, 2);
250 inner_members.Add(&uint32_type);
251 inner_members.Add(&uint8_type);
252 const intptr_t packing = 1;
253 const auto& inner_struct_type =
254 NativeStructType::FromNativeTypes(Z, inner_members, packing);
255
256 EXPECT_EQ(5, inner_struct_type.SizeInBytes());
257 // Non-windows x64 considers this struct as all members aligned, even though
258 // its size is not a multiple of its individual member alignment.
259 EXPECT(!inner_struct_type.ContainsUnalignedMembers());
260
261 auto& members = *new (Z) NativeTypes(Z, 2);
262 members.Add(&uint8_type);
263 members.Add(&inner_struct_type);
264 const auto& struct_type = NativeStructType::FromNativeTypes(Z, members);
265
266 EXPECT_EQ(6, struct_type.SizeInBytes());
267 // Non-windows x64 passes this as a struct with unaligned members, even
268 // though the nested struct itself has all its members aligned in isolation.
269 EXPECT(struct_type.ContainsUnalignedMembers());
270}
271
272UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_union_size) {
273 const auto& uint8_type = *new (Z) NativePrimitiveType(kUint8);
274 const auto& uint32_type = *new (Z) NativePrimitiveType(kUint32);
275
276 const auto& array8_bytes = *new (Z) NativeArrayType(uint32_type, 2);
277 const auto& array9_bytes = *new (Z) NativeArrayType(uint8_type, 9);
278
279 auto& members = *new (Z) NativeTypes(Z, 2);
280 members.Add(&array8_bytes);
281 members.Add(&array9_bytes);
282 const auto& union_type = NativeUnionType::FromNativeTypes(Z, members);
283
284 // The alignment requirements of the first member and the size of the second
285 // member force the size to be rounded up to 12.
286 EXPECT_EQ(12, union_type.SizeInBytes());
287
288 EXPECT(!union_type.ContainsUnalignedMembers());
289}
290
291UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_union_primitive_members) {
292 const auto& float_type = *new (Z) NativePrimitiveType(kFloat);
293
294 const auto& float_array_type = *new (Z) NativeArrayType(float_type, 3);
295
296 auto& struct_member_types = *new (Z) NativeTypes(Z, 4);
297 struct_member_types.Add(&float_type);
298 struct_member_types.Add(&float_type);
299 struct_member_types.Add(&float_type);
300 struct_member_types.Add(&float_type);
301 const auto& struct_type =
302 NativeStructType::FromNativeTypes(Z, struct_member_types);
303
304 auto& member_types = *new (Z) NativeTypes(Z, 2);
305 member_types.Add(&float_array_type);
306 member_types.Add(&struct_type);
307 const auto& union_type = NativeUnionType::FromNativeTypes(Z, member_types);
308
309 EXPECT_EQ(16, union_type.SizeInBytes());
310
311 EXPECT_EQ(4, union_type.NumPrimitiveMembersRecursive());
312 EXPECT(union_type.FirstPrimitiveMember().Equals(float_type));
313 EXPECT(union_type.ContainsHomogeneousFloats());
314
315 EXPECT(!union_type.ContainsUnalignedMembers());
316}
317
318UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_union_unaligned) {
319 const auto& uint8_type = *new (Z) NativePrimitiveType(kUint8);
320 const auto& uint32_type = *new (Z) NativePrimitiveType(kUint32);
321
322 auto& inner_members = *new (Z) NativeTypes(Z, 2);
323 inner_members.Add(&uint8_type);
324 inner_members.Add(&uint32_type);
325 const intptr_t packing = 1;
326 const auto& struct_type =
327 NativeStructType::FromNativeTypes(Z, inner_members, packing);
328
329 const auto& array_type = *new (Z) NativeArrayType(uint8_type, 5);
330
331 auto& member_types = *new (Z) NativeTypes(Z, 2);
332 member_types.Add(&array_type);
333 member_types.Add(&struct_type);
334 const auto& union_type = NativeUnionType::FromNativeTypes(Z, member_types);
335
336 EXPECT_EQ(5, union_type.SizeInBytes());
337 EXPECT_EQ(1, union_type.AlignmentInBytesField());
338
339 EXPECT(union_type.ContainsUnalignedMembers());
340}
341
342} // namespace ffi
343} // namespace compiler
344} // namespace dart
#define EXPECT(type, expectedAlignment, expectedSize)
#define Z
static void Print(const char *format,...) PRINTF_ATTRIBUTE(1
static int SNPrint(char *str, size_t size, const char *format,...) PRINTF_ATTRIBUTE(3
static constexpr T RoundUp(T x, uintptr_t alignment, uintptr_t offset=0)
Definition: utils.h:120
static NativeStructType & FromNativeTypes(Zone *zone, const NativeTypes &members, intptr_t member_packing=kMaxInt32)
Definition: native_type.cc:196
static NativeUnionType & FromNativeTypes(Zone *zone, const NativeTypes &members)
Definition: native_type.cc:256
static Range StartAndEnd(intptr_t start_inclusive, intptr_t end_exclusive)
Definition: range.h:35
UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_int8x10)
void WriteToFile(char *path, const char *contents)
Definition: unit_test.cc:20
const NativeCompoundType & RunStructTest(dart::Zone *zone, const char *name, const NativeTypes &member_types, intptr_t packing=kMaxInt32)
ZoneGrowableArray< const NativeType * > NativeTypes
Definition: native_type.h:316
void ReadFromFile(char *path, char **buffer_pointer)
Definition: unit_test.cc:31
const char * kOs
Definition: unit_test.cc:17
static constexpr intptr_t kWordSize
Definition: runtime_api.h:274
Definition: dart_vm.cc:33
const char *const name
constexpr int32_t kMaxInt32
Definition: globals.h:483
def array_type(data_type)
Definition: systemnative.py:28