Repository: dotnet/runtime
File: src/coreclr/jit/codegenwasm.cpp (C++)

Code before:

    // This GenTree node has data about GC pointers, this means we're dealing
    // with CpObj.
    assert(cpObjNode->GetLayout()->HasGCPtr());
#endif // DEBUG

    genConsumeOperands(cpObjNode);

    emitter* emit = GetEmitter();

    // TODO-WASM: Implicit null check

    // TODO-WASM: Remove the need to do this somehow
    // The dst and src may be on the evaluation stack, but we can't reliably use them, so drop them.
    emit->emitIns(INS_drop);
    if (!source->isContained())
        emit->emitIns(INS_drop);

    if (cpObjNode->IsVolatile())
    {
        // TODO-WASM: Memory barrier
    }

    ClassLayout* layout = cpObjNode->GetLayout();
    unsigned     slots  = layout->GetSlotCount();

    emitAttr attrSrcAddr = emitActualTypeSize(srcAddrType);
    emitAttr attrDstAddr = emitActualTypeSize(dstAddr->TypeGet());

    unsigned gcPtrCount = cpObjNode->GetLayout()->GetGCPtrCount();

    unsigned i = 0;
    while (i < slots)
    {
        // Copy the pointer-sized non-gc-pointer slots one at a time using regular I-sized load/store pairs,
        //  and gc-pointer slots using a write barrier.
        if (!layout->IsGCPtr(i))
        {
            // Do a pointer-sized load+store pair at the appropriate offset relative to dest and source
            emit->emitIns_I(INS_local_get, attrDstAddr, WasmRegToIndex(dstReg));
            emit->emitIns_I(INS_local_get, attrSrcAddr, WasmRegToIndex(srcReg));
            emit->emitIns_I(INS_I_load, EA_PTRSIZE, srcOffset);
            emit->emitIns_I(INS_I_store, EA_PTRSIZE, dstOffset);
        }
        else
        {
            // Load the sp onto the stack for the helper call.
            // TODO-WASM: Implement a special calling convention for this helper that doesn't accept sp/pep.
            emit->emitIns_I(INS_local_get, EA_PTRSIZE, WasmRegToIndex(GetStackPointerReg()));
            // Compute the actual dest/src of the slot being copied to pass to the helper.
            emit->emitIns_I(INS_local_get, attrDstAddr, WasmRegToIndex(dstReg));

Review comment (refactor):
I am confused by the need for this `drop`. These operands are already in the right order for the first helper call / load/store pair.

(Assuming we implement the write barrier calling convention opt below)

Code after:
    }

    // If the destination is on the stack we don't need the write barrier.
    bool dstOnStack = cpObjNode->IsAddressNotOnHeap(m_compiler);
    // We should have generated a memory.copy for this scenario in lowering.
    assert(!dstOnStack);

#ifdef DEBUG
    assert(!dstAddr->isContained());

    // This GenTree node has data about GC pointers, this means we're dealing
    // with CpObj.
    assert(cpObjNode->GetLayout()->HasGCPtr());
#endif // DEBUG

    genConsumeOperands(cpObjNode);

    emitter* emit = GetEmitter();

    genEmitNullCheck(dstReg);

    // TODO-WASM: Remove the need to do this somehow
    // The dst and src may be on the evaluation stack, but we can't reliably use them, so drop them.
    emit->emitIns(INS_drop);
    if (!source->isContained())
        emit->emitIns(INS_drop);

    if (cpObjNode->IsVolatile())
    {
        // TODO-WASM: Memory barrier
    }

    ClassLayout* layout = cpObjNode->GetLayout();
    unsigned     slots  = layout->GetSlotCount();

    emitAttr attrSrcAddr = emitActualTypeSize(srcAddrType);
    emitAttr attrDstAddr = emitActualTypeSize(dstAddr->TypeGet());

    unsigned gcPtrCount = cpObjNode->GetLayout()->GetGCPtrCount();

    unsigned i = 0;
    while (i < slots)
    {
        // Copy the pointer-sized non-gc-pointer slots one at a time using regular I-sized load/store pairs,
        //  and gc-pointer slots using a write barrier.
        if (!layout->IsGCPtr(i))
        {
            // Do a pointer-sized load+store pair at the appropriate offset relative to dest and source
            emit->emitIns_I(INS_local_get, attrDstAddr, WasmRegToIndex(dstReg));
            emit->emitIns_I(INS_local_get, attrSrcAddr, WasmRegToIndex(srcReg));
            emit->emitIns_I(INS_I_load, EA_PTRSIZE, srcOffset);