[svn r225] Fixed: delete expressions no longer use llvm's free instruction, which crashes on a GC provided pointer.

This commit is contained in:
Tomas Lindquist Olsen
2008-05-14 01:22:40 +02:00
parent bcc112e37f
commit 19748f09ec
12 changed files with 241 additions and 145 deletions

View File

@@ -932,6 +932,19 @@ void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance)
//////////////////////////////////////////////////////////////////////////////////////////
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());

View File

@@ -28,6 +28,7 @@ DValue* DtoNewClass(TypeClass* type, NewExp* newexp);
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);

View File

@@ -283,6 +283,40 @@ static void LLVM_D_BuildRuntimeModule()
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);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

View File

@@ -1984,66 +1984,6 @@ DValue* NewExp::toElem(IRState* p)
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 @@ DValue* DeleteExp::toElem(IRState* p)
Logger::print("DeleteExp::toElem: %s | %s\n", toChars(), type->toChars());
LOG_SCOPE;
//assert(e1->type->ty != Tclass);
DValue* dval = e1->toElem(p);
Type* et = DtoDType(e1->type);
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());
// 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;
}
//////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -703,6 +703,40 @@ llvm::Value* DtoNew(Type* newtype)
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)

View File

@@ -61,6 +61,9 @@ llvm::Value* DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std::stri
// 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);

View File

@@ -760,6 +760,10 @@ tangotests/j.d
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

View File

@@ -131,64 +131,60 @@ extern (C) Object _d_newclass(ClassInfo ci)
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 @@ extern (C) void* _d_allocmemoryT(TypeInfo ti)
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;
}
}

11
tangotests/mem2.d Normal file
View File

@@ -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);
}

12
tangotests/mem3.d Normal file
View File

@@ -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);
}

29
tangotests/mem4.d Normal file
View File

@@ -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);
}

24
tangotests/mem5.d Normal file
View File

@@ -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();
}