Skip to content

Commit 3baae5c

Browse files
authored
Merge pull request #402 from yamacir-kit/garbage-collector
2 parents e01f937 + c09870a commit 3baae5c

17 files changed

+396
-373
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ sudo rm -rf /usr/local/share/meevax
103103

104104
| Target Name | Description
105105
|:-------------------|:--
106-
| `all` (default) | Build shared-library `libmeevax.0.4.64.so` and executable `meevax`.
106+
| `all` (default) | Build shared-library `libmeevax.0.4.81.so` and executable `meevax`.
107107
| `test` | Test executable `meevax`.
108-
| `package` | Generate debian package `meevax_0.4.64_amd64.deb`.
108+
| `package` | Generate debian package `meevax_0.4.81_amd64.deb`.
109109
| `install` | Copy files into `/usr/local` __(1)__.
110110
| `install.deb` | `all` + `package` + `sudo apt install <meevax>.deb`
111111
| `safe-install.deb` | `all` + `test` + `package` + `sudo apt install <meevax>.deb`
@@ -120,7 +120,7 @@ __(1)__ Meevax installed by `make install` cannot be uninstalled by the system's
120120
## Usage
121121

122122
```
123-
Meevax Lisp System, version 0.4.64
123+
Meevax Lisp System, version 0.4.81
124124
125125
Usage: meevax [OPTION...] [FILE...]
126126

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.4.64
1+
0.4.81

include/meevax/kernel/environment.hpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,9 @@ inline namespace kernel
7272

7373
auto declare_import(const_reference) -> void;
7474

75-
template <typename... Ts, REQUIRES(std::is_convertible<Ts, std::string>...)>
76-
auto declare_import(Ts&&... xs) -> void
75+
auto declare_import(std::string const& import_set) -> void
7776
{
78-
(declare_import(read(xs)), ...);
77+
declare_import(read(import_set));
7978
}
8079

8180
auto define(const_reference, const_reference = undefined) -> void;

include/meevax/kernel/heterogeneous.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ inline namespace kernel
8989

9090
if constexpr (std::is_same_v<Bound, Top>)
9191
{
92-
return heterogeneous(new (gc) Top(std::forward<decltype(xs)>(xs)...));
92+
return heterogeneous(gc.make<Top>(std::forward<decltype(xs)>(xs)...));
9393
}
9494
else if constexpr (std::is_class_v<Bound>)
9595
{
96-
return heterogeneous(new (gc) binder<Bound>(std::forward<decltype(xs)>(xs)...));
96+
return heterogeneous(gc.make<binder<Bound>>(std::forward<decltype(xs)>(xs)...));
9797
}
9898
else
9999
{

include/meevax/kernel/library.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef INCLUDED_MEEVAX_KERNEL_LIBRARY_HPP
1818
#define INCLUDED_MEEVAX_KERNEL_LIBRARY_HPP
1919

20+
#include <functional>
2021
#include <meevax/kernel/environment.hpp>
2122
#include <unordered_map>
2223

@@ -73,10 +74,9 @@ inline namespace kernel
7374
export_specs.push_back(export_spec);
7475
}
7576

76-
template <typename... Ts, REQUIRES(std::is_convertible<Ts, std::string>...)>
77-
auto declare_export(Ts&&... xs) -> void
77+
auto declare_export(std::string const& export_spec) -> void
7878
{
79-
(declare_export(read(xs)), ...);
79+
declare_export(read(export_spec));
8080
}
8181

8282
auto resolve_export_specs()

include/meevax/kernel/reader.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ inline namespace kernel
443443
{
444444
let const result = read(standard_input);
445445

446-
write(debug_port(), header(__func__), result, "\n");
446+
write(debug_port(), pretty::header(__func__), result, "\n");
447447

448448
return result;
449449
}

include/meevax/memory/collector.hpp

+97-42
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#include <new>
2626
#include <set>
2727

28-
#include <meevax/memory/region.hpp>
28+
#include <meevax/memory/tracer.hpp>
2929
#include <meevax/memory/simple_allocator.hpp>
3030
#include <meevax/string/header.hpp>
3131

@@ -44,68 +44,108 @@ inline namespace memory
4444
* ------------------------------------------------------------------------- */
4545
{
4646
public:
47-
struct collectable
47+
class traceable
4848
{
49+
friend class collector;
50+
51+
memory::tracer * tracer = nullptr;
52+
53+
explicit traceable(memory::tracer * tracer)
54+
: tracer { tracer }
55+
{
56+
if (tracer)
57+
{
58+
auto const lock = std::unique_lock(resource);
59+
traceables.insert(std::end(traceables), this);
60+
}
61+
}
62+
63+
auto reset(memory::tracer * after) -> void
64+
{
65+
if (auto before = std::exchange(tracer, after); not before and after)
66+
{
67+
auto const lock = std::unique_lock(resource);
68+
traceables.insert(this);
69+
}
70+
else if (before and not after)
71+
{
72+
traceables.erase(this);
73+
}
74+
}
75+
76+
auto locate(void * const data)
77+
{
78+
assert(data);
79+
80+
if (newest_tracer->contains(data)) // Heuristic-based optimization.
81+
{
82+
return newest_tracer;
83+
}
84+
else
85+
{
86+
auto dummy = memory::tracer(data, 0);
87+
auto iter = tracers.lower_bound(&dummy);
88+
assert(iter != std::end(tracers));
89+
return *iter;
90+
}
91+
}
92+
4993
protected:
50-
region * context = nullptr;
94+
explicit traceable() = default;
5195

52-
explicit constexpr collectable() = default;
96+
explicit traceable(traceable const& other)
97+
: traceable { other.tracer }
98+
{}
5399

54100
template <typename Pointer>
55-
explicit collectable(Pointer const p)
56-
: collectable { collector::reset(p, deallocator<Pointer>::deallocate) }
101+
explicit traceable(Pointer const p)
102+
: traceable { p ? locate(p) : nullptr }
57103
{}
58104

59-
explicit collectable(region * region)
60-
: context { region }
105+
~traceable()
61106
{
62-
if (context)
107+
if (tracer)
63108
{
64109
auto const lock = std::unique_lock(resource);
65-
objects.try_emplace(this, context);
110+
traceables.erase(this);
66111
}
67112
}
68113

69-
~collectable()
114+
auto reset()
70115
{
71-
auto const lock = std::unique_lock(resource);
72-
objects.erase(this);
116+
reset(nullptr);
73117
}
74118

75119
template <typename Pointer>
76120
auto reset(Pointer const p) -> void
77121
{
78-
reset(collector::reset(p, deallocator<Pointer>::deallocate));
122+
reset(p ? locate(p) : nullptr);
79123
}
80124

81-
auto reset(region * region) -> void
125+
auto reset(traceable const& other) -> void
82126
{
83-
if (context = region)
84-
{
85-
auto const lock = std::unique_lock(resource);
86-
objects.insert_or_assign(this, context);
87-
}
127+
reset(other.tracer);
88128
}
89129
};
90130

91131
private:
92-
static inline std::mutex resource;
93-
94-
static inline simple_allocator<region> region_allocator {};
95-
96132
template <typename T>
97133
using set = std::set<T, std::less<T>, simple_allocator<T>>;
98134

99-
static inline set<region *> regions;
135+
protected:
136+
static inline std::mutex resource;
137+
138+
static inline simple_allocator<tracer> tracer_source {};
139+
140+
static inline tracer * newest_tracer = nullptr;
100141

101-
template <typename T, typename U>
102-
using map = std::map<T, U, std::less<T>, simple_allocator<std::pair<T, U>>>;
142+
static inline set<tracer *> tracers {};
103143

104-
static inline map<collectable * const, region *> objects;
144+
static inline set<traceable *> traceables {};
105145

106-
static inline std::size_t allocation;
146+
static inline std::size_t allocation = 0;
107147

108-
static inline std::size_t threshold;
148+
static inline std::size_t threshold = 8_MiB;
109149

110150
public:
111151
explicit collector();
@@ -120,33 +160,48 @@ inline namespace memory
120160

121161
auto operator =(collector const&) -> collector & = delete;
122162

123-
static auto allocate(std::size_t const) -> void *;
163+
template <typename T, typename... Ts>
164+
static auto make(Ts&&... xs)
165+
{
166+
if (auto data = new T(std::forward<decltype(xs)>(xs)...); data)
167+
{
168+
if (allocation += sizeof(T); threshold < allocation)
169+
{
170+
collect();
171+
}
172+
173+
newest_tracer = tracer_source.new_(data, sizeof(T), deallocator<T>::deallocate);
174+
175+
assert(tracers.find(newest_tracer) == std::end(tracers));
176+
177+
tracers.insert(std::end(tracers), newest_tracer);
178+
179+
return data;
180+
}
181+
else
182+
{
183+
throw std::bad_alloc();
184+
}
185+
}
124186

125187
static auto clear() -> void;
126188

127189
static auto collect() -> std::size_t;
128190

129191
static auto count() noexcept -> std::size_t;
130192

131-
static auto deallocate(void * const, std::size_t const = 0) -> void;
132-
133193
static auto mark() -> void;
134194

135-
static auto region_of(void const* const) -> decltype(regions)::iterator;
136-
137-
static auto reset(void * const, deallocator<void>::signature const) -> region *;
195+
static auto tracer_of(void * const) -> decltype(tracers)::iterator;
138196

139197
static auto reset_threshold(std::size_t const = std::numeric_limits<std::size_t>::max()) -> void;
140198

141199
static auto sweep() -> void;
142200

143-
static auto traverse(region * const) -> void;
144-
} static gc;
201+
static auto trace(tracer * const) -> void;
202+
}
203+
static gc;
145204
} // namespace memory
146205
} // namespace meevax
147206

148-
auto operator new(std::size_t const, meevax::collector &) -> void *;
149-
150-
void operator delete(void * const, meevax::collector &) noexcept;
151-
152207
#endif // INCLUDED_MEEVAX_MEMORY_COLLECTOR_HPP

include/meevax/memory/deallocator.hpp

+3-11
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,11 @@ inline namespace memory
2626
template <typename T>
2727
struct deallocator
2828
{
29-
using signature = void (*)(void const* const);
29+
using signature = void (*)(void *);
3030

31-
static void deallocate(void const* const p)
31+
static void deallocate(void * p)
3232
{
33-
if constexpr (std::is_pointer<T>::value)
34-
{
35-
using element_type = typename std::pointer_traits<T>::element_type;
36-
delete static_cast<element_type const* const>(p);
37-
}
38-
else
39-
{
40-
delete static_cast<T const* const>(p);
41-
}
33+
delete static_cast<T *>(p);
4234
}
4335
};
4436
} // namespace memory

include/meevax/memory/gc_pointer.hpp

+20-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef INCLUDED_MEEVAX_MEMORY_GC_POINTER_HPP
1818
#define INCLUDED_MEEVAX_MEMORY_GC_POINTER_HPP
1919

20+
#include <cstddef>
2021
#include <meevax/memory/collector.hpp>
2122
#include <meevax/memory/nan_boxing_pointer.hpp>
2223

@@ -27,19 +28,25 @@ inline namespace memory
2728
template <typename... Ts>
2829
struct gc_pointer
2930
: public nan_boxing_pointer<Ts...>
30-
, private collector::collectable
31+
, private collector::traceable
3132
{
32-
gc_pointer(std::nullptr_t = nullptr)
33+
explicit gc_pointer(std::nullptr_t = nullptr)
34+
{}
35+
36+
template <typename T, REQUIRES(std::is_scalar<T>)>
37+
explicit gc_pointer(T const& datum)
38+
: nan_boxing_pointer<Ts...> { datum }
39+
, collector::traceable { nan_boxing_pointer<Ts...>::get() }
3340
{}
3441

3542
explicit gc_pointer(nan_boxing_pointer<Ts...> const& datum)
3643
: nan_boxing_pointer<Ts...> { datum }
37-
, collector::collectable { datum.get() }
44+
, collector::traceable { nan_boxing_pointer<Ts...>::get() }
3845
{}
3946

4047
explicit gc_pointer(gc_pointer const& gcp)
4148
: nan_boxing_pointer<Ts...> { gcp }
42-
, collector::collectable { gcp.context }
49+
, collector::traceable { static_cast<collector::traceable const&>(gcp) }
4350
{}
4451

4552
auto operator =(gc_pointer const& gcp) -> auto &
@@ -48,10 +55,16 @@ inline namespace memory
4855
return *this;
4956
}
5057

51-
auto reset(gc_pointer const& gcp = nullptr) -> void
58+
auto reset(gc_pointer const& gcp) -> void
59+
{
60+
nan_boxing_pointer<Ts...>::reset(gcp);
61+
collector::traceable::reset(static_cast<collector::traceable const&>(gcp));
62+
}
63+
64+
auto reset(std::nullptr_t = nullptr) -> void
5265
{
53-
nan_boxing_pointer<Ts...>::operator =(gcp);
54-
collector::collectable::reset(gcp.context);
66+
nan_boxing_pointer<Ts...>::reset();
67+
collector::traceable::reset();
5568
}
5669
};
5770
} // namespace memory

0 commit comments

Comments
 (0)