refactor(runtime): C backend

This commit is contained in:
Leonardo de Moura 2019-08-21 21:04:42 -07:00
parent cf18cda557
commit dcd15f3424
24 changed files with 1335 additions and 2450 deletions

View file

@ -530,8 +530,7 @@ function(add_exec_test name tgt)
endif()
endfunction()
# C++ unit tests are disabled for now since they rely on `format` which relies on `Lean` generated code.
# add_subdirectory(tests/util)
add_subdirectory(tests/util)
# Include style check
if (NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows") AND PYTHONINTERP_FOUND)

View file

@ -61,7 +61,7 @@ local_decl local_ctx::mk_local_decl(name const & n, name const & un, expr const
object * p = lean_local_ctx_mk_let_decl(raw(), n.to_obj_arg(), un.to_obj_arg(), type.to_obj_arg(), value.to_obj_arg());
local_decl decl(cnstr_get(p, 0));
m_obj = cnstr_get(p, 1);
free_heap_obj(p);
lean_free_heap_obj(p);
return decl;
}
@ -69,7 +69,7 @@ local_decl local_ctx::mk_local_decl(name const & n, name const & un, expr const
object * p = lean_local_ctx_mk_local_decl(raw(), n.to_obj_arg(), un.to_obj_arg(), type.to_obj_arg(), static_cast<uint8>(bi));
local_decl decl(cnstr_get(p, 0));
m_obj = cnstr_get(p, 1);
free_heap_obj(p);
lean_free_heap_obj(p);
return decl;
}

View file

@ -155,7 +155,7 @@ extern "C" object * lean_serialize_modifications(object * mod_list, object * w)
std::string bytes = out.str();
object * r = alloc_sarray(1, bytes.size(), bytes.size());
memcpy(sarray_cptr<uint8>(r), bytes.data(), bytes.size());
memcpy(sarray_cptr(r), bytes.data(), bytes.size());
return set_io_result(w, r);
} catch (exception & ex) {
@ -165,7 +165,7 @@ extern "C" object * lean_serialize_modifications(object * mod_list, object * w)
extern "C" object * lean_perform_serialized_modifications(object * env0, object * bytes, object * w) {
environment env(env0);
std::string code(sarray_cptr<char>(bytes), sarray_size(bytes));
std::string code((char*)sarray_cptr(bytes), sarray_size(bytes));
dec_ref(bytes);
try {
std::istringstream in(code, std::ios_base::binary);

View file

@ -7,12 +7,9 @@ Author: Leonardo de Moura
#include <vector>
#include "runtime/thread.h"
#include "runtime/debug.h"
#include "runtime/compiler_hints.h"
#include "runtime/object.h"
#include "runtime/alloc.h"
#include "runtime/lean.h"
#define LEAN_OBJECT_SIZE_DELTA 8
#define LEAN_MAX_SMALL_OBJECT_SIZE 512
#define LEAN_PAGE_SIZE 8192 // 8 Kb
#define LEAN_SEGMENT_SIZE 8*1024*1024 // 8 Mb
#define LEAN_NUM_SLOTS (LEAN_MAX_SMALL_OBJECT_SIZE / LEAN_OBJECT_SIZE_DELTA)
@ -73,12 +70,8 @@ struct page {
void push_free_obj(void * o);
};
inline size_t align(size_t v, size_t a) {
return (v / a)*a + a * (v % a != 0);
}
inline char * align_ptr(char * p, size_t a) {
return reinterpret_cast<char*>(align(reinterpret_cast<size_t>(p), a));
return reinterpret_cast<char*>(lean_align(reinterpret_cast<size_t>(p), a));
}
struct segment {
@ -149,12 +142,6 @@ LEAN_THREAD_GLOBAL_PTR(page *, g_curr_pages);
LEAN_THREAD_PTR(heap, g_heap);
static heap_manager * g_heap_manager = nullptr;
inline unsigned get_slot_idx(unsigned obj_size) {
lean_assert(obj_size > 0);
lean_assert(align(obj_size, LEAN_OBJECT_SIZE_DELTA) == obj_size);
return obj_size / LEAN_OBJECT_SIZE_DELTA - 1;
}
inline void set_next_obj(void * obj, void * next) {
*reinterpret_cast<void**>(obj) = next;
}
@ -300,7 +287,7 @@ void heap::alloc_segment() {
}
static page * alloc_page(heap * h, unsigned obj_size) {
lean_assert(align(obj_size, LEAN_OBJECT_SIZE_DELTA) == obj_size);
lean_assert(lean_align(obj_size, LEAN_OBJECT_SIZE_DELTA) == obj_size);
segment * s = h->m_curr_segment;
LEAN_RUNTIME_STAT_CODE(g_num_pages++);
page * p = new (s->m_next_page_mem) page();
@ -309,7 +296,7 @@ static page * alloc_page(heap * h, unsigned obj_size) {
/* s is full, we need to allocate a new one. */
h->alloc_segment();
}
unsigned slot_idx = get_slot_idx(obj_size);
unsigned slot_idx = lean_get_slot_idx(obj_size);
p->m_header.m_heap = h;
page_list_insert(h->m_curr_page[slot_idx], p);
p->m_header.m_slot_idx = slot_idx;
@ -372,17 +359,7 @@ void init_thread_heap() {
init_heap(false);
}
void * alloc(size_t sz) {
sz = align(sz, LEAN_OBJECT_SIZE_DELTA);
LEAN_RUNTIME_STAT_CODE(g_num_alloc++);
if (LEAN_UNLIKELY(sz > LEAN_MAX_SMALL_OBJECT_SIZE)) {
void * r = malloc(sz);
if (r == nullptr) throw std::bad_alloc();
return r;
}
lean_assert(g_heap);
LEAN_RUNTIME_STAT_CODE(g_num_small_alloc++);
unsigned slot_idx = get_slot_idx(sz);
extern "C" void * lean_alloc_small(unsigned sz, unsigned slot_idx) {
page * p = g_heap->m_curr_page[slot_idx];
void * r = p->m_header.m_free_list;
if (LEAN_UNLIKELY(r == nullptr)) {
@ -402,6 +379,20 @@ void * alloc(size_t sz) {
return r;
}
void * alloc(size_t sz) {
sz = lean_align(sz, LEAN_OBJECT_SIZE_DELTA);
LEAN_RUNTIME_STAT_CODE(g_num_alloc++);
if (LEAN_UNLIKELY(sz > LEAN_MAX_SMALL_OBJECT_SIZE)) {
void * r = malloc(sz);
if (r == nullptr) lean_panic_out_of_memory();
return r;
}
lean_assert(g_heap);
LEAN_RUNTIME_STAT_CODE(g_num_small_alloc++);
unsigned slot_idx = lean_get_slot_idx(sz);
return lean_alloc_small(sz, slot_idx);
}
static inline void dealloc_small_core(void * o) {
LEAN_RUNTIME_STAT_CODE(g_num_small_dealloc++);
if (LEAN_UNLIKELY(g_heap == nullptr)) {
@ -424,18 +415,18 @@ static inline void dealloc_small_core(void * o) {
void dealloc(void * o, size_t sz) {
LEAN_RUNTIME_STAT_CODE(g_num_dealloc++);
sz = align(sz, LEAN_OBJECT_SIZE_DELTA);
sz = lean_align(sz, LEAN_OBJECT_SIZE_DELTA);
if (LEAN_UNLIKELY(sz > LEAN_MAX_SMALL_OBJECT_SIZE)) {
return free(o);
}
dealloc_small_core(o);
}
void dealloc_small(void * o) {
extern "C" void lean_free_small(void * o) {
dealloc_small_core(o);
}
unsigned get_small_object_size(void * o) {
extern "C" unsigned lean_small_mem_size(void * o) {
page * p = get_page_of(o);
return p->m_header.m_obj_size;
}

View file

@ -11,8 +11,6 @@ namespace lean {
void init_thread_heap();
void * alloc(size_t sz);
void dealloc(void * o, size_t sz);
void dealloc_small(void * o);
unsigned get_small_object_size(void * o);
void initialize_alloc();
void finalize_alloc();
}

File diff suppressed because it is too large Load diff

View file

@ -12,23 +12,18 @@ Author: Leonardo de Moura
#define LEAN_COMPACTOR_INIT_SZ 1024*1024
namespace lean {
#define TERMINATOR_ID (static_cast<unsigned>(object_kind::External) + 1)
/*
Special object that terminates the data block constructing the object graph rooted in `m_value`.
We use this object to ensure `m_value` is correctly aligned. In the past, we would allocate
a chunk of memory `p` of size `sizeof(object) + sizeof(object*)`, and then write at `p + sizeof(object)`.
This is incorrect because `sizeof(object)` is not a multiple of the word size.
*/
struct terminator_object : public object {
object * m_value;
explicit terminator_object(object * value) : object(object_kind::External, object_memory_kind::Region), m_value(value) {
// not an actual `object_kind`, so write to the field directly
m_kind = TERMINATOR_ID;
}
struct terminator_object {
lean_object m_header;
lean_object * m_value;
};
object_compactor::object_compactor():
m_begin(malloc(LEAN_COMPACTOR_INIT_SZ)),
m_end(m_begin),
@ -75,16 +70,17 @@ object_offset object_compactor::to_offset(object * o) {
}
void object_compactor::insert_terminator(object * o) {
void * mem = alloc(sizeof(terminator_object));
new (mem) terminator_object(to_offset(o));
terminator_object * t = (terminator_object*) alloc(sizeof(terminator_object));
lean_set_other_header((lean_object*)t, LeanReserved, 0);
t->m_value = to_offset(o);
}
object * object_compactor::copy_object(object * o) {
size_t sz = obj_byte_size(o);
size_t sz = lean_object_byte_size(o);
void * mem = alloc(sz);
memcpy(mem, o, sz);
object * r = static_cast<object*>(mem);
r->m_mem_kind = static_cast<unsigned>(object_memory_kind::Region);
lean_set_other_mem_kind(r);
save(o, r);
return r;
}
@ -121,12 +117,15 @@ bool object_compactor::insert_array(object * o) {
}
if (missing_children)
return false;
void * mem = alloc(sizeof(array_object) + sz * sizeof(object *));
object * new_o = new (mem) array_object(sz, sz, object_memory_kind::Region);
lean_array_object * new_o = (lean_array_object*)alloc(sizeof(lean_array_object) + sizeof(void*)*sz);
lean_set_other_header((lean_object*)new_o, LeanArray, 0);
new_o->m_size = sz;
new_o->m_capacity = sz;
for (size_t i = 0; i < sz; i++) {
array_set(new_o, i, offsets[i]);
array_set((lean_object*)new_o, i, offsets[i]);
}
save(o, new_o);
save(o, (lean_object*)new_o);
return true;
}
@ -136,17 +135,17 @@ bool object_compactor::insert_thunk(object * o) {
if (c == g_null_offset)
return false;
object * r = copy_object(o);
to_thunk(r)->m_value = c;
lean_to_thunk(r)->m_value = c;
return true;
}
bool object_compactor::insert_ref(object * o) {
object * v = to_ref(o)->m_value;
object * v = lean_to_ref(o)->m_value;
object_offset c = to_offset(v);
if (c == g_null_offset)
return false;
object * r = copy_object(o);
to_ref(r)->m_value = c;
lean_to_ref(r)->m_value = c;
return true;
}
@ -164,9 +163,11 @@ bool object_compactor::insert_task(object * o) {
To cope with this issue, we always save tasks as thunks,
and rely on the fact that all task API accepts thunks as arguments
even when multi-threading is enabled. */
void * mem = alloc(sizeof(thunk_object));
object * new_o = new (mem) thunk_object(c, true, object_memory_kind::Region);
save(o, new_o);
lean_thunk_object * new_o = (lean_thunk_object*)alloc(sizeof(lean_thunk_object));
lean_set_other_header((lean_object*)new_o, LeanThunk, 0);
new_o->m_value = c;
new_o->m_closure = (lean_object*)0;
save(o, (lean_object*)new_o);
return true;
}
@ -177,8 +178,9 @@ void object_compactor::insert_mpz(object * o) {
into an mpz number. So, we use std::max to make sure we have enough space for both. */
size_t extra_space = std::max(s.size() + 1, sizeof(mpz_object*));
void * mem = alloc(sizeof(mpz_object) + extra_space);
object * new_o = new (mem) object(object_kind::MPZ, object_memory_kind::Region);
save(o, new_o);
mpz_object * new_o = new (mem) mpz_object();
lean_set_other_header((lean_object*)new_o, LeanMPZ, 0);
save(o, (lean_object*)new_o);
void * data = reinterpret_cast<char*>(new_o) + sizeof(mpz_object);
memcpy(data, s.c_str(), s.size() + 1);
}
@ -195,17 +197,18 @@ void object_compactor::operator()(object * o) {
}
lean_assert(!is_scalar(curr));
bool r = true;
switch (get_kind(curr)) {
case object_kind::Constructor: r = insert_constructor(curr); break;
case object_kind::Closure: throw exception("closures cannot be compacted");
case object_kind::Array: r = insert_array(curr); break;
case object_kind::ScalarArray: copy_object(curr); break;
case object_kind::String: copy_object(curr); break;
case object_kind::MPZ: insert_mpz(curr); break;
case object_kind::Thunk: r = insert_thunk(curr); break;
case object_kind::Task: r = insert_task(curr); break;
case object_kind::Ref: r = insert_ref(curr); break;
case object_kind::External: throw exception("external objects cannot be compacted");
switch (lean_ptr_tag(curr)) {
case LeanClosure: throw exception("closures cannot be compacted");
case LeanArray: r = insert_array(curr); break;
case LeanScalarArray: copy_object(curr); break;
case LeanString: copy_object(curr); break;
case LeanMPZ: insert_mpz(curr); break;
case LeanThunk: r = insert_thunk(curr); break;
case LeanTask: r = insert_task(curr); break;
case LeanRef: r = insert_ref(curr); break;
case LeanExternal: throw exception("external objects cannot be compacted");
case LeanReserved: lean_unreachable();
default: r = insert_constructor(curr); break;
}
if (r) m_todo.pop_back();
}
@ -256,7 +259,7 @@ inline void compacted_region::fix_constructor(object * o) {
for (; it != end; it++) {
*it = fix_object_ptr(*it);
}
move(cnstr_byte_size(o));
move(lean_ctor_byte_size(o));
}
inline void compacted_region::fix_array(object * o) {
@ -265,17 +268,17 @@ inline void compacted_region::fix_array(object * o) {
for (; it != end; it++) {
*it = fix_object_ptr(*it);
}
move(array_byte_size(o));
move(lean_array_byte_size(o));
}
inline void compacted_region::fix_thunk(object * o) {
to_thunk(o)->m_value = fix_object_ptr(to_thunk(o)->m_value);
move(sizeof(thunk_object));
lean_to_thunk(o)->m_value = fix_object_ptr(lean_to_thunk(o)->m_value);
move(sizeof(lean_thunk_object));
}
inline void compacted_region::fix_ref(object * o) {
to_ref(o)->m_value = fix_object_ptr(to_ref(o)->m_value);
move(sizeof(ref_object));
lean_to_ref(o)->m_value = fix_object_ptr(lean_to_ref(o)->m_value);
move(sizeof(lean_ref_object));
}
void compacted_region::fix_mpz(object * o) {
@ -290,10 +293,10 @@ void compacted_region::fix_mpz(object * o) {
sz++;
}
/* use string to initialize memory */
new (&(to_mpz(o)->m_value)) mpz(s.c_str());
new (&(((mpz_object*)o)->m_value)) mpz(s.c_str());
/* update m_nested_mpzs list */
*reinterpret_cast<mpz_object**>(m_next) = m_nested_mpzs;
m_nested_mpzs = to_mpz(o);
m_nested_mpzs = (mpz_object*)o;
/* consume region after mpz_object */
sz++; // string delimiter
if (sz < sizeof(mpz_object*))
@ -307,23 +310,23 @@ object * compacted_region::read() {
while (true) {
lean_assert(static_cast<char*>(m_next) + sizeof(object) <= m_end);
object * curr = reinterpret_cast<object*>(m_next);
if (curr->m_kind == TERMINATOR_ID) {
switch (lean_ptr_tag(curr)) {
case LeanClosure: lean_unreachable();
case LeanArray: fix_array(curr); break;
case LeanScalarArray: move(lean_sarray_byte_size(curr)); break;
case LeanString: move(lean_string_byte_size(curr)); break;
case LeanMPZ: fix_mpz(curr); break;
case LeanThunk: fix_thunk(curr); break;
case LeanRef: fix_ref(curr); break;
case LeanTask: lean_unreachable();
case LeanExternal: lean_unreachable();
case LeanReserved: {
object * r = reinterpret_cast<terminator_object*>(m_next)->m_value;
move(sizeof(terminator_object));
return fix_object_ptr(r);
} else {
switch (get_kind(curr)) {
case object_kind::Constructor: fix_constructor(curr); break;
case object_kind::Closure: lean_unreachable();
case object_kind::Array: fix_array(curr); break;
case object_kind::ScalarArray: move(sarray_byte_size(curr)); break;
case object_kind::String: move(string_byte_size(curr)); break;
case object_kind::MPZ: fix_mpz(curr); break;
case object_kind::Thunk: fix_thunk(curr); break;
case object_kind::Ref: fix_ref(curr); break;
case object_kind::Task: lean_unreachable();
case object_kind::External: lean_unreachable();
}
}
default:
fix_constructor(curr); break;
}
}
}

View file

@ -11,7 +11,7 @@ Author: Leonardo de Moura
#include "runtime/object.h"
namespace lean {
typedef object * object_offset;
typedef lean_object * object_offset;
class object_compactor {
std::unordered_map<object*, object_offset, std::hash<object*>, std::equal_to<object*>> m_obj_table;

View file

@ -8,7 +8,6 @@ Author: Leonardo de Moura
#include <iostream>
#include <typeinfo>
#include "runtime/exception.h"
#include "runtime/compiler_hints.h"
#ifndef __has_builtin
#define __has_builtin(x) 0

View file

@ -14,12 +14,14 @@ Author: Leonardo de Moura
#endif
#include <iostream>
#include <chrono>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <sys/stat.h>
#include "runtime/object.h"
#include "runtime/thread.h"
#include "runtime/allocprof.h"
#ifdef _MSC_VER
@ -31,7 +33,7 @@ Author: Leonardo de Moura
namespace lean {
static obj_res const REAL_WORLD = box(0);
void io_result_show_error(b_obj_arg r) {
extern "C" void lean_io_result_show_error(b_obj_arg r) {
std::cerr << "uncaught exception: " << string_cstr(io_result_get_error(r)) << std::endl;
}
@ -76,7 +78,7 @@ obj_res set_io_error(obj_arg r, std::string const & msg) {
}
static bool g_initializing = true;
void io_mark_end_initialization() {
extern "C" void lean_io_mark_end_initialization() {
g_initializing = false;
}
@ -254,15 +256,17 @@ extern "C" obj_res lean_io_app_dir(obj_arg r) {
// =======================================
// IO ref primitives
obj_res io_mk_ref(obj_arg a, obj_arg r) {
object * ref = new (alloc_heap_object(sizeof(ref_object))) ref_object(a);
return set_io_result(r, ref);
extern "C" obj_res lean_io_mk_ref(obj_arg a, obj_arg r) {
lean_ref_object * o = (lean_ref_object*)lean_alloc_small_object(sizeof(lean_ref_object));
lean_set_st_header((lean_object*)o, LeanRef, 0);
o->m_value = a;
return set_io_result(r, (lean_object*)o);
}
static object * g_io_error_nullptr_read = nullptr;
static inline atomic<object*> * mt_ref_val_addr(object * o) {
return reinterpret_cast<atomic<object*> *>(&(to_ref(o)->m_value));
return reinterpret_cast<atomic<object*> *>(&(lean_to_ref(o)->m_value));
}
/*
@ -276,13 +280,9 @@ static inline atomic<object*> * mt_ref_val_addr(object * o) {
object as we do for multi-threaded `IO.Ref`s. It makes sense since
the global `IO.Ref` may be used to communicate data between threads.
*/
static inline bool ref_maybe_mt(b_obj_arg ref) {
return
ref->m_mem_kind == static_cast<unsigned>(object_memory_kind::MTHeap) ||
ref->m_mem_kind == static_cast<unsigned>(object_memory_kind::Persistent);
}
static inline bool ref_maybe_mt(b_obj_arg ref) { return lean_is_mt(ref) || lean_is_persistent(ref); }
obj_res io_ref_get(b_obj_arg ref, obj_arg r) {
extern "C" obj_res lean_io_ref_get(b_obj_arg ref, obj_arg r) {
if (ref_maybe_mt(ref)) {
atomic<object *> * val_addr = mt_ref_val_addr(ref);
object * val = val_addr->exchange(nullptr);
@ -296,7 +296,7 @@ obj_res io_ref_get(b_obj_arg ref, obj_arg r) {
}
return set_io_result(r, val);
} else {
object * val = to_ref(ref)->m_value;
object * val = lean_to_ref(ref)->m_value;
if (val == nullptr)
return set_io_error(r, g_io_error_nullptr_read);
inc(val);
@ -306,7 +306,7 @@ obj_res io_ref_get(b_obj_arg ref, obj_arg r) {
static_assert(sizeof(atomic<unsigned short>) == sizeof(unsigned short), "`atomic<unsigned short>` and `unsigned short` must have the same size"); // NOLINT
obj_res io_ref_reset(b_obj_arg ref, obj_arg r) {
extern "C" obj_res lean_io_ref_reset(b_obj_arg ref, obj_arg r) {
if (ref_maybe_mt(ref)) {
atomic<object *> * val_addr = mt_ref_val_addr(ref);
object * old_a = val_addr->exchange(nullptr);
@ -314,14 +314,14 @@ obj_res io_ref_reset(b_obj_arg ref, obj_arg r) {
dec(old_a);
return r;
} else {
if (to_ref(ref)->m_value != nullptr)
dec(to_ref(ref)->m_value);
to_ref(ref)->m_value = nullptr;
if (lean_to_ref(ref)->m_value != nullptr)
dec(lean_to_ref(ref)->m_value);
lean_to_ref(ref)->m_value = nullptr;
return r;
}
}
obj_res io_ref_set(b_obj_arg ref, obj_arg a, obj_arg r) {
extern "C" obj_res lean_io_ref_set(b_obj_arg ref, obj_arg a, obj_arg r) {
if (ref_maybe_mt(ref)) {
/* We must mark `a` as multi-threaded if `ref` is marked as multi-threaded.
Reason: our runtime relies on the fact that a single-threaded object
@ -333,14 +333,14 @@ obj_res io_ref_set(b_obj_arg ref, obj_arg a, obj_arg r) {
dec(old_a);
return r;
} else {
if (to_ref(ref)->m_value != nullptr)
dec(to_ref(ref)->m_value);
to_ref(ref)->m_value = a;
if (lean_to_ref(ref)->m_value != nullptr)
dec(lean_to_ref(ref)->m_value);
lean_to_ref(ref)->m_value = a;
return r;
}
}
obj_res io_ref_swap(b_obj_arg ref, obj_arg a, obj_arg r) {
extern "C" obj_res lean_io_ref_swap(b_obj_arg ref, obj_arg a, obj_arg r) {
if (ref_maybe_mt(ref)) {
/* See io_ref_write */
mark_mt(a);
@ -350,10 +350,10 @@ obj_res io_ref_swap(b_obj_arg ref, obj_arg a, obj_arg r) {
return set_io_error(r, g_io_error_nullptr_read);
return set_io_result(r, old_a);
} else {
object * old_a = to_ref(ref)->m_value;
object * old_a = lean_to_ref(ref)->m_value;
if (old_a == nullptr)
return set_io_error(r, g_io_error_nullptr_read);
to_ref(ref)->m_value = a;
lean_to_ref(ref)->m_value = a;
return set_io_result(r, old_a);
}
}

View file

@ -15,6 +15,9 @@ Author: Leonardo de Moura
#include <malloc.h>
#endif
#define LEAN_SMALL_ALLOCATOR
#define LEAN_COMPRESSED_OBJECT_HEADER
#ifdef __cplusplus
#include <atomic>
#define _Atomic(t) std::atomic<t>
@ -25,7 +28,9 @@ extern "C" {
#define LEAN_USING_STD
#endif
#define LEAN_CLOSURE_MAX_ARGS 16
#define LEAN_CLOSURE_MAX_ARGS 16
#define LEAN_OBJECT_SIZE_DELTA 8
#define LEAN_MAX_SMALL_OBJECT_SIZE 512
#ifdef _MSC_VER
#define LEAN_ALLOCA(s) _alloca(s)
@ -43,6 +48,12 @@ extern "C" {
#define LEAN_ALWAYS_INLINE
#endif
#ifdef LEAN_RUNTIME_STATS
#define LEAN_RUNTIME_STAT_CODE(c) c
#else
#define LEAN_RUNTIME_STAT_CODE(c)
#endif
#define LEAN_BYTE(Var, Index) *(((uint8_t*)&Var)+Index)
#define LeanMaxCtorTag 244
@ -218,8 +229,52 @@ static inline size_t lean_unbox(lean_object * o) { return (size_t)(o) >> 1; }
void lean_panic_out_of_memory();
void * lean_alloc_heap_object(size_t sz);
void lean_free_heap_obj(lean_object * o);
static inline size_t lean_align(size_t v, size_t a) {
return (v / a)*a + a * (v % a != 0);
}
static inline unsigned lean_get_slot_idx(unsigned sz) {
assert(sz > 0);
assert(lean_align(sz, LEAN_OBJECT_SIZE_DELTA) == sz);
return sz / LEAN_OBJECT_SIZE_DELTA - 1;
}
void * lean_alloc_small(unsigned sz, unsigned slot_idx);
void lean_free_small(void * p);
unsigned lean_small_mem_size(void * p);
static inline lean_object * lean_alloc_small_object(unsigned sz) {
#ifdef LEAN_SMALL_ALLOCATOR
sz = lean_align(sz, LEAN_OBJECT_SIZE_DELTA);
unsigned slot_idx = lean_get_slot_idx(sz);
assert(sz <= LEAN_MAX_SMALL_OBJECT_SIZE);
return (lean_object*)lean_alloc_small(sz, slot_idx);
#else
void * mem = malloc(sizeof(size_t) + sz);
if (mem == 0) lean_panic_out_of_memory();
*(size_t*)mem = sz;
return (lean_object*)((size_t*)mem + 1);
#endif
}
static inline unsigned lean_small_object_size(lean_object * o) {
#ifdef LEAN_SMALL_ALLOCATOR
return lean_small_mem_size(o);
#else
return *((size_t*)o - 1);
#endif
}
static inline void lean_free_small_object(lean_object * o) {
#ifdef LEAN_SMALL_ALLOCATOR
lean_free_small(o);
#else
free((size_t*)o - 1);
#endif
}
lean_object * lean_alloc_object(size_t sz);
void lean_free_object(lean_object * o);
/* The object size may be slightly bigger for constructor objects.
The runtime does not track the size of the scalar size area.
@ -260,7 +315,7 @@ static inline bool lean_is_persistent(lean_object * o) {
#endif
}
static inline bool lean_is_heap_obj(lean_object * o) {
static inline bool lean_is_heap_object(lean_object * o) {
return lean_is_st(o) || lean_is_mt(o);
}
@ -485,7 +540,7 @@ static inline uint8_t * lean_ctor_scalar_cptr(lean_object * o) {
static inline lean_object * lean_alloc_ctor(unsigned tag, unsigned num_objs, unsigned scalar_sz) {
assert(tag <= LeanMaxCtorTag && num_objs < 256 && scalar_sz < 1024);
lean_object * o = (lean_object*)lean_alloc_heap_object(sizeof(lean_ctor_object) + sizeof(void*)*num_objs + scalar_sz);
lean_object * o = lean_alloc_small_object(sizeof(lean_ctor_object) + sizeof(void*)*num_objs + scalar_sz);
lean_set_st_header(o, tag, num_objs);
return o;
}
@ -575,7 +630,7 @@ static inline lean_object ** lean_closure_arg_cptr(lean_object * o) { return lea
static inline lean_obj_res lean_alloc_closure(void * fun, unsigned arity, unsigned num_fixed) {
assert(arity > 0);
assert(num_fixed < arity);
lean_closure_object * o = (lean_closure_object*)lean_alloc_heap_object(sizeof(lean_closure_object) + sizeof(void*)*num_fixed);
lean_closure_object * o = (lean_closure_object*)lean_alloc_small_object(sizeof(lean_closure_object) + sizeof(void*)*num_fixed);
lean_set_st_header((lean_object*)o, LeanClosure, 0);
o->m_fun = fun;
o->m_arity = arity;
@ -622,7 +677,7 @@ lean_obj_res lean_fixpoint6(lean_obj_arg rec, lean_obj_arg a1, lean_obj_arg a2,
/* Arrays of objects (low level API) */
static inline lean_obj_res lean_alloc_array(size_t size, size_t capacity) {
lean_array_object * o = (lean_array_object*)lean_alloc_heap_object(sizeof(lean_array_object) + sizeof(void*)*capacity);
lean_array_object * o = (lean_array_object*)lean_alloc_object(sizeof(lean_array_object) + sizeof(void*)*capacity);
lean_set_st_header((lean_object*)o, LeanArray, 0);
o->m_size = size;
o->m_capacity = capacity;
@ -771,7 +826,7 @@ lean_object * lean_mk_array(lean_obj_arg n, lean_obj_arg v);
/* Array of scalars */
static inline lean_obj_res lean_alloc_sarray(unsigned elem_size, size_t size, size_t capacity) {
lean_sarray_object * o = (lean_sarray_object*)lean_alloc_heap_object(sizeof(lean_sarray_object) + elem_size*capacity);
lean_sarray_object * o = (lean_sarray_object*)lean_alloc_object(sizeof(lean_sarray_object) + elem_size*capacity);
lean_set_st_header((lean_object*)o, LeanScalarArray, elem_size);
o->m_size = size;
o->m_capacity = capacity;
@ -847,7 +902,7 @@ static inline lean_obj_res lean_byte_array_set(lean_obj_arg a, b_lean_obj_arg i,
/* Strings */
static inline lean_obj_res lean_alloc_string(size_t size, size_t capacity, size_t len) {
lean_string_object * o = (lean_string_object*)lean_alloc_heap_object(sizeof(lean_string_object) + capacity);
lean_string_object * o = (lean_string_object*)lean_alloc_object(sizeof(lean_string_object) + capacity);
lean_set_st_header((lean_object*)o, LeanString, 0);
o->m_size = size;
o->m_capacity = capacity;
@ -892,7 +947,7 @@ size_t lean_string_hash(b_lean_obj_arg);
/* Thunks */
static inline lean_obj_res lean_mk_thunk(lean_obj_arg c) {
lean_thunk_object * o = (lean_thunk_object*)lean_alloc_heap_object(sizeof(lean_thunk_object));
lean_thunk_object * o = (lean_thunk_object*)lean_alloc_small_object(sizeof(lean_thunk_object));
lean_set_st_header((lean_object*)o, LeanThunk, 0);
o->m_value = (lean_object*)0;
o->m_closure = c;
@ -901,7 +956,7 @@ static inline lean_obj_res lean_mk_thunk(lean_obj_arg c) {
/* Thunk.pure : A -> Thunk A */
static inline lean_obj_res lean_thunk_pure(lean_obj_arg v) {
lean_thunk_object * o = (lean_thunk_object*)lean_alloc_heap_object(sizeof(lean_thunk_object));
lean_thunk_object * o = (lean_thunk_object*)lean_alloc_small_object(sizeof(lean_thunk_object));
lean_set_st_header((lean_object*)o, LeanThunk, 0);
o->m_value = v;
o->m_closure = (lean_object*)0;
@ -957,7 +1012,7 @@ b_lean_obj_res lean_io_wait_any_core(b_lean_obj_arg task_list);
/* External objects */
static inline lean_object * lean_alloc_external(lean_external_class * cls, void * data) {
lean_external_object * o = (lean_external_object*)lean_alloc_heap_object(sizeof(lean_external_object));
lean_external_object * o = (lean_external_object*)lean_alloc_small_object(sizeof(lean_external_object));
lean_set_st_header((lean_object*)o, LeanExternal, 0);
o->m_class = cls;
o->m_data = data;

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/
#pragma once
#include "runtime/mpz.h"
#include "runtime/serializer.h"
namespace lean {
/**

View file

@ -10,9 +10,12 @@ Author: Leonardo de Moura
#include <string>
#include <iostream>
#include <limits>
#include "runtime/int64.h"
#include "runtime/debug.h"
#include "runtime/serializer.h"
#include "runtime/lean.h"
namespace lean {
class mpq;
/** \brief Wrapper for GMP integers */
class mpz {
@ -275,7 +278,4 @@ public:
struct mpz_cmp_fn {
int operator()(mpz const & v1, mpz const & v2) const { return cmp(v1, v2); }
};
inline serializer & operator<<(serializer & s, mpz const & n) { s.write_mpz(n); return s; }
inline deserializer & operator>>(deserializer & d, mpz & n) { n = d.read_mpz(); return d; }
}

View file

@ -4,251 +4,169 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <limits>
#include <iostream>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
#include <utility>
#include <unordered_set>
#include <deque>
#include "runtime/stackinfo.h"
#include "runtime/object.h"
#include "runtime/utf8.h"
#include "runtime/apply.h"
#include "runtime/flet.h"
#include "runtime/interrupt.h"
#include "runtime/hash.h"
#include "runtime/thread.h"
#include "runtime/alloc.h"
#include "runtime/debug.h"
#include "util/buffer.h" // move to runtime
#define LEAN_MAX_PRIO 8
namespace lean {
// =======================================
// External objects
struct external_object_class {
external_object_finalize_proc m_finalize;
external_object_foreach_proc m_foreach;
};
static std::vector<external_object_class*> * g_ext_classes;
static mutex * g_ext_classes_mutex;
external_object_class * register_external_object_class(external_object_finalize_proc p1, external_object_foreach_proc p2) {
unique_lock<mutex> lock(*g_ext_classes_mutex);
external_object_class * cls = new external_object_class{p1, p2};
g_ext_classes->push_back(cls);
return cls;
extern "C" void lean_panic_out_of_memory() {
std::cerr << "out of memory\n";
std::exit(1);
}
// =======================================
// Object
size_t obj_byte_size(object * o) {
switch (get_kind(o)) {
case object_kind::Constructor: return cnstr_byte_size(o);
case object_kind::Closure: return closure_byte_size(o);
case object_kind::Array: return array_byte_size(o);
case object_kind::ScalarArray: return sarray_byte_size(o);
case object_kind::String: return string_byte_size(o);
case object_kind::MPZ: return sizeof(mpz_object);
case object_kind::Thunk: return sizeof(thunk_object);
case object_kind::Task: return sizeof(task_object);
case object_kind::Ref: return sizeof(ref_object);
case object_kind::External: lean_unreachable();
extern "C" size_t lean_object_byte_size(lean_object * o) {
switch (lean_ptr_tag(o)) {
case LeanArray: return lean_array_byte_size(o);
case LeanScalarArray: return lean_sarray_byte_size(o);
case LeanString: return lean_string_byte_size(o);
default: return lean_small_object_size(o);
}
lean_unreachable();
}
size_t obj_header_size(object * o) {
switch (get_kind(o)) {
case object_kind::Constructor: return sizeof(constructor_object);
case object_kind::Closure: return sizeof(closure_object);
case object_kind::Array: return sizeof(array_object);
case object_kind::ScalarArray: return sizeof(sarray_object);
case object_kind::String: return sizeof(string_object);
case object_kind::MPZ: return sizeof(mpz_object);
case object_kind::Thunk: return sizeof(thunk_object);
case object_kind::Task: return sizeof(task_object);
case object_kind::Ref: return sizeof(ref_object);
case object_kind::External: lean_unreachable();
}
lean_unreachable();
static inline lean_object * get_next(lean_object * o) {
#ifdef LEAN_COMPRESSED_OBJECT_HEADER
size_t header = o->m_header;
LEAN_BYTE(header, 6) = 0;
LEAN_BYTE(header, 7) = 0;
return (lean_object*)(header);
#else
return (lean_object*)(o->m_rc);
#endif
}
/* We use the RC memory to implement a linked list of lean objects to be deleted.
This hack is safe because rc_type is uintptr_t. */
static inline void set_next(lean_object * o, lean_object * n) {
#ifdef LEAN_COMPRESSED_OBJECT_HEADER
size_t new_header = (size_t)n;
LEAN_BYTE(new_header, 6) = LEAN_BYTE(o->m_header, 6);
LEAN_BYTE(new_header, 7) = LEAN_BYTE(o->m_header, 7);
o->m_header = new_header;
#else
*(lean_object*)(o->m_rc) = n;
#endif
}
static_assert(sizeof(atomic<rc_type>) == sizeof(object*), "unexpected atomic<rc_type> size, the object GC assumes these two types have the same size"); // NOLINT
static inline void push_back(lean_object * & todo, lean_object * v) {
set_next(v, todo);
todo = v;
}
static inline lean_object * pop_back(lean_object * & todo) {
lean_object * r = todo;
todo = get_next(todo);
return r;
}
static inline void dec_ref(lean_object * o, lean_object* & todo) {
if (lean_dec_ref_core(o))
push_back(todo, o);
}
static inline void dec(lean_object * o, lean_object* & todo) {
if (!lean_is_scalar(o) && lean_dec_ref_core(o))
push_back(todo, o);
}
#ifdef LEAN_LAZY_RC
LEAN_THREAD_PTR(object, g_to_free);
#endif
inline object * get_next(object * o) {
return *reinterpret_cast<object**>(st_rc_addr(o));
}
inline void set_next(object * o, object * n) {
*reinterpret_cast<object**>(st_rc_addr(o)) = n;
}
inline void push_back(object * & todo, object * v) {
set_next(v, todo);
todo = v;
}
inline object * pop_back(object * & todo) {
object * r = todo;
todo = get_next(todo);
return r;
}
inline void dec_ref(object * o, object* & todo) {
if (dec_ref_core(o))
push_back(todo, o);
}
inline void dec(object * o, object* & todo) {
if (!is_scalar(o) && dec_ref_core(o))
push_back(todo, o);
}
void deactivate_task(task_object * t);
static void lean_del_core(object * o, object * & todo);
extern "C" lean_object * lean_alloc_object(size_t sz) {
#ifdef LEAN_LAZY_RC
if (g_to_free) {
object * o = pop_back(g_to_free);
lean_del_core(o, g_to_free);
}
#endif
#ifdef LEAN_SMALL_ALLOCATOR
static inline void free_heap_obj_core(object * o, size_t sz) {
return (lean_object*)alloc(sz);
#else
static inline void free_heap_obj_core(object * o) {
#endif
#ifdef LEAN_FAKE_FREE
// Set kinds to invalid values, which should trap any further accesses in debug mode.
lean_always_assert(o->m_kind != 42);
o->m_kind = 42;
o->m_mem_kind = 42;
#else
#ifdef LEAN_SMALL_ALLOCATOR
dealloc(reinterpret_cast<char *>(o) - sizeof(rc_type), sz);
#else
free(reinterpret_cast<char *>(o) - sizeof(rc_type));
#endif
void * r = malloc(sz);
if (r == nullptr) lean_panic_out_of_memory();
return (lean_object*)r;
#endif
}
#ifdef LEAN_SMALL_ALLOCATOR
#define FREE_OBJ(o, sz) free_heap_obj_core(o, sz)
static void deactivate_task(lean_task_object * t);
static inline void lean_set_tag(b_lean_obj_arg o, uint8_t new_tag) {
assert(new_tag <= LeanMaxCtorTag);
#ifdef LEAN_COMPRESSED_OBJECT_HEADER
LEAN_BYTE(o->m_header, 7) = new_tag;
#else
#define FREE_OBJ(o, sz) free_heap_obj_core(o)
o->m_tag = new_tag;
#endif
void free_heap_obj(object * o) {
FREE_OBJ(o, obj_byte_size(o) + sizeof(rc_type));
}
static inline void free_cnstr_obj(object * o) {
FREE_OBJ(o, cnstr_byte_size(o) + sizeof(rc_type));
}
static inline void free_closure_obj_core(object * o) {
FREE_OBJ(o, closure_byte_size(o) + sizeof(rc_type));
}
void free_closure_obj(object * o) {
return free_closure_obj_core(o);
}
static inline void free_array_obj(object * o) {
FREE_OBJ(o, array_byte_size(o) + sizeof(rc_type));
}
static inline void free_sarray_obj(object * o) {
FREE_OBJ(o, sarray_byte_size(o) + sizeof(rc_type));
}
static inline void free_string_obj(object * o) {
FREE_OBJ(o, string_byte_size(o) + sizeof(rc_type));
}
inline void free_mpz_obj(object * o) {
FREE_OBJ(o, sizeof(mpz_object) + sizeof(rc_type));
}
static inline void free_thunk_obj(object * o) {
FREE_OBJ(o, sizeof(thunk_object) + sizeof(rc_type));
}
static inline void free_ref_obj(object * o) {
FREE_OBJ(o, sizeof(ref_object) + sizeof(rc_type));
}
static inline void free_task_obj(object * o) {
FREE_OBJ(o, sizeof(task_object) + sizeof(rc_type));
}
static inline void free_external_obj(object * o) {
FREE_OBJ(o, sizeof(external_object) + sizeof(rc_type));
}
static void del_core(object * o, object * & todo) {
lean_assert(is_heap_obj(o));
LEAN_RUNTIME_STAT_CODE(g_num_del++);
switch (get_kind(o)) {
case object_kind::Constructor: {
object ** it = cnstr_obj_cptr(o);
object ** end = it + cnstr_num_objs(o);
static void lean_del_core(object * o, object * & todo) {
lean_assert(lean_is_heap_object(o));
uint8 tag = lean_ptr_tag(o);
if (tag <= LeanMaxCtorTag) {
object ** it = lean_ctor_obj_cptr(o);
object ** end = it + lean_ctor_num_objs(o);
for (; it != end; ++it) dec(*it, todo);
free_cnstr_obj(o);
break;
lean_free_small(o);
return;
}
case object_kind::Closure: {
object ** it = closure_arg_cptr(o);
object ** end = it + closure_num_fixed(o);
switch (tag) {
case LeanClosure: {
object ** it = lean_closure_arg_cptr(o);
object ** end = it + lean_closure_num_fixed(o);
for (; it != end; ++it) dec(*it, todo);
free_closure_obj_core(o);
lean_free_small(o);
break;
}
case object_kind::Array: {
object ** it = array_cptr(o);
object ** end = it + array_size(o);
case LeanArray: {
object ** it = lean_array_cptr(o);
object ** end = it + lean_array_size(o);
for (; it != end; ++it) dec(*it, todo);
free_array_obj(o);
dealloc(o, lean_array_byte_size(o));
break;
}
case object_kind::ScalarArray:
free_sarray_obj(o); break;
case object_kind::String:
free_string_obj(o); break;
case object_kind::MPZ:
dealloc_mpz(o); break;
case object_kind::Thunk:
if (object * c = to_thunk(o)->m_closure) dec(c, todo);
if (object * v = to_thunk(o)->m_value) dec(v, todo);
free_thunk_obj(o);
case LeanScalarArray:
dealloc(o, lean_sarray_byte_size(o));
break;
case object_kind::Ref:
if (object * v = to_ref(o)->m_value) dec(v, todo);
free_ref_obj(o);
case LeanString:
dealloc(o, lean_string_byte_size(o));
break;
case object_kind::Task:
deactivate_task(to_task(o));
case LeanMPZ:
to_mpz(o)->m_value.~mpz();
lean_free_small(o);
break;
case object_kind::External:
to_external(o)->m_class->m_finalize(to_external(o)->m_data);
free_external_obj(o);
case LeanThunk:
if (object * c = lean_to_thunk(o)->m_closure) dec(c, todo);
if (object * v = lean_to_thunk(o)->m_value) dec(v, todo);
lean_free_small(o);
break;
case LeanRef:
if (object * v = lean_to_ref(o)->m_value) dec(v, todo);
lean_free_small(o);
break;
case LeanTask:
deactivate_task(lean_to_task(o));
break;
case LeanExternal:
lean_to_external(o)->m_class->m_finalize(lean_to_external(o)->m_data);
lean_free_small(o);
break;
default:
lean_unreachable();
}
}
void del(object * o) {
extern "C" void lean_del(object * o) {
#ifdef LEAN_LAZY_RC
push_back(g_to_free, o);
#else
object * todo = nullptr;
while (true) {
lean_assert(is_heap_obj(o));
del_core(o, todo);
lean_assert(lean_is_heap_object(o));
lean_del_core(o, todo);
if (todo == nullptr)
return;
o = pop_back(todo);
@ -256,23 +174,6 @@ void del(object * o) {
#endif
}
void * alloc_heap_object(size_t sz) {
#ifdef LEAN_LAZY_RC
if (g_to_free) {
object * o = pop_back(g_to_free);
del_core(o, g_to_free);
}
#endif
#ifdef LEAN_SMALL_ALLOCATOR
void * r = alloc(sizeof(rc_type) + sz);
#else
void * r = malloc(sizeof(rc_type) + sz);
if (r == nullptr) throw std::bad_alloc();
#endif
*static_cast<rc_type *>(r) = 1;
return static_cast<char *>(r) + sizeof(rc_type);
}
// =======================================
// Arrays
static object * g_array_empty = nullptr;
@ -281,6 +182,7 @@ object * array_mk_empty() {
return g_array_empty;
}
// =======================================
// Closures
@ -288,15 +190,15 @@ typedef object * (*lean_cfun2)(object *, object *); // NOLINT
typedef object * (*lean_cfun3)(object *, object *, object *); // NOLINT
static obj_res mk_closure_2_1(lean_cfun2 fn, obj_arg a) {
object * c = alloc_closure(fn, 1);
closure_set(c, 0, a);
object * c = lean_alloc_closure((void*)fn, 2, 1);
lean_closure_set(c, 0, a);
return c;
}
static obj_res mk_closure_3_2(lean_cfun3 fn, obj_arg a1, obj_arg a2) {
object * c = alloc_closure(fn, 2);
closure_set(c, 0, a1);
closure_set(c, 1, a2);
object * c = lean_alloc_closure((void*)fn, 3, 2);
lean_closure_set(c, 0, a1);
lean_closure_set(c, 1, a2);
return c;
}
@ -304,11 +206,11 @@ static obj_res mk_closure_3_2(lean_cfun3 fn, obj_arg a1, obj_arg a2) {
// Thunks
static obj_res mk_thunk_3_2(lean_cfun3 fn, obj_arg a1, obj_arg a2) {
return mk_thunk(mk_closure_3_2(fn, a1, a2));
return lean_mk_thunk(mk_closure_3_2(fn, a1, a2));
}
b_obj_res thunk_get_core(b_obj_arg t) {
object * c = to_thunk(t)->m_closure.exchange(nullptr);
extern "C" b_obj_res lean_thunk_get_core(b_obj_arg t) {
object * c = lean_to_thunk(t)->m_closure.exchange(nullptr);
if (c != nullptr) {
/* Recall that a closure uses the standard calling convention.
`thunk_get` "consumes" the result `r` by storing it at `to_thunk(t)->m_value`.
@ -317,48 +219,225 @@ b_obj_res thunk_get_core(b_obj_arg t) {
to be object stored in the constructor object.
Recall that `apply_1` also consumes `c`'s RC. */
object * r = apply_1(c, box(0));
object * r = lean_apply_1(c, lean_box(0));
lean_assert(r != nullptr); /* Closure must return a valid lean object */
lean_assert(to_thunk(t)->m_value == nullptr);
to_thunk(t)->m_value = r;
lean_assert(lean_to_thunk(t)->m_value == nullptr);
lean_to_thunk(t)->m_value = r;
return r;
} else {
lean_assert(c == nullptr);
/* There is another thread executing the closure. We keep waiting for the m_value to be
set by another thread. */
while (!to_thunk(t)->m_value) {
while (!lean_to_thunk(t)->m_value) {
this_thread::yield();
}
return to_thunk(t)->m_value;
return lean_to_thunk(t)->m_value;
}
}
static obj_res thunk_map_fn_closure(obj_arg f, obj_arg t, obj_arg /* u */) {
b_obj_res v = thunk_get(t);
inc(v);
obj_res r = apply_1(f, v);
dec(v);
b_obj_res v = lean_thunk_get(t);
lean_inc(v);
obj_res r = lean_apply_1(f, v);
lean_dec(v);
return r;
}
obj_res thunk_map(obj_arg f, obj_arg t) {
lean_assert(is_closure(f));
lean_assert(is_thunk(t));
extern "C" obj_res lean_thunk_map(obj_arg f, obj_arg t) {
lean_assert(lean_is_closure(f));
lean_assert(lean_is_thunk(t));
return mk_thunk_3_2(thunk_map_fn_closure, f, t);
}
static obj_res thunk_bind_fn_closure(obj_arg x, obj_arg f, obj_arg /* u */) {
b_obj_res v = thunk_get(x);
inc(v);
obj_res r = apply_1(f, v);
dec(x);
b_obj_res v = lean_thunk_get(x);
lean_inc(v);
obj_res r = lean_apply_1(f, v);
lean_dec(x);
return r;
}
obj_res thunk_bind(obj_arg x, obj_arg f) {
extern "C" obj_res lean_thunk_bind(obj_arg x, obj_arg f) {
return mk_thunk_3_2(thunk_bind_fn_closure, x, f);
}
// =======================================
// Fixpoint
static inline object * ptr_to_weak_ptr(object * p) {
return reinterpret_cast<object*>(reinterpret_cast<uintptr_t>(p) | 1);
}
static inline object * weak_ptr_to_ptr(object * w) {
return reinterpret_cast<object*>((reinterpret_cast<uintptr_t>(w) >> 1) << 1);
}
obj_res fixpoint_aux(obj_arg rec, obj_arg weak_k, obj_arg a) {
object * k = weak_ptr_to_ptr(weak_k);
lean_inc(k);
return lean_apply_2(rec, k, a);
}
extern "C" obj_res lean_fixpoint(obj_arg rec, obj_arg a) {
object * k = lean_alloc_closure((void*)fixpoint_aux, 3, 2);
lean_inc(rec);
lean_closure_set(k, 0, rec);
lean_closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = lean_apply_2(rec, k, a);
return r;
}
obj_res fixpoint_aux2(obj_arg rec, obj_arg weak_k, obj_arg a1, obj_arg a2) {
object * k = weak_ptr_to_ptr(weak_k);
lean_inc(k);
return lean_apply_3(rec, k, a1, a2);
}
extern "C" obj_res lean_fixpoint2(obj_arg rec, obj_arg a1, obj_arg a2) {
object * k = lean_alloc_closure((void*)fixpoint_aux2, 4, 2);
lean_inc(rec);
lean_closure_set(k, 0, rec);
lean_closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = lean_apply_3(rec, k, a1, a2);
return r;
}
obj_res fixpoint_aux3(obj_arg rec, obj_arg weak_k, obj_arg a1, obj_arg a2, obj_arg a3) {
object * k = weak_ptr_to_ptr(weak_k);
lean_inc(k);
return lean_apply_4(rec, k, a1, a2, a3);
}
extern "C" obj_res lean_fixpoint3(obj_arg rec, obj_arg a1, obj_arg a2, obj_arg a3) {
object * k = lean_alloc_closure((void*)fixpoint_aux3, 5, 2);
lean_inc(rec);
lean_closure_set(k, 0, rec);
lean_closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = lean_apply_4(rec, k, a1, a2, a3);
return r;
}
obj_res fixpoint_aux4(obj_arg rec, obj_arg weak_k, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4) {
object * k = weak_ptr_to_ptr(weak_k);
lean_inc(k);
return lean_apply_5(rec, k, a1, a2, a3, a4);
}
extern "C" obj_res lean_fixpoint4(obj_arg rec, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4) {
object * k = lean_alloc_closure((void*)fixpoint_aux4, 6, 2);
lean_inc(rec);
lean_closure_set(k, 0, rec);
lean_closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = lean_apply_5(rec, k, a1, a2, a3, a4);
return r;
}
obj_res fixpoint_aux5(obj_arg rec, obj_arg weak_k, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4, obj_arg a5) {
object * k = weak_ptr_to_ptr(weak_k);
lean_inc(k);
return lean_apply_6(rec, k, a1, a2, a3, a4, a5);
}
extern "C" obj_res lean_fixpoint5(obj_arg rec, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4, obj_arg a5) {
object * k = lean_alloc_closure((void*)fixpoint_aux5, 7, 2);
lean_inc(rec);
lean_closure_set(k, 0, rec);
lean_closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = lean_apply_6(rec, k, a1, a2, a3, a4, a5);
return r;
}
obj_res fixpoint_aux6(obj_arg rec, obj_arg weak_k, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4, obj_arg a5, obj_arg a6) {
object * k = weak_ptr_to_ptr(weak_k);
lean_inc(k);
return lean_apply_7(rec, k, a1, a2, a3, a4, a5, a6);
}
extern "C" obj_res lean_fixpoint6(obj_arg rec, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4, obj_arg a5, obj_arg a6) {
object * k = lean_alloc_closure((void*)fixpoint_aux6, 8, 2);
lean_inc(rec);
lean_closure_set(k, 0, rec);
lean_closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = lean_apply_7(rec, k, a1, a2, a3, a4, a5, a6);
return r;
}
// =======================================
// Mark Persistent
extern "C" void lean_mark_persistent(object * o);
static obj_res mark_persistent_fn(obj_arg o) {
lean_mark_persistent(o);
return box(0);
}
extern "C" void lean_mark_persistent(object * o) {
buffer<object*> todo;
todo.push_back(o);
while (!todo.empty()) {
object * o = todo.back();
todo.pop_back();
if (!lean_is_scalar(o) && lean_is_heap_object(o)) {
#ifdef LEAN_COMPRESSED_OBJECT_HEADER
o->m_header &= ~((1ull << LEAN_ST_BIT) | (1ull << LEAN_MT_BIT));
o->m_header |= (1ull << LEAN_PERSISTENT_BIT);
#else
o->m_mem_kind = LEAN_PERSISTENT_MEM_KIND;
#endif
switch (lean_ptr_tag(o)) {
case LeanScalarArray:
case LeanString:
case LeanMPZ:
break;
case LeanExternal: {
object * fn = lean_alloc_closure(reinterpret_cast<void*>(mark_persistent_fn), 1, 0);
lean_to_external(o)->m_class->m_foreach(lean_to_external(o)->m_data, fn);
lean_dec(fn);
break;
}
case LeanTask:
todo.push_back(lean_task_get(o));
break;
case LeanClosure: {
object ** it = lean_closure_arg_cptr(o);
object ** end = it + lean_closure_num_fixed(o);
for (; it != end; ++it) todo.push_back(*it);
break;
}
case LeanArray: {
object ** it = lean_array_cptr(o);
object ** end = it + lean_array_size(o);
for (; it != end; ++it) todo.push_back(*it);
break;
}
case LeanThunk:
if (object * c = lean_to_thunk(o)->m_closure) todo.push_back(c);
if (object * v = lean_to_thunk(o)->m_value) todo.push_back(v);
break;
case LeanRef:
if (object * v = lean_to_ref(o)->m_value) todo.push_back(v);
break;
case LeanReserved:
lean_unreachable();
break;
default: {
object ** it = lean_ctor_obj_cptr(o);
object ** end = it + lean_ctor_num_objs(o);
for (; it != end; ++it) todo.push_back(*it);
break;
}}
}
}
}
}
#if 0
namespace lean {
// =======================================
// Tasks
@ -841,64 +920,6 @@ b_obj_res io_wait_any_core(b_obj_arg task_list) {
return g_task_manager->wait_any(task_list);
}
void mark_persistent(object * o);
static obj_res mark_persistent_fn(obj_arg o) {
mark_persistent(o);
return box(0);
}
void mark_persistent(object * o) {
buffer<object*> todo;
todo.push_back(o);
while (!todo.empty()) {
object * o = todo.back();
todo.pop_back();
if (!is_scalar(o) && is_heap_obj(o)) {
o->m_mem_kind = static_cast<unsigned>(object_memory_kind::Persistent);
switch (get_kind(o)) {
case object_kind::ScalarArray:
case object_kind::String:
case object_kind::MPZ:
break;
case object_kind::External: {
object * fn = alloc_closure(reinterpret_cast<void*>(mark_persistent_fn), 1, 0);
to_external(o)->m_class->m_foreach(to_external(o)->m_data, fn);
dec(fn);
break;
}
case object_kind::Task:
todo.push_back(task_get(o));
break;
case object_kind::Constructor: {
object ** it = cnstr_obj_cptr(o);
object ** end = it + cnstr_num_objs(o);
for (; it != end; ++it) todo.push_back(*it);
break;
}
case object_kind::Closure: {
object ** it = closure_arg_cptr(o);
object ** end = it + closure_num_fixed(o);
for (; it != end; ++it) todo.push_back(*it);
break;
}
case object_kind::Array: {
object ** it = array_cptr(o);
object ** end = it + array_size(o);
for (; it != end; ++it) todo.push_back(*it);
break;
}
case object_kind::Thunk:
if (object * c = to_thunk(o)->m_closure) todo.push_back(c);
if (object * v = to_thunk(o)->m_value) todo.push_back(v);
break;
case object_kind::Ref:
if (object * v = to_ref(o)->m_value) todo.push_back(v);
break;
}
}
}
}
// =======================================
// Natural numbers
@ -1605,106 +1626,6 @@ object * array_push(obj_arg a, obj_arg v) {
return r;
}
// =======================================
// fixpoint
static inline object * ptr_to_weak_ptr(object * p) {
return reinterpret_cast<object*>(reinterpret_cast<uintptr_t>(p) | 1);
}
static inline object * weak_ptr_to_ptr(object * w) {
return reinterpret_cast<object*>((reinterpret_cast<uintptr_t>(w) >> 1) << 1);
}
obj_res fixpoint_aux(obj_arg rec, obj_arg weak_k, obj_arg a) {
object * k = weak_ptr_to_ptr(weak_k);
inc(k);
return apply_2(rec, k, a);
}
obj_res fixpoint(obj_arg rec, obj_arg a) {
object * k = alloc_closure(fixpoint_aux, 2);
inc(rec);
closure_set(k, 0, rec);
closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = apply_2(rec, k, a);
return r;
}
obj_res fixpoint_aux2(obj_arg rec, obj_arg weak_k, obj_arg a1, obj_arg a2) {
object * k = weak_ptr_to_ptr(weak_k);
inc(k);
return apply_3(rec, k, a1, a2);
}
obj_res fixpoint2(obj_arg rec, obj_arg a1, obj_arg a2) {
object * k = alloc_closure(fixpoint_aux2, 2);
inc(rec);
closure_set(k, 0, rec);
closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = apply_3(rec, k, a1, a2);
return r;
}
obj_res fixpoint_aux3(obj_arg rec, obj_arg weak_k, obj_arg a1, obj_arg a2, obj_arg a3) {
object * k = weak_ptr_to_ptr(weak_k);
inc(k);
return apply_4(rec, k, a1, a2, a3);
}
obj_res fixpoint3(obj_arg rec, obj_arg a1, obj_arg a2, obj_arg a3) {
object * k = alloc_closure(fixpoint_aux3, 2);
inc(rec);
closure_set(k, 0, rec);
closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = apply_4(rec, k, a1, a2, a3);
return r;
}
obj_res fixpoint_aux4(obj_arg rec, obj_arg weak_k, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4) {
object * k = weak_ptr_to_ptr(weak_k);
inc(k);
return apply_5(rec, k, a1, a2, a3, a4);
}
obj_res fixpoint4(obj_arg rec, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4) {
object * k = alloc_closure(fixpoint_aux4, 2);
inc(rec);
closure_set(k, 0, rec);
closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = apply_5(rec, k, a1, a2, a3, a4);
return r;
}
obj_res fixpoint_aux5(obj_arg rec, obj_arg weak_k, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4, obj_arg a5) {
object * k = weak_ptr_to_ptr(weak_k);
inc(k);
return apply_6(rec, k, a1, a2, a3, a4, a5);
}
obj_res fixpoint5(obj_arg rec, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4, obj_arg a5) {
object * k = alloc_closure(fixpoint_aux5, 2);
inc(rec);
closure_set(k, 0, rec);
closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = apply_6(rec, k, a1, a2, a3, a4, a5);
return r;
}
obj_res fixpoint_aux6(obj_arg rec, obj_arg weak_k, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4, obj_arg a5, obj_arg a6) {
object * k = weak_ptr_to_ptr(weak_k);
inc(k);
return apply_7(rec, k, a1, a2, a3, a4, a5, a6);
}
obj_res fixpoint6(obj_arg rec, obj_arg a1, obj_arg a2, obj_arg a3, obj_arg a4, obj_arg a5, obj_arg a6) {
object * k = alloc_closure(fixpoint_aux6, 2);
inc(rec);
closure_set(k, 0, rec);
closure_set(k, 1, ptr_to_weak_ptr(k));
object * r = apply_7(rec, k, a1, a2, a3, a4, a5, a6);
return r;
}
// =======================================
// Runtime info
@ -1812,3 +1733,4 @@ void finalize_object() {
extern "C" void lean_dbg_print_str(lean::object* o) { lean::dbg_print_str(o); }
extern "C" void lean_dbg_print_num(lean::object* o) { lean::dbg_print_num(o); }
#endif

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "runtime/lean.h"
#include "runtime/debug.h"
namespace lean {

View file

@ -75,7 +75,10 @@ void serializer::write_blob(std::string const & s) {
void serializer::write_constructor(object * o) {
lean_assert(is_cnstr(o));
unsigned num_objs = cnstr_num_objs(o);
unsigned scalar_sz = cnstr_scalar_size(o);
unsigned obj_size = lean_object_byte_size(o);
unsigned main_size = sizeof(lean_ctor_object) + sizeof(lean_object*)*num_objs;
lean_assert(obj_size >= main_size);
unsigned scalar_sz = obj_size - main_size;
write_unsigned_short(cnstr_tag(o));
write_unsigned_short(num_objs);
write_unsigned_short(scalar_sz);
@ -127,8 +130,8 @@ void serializer::write_scalar_array(object * o) {
write_unsigned(esz);
write_size_t(sz);
size_t num_bytes = sz*esz;
unsigned char const * it = sarray_cptr_core<unsigned char>(o);
unsigned char const * end = it + num_bytes;
uint8 const * it = sarray_cptr(o);
uint8 const * end = it + num_bytes;
for (; it != end; ++it)
m_out.put(*it);
}
@ -167,19 +170,19 @@ void serializer::write_object(object * o) {
m_out.put(1);
write_unsigned(it->second);
} else {
object_kind k = get_kind(o);
uint8 k = lean_ptr_tag(o);
m_out.put(static_cast<unsigned>(k) + 2);
switch (k) {
case object_kind::Constructor: write_constructor(o); break;
case object_kind::Closure: write_closure(o); break;
case object_kind::Task: write_task(o); break;
case object_kind::Thunk: write_thunk(o); break;
case object_kind::Array: write_array(o); break;
case object_kind::ScalarArray: write_scalar_array(o); break;
case object_kind::String: write_string_object(o); break;
case object_kind::MPZ: write_mpz(mpz_value(o)); break;
case object_kind::External: write_external(o); break;
default: lean_unreachable();
case LeanClosure: write_closure(o); break;
case LeanTask: write_task(o); break;
case LeanThunk: write_thunk(o); break;
case LeanArray: write_array(o); break;
case LeanScalarArray: write_scalar_array(o); break;
case LeanString: write_string_object(o); break;
case LeanMPZ: write_mpz(mpz_value(o)); break;
case LeanExternal: write_external(o); break;
case LeanReserved: lean_unreachable(); break;
default: write_constructor(o); break;
}
inc_ref(o);
m_obj_table.insert(std::make_pair(o, m_obj_table.size()));
@ -320,11 +323,11 @@ object * deserializer::read_array() {
}
object * deserializer::read_scalar_array() {
unsigned esz = read_unsigned();
size_t sz = read_size_t();
object * r = alloc_sarray(esz, sz, sz);
unsigned char * it = sarray_cptr_core<unsigned char>(r);
unsigned char * end = it + sz*esz;
unsigned esz = read_unsigned();
size_t sz = read_size_t();
object * r = alloc_sarray(esz, sz, sz);
uint8 * it = sarray_cptr(r);
uint8 * end = it + sz*esz;
for (; it != end; ++it)
*it = m_in.get();
return r;
@ -355,19 +358,23 @@ object * deserializer::read_object() {
throw corrupted_stream_exception();
return m_objs[i];
} else {
object_kind k = static_cast<object_kind>(c - 2);
object * r;
switch (k) {
case object_kind::Constructor: r = read_constructor(); break;
case object_kind::Closure: r = read_closure(); break;
case object_kind::Thunk: r = read_thunk(); break;
case object_kind::Task: r = read_task(); break;
case object_kind::Array: r = read_array(); break;
case object_kind::ScalarArray: r = read_scalar_array(); break;
case object_kind::String: r = read_string_object(); break;
case object_kind::MPZ: r = alloc_mpz(read_mpz()); break;
case object_kind::External: r = read_external(); break;
default: throw corrupted_stream_exception();
switch (c - 2) {
case LeanClosure: r = read_closure(); break;
case LeanThunk: r = read_thunk(); break;
case LeanTask: r = read_task(); break;
case LeanArray: r = read_array(); break;
case LeanScalarArray: r = read_scalar_array(); break;
case LeanString: r = read_string_object(); break;
case LeanMPZ: r = alloc_mpz(read_mpz()); break;
case LeanExternal: r = read_external(); break;
case LeanReserved: throw corrupted_stream_exception();
default:
if (c - 2 < LeanMaxCtorTag)
r = read_constructor();
else
throw corrupted_stream_exception();
break;
}
m_objs.push_back(r);
return r;

View file

@ -12,12 +12,10 @@ Author: Leonardo de Moura
#include <functional>
#include <unordered_map>
#include <cstring>
#include "runtime/int64.h"
#include "runtime/object.h"
#include "runtime/optional.h"
namespace lean {
struct object;
class mpz;
class serializer {
std::ostream & m_out;
std::unordered_map<object*, unsigned, std::hash<object*>, std::equal_to<object*>> m_obj_table;
@ -138,4 +136,7 @@ deserializer & operator>>(deserializer & d, optional<T> & a) {
a = read_optional<T>(d);
return d;
}
inline serializer & operator<<(serializer & s, mpz const & n) { s.write_mpz(n); return s; }
inline deserializer & operator>>(deserializer & d, mpz & n) { n = d.read_mpz(); return d; }
}

View file

@ -4,48 +4,7 @@ add_exec_test(object "object")
add_executable(compact compact.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(compact ${EXTRA_LIBS})
add_exec_test(compact "compact")
add_executable(name name.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(name ${EXTRA_LIBS})
add_exec_test(name "name")
add_executable(nat nat.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(nat ${EXTRA_LIBS})
add_exec_test(nat "nat")
add_executable(buffer buffer.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(buffer ${EXTRA_LIBS})
add_exec_test(buffer "buffer")
add_executable(list list.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(list ${EXTRA_LIBS})
add_exec_test(list "list")
add_executable(rb_tree rb_tree.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(rb_tree ${EXTRA_LIBS})
add_exec_test(rb_tree "rb_tree")
add_executable(rb_map rb_map.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(rb_map ${EXTRA_LIBS})
add_exec_test(rb_map "rb_map")
add_executable(bit_tricks bit_tricks.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(bit_tricks ${EXTRA_LIBS})
add_exec_test(bit_tricks "bit_tricks")
add_executable(hash hash.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(hash ${EXTRA_LIBS})
add_exec_test(hash "hash")
add_executable(set set.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(set ${EXTRA_LIBS})
add_exec_test(set "set")
add_executable(optional optional.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(optional ${EXTRA_LIBS})
add_exec_test(optional "optional")
add_executable(stackinfo stackinfo.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(stackinfo ${EXTRA_LIBS})
add_exec_test(stackinfo "stackinfo")
add_executable(serializer serializer.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(serializer ${EXTRA_LIBS})
add_exec_test(serializer "serializer")
add_executable(trie trie.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(trie ${EXTRA_LIBS})
add_exec_test(trie "trie")
add_executable(thread thread.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(thread ${EXTRA_LIBS})
add_exec_test(thread "thread")
add_executable(bitap_fuzzy_search bitap_fuzzy_search.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:runtime>)
target_link_libraries(bitap_fuzzy_search ${EXTRA_LIBS})
add_exec_test(bitap_fuzzy_search "bitap_fuzzy_search")
add_executable(testruntime runtime.cpp ${LEAN_SOURCE_DIR}/runtime/object.cpp ${LEAN_SOURCE_DIR}/runtime/alloc.cpp ${LEAN_SOURCE_DIR}/runtime/thread.cpp
${LEAN_SOURCE_DIR}/runtime/exception.cpp ${LEAN_SOURCE_DIR}/runtime/interrupt.cpp ${LEAN_SOURCE_DIR}/runtime/stackinfo.cpp ${LEAN_SOURCE_DIR}/runtime/memory.cpp ${LEAN_SOURCE_DIR}/runtime/debug.cpp ${LEAN_SOURCE_DIR}/runtime/apply.cpp)
target_link_libraries(testruntime ${EXTRA_LIBS})
add_exec_test(testruntime "runtime")

View file

@ -11,6 +11,7 @@ Author: Leonardo de Moura
#include "util/test.h" // <<< comment this list for performance experiments
#include "util/timeit.h"
#include "runtime/stackinfo.h"
#include "runtime/thread.h"
#include "runtime/serializer.h"
#include "runtime/sstream.h"
#include "util/object_ref.h"
@ -433,7 +434,7 @@ bool contains(object * l, object * v) {
object * h = cnstr_get(l, 0);
object * t = cnstr_get(l, 1);
if (!is_shared(l)) {
free_heap_obj(l);
lean_free_object(l);
} else {
inc(h);
inc(t);
@ -482,7 +483,7 @@ bool contains_hybrid(object * l, object * v) {
if (l_b) {
t = mark_borrowed(t_obj);
} else if (!is_shared(l_obj)) {
free_heap_obj(l_obj);
lean_free_object(l_obj);
t = t_obj;
} else {
inc(h_obj);
@ -511,7 +512,7 @@ bool contains_fast_hybrid(object * l, object * v) {
object * t = cnstr_get(l, 1);
bool shared = is_shared(l);
if (!shared) {
free_heap_obj(l);
lean_free_object(l);
} else {
inc(h);
inc(t);

View file

@ -1,5 +1,5 @@
add_library(util OBJECT object_ref.cpp name.cpp name_set.cpp fresh_name.cpp
escaped.cpp bit_tricks.cpp ascii.cpp shared_mutex.cpp
escaped.cpp bit_tricks.cpp ascii.cpp
path.cpp lean_path.cpp lbool.cpp bitap_fuzzy_search.cpp
init_module.cpp list_fn.cpp file_lock.cpp timeit.cpp timer.cpp
parser_exception.cpp name_generator.cpp kvmap.cpp map_foreach.cpp

View file

@ -9,6 +9,7 @@ Author: Leonardo de Moura
#include <string>
#include "runtime/object.h"
#include "runtime/optional.h"
#include "runtime/serializer.h"
namespace lean {
/* Smart point for Lean objects. It is useful for writing C++ code that manipulates Lean objects. */
@ -17,7 +18,7 @@ protected:
object * m_obj;
public:
object_ref():m_obj(box(0)) {}
explicit object_ref(obj_arg o):m_obj(o) { lean_assert(is_scalar(o) || !is_heap_obj(o) || get_rc(o) > 0); }
explicit object_ref(obj_arg o):m_obj(o) { lean_assert(is_scalar(o) || !is_heap_obj(o) || lean_nonzero_rc(o)); }
object_ref(b_obj_arg o, bool):m_obj(o) { inc(o); }
object_ref(object_ref const & s):m_obj(s.m_obj) { inc(m_obj); }
object_ref(object_ref && s):m_obj(s.m_obj) { s.m_obj = box(0); }
@ -128,7 +129,7 @@ inline object_ref mk_cnstr(unsigned tag, object_ref const & o1, object_ref const
inline object_ref const & cnstr_get_ref(object * o, unsigned i) {
static_assert(sizeof(object_ref) == sizeof(object *), "unexpected object_ref size"); // NOLINT
lean_assert(is_cnstr(o));
return reinterpret_cast<object_ref const *>(reinterpret_cast<char*>(o) + sizeof(constructor_object))[i];
return reinterpret_cast<object_ref const *>(lean_to_ctor(o)->m_objs)[i];
}
inline object_ref const & cnstr_get_ref(object_ref const & ref, unsigned i) {

View file

@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "util/shared_mutex.h"
#include "util/option_declarations.h"
namespace lean {
@ -46,11 +45,11 @@ void option_declaration::display_value(std::ostream & out, options const & o) co
}
static option_declarations * g_option_declarations = nullptr;
static shared_mutex * g_option_declarations_guard = nullptr;
static mutex * g_option_declarations_guard = nullptr;
void initialize_option_declarations() {
g_option_declarations = new option_declarations();
g_option_declarations_guard = new shared_mutex();
g_option_declarations_guard = new mutex();
}
void finalize_option_declarations() {
@ -61,14 +60,14 @@ void finalize_option_declarations() {
option_declarations get_option_declarations() {
option_declarations r;
{
shared_lock lock(*g_option_declarations_guard);
unique_lock<mutex> lock(*g_option_declarations_guard);
r = *g_option_declarations;
}
return r;
}
void register_option(name const & n, data_value_kind k, char const * default_value, char const * description) {
exclusive_lock lock(*g_option_declarations_guard);
unique_lock<mutex> lock(*g_option_declarations_guard);
g_option_declarations->insert(n, option_declaration(n, k, default_value, description));
}
}

View file

@ -5,6 +5,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "runtime/serializer.h"
#include "util/object_ref.h"
namespace lean {