diff --git a/dmd/mars.c b/dmd/mars.c index 9a488319..dc49a9dd 100644 --- a/dmd/mars.c +++ b/dmd/mars.c @@ -265,7 +265,7 @@ int main(int argc, char *argv[]) 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 --git a/gen/runtime.cpp b/gen/runtime.cpp index 4bc9f368..49419452 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -883,4 +883,17 @@ static void LLVM_D_BuildRuntimeModule() 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 --git a/gen/tocall.cpp b/gen/tocall.cpp index 9fdee7bf..d7b465c4 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -113,8 +113,11 @@ void DtoBuildDVarArgList(std::vector& args, llvm::PAListPtr& palist, T 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 @@ void DtoBuildDVarArgList(std::vector& args, llvm::PAListPtr& palist, T 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 @@ void DtoBuildDVarArgList(std::vector& args, llvm::PAListPtr& palist, T 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 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* 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 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // 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 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* 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 --git a/gen/toir.cpp b/gen/toir.cpp index bf295df4..17be3f83 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1569,30 +1569,56 @@ DValue* AssertExp::toElem(IRState* p) Logger::print("AssertExp::toElem: %s\n", toChars()); LOG_SCOPE; + if(!global.params.useAssert) + return NULL; + // condition DValue* cond = e1->toElem(p); + Type* condty = e1->type->toBasetype(); - // 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); + InvariantDeclaration* invdecl; - // test condition - LLValue* condval = DtoBoolean(loc, cond); + // 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); - // branch - llvm::BranchInst::Create(endbb, assertbb, condval, p->scopebb()); + // test condition + LLValue* condval = DtoBoolean(loc, cond); - // call assert runtime functions - p->scope() = IRScope(assertbb,endbb); - DtoAssert(&loc, msg ? msg->toElem(p) : NULL); + // branch + llvm::BranchInst::Create(endbb, assertbb, condval, p->scopebb()); - // assert inserts unreachable terminator -// if (!gIR->scopereturned()) -// llvm::BranchInst::Create(endbb, 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); + // rewrite the scope + p->scope() = IRScope(endbb,oldend); + } // no meaningful return value return NULL; diff --git a/runtime/internal/invariant.d b/runtime/internal/invariant.d new file mode 100644 index 00000000..f706c84e --- /dev/null +++ b/runtime/internal/invariant.d @@ -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 --git a/runtime/internal/llvmdc.mak b/runtime/internal/llvmdc.mak index 9d6e0da3..5e802e42 100644 --- a/runtime/internal/llvmdc.mak +++ b/runtime/internal/llvmdc.mak @@ -83,6 +83,7 @@ OBJ_BASE= \ memory.bc \ qsort2.bc \ switch.bc \ + invariant.bc \ OBJ_UTIL= \ util/console.bc \