changeset 530:d30c40f1128d

Make class invariants work.
author Christian Kamm <kamm incasoftware de>
date Thu, 21 Aug 2008 15:19:45 +0200
parents cef0cbcf7d22
children 0beebf923322
files dmd/mars.c gen/runtime.cpp gen/tocall.cpp gen/toir.cpp runtime/internal/invariant.d runtime/internal/llvmdc.mak
diffstat 6 files changed, 99 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/mars.c	Wed Aug 20 19:03:28 2008 +0200
+++ b/dmd/mars.c	Thu Aug 21 15:19:45 2008 +0200
@@ -265,7 +265,7 @@
     global.params.argv0 = argv[0];
 #endif
     global.params.link = 1;
-    global.params.useAssert = 0;
+    global.params.useAssert = 1;
     global.params.useInvariants = 1;
     global.params.useIn = 1;
     global.params.useOut = 1;
--- a/gen/runtime.cpp	Wed Aug 20 19:03:28 2008 +0200
+++ b/gen/runtime.cpp	Thu Aug 21 15:19:45 2008 +0200
@@ -883,4 +883,17 @@
         const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
         llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
     }
+
+    /////////////////////////////////////////////////////////////////////////////////////
+    /////////////////////////////////////////////////////////////////////////////////////
+    /////////////////////////////////////////////////////////////////////////////////////
+
+    // void _d_invariant(Object o)
+    {
+        std::string fname("_d_invariant");
+        std::vector<const LLType*> 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/tocall.cpp	Wed Aug 20 19:03:28 2008 +0200
+++ b/gen/tocall.cpp	Thu Aug 21 15:19:45 2008 +0200
@@ -113,8 +113,11 @@
     int begin = tf->parameters->dim;
     Logger::println("num non vararg params = %d", begin);
 
+    // get n args in arguments list
+    size_t n_arguments = arguments ? arguments->dim : 0;
+
     // build struct with argument types (non variadic args)
-    for (int i=begin; i<arguments->dim; i++)
+    for (int i=begin; i<n_arguments; i++)
     {
         Expression* argexp = (Expression*)arguments->data[i];
         vtypes.push_back(DtoType(argexp->type));
@@ -127,7 +130,7 @@
     LLValue* mem = DtoAlloca(vtype,"_argptr_storage");
 
     // store arguments in the struct
-    for (int i=begin,k=0; i<arguments->dim; i++,k++)
+    for (int i=begin,k=0; i<n_arguments; i++,k++)
     {
         Expression* argexp = (Expression*)arguments->data[i];
         if (global.params.llvmAnnotate)
@@ -147,7 +150,7 @@
     Logger::cout() << "_arguments storage: " << *typeinfomem << '\n';
 
     std::vector<LLConstant*> vtypeinfos;
-    for (int i=begin,k=0; i<arguments->dim; i++,k++)
+    for (int i=begin,k=0; i<n_arguments; i++,k++)
     {
         Expression* argexp = (Expression*)arguments->data[i];
         vtypeinfos.push_back(DtoTypeInfoOf(argexp->type));
@@ -219,6 +222,9 @@
     const LLFunctionType* callableTy = DtoExtractFunctionType(callable->getType());
     assert(callableTy);
 
+    // get n arguments
+    size_t n_arguments = arguments ? arguments->dim : 0;
+
     // get llvm argument iterator, for types
     LLFunctionType::param_iterator argbegin = callableTy->param_begin();
     LLFunctionType::param_iterator argiter = argbegin;
@@ -280,8 +286,7 @@
     // variadic instrinsics need some custom casts
     if (va_intrinsic)
     {
-        size_t n = arguments->dim;
-        for (int i=0; i<n; i++)
+        for (int i=0; i<n_arguments; i++)
         {
             Expression* exp = (Expression*)arguments->data[i];
             DValue* expelem = exp->toElem(gIR);
@@ -302,7 +307,7 @@
     else
     {
         Logger::println("doing normal arguments");
-        for (int i=0; i<arguments->dim; i++) {
+        for (int i=0; i<n_arguments; i++) {
             int j = argiter-argbegin;
             Argument* fnarg = Argument::getNth(tf->parameters, i);
             DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
--- a/gen/toir.cpp	Wed Aug 20 19:03:28 2008 +0200
+++ b/gen/toir.cpp	Thu Aug 21 15:19:45 2008 +0200
@@ -1569,30 +1569,56 @@
     Logger::print("AssertExp::toElem: %s\n", toChars());
     LOG_SCOPE;
 
+    if(!global.params.useAssert)
+        return NULL;
+
     // condition
     DValue* cond = e1->toElem(p);
-
-    // create basic blocks
-    llvm::BasicBlock* oldend = p->scopeend();
-    llvm::BasicBlock* assertbb = llvm::BasicBlock::Create("assert", p->topfunc(), oldend);
-    llvm::BasicBlock* endbb = llvm::BasicBlock::Create("noassert", p->topfunc(), oldend);
-
-    // test condition
-    LLValue* condval = DtoBoolean(loc, cond);
-
-    // branch
-    llvm::BranchInst::Create(endbb, assertbb, condval, p->scopebb());
-
-    // call assert runtime functions
-    p->scope() = IRScope(assertbb,endbb);
-    DtoAssert(&loc, msg ? msg->toElem(p) : NULL);
-
-    // assert inserts unreachable terminator
-//     if (!gIR->scopereturned())
-//         llvm::BranchInst::Create(endbb, p->scopebb());
-
-    // rewrite the scope
-    p->scope() = IRScope(endbb,oldend);
+    Type* condty = e1->type->toBasetype();
+
+    InvariantDeclaration* invdecl;
+
+    // class invariants
+    if(
+        global.params.useInvariants && 
+        condty->ty == Tclass &&
+        !((TypeClass*)condty)->sym->isInterfaceDeclaration())
+    {
+        Logger::print("calling class invariant");
+        llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_invariant");
+        LLValue* arg = DtoBitCast(cond->getRVal(), fn->getFunctionType()->getParamType(0));
+        gIR->CreateCallOrInvoke(fn, arg);
+    }
+    // struct invariants
+    else if(
+        global.params.useInvariants && 
+        condty->ty == Tpointer && condty->next->ty == Tstruct &&
+        (invdecl = ((TypeStruct*)condty->next)->sym->inv) != NULL)
+    {
+        Logger::print("calling struct invariant");
+        DFuncValue invfunc(invdecl, invdecl->ir.irFunc->func, cond->getRVal());
+        DtoCallFunction(loc, NULL, &invfunc, NULL);
+    }
+    else
+    {
+        // create basic blocks
+        llvm::BasicBlock* oldend = p->scopeend();
+        llvm::BasicBlock* assertbb = llvm::BasicBlock::Create("assert", p->topfunc(), oldend);
+        llvm::BasicBlock* endbb = llvm::BasicBlock::Create("noassert", p->topfunc(), oldend);
+
+        // test condition
+        LLValue* condval = DtoBoolean(loc, cond);
+
+        // branch
+        llvm::BranchInst::Create(endbb, assertbb, condval, p->scopebb());
+
+        // call assert runtime functions
+        p->scope() = IRScope(assertbb,endbb);
+        DtoAssert(&loc, msg ? msg->toElem(p) : NULL);
+
+        // rewrite the scope
+        p->scope() = IRScope(endbb,oldend);
+    }
 
     // no meaningful return value
     return NULL;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/internal/invariant.d	Thu Aug 21 15:19:45 2008 +0200
@@ -0,0 +1,25 @@
+
+/*
+ * Placed into the Public Domain
+ * written by Walter Bright
+ * www.digitalmars.com
+ */
+
+extern(C) void _d_invariant(Object o)
+{   ClassInfo c;
+
+    //printf("__d_invariant(%p)\n", o);
+
+    // BUG: needs to be filename/line of caller, not library routine
+    assert(o !is null);	// just do null check, not invariant check
+
+    c = o.classinfo;
+    do
+    {
+	if (c.classInvariant)
+	{
+	    (*c.classInvariant)(o);
+	}
+	c = c.base;
+    } while (c);
+}
--- a/runtime/internal/llvmdc.mak	Wed Aug 20 19:03:28 2008 +0200
+++ b/runtime/internal/llvmdc.mak	Thu Aug 21 15:19:45 2008 +0200
@@ -83,6 +83,7 @@
     memory.bc \
     qsort2.bc \
     switch.bc \
+    invariant.bc \
 
 OBJ_UTIL= \
     util/console.bc \