feat(runtime/cpp): add runtime library for Lean -> C++ compiler

This commit is contained in:
Leonardo de Moura 2015-09-09 19:35:47 -07:00
parent f941af03ba
commit e36fde4d45
2 changed files with 605 additions and 0 deletions

View file

@ -0,0 +1,467 @@
/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "util/thread.h"
#include "util/buffer.h"
#include "runtime/cpp/lean_runtime.h"
#define LEAN_NUM_OBJ_FREE_LISTS 32
namespace lean {
class obj_pool {
void * m_free_list[LEAN_NUM_OBJ_FREE_LISTS];
public:
obj_pool() {
for (unsigned i = 0; i < LEAN_NUM_OBJ_FREE_LISTS; i++)
m_free_list[i] = nullptr;
}
~obj_pool() {
for (unsigned i = 0; i < LEAN_NUM_OBJ_FREE_LISTS; i++) {
void * lst = m_free_list[i];
while (lst != nullptr) {
void * r = lst;
lst = *(reinterpret_cast<void **>(r));
free(r);
}
}
}
void * allocate(unsigned n) {
if (n < LEAN_NUM_OBJ_FREE_LISTS && m_free_list[n] != nullptr) {
void * r = m_free_list[n];
m_free_list[n] = *(reinterpret_cast<void **>(r));
return r;
} else {
return malloc(sizeof(obj) + sizeof(void*)*n);
}
}
void recycle(void * ptr, unsigned n) {
if (n < LEAN_NUM_OBJ_FREE_LISTS) {
*(reinterpret_cast<void**>(ptr)) = m_free_list[n];
m_free_list[n] = ptr;
} else {
free(ptr);
}
}
};
LEAN_THREAD_PTR(obj_pool, g_obj_pool);
static void finalize_obj_pool(void * p) {
obj_pool * pool = reinterpret_cast<obj_pool*>(p);
delete pool;
g_obj_pool = nullptr;
}
void * alloc_obj(unsigned n) {
if (!g_obj_pool) {
g_obj_pool = new obj_pool();
register_post_thread_finalizer(finalize_obj_pool, g_obj_pool);
}
return g_obj_pool->allocate(n);
}
obj_cell::obj_cell(unsigned cidx, unsigned sz, obj const * fs):
m_rc(0), m_kind(static_cast<unsigned>(obj_kind::Constructor)), m_size(sz), m_cidx(cidx) {
void ** mem = field_addr();
for (unsigned i = 0; i < sz; i++, mem++)
new (mem) obj(fs[i]);
}
obj_cell::obj_cell(void * fn, unsigned arity, unsigned sz, obj const * fs):
m_rc(0), m_kind(static_cast<unsigned>(obj_kind::Closure)), m_size(sz), m_cidx(arity) {
void ** mem = field_addr();
for (unsigned i = 0; i < sz; i++, mem++)
new (mem) obj(fs[i]);
*fn_ptr_addr() = fn;
}
void obj_cell::copy_fields(obj_cell const & src) {
obj const * from = src.field_ptr();
void ** mem = field_addr();
for (unsigned i = 0; i < src.m_size; i++, from++, mem++)
new (mem) obj(*from);
}
obj_cell::obj_cell(obj_cell const & src, obj const & a1):
m_rc(0), m_kind(static_cast<unsigned>(obj_kind::Closure)), m_size(src.m_size+1), m_cidx(src.m_cidx) {
copy_fields(src);
void ** f = field_addr();
new (f + src.m_size) obj(a1);
}
obj_cell::obj_cell(obj_cell const & src, obj const & a1, obj const & a2):
m_rc(0), m_kind(static_cast<unsigned>(obj_kind::Closure)), m_size(src.m_size+2), m_cidx(src.m_cidx) {
copy_fields(src);
void ** f = field_addr();
new (f + src.m_size) obj(a1);
new (f + src.m_size + 1) obj(a2);
}
obj_cell::obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3):
m_rc(0), m_kind(static_cast<unsigned>(obj_kind::Closure)), m_size(src.m_size+3), m_cidx(src.m_cidx) {
copy_fields(src);
void ** f = field_addr();
new (f + src.m_size) obj(a1);
new (f + src.m_size + 1) obj(a2);
new (f + src.m_size + 2) obj(a3);
}
obj_cell::obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3, obj const & a4):
m_rc(0), m_kind(static_cast<unsigned>(obj_kind::Closure)), m_size(src.m_size+4), m_cidx(src.m_cidx) {
copy_fields(src);
void ** f = field_addr();
new (f + src.m_size) obj(a1);
new (f + src.m_size + 1) obj(a2);
new (f + src.m_size + 2) obj(a3);
new (f + src.m_size + 3) obj(a4);
}
obj_cell::obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5):
m_rc(0), m_kind(static_cast<unsigned>(obj_kind::Closure)), m_size(src.m_size+5), m_cidx(src.m_cidx) {
copy_fields(src);
void ** f = field_addr();
new (f + src.m_size) obj(a1);
new (f + src.m_size + 1) obj(a2);
new (f + src.m_size + 2) obj(a3);
new (f + src.m_size + 3) obj(a4);
new (f + src.m_size + 4) obj(a5);
}
obj_cell::obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5,
obj const & a6):
m_rc(0), m_kind(static_cast<unsigned>(obj_kind::Closure)), m_size(src.m_size+6), m_cidx(src.m_cidx) {
copy_fields(src);
void ** f = field_addr();
new (f + src.m_size) obj(a1);
new (f + src.m_size + 1) obj(a2);
new (f + src.m_size + 2) obj(a3);
new (f + src.m_size + 3) obj(a4);
new (f + src.m_size + 4) obj(a5);
new (f + src.m_size + 5) obj(a6);
}
obj_cell::obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5,
obj const & a6, obj const & a7):
m_rc(0), m_kind(static_cast<unsigned>(obj_kind::Closure)), m_size(src.m_size+7), m_cidx(src.m_cidx) {
copy_fields(src);
void ** f = field_addr();
new (f + src.m_size) obj(a1);
new (f + src.m_size + 1) obj(a2);
new (f + src.m_size + 2) obj(a3);
new (f + src.m_size + 3) obj(a4);
new (f + src.m_size + 4) obj(a5);
new (f + src.m_size + 5) obj(a6);
new (f + src.m_size + 6) obj(a7);
}
obj_cell::obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5,
obj const & a6, obj const & a7, obj const & a8):
m_rc(0), m_kind(static_cast<unsigned>(obj_kind::Closure)), m_size(src.m_size+8), m_cidx(src.m_cidx) {
copy_fields(src);
void ** f = field_addr();
new (f + src.m_size) obj(a1);
new (f + src.m_size + 1) obj(a2);
new (f + src.m_size + 2) obj(a3);
new (f + src.m_size + 3) obj(a4);
new (f + src.m_size + 4) obj(a5);
new (f + src.m_size + 5) obj(a6);
new (f + src.m_size + 6) obj(a7);
new (f + src.m_size + 7) obj(a8);
}
#define DEC_FIELDS(o, todo) { \
void ** f = o->field_addr(); \
for (unsigned i = 0; i < o->m_size; i++, f++) { \
obj_cell * c = reinterpret_cast<obj*>(f)->steal_ptr(); \
if (LEAN_IS_PTR(c) && c->dec_ref_core()) \
todo.push_back(c); \
} \
}
void obj_cell::dealloc() {
try {
buffer<obj_cell*> todo;
todo.push_back(this);
while (!todo.empty()) {
obj_cell * it = todo.back();
unsigned sz = it->m_size;
todo.pop_back();
switch (it->kind()) {
case obj_kind::Constructor:
DEC_FIELDS(it, todo);
it->~obj_cell();
g_obj_pool->recycle(it, sz);
break;
case obj_kind::Closure:
DEC_FIELDS(it, todo);
it->~obj_cell();
g_obj_pool->recycle(it, sz+1);
break;
case obj_kind::MPN:
// TODO(Leo):
break;
}
}
} catch (std::bad_alloc&) {
// We need this catch, because push_back may fail when expanding the buffer.
// In this case, we avoid the crash, and "accept" the memory leak.
}
}
obj mk_obj(unsigned cidx, unsigned n, obj const * fs) {
void * mem = alloc_obj(n);
return obj(new (mem) obj_cell(cidx, n, fs));
}
obj mk_closure_core(void * fn, unsigned arity, unsigned n, obj const * fs) {
void * mem = alloc_obj(n+1);
return obj(new (mem) obj_cell(fn, arity, n, fs));
}
static obj mk_closure(obj const & f, obj const & a1) {
void * mem = alloc_obj(f.size()+1);
return obj(new (mem) obj_cell(f.data(), a1));
}
static obj mk_closure(obj const & f, obj const & a1, obj const & a2) {
void * mem = alloc_obj(f.size()+2);
return obj(new (mem) obj_cell(f.data(), a1, a2));
}
static obj mk_closure(obj const & f, obj const & a1, obj const & a2, obj const & a3) {
void * mem = alloc_obj(f.size()+3);
return obj(new (mem) obj_cell(f.data(), a1, a2, a3));
}
static obj mk_closure(obj const & f, obj const & a1, obj const & a2, obj const & a3, obj const & a4) {
void * mem = alloc_obj(f.size()+4);
return obj(new (mem) obj_cell(f.data(), a1, a2, a3, a4));
}
static obj mk_closure(obj const & f, obj const & a1, obj const & a2, obj const & a3, obj const & a4,
obj const & a5) {
void * mem = alloc_obj(f.size()+5);
return obj(new (mem) obj_cell(f.data(), a1, a2, a3, a4, a5));
}
static obj mk_closure(obj const & f, obj const & a1, obj const & a2, obj const & a3, obj const & a4,
obj const & a5, obj const & a6) {
void * mem = alloc_obj(f.size()+6);
return obj(new (mem) obj_cell(f.data(), a1, a2, a3, a4, a5, a6));
}
static obj mk_closure(obj const & f, obj const & a1, obj const & a2, obj const & a3, obj const & a4,
obj const & a5, obj const & a6, obj const & a7) {
void * mem = alloc_obj(f.size()+7);
return obj(new (mem) obj_cell(f.data(), a1, a2, a3, a4, a5, a6, a7));
}
static obj mk_closure(obj const & f, obj const & a1, obj const & a2, obj const & a3, obj const & a4,
obj const & a5, obj const & a6, obj const & a7, obj const & a8) {
void * mem = alloc_obj(f.size()+8);
return obj(new (mem) obj_cell(f.data(), a1, a2, a3, a4, a5, a6, a7, a8));
}
typedef obj (*fn1)(obj const &);
typedef obj (*fn2)(obj const &, obj const &);
typedef obj (*fn3)(obj const &, obj const &, obj const &);
typedef obj (*fn4)(obj const &, obj const &, obj const &, obj const &);
typedef obj (*fn5)(obj const &, obj const &, obj const &, obj const &, obj const &);
typedef obj (*fn6)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &);
typedef obj (*fn7)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &);
typedef obj (*fn8)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &);
typedef obj (*fn9)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &, obj const &);
typedef obj (*fn10)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &, obj const &, obj const &);
typedef obj (*fn11)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &, obj const &, obj const &, obj const &);
typedef obj (*fn12)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &, obj const &, obj const &, obj const &, obj const &);
typedef obj (*fn13)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &);
typedef obj (*fn14)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &);
typedef obj (*fn15)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &, obj const &);
typedef obj (*fn16)(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &, obj const &, obj const &);
typedef obj (*fnN)(unsigned, obj const *);
inline fn1 to_fn1(obj const & o) { return reinterpret_cast<fn1>(o.fn_ptr()); }
inline fn2 to_fn2(obj const & o) { return reinterpret_cast<fn2>(o.fn_ptr()); }
inline fn3 to_fn3(obj const & o) { return reinterpret_cast<fn3>(o.fn_ptr()); }
inline fn4 to_fn4(obj const & o) { return reinterpret_cast<fn4>(o.fn_ptr()); }
inline fn5 to_fn5(obj const & o) { return reinterpret_cast<fn5>(o.fn_ptr()); }
inline fn6 to_fn6(obj const & o) { return reinterpret_cast<fn6>(o.fn_ptr()); }
inline fn7 to_fn7(obj const & o) { return reinterpret_cast<fn7>(o.fn_ptr()); }
inline fn8 to_fn8(obj const & o) { return reinterpret_cast<fn8>(o.fn_ptr()); }
inline fnN to_fnN(obj const & o) { return reinterpret_cast<fnN>(o.fn_ptr()); }
#define FN1 to_fn1(*this)
#define FN2 to_fn2(*this)
#define FN3 to_fn3(*this)
#define FN4 to_fn4(*this)
#define FN5 to_fn5(*this)
#define FN6 to_fn6(*this)
#define FN7 to_fn7(*this)
#define FN8 to_fn8(*this)
#define FNN to_fnN(*this)
obj obj::apply() const {
unsigned ar = arity();
if (ar == size()) {
switch (ar) {
case 1: return FN1(fld(0));
case 2: return FN2(fld(0), fld(1));
case 3: return FN3(fld(0), fld(1), fld(2));
case 4: return FN4(fld(0), fld(1), fld(2), fld(3));
case 5: return FN5(fld(0), fld(1), fld(2), fld(3), fld(4));
case 6: return FN6(fld(0), fld(1), fld(2), fld(3), fld(4), fld(5));
case 7: return FN7(fld(0), fld(1), fld(2), fld(3), fld(4), fld(5), fld(6));
case 8: return FN8(fld(0), fld(1), fld(2), fld(3), fld(4), fld(5), fld(6), fld(7));
default: return FNN(ar, m_data->field_ptr());
}
} else {
return *this;
}
}
obj obj::apply(obj const & a1) const {
unsigned ar = arity();
if (ar == size() + 1) {
switch (ar) {
case 1: return FN1(a1);
case 2: return FN2(fld(0), a1);
case 3: return FN3(fld(0), fld(1), a1);
case 4: return FN4(fld(0), fld(1), fld(2), a1);
case 5: return FN5(fld(0), fld(1), fld(2), fld(3), a1);
case 6: return FN6(fld(0), fld(1), fld(2), fld(3), fld(4), a1);
case 7: return FN7(fld(0), fld(1), fld(2), fld(3), fld(4), fld(5), a1);
case 8: return FN8(fld(0), fld(1), fld(2), fld(3), fld(4), fld(5), fld(6), a1);
default: return mk_closure(*this, a1).apply();
}
} else {
return mk_closure(*this, a1);
}
}
obj obj::apply(obj const & a1, obj const & a2) const {
unsigned ar = arity();
if (ar == size() + 2) {
switch (ar) {
case 2: return FN2(a1, a2);
case 3: return FN3(fld(0), a1, a2);
case 4: return FN4(fld(0), fld(1), a1, a2);
case 5: return FN5(fld(0), fld(1), fld(2), a1, a2);
case 6: return FN6(fld(0), fld(1), fld(2), fld(3), a1, a2);
case 7: return FN7(fld(0), fld(1), fld(2), fld(3), fld(4), a1, a2);
case 8: return FN8(fld(0), fld(1), fld(2), fld(3), fld(4), fld(5), a1, a2);
default: return mk_closure(*this, a1, a2).apply();
}
} else {
return mk_closure(*this, a1, a2);
}
}
obj obj::apply(obj const & a1, obj const & a2, obj const & a3) const {
unsigned ar = arity();
if (ar == size() + 3) {
switch (ar) {
case 3: return FN3(a1, a2, a3);
case 4: return FN4(fld(0), a1, a2, a3);
case 5: return FN5(fld(0), fld(1), a1, a2, a3);
case 6: return FN6(fld(0), fld(1), fld(2), a1, a2, a3);
case 7: return FN7(fld(0), fld(1), fld(2), fld(3), a1, a2, a3);
case 8: return FN8(fld(0), fld(1), fld(2), fld(3), fld(4), a1, a2, a3);
default: return mk_closure(*this, a1, a2, a3).apply();
}
} else {
return mk_closure(*this, a1, a2, a3);
}
}
obj obj::apply(obj const & a1, obj const & a2, obj const & a3, obj const & a4) const {
unsigned ar = arity();
if (ar == size() + 4) {
switch (ar) {
case 4: return FN4(a1, a2, a3, a4);
case 5: return FN5(fld(0), a1, a2, a3, a4);
case 6: return FN6(fld(0), fld(1), a1, a2, a3, a4);
case 7: return FN7(fld(0), fld(1), fld(2), a1, a2, a3, a4);
case 8: return FN8(fld(0), fld(1), fld(2), fld(3), a1, a2, a3, a4);
default: return mk_closure(*this, a1, a2, a3, a4).apply();
}
} else {
return mk_closure(*this, a1, a2, a3, a4);
}
}
obj obj::apply(obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5) const {
unsigned ar = arity();
if (ar == size() + 5) {
switch (ar) {
case 5: return FN5(a1, a2, a3, a4, a5);
case 6: return FN6(fld(0), a1, a2, a3, a4, a5);
case 7: return FN7(fld(0), fld(1), a1, a2, a3, a4, a5);
case 8: return FN8(fld(0), fld(1), fld(2), a1, a2, a3, a4, a5);
default: return mk_closure(*this, a1, a2, a3, a4, a5).apply();
}
} else {
return mk_closure(*this, a1, a2, a3, a4, a5);
}
}
obj obj::apply(obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5, obj const & a6) const {
unsigned ar = arity();
if (ar == size() + 6) {
switch (ar) {
case 6: return FN6(a1, a2, a3, a4, a5, a6);
case 7: return FN7(fld(0), a1, a2, a3, a4, a5, a6);
case 8: return FN8(fld(0), fld(1), a1, a2, a3, a4, a5, a6);
default: return mk_closure(*this, a1, a2, a3, a4, a5, a6).apply();
}
} else {
return mk_closure(*this, a1, a2, a3, a4, a5, a6);
}
}
obj obj::apply(obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5, obj const & a6,
obj const & a7) const {
unsigned ar = arity();
if (ar == size() + 7) {
switch (ar) {
case 7: return FN7(a1, a2, a3, a4, a5, a6, a7);
case 8: return FN8(fld(0), a1, a2, a3, a4, a5, a6, a7);
default: return mk_closure(*this, a1, a2, a3, a4, a5, a6, a7).apply();
}
} else {
return mk_closure(*this, a1, a2, a3, a4, a5, a6, a7);
}
}
obj obj::apply(obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5, obj const & a6,
obj const & a7, obj const & a8) const {
unsigned ar = arity();
if (ar == size() + 8) {
switch (ar) {
case 8: return FN8(a1, a2, a3, a4, a5, a6, a7, a8);
default: return mk_closure(*this, a1, a2, a3, a4, a5, a6, a7, a8).apply();
}
} else {
return mk_closure(*this, a1, a2, a3, a4, a5, a6, a7, a8);
}
}
}

