mirror of
https://github.com/ziglang/zig.git
synced 2025-12-20 21:23:06 +00:00
- split util_base.hpp from util.hpp - new namespaces: `mem` and `heap` - new `mem::Allocator` interface - new `heap::CAllocator` impl with global `heap::c_allocator` - new `heap::ArenaAllocator` impl - new `mem::TypeInfo` extracts names without RTTI - name extraction is enabled w/ ZIG_ENABLE_MEM_PROFILE=1 - new `mem::List` takes explicit `Allocator&` parameter - new `mem::HashMap` takes explicit `Allocator&` parameter - add Codegen.pass1_arena and use for all `ZigValue` allocs - deinit Codegen.pass1_arena early in `zig_llvm_emit_output()`
150 lines
4.1 KiB
C++
150 lines
4.1 KiB
C++
/*
|
|
* 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 <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#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 <typename T> ATTRIBUTE_RETURNS_NOALIAS
|
|
T *allocate(size_t count) {
|
|
return reinterpret_cast<T *>(this->internal_allocate(TypeInfo::make<T>(), count));
|
|
}
|
|
|
|
template <typename T> ATTRIBUTE_RETURNS_NOALIAS
|
|
T *allocate_nonzero(size_t count) {
|
|
return reinterpret_cast<T *>(this->internal_allocate_nonzero(TypeInfo::make<T>(), count));
|
|
}
|
|
|
|
template <typename T>
|
|
T *reallocate(T *old_ptr, size_t old_count, size_t new_count) {
|
|
return reinterpret_cast<T *>(this->internal_reallocate(TypeInfo::make<T>(), old_ptr, old_count, new_count));
|
|
}
|
|
|
|
template <typename T>
|
|
T *reallocate_nonzero(T *old_ptr, size_t old_count, size_t new_count) {
|
|
return reinterpret_cast<T *>(this->internal_reallocate_nonzero(TypeInfo::make<T>(), old_ptr, old_count, new_count));
|
|
}
|
|
|
|
template<typename T>
|
|
void deallocate(T *ptr, size_t count) {
|
|
this->internal_deallocate(TypeInfo::make<T>(), ptr, count);
|
|
}
|
|
|
|
template<typename T>
|
|
T *create() {
|
|
return reinterpret_cast<T *>(this->internal_allocate(TypeInfo::make<T>(), 1));
|
|
}
|
|
|
|
template<typename T>
|
|
void destroy(T *ptr) {
|
|
this->internal_deallocate(TypeInfo::make<T>(), 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
|