mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:20:31 +00:00
7487e5ea8b
A cleanup round of our FFI tests. Change-Id: I3883b9d14785c759c7129c072c9588bfa5a3fba0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/214802 Reviewed-by: Clement Skau <cskau@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
134 lines
5.1 KiB
Dart
134 lines
5.1 KiB
Dart
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file
|
|
|
|
// @dart = 2.9
|
|
|
|
import 'dart:ffi';
|
|
import 'dart:io';
|
|
|
|
import 'package:expect/expect.dart';
|
|
|
|
import 'ffi_test_helpers.dart';
|
|
|
|
// void* mmap(void* addr, size_t length,
|
|
// int prot, int flags,
|
|
// int fd, off_t offset)
|
|
typedef MMapNative = Pointer<Uint8> Function(Pointer<Uint8> address, IntPtr len,
|
|
IntPtr prot, IntPtr flags, IntPtr fd, IntPtr offset);
|
|
typedef MMap = Pointer<Uint8> Function(
|
|
Pointer<Uint8> address, int len, int prot, int flags, int fd, int offset);
|
|
final mmap = processSymbols.lookupFunction<MMapNative, MMap>('mmap');
|
|
|
|
// int munmap(void *addr, size_t length)
|
|
typedef MUnMapNative = IntPtr Function(Pointer<Uint8> address, IntPtr len);
|
|
typedef MUnMap = int Function(Pointer<Uint8> address, int len);
|
|
final munmap = processSymbols.lookupFunction<MUnMapNative, MUnMap>('munmap');
|
|
|
|
final processSymbols = DynamicLibrary.process();
|
|
|
|
const int kProtRead = 1;
|
|
const int kProtWrite = 2;
|
|
|
|
const int kMapPrivate = 2;
|
|
const int kMapFixed = 16;
|
|
final int kMapAnonymous = Platform.isMacOS ? 0x1000 : 0x20;
|
|
|
|
const int kMapFailed = -1;
|
|
|
|
// On 32-bit platforms the upper 4 bytes should be ignored.
|
|
const int kIgnoreBytesPositive = 0x1122334400000000;
|
|
const int kIgnoreBytesNegative = 0xffddccbb00000000;
|
|
|
|
void swapBytes(
|
|
Pointer<Uint8> memoryView, int indexOffset, int indexA, int indexB) {
|
|
final int oldA = memoryView[indexOffset + indexA];
|
|
memoryView[indexOffset + indexA] = memoryView[indexOffset + indexB];
|
|
memoryView[indexOffset + indexB] = oldA;
|
|
}
|
|
|
|
void testLoadsAndStores(int indexOffset, Pointer<Uint8> memory) {
|
|
for (int i = 0; i < 10; ++i) {
|
|
memory[indexOffset + i] = 10 + i;
|
|
}
|
|
Expect.listEquals(<int>[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
|
|
memory.offsetBy(indexOffset).asTypedList(10));
|
|
|
|
for (int i = 0; i < 9; ++i) {
|
|
swapBytes(memory, indexOffset + 0, i, i + 1);
|
|
}
|
|
Expect.listEquals(<int>[11, 12, 13, 14, 15, 16, 17, 18, 19, 10],
|
|
memory.offsetBy(indexOffset).asTypedList(10));
|
|
for (int i = 0; i < 9; ++i) {
|
|
swapBytes(memory, indexOffset + kIgnoreBytesPositive, i, i + 1);
|
|
}
|
|
Expect.listEquals(<int>[12, 13, 14, 15, 16, 17, 18, 19, 10, 11],
|
|
memory.offsetBy(indexOffset).asTypedList(10));
|
|
for (int i = 0; i < 9; ++i) {
|
|
swapBytes(memory, indexOffset + kIgnoreBytesNegative, i, i + 1);
|
|
}
|
|
Expect.listEquals(<int>[13, 14, 15, 16, 17, 18, 19, 10, 11, 12],
|
|
memory.offsetBy(indexOffset).asTypedList(10));
|
|
}
|
|
|
|
void testOnHighOrLowMemory(Pointer<Uint8> memory, int indexOffset) {
|
|
testLoadsAndStores(indexOffset, memory);
|
|
testLoadsAndStores(indexOffset, memory.offsetBy(5));
|
|
testLoadsAndStores(indexOffset, memory.offsetBy(-5));
|
|
testLoadsAndStores(indexOffset, memory.offsetBy(kIgnoreBytesPositive + 5));
|
|
testLoadsAndStores(indexOffset, memory.offsetBy(kIgnoreBytesNegative + 5));
|
|
testLoadsAndStores(indexOffset, memory.offsetBy(kIgnoreBytesPositive - 5));
|
|
testLoadsAndStores(indexOffset, memory.offsetBy(kIgnoreBytesNegative - 5));
|
|
final m2 = Pointer<Uint8>.fromAddress(kIgnoreBytesPositive + memory.address);
|
|
Expect.equals(memory, m2); //# 01: ok
|
|
Expect.equals(memory.address, m2.address); //# 01: ok
|
|
testLoadsAndStores(indexOffset, m2);
|
|
final m3 = Pointer<Uint8>.fromAddress(kIgnoreBytesNegative + memory.address);
|
|
Expect.equals(memory, m3); //# 01: ok
|
|
Expect.equals(memory.address, m3.address); //# 01: ok
|
|
testLoadsAndStores(indexOffset, m3);
|
|
}
|
|
|
|
const int kPageSize = 4096;
|
|
|
|
withMMapedAddress(
|
|
Pointer<Uint8> fixedAddress, void fun(Pointer<Uint8> address)) {
|
|
final result = mmap(fixedAddress, kPageSize, kProtRead | kProtWrite,
|
|
kMapAnonymous | kMapFixed | kMapPrivate, 0, 0);
|
|
if (result.address == kMapFailed) {
|
|
throw 'Could not mmap @0x${fixedAddress.address.toRadixString(16)}!';
|
|
}
|
|
Expect.equals(fixedAddress, result); //# 01: ok
|
|
Expect.equals(fixedAddress.address, result.address); //# 01: ok
|
|
try {
|
|
fun(result);
|
|
} finally {
|
|
if (munmap(result, kPageSize) != 0) {
|
|
throw 'Failed to unmap memory!';
|
|
}
|
|
}
|
|
}
|
|
|
|
main() {
|
|
final bool is32BitProcess = sizeOf<Pointer<Uint8>>() == 4;
|
|
|
|
// User space processes usually have
|
|
// * the lower 3 GB available on Linux/Android on 32bit OS
|
|
// * full 4 GB available on Linux/Android on 64bit OS
|
|
// * full 4 GB available on MacOS
|
|
// So we choose high and low addresses that fall into lower 3 GB.
|
|
if (is32BitProcess && !Platform.isWindows) {
|
|
final highMemoryAddress = Pointer<Uint8>.fromAddress(0xaaaa0000);
|
|
final lowMemoryAddress = Pointer<Uint8>.fromAddress(0x11110000);
|
|
withMMapedAddress(lowMemoryAddress, (Pointer<Uint8> lowMemory) {
|
|
withMMapedAddress(highMemoryAddress, (Pointer<Uint8> highMemory) {
|
|
testOnHighOrLowMemory(lowMemory, 2048);
|
|
testOnHighOrLowMemory(highMemory, 2048);
|
|
testOnHighOrLowMemory(
|
|
lowMemory, 2048 + highMemory.address - lowMemory.address);
|
|
testOnHighOrLowMemory(
|
|
highMemory, 2048 + lowMemory.address - highMemory.address);
|
|
});
|
|
});
|
|
}
|
|
}
|