# HG changeset patch # User Christian Kamm # Date 1219324785 -7200 # Node ID d30c40f1128d6caef3b5f56ead1bf0911f612adb # Parent cef0cbcf7d22c093de3053e0adf96abf418eb724 Make class invariants work. diff -r cef0cbcf7d22 -r d30c40f1128d dmd/mars.c --- 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; diff -r cef0cbcf7d22 -r d30c40f1128d gen/runtime.cpp --- 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 types; + types.push_back(objectTy); + const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); + } } diff -r cef0cbcf7d22 -r d30c40f1128d gen/tocall.cpp --- 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; idim; i++) + for (int i=begin; idata[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; idim; i++,k++) + for (int i=begin,k=0; idata[i]; if (global.params.llvmAnnotate) @@ -147,7 +150,7 @@ Logger::cout() << "_arguments storage: " << *typeinfomem << '\n'; std::vector vtypeinfos; - for (int i=begin,k=0; idim; i++,k++) + for (int i=begin,k=0; idata[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; idata[i]; DValue* expelem = exp->toElem(gIR); @@ -302,7 +307,7 @@ else { Logger::println("doing normal arguments"); - for (int i=0; idim; i++) { + for (int i=0; iparameters, i); DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); diff -r cef0cbcf7d22 -r d30c40f1128d gen/toir.cpp --- 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; diff -r cef0cbcf7d22 -r d30c40f1128d runtime/internal/invariant.d --- /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); +} diff -r cef0cbcf7d22 -r d30c40f1128d runtime/internal/llvmdc.mak --- 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 \