Mercurial > projects > ldc
changeset 209:c4c9b4ac021b trunk
[svn r225] Fixed: delete expressions no longer use llvm's free instruction, which crashes on a GC provided pointer.
author | lindquist |
---|---|
date | Wed, 14 May 2008 01:22:40 +0200 |
parents | 086e1aa99557 |
children | 1d6cfdbc97f0 |
files | gen/classes.cpp gen/classes.h gen/runtime.cpp gen/toir.cpp gen/tollvm.cpp gen/tollvm.h llvmdc.kdevelop.filelist tango/lib/compiler/llvmdc/lifetime.d tangotests/mem2.d tangotests/mem3.d tangotests/mem4.d tangotests/mem5.d |
diffstat | 12 files changed, 242 insertions(+), 146 deletions(-) [+] |
line wrap: on
line diff
--- a/gen/classes.cpp Tue May 13 21:41:25 2008 +0200 +++ b/gen/classes.cpp Wed May 14 01:22:40 2008 +0200 @@ -932,6 +932,19 @@ ////////////////////////////////////////////////////////////////////////////////////////// +void DtoFinalizeClass(llvm::Value* inst) +{ + // get runtime function + llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_callfinalizer"); + // build args + llvm::SmallVector<llvm::Value*,1> arg; + arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp")); + // call + llvm::CallInst::Create(fn, arg.begin(), arg.end(), "", gIR->scopebb()); +} + +////////////////////////////////////////////////////////////////////////////////////////// + DValue* DtoCastClass(DValue* val, Type* _to) { Logger::println("DtoCastClass(%s, %s)", val->getType()->toChars(), _to->toChars());
--- a/gen/classes.h Tue May 13 21:41:25 2008 +0200 +++ b/gen/classes.h Wed May 14 01:22:40 2008 +0200 @@ -28,6 +28,7 @@ void DtoInitClass(TypeClass* tc, llvm::Value* dst); DValue* DtoCallClassCtor(TypeClass* type, CtorDeclaration* ctor, Array* arguments, llvm::Value* mem); void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance); +void DtoFinalizeClass(llvm::Value* inst); DValue* DtoCastClass(DValue* val, Type* to); DValue* DtoDynamicCastObject(DValue* val, Type* to);
--- a/gen/runtime.cpp Tue May 13 21:41:25 2008 +0200 +++ b/gen/runtime.cpp Wed May 14 01:22:40 2008 +0200 @@ -283,6 +283,40 @@ llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); } + // void _d_delarray(size_t plength, void* pdata) + { + std::string fname("_d_delarray"); + std::vector<const llvm::Type*> types; + types.push_back(sizeTy); + types.push_back(voidPtrTy); + const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); + } + + // void _d_delmemory(void* p) + // void _d_delinterface(void* p) + // void _d_callfinalizer(void* p) + { + std::string fname("_d_delmemory"); + std::string fname2("_d_delinterface"); + std::string fname3("_d_callfinalizer"); + std::vector<const llvm::Type*> types; + types.push_back(voidPtrTy); + const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname3, M); + } + + // void _d_delclass(Object p) + { + std::string fname("_d_delclass"); + std::vector<const llvm::Type*> types; + types.push_back(objectTy); + const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); + } + ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
--- a/gen/toir.cpp Tue May 13 21:41:25 2008 +0200 +++ b/gen/toir.cpp Wed May 14 01:22:40 2008 +0200 @@ -1984,66 +1984,6 @@ return new DImValue(type, mem, false); } - /* - - const llvm::Type* t = DtoType(ntype); - - llvm::Value* emem = 0; - bool inplace = false; - - if (ntype->ty == Tarray) { - assert(arguments); - if (arguments->dim == 1) { - DValue* sz = ((Expression*)arguments->data[0])->toElem(p); - llvm::Value* dimval = sz->getRVal(); - Type* nnt = DtoDType(ntype->next); - if (nnt->ty == Tvoid) - nnt = Type::tint8; - - if (p->topexp() && p->topexp()->e2 == this) { - assert(p->topexp()->v); - emem = p->topexp()->v->getLVal(); - DtoNewDynArray(emem, dimval, nnt); - inplace = true; - } - else { - const llvm::Type* restype = DtoType(type); - Logger::cout() << "restype = " << *restype << '\n'; - emem = new llvm::AllocaInst(restype,"newstorage",p->topallocapoint()); - DtoNewDynArray(emem, dimval, nnt); - return new DVarValue(newtype, emem, true); - } - } - else { - assert(0 && "num args to 'new' != 1"); - } - } - // simple new of a single non-class, non-array value - else { - // get runtime function - llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_allocmemoryT"); - // get type info - llvm::Constant* ti = DtoTypeInfoOf(newtype); - assert(isaPointer(ti)); - // call runtime - llvm::SmallVector<llvm::Value*,1> arg; - arg.push_back(ti); - emem = p->ir->CreateCall(fn, arg.begin(), arg.end(), ".gc_mem"); - } - - if (ntype->ty == Tstruct) { - TypeStruct* ts = (TypeStruct*)ntype; - if (ts->isZeroInit()) { - DtoStructZeroInit(emem); - } - else { - assert(ts->sym); - DtoStructCopy(emem,ts->sym->ir.irStruct->init); - } - } - - return new DImValue(type, emem, inplace); - */ assert(0); } @@ -2054,55 +1994,54 @@ Logger::print("DeleteExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - //assert(e1->type->ty != Tclass); - - DValue* v = e1->toElem(p); - const llvm::Type* t = DtoType(v->getType()); - llvm::Value* ldval = 0; - llvm::Constant* z = llvm::Constant::getNullValue(t); - - Type* e1type = DtoDType(e1->type); - - if (e1type->ty == Tpointer) { - llvm::Value* val = v->getRVal(); - Logger::cout() << *z << '\n'; - Logger::cout() << *val << '\n'; - new llvm::FreeInst(val, p->scopebb()); - new llvm::StoreInst(z, v->getLVal(), p->scopebb()); + DValue* dval = e1->toElem(p); + Type* et = DtoDType(e1->type); + + // simple pointer + if (et->ty == Tpointer) + { + llvm::Value* rval = dval->getRVal(); + DtoDeleteMemory(rval); + if (dval->isVar() && dval->isVar()->lval) + DtoStore(llvm::Constant::getNullValue(rval->getType()), dval->getLVal()); } - else if (e1type->ty == Tclass) { - TypeClass* tc = (TypeClass*)e1type; - llvm::Value* val = 0; - if (tc->sym->dtors.dim > 0) { - val = v->getRVal(); - DtoCallClassDtors(tc, val); - } - - if (DVarValue* vv = v->isVar()) { - if (vv->var && !vv->var->onstack) { - if (!val) val = v->getRVal(); - new llvm::FreeInst(val, p->scopebb()); + // class + else if (et->ty == Tclass) + { + bool onstack = false; + if (DVarValue* vv = dval->isVar()) { + if (vv->var && vv->var->onstack) { + TypeClass* tc = (TypeClass*)et; + if (tc->sym->dtors.dim > 0) { + DtoFinalizeClass(dval->getRVal()); + onstack = true; + } } } - if (!v->isThis()) - new llvm::StoreInst(z, v->getLVal(), p->scopebb()); + if (!onstack) { + llvm::Value* rval = dval->getRVal(); + DtoDeleteClass(rval); + } + if (dval->isVar() && dval->isVar()->lval) { + llvm::Value* lval = dval->getLVal(); + DtoStore(llvm::Constant::getNullValue(lval->getType()->getContainedType(0)), lval); + } } - else if (e1type->ty == Tarray) { - // must be on the heap (correct?) - llvm::Value* val = v->getRVal(); - llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); - llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); - llvm::Value* ptr = DtoGEP(val,zero,one,"tmp",p->scopebb()); - ptr = new llvm::LoadInst(ptr,"tmp",p->scopebb()); - new llvm::FreeInst(ptr, p->scopebb()); - DtoSetArrayToNull(val); + // dyn array + else if (et->ty == Tarray) + { + DtoDeleteArray(dval); + if (!dval->isSlice()) + DtoSetArrayToNull(dval->getRVal()); } - else { - assert(0); + // unknown/invalid + else + { + assert(0 && "invalid delete"); } - // this expression produces no useful data - return 0; + // no value to return + return NULL; } //////////////////////////////////////////////////////////////////////////////////////////
--- a/gen/tollvm.cpp Tue May 13 21:41:25 2008 +0200 +++ b/gen/tollvm.cpp Wed May 14 01:22:40 2008 +0200 @@ -703,6 +703,40 @@ return DtoBitCast(mem, getPtrToType(DtoType(newtype)), ".gc_mem"); } +void DtoDeleteMemory(llvm::Value* ptr) +{ + // get runtime function + llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delmemory"); + // build args + llvm::SmallVector<llvm::Value*,1> arg; + arg.push_back(DtoBitCast(ptr, getVoidPtrType(), ".tmp")); + // call + llvm::CallInst::Create(fn, arg.begin(), arg.end(), "", gIR->scopebb()); +} + +void DtoDeleteClass(llvm::Value* inst) +{ + // get runtime function + llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delclass"); + // build args + llvm::SmallVector<llvm::Value*,1> arg; + arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp")); + // call + llvm::CallInst::Create(fn, arg.begin(), arg.end(), "", gIR->scopebb()); +} + +void DtoDeleteArray(DValue* arr) +{ + // get runtime function + llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delarray"); + // build args + llvm::SmallVector<llvm::Value*,2> arg; + arg.push_back(DtoArrayLen(arr)); + arg.push_back(DtoBitCast(DtoArrayPtr(arr), getVoidPtrType(), ".tmp")); + // call + llvm::CallInst::Create(fn, arg.begin(), arg.end(), "", gIR->scopebb()); +} + ////////////////////////////////////////////////////////////////////////////////////////// void DtoAssert(Loc* loc, DValue* msg)
--- a/gen/tollvm.h Tue May 13 21:41:25 2008 +0200 +++ b/gen/tollvm.h Wed May 14 01:22:40 2008 +0200 @@ -61,6 +61,9 @@ // dynamic memory helpers llvm::Value* DtoNew(Type* newtype); +void DtoDeleteMemory(llvm::Value* ptr); +void DtoDeleteClass(llvm::Value* inst); +void DtoDeleteArray(DValue* arr); // assertion generator void DtoAssert(Loc* loc, DValue* msg);
--- a/llvmdc.kdevelop.filelist Tue May 13 21:41:25 2008 +0200 +++ b/llvmdc.kdevelop.filelist Wed May 14 01:22:40 2008 +0200 @@ -760,6 +760,10 @@ tangotests/k.d tangotests/l.d tangotests/m.d +tangotests/mem2.d +tangotests/mem3.d +tangotests/mem4.d +tangotests/mem5.d tangotests/n.d tangotests/o.d tangotests/r.d
--- a/tango/lib/compiler/llvmdc/lifetime.d Tue May 13 21:41:25 2008 +0200 +++ b/tango/lib/compiler/llvmdc/lifetime.d Wed May 14 01:22:40 2008 +0200 @@ -131,64 +131,60 @@ return cast(Object) p; } -/+ - /** * */ -extern (C) void _d_delinterface(void** p) +extern (C) void _d_delinterface(void* p) { - if (*p) + if (p) { - Interface* pi = **cast(Interface ***)*p; - Object o = cast(Object)(*p - pi.offset); + Interface* pi = **cast(Interface ***)p; + Object o = cast(Object)(p - pi.offset); - _d_delclass(&o); - *p = null; + _d_delclass(o); + //*p = null; } } -+/ - // used for deletion private extern (D) alias void function(Object) fp_t; -/+ - /** * */ -extern (C) void _d_delclass(Object* p) +extern (C) void _d_delclass(Object p) { - if (*p) + if (p) { - debug(PRINTF) printf("_d_delclass(%p)\n", *p); + debug(PRINTF) printf("_d_delclass(%p)\n", p); - ClassInfo **pc = cast(ClassInfo **)*p; + ClassInfo **pc = cast(ClassInfo **)p; if (*pc) { ClassInfo c = **pc; - rt_finalize(cast(void*) *p); + rt_finalize(cast(void*) p); if (c.deallocator) { fp_t fp = cast(fp_t)c.deallocator; - (*fp)(*p); // call deallocator - *p = null; + (*fp)(p); // call deallocator + //*p = null; return; } } else { - rt_finalize(cast(void*) *p); + rt_finalize(cast(void*) p); } - gc_free(cast(void*) *p); - *p = null; + gc_free(cast(void*) p); + //*p = null; } } +/+ + /** * */ @@ -420,35 +416,31 @@ return gc_malloc(ti.tsize(), (ti.flags() & 1) ? BlkAttr.NO_SCAN : 0); } -/+ +/** + * + */ +extern (C) void _d_delarray(size_t plength, void* pdata) +{ +// if (p) +// { + assert(!plength || pdata); + + if (pdata) + gc_free(pdata); +// p.data = null; +// p.length = 0; +// } +} /** * */ -extern (C) void _d_delarray(Array *p) +extern (C) void _d_delmemory(void* p) { if (p) { - assert(!p.length || p.data); - - if (p.data) - gc_free(p.data); - p.data = null; - p.length = 0; - } -} - -+/ - -/** - * - */ -extern (C) void _d_delmemory(void* *p) -{ - if (*p) - { - gc_free(*p); - *p = null; + gc_free(p); + //*p = null; } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tangotests/mem2.d Wed May 14 01:22:40 2008 +0200 @@ -0,0 +1,11 @@ +module tangotests.mem2; + +void main() +{ + int* ip = new int; + assert(*ip == 0); + *ip = 4; + assert(*ip == 4); + delete ip; + assert(ip is null); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tangotests/mem3.d Wed May 14 01:22:40 2008 +0200 @@ -0,0 +1,12 @@ +module tangotests.mem3; + +void main() +{ + int[] arr; + arr ~= [1,2,3]; + assert(arr[0] == 1); + assert(arr[1] == 2); + assert(arr[2] == 3); + delete arr; + assert(arr is null); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tangotests/mem4.d Wed May 14 01:22:40 2008 +0200 @@ -0,0 +1,29 @@ +module tangotests.mem4; + +import tango.stdc.stdio; + +class C { + int* ptr; + this() { + printf("this()\n"); + ptr = new int; + } + ~this() { + printf("~this()\n"); + delete ptr; + assert(ptr is null); + } + final void check() + { + printf("check()\n"); + assert(ptr !is null); + } +} + +void main() +{ + C c = new C(); + c.check(); + delete c; + assert(c is null); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tangotests/mem5.d Wed May 14 01:22:40 2008 +0200 @@ -0,0 +1,24 @@ +module tangotests.mem5; + +class SC +{ + int* ip; + this() + { + ip = new int; + } + ~this() + { + delete ip; + } + void check() + { + assert(ip !is null); + } +} + +void main() +{ + scope sc = new SC; + sc.check(); +}