Call postblit on a struct when appending it to an array. Use _d_arraycatnT to concatenate multiple arrays.

Before, _d_arraycatT was used to concatenate multiple arrays. That caused an issue when postblit
was called on a struct multiple times. The next code asserted due to the issue:

void main()
{
    static struct S
    {
        int x;
        int pad;
        this(this)
        {
            ++x;
        }
    }

    auto sarr = new S[1];
    auto sarr2 = sarr ~ sarr ~ sarr;
    assert(sarr2[0].x == 1);
    assert(sarr2[1].x == 1);
    assert(sarr2[2].x == 1);
    assert(sarr[0].x == 0);
}
This commit is contained in:
Alexey Prokhin 2011-09-10 13:22:05 +04:00
parent 9864129fb8
commit 0caba6672d
5 changed files with 98 additions and 40 deletions

View file

@ -23,7 +23,7 @@
static LLValue *DtoSlice(DValue *dval)
{
LLValue *val = dval->getRVal();
if (dval->isVar() && dval->isVar()->type->ty == Tsarray) {
if (dval->getType()->toBasetype()->ty == Tsarray) {
// Convert static array to slice
const LLStructType *type = DtoArrayType(LLType::getInt8Ty(gIR->context()));
LLValue *array = DtoRawAlloca(type, 0, ".array");
@ -36,6 +36,25 @@ static LLValue *DtoSlice(DValue *dval)
//////////////////////////////////////////////////////////////////////////////////////////
static LLValue *DtoSlicePtr(DValue *dval)
{
Loc loc;
const LLStructType *type = DtoArrayType(LLType::getInt8Ty(gIR->context()));
Type *vt = dval->getType()->toBasetype();
if (vt->ty == Tarray)
return makeLValue(loc, dval);
bool isStaticArray = vt->ty == Tsarray;
LLValue *val = isStaticArray ? dval->getRVal() : makeLValue(loc, dval);
LLValue *array = DtoRawAlloca(type, 0, ".array");
LLValue *len = isStaticArray ? DtoArrayLen(dval) : DtoConstSize_t(1);
DtoStore(len, DtoGEPi(array, 0, 0, ".len"));
DtoStore(DtoBitCast(val, getVoidPtrType()), DtoGEPi(array, 0, 1, ".ptr"));
return array;
}
//////////////////////////////////////////////////////////////////////////////////////////
const LLStructType* DtoArrayType(Type* arrayTy)
{
assert(arrayTy->nextOf());
@ -751,6 +770,7 @@ void DtoCatAssignElement(Loc& loc, Type* arrayType, DValue* array, Expression* e
val = DtoGEP1(val, oldLength, "lastElem");
val = DtoBitCast(val, DtoType(arrayType->nextOf()->pointerTo()));
DtoAssign(loc, new DVarValue(arrayType->nextOf(), val), expVal);
callPostblit(loc, exp, val);
}
#else
@ -846,23 +866,46 @@ DSliceValue* DtoCatArrays(Type* arrayType, Expression* exp1, Expression* exp2)
Logger::println("DtoCatAssignArray");
LOG_SCOPE;
// Prepare arguments
LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_arraycatT");
LLSmallVector<LLValue*,3> args;
// TypeInfo ti
args.push_back(DtoTypeInfoOf(arrayType));
// byte[] x
LLValue *val = DtoSlice(exp1->toElem(gIR));
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(1));
args.push_back(val);
// byte[] y
val = DtoSlice(exp2->toElem(gIR));
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(2));
args.push_back(val);
std::vector<LLValue*> args;
LLFunction* fn = 0;
// Call _d_arraycatT
LLValue* newArray = gIR->CreateCallOrInvoke(fn, args.begin(), args.end(), ".appendedArray").getInstruction();
if (exp1->op == TOKcat)
{ // handle multiple concat
fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_arraycatnT");
args.push_back(DtoSlicePtr(exp2->toElem(gIR)));
CatExp *ce = (CatExp*)exp1;
do
{
args.push_back(DtoSlicePtr(ce->e2->toElem(gIR)));
ce = (CatExp *)ce->e1;
} while (ce->op == TOKcat);
args.push_back(DtoSlicePtr(ce->toElem(gIR)));
// uint n
args.push_back(DtoConstUint(args.size()));
// TypeInfo ti
args.push_back(DtoTypeInfoOf(arrayType));
std::reverse(args.begin(), args.end());
}
else
{
fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_arraycatT");
// TypeInfo ti
args.push_back(DtoTypeInfoOf(arrayType));
// byte[] x
LLValue *val = DtoSlice(exp1->toElem(gIR));
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(1));
args.push_back(val);
// byte[] y
val = DtoSlice(exp2->toElem(gIR));
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(2));
args.push_back(val);
}
LLValue *newArray = gIR->CreateCallOrInvoke(fn, args.begin(), args.end(), ".appendedArray").getInstruction();
return getSlice(arrayType, newArray);
}

