|
| 1 | +// Copyright (c) 2019, 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 | + |
| 5 | +import 'dart:ffi'; |
| 6 | +import 'dart:io'; |
| 7 | + |
| 8 | +// Note that kernel32.dll is the correct name in both 32-bit and 64-bit. |
| 9 | +final DynamicLibrary stdlib = Platform.isWindows |
| 10 | + ? DynamicLibrary.open("kernel32.dll") |
| 11 | + : DynamicLibrary.process(); |
| 12 | + |
| 13 | +typedef PosixMallocNative = Pointer Function(IntPtr); |
| 14 | +typedef PosixMalloc = Pointer Function(int); |
| 15 | +final PosixMalloc posixMalloc = |
| 16 | + stdlib.lookupFunction<PosixMallocNative, PosixMalloc>("malloc"); |
| 17 | + |
| 18 | +typedef PosixFreeNative = Void Function(Pointer); |
| 19 | +typedef PosixFree = void Function(Pointer); |
| 20 | +final PosixFree posixFree = |
| 21 | + stdlib.lookupFunction<PosixFreeNative, PosixFree>("free"); |
| 22 | + |
| 23 | +typedef WinGetProcessHeapFn = Pointer Function(); |
| 24 | +final WinGetProcessHeapFn winGetProcessHeap = stdlib |
| 25 | + .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>("GetProcessHeap"); |
| 26 | +final Pointer processHeap = winGetProcessHeap(); |
| 27 | + |
| 28 | +typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr); |
| 29 | +typedef WinHeapAlloc = Pointer Function(Pointer, int, int); |
| 30 | +final WinHeapAlloc winHeapAlloc = |
| 31 | + stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>("HeapAlloc"); |
| 32 | + |
| 33 | +typedef WinHeapFreeNative = Int32 Function( |
| 34 | + Pointer heap, Uint32 flags, Pointer memory); |
| 35 | +typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory); |
| 36 | +final WinHeapFree winHeapFree = |
| 37 | + stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>("HeapFree"); |
| 38 | + |
| 39 | +/// Allocates memory on the native heap. |
| 40 | +/// |
| 41 | +/// For POSIX-based systems, this uses malloc. On Windows, it uses HeapAlloc |
| 42 | +/// against the default public heap. Allocation of either element size or count |
| 43 | +/// of 0 is undefined. |
| 44 | +/// |
| 45 | +/// Throws an ArgumentError on failure to allocate. |
| 46 | +Pointer<T> allocate<T extends NativeType>({int count = 1}) { |
| 47 | + final int totalSize = count * sizeOf<T>(); |
| 48 | + Pointer<T> result; |
| 49 | + if (Platform.isWindows) { |
| 50 | + result = winHeapAlloc(processHeap, /*flags=*/ 0, totalSize).cast(); |
| 51 | + } else { |
| 52 | + result = posixMalloc(totalSize).cast(); |
| 53 | + } |
| 54 | + if (result.address == 0) { |
| 55 | + throw ArgumentError("Could not allocate $totalSize bytes."); |
| 56 | + } |
| 57 | + return result; |
| 58 | +} |
| 59 | + |
| 60 | +/// Releases memory on the native heap. |
| 61 | +/// |
| 62 | +/// For POSIX-based systems, this uses free. On Windows, it uses HeapFree |
| 63 | +/// against the default public heap. It may only be used against pointers |
| 64 | +/// allocated in a manner equivalent to [allocate]. |
| 65 | +/// |
| 66 | +/// Throws an ArgumentError on failure to free. |
| 67 | +/// |
| 68 | +// TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead |
| 69 | +// of testing the return integer to be non-zero. |
| 70 | +void free(Pointer pointer) { |
| 71 | + if (Platform.isWindows) { |
| 72 | + if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) { |
| 73 | + throw ArgumentError("Could not free $pointer."); |
| 74 | + } |
| 75 | + } else { |
| 76 | + posixFree(pointer); |
| 77 | + } |
| 78 | +} |
0 commit comments