<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     <NAME> <<EMAIL>>
 */

/* 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/. */

#include <minizinc/gc.hh>
#include <minizinc/ast.hh>
#include <minizinc/hash.hh>
#include <minizinc/model.hh>
#include <minizinc/config.hh>

#include <vector>
#include <cstring>

//#define MINIZINC_GC_STATS

#if defined(MINIZINC_GC_STATS)
#include <map>
#endif

namespace MiniZinc {
  
  GC*&
  GC::gc(void) {
#if defined(HAS_DECLSPEC_THREAD)
    __declspec (thread) static GC* gc = NULL;
#elif defined(HAS_ATTR_THREAD)
    static __thread GC* gc = NULL;
#else
#error Need thread-local storage
#endif
    return gc;
  }
    
  bool
  GC::locked(void) {
    assert(gc());
    return gc()->_lock_count > 0;
  }

  GCLock::GCLock(void) {
    GC::lock();
  }
  GCLock::~GCLock(void) {
    GC::unlock();
  }

  class FreeListNode : public ASTNode {
  public:
    FreeListNode* next;
    size_t size;
    FreeListNode(size_t s, FreeListNode* n)
      : ASTNode(ASTNode::NID_FL)
      , next(n)
      , size(s) {
      _gc_mark = 1;
    }
    FreeListNode(size_t s) : ASTNode(ASTNode::NID_FL), next(NULL), size(s) {}
  };

  class HeapPage {
  public:
    HeapPage* next;
    size_t size;
    size_t used;
    char data[1];
    HeapPage(HeapPage* n, size_t s) : next(n), size(s), used(0) {}
  };

  /// Memory managed by the garbage collector
  class GC::Heap {
    friend class GC;
#if defined(MINIZINC_GC_STATS)
    static const char* _nodeid[Item::II_END+1];
    struct GCStat {
      int first;
      int second;
      int keepalive;
      int inmodel;
      size_t total;
      GCStat(void) : first(0), second(0), keepalive(0), inmodel(0), total(0) {}
    };
    std::map<int,GCStat> gc_stats;
#endif
  protected:
    HeapPage* _page;
    Model* _rootset;
    KeepAlive* _roots;
    WeakRef* _weakRefs;
    static const int _max_fl = 5;
    FreeListNode* _fl[_max_fl+1];
    static const size_t _fl_size[_max_fl+1];
    int _fl_slot(size_t _size) {
      size_t size = _size;
      assert(size <= _fl_size[_max_fl]);
      assert(size >= _fl_size[0]);
      size -= sizeof(Item);
      assert(size % sizeof(void*) == 0);
      size /= sizeof(void*);
      assert(size >= 1);
      int slot = static_cast<int>(size)-1;
      return slot;
    }

    /// Total amount of memory allocated
    size_t _alloced_mem;
    /// Total amount of memory currently free
    size_t _free_mem;
    /// Memory threshold for next garbage collection
    size_t _gc_threshold;
    /// High water mark of all allocated memory
    size_t _max_alloced_mem;

    /// A trail item
    struct TItem {
      Expression** l;
      Expression* v;
      bool mark;
      TItem(Expression** l0, Expression* v0)
        : l(l0), v(v0), mark(false) {}
    };
    /// Trail
    std::vector<TItem> trail;

    Heap(void)
      : _page(NULL)
      , _rootset(NULL)
      , _roots(NULL)
      , _weakRefs(NULL)
      , _alloced_mem(0)
      , _free_mem(0)
      , _gc_threshold(10)
      , _max_alloced_mem(0) {
      for (int i=_max_fl+1; i--;)
        _fl[i] = NULL;
    }

    /// Default size of pages to allocate
    static const size_t pageSize = 1<<20;
    