View file

@ -1733,3 +1733,28 @@ LLValue* makeLValue(Loc& loc, DValue* value)
return valuePointer;
}
//////////////////////////////////////////////////////////////////////////////////////////
#if DMDV2
void callPostblit(Loc &loc, Expression *exp, LLValue *val)
{
Type *tb = exp->type->toBasetype();
if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar || exp->op == TOKthis) &&
tb->ty == Tstruct)
{ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
if (sd->postblit)
{
FuncDeclaration *fd = sd->postblit;
if (fd->storage_class & STCdisable)
fd->toParent()->error(loc, "is not copyable because it is annotated with @disable");
fd->codegen(Type::sir);
Expressions args;
DFuncValue dfn(fd, fd->ir.irFunc->func, val);
DtoCallFunction(loc, Type::basic[Tvoid], &dfn, &args);
}
}
}
#endif

View file

@ -152,6 +152,10 @@ size_t realignOffset(size_t offset, Type* type);
/// functions without problems.
LLValue* makeLValue(Loc& loc, DValue* value);
#if DMDV2
void callPostblit(Loc &loc, Expression *exp, LLValue *val);
#endif
////////////////////////////////////////////
// gen/tocall.cpp stuff below
////////////////////////////////////////////

View file

@ -439,6 +439,14 @@ static void LLVM_D_BuildRuntimeModule()
const llvm::FunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, false);
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)
{
llvm::StringRef fname("_d_arraycatnT");
std::vector<const LLType*> types;
types.push_back(typeInfoTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, true);
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
#else // DMDV1
// byte[] _d_arrayappendcT(TypeInfo ti, void* array, void* element)
{

View file

@ -47,28 +47,6 @@ void CompoundStatement::toIR(IRState* p)
//////////////////////////////////////////////////////////////////////////////
#if DMDV2
static void callPostblitHelper(Loc &loc, Expression *exp, LLValue *val)
{
Type *tb = exp->type->toBasetype();
if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar || exp->op == TOKthis) &&
tb->ty == Tstruct)
{ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
if (sd->postblit)
{
FuncDeclaration *fd = sd->postblit;
if (fd->storage_class & STCdisable)
fd->toParent()->error(loc, "is not copyable because it is annotated with @disable");
fd->codegen(Type::sir);
Expressions args;
DFuncValue dfn(fd, fd->ir.irFunc->func, val);
DtoCallFunction(loc, Type::basic[Tvoid], &dfn, &args);
}
}
}
#endif
void ReturnStatement::toIR(IRState* p)
{
Logger::println("ReturnStatement::toIR(): %s", loc.toChars());
@ -101,7 +79,7 @@ void ReturnStatement::toIR(IRState* p)
#if DMDV2
// call postblit if necessary
if (!p->func()->type->isref)
callPostblitHelper(loc, exp, rvar->getLVal());
callPostblit(loc, exp, rvar->getLVal());
#endif
// emit scopes
@ -127,7 +105,7 @@ void ReturnStatement::toIR(IRState* p)
#if DMDV2
// call postblit if necessary
if (!p->func()->type->isref)
callPostblitHelper(loc, exp, dval->getRVal());
callPostblit(loc, exp, dval->getRVal());
// do abi specific transformations on the return value
v = p->func()->type->fty.putRet(exp->type, dval, p->func()->type->isref);
#else