| // 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. | |
| import 'dart:ffi'; | |
| import 'dart:io'; | |
| typedef PosixMallocNative = Pointer Function(IntPtr); | |
| @Native<PosixMallocNative>(symbol: 'malloc') | |
| external Pointer posixMalloc(int size); | |
| typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size); | |
| @Native<PosixCallocNative>(symbol: 'calloc') | |
| external Pointer posixCalloc(int num, int size); | |
| typedef PosixFreeNative = Void Function(Pointer); | |
| @Native<Void Function(Pointer)>(symbol: 'free') | |
| external void posixFree(Pointer ptr); | |
| final Pointer<NativeFunction<PosixFreeNative>> posixFreePointer = | |
| Native.addressOf(posixFree); | |
| // Note that ole32.dll is the correct name in both 32-bit and 64-bit. | |
| final DynamicLibrary ole32lib = DynamicLibrary.open('ole32.dll'); | |
| typedef WinCoTaskMemAllocNative = Pointer Function(Size); | |
| typedef WinCoTaskMemAlloc = Pointer Function(int); | |
| final WinCoTaskMemAlloc winCoTaskMemAlloc = ole32lib | |
| .lookupFunction<WinCoTaskMemAllocNative, WinCoTaskMemAlloc>( | |
| 'CoTaskMemAlloc', | |
| ); | |
| typedef WinCoTaskMemFreeNative = Void Function(Pointer); | |
| typedef WinCoTaskMemFree = void Function(Pointer); | |
| final Pointer<NativeFunction<WinCoTaskMemFreeNative>> winCoTaskMemFreePointer = | |
| ole32lib.lookup('CoTaskMemFree'); | |
| final WinCoTaskMemFree winCoTaskMemFree = winCoTaskMemFreePointer.asFunction(); | |
| /// Manages memory on the native heap. | |
| /// | |
| /// Does not initialize newly allocated memory to zero. Use [CallocAllocator] | |
| /// for zero-initialized memory on allocation. | |
| /// | |
| /// For POSIX-based systems, this uses `malloc` and `free`. On Windows, it uses | |
| /// `CoTaskMemAlloc` and `CoTaskMemFree`. | |
| final class MallocAllocator implements Allocator { | |
| const MallocAllocator._(); | |
| /// Allocates [byteCount] bytes of of uninitialized memory on the native heap. | |
| /// | |
| /// For POSIX-based systems, this uses `malloc`. On Windows, it uses | |
| /// `CoTaskMemAlloc`. | |
| /// | |
| /// Throws an [ArgumentError] if the number of bytes or alignment cannot be | |
| /// satisfied. | |
| // TODO: Stop ignoring alignment if it's large, for example for SSE data. | |
| @override | |
| Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) { | |
| Pointer<T> result; | |
| if (Platform.isWindows) { | |
| result = winCoTaskMemAlloc(byteCount).cast(); | |
| } else { | |
| result = posixMalloc(byteCount).cast(); | |
| } | |
| if (result.address == 0) { | |
| throw ArgumentError('Could not allocate $byteCount bytes.'); | |
| } | |
| return result; | |
| } | |
| /// Releases memory allocated on the native heap. | |
| /// | |
| /// For POSIX-based systems, this uses `free`. On Windows, it uses | |
| /// `CoTaskMemFree`. It may only be used against pointers allocated in a | |
| /// manner equivalent to [allocate]. | |
| @override | |
| void free(Pointer pointer) { | |
| if (Platform.isWindows) { | |
| winCoTaskMemFree(pointer); | |
| } else { | |
| posixFree(pointer); | |
| } | |
| } | |
| /// Returns a pointer to a native free function. | |
| /// | |
| /// This function can be used to release memory allocated by [allocate] | |
| /// from the native side. It can also be used as a finalization callback | |
| /// passed to `NativeFinalizer` constructor or `Pointer.atTypedList` | |
| /// method. | |
| /// | |
| /// For example to automatically free native memory when the Dart object | |
| /// wrapping it is reclaimed by GC: | |
| /// | |
| /// ```dart | |
| /// class Wrapper implements Finalizable { | |
| /// static final finalizer = NativeFinalizer(malloc.nativeFree); | |
| /// | |
| /// final Pointer<Uint8> data; | |
| /// | |
| /// Wrapper() : data = malloc.allocate<Uint8>(length) { | |
| /// finalizer.attach(this, data); | |
| /// } | |
| /// } | |
| /// ``` | |
| /// | |
| /// or to free native memory that is owned by a typed list: | |
| /// | |
| /// ```dart | |
| /// malloc.allocate<Uint8>(n).asTypedList(n, finalizer: malloc.nativeFree) | |
| /// ``` | |
| /// | |
| Pointer<NativeFinalizerFunction> get nativeFree => | |
| Platform.isWindows ? winCoTaskMemFreePointer : posixFreePointer; | |
| } | |
| /// Manages memory on the native heap. | |
| /// | |
| /// Does not initialize newly allocated memory to zero. Use [calloc] for | |
| /// zero-initialized memory allocation. | |
| /// | |
| /// For POSIX-based systems, this uses `malloc` and `free`. On Windows, it uses | |
| /// `CoTaskMemAlloc` and `CoTaskMemFree`. | |
| const MallocAllocator malloc = MallocAllocator._(); | |
| /// Manages memory on the native heap. | |
| /// | |
| /// Initializes newly allocated memory to zero. | |
| /// | |
| /// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses | |
| /// `CoTaskMemAlloc` and `CoTaskMemFree`. | |
| final class CallocAllocator implements Allocator { | |
| const CallocAllocator._(); | |
| /// Fills a block of memory with a specified value. | |
| void _fillMemory(Pointer destination, int length, int fill) { | |
| final ptr = destination.cast<Uint8>(); | |
| for (var i = 0; i < length; i++) { | |
| ptr[i] = fill; | |
| } | |
| } | |
| /// Fills a block of memory with zeros. | |
| /// | |
| void _zeroMemory(Pointer destination, int length) => | |
| _fillMemory(destination, length, 0); | |
| /// Allocates [byteCount] bytes of zero-initialized of memory on the native | |
| /// heap. | |
| /// | |
| /// For POSIX-based systems, this uses `malloc`. On Windows, it uses | |
| /// `CoTaskMemAlloc`. | |
| /// | |
| /// Throws an [ArgumentError] if the number of bytes or alignment cannot be | |
| /// satisfied. | |
| // TODO: Stop ignoring alignment if it's large, for example for SSE data. | |
| @override | |
| Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) { | |
| Pointer<T> result; | |
| if (Platform.isWindows) { | |
| result = winCoTaskMemAlloc(byteCount).cast(); | |
| } else { | |
| result = posixCalloc(byteCount, 1).cast(); | |
| } | |
| if (result.address == 0) { | |
| throw ArgumentError('Could not allocate $byteCount bytes.'); | |
| } | |
| if (Platform.isWindows) { | |
| _zeroMemory(result, byteCount); | |
| } | |
| return result; | |
| } | |
| /// Releases memory allocated on the native heap. | |
| /// | |
| /// For POSIX-based systems, this uses `free`. On Windows, it uses | |
| /// `CoTaskMemFree`. It may only be used against pointers allocated in a | |
| /// manner equivalent to [allocate]. | |
| @override | |
| void free(Pointer pointer) { | |
| if (Platform.isWindows) { | |
| winCoTaskMemFree(pointer); | |
| } else { | |
| posixFree(pointer); | |
| } | |
| } | |
| /// Returns a pointer to a native free function. | |
| /// | |
| /// This function can be used to release memory allocated by [allocate] | |
| /// from the native side. It can also be used as a finalization callback | |
| /// passed to `NativeFinalizer` constructor or `Pointer.atTypedList` | |
| /// method. | |
| /// | |
| /// For example to automatically free native memory when the Dart object | |
| /// wrapping it is reclaimed by GC: | |
| /// | |
| /// ```dart | |
| /// class Wrapper implements Finalizable { | |
| /// static final finalizer = NativeFinalizer(calloc.nativeFree); | |
| /// | |
| /// final Pointer<Uint8> data; | |
| /// | |
| /// Wrapper() : data = calloc.allocate<Uint8>(length) { | |
| /// finalizer.attach(this, data); | |
| /// } | |
| /// } | |
| /// ``` | |
| /// | |
| /// or to free native memory that is owned by a typed list: | |
| /// | |
| /// ```dart | |
| /// calloc.allocate<Uint8>(n).asTypedList(n, finalizer: calloc.nativeFree) | |
| /// ``` | |
| /// | |
| Pointer<NativeFinalizerFunction> get nativeFree => | |
| Platform.isWindows ? winCoTaskMemFreePointer : posixFreePointer; | |
| } | |
| /// Manages memory on the native heap. | |
| /// | |
| /// Initializes newly allocated memory to zero. Use [malloc] for uninitialized | |
| /// memory allocation. | |
| /// | |
| /// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses | |
| /// `CoTaskMemAlloc` and `CoTaskMemFree`. | |
| const CallocAllocator calloc = CallocAllocator._(); |