/* * Copyright (c) 2020 Andrew Kelley * * This file is part of zig, which is MIT licensed. * See http://opensource.org/licenses/MIT */ #ifndef ZIG_MEM_HPP #define ZIG_MEM_HPP #include #include #include #include "config.h" #include "util_base.hpp" #include "mem_type_info.hpp" // // -- Memory Allocation General Notes -- // // `heap::c_allocator` is the preferred general allocator. // // `heap::bootstrap_allocator` is an implementation detail for use // by allocators themselves when incidental heap may be required for // profiling and statistics. It breaks the infinite recursion cycle. // // `mem::os` contains a raw wrapper for system malloc API used in // preference to calling ::{malloc, free, calloc, realloc} directly. // This isolates usage and helps with audits: // // mem::os::malloc // mem::os::free // mem::os::calloc // mem::os::realloc // namespace mem { // initialize mem module before any use void init(); // deinitialize mem module to free memory and print report void deinit(); // isolate system/libc allocators namespace os { ATTRIBUTE_RETURNS_NOALIAS inline void *malloc(size_t size) { #ifndef NDEBUG // make behavior when size == 0 portable if (size == 0) return nullptr; #endif auto ptr = ::malloc(size); if (ptr == nullptr) zig_panic("allocation failed"); return ptr; } inline void free(void *ptr) { ::free(ptr); } ATTRIBUTE_RETURNS_NOALIAS inline void *calloc(size_t count, size_t size) { #ifndef NDEBUG // make behavior when size == 0 portable if (count == 0 || size == 0) return nullptr; #endif auto ptr = ::calloc(count, size); if (ptr == nullptr) zig_panic("allocation failed"); return ptr; } inline void *realloc(void *old_ptr, size_t size) { #ifndef NDEBUG // make behavior when size == 0 portable if (old_ptr == nullptr && size == 0) return nullptr; #endif auto ptr = ::realloc(old_ptr, size); if (ptr == nullptr) zig_panic("allocation failed"); return ptr; } } // namespace os struct Allocator { virtual void destruct(Allocator *allocator) = 0; template ATTRIBUTE_RETURNS_NOALIAS T *allocate(size_t count) { return reinterpret_cast(this->internal_allocate(TypeInfo::make(), count)); } template ATTRIBUTE_RETURNS_NOALIAS T *allocate_nonzero(size_t count) { return reinterpret_cast(this->internal_allocate_nonzero(TypeInfo::make(), count)); } template T *reallocate(T *old_ptr, size_t old_count, size_t new_count) { return reinterpret_cast(this->internal_reallocate(TypeInfo::make(), old_ptr, old_count, new_count)); } template T *reallocate_nonzero(T *old_ptr, size_t old_count, size_t new_count) { return reinterpret_cast(this->internal_reallocate_nonzero(TypeInfo::make(), old_ptr, old_count, new_count)); } template void deallocate(T *ptr, size_t count) { this->internal_deallocate(TypeInfo::make(), ptr, count); } template T *create() { return reinterpret_cast(this->internal_allocate(TypeInfo::make(), 1)); } template void destroy(T *ptr) { this->internal_deallocate(TypeInfo::make(), ptr, 1); } protected: ATTRIBUTE_RETURNS_NOALIAS virtual void *internal_allocate(const TypeInfo &info, size_t count) = 0; ATTRIBUTE_RETURNS_NOALIAS virtual void *internal_allocate_nonzero(const TypeInfo &info, size_t count) = 0; virtual void *internal_reallocate(const TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) = 0; virtual void *internal_reallocate_nonzero(const TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) = 0; virtual void internal_deallocate(const TypeInfo &info, void *ptr, size_t count) = 0; }; #ifdef ZIG_ENABLE_MEM_PROFILE void print_report(FILE *file = nullptr); // global memory report flag extern bool report_print; // global memory report default destination extern FILE *report_file; #endif } // namespace mem #endif