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, 254 insertions(+), 158 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)
+{
+    if (p)
+    {
+        Interface* pi = **cast(Interface ***)p;
+        Object     o  = cast(Object)(p - pi.offset);
+
+        _d_delclass(o);
+        //*p = null;
+    }
+}
+
+// used for deletion
+private extern (D) alias void function(Object) fp_t;
+
 
 /**
  *
  */
-extern (C) void _d_delinterface(void** p)
+extern (C) void _d_delclass(Object p)
 {
-    if (*p)
+    if (p)
     {
-        Interface* pi = **cast(Interface ***)*p;
-        Object     o  = cast(Object)(*p - pi.offset);
+        debug(PRINTF) printf("_d_delclass(%p)\n", p);
 
-        _d_delclass(&o);
-        *p = null;
-    }
-}
-
-+/
-
-// used for deletion
-private extern (D) alias void function(Object) fp_t;
-
-/+
-
-
-/**
- *
- */
-extern (C) void _d_delclass(Object* p)
-{
-    if (*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();
+}