1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.

267 lines
6.2 KiB
C++

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Guido Tack <guido.tack@monash.edu>
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __MINIZINC_GC_HH__
#define __MINIZINC_GC_HH__
#include <minizinc/config.hh>
#include <minizinc/timer.hh>
#include <cassert>
#include <cstdlib>
#include <new>
#include <unordered_map>
namespace MiniZinc {
/**
* \brief Base class for abstract syntax tree nodes
*/
class ASTNode {
friend class GC;
protected:
/// Mark for garbage collection
mutable unsigned int _gc_mark : 1;
/// Id of the node
unsigned int _id : 7;
/// Secondary id
unsigned int _sec_id : 7;
/// Flag
unsigned int _flag_1 : 1;
/// Flag
unsigned int _flag_2 : 1;
/// Flag
unsigned int _flag_3 : 1;
/// Flag
unsigned int _flag_4 : 1;
enum BaseNodes { NID_FL, NID_CHUNK, NID_VEC, NID_END = NID_VEC };
/// Constructor
ASTNode(unsigned int id) : _gc_mark(0), _id(id), _flag_1(0), _flag_2(0), _flag_3(0), _flag_4(0) {}
public:
/// Allocate node
void* operator new(size_t size);
/// Placement-new
void* operator new(size_t, void* n) throw() { return n; }
/// Delete node (no-op)
void operator delete(void*, size_t) throw() {}
/// Delete node (no-op)
void operator delete(void*, void*) throw() {}
/// Delete node (no-op)
void operator delete(void*) throw() {}
/// Return state of first user-defined flag
bool user_flag0(void) const { return _flag_3; }
/// Set state of first user-defined flag
void user_flag0(bool b) { _flag_3 = b; }
/// Return state of second user-defined flag
bool user_flag1(void) const { return _flag_4; }
/// Set state of second user-defined flag
void user_flag1(bool b) { _flag_4 = b; }
};
/**
* \brief Base class for unstructured garbage collected data
*/
class ASTChunk : public ASTNode {
friend class GC;
protected:
/// Allocated size
size_t _size;
/// Storage
char _data[4];
/// Constructor
ASTChunk(size_t size);
/// Actual size of object in memory
size_t memsize(void) const {
size_t s = sizeof(ASTChunk) + (_size <= 4 ? 0 : _size - 4) * sizeof(char);
s += ((8 - (s & 7)) & 7);
return s;
}
/// Allocate raw memory
static void* alloc(size_t size);
};
/**
* \brief Base class for structured garbage collected data
*/
class ASTVec : public ASTNode {
friend class GC;
protected:
/// Allocated size
size_t _size;
/// Storage
void* _data[2];
/// Constructor
ASTVec(size_t size);
/// Actual size of object in memory
size_t memsize(void) const {
size_t s = sizeof(ASTVec) + (_size <= 2 ? 0 : _size - 2) * sizeof(void*);
s += ((8 - (s & 7)) & 7);
return s;
}
/// Allocate raw memory
static void* alloc(size_t size);
};
class Model;
class Expression;
class KeepAlive;
class WeakRef;
class ASTNodeWeakMap;
/// Garbage collector
class GC {
friend class ASTNode;
friend class ASTVec;
friend class ASTChunk;
friend class KeepAlive;
friend class WeakRef;
friend class ASTNodeWeakMap;
private:
class Heap;
/// The memory controlled by the collector
Heap* _heap;
/// Count how many locks are currently active
unsigned int _lock_count;
/// Timeout in milliseconds
unsigned long long int _timeout;
/// Counter for timeout
int _timeout_counter;
/// Timer for timeout
Timer _timeout_timer;
/// Return thread-local GC object
static GC*& gc(void);
/// Constructor
GC(void);
/// Allocate garbage collected memory
void* alloc(size_t size);
static void addKeepAlive(KeepAlive* e);
static void removeKeepAlive(KeepAlive* e);
static void addWeakRef(WeakRef* e);
static void removeWeakRef(WeakRef* e);
static void addNodeWeakMap(ASTNodeWeakMap* m);
static void removeNodeWeakMap(ASTNodeWeakMap* m);
public:
/// Acquire garbage collector lock for this thread
static void lock(void);
/// Release garbage collector lock for this thread
static void unlock(void);
/// Manually trigger garbage collector (must be unlocked)
static void trigger(void);
/// Test if garbage collector is locked
static bool locked(void);
/// Add model \a m to root set
static void add(Model* m);
/// Remove model \a m from root set
static void remove(Model* m);
/// Put a mark on the trail
static void mark(void);
/// Add a trail entry
static void trail(Expression**, Expression*);
/// Untrail to previous mark
static void untrail(void);
/// Set timeout of \a t milliseconds, 0 means disable
static void setTimeout(unsigned long long int t);
/// Return maximum allocated memory (high water mark)
static size_t maxMem(void);
};
/// Automatic garbage collection lock
class GCLock {
public:
/// Acquire lock
GCLock(void);
/// Release lock upon destruction
~GCLock(void);
};
/// Expression wrapper that is a member of the root set
class KeepAlive {
friend class GC;
private:
Expression* _e;
KeepAlive* _p;
KeepAlive* _n;
public:
KeepAlive(Expression* e = NULL);
~KeepAlive(void);
KeepAlive(const KeepAlive& e);
KeepAlive& operator=(const KeepAlive& e);
Expression* operator()(void) { return _e; }
Expression* operator()(void) const { return _e; }
KeepAlive* next(void) const { return _n; }
};
/// Expression wrapper that is a member of the root set
class WeakRef {
friend class GC;
private:
Expression* _e;
WeakRef* _p;
WeakRef* _n;
bool _valid;
public:
WeakRef(Expression* e = NULL);
~WeakRef(void);
WeakRef(const WeakRef& e);
WeakRef& operator=(const WeakRef& e);
Expression* operator()(void) { return _valid ? _e : NULL; }
Expression* operator()(void) const { return _valid ? _e : NULL; }
WeakRef* next(void) const { return _n; }
};
class ASTNodeWeakMap {
friend class GC;
private:
ASTNodeWeakMap(const WeakRef& e);
ASTNodeWeakMap& operator=(const ASTNodeWeakMap& e);
protected:
typedef std::unordered_map<ASTNode*, ASTNode*> NodeMap;
ASTNodeWeakMap* _p;
ASTNodeWeakMap* _n;
ASTNodeWeakMap* next(void) const { return _n; }
NodeMap _m;
public:
ASTNodeWeakMap(void);
~ASTNodeWeakMap(void);
void insert(ASTNode* n0, ASTNode* n1);
ASTNode* find(ASTNode* n);
void clear() { _m.clear(); }
};
} // namespace MiniZinc
#endif