Skip to content

Commit e8c1391

Browse files
dcharkescommit-bot@chromium.org
authored andcommitted
[vm/ffi] Test truncation and extension on calls and callbacks
This CL adds tests for the truncation and sign extension of the following cases: * Arguments in registers in callbacks (we already had these for calls). * Arguments on stack in calls and callbacks. * Return values in registers in calls and callbacks. Related CL (replacing FFI pipeline): https://dart-review.googlesource.com/c/sdk/+/129081 Change-Id: I776d103cf72007b686b1fe804d6a3bc6cb0e7122 Cq-Include-Trybots: luci.dart.try:vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,app-kernel-linux-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-kernel-precomp-linux-debug-x64-try,vm-dartkb-linux-release-x64-abi-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,dart-sdk-linux-try,analyzer-analysis-server-linux-try,analyzer-linux-release-try,front-end-linux-release-x64-try,vm-kernel-precomp-win-release-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/132284 Commit-Queue: Daco Harkes <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent e7b1392 commit e8c1391

File tree

3 files changed

+191
-15
lines changed

3 files changed

+191
-15
lines changed

runtime/bin/ffi_test/ffi_test_functions.cc

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ DART_EXPORT int32_t SumPlus42(int32_t a, int32_t b) {
4949
return retval;
5050
}
5151

52-
//// Tests for sign and zero extension of arguments and results.
53-
52+
// Tests for sign and zero extension return values when passed to Dart.
5453
DART_EXPORT uint8_t ReturnMaxUint8() {
5554
return 0xff;
5655
}
@@ -75,36 +74,100 @@ DART_EXPORT int32_t ReturnMinInt32() {
7574
return 0x80000000;
7675
}
7776

77+
// Test that return values are truncated by callee before passed to Dart.
78+
DART_EXPORT uint8_t ReturnMaxUint8v2() {
79+
uint64_t v = 0xabcff;
80+
// Truncated to 8 bits and zero extended, or truncated to 32 bits, depending
81+
// on ABI.
82+
return v;
83+
}
84+
85+
DART_EXPORT uint16_t ReturnMaxUint16v2() {
86+
uint64_t v = 0xabcffff;
87+
return v;
88+
}
89+
90+
DART_EXPORT uint32_t ReturnMaxUint32v2() {
91+
uint64_t v = 0xabcffffffff;
92+
return v;
93+
}
94+
95+
DART_EXPORT int8_t ReturnMinInt8v2() {
96+
int64_t v = 0x8abc80;
97+
return v;
98+
}
99+
100+
DART_EXPORT int16_t ReturnMinInt16v2() {
101+
int64_t v = 0x8abc8000;
102+
return v;
103+
}
104+
105+
DART_EXPORT int32_t ReturnMinInt32v2() {
106+
int64_t v = 0x8abc80000000;
107+
return v;
108+
}
109+
110+
// Test that arguments are truncated correctly.
78111
DART_EXPORT intptr_t TakeMaxUint8(uint8_t x) {
112+
std::cout << "TakeMaxUint8(" << static_cast<int>(x) << ")\n";
79113
return x == 0xff ? 1 : 0;
80114
}
81115

82116
DART_EXPORT intptr_t TakeMaxUint16(uint16_t x) {
117+
std::cout << "TakeMaxUint16(" << x << ")\n";
83118
return x == 0xffff ? 1 : 0;
84119
}
85120

86121
DART_EXPORT intptr_t TakeMaxUint32(uint32_t x) {
122+
std::cout << "TakeMaxUint32(" << x << ")\n";
87123
return x == 0xffffffff ? 1 : 0;
88124
}
89125

90126
DART_EXPORT intptr_t TakeMinInt8(int8_t x) {
127+
std::cout << "TakeMinInt8(" << static_cast<int>(x) << ")\n";
91128
const int64_t expected = -0x80;
92129
const int64_t received = x;
93130
return expected == received ? 1 : 0;
94131
}
95132

96133
DART_EXPORT intptr_t TakeMinInt16(int16_t x) {
134+
std::cout << "TakeMinInt16(" << x << ")\n";
97135
const int64_t expected = -0x8000;
98136
const int64_t received = x;
99137
return expected == received ? 1 : 0;
100138
}
101139

102140
DART_EXPORT intptr_t TakeMinInt32(int32_t x) {
141+
std::cout << "TakeMinInt32(" << x << ")\n";
103142
const int64_t expected = INT32_MIN;
104143
const int64_t received = x;
105144
return expected == received ? 1 : 0;
106145
}
107146

147+
// Test that arguments are truncated correctly, including stack arguments
148+
DART_EXPORT intptr_t TakeMaxUint8x10(uint8_t a,
149+
uint8_t b,
150+
uint8_t c,
151+
uint8_t d,
152+
uint8_t e,
153+
uint8_t f,
154+
uint8_t g,
155+
uint8_t h,
156+
uint8_t i,
157+
uint8_t j) {
158+
std::cout << "TakeMaxUint8x10(" << static_cast<int>(a) << ", "
159+
<< static_cast<int>(b) << ", " << static_cast<int>(c) << ", "
160+
<< static_cast<int>(d) << ", " << static_cast<int>(e) << ", "
161+
<< static_cast<int>(f) << ", " << static_cast<int>(g) << ", "
162+
<< static_cast<int>(h) << ", " << static_cast<int>(i) << ", "
163+
<< static_cast<int>(j) << ", "
164+
<< ")\n";
165+
return (a == 0xff && b == 0xff && c == 0xff && d == 0xff && e == 0xff &&
166+
f == 0xff && g == 0xff && h == 0xff && i == 0xff && j == 0xff)
167+
? 1
168+
: 0;
169+
}
170+
108171
// Performs some computation on various sized signed ints.
109172
// Used for testing value ranges for signed ints.
110173
DART_EXPORT int64_t IntComputation(int8_t a, int16_t b, int32_t c, int64_t d) {
@@ -656,6 +719,29 @@ DART_EXPORT int TestThrowException(int (*fn)()) {
656719
return 0;
657720
}
658721

722+
DART_EXPORT int TestTakeMaxUint8x10(intptr_t (*fn)(uint8_t,
723+
uint8_t,
724+
uint8_t,
725+
uint8_t,
726+
uint8_t,
727+
uint8_t,
728+
uint8_t,
729+
uint8_t,
730+
uint8_t,
731+
uint8_t)) {
732+
CHECK_EQ(1, fn(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF));
733+
// Check the argument values are properly truncated.
734+
uint64_t v = 0xabcFF;
735+
CHECK_EQ(1, fn(v, v, v, v, v, v, v, v, v, v));
736+
return 0;
737+
}
738+
739+
DART_EXPORT int TestReturnMaxUint8(uint8_t (*fn)()) {
740+
std::cout << "TestReturnMaxUint8(fn): " << static_cast<int>(fn()) << "\n";
741+
CHECK_EQ(0xFF, fn());
742+
return 0;
743+
}
744+
659745
// Receives some pointer (Pointer<NativeType> in Dart) and writes some bits.
660746
DART_EXPORT void NativeTypePointerParam(void* p) {
661747
uint8_t* p2 = reinterpret_cast<uint8_t*>(p);

tests/ffi/function_callbacks_test.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,34 @@ Pointer<Void> throwExceptionPointer() {
189189
throw "Exception.";
190190
}
191191

192+
typedef TakeMaxUint8x10Type = IntPtr Function(
193+
Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8);
194+
int takeMaxUint8x10(
195+
int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) {
196+
print("takeMaxUint8x10($a, $b, $c, $d, $e, $f, $g, $h, $i, $j)");
197+
return a == 0xff &&
198+
b == 0xff &&
199+
c == 0xff &&
200+
d == 0xff &&
201+
e == 0xff &&
202+
f == 0xff &&
203+
g == 0xff &&
204+
h == 0xff &&
205+
i == 0xff &&
206+
j == 0xff
207+
? 1
208+
: 0;
209+
}
210+
211+
typedef ReturnMaxUint8Type = Uint8 Function();
212+
int returnMaxUint8() {
213+
return 0xff;
214+
}
215+
216+
int returnMaxUint8v2() {
217+
return 0xabcff;
218+
}
219+
192220
final List<Test> testcases = [
193221
Test("SimpleAddition",
194222
Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 0)),
@@ -213,6 +241,12 @@ final List<Test> testcases = [
213241
Pointer.fromFunction<ThrowExceptionPointer>(throwExceptionPointer)),
214242
Test("ThrowException",
215243
Pointer.fromFunction<ThrowExceptionInt>(throwExceptionInt, 42)),
244+
Test("TakeMaxUint8x10",
245+
Pointer.fromFunction<TakeMaxUint8x10Type>(takeMaxUint8x10, 0)),
246+
Test("ReturnMaxUint8",
247+
Pointer.fromFunction<ReturnMaxUint8Type>(returnMaxUint8, 0)),
248+
Test("ReturnMaxUint8",
249+
Pointer.fromFunction<ReturnMaxUint8Type>(returnMaxUint8v2, 0)),
216250
];
217251

218252
void main() {

tests/ffi/function_test.dart

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,36 +87,60 @@ int Function() returnMaxUint8 = ffiTestFunctions
8787
.lookup("ReturnMaxUint8")
8888
.cast<NativeFunction<NativeReturnMaxUint8>>()
8989
.asFunction();
90+
int Function() returnMaxUint8v2 = ffiTestFunctions
91+
.lookup("ReturnMaxUint8v2")
92+
.cast<NativeFunction<NativeReturnMaxUint8>>()
93+
.asFunction();
9094

9195
typedef NativeReturnMaxUint16 = Uint16 Function();
9296
int Function() returnMaxUint16 = ffiTestFunctions
9397
.lookup("ReturnMaxUint16")
9498
.cast<NativeFunction<NativeReturnMaxUint16>>()
9599
.asFunction();
100+
int Function() returnMaxUint16v2 = ffiTestFunctions
101+
.lookup("ReturnMaxUint16v2")
102+
.cast<NativeFunction<NativeReturnMaxUint16>>()
103+
.asFunction();
96104

97105
typedef NativeReturnMaxUint32 = Uint32 Function();
98106
int Function() returnMaxUint32 = ffiTestFunctions
99107
.lookup("ReturnMaxUint32")
100108
.cast<NativeFunction<NativeReturnMaxUint32>>()
101109
.asFunction();
110+
int Function() returnMaxUint32v2 = ffiTestFunctions
111+
.lookup("ReturnMaxUint32v2")
112+
.cast<NativeFunction<NativeReturnMaxUint32>>()
113+
.asFunction();
102114

103115
typedef NativeReturnMinInt8 = Int8 Function();
104116
int Function() returnMinInt8 = ffiTestFunctions
105117
.lookup("ReturnMinInt8")
106118
.cast<NativeFunction<NativeReturnMinInt8>>()
107119
.asFunction();
120+
int Function() returnMinInt8v2 = ffiTestFunctions
121+
.lookup("ReturnMinInt8v2")
122+
.cast<NativeFunction<NativeReturnMinInt8>>()
123+
.asFunction();
108124

109125
typedef NativeReturnMinInt16 = Int16 Function();
110126
int Function() returnMinInt16 = ffiTestFunctions
111127
.lookup("ReturnMinInt16")
112128
.cast<NativeFunction<NativeReturnMinInt16>>()
113129
.asFunction();
130+
int Function() returnMinInt16v2 = ffiTestFunctions
131+
.lookup("ReturnMinInt16v2")
132+
.cast<NativeFunction<NativeReturnMinInt16>>()
133+
.asFunction();
114134

115135
typedef NativeReturnMinInt32 = Int32 Function();
116136
int Function() returnMinInt32 = ffiTestFunctions
117137
.lookup("ReturnMinInt32")
118138
.cast<NativeFunction<NativeReturnMinInt32>>()
119139
.asFunction();
140+
int Function() returnMinInt32v2 = ffiTestFunctions
141+
.lookup("ReturnMinInt32v2")
142+
.cast<NativeFunction<NativeReturnMinInt32>>()
143+
.asFunction();
120144

121145
typedef NativeTakeMaxUint8 = IntPtr Function(Uint8);
122146
int Function(int) takeMaxUint8 = ffiTestFunctions
@@ -154,20 +178,52 @@ int Function(int) takeMinInt32 = ffiTestFunctions
154178
.cast<NativeFunction<NativeTakeMinInt32>>()
155179
.asFunction();
156180

181+
typedef NativeTakeMaxUint8x10 = IntPtr Function(
182+
Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8);
183+
int Function(int, int, int, int, int, int, int, int, int, int) takeMaxUint8x10 =
184+
ffiTestFunctions
185+
.lookup("TakeMaxUint8x10")
186+
.cast<NativeFunction<NativeTakeMaxUint8x10>>()
187+
.asFunction();
188+
157189
void testExtension() {
158-
Expect.equals(returnMaxUint8(), 0xff);
159-
Expect.equals(returnMaxUint16(), 0xffff);
160-
Expect.equals(returnMaxUint32(), 0xffffffff);
161-
Expect.equals(returnMinInt8(), -0x80);
162-
Expect.equals(returnMinInt16(), -0x8000);
163-
Expect.equals(returnMinInt32(), -0x80000000);
164-
165-
Expect.equals(takeMaxUint8(0xff), 1);
166-
Expect.equals(takeMaxUint16(0xffff), 1);
167-
Expect.equals(takeMaxUint32(0xffffffff), 1);
168-
Expect.equals(takeMinInt8(0x80), 1);
169-
Expect.equals(takeMinInt16(0x8000), 1);
170-
Expect.equals(takeMinInt32(0x80000000), 1);
190+
// Sign extension on the way back to Dart.
191+
Expect.equals(0xff, returnMaxUint8());
192+
Expect.equals(0xffff, returnMaxUint16());
193+
Expect.equals(0xffffffff, returnMaxUint32());
194+
Expect.equals(-0x80, returnMinInt8());
195+
Expect.equals(-0x8000, returnMinInt16());
196+
Expect.equals(-0x80000000, returnMinInt32());
197+
// Truncation in C, and sign extension back to Dart.
198+
Expect.equals(0xff, returnMaxUint8v2());
199+
Expect.equals(0xffff, returnMaxUint16v2());
200+
Expect.equals(0xffffffff, returnMaxUint32v2());
201+
Expect.equals(-0x80, returnMinInt8v2());
202+
Expect.equals(-0x8000, returnMinInt16v2());
203+
Expect.equals(-0x80000000, returnMinInt32v2());
204+
205+
// Upper bits propper, should work without truncation.
206+
Expect.equals(1, takeMaxUint8(0xff));
207+
Expect.equals(1, takeMaxUint16(0xffff));
208+
Expect.equals(1, takeMaxUint32(0xffffffff));
209+
Expect.equals(1, takeMinInt8(-0x80));
210+
Expect.equals(1, takeMinInt16(-0x8000));
211+
Expect.equals(1, takeMinInt32(-0x80000000));
212+
Expect.equals(
213+
1,
214+
takeMaxUint8x10(
215+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff));
216+
// Upper bits garbage, needs to truncate.
217+
Expect.equals(1, takeMaxUint8(0xabcff));
218+
Expect.equals(1, takeMaxUint16(0xabcffff));
219+
Expect.equals(1, takeMaxUint32(0xabcffffffff));
220+
Expect.equals(1, takeMinInt8(0x8abc80));
221+
Expect.equals(1, takeMinInt16(0x8abc8000));
222+
Expect.equals(1, takeMinInt32(0x8abc80000000));
223+
Expect.equals(
224+
1,
225+
takeMaxUint8x10(0xabcff, 0xabcff, 0xabcff, 0xabcff, 0xabcff, 0xabcff,
226+
0xabcff, 0xabcff, 0xabcff, 0xabcff));
171227
}
172228

173229
QuadOp uintComputation = ffiTestFunctions

0 commit comments

Comments
 (0)