[pure-lang-svn] SF.net SVN: pure-lang: [107] pure/trunk
Status: Beta
Brought to you by:
agraef
From: <ag...@us...> - 2008-05-23 01:15:03
|
Revision: 107 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=107&view=rev Author: agraef Date: 2008-05-22 18:15:11 -0700 (Thu, 22 May 2008) Log Message: ----------- Fix segfaults caused by closures being called after their environments and LLVM IR was freed. Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/interpreter.cc pure/trunk/interpreter.hh Added Paths: ----------- pure/trunk/test/test10.log pure/trunk/test/test10.pure Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-05-22 14:42:19 UTC (rev 106) +++ pure/trunk/ChangeLog 2008-05-23 01:15:11 UTC (rev 107) @@ -1,3 +1,21 @@ +2008-05-23 Albert Graef <Dr....@t-...> + + * interpreter.cc: If there are any child environments, doeval and + dodefn both create semi-permanent environments now, so that the + child environments and the corresponding LLVM IR survive for the + entire lifetime of any embedded closures, which might still be + called at a later time. This fixes the segfaults occurring when a + closure gets called after its associated environment was purged. A + partial fix for some situations (as reported earlier by Chris + Double) was already in the 0.2 release, but this didn't deal with + all cases, such as closures constructed in a call to the eval + function, as reported by Eddie Rucker. + + TODO: The current solution leaks memory, as the doeval/dodefn + environments aren't reclaimed any more. This still needs to be + fixed, by counting references on the global ancestor environments + of each closure constructed in doeval and dodefn. + 2008-05-22 Albert Graef <Dr....@t-...> * interpreter.cc, runtime.cc: Major overhaul of expression memory Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-05-22 14:42:19 UTC (rev 106) +++ pure/trunk/interpreter.cc 2008-05-23 01:15:11 UTC (rev 107) @@ -787,7 +787,6 @@ // 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); @@ -1554,8 +1553,7 @@ 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); @@ -1575,15 +1573,6 @@ 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) { @@ -2569,8 +2558,7 @@ (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); @@ -2597,7 +2585,13 @@ } // Create an anonymous function to call in order to evaluate the target // expression. - Env f(0, 0, x, false); + /* NOTE: The environment is allocated dynamically, so that its child + environments survive for the entire lifetime of any embedded closures, + which might still be called at a later time. XXXFIXME: This leaks memory + right now. How do we keep track of environments that might still be + needed? */ + Env *fptr = new Env(0, 0, x, false); + Env &f = *fptr; push("doeval", &f); fun_prolog(""); #if DEBUG>1 @@ -2618,6 +2612,8 @@ // Get rid of our anonymous function. JIT->freeMachineCodeForFunction(f.f); f.f->eraseFromParent(); + // If there are no child envs, we can get rid of the environment now. + if (f.fmap[0].empty()) delete fptr; // NOTE: Result (if any) is to be freed by the caller. return res; } @@ -2631,10 +2627,6 @@ } // Create an anonymous function to call in order to evaluate the rhs // expression, match against the lhs and bind variables in lhs accordingly. - /* 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); @@ -2673,9 +2665,7 @@ 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 @@ -2703,13 +2693,14 @@ // Get rid of our anonymous function. JIT->freeMachineCodeForFunction(f.f); f.f->eraseFromParent(); + // If there are no child envs, we can get rid of the environment now. + if (f.fmap[0].empty()) delete fptr; if (!res) { // We caught an exception, clean up the mess. for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) { 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); @@ -3407,8 +3398,7 @@ (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-22 14:42:19 UTC (rev 106) +++ pure/trunk/interpreter.hh 2008-05-23 01:15:11 UTC (rev 107) @@ -69,9 +69,7 @@ // global variable llvm::GlobalVariable* v; pure_expr *x; - Env *e; - GlobalVar() { v = 0; x = 0; e = 0; } - void clear(); + GlobalVar() { v = 0; x = 0; } }; struct VarInfo { @@ -133,7 +131,7 @@ Builder builder; // parent environment (if any) Env *parent; - // reference counter (for dodefn) + // reference counter (currently unused) uint32_t refc; // convenience functions for invoking CreateGEP() and CreateLoad() llvm::Value *CreateGEP Added: pure/trunk/test/test10.log =================================================================== --- pure/trunk/test/test10.log (rev 0) +++ pure/trunk/test/test10.log 2008-05-23 01:15:11 UTC (rev 107) @@ -0,0 +1,3 @@ +\x -> x!0==[0,1,0,0]; +eval "(\\x -> (x!0) == [0,1,0,0])" [[0,1,0,0],[1,1,2]]; +1 Added: pure/trunk/test/test10.pure =================================================================== --- pure/trunk/test/test10.pure (rev 0) +++ pure/trunk/test/test10.pure 2008-05-23 01:15:11 UTC (rev 107) @@ -0,0 +1,2 @@ + +eval "(\\x -> (x!0) == [0,1,0,0])" [[0,1,0,0],[1,1,2]]; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |