diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index b3d52ce9773e48..427ca469d3cd94 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2769,7 +2769,50 @@ GenTree* Compiler::optVNBasedFoldExpr(BasicBlock* block, GenTree* parent, GenTre case GT_CALL: return optVNBasedFoldExpr_Call(block, parent, tree->AsCall()); - // We can add more VN-based foldings here. + case GT_STORE_BLK: + { + if (!opts.IsReadyToRun()) + { + // TODO: Implement CORINFO_HELP_ASSIGN_STRUCT for R2R/ILC + break; + } + + // Replace STORE_BLK (struct copy) with CORINFO_HELP_ASSIGN_STRUCT which performs + // bulk copy for byrefs. + GenTreeBlk* blk = tree->AsBlk(); + if (!blk->OperIsInitBlkOp() && blk->IsReverseOp() && (blk->GetLayout()->GetGCPtrCount() > 3)) + { + GenTree* addr = blk->Addr(); + GenTree* data = blk->Data(); + if (data->OperIs(GT_BLK)) + { + data = data->AsBlk()->Addr(); + } + else + { + assert(data->OperIs(GT_LCL_VAR, GT_LCL_FLD)); + } + + // For now, we use it only for newly created objects where we know we don't have to + // be precise (from GC's point of view) and update card tables. + // For that, we expect addr to be "JIT_New + offset" + VNFuncApp funcApp; + if (vnStore->GetVNFunc(vnStore->VNLiberalNormalValue(addr->gtVNPair), &funcApp) && + (funcApp.m_func == VNFunc(GT_ADD)) && vnStore->GetVNFunc(funcApp.m_args[0], &funcApp) && + (funcApp.m_func == VNF_JitNew)) + { + const unsigned gcPtrs = blk->GetLayout()->GetGCPtrCount(); + if (!CheckedOps::MulOverflows((int)gcPtrs, TARGET_POINTER_SIZE, true)) + { + GenTree* slots = gtNewIconNode((ssize_t)gcPtrs * TARGET_POINTER_SIZE, TYP_I_IMPL); + GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_ASSIGN_STRUCT, TYP_VOID, data, addr, slots); + fgMorphArgs(call); + return call; + } + } + } + break; + } default: break; @@ -6469,6 +6512,10 @@ Compiler::fgWalkResult Compiler::optVNBasedFoldCurStmt(BasicBlock* block, // This can occur for HFA return values (see hfa_sf3E_r.exe) if (tree->TypeGet() == TYP_STRUCT) { + if (tree->OperIs(GT_STORE_BLK) && tree->AsBlk()->GetLayout()->HasGCPtr()) + { + goto PERFORM_FOLD; + } return WALK_CONTINUE; } @@ -6545,6 +6592,7 @@ Compiler::fgWalkResult Compiler::optVNBasedFoldCurStmt(BasicBlock* block, // Unknown node, continue to walk. return WALK_CONTINUE; } +PERFORM_FOLD: // Perform the VN-based folding: GenTree* newTree = optVNBasedFoldExpr(block, parent, tree); diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 98d6780258a6c6..a93c399b946e77 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -4780,15 +4780,15 @@ HCIMPLEND //======================================================================== /*************************************************************/ -HCIMPL3(VOID, JIT_StructWriteBarrier, void *dest, void* src, CORINFO_CLASS_HANDLE typeHnd_) +HCIMPL3(VOID, JIT_StructWriteBarrier, void* src, void* dest, size_t byteSize) { FCALL_CONTRACT; - TypeHandle typeHnd(typeHnd_); - MethodTable *pMT = typeHnd.AsMethodTable(); + _ASSERT(byteSize > 0); + _ASSERT((byteSize % TARGET_POINTER_SIZE) == 0); HELPER_METHOD_FRAME_BEGIN_NOPOLL(); // Set up a frame - CopyValueClass(dest, src, pMT); + memmoveGCRefs(dest, src, byteSize); HELPER_METHOD_FRAME_END_POLL(); }