Skip to content

Commit c0a9368

Browse files
rmacnak-googleCommit Queue
authored and
Commit Queue
committed
[vm, ffi] Round up checking for registers for small structs.
This fixes an edge case on all ARM64 ABIs, when there is only one argument register remaining and the next argument is a 9-16 byte struct. TEST=ci Bug: #52644 Change-Id: I40d962e6d1b3484dbfcf91f5d6baca0bfec76056 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/330161 Reviewed-by: Daco Harkes <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent b04c5a4 commit c0a9368

File tree

46 files changed

+1361
-82
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1361
-82
lines changed

runtime/bin/ffi_test/ffi_test_functions_generated.cc

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ struct Struct12BytesHomogeneousFloat {
137137
float a2;
138138
};
139139

140+
struct Struct12BytesHomogeneousInt32 {
141+
int32_t a0;
142+
int32_t a1;
143+
int32_t a2;
144+
};
145+
140146
struct Struct16BytesHomogeneousFloat {
141147
float a0;
142148
float a1;
@@ -4833,6 +4839,41 @@ DART_EXPORT wchar_t PassWCharStructInlineArrayIntUintPtrx2LongUnsigned(
48334839
return result;
48344840
}
48354841

4842+
// Used for testing structs and unions by value.
4843+
// Struct stradles last argument register
4844+
DART_EXPORT int64_t
4845+
PassInt64x7Struct12BytesHomogeneousInt32(int64_t a0,
4846+
int64_t a1,
4847+
int64_t a2,
4848+
int64_t a3,
4849+
int64_t a4,
4850+
int64_t a5,
4851+
int64_t a6,
4852+
Struct12BytesHomogeneousInt32 a7) {
4853+
std::cout << "PassInt64x7Struct12BytesHomogeneousInt32"
4854+
<< "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
4855+
<< ", " << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1
4856+
<< ", " << a7.a2 << "))"
4857+
<< "\n";
4858+
4859+
int64_t result = 0;
4860+
4861+
result += a0;
4862+
result += a1;
4863+
result += a2;
4864+
result += a3;
4865+
result += a4;
4866+
result += a5;
4867+
result += a6;
4868+
result += a7.a0;
4869+
result += a7.a1;
4870+
result += a7.a2;
4871+
4872+
std::cout << "result = " << result << "\n";
4873+
4874+
return result;
4875+
}
4876+
48364877
// Used for testing structs and unions by value.
48374878
// Smallest struct with data.
48384879
DART_EXPORT Struct1ByteInt ReturnStruct1ByteInt(int8_t a0) {
@@ -12503,6 +12544,67 @@ DART_EXPORT intptr_t TestPassWCharStructInlineArrayIntUintPtrx2LongUnsigned(
1250312544
return 0;
1250412545
}
1250512546

12547+
// Used for testing structs and unions by value.
12548+
// Struct stradles last argument register
12549+
DART_EXPORT intptr_t TestPassInt64x7Struct12BytesHomogeneousInt32(
12550+
// NOLINTNEXTLINE(whitespace/parens)
12551+
int64_t (*f)(int64_t a0,
12552+
int64_t a1,
12553+
int64_t a2,
12554+
int64_t a3,
12555+
int64_t a4,
12556+
int64_t a5,
12557+
int64_t a6,
12558+
Struct12BytesHomogeneousInt32 a7)) {
12559+
int64_t a0;
12560+
int64_t a1;
12561+
int64_t a2;
12562+
int64_t a3;
12563+
int64_t a4;
12564+
int64_t a5;
12565+
int64_t a6;
12566+
Struct12BytesHomogeneousInt32 a7 = {};
12567+
12568+
a0 = -1;
12569+
a1 = 2;
12570+
a2 = -3;
12571+
a3 = 4;
12572+
a4 = -5;
12573+
a5 = 6;
12574+
a6 = -7;
12575+
a7.a0 = 8;
12576+
a7.a1 = -9;
12577+
a7.a2 = 10;
12578+
12579+
std::cout << "Calling TestPassInt64x7Struct12BytesHomogeneousInt32("
12580+
<< "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
12581+
<< ", " << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1
12582+
<< ", " << a7.a2 << "))"
12583+
<< ")\n";
12584+
12585+
int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7);
12586+
12587+
std::cout << "result = " << result << "\n";
12588+
12589+
CHECK_EQ(5, result);
12590+
12591+
// Pass argument that will make the Dart callback throw.
12592+
a0 = 42;
12593+
12594+
result = f(a0, a1, a2, a3, a4, a5, a6, a7);
12595+
12596+
CHECK_EQ(0, result);
12597+
12598+
// Pass argument that will make the Dart callback return null.
12599+
a0 = 84;
12600+
12601+
result = f(a0, a1, a2, a3, a4, a5, a6, a7);
12602+
12603+
CHECK_EQ(0, result);
12604+
12605+
return 0;
12606+
}
12607+
1250612608
// Used for testing structs and unions by value.
1250712609
// Smallest struct with data.
1250812610
DART_EXPORT intptr_t TestReturnStruct1ByteInt(
@@ -21080,6 +21182,47 @@ DART_EXPORT void TestAsyncPassWCharStructInlineArrayIntUintPtrx2LongUnsigned(
2108021182
f(a0, a1, a2, a3, a4, a5);
2108121183
}
2108221184

21185+
// Used for testing structs and unions by value.
21186+
// Struct stradles last argument register
21187+
DART_EXPORT void TestAsyncPassInt64x7Struct12BytesHomogeneousInt32(
21188+
// NOLINTNEXTLINE(whitespace/parens)
21189+
void (*f)(int64_t a0,
21190+
int64_t a1,
21191+
int64_t a2,
21192+
int64_t a3,
21193+
int64_t a4,
21194+
int64_t a5,
21195+
int64_t a6,
21196+
Struct12BytesHomogeneousInt32 a7)) {
21197+
int64_t a0;
21198+
int64_t a1;
21199+
int64_t a2;
21200+
int64_t a3;
21201+
int64_t a4;
21202+
int64_t a5;
21203+
int64_t a6;
21204+
Struct12BytesHomogeneousInt32 a7 = {};
21205+
21206+
a0 = -1;
21207+
a1 = 2;
21208+
a2 = -3;
21209+
a3 = 4;
21210+
a4 = -5;
21211+
a5 = 6;
21212+
a6 = -7;
21213+
a7.a0 = 8;
21214+
a7.a1 = -9;
21215+
a7.a2 = 10;
21216+
21217+
std::cout << "Calling TestAsyncPassInt64x7Struct12BytesHomogeneousInt32("
21218+
<< "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
21219+
<< ", " << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1
21220+
<< ", " << a7.a2 << "))"
21221+
<< ")\n";
21222+
21223+
f(a0, a1, a2, a3, a4, a5, a6, a7);
21224+
}
21225+
2108321226
// Used for testing structs and unions by value.
2108421227
// Smallest struct with data.
2108521228
DART_EXPORT void TestAsyncReturnStruct1ByteInt(
@@ -23371,6 +23514,46 @@ DART_EXPORT double VariadicAt5Doublex5(double a0,
2337123514
return result;
2337223515
}
2337323516

23517+
// Used for testing structs and unions by value.
23518+
// Struct stradles last argument register, variadic
23519+
DART_EXPORT int64_t VariadicAt1Int64x7Struct12BytesHomogeneousInt32(int64_t a0,
23520+
...) {
23521+
va_list var_args;
23522+
va_start(var_args, a0);
23523+
int64_t a1 = va_arg(var_args, int64_t);
23524+
int64_t a2 = va_arg(var_args, int64_t);
23525+
int64_t a3 = va_arg(var_args, int64_t);
23526+
int64_t a4 = va_arg(var_args, int64_t);
23527+
int64_t a5 = va_arg(var_args, int64_t);
23528+
int64_t a6 = va_arg(var_args, int64_t);
23529+
Struct12BytesHomogeneousInt32 a7 =
23530+
va_arg(var_args, Struct12BytesHomogeneousInt32);
23531+
va_end(var_args);
23532+
23533+
std::cout << "VariadicAt1Int64x7Struct12BytesHomogeneousInt32"
23534+
<< "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
23535+
<< ", " << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1
23536+
<< ", " << a7.a2 << "))"
23537+
<< "\n";
23538+
23539+
int64_t result = 0;
23540+
23541+
result += a0;
23542+
result += a1;
23543+
result += a2;
23544+
result += a3;
23545+
result += a4;
23546+
result += a5;
23547+
result += a6;
23548+
result += a7.a0;
23549+
result += a7.a1;
23550+
result += a7.a2;
23551+
23552+
std::cout << "result = " << result << "\n";
23553+
23554+
return result;
23555+
}
23556+
2337423557
// Used for testing structs and unions by value.
2337523558
// Single variadic argument.
2337623559
DART_EXPORT intptr_t TestVariadicAt1Int64x2(
@@ -24239,4 +24422,58 @@ DART_EXPORT intptr_t TestVariadicAt5Doublex5(
2423924422
return 0;
2424024423
}
2424124424

24425+
// Used for testing structs and unions by value.
24426+
// Struct stradles last argument register, variadic
24427+
DART_EXPORT intptr_t TestVariadicAt1Int64x7Struct12BytesHomogeneousInt32(
24428+
// NOLINTNEXTLINE(whitespace/parens)
24429+
int64_t (*f)(int64_t a0, ...)) {
24430+
int64_t a0;
24431+
int64_t a1;
24432+
int64_t a2;
24433+
int64_t a3;
24434+
int64_t a4;
24435+
int64_t a5;
24436+
int64_t a6;
24437+
Struct12BytesHomogeneousInt32 a7 = {};
24438+
24439+
a0 = -1;
24440+
a1 = 2;
24441+
a2 = -3;
24442+
a3 = 4;
24443+
a4 = -5;
24444+
a5 = 6;
24445+
a6 = -7;
24446+
a7.a0 = 8;
24447+
a7.a1 = -9;
24448+
a7.a2 = 10;
24449+
24450+
std::cout << "Calling TestVariadicAt1Int64x7Struct12BytesHomogeneousInt32("
24451+
<< "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
24452+
<< ", " << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1
24453+
<< ", " << a7.a2 << "))"
24454+
<< ")\n";
24455+
24456+
int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7);
24457+
24458+
std::cout << "result = " << result << "\n";
24459+
24460+
CHECK_EQ(5, result);
24461+
24462+
// Pass argument that will make the Dart callback throw.
24463+
a0 = 42;
24464+
24465+
result = f(a0, a1, a2, a3, a4, a5, a6, a7);
24466+
24467+
CHECK_EQ(0, result);
24468+
24469+
// Pass argument that will make the Dart callback return null.
24470+
a0 = 84;
24471+
24472+
result = f(a0, a1, a2, a3, a4, a5, a6, a7);
24473+
24474+
CHECK_EQ(0, result);
24475+
24476+
return 0;
24477+
}
24478+
2424224479
} // namespace dart

runtime/vm/compiler/ffi/native_calling_convention.cc

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -433,31 +433,31 @@ class ArgumentAllocator : public ValueObject {
433433
}
434434

435435
if (size <= 16) {
436-
const intptr_t required_regs = size / 8;
437-
const bool regs_available =
438-
cpu_regs_used + required_regs <= CallingConventions::kNumArgRegs;
436+
const intptr_t size_rounded = Utils::RoundUp(size, 8);
437+
const intptr_t num_chunks = size_rounded / 8;
438+
ASSERT((num_chunks == 1) || (num_chunks == 2));
439439

440-
if (regs_available) {
441-
const intptr_t size_rounded =
442-
Utils::RoundUp(payload_type.SizeInBytes(), 8);
443-
const intptr_t num_chunks = size_rounded / 8;
444-
const auto& chunk_type = *new (zone_) NativePrimitiveType(kInt64);
440+
// All-or-none: block any leftover registers.
441+
#if defined(DART_TARGET_OS_WINDOWS)
442+
if (!HasAvailableCpuRegisters(num_chunks) && !is_vararg) {
443+
cpu_regs_used = CallingConventions::kNumArgRegs;
444+
}
445+
#else
446+
if (!HasAvailableCpuRegisters(num_chunks)) {
447+
cpu_regs_used = CallingConventions::kNumArgRegs;
448+
}
449+
#endif
445450

446-
NativeLocations& multiple_locations =
447-
*new (zone_) NativeLocations(zone_, num_chunks);
448-
for (int i = 0; i < num_chunks; i++) {
449-
const auto& allocated_chunk =
450-
&AllocateArgument(chunk_type, is_vararg);
451-
multiple_locations.Add(allocated_chunk);
452-
}
453-
return *new (zone_)
454-
MultipleNativeLocations(compound_type, multiple_locations);
451+
const auto& chunk_type = *new (zone_) NativePrimitiveType(kInt64);
455452

456-
} else {
457-
// Block all CPU registers.
458-
cpu_regs_used = CallingConventions::kNumArgRegs;
459-
return AllocateStack(payload_type, is_vararg);
453+
NativeLocations& multiple_locations =
454+
*new (zone_) NativeLocations(zone_, num_chunks);
455+
for (int i = 0; i < num_chunks; i++) {
456+
const auto& allocated_chunk = &AllocateArgument(chunk_type, is_vararg);
457+
multiple_locations.Add(allocated_chunk);
460458
}
459+
return *new (zone_)
460+
MultipleNativeLocations(compound_type, multiple_locations);
461461
}
462462

463463
const auto& pointer_location =

runtime/vm/compiler/ffi/unit_tests/stradle_last_register/arm64_android.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ r3 int64
55
r4 int64
66
r5 int64
77
r6 int64
8-
M(r7 int64, S+0 int64) Struct(size: 12)
8+
M(S+0 int64, S+8 int64) Struct(size: 12)
99
=>
1010
r0 int64

runtime/vm/compiler/ffi/unit_tests/stradle_last_register/arm64_fuchsia.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ r3 int64
55
r4 int64
66
r5 int64
77
r6 int64
8-
M(r7 int64, S+0 int64) Struct(size: 12)
8+
M(S+0 int64, S+8 int64) Struct(size: 12)
99
=>
1010
r0 int64

runtime/vm/compiler/ffi/unit_tests/stradle_last_register/arm64_ios.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ r3 int64
55
r4 int64
66
r5 int64
77
r6 int64
8-
M(r7 int64, S+0 int64) Struct(size: 12)
8+
M(S+0 int64, S+8 int64) Struct(size: 12)
99
=>
1010
r0 int64

runtime/vm/compiler/ffi/unit_tests/stradle_last_register/arm64_linux.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ r3 int64
55
r4 int64
66
r5 int64
77
r6 int64
8-
M(r7 int64, S+0 int64) Struct(size: 12)
8+
M(S+0 int64, S+8 int64) Struct(size: 12)
99
=>
1010
r0 int64

runtime/vm/compiler/ffi/unit_tests/stradle_last_register/arm64_macos.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ r3 int64
55
r4 int64
66
r5 int64
77
r6 int64
8-
M(r7 int64, S+0 int64) Struct(size: 12)
8+
M(S+0 int64, S+8 int64) Struct(size: 12)
99
=>
1010
r0 int64

runtime/vm/compiler/ffi/unit_tests/stradle_last_register/arm64_win.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ r3 int64
55
r4 int64
66
r5 int64
77
r6 int64
8-
M(r7 int64, S+0 int64) Struct(size: 12)
8+
M(S+0 int64, S+8 int64) Struct(size: 12)
99
=>
1010
r0 int64

runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_android.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ M(r4 int64) Struct(size: 8)
66
M(r5 int64) Struct(size: 8)
77
M(r6 int64) Struct(size: 8)
88
M(r7 int64) Struct(size: 8)
9-
S+0 Struct(size: 8)
10-
S+8 Struct(size: 8)
9+
M(S+0 int64) Struct(size: 8)
10+
M(S+8 int64) Struct(size: 8)
1111
=>
1212
M(r0 int64) Struct(size: 8)

runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_fuchsia.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ M(r4 int64) Struct(size: 8)
66
M(r5 int64) Struct(size: 8)
77
M(r6 int64) Struct(size: 8)
88
M(r7 int64) Struct(size: 8)
9-
S+0 Struct(size: 8)
10-
S+8 Struct(size: 8)
9+
M(S+0 int64) Struct(size: 8)
10+
M(S+8 int64) Struct(size: 8)
1111
=>
1212
M(r0 int64) Struct(size: 8)

0 commit comments

Comments
 (0)