View file

@ -0,0 +1,138 @@
/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "util/thread.h"
#include <vector>
#include <gmp.h>
namespace lean {
class obj;
enum class obj_kind { Constructor, Closure, MPN };
class obj_cell {
atomic<unsigned> m_rc;
unsigned m_kind:2;
unsigned m_size:14;
unsigned m_cidx:16; // constructor idx if Constructor, and arity if closure
bool dec_ref_core() {
if (atomic_fetch_sub_explicit(&m_rc, 1u, memory_order_release) == 1u) {
atomic_thread_fence(memory_order_acquire);
return true;
} else {
return false;
}
}
void dealloc();
obj_cell(unsigned cidx, unsigned sz, obj const * fs);
obj_cell(void * fn, unsigned arity, unsigned sz, obj const * fs);
friend obj mk_obj(unsigned cidx, unsigned n, obj const * fs);
friend obj mk_closure_core(void * fn, unsigned arity, unsigned n, obj const * fs);
void ** field_addr() {
return reinterpret_cast<void **>(reinterpret_cast<char*>(this)+sizeof(obj_cell));
}
void ** fn_ptr_addr() { return field_addr() + m_size; }
void copy_fields(obj_cell const & src);
public:
obj_cell(obj_cell const & src, obj const & a1);
obj_cell(obj_cell const & src, obj const & a1, obj const & a2);
obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3);
obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3, obj const & a4);
obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5);
obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5,
obj const & a6);
obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5,
obj const & a6, obj const & a7);
obj_cell(obj_cell const & src, obj const & a1, obj const & a2, obj const & a3, obj const & a4, obj const & a5,
obj const & a6, obj const & a7, obj const & a8);
unsigned get_rc() const { return atomic_load(&m_rc); }
void inc_ref() { atomic_fetch_add_explicit(&m_rc, 1u, memory_order_relaxed); }
void dec_ref() { if (dec_ref_core()) { dealloc(); } }
obj_kind kind() const { return static_cast<obj_kind>(m_kind); }
size_t cidx() const { return m_cidx; }
unsigned size() const { return m_size; }
unsigned arity() const { return m_cidx; }
obj const * field_ptr() const {
return reinterpret_cast<obj const *>(reinterpret_cast<char const *>(this)+sizeof(obj_cell));
}
void * fn_ptr() const {
return *(reinterpret_cast<void **>(const_cast<obj*>(field_ptr()))+m_size);
}
};
#define LEAN_IS_PTR(obj) ((reinterpret_cast<size_t>(obj) & 1) == 0)
#define LEAN_BOX(num) (reinterpret_cast<obj_cell*>((num << 1) | 1))
#define LEAN_UNBOX(obj) (reinterpret_cast<size_t>(obj) >> 1)
class obj {
friend class obj_cell;
obj_cell * m_data;
void copy_fields(std::vector<obj> & r);
obj apply() const;
obj_cell * steal_ptr() { obj_cell * r = m_data; m_data = LEAN_BOX(0); return r; }
public:
obj():m_data(LEAN_BOX(0)) { static_assert(sizeof(obj) == sizeof(void *), "unexpected class obj size"); }
obj(unsigned cidx):m_data(LEAN_BOX(cidx)) {}
obj(obj_cell * c):m_data(c) { m_data->inc_ref(); }
obj(obj const & o):m_data(o.m_data) { if (LEAN_IS_PTR(m_data)) m_data->inc_ref(); }
obj(obj && o):m_data(o.m_data) { o.m_data = LEAN_BOX(0); }
~obj() { if (LEAN_IS_PTR(m_data)) m_data->dec_ref(); }
obj & operator=(obj const & s) {
if (LEAN_IS_PTR(s.m_data))
s.m_data->inc_ref();
auto new_data = s.m_data;
if (LEAN_IS_PTR(m_data))
m_data->dec_ref();
m_data = new_data;
return *this;
}
obj & operator=(obj && s) {
if (LEAN_IS_PTR(m_data))
m_data->dec_ref();
m_data = s.m_data;
s.m_data = LEAN_BOX(0);
return *this;
}
obj_cell const & data() const { return *m_data; }
size_t cidx() const { return LEAN_IS_PTR(m_data) ? m_data->cidx() : LEAN_UNBOX(m_data); }
unsigned size() const { return m_data->size(); }
obj const & fld(unsigned fidx) const { return m_data->field_ptr()[fidx]; }
obj const & operator[](unsigned fidx) const { return fld(fidx); }
unsigned arity() const { return m_data->arity(); }
void * fn_ptr() const { return m_data->fn_ptr(); }
obj apply(obj const &) const;
obj apply(obj const &, obj const &) const;
obj apply(obj const &, obj const &, obj const &) const;
obj apply(obj const &, obj const &, obj const &, obj const &) const;
obj apply(obj const &, obj const &, obj const &, obj const &, obj const &) const;
obj apply(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &) const;
obj apply(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &) const;
obj apply(obj const &, obj const &, obj const &, obj const &, obj const &, obj const &,
obj const &, obj const &) const;
obj apply(unsigned, obj const *) const;
};
inline obj mk_obj(unsigned cidx) { return obj(cidx); }
obj mk_obj(unsigned cidx, unsigned n, obj const * fs);
inline obj mk_obj(unsigned cidx, obj const & o) { return mk_obj(cidx, 1, &o); }
inline obj mk_obj(unsigned cidx, std::initializer_list<obj> const & os) { return mk_obj(cidx, os.size(), os.begin()); }
obj mk_closure_core(void * fn, unsigned arity, unsigned n, obj const * fs);
template<typename T>
obj mk_closure(T fn, unsigned arity, unsigned n, obj const * fs) {
return mk_closure_core(reinterpret_cast<void*>(fn), arity, n, fs);
}
template<typename T>
obj mk_closure(T fn, unsigned arity, std::initializer_list<obj> const & os) {
return mk_closure_core(reinterpret_cast<void*>(fn), arity, os.size(), os.begin());
}
}