    HeapPage* allocPage(size_t s, bool exact=false) {
      if (!exact)
        s = std::max(s,pageSize);
      HeapPage* newPage =
        static_cast<HeapPage*>(::malloc(sizeof(HeapPage)+s-1));
#ifndef NDEBUG
        memset(newPage,255,sizeof(HeapPage)+s-1);
#endif
      _alloced_mem += s;
      _max_alloced_mem = std::max(_max_alloced_mem, _alloced_mem);
      _free_mem += s;
      if (exact && _page) {
        new (newPage) HeapPage(_page->next,s);
        _page->next = newPage;
      } else {
        if (_page) {
          size_t ns = _page->size-_page->used;
          assert(ns <= _fl_size[_max_fl]);
          if (ns >= _fl_size[0]) {
            // Remainder of page can be added to free lists
            FreeListNode* fln = 
              reinterpret_cast<FreeListNode*>(_page->data+_page->used);
            _page->used += ns;
            new (fln) FreeListNode(ns, _fl[_fl_slot(ns)]);
            _fl[_fl_slot(ns)] = fln;
          } else {
            // Waste a little memory (less than smallest free list slot)
            _free_mem -= ns;
            assert(_alloced_mem >= _free_mem);
          }
        }
        new (newPage) HeapPage(_page,s);<commit_msg>Abort with error message if memory allocation fails<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     <NAME> <<EMAIL>>
 */

/* 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/. */

#include <minizinc/gc.hh>
#include <minizinc/ast.hh>
#include <minizinc/hash.hh>
#include <minizinc/model.hh>
#include <minizinc/config.hh>

#include <vector>
#include <cstring>

//#define MINIZINC_GC_STATS

#if defined(MINIZINC_GC_STATS)
#include <map>
#endif

namespace MiniZinc {
  
  GC*&
  GC::gc(void) {
#if defined(HAS_DECLSPEC_THREAD)
    __declspec (thread) static GC* gc = NULL;
#elif defined(HAS_ATTR_THREAD)
    static __thread GC* gc = NULL;
#else
#error Need thread-local storage
#endif
    return gc;
  }
    
  bool
  GC::locked(void) {
    assert(gc());
    return gc()->_lock_count > 0;
  }

  GCLock::GCLock(void) {
    GC::lock();
  }
  GCLock::~GCLock(void) {
    GC::unlock();
  }

  class FreeListNode : public ASTNode {
  public:
    FreeListNode* next;
    size_t size;
    FreeListNode(size_t s, FreeListNode* n)
      : ASTNode(ASTNode::NID_FL)
      , next(n)
      , size(s) {
      _gc_mark = 1;
    }
    FreeListNode(size_t s) : ASTNode(ASTNode::NID_FL), next(NULL), size(s) {}
  };

  class HeapPage {
  public:
    HeapPage* next;
    size_t size;
    size_t used;
    char data[1];
    HeapPage(HeapPage* n, size_t s) : next(n), size(s), used(0) {}
  };

  /// Memory managed by the garbage collector
  class GC::Heap {
    friend class GC;
#if defined(MINIZINC_GC_STATS)
    static const char* _nodeid[Item::II_END+1];
    struct GCStat {
      int first;
      int second;
      int keepalive;
      int inmodel;
      size_t total;
      GCStat(void) : first(0), second(0), keepalive(0), inmodel(0), total(0) {}
    };
    std::map<int,GCStat> gc_stats;
#endif
  protected:
    HeapPage* _page;
    Model* _rootset;
    KeepAlive* _roots;
    WeakRef* _weakRefs;
    static const int _max_fl = 5;
    FreeListNode* _fl[_max_fl+1];
    static const size_t _fl_size[_max_fl+1];
    int _fl_slot(size_t _size) {
      size_t size = _size;
      assert(size <= _fl_size[_max_fl]);
      assert(size >= _fl_size[0]);
      size -= sizeof(Item);
      assert(size % sizeof(void*) == 0);
      size /= sizeof(void*);
      assert(size >= 1);
      int slot = static_cast<int>(size)-1;
      return slot;
    }

    /// Total amount of memory allocated
    size_t _alloced_mem;
    /// Total amount of memory currently free
    size_t _free_mem;
    /// Memory threshold for next garbage collection
    size_t _gc_threshold;
    /// High water mark of all allocated memory
    size_t _max_alloced_mem;

    /// A trail item
    struct TItem {
      Expression** l;
      Expression* v;
      bool mark;
      TItem(Expression** l0, Expression* v0)
        : l(l0), v(v0), mark(false) {}
    };
    /// Trail
    std::vector<TItem> trail;

    Heap(void)
      : _page(NULL)
      , _rootset(NULL)
      , _roots(NULL)
      , _weakRefs(NULL)
      , _alloced_mem(0)
      , _free_mem(0)
      , _gc_threshold(10)
      , _max_alloced_mem(0) {
      for (int i=_max_fl+1; i--;)
        _fl[i] = NULL;
    }

    /// Default size of pages to allocate
    static const size_t pageSize = 1<<20;
    
    HeapPage* allocPage(size_t s, bool exact=false) {
      if (!exact)
        s = std::max(s,pageSize);
      HeapPage* newPage =
        static_cast<HeapPage*>(::malloc(sizeof(HeapPage)+s-1));
      if (newPage==NULL) {
        throw InternalError("out of memory");
      }
#ifndef NDEBUG
      memset(newPage,255,sizeof(HeapPage)+s-1);
#endif
      _alloced_mem += s;
      _max_alloced_mem = std::max(_max_alloced_mem, _alloced_mem);
      _free_mem += s;
      if (exact && _page) {
        new (newPage) HeapPage(_page->next,s);
        _page->next = newPage;
      } else {
        if (_page) {
          size_t ns = _page->size-_page->used;
          assert(ns <= _fl_size[_max_fl]);
          if (ns >= _fl_size[0]) {
            // Remainder of page can be added to free lists
            FreeListNode* fln = 
              reinterpret_cast<FreeListNode*>(_page->data+_page->used);
            _page->used += ns;
            new (fln) FreeListNode(ns, _fl[_fl_slot(ns)]);
            _fl[_fl_slot(ns)] = fln;
          } else {
            // Waste a little memory (less than smallest free list slot)
            _free_mem -= ns;
            assert(_alloced_mem >= _free_mem);
          }
        }
        new (newPage) HeapPage(_page,s);
{'fraction_non_alphanumeric': 0.134730213874715, 'fraction_numerical': 0.00890239930517859, 'mean_word_length': 2.445026178010471, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5056273', 'n_tokens_mistral': 3376, 'n_tokens_neox': 3313, 'n_words': 782}