1 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3 /* 4 * Main authors: 5 * Guido Tack <guido.tack@monash.edu> 6 */ 7 8 /* This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 11 12 #pragma once 13 14 #include <minizinc/config.hh> 15 #include <minizinc/timer.hh> 16 17 #include <cassert> 18 #include <cstdlib> 19 #include <new> 20 #include <unordered_map> 21 22 //#define MINIZINC_GC_STATS 23 24 #if defined(MINIZINC_GC_STATS) 25 #include <map> 26 27 struct GCStat { 28 int first; 29 int second; 30 int keepalive; 31 int inmodel; 32 size_t total; GCStatGCStat33 GCStat() : first(0), second(0), keepalive(0), inmodel(0), total(0) {} 34 }; 35 36 #define MINIZINC_GC_STAT_ARGS std::map<int, GCStat>& gc_stats 37 #else 38 39 #define MINIZINC_GC_STAT_ARGS 40 41 #endif 42 43 namespace MiniZinc { 44 45 /** 46 * \brief Base class for abstract syntax tree nodes 47 */ 48 class ASTNode { 49 friend class GC; 50 51 protected: 52 /// Mark for garbage collection 53 mutable unsigned int _gcMark : 1; 54 /// Id of the node 55 unsigned int _id : 7; 56 /// Secondary id 57 unsigned int _secondaryId : 7; 58 /// Flag 59 unsigned int _flag1 : 1; 60 /// Flag 61 unsigned int _flag2 : 1; 62 63 enum BaseNodes { NID_FL, NID_CHUNK, NID_VEC, NID_STR, NID_END = NID_STR }; 64 65 /// Constructor ASTNode(unsigned int id)66 ASTNode(unsigned int id) : _gcMark(0), _id(id) {} 67 68 public: 69 /// Allocate node 70 void* operator new(size_t size); 71 72 /// Placement-new operator new(size_t,void * n)73 void* operator new(size_t /*s*/, void* n) throw() { return n; } 74 75 /// Delete node (no-op) operator delete(void *,size_t)76 void operator delete(void* /*n*/, size_t /*s*/) throw() {} 77 /// Delete node (no-op) operator delete(void *,void *)78 void operator delete(void* /*n*/, void* /*m*/) throw() {} 79 80 /// Delete node (no-op) operator delete(void *)81 void operator delete(void* /*n*/) throw() {} 82 }; 83 84 /** 85 * \brief Base class for unstructured garbage collected data 86 */ 87 class ASTChunk : public ASTNode { 88 friend class GC; 89 90 protected: 91 /// Allocated size 92 size_t _size; 93 /// Storage 94 char _data[4]; 95 /// Constructor 96 ASTChunk(size_t size, unsigned int id = ASTNode::NID_CHUNK); 97 /// Actual size of object in memory memsize() const98 size_t memsize() const { 99 size_t s = sizeof(ASTChunk) + (_size <= 4 ? 0 : _size - 4) * sizeof(char); 100 s += ((8 - (s & 7)) & 7); 101 return s; 102 } 103 /// Allocate raw memory 104 static void* alloc(size_t size); 105 }; 106 107 /** 108 * \brief Base class for structured garbage collected data 109 */ 110 class ASTVec : public ASTNode { 111 friend class GC; 112 113 protected: 114 /// Allocated size 115 size_t _size; 116 /// Storage 117 void* _data[2]; 118 /// Constructor 119 ASTVec(size_t size); 120 /// Actual size of object in memory memsize() const121 size_t memsize() const { 122 size_t s = sizeof(ASTVec) + (_size <= 2 ? 0 : _size - 2) * sizeof(void*); 123 s += ((8 - (s & 7)) & 7); 124 return s; 125 } 126 /// Allocate raw memory 127 static void* alloc(size_t size); 128 }; 129 130 class Expression; 131 132 class GCMarker; 133 class KeepAlive; 134 class WeakRef; 135 136 class ASTNodeWeakMap; 137 class ASTStringData; 138 139 /// Garbage collector 140 class GC { 141 friend class ASTNode; 142 friend class ASTVec; 143 friend class ASTChunk; 144 friend class ASTStringData; 145 friend class KeepAlive; 146 friend class WeakRef; 147 friend class ASTNodeWeakMap; 148 149 private: 150 class Heap; 151 /// The memory controlled by the collector 152 Heap* _heap; 153 /// Count how many locks are currently active 154 unsigned int _lockCount; 155 /// Timeout in milliseconds 156 unsigned long long int _timeout; 157 /// Counter for timeout 158 int _timeoutCount; 159 /// Timer for timeout 160 Timer _timeoutTimer; 161 /// Return thread-local GC object 162 static GC*& gc(); 163 /// Constructor 164 GC(); 165 166 /// Allocate garbage collected memory 167 void* alloc(size_t size); 168 169 static void addKeepAlive(KeepAlive* e); 170 static void removeKeepAlive(KeepAlive* e); 171 static void addWeakRef(WeakRef* e); 172 static void removeWeakRef(WeakRef* e); 173 static void addNodeWeakMap(ASTNodeWeakMap* m); 174 static void removeNodeWeakMap(ASTNodeWeakMap* m); 175 176 public: 177 /// Acquire garbage collector lock for this thread 178 static void lock(); 179 /// Release garbage collector lock for this thread 180 static void unlock(); 181 /// Manually trigger garbage collector (must be unlocked) 182 static void trigger(); 183 /// Test if garbage collector is locked 184 static bool locked(); 185 /// Add model \a m to root set 186 static void add(GCMarker* m); 187 /// Remove model \a m from root set 188 static void remove(GCMarker* m); 189 190 /// Put a mark on the trail 191 static void mark(); 192 /// Add a trail entry 193 static void trail(Expression** l, Expression* v); 194 /// Untrail to previous mark 195 static void untrail(); 196 197 /// Set timeout of \a t milliseconds, 0 means disable 198 static void setTimeout(unsigned long long int t); 199 200 /// Return maximum allocated memory (high water mark) 201 static size_t maxMem(); 202 }; 203 204 /// Automatic garbage collection lock 205 class GCLock { 206 public: 207 /// Acquire lock 208 GCLock(); 209 /// Release lock upon destruction 210 ~GCLock(); 211 }; 212 213 /// Expression wrapper that is a member of the root set 214 class KeepAlive { 215 friend class GC; 216 217 private: 218 Expression* _e; 219 KeepAlive* _p; 220 KeepAlive* _n; 221 222 public: 223 KeepAlive(Expression* e = nullptr); 224 ~KeepAlive(); 225 KeepAlive(const KeepAlive& e); 226 KeepAlive& operator=(const KeepAlive& e); operator ()()227 Expression* operator()() { return _e; } operator ()() const228 Expression* operator()() const { return _e; } next() const229 KeepAlive* next() const { return _n; } 230 }; 231 232 /// Expression wrapper that is a member of the root set 233 class WeakRef { 234 friend class GC; 235 236 private: 237 Expression* _e; 238 WeakRef* _p; 239 WeakRef* _n; 240 bool _valid; 241 242 public: 243 WeakRef(Expression* e = nullptr); 244 ~WeakRef(); 245 WeakRef(const WeakRef& e); 246 WeakRef& operator=(const WeakRef& e); operator ()()247 Expression* operator()() { return _valid ? _e : nullptr; } operator ()() const248 Expression* operator()() const { return _valid ? _e : nullptr; } next() const249 WeakRef* next() const { return _n; } 250 }; 251 252 class ASTNodeWeakMap { 253 friend class GC; 254 255 private: 256 ASTNodeWeakMap(const WeakRef& e); 257 ASTNodeWeakMap& operator=(const ASTNodeWeakMap& e); 258 259 protected: 260 typedef std::unordered_map<ASTNode*, ASTNode*> NodeMap; 261 ASTNodeWeakMap* _p; 262 ASTNodeWeakMap* _n; next() const263 ASTNodeWeakMap* next() const { return _n; } 264 NodeMap _m; 265 266 public: 267 ASTNodeWeakMap(); 268 ~ASTNodeWeakMap(); 269 void insert(ASTNode* n0, ASTNode* n1); 270 ASTNode* find(ASTNode* n); clear()271 void clear() { _m.clear(); } 272 }; 273 274 /** 275 * \brief Abstract base class for object containing garbage collected data 276 */ 277 class GCMarker { 278 friend class GC; 279 280 private: 281 /// Previous object in root set list 282 GCMarker* _rootsPrev = nullptr; 283 /// Next object in root set list 284 GCMarker* _rootsNext = nullptr; 285 286 protected: 287 /// Mark garbage collected objects that 288 virtual void mark(MINIZINC_GC_STAT_ARGS) = 0; 289 290 public: GCMarker()291 GCMarker() { GC::add(this); } ~GCMarker()292 virtual ~GCMarker() { GC::remove(this); } 293 }; 294 295 } // namespace MiniZinc 296