blob: 8b58884c1bd70f6563c52e279b6923aa71d04055 [file] [log] [blame]
// 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';
// Note that ole32.dll is the correct name in both 32-bit and 64-bit.
final DynamicLibrary stdlib = Platform.isWindows
? DynamicLibrary.open('ole32.dll')
: DynamicLibrary.process();
typedef PosixMallocNative = Pointer Function(IntPtr);
typedef PosixMalloc = Pointer Function(int);
final PosixMalloc posixMalloc =
stdlib.lookupFunction<PosixMallocNative, PosixMalloc>('malloc');
typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
typedef PosixCalloc = Pointer Function(int num, int size);
final PosixCalloc posixCalloc =
stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
typedef PosixFreeNative = Void Function(Pointer);
typedef PosixFree = void Function(Pointer);
final PosixFree posixFree =
stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
typedef WinCoTaskMemAllocNative = Pointer Function(Size cb);
typedef WinCoTaskMemAlloc = Pointer Function(int cb);
final WinCoTaskMemAlloc winCoTaskMemAlloc =
stdlib.lookupFunction<WinCoTaskMemAllocNative, WinCoTaskMemAlloc>(
'CoTaskMemAlloc');
typedef WinCoTaskMemFreeNative = Void Function(Pointer pv);
typedef WinCoTaskMemFree = void Function(Pointer pv);
final WinCoTaskMemFree winCoTaskMemFree = stdlib
.lookupFunction<WinCoTaskMemFreeNative, WinCoTaskMemFree>('CoTaskMemFree');
/// 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`.
class _MallocAllocator implements Allocator {
const _MallocAllocator();
/// Allocates [byteCount] bytes of of unitialized 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);
}
}
}
/// 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 Allocator 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`.
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);
}
}
}
/// 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 Allocator calloc = _CallocAllocator();