aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--gc.cpp71
-rw-r--r--llvm.cpp54
-rw-r--r--tuplr.cpp5
-rw-r--r--tuplr.hpp112
-rw-r--r--typing.cpp5
6 files changed, 194 insertions, 55 deletions
diff --git a/Makefile b/Makefile
index 83fdfb0..d2fa881 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ LLVM_LDFLAGS=`llvm-config --ldflags --libs core jit native`
CXXFLAGS=-O0 -g -Wall -Wextra -Wno-unused-parameter $(LLVM_CXXFLAGS)
LDFLAGS=$(LLVM_LDFLAGS) -lm
-build/tuplr: build/tuplr.o build/typing.o build/llvm.o build/write.o
+build/tuplr: build/tuplr.o build/typing.o build/llvm.o build/write.o build/gc.o
g++ -o $@ $^ $(LDFLAGS)
build/%.o: %.cpp tuplr.hpp
diff --git a/gc.cpp b/gc.cpp
new file mode 100644
index 0000000..1cfd087
--- /dev/null
+++ b/gc.cpp
@@ -0,0 +1,71 @@
+/* Tuplr: A programming language
+ * Copyright (C) 2008-2009 David Robillard <dave@drobilla.net>
+ *
+ * Tuplr is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * Tuplr is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Tuplr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <set>
+#include <iostream>
+#include "tuplr.hpp"
+
+using namespace std;
+
+void*
+GC::alloc(size_t size)
+{
+ void* ret = malloc(size);
+ _heap.push_back((AST*)ret);
+ return ret;
+}
+
+inline void
+mark(CEnv& cenv, const AST* ast)
+{
+ if (!ast || ast->used)
+ return;
+
+ ast->used = true;
+ const ATuple* tup = ast->to<const ATuple*>();
+ if (tup) {
+ FOREACH(ATuple::const_iterator, i, *tup) {
+ mark(cenv, *i);
+ mark(cenv, cenv.type(*i));
+ }
+ }
+}
+
+void
+GC::collect(CEnv& cenv, const Roots& roots)
+{
+ for (Roots::const_iterator i = roots.begin(); i != roots.end(); ++i)
+ mark(cenv, *i);
+
+ for (Heap::iterator i = _heap.begin(); i != _heap.end();) {
+ Heap::iterator next = i;
+ ++next;
+ if ((*i)->used) {
+ (*i)->used = false;
+ } else {
+ AType* t = (*i)->to<AType*>();
+ // Don't delete types that are keys in the current type substitution
+ if (!t || cenv.tsubst.find(t) == cenv.tsubst.end()) {
+ (*i)->~AST();
+ free(*i);
+ _heap.erase(i);
+ }
+ }
+ i = next;
+ }
+}
+
diff --git a/llvm.cpp b/llvm.cpp
index 9597236..407e8f2 100644
--- a/llvm.cpp
+++ b/llvm.cpp
@@ -165,7 +165,7 @@ compileFunction(CEnv& cenv, const std::string& name, const Type* retT, const ATu
if (f->getName() != name) {
f->eraseFromParent();
- throw Error(loc, "function redefined");
+ throw Error(loc, (format("function `%1%' redefined") % name).str());
}
// Set argument names in generated code
@@ -211,23 +211,22 @@ AClosure::liftCall(CEnv& cenv, const vector<AType*>& argsT)
{
TEnv::GenericTypes::const_iterator gt = cenv.tenv.genericTypes.find(this);
assert(gt != cenv.tenv.genericTypes.end());
- AType* genericType = new AType(*gt->second);
-
- AType* thisType = genericType;
+ AType* thisType = new AType(*gt->second);
Subst argsSubst;
if (!thisType->concrete()) {
- // Find type and build substitution
+ // Build substitution to apply to generic type
assert(argsT.size() == prot()->size());
- ATuple* genericProtT = genericType->at(1)->as<ATuple*>();
+ ATuple* genericProtT = gt->second->at(1)->as<ATuple*>();
for (size_t i = 0; i < argsT.size(); ++i)
- argsSubst[*genericProtT->at(i)->to<AType*>()] = argsT.at(i)->to<AType*>();
- thisType = argsSubst.apply(genericType)->as<AType*>();
+ argsSubst[genericProtT->at(i)->to<AType*>()] = argsT.at(i)->to<AType*>();
+
+ // Apply substitution to get concrete type for this call
+ thisType = argsSubst.apply(thisType)->as<AType*>();
if (!thisType->concrete())
throw Error(loc, "unable to resolve concrete type for function");
- } else {
- thisType = genericType;
}
+ AST::pool.addRoot(thisType);
if (funcs.find(thisType))
return;
@@ -241,7 +240,7 @@ AClosure::liftCall(CEnv& cenv, const vector<AType*>& argsT)
cenv.push();
Subst oldSubst = cenv.tsubst;
- cenv.tsubst = Subst::compose(cenv.tsubst, Subst::compose(argsSubst, *subst));
+ cenv.tsubst = Subst::compose(cenv.tsubst, Subst::compose(argsSubst, subst));
// Bind argument values in CEnv
vector<Value*> args;
@@ -304,15 +303,15 @@ ACall::compile(CEnv& cenv)
if (!c) return NULL; // Primitive
- AType* protT = new AType(loc, NULL);
+ AType protT(loc, NULL);
for (size_t i = 1; i < size(); ++i)
- protT->push_back(cenv.type(at(i)));
+ protT.push_back(cenv.type(at(i)));
TEnv::GenericTypes::const_iterator gt = cenv.tenv.genericTypes.find(c);
assert(gt != cenv.tenv.genericTypes.end());
- AType* fnT = new AType(loc, cenv.penv.sym("Fn"), protT, cenv.type(this), 0);
- Function* f = (Function*)c->funcs.find(fnT);
- THROW_IF(!f, loc, (format("callee failed to compile for type %1%") % fnT->str()).str())
+ AType fnT(loc, cenv.penv.sym("Fn"), &protT, cenv.type(this), 0);
+ Function* f = (Function*)c->funcs.find(&fnT);
+ THROW_IF(!f, loc, (format("callee failed to compile for type %1%") % fnT.str()).str())
vector<Value*> params(size() - 1);
for (size_t i = 1; i < size(); ++i)
@@ -557,6 +556,10 @@ eval(CEnv& cenv, const string& name, istream& is)
resultType = cenv.type(result);
result->lift(cenv); // Lift functions
exprs.push_back(make_pair(exp, result));
+
+ // Add definitions as GC roots
+ if (result->to<ADefinition*>())
+ cenv.lock(result);
}
const Type* ctype = lltype(resultType);
@@ -576,6 +579,9 @@ eval(CEnv& cenv, const string& name, istream& is)
cenv.out << call(resultType, llengine(cenv)->engine->getPointerToFunction(f))
<< " : " << resultType << endl;
+
+ AST::pool.collect(cenv, AST::pool.roots());
+
} catch (Error& e) {
cenv.err << e.what() << endl;
return 1;
@@ -624,7 +630,15 @@ repl(CEnv& cenv)
cenv.out << "; " << cenv.compile(body);
}
cenv.out << " : " << cenv.type(body) << endl;
+
+ // Add definitions as GC roots
+ if (body->to<ADefinition*>())
+ cenv.lock(body);
+
+ AST::pool.collect(cenv, AST::pool.roots());
+
cenv.tsubst = oldSubst;
+
} catch (Error& e) {
cenv.err << e.what() << endl;
}
@@ -646,3 +660,11 @@ newCenv(PEnv& penv, TEnv& tenv)
return cenv;
}
+void
+freeCenv(CEnv* cenv)
+{
+ AST::pool.collect(*cenv, GC::Roots());
+ delete (LLVMEngine*)cenv->engine();
+ delete cenv;
+}
+
diff --git a/tuplr.cpp b/tuplr.cpp
index 10233f9..6321a5c 100644
--- a/tuplr.cpp
+++ b/tuplr.cpp
@@ -27,6 +27,7 @@ using namespace std;
using boost::format;
Funcs AConsCall::funcs;
+GC AST::pool;
template<typename Atom>
ostream&
@@ -228,6 +229,7 @@ initLang(PEnv& penv, TEnv& tenv)
}
+
/***************************************************************************
* EVAL/REPL/MAIN *
***************************************************************************/
@@ -256,6 +258,7 @@ main(int argc, char** argv)
CEnv* cenv = newCenv(penv, tenv);
cenv->push();
+ AST::pool.lock();
map<string,string> args;
list<string> files;
@@ -326,7 +329,7 @@ main(int argc, char** argv)
os.close();
}
- delete cenv;
+ freeCenv(cenv);
return ret;
}
diff --git a/tuplr.hpp b/tuplr.hpp
index 025dd55..2c906d6 100644
--- a/tuplr.hpp
+++ b/tuplr.hpp
@@ -22,6 +22,7 @@
#include <iostream>
#include <list>
#include <map>
+#include <set>
#include <sstream>
#include <string>
#include <vector>
@@ -134,13 +135,33 @@ typedef void* CEngine; ///< Compiler Engine (opaque)
/***************************************************************************
+ * Garbage Collector *
+ ***************************************************************************/
+
+struct AST; ///< Abstract Syntax Tree node
+struct CEnv; ///< Compile-Time Environment
+
+extern ostream& operator<<(ostream& out, const AST* ast);
+struct GC {
+ typedef std::list<const AST*> Roots;
+ typedef std::list<AST*> Heap;
+ void* alloc(size_t size);
+ void collect(CEnv& cenv, const Roots& roots);
+ const AST* addRoot(const AST* ast) { if (ast) { cout << "ADD ROOT " << ast << endl; _roots.push_back(ast); } return ast; }
+ void lock() { _roots.insert(_roots.end(), _heap.begin(), _heap.end()); }
+ const Roots& roots() const { return _roots; }
+private:
+ Heap _heap;
+ Roots _roots;
+};
+
+
+/***************************************************************************
* Abstract Syntax Tree *
***************************************************************************/
struct Constraint; ///< Type Constraint
struct TEnv; ///< Type-Time Environment
-struct CEnv; ///< Compile-Time Environment
-struct AST;
struct Constraints;
struct Subst;
@@ -148,7 +169,7 @@ extern ostream& operator<<(ostream& out, const AST* ast);
/// Base class for all AST nodes
struct AST {
- AST(Cursor c=Cursor()) : loc(c) {}
+ AST(Cursor c=Cursor()) : loc(c), used(false) {}
virtual ~AST() {}
virtual bool operator==(const AST& o) const = 0;
virtual bool contains(const AST* child) const { return false; }
@@ -163,7 +184,13 @@ struct AST {
if (!t) throw Error(loc, "internal error: bad cast");
return t;
}
- Cursor loc;
+ Cursor loc;
+ mutable bool used;
+
+ static void* operator new(size_t size) { return pool.alloc(size); }
+ static void operator delete(void* ptr) {}
+
+ static GC pool;
};
/// Literal value
@@ -202,6 +229,10 @@ struct ATuple : public AST, public vector<AST*> {
push_back(a);
va_end(args);
}
+ void free() {
+ FOREACH(const_iterator, p, *this)
+ delete *p;
+ }
bool operator==(const AST& rhs) const {
const ATuple* rt = rhs.to<const ATuple*>();
if (!rt || rt->size() != size()) return false;
@@ -283,6 +314,33 @@ struct AType : public ATuple {
unsigned id;
};
+struct typeLessThan {
+ inline bool operator()(const AType* a, const AType* b) const { return *a < *b; }
+};
+
+/// Type substitution
+struct Subst : public map<const AType*,AType*,typeLessThan> {
+ Subst(AType* s=0, AType* t=0) { if (s && t) { assert(s != t); insert(make_pair(s, t)); } }
+ static Subst compose(const Subst& delta, const Subst& gamma);
+ AST* apply(AST* ast) const {
+ AType* in = ast->to<AType*>();
+ if (!in) return ast;
+ if (in->kind == AType::EXPR) {
+ AType* out = new AType(in->loc, NULL);
+ for (size_t i = 0; i < in->size(); ++i)
+ out->push_back(apply(in->at(i)));
+ return out;
+ } else {
+ const_iterator i = find(in);
+ if (i != end()) {
+ return i->second;
+ } else {
+ return in;
+ }
+ }
+ }
+};
+
/// Lifted system functions (of various types) for a single Tuplr function
struct Funcs : public list< pair<AType*, CFunction> > {
CFunction find(AType* type) const {
@@ -296,16 +354,16 @@ struct Funcs : public list< pair<AType*, CFunction> > {
/// Closure (first-class function with captured lexical bindings)
struct AClosure : public ATuple {
AClosure(Cursor c, ASymbol* fn, ATuple* p, const string& n="")
- : ATuple(c, fn, p, NULL), subst(0), name(n) {}
+ : ATuple(c, fn, p, NULL), name(n) {}
bool operator==(const AST& rhs) const { return this == &rhs; }
void constrain(TEnv& tenv, Constraints& c) const;
void lift(CEnv& cenv);
void liftCall(CEnv& cenv, const vector<AType*>& argsT);
CValue compile(CEnv& cenv);
ATuple* prot() const { return at(1)->to<ATuple*>(); }
- Funcs funcs;
- mutable Subst* subst;
- string name;
+ Funcs funcs;
+ mutable Subst subst;
+ string name;
};
/// Function call/application, e.g. "(func arg1 arg2)"
@@ -319,7 +377,7 @@ struct ACall : public ATuple {
/// Definition special form, e.g. "(def x 2)"
struct ADefinition : public ACall {
ADefinition(const SExp& e, const ATuple& t) : ACall(e, t) {}
- ASymbol* sym() const {
+ ASymbol* sym() const {
ASymbol* sym = at(1)->to<ASymbol*>();
if (!sym) {
ATuple* tup = at(1)->to<ATuple*>();
@@ -401,9 +459,13 @@ struct PEnv : private map<const string, ASymbol*> {
}
ASymbol* sym(const string& s, Cursor c=Cursor()) {
const const_iterator i = find(s);
- return ((i != end())
- ? i->second
- : insert(make_pair(s, new ASymbol(s, c))).first->second);
+ if (i != end()) {
+ return i->second;
+ } else {
+ ASymbol* sym = new ASymbol(s, c);
+ insert(make_pair(s, sym));
+ return sym;
+ }
}
ATuple parseTuple(const SExp& e) {
ATuple ret(e.loc, vector<AST*>(e.size()));
@@ -458,28 +520,6 @@ inline ostream& operator<<(ostream& out, const Constraints& c) {
return out;
}
-struct Subst : public map<const AType,AType*> {
- Subst(AType* s=0, AType* t=0) { if (s && t) { assert(s != t); insert(make_pair(*s, t)); } }
- static Subst compose(const Subst& delta, const Subst& gamma);
- AST* apply(AST* ast) const {
- AType* in = ast->to<AType*>();
- if (!in) return ast;
- if (in->kind == AType::EXPR) {
- AType* out = new AType(in->loc, NULL);
- for (size_t i = 0; i < in->size(); ++i)
- out->push_back(apply(in->at(i)));
- return out;
- } else {
- const_iterator i = find(*in);
- if (i != end()) {
- return i->second;
- } else {
- return in;
- }
- }
- }
-};
-
/// Type-Time Environment
struct TEnv : public Env< const ASymbol*, pair<AST*, AType*> > {
TEnv(PEnv& p) : penv(p), varID(1) {}
@@ -542,10 +582,11 @@ struct CEnv {
CValue compile(AST* obj);
void optimise(CFunction f);
void write(std::ostream& os);
+ void lock(AST* ast) { AST::pool.addRoot(ast); AST::pool.addRoot(type(ast)); }
AType* type(AST* ast, const Subst& subst = Subst()) const {
ASymbol* sym = ast->to<ASymbol*>();
if (sym)
- return tenv.deref(sym->addr).second;
+ return sym->addr ? tenv.deref(sym->addr).second : NULL;
return tsubst.apply(subst.apply(tenv.vars[ast]))->to<AType*>();
}
void def(ASymbol* sym, AST* c, AType* t, CValue v) {
@@ -576,6 +617,7 @@ private:
void pprint(std::ostream& out, const AST* ast);
void initLang(PEnv& penv, TEnv& tenv);
CEnv* newCenv(PEnv& penv, TEnv& tenv);
+void freeCenv(CEnv* cenv);
int eval(CEnv& cenv, const string& name, istream& is);
int repl(CEnv& cenv);
diff --git a/typing.cpp b/typing.cpp
index 8487001..fd8e35e 100644
--- a/typing.cpp
+++ b/typing.cpp
@@ -108,9 +108,10 @@ AClosure::constrain(TEnv& tenv, Constraints& c) const
genericType = new AType(loc, tenv.penv.sym("Fn"),
tsubst.apply(protT), tsubst.apply(bodyT), 0);
tenv.genericTypes.insert(make_pair(this, genericType));
+ AST::pool.addRoot(genericType);
tenv.pop();
- subst = new Subst(tsubst);
+ subst = tsubst;
}
c.constrain(tenv, this, new AType(*genericType));
@@ -283,7 +284,7 @@ Subst::compose(const Subst& delta, const Subst& gamma) // TAPL 22.1.1
{
Subst r;
for (Subst::const_iterator g = gamma.begin(); g != gamma.end(); ++g) {
- Subst::const_iterator d = delta.find(*g->second);
+ Subst::const_iterator d = delta.find(g->second);
r.insert(make_pair(g->first, ((d != delta.end()) ? d : g)->second));
}
for (Subst::const_iterator d = delta.begin(); d != delta.end(); ++d) {