Permalink
Browse files

Handle IL OpCode initobj by generating proper offset to the class poi…

…nter (we don't want the initobj to clear the method table pointer)
  • Loading branch information...
xoofx committed Oct 7, 2015
1 parent be67f22 commit 48a3840b0f006f50f8d03b31e258004b3a25bb90
Showing with 55 additions and 14 deletions.
  1. +3 −1 src/jit/codegenlinear.h
  2. +36 −3 src/jit/codegenxarch.cpp
  3. +5 −2 src/jit/importer.cpp
  4. +11 −8 src/jit/morph.cpp
@@ -134,7 +134,9 @@

void genCodeForInitBlkRepStos (GenTreeInitBlk* initBlkNode);

void genCodeForInitBlkUnroll (GenTreeInitBlk* initBlkNode);
void genCodeInitBlkAdjustForReferenceType(GenTreeInitBlk* initBlkNode);

void genCodeForInitBlkUnroll (GenTreeInitBlk* initBlkNode);

void genJumpTable(GenTree* tree);

@@ -3223,7 +3223,12 @@ void CodeGen::genCodeForInitBlkRepStos(GenTreeInitBlk* initBlkNode)
assert(!blockSize->isContained());

assert(blockSize->gtSkipReloadOrCopy()->IsCnsIntOrI());

// ClassAsValue: Emit code to adjust the destination and size of initblk
genCodeInitBlkAdjustForReferenceType(initBlkNode);

size_t size = blockSize->gtIntCon.gtIconVal;

if (initVal->IsCnsIntOrI())
{
assert(size > INITBLK_UNROLL_LIMIT && size < INITBLK_STOS_LIMIT);
@@ -3235,6 +3240,29 @@ void CodeGen::genCodeForInitBlkRepStos(GenTreeInitBlk* initBlkNode)
instGen(INS_r_stosb);
}

void CodeGen::genCodeInitBlkAdjustForReferenceType(GenTreeInitBlk* initBlkNode)
{
GenTreePtr dstAddr = initBlkNode->Dest();
// ClassAsValue: Because the methodtable is already setup in codegencommon.cpp (search for ObjHeader)
// We are making sure that for a class, we don't clear the methodtable pointer, so we skip it here (offset+= ptr_size, size -= ptrsize)
if (dstAddr->gtOper == GT_LCL_VAR_ADDR)
{
LclVarDsc * varDsc = &(compiler->lvaTable[dstAddr->AsLclVar()->GetLclNum()]);
if (varDsc->lvType == TYP_STRUCT && varDsc->IsReferenceType())
{
emitter *emit = getEmitter();
size_t offset = sizeof(void*);

GenTreePtr blockSize = initBlkNode->Size();
size_t size = (blockSize->gtIntCon.gtIconVal -= offset);
if (size > 0)
{
emit->emitIns_R_I(INS_add, EA_8BYTE, dstAddr->gtRegNum, offset);
}
}
}
}

// Generate code for InitBlk by performing a loop unroll
// Preconditions:
// a) Both the size and fill byte value are integer constants.
@@ -3255,7 +3283,11 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeInitBlk* initBlkNode)
assert(blockSize->IsCnsIntOrI());
#endif // DEBUG

size_t size = blockSize->gtIntCon.gtIconVal;
// ClassAsValue: Emit code to adjust the destination and size of initblk
genCodeInitBlkAdjustForReferenceType(initBlkNode);

unsigned offset = 0;
size_t size = blockSize->gtIntCon.gtIconVal;

assert(size <= INITBLK_UNROLL_LIMIT);
assert(initVal->gtSkipReloadOrCopy()->IsCnsIntOrI());
@@ -3270,8 +3302,6 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeInitBlk* initBlkNode)
regNumber valReg = initVal->gtRegNum;
initVal = initVal->gtSkipReloadOrCopy();

unsigned offset = 0;

// Perform an unroll using SSE2 loads and stores.
if (size >= XMM_REGSIZE_BYTES)
{
@@ -3356,6 +3386,9 @@ void CodeGen::genCodeForInitBlk(GenTreeInitBlk* initBlkNode)
}
#endif // DEBUG

// ClassAsValue: Adjust offset and size
genCodeInitBlkAdjustForReferenceType(initBlkNode);

genConsumeBlockOp(initBlkNode, REG_ARG_0, REG_ARG_1, REG_ARG_2);

genEmitHelperCall(CORINFO_HELP_MEMSET, 0, EA_UNKNOWN);
@@ -12693,8 +12693,11 @@ MATH_MAYBE_CALL_NO_OVF: ovfl = false;

}

op3 = gtNewIconNode(info.compCompHnd->getClassSize(resolvedToken.hClass)); // Size
op2 = gtNewIconNode(0); // Value
// ClassAsValue: In case of a value type, we want the full size of the class and not the size of the pointer
op3 = gtNewIconNode(info.compCompHnd->isValueClass(resolvedToken.hClass) ?
info.compCompHnd->getClassSize(resolvedToken.hClass) :
info.compCompHnd->getBaseSize(resolvedToken.hClass)); // Size
op2 = gtNewIconNode(0); // Value
goto INITBLK_OR_INITOBJ;

case CEE_INITBLK:
@@ -6582,23 +6582,26 @@ GenTreePtr Compiler::fgMorphInitBlock(GenTreePtr tree)

JITDUMP("\nfgMorphInitBlock:");

GenTreePtr oneAsgTree = fgMorphOneAsgBlockOp(tree);
GenTreePtr oneAsgTree = nullptr;
GenTreeInitBlk* initBlkOp = tree->AsInitBlk();
GenTreePtr destAddr = initBlkOp->Dest();
GenTreePtr initVal = initBlkOp->InitVal();
GenTreePtr blockSize = initBlkOp->Size();
if (destAddr->gtType != TYP_REF)
{
oneAsgTree = fgMorphOneAsgBlockOp(tree);
}

if (oneAsgTree)
{
JITDUMP(" using oneAsgTree.\n");
tree = oneAsgTree;
}
else
{
GenTreeInitBlk* initBlkOp = tree->AsInitBlk();

GenTreePtr destAddr = initBlkOp->Dest();
GenTreePtr initVal = initBlkOp->InitVal();
GenTreePtr blockSize = initBlkOp->Size();

// The dest must be an address
noway_assert(genActualType(destAddr->gtType) == TYP_I_IMPL ||
destAddr->gtType == TYP_BYREF);
destAddr->gtType == TYP_BYREF || destAddr->gtType == TYP_REF);

// The size must be an integer type
assert(varTypeIsIntegral(blockSize->gtType));

0 comments on commit 48a3840

Please sign in to comment.