[pure-lang-svn] SF.net SVN: pure-lang: [20] pure/trunk
Status: Beta
Brought to you by:
agraef
From: <ag...@us...> - 2008-05-02 03:55:10
|
Revision: 20 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=20&view=rev Author: agraef Date: 2008-05-01 20:55:18 -0700 (Thu, 01 May 2008) Log Message: ----------- Fix premature deallocation of closures bound in variable definitions. Modified Paths: -------------- pure/trunk/interpreter.cc pure/trunk/interpreter.hh pure/trunk/runtime.cc Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-05-01 15:29:39 UTC (rev 19) +++ pure/trunk/interpreter.cc 2008-05-02 03:55:18 UTC (rev 20) @@ -721,6 +721,7 @@ // patch up the global variable table to replace it with a cbox. map<int32_t,GlobalVar>::iterator v = globalvars.find(f); if (v != globalvars.end()) { + v->second.clear(); pure_expr *cv = pure_const(f); if (v->second.x) pure_free(v->second.x); v->second.x = pure_new(cv); @@ -1480,7 +1481,8 @@ v.v = new GlobalVariable (ExprPtrTy, false, GlobalVariable::ExternalLinkage, 0, sym.s, module); JIT->addGlobalMapping(v.v, &v.x); - } + } else + v.clear(); if (v.x) pure_free(v.x); v.x = pure_new(x); environ[tag] = env_info(&v.x, temp); restore_globals(g); @@ -1500,6 +1502,15 @@ return os << ")"; } +void GlobalVar::clear() +{ + if (e) { + assert(e->refc > 0); + if (--e->refc == 0) delete e; + e = 0; + } +} + Env& Env::operator= (const Env& e) { if (f) { @@ -1524,17 +1535,28 @@ interpreter& interp = *interpreter::g_interp; if (local) { // purge local functions +#if DEBUG>2 + llvm::cerr << "clearing local '" << name << "'\n"; +#endif + if (h != f) interp.JIT->freeMachineCodeForFunction(h); + interp.JIT->freeMachineCodeForFunction(f); f->dropAllReferences(); if (h != f) h->dropAllReferences(); + fp = 0; fmap.clear(); - interp.JIT->freeMachineCodeForFunction(f); - if (h != f) interp.JIT->freeMachineCodeForFunction(h); - fp = 0; to_be_deleted.push_back(f); if (h != f) to_be_deleted.push_back(h); } else { - // only delete the body, this keeps existing references intact - f->deleteBody(); - interp.JIT->freeMachineCodeForFunction(f); - if (h != f) interp.JIT->freeMachineCodeForFunction(h); +#if DEBUG>2 + llvm::cerr << "clearing global '" << name << "'\n"; +#endif + // The code of anonymous globals (doeval, dodefn) is taken care of + // elsewhere, we must not collect that here. + if (!name.empty()) { + // named global, get rid of the machine code + if (h != f) interp.JIT->freeMachineCodeForFunction(h); + interp.JIT->freeMachineCodeForFunction(f); + // only delete the body, this keeps existing references intact + f->deleteBody(); + } fp = 0; // delete all nested environments and reinitialize other body-related data fmap.clear(); xmap.clear(); xtab.clear(); prop.clear(); m = 0; argv = 0; @@ -2454,7 +2476,8 @@ (ExprPtrTy, false, GlobalVariable::InternalLinkage, 0, mkvarlabel(sym.f), module); JIT->addGlobalMapping(v.v, &v.x); - } + } else + v.clear(); if (v.x) pure_free(v.x); v.x = pure_new(cv); Value *defaultv = b.CreateLoad(v.v); vector<Value*> myargs(2); @@ -2522,6 +2545,7 @@ pure_expr *res = pure_invoke(f.fp, e); if (interactive && stats) clocks = clock()-t0; // Get rid of our anonymous function. + JIT->freeMachineCodeForFunction(f.f); f.f->eraseFromParent(); // NOTE: Result (if any) is to be freed by the caller. return res; @@ -2536,7 +2560,12 @@ } // Create an anonymous function to call in order to evaluate the rhs // expression, match against the lhs and bind variables in lhs accordingly. - Env f(0, 0, rhs, false); + /* NOTE: Unlike doeval(), we must create a semi-permanent environment here + whose child environments persist for the entire lifetime of the variables + bound in this definition, since some of those bindings may refer to + closures (executable code) that might still be called some time. */ + Env *fptr = new Env(0, 0, rhs, false); + Env &f = *fptr; push("dodefn", &f); fun_prolog(""); #if DEBUG>1 @@ -2573,9 +2602,16 @@ v.v = new GlobalVariable (ExprPtrTy, false, GlobalVariable::ExternalLinkage, 0, sym.s, module); JIT->addGlobalMapping(v.v, &v.x); - } + } else + v.clear(); + v.e = fptr; f.refc++; if (v.x) call("pure_free", f.builder.CreateLoad(v.v)); call("pure_new", x); +#if DEBUG>2 + ostringstream msg; + msg << "dodef: " << sym.s << " := %p"; + debug(msg.str().c_str(), x); +#endif f.builder.CreateStore(x, v.v); } // return the matchee to indicate success @@ -2594,6 +2630,7 @@ pure_expr *res = pure_invoke(f.fp, e); if (interactive && stats) clocks = clock()-t0; // Get rid of our anonymous function. + JIT->freeMachineCodeForFunction(f.f); f.f->eraseFromParent(); if (!res) { // We caught an exception, clean up the mess. @@ -2601,6 +2638,7 @@ int32_t tag = it->first; GlobalVar& v = globalvars[tag]; if (!v.x) { + v.clear(); JIT->updateGlobalMapping(v.v, 0); v.v->eraseFromParent(); globalvars.erase(tag); @@ -3288,7 +3326,8 @@ (ExprPtrTy, false, GlobalVariable::InternalLinkage, 0, mkvarlabel(tag), module); JIT->addGlobalMapping(v.v, &v.x); - } + } else + v.clear(); if (v.x) pure_free(v.x); v.x = pure_new(cv); return act_builder().CreateLoad(v.v); } Modified: pure/trunk/interpreter.hh =================================================================== --- pure/trunk/interpreter.hh 2008-05-01 15:29:39 UTC (rev 19) +++ pure/trunk/interpreter.hh 2008-05-02 03:55:18 UTC (rev 20) @@ -63,15 +63,17 @@ /* Data structures used in code generation. */ +struct Env; + struct GlobalVar { // global variable llvm::GlobalVariable* v; pure_expr *x; - GlobalVar() { v = 0; x = 0; } + Env *e; + GlobalVar() { v = 0; x = 0; e = 0; } + void clear(); }; -struct Env; - struct VarInfo { // info about captured variable uint32_t v; // local proxy (offset into extra parameter block) @@ -85,7 +87,6 @@ //#define Builder llvm::LLVMBuilder #define Builder llvm::LLVMFoldingBuilder -struct Env; typedef list<Env*> EnvStack; typedef pair<int32_t,uint8_t> xmap_key; @@ -126,6 +127,8 @@ Builder builder; // parent environment (if any) Env *parent; + // reference counter (for dodefn) + uint32_t refc; // convenience functions for invoking CreateGEP() and CreateLoad() llvm::Value *CreateGEP (llvm::Value *x, llvm::Value *i, const char* name = "") @@ -158,11 +161,11 @@ // default constructor Env() : tag(0), n(0), m(0), l(0), f(0), h(0), fp(0), args(0), envs(0), argv(0), - b(false), local(false), parent(0) {} + b(false), local(false), parent(0), refc(0) {} // environment for an anonymous closure with given body x Env(int32_t _tag, uint32_t _n, expr x, bool _b, bool _local = false) : tag(_tag), n(_n), m(0), l(0), f(0), h(0), fp(0), args(n), envs(0), - argv(0), b(_b), local(_local), parent(0) + argv(0), b(_b), local(_local), parent(0), refc(0) { if (envstk.empty()) { assert(!local); @@ -176,7 +179,7 @@ // environment for a named closure with given definition info Env(int32_t _tag, const env_info& info, bool _b, bool _local = false) : tag(_tag), n(info.argc), m(0), l(0), f(0), h(0), fp(0), args(n), envs(0), - argv(0), b(_b), local(_local), parent(0) + argv(0), b(_b), local(_local), parent(0), refc(0) { if (envstk.empty()) { assert(!local); Modified: pure/trunk/runtime.cc =================================================================== --- pure/trunk/runtime.cc 2008-05-01 15:29:39 UTC (rev 19) +++ pure/trunk/runtime.cc 2008-05-02 03:55:18 UTC (rev 20) @@ -378,8 +378,16 @@ // parameterless call checkstk(test); return ((pure_expr*(*)())fp)(); - } else + } else { +#if DEBUG>2 + if (x->tag >= 0 && x->data.clos) + cerr << "pure_call: returning " << x << " -> " << x->data.clos->fp + << " (" << x->data.clos->n << " args)" << endl; + else + cerr << "pure_call: returning " << x << endl; +#endif return x; + } } extern "C" @@ -534,6 +542,9 @@ // Cast the function pointer to the right type (takes no arguments, returns // a pure_expr*), so we can call it as a native function. pure_expr *(*fp)() = (pure_expr*(*)())f; +#if DEBUG>1 + cerr << "pure_invoke: calling " << f << endl; +#endif // Push an exception. pure_exception ex; ex.e = 0; interp.estk.push_front(ex); // Call the function now. Catch exceptions generated by the runtime. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |