[stable][vm/ffi] Fix variadic arguments on MacOS Arm64
Non-variadic arguments on the stack on MacOS Arm64 are aligned to
the value size (which can be smaller than word size). However, for
varargs, the arguments on the stack seem to be aligned to the word
size.
This CL introduces an alignment strategy constant for primitives on
the stack in varargs and uses it in the native calling convention
calculation.
TEST=runtime/vm/compiler/ffi/native_calling_convention_test.cc with
runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_macos.expect
TEST=tests/ffi/function_varargs_generated_native_leaf_test.dart
Cherry-pick: https://dart-review.googlesource.com/c/sdk/+/362762
Cherry-pick-request: https://github.com/dart-lang/sdk/issues/55943
Change-Id: I621b89d8554a5507c25d9fd24ca64cd954f37388
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/369822
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d3d1996..f3d948b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@
and conditional import condition `dart.library.ffi` is true in dart2wasm.
(issue [#55948]).
+- Fixes an issue where FFI calls with variadic arguments on MacOS Arm64
+ would mangle the arguments. (issue [#55943]).
+
+[#55943]: https://github.com/dart-lang/sdk/issues/55943
[#55948]: https://github.com/dart-lang/sdk/issues/55948
## 3.4.3 - 2024-06-05
diff --git a/runtime/bin/ffi_test/ffi_test_functions_generated.cc b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
index 59491b1..32304ed 100644
--- a/runtime/bin/ffi_test/ffi_test_functions_generated.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
@@ -23556,6 +23556,38 @@
}
// Used for testing structs and unions by value.
+// Variadic arguments test on macos_arm64.
+DART_EXPORT int32_t VariadicAt1Struct12BytesHomogeneousInt32Int32x4(
+ Struct12BytesHomogeneousInt32 a0,
+ ...) {
+ va_list var_args;
+ va_start(var_args, a0);
+ int32_t a1 = va_arg(var_args, int32_t);
+ int32_t a2 = va_arg(var_args, int32_t);
+ int32_t a3 = va_arg(var_args, int32_t);
+ int32_t a4 = va_arg(var_args, int32_t);
+ va_end(var_args);
+
+ std::cout << "VariadicAt1Struct12BytesHomogeneousInt32Int32x4" << "(("
+ << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), " << a1 << ", "
+ << a2 << ", " << a3 << ", " << a4 << ")" << "\n";
+
+ int32_t result = 0;
+
+ result += a0.a0;
+ result += a0.a1;
+ result += a0.a2;
+ result += a1;
+ result += a2;
+ result += a3;
+ result += a4;
+
+ std::cout << "result = " << result << "\n";
+
+ return result;
+}
+
+// Used for testing structs and unions by value.
// Single variadic argument.
DART_EXPORT intptr_t TestVariadicAt1Int64x2(
// NOLINTNEXTLINE(whitespace/parens)
@@ -24477,4 +24509,50 @@
return 0;
}
+// Used for testing structs and unions by value.
+// Variadic arguments test on macos_arm64.
+DART_EXPORT intptr_t TestVariadicAt1Struct12BytesHomogeneousInt32Int32x4(
+ // NOLINTNEXTLINE(whitespace/parens)
+ int32_t (*f)(Struct12BytesHomogeneousInt32 a0, ...)) {
+ Struct12BytesHomogeneousInt32 a0 = {};
+ int32_t a1;
+ int32_t a2;
+ int32_t a3;
+ int32_t a4;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1 = 4;
+ a2 = -5;
+ a3 = 6;
+ a4 = -7;
+
+ std::cout << "Calling TestVariadicAt1Struct12BytesHomogeneousInt32Int32x4("
+ << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), " << a1
+ << ", " << a2 << ", " << a3 << ", " << a4 << ")" << ")\n";
+
+ int32_t result = f(a0, a1, a2, a3, a4);
+
+ std::cout << "result = " << result << "\n";
+
+ CHECK_EQ(-4, result);
+
+ // Pass argument that will make the Dart callback throw.
+ a0.a0 = 42;
+
+ result = f(a0, a1, a2, a3, a4);
+
+ CHECK_EQ(0, result);
+
+ // Pass argument that will make the Dart callback return null.
+ a0.a0 = 84;
+
+ result = f(a0, a1, a2, a3, a4);
+
+ CHECK_EQ(0, result);
+
+ return 0;
+}
+
} // namespace dart
diff --git a/runtime/vm/compiler/ffi/native_calling_convention.cc b/runtime/vm/compiler/ffi/native_calling_convention.cc
index 3914afe..a555193 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention.cc
+++ b/runtime/vm/compiler/ffi/native_calling_convention.cc
@@ -242,7 +242,7 @@
zone_, payload_type, container_type, AllocateCpuRegister());
}
}
- return AllocateStack(payload_type);
+ return AllocateStack(payload_type, is_vararg);
}
// Constructs a container type.
diff --git a/runtime/vm/compiler/ffi/native_calling_convention_test.cc b/runtime/vm/compiler/ffi/native_calling_convention_test.cc
index 456a693..5be3304 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention_test.cc
+++ b/runtime/vm/compiler/ffi/native_calling_convention_test.cc
@@ -969,6 +969,28 @@
RunSignatureTest(Z, "variadic_stradle_last_register", native_signature);
}
+// Struct parameter that potentially is partially allocated to a register and
+// partially to the stack. Mainly interesting on ARM64 and RISC-V.
+//
+// See the *.expect in ./unit_tests for this behavior.
+UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_variadic_less_than_word) {
+#if defined(TARGET_ARCH_IS_32_BIT)
+ const auto& halfptr_type = *new (Z) NativePrimitiveType(kInt16);
+#elif defined(TARGET_ARCH_IS_64_BIT)
+ const auto& halfptr_type = *new (Z) NativePrimitiveType(kInt32);
+#endif
+
+ auto& arguments = *new (Z) NativeTypes(Z, 12);
+ for (intptr_t i = 0; i < 12; i++) {
+ arguments.Add(&halfptr_type);
+ }
+
+ const auto& native_signature = *new (Z) NativeFunctionType(
+ arguments, halfptr_type, /*variadic_arguments_index=*/1);
+
+ RunSignatureTest(Z, "variadic_less_than_word", native_signature);
+}
+
} // namespace ffi
} // namespace compiler
} // namespace dart
diff --git a/runtime/vm/compiler/ffi/native_type.cc b/runtime/vm/compiler/ffi/native_type.cc
index 368fcbd..b0c86f9 100644
--- a/runtime/vm/compiler/ffi/native_type.cc
+++ b/runtime/vm/compiler/ffi/native_type.cc
@@ -152,7 +152,10 @@
}
intptr_t NativePrimitiveType::AlignmentInBytesStack(bool is_vararg) const {
- switch (CallingConventions::kArgumentStackAlignment) {
+ const auto alignment =
+ is_vararg ? CallingConventions::kArgumentStackAlignmentVarArgs
+ : CallingConventions::kArgumentStackAlignment;
+ switch (alignment) {
case kAlignedToWordSize:
// The default is to align stack arguments to word size.
return compiler::target::kWordSize;
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_android.expect
new file mode 100644
index 0000000..abd76a4
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_android.expect
@@ -0,0 +1,14 @@
+r0 int32
+r1 int32
+r2 int32
+r3 int32
+r4 int32
+r5 int32
+r6 int32
+r7 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+=>
+r0 int32
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_fuchsia.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_fuchsia.expect
new file mode 100644
index 0000000..abd76a4
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_fuchsia.expect
@@ -0,0 +1,14 @@
+r0 int32
+r1 int32
+r2 int32
+r3 int32
+r4 int32
+r5 int32
+r6 int32
+r7 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+=>
+r0 int32
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_ios.expect
new file mode 100644
index 0000000..e70c7a8
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_ios.expect
@@ -0,0 +1,14 @@
+r0 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+S+32 int32
+S+40 int32
+S+48 int32
+S+56 int32
+S+64 int32
+S+72 int32
+S+80 int32
+=>
+r0 int32
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_linux.expect
new file mode 100644
index 0000000..abd76a4
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_linux.expect
@@ -0,0 +1,14 @@
+r0 int32
+r1 int32
+r2 int32
+r3 int32
+r4 int32
+r5 int32
+r6 int32
+r7 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+=>
+r0 int32
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_macos.expect
new file mode 100644
index 0000000..e70c7a8
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_macos.expect
@@ -0,0 +1,14 @@
+r0 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+S+32 int32
+S+40 int32
+S+48 int32
+S+56 int32
+S+64 int32
+S+72 int32
+S+80 int32
+=>
+r0 int32
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_win.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_win.expect
new file mode 100644
index 0000000..abd76a4
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_win.expect
@@ -0,0 +1,14 @@
+r0 int32
+r1 int32
+r2 int32
+r3 int32
+r4 int32
+r5 int32
+r6 int32
+r7 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+=>
+r0 int32
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm_android.expect
new file mode 100644
index 0000000..69e01c4
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm_android.expect
@@ -0,0 +1,14 @@
+r0 int32[int16]
+r1 int32[int16]
+r2 int32[int16]
+r3 int32[int16]
+S+0 int32[int16]
+S+4 int32[int16]
+S+8 int32[int16]
+S+12 int32[int16]
+S+16 int32[int16]
+S+20 int32[int16]
+S+24 int32[int16]
+S+28 int32[int16]
+=>
+r0 int32[int16]
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm_ios.expect
new file mode 100644
index 0000000..69e01c4
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm_ios.expect
@@ -0,0 +1,14 @@
+r0 int32[int16]
+r1 int32[int16]
+r2 int32[int16]
+r3 int32[int16]
+S+0 int32[int16]
+S+4 int32[int16]
+S+8 int32[int16]
+S+12 int32[int16]
+S+16 int32[int16]
+S+20 int32[int16]
+S+24 int32[int16]
+S+28 int32[int16]
+=>
+r0 int32[int16]
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm_linux.expect
new file mode 100644
index 0000000..69e01c4
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm_linux.expect
@@ -0,0 +1,14 @@
+r0 int32[int16]
+r1 int32[int16]
+r2 int32[int16]
+r3 int32[int16]
+S+0 int32[int16]
+S+4 int32[int16]
+S+8 int32[int16]
+S+12 int32[int16]
+S+16 int32[int16]
+S+20 int32[int16]
+S+24 int32[int16]
+S+28 int32[int16]
+=>
+r0 int32[int16]
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/ia32_android.expect
new file mode 100644
index 0000000..2505a8af
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/ia32_android.expect
@@ -0,0 +1,14 @@
+S+0 int32[int16]
+S+4 int32[int16]
+S+8 int32[int16]
+S+12 int32[int16]
+S+16 int32[int16]
+S+20 int32[int16]
+S+24 int32[int16]
+S+28 int32[int16]
+S+32 int32[int16]
+S+36 int32[int16]
+S+40 int32[int16]
+S+44 int32[int16]
+=>
+eax int16
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/ia32_linux.expect
new file mode 100644
index 0000000..2505a8af
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/ia32_linux.expect
@@ -0,0 +1,14 @@
+S+0 int32[int16]
+S+4 int32[int16]
+S+8 int32[int16]
+S+12 int32[int16]
+S+16 int32[int16]
+S+20 int32[int16]
+S+24 int32[int16]
+S+28 int32[int16]
+S+32 int32[int16]
+S+36 int32[int16]
+S+40 int32[int16]
+S+44 int32[int16]
+=>
+eax int16
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/ia32_win.expect
new file mode 100644
index 0000000..2505a8af
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/ia32_win.expect
@@ -0,0 +1,14 @@
+S+0 int32[int16]
+S+4 int32[int16]
+S+8 int32[int16]
+S+12 int32[int16]
+S+16 int32[int16]
+S+20 int32[int16]
+S+24 int32[int16]
+S+28 int32[int16]
+S+32 int32[int16]
+S+36 int32[int16]
+S+40 int32[int16]
+S+44 int32[int16]
+=>
+eax int16
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/riscv32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/riscv32_linux.expect
new file mode 100644
index 0000000..bd7f07f
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/riscv32_linux.expect
@@ -0,0 +1,14 @@
+a0 int32[int16]
+a1 int32[int16]
+a2 int32[int16]
+t3 int32[int16]
+t4 int32[int16]
+t5 int32[int16]
+a6 int32[int16]
+a7 int32[int16]
+S+0 int32[int16]
+S+4 int32[int16]
+S+8 int32[int16]
+S+12 int32[int16]
+=>
+a0 int32[int16]
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/riscv64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/riscv64_linux.expect
new file mode 100644
index 0000000..7c1201a
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/riscv64_linux.expect
@@ -0,0 +1,14 @@
+a0 int64[int32]
+a1 int64[int32]
+a2 int64[int32]
+t3 int64[int32]
+t4 int64[int32]
+t5 int64[int32]
+a6 int64[int32]
+a7 int64[int32]
+S+0 int64[int32]
+S+8 int64[int32]
+S+16 int64[int32]
+S+24 int64[int32]
+=>
+a0 int64[int32]
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_fuchsia.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_fuchsia.expect
new file mode 100644
index 0000000..c61096a
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_fuchsia.expect
@@ -0,0 +1,14 @@
+rdi int32
+rsi int32
+rdx int32
+rcx int32
+r8 int32
+r9 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+S+32 int32
+S+40 int32
+=>
+rax int32
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_ios.expect
new file mode 100644
index 0000000..c61096a
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_ios.expect
@@ -0,0 +1,14 @@
+rdi int32
+rsi int32
+rdx int32
+rcx int32
+r8 int32
+r9 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+S+32 int32
+S+40 int32
+=>
+rax int32
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_linux.expect
new file mode 100644
index 0000000..c61096a
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_linux.expect
@@ -0,0 +1,14 @@
+rdi int32
+rsi int32
+rdx int32
+rcx int32
+r8 int32
+r9 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+S+32 int32
+S+40 int32
+=>
+rax int32
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_macos.expect
new file mode 100644
index 0000000..c61096a
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_macos.expect
@@ -0,0 +1,14 @@
+rdi int32
+rsi int32
+rdx int32
+rcx int32
+r8 int32
+r9 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+S+32 int32
+S+40 int32
+=>
+rax int32
diff --git a/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_win.expect
new file mode 100644
index 0000000..c288554
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/x64_win.expect
@@ -0,0 +1,14 @@
+rcx int32
+rdx int32
+r8 int32
+r9 int32
+S+0 int32
+S+8 int32
+S+16 int32
+S+24 int32
+S+32 int32
+S+40 int32
+S+48 int32
+S+56 int32
+=>
+rax int32
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 80b5b79..c2f4c00 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -718,6 +718,8 @@
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSizeAndValueSize;
+ static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
+ kArgumentStackAlignment;
// How fields in compounds are aligned.
#if defined(DART_TARGET_OS_MACOS_IOS)
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index 0930e81..26bb328 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -584,9 +584,14 @@
// https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToValueSize;
+ // Varargs are aligned to wordsize.
+ static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
+ kAlignedToWordSize;
#else
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
+ static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
+ kArgumentStackAlignment;
#endif
// How fields in compounds are aligned.
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index 8903cff..d209d42 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -503,6 +503,8 @@
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
+ static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
+ kArgumentStackAlignment;
// How fields in compounds are aligned.
#if defined(DART_TARGET_OS_WINDOWS)
diff --git a/runtime/vm/constants_riscv.h b/runtime/vm/constants_riscv.h
index 90df737..ab10687 100644
--- a/runtime/vm/constants_riscv.h
+++ b/runtime/vm/constants_riscv.h
@@ -557,6 +557,8 @@
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSizeAndValueSize;
+ static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
+ kArgumentStackAlignment;
// How fields in compounds are aligned.
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index 548ee1f..2086183 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -571,6 +571,8 @@
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
+ static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
+ kArgumentStackAlignment;
// How fields in compounds are aligned.
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
@@ -641,6 +643,8 @@
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
+ static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
+ kArgumentStackAlignment;
// How fields in compounds are aligned.
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
diff --git a/tests/ffi/function_callbacks_varargs_generated_test.dart b/tests/ffi/function_callbacks_varargs_generated_test.dart
index 091eecd..4d25af0 100644
--- a/tests/ffi/function_callbacks_varargs_generated_test.dart
+++ b/tests/ffi/function_callbacks_varargs_generated_test.dart
@@ -122,6 +122,11 @@
Pointer.fromFunction<VariadicAt1Int64x7Struct12BytesHomogeneousInt32Type>(
variadicAt1Int64x7Struct12BytesHomogeneousInt32, 0),
variadicAt1Int64x7Struct12BytesHomogeneousInt32AfterCallback),
+ CallbackTest.withCheck(
+ "VariadicAt1Struct12BytesHomogeneousInt32Int32x4",
+ Pointer.fromFunction<VariadicAt1Struct12BytesHomogeneousInt32Int32x4Type>(
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4, 0),
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4AfterCallback),
];
typedef VariadicAt1Int64x2Type = Int64 Function(Int64, VarArgs<(Int64,)>);
@@ -1486,3 +1491,70 @@
Expect.equals(5, result);
}
+
+typedef VariadicAt1Struct12BytesHomogeneousInt32Int32x4Type = Int32 Function(
+ Struct12BytesHomogeneousInt32, VarArgs<(Int32, Int32, Int32, Int32)>);
+
+// Global variables to be able to test inputs after callback returned.
+Struct12BytesHomogeneousInt32
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0 =
+ Pointer<Struct12BytesHomogeneousInt32>.fromAddress(0).ref;
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1 = 0;
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2 = 0;
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3 = 0;
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4Result = 0;
+
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult() {
+ int result = 0;
+
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a0;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a1;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a2;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4;
+
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4Result = result;
+
+ return result;
+}
+
+/// Variadic arguments test on macos_arm64.
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4(
+ Struct12BytesHomogeneousInt32 a0, int a1, int a2, int a3, int a4) {
+ print(
+ "variadicAt1Struct12BytesHomogeneousInt32Int32x4(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+ // Possibly throw.
+ if (a0.a0 == 42 || a0.a0 == 84) {
+ print("throwing!");
+ throw Exception(
+ "VariadicAt1Struct12BytesHomogeneousInt32Int32x4 throwing on purpose!");
+ }
+
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0 = a0;
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1 = a1;
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2 = a2;
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3 = a3;
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4 = a4;
+
+ final result =
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void variadicAt1Struct12BytesHomogeneousInt32Int32x4AfterCallback() {
+ final result =
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.equals(-4, result);
+}
diff --git a/tests/ffi/function_callbacks_varargs_native_callable_generated_test.dart b/tests/ffi/function_callbacks_varargs_native_callable_generated_test.dart
index 2a753a3..93d7f3a 100644
--- a/tests/ffi/function_callbacks_varargs_native_callable_generated_test.dart
+++ b/tests/ffi/function_callbacks_varargs_native_callable_generated_test.dart
@@ -143,6 +143,13 @@
variadicAt1Int64x7Struct12BytesHomogeneousInt32,
exceptionalReturn: 0),
variadicAt1Int64x7Struct12BytesHomogeneousInt32AfterCallback),
+ CallbackTest.withCheck(
+ "VariadicAt1Struct12BytesHomogeneousInt32Int32x4",
+ NativeCallable<
+ VariadicAt1Struct12BytesHomogeneousInt32Int32x4Type>.isolateLocal(
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4,
+ exceptionalReturn: 0),
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4AfterCallback),
];
typedef VariadicAt1Int64x2Type = Int64 Function(Int64, VarArgs<(Int64,)>);
@@ -1507,3 +1514,70 @@
Expect.equals(5, result);
}
+
+typedef VariadicAt1Struct12BytesHomogeneousInt32Int32x4Type = Int32 Function(
+ Struct12BytesHomogeneousInt32, VarArgs<(Int32, Int32, Int32, Int32)>);
+
+// Global variables to be able to test inputs after callback returned.
+Struct12BytesHomogeneousInt32
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0 =
+ Pointer<Struct12BytesHomogeneousInt32>.fromAddress(0).ref;
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1 = 0;
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2 = 0;
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3 = 0;
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4Result = 0;
+
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult() {
+ int result = 0;
+
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a0;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a1;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a2;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3;
+ result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4;
+
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4Result = result;
+
+ return result;
+}
+
+/// Variadic arguments test on macos_arm64.
+int variadicAt1Struct12BytesHomogeneousInt32Int32x4(
+ Struct12BytesHomogeneousInt32 a0, int a1, int a2, int a3, int a4) {
+ print(
+ "variadicAt1Struct12BytesHomogeneousInt32Int32x4(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+ // Possibly throw.
+ if (a0.a0 == 42 || a0.a0 == 84) {
+ print("throwing!");
+ throw Exception(
+ "VariadicAt1Struct12BytesHomogeneousInt32Int32x4 throwing on purpose!");
+ }
+
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0 = a0;
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1 = a1;
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2 = a2;
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3 = a3;
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4 = a4;
+
+ final result =
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void variadicAt1Struct12BytesHomogeneousInt32Int32x4AfterCallback() {
+ final result =
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.equals(-4, result);
+}
diff --git a/tests/ffi/function_varargs_generated_leaf_test.dart b/tests/ffi/function_varargs_generated_leaf_test.dart
index 9c400f4..0277809 100644
--- a/tests/ffi/function_varargs_generated_leaf_test.dart
+++ b/tests/ffi/function_varargs_generated_leaf_test.dart
@@ -42,6 +42,7 @@
testVariadicAt1DoubleInt64Int32Struct20BytesHomogeneouLeaf();
testVariadicAt5Doublex5Leaf();
testVariadicAt1Int64x7Struct12BytesHomogeneousInt32Leaf();
+ testVariadicAt1Struct12BytesHomogeneousInt32Int32x4Leaf();
}
}
@@ -803,3 +804,38 @@
calloc.free(a7Pointer);
}
+
+final variadicAt1Struct12BytesHomogeneousInt32Int32x4Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int32 Function(Struct12BytesHomogeneousInt32,
+ VarArgs<(Int32, Int32, Int32, Int32)>),
+ int Function(Struct12BytesHomogeneousInt32, int, int, int, int)>(
+ "VariadicAt1Struct12BytesHomogeneousInt32Int32x4",
+ isLeaf: true);
+
+/// Variadic arguments test on macos_arm64.
+void testVariadicAt1Struct12BytesHomogeneousInt32Int32x4Leaf() {
+ final a0Pointer = calloc<Struct12BytesHomogeneousInt32>();
+ final Struct12BytesHomogeneousInt32 a0 = a0Pointer.ref;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1 = 4;
+ a2 = -5;
+ a3 = 6;
+ a4 = -7;
+
+ final result =
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.equals(-4, result);
+
+ calloc.free(a0Pointer);
+}
diff --git a/tests/ffi/function_varargs_generated_native_leaf_test.dart b/tests/ffi/function_varargs_generated_native_leaf_test.dart
index 85d3986..a27a27f 100644
--- a/tests/ffi/function_varargs_generated_native_leaf_test.dart
+++ b/tests/ffi/function_varargs_generated_native_leaf_test.dart
@@ -45,6 +45,7 @@
testVariadicAt1DoubleInt64Int32Struct20BytesHomogeneouNativeLeaf();
testVariadicAt5Doublex5NativeLeaf();
testVariadicAt1Int64x7Struct12BytesHomogeneousInt32NativeLeaf();
+ testVariadicAt1Struct12BytesHomogeneousInt32Int32x4NativeLeaf();
}
}
@@ -798,3 +799,37 @@
calloc.free(a7Pointer);
}
+
+@Native<
+ Int32 Function(Struct12BytesHomogeneousInt32,
+ VarArgs<(Int32, Int32, Int32, Int32)>)>(
+ symbol: 'VariadicAt1Struct12BytesHomogeneousInt32Int32x4', isLeaf: true)
+external int variadicAt1Struct12BytesHomogeneousInt32Int32x4NativeLeaf(
+ Struct12BytesHomogeneousInt32 a0, int a1, int a2, int a3, int a4);
+
+/// Variadic arguments test on macos_arm64.
+void testVariadicAt1Struct12BytesHomogeneousInt32Int32x4NativeLeaf() {
+ final a0Pointer = calloc<Struct12BytesHomogeneousInt32>();
+ final Struct12BytesHomogeneousInt32 a0 = a0Pointer.ref;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1 = 4;
+ a2 = -5;
+ a3 = 6;
+ a4 = -7;
+
+ final result = variadicAt1Struct12BytesHomogeneousInt32Int32x4NativeLeaf(
+ a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.equals(-4, result);
+
+ calloc.free(a0Pointer);
+}
diff --git a/tests/ffi/function_varargs_generated_native_test.dart b/tests/ffi/function_varargs_generated_native_test.dart
index 379908d..34520cf 100644
--- a/tests/ffi/function_varargs_generated_native_test.dart
+++ b/tests/ffi/function_varargs_generated_native_test.dart
@@ -45,6 +45,7 @@
testVariadicAt1DoubleInt64Int32Struct20BytesHomogeneouNative();
testVariadicAt5Doublex5Native();
testVariadicAt1Int64x7Struct12BytesHomogeneousInt32Native();
+ testVariadicAt1Struct12BytesHomogeneousInt32Int32x4Native();
}
}
@@ -793,3 +794,37 @@
calloc.free(a7Pointer);
}
+
+@Native<
+ Int32 Function(Struct12BytesHomogeneousInt32,
+ VarArgs<(Int32, Int32, Int32, Int32)>)>(
+ symbol: 'VariadicAt1Struct12BytesHomogeneousInt32Int32x4')
+external int variadicAt1Struct12BytesHomogeneousInt32Int32x4Native(
+ Struct12BytesHomogeneousInt32 a0, int a1, int a2, int a3, int a4);
+
+/// Variadic arguments test on macos_arm64.
+void testVariadicAt1Struct12BytesHomogeneousInt32Int32x4Native() {
+ final a0Pointer = calloc<Struct12BytesHomogeneousInt32>();
+ final Struct12BytesHomogeneousInt32 a0 = a0Pointer.ref;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1 = 4;
+ a2 = -5;
+ a3 = 6;
+ a4 = -7;
+
+ final result =
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4Native(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.equals(-4, result);
+
+ calloc.free(a0Pointer);
+}
diff --git a/tests/ffi/function_varargs_generated_test.dart b/tests/ffi/function_varargs_generated_test.dart
index c46eff0..705a186 100644
--- a/tests/ffi/function_varargs_generated_test.dart
+++ b/tests/ffi/function_varargs_generated_test.dart
@@ -42,6 +42,7 @@
testVariadicAt1DoubleInt64Int32Struct20BytesHomogeneou();
testVariadicAt5Doublex5();
testVariadicAt1Int64x7Struct12BytesHomogeneousInt32();
+ testVariadicAt1Struct12BytesHomogeneousInt32Int32x4();
}
}
@@ -768,3 +769,37 @@
calloc.free(a7Pointer);
}
+
+final variadicAt1Struct12BytesHomogeneousInt32Int32x4 =
+ ffiTestFunctions.lookupFunction<
+ Int32 Function(Struct12BytesHomogeneousInt32,
+ VarArgs<(Int32, Int32, Int32, Int32)>),
+ int Function(Struct12BytesHomogeneousInt32, int, int, int,
+ int)>("VariadicAt1Struct12BytesHomogeneousInt32Int32x4");
+
+/// Variadic arguments test on macos_arm64.
+void testVariadicAt1Struct12BytesHomogeneousInt32Int32x4() {
+ final a0Pointer = calloc<Struct12BytesHomogeneousInt32>();
+ final Struct12BytesHomogeneousInt32 a0 = a0Pointer.ref;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1 = 4;
+ a2 = -5;
+ a3 = 6;
+ a4 = -7;
+
+ final result =
+ variadicAt1Struct12BytesHomogeneousInt32Int32x4(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.equals(-4, result);
+
+ calloc.free(a0Pointer);
+}
diff --git a/tests/ffi/generator/structs_by_value_tests_configuration.dart b/tests/ffi/generator/structs_by_value_tests_configuration.dart
index 60126ea4..d1a0043 100644
--- a/tests/ffi/generator/structs_by_value_tests_configuration.dart
+++ b/tests/ffi/generator/structs_by_value_tests_configuration.dart
@@ -847,6 +847,18 @@
int64,
"Struct stradles last argument register, variadic",
),
+ FunctionType(
+ varArgsIndex: 1,
+ [
+ struct12bytesInt,
+ int32,
+ int32,
+ int32,
+ int32,
+ ],
+ int32,
+ "Variadic arguments test on macos_arm64.",
+ ),
];
final struct1byteBool = StructType([bool_]);