diff options
| author | Michael Dusan <michael.dusan@gmail.com> | 2020-02-10 21:08:08 -0500 |
|---|---|---|
| committer | Michael Dusan <michael.dusan@gmail.com> | 2020-02-10 21:08:08 -0500 |
| commit | edb210905dcbe666fa5222bceacd2e5bdb16bb89 (patch) | |
| tree | 984aec0e5bad756daf426855c54bae3c42c73eca /src/mem.hpp | |
| parent | 1cdefeb10b7496126bbb7d00709235abfee56a4a (diff) | |
| download | zig-edb210905dcbe666fa5222bceacd2e5bdb16bb89.tar.gz zig-edb210905dcbe666fa5222bceacd2e5bdb16bb89.zip | |
stage1: memory/report overhaul
- 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()`
Diffstat (limited to 'src/mem.hpp')
| -rw-r--r-- | src/mem.hpp | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/src/mem.hpp b/src/mem.hpp new file mode 100644 index 0000000000..9e262b7d53 --- /dev/null +++ b/src/mem.hpp @@ -0,0 +1,149 @@ +/* + * 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 |
