Fix for bugs related to clasifying System.TypedReference.
authorLubomir Litchev <lubol@microsoft.com>
Tue, 26 Jan 2016 06:23:31 +0000 (22:23 -0800)
committerLubomir Litchev <lubol@microsoft.com>
Tue, 2 Feb 2016 00:32:13 +0000 (16:32 -0800)
It was a long standing assumption in the Jit that a field of a struct can
never be of ByRef type. It turns out this assumption is not entirely
holding.
The System.TypedReference is a very special type that is a struct, defined
to have two IntPtr fields. When the VM instantiates this type it changes
the type of the first field to ByRef.
This change closes a GC hole in the passing this struct by value on the
stack. It adds support to the classification algorithm for ByRef
references. It also uses the tree types for generating the code that
places struct field on the stack by value for passin to a callee.

The handling of GT_RETURN in the codegenxarch.cpp has been extracted as a
separate routine - genReturn. In case of struct return (multi-register
struct return or an implicit retBuf return, it delegates to the
genStructReturn method. This is a refactoring as well as making
sure that GT_RETFILT is handled properly - the return type of it is always
bool or void for the last statement of a finally block.

More feedback addressed.

15 files changed:
src/inc/corinfo.h
src/jit/codegencommon.cpp
src/jit/codegenlinear.h
src/jit/codegenxarch.cpp
src/jit/compiler.cpp
src/jit/ee_il_dll.cpp
src/jit/lclvars.cpp
src/jit/lowerxarch.cpp
src/jit/morph.cpp
src/vm/argdestination.h
src/vm/callingconvention.h
src/vm/jitinterface.cpp
src/vm/methodtable.cpp
src/vm/methodtable.h
src/vm/threadsuspend.cpp

index fef4126..ae44b0f 100644 (file)
@@ -276,12 +276,26 @@ enum SystemVClassificationType : unsigned __int8
     SystemVClassificationTypeMemory             = 3,
     SystemVClassificationTypeInteger            = 4,
     SystemVClassificationTypeIntegerReference   = 5,
-    SystemVClassificationTypeSSE                = 6,
+    SystemVClassificationTypeIntegerByRef       = 6,
+    SystemVClassificationTypeSSE                = 7,
     // SystemVClassificationTypeSSEUp           = Unused, // Not supported by the CLR.
     // SystemVClassificationTypeX87             = Unused, // Not supported by the CLR.
     // SystemVClassificationTypeX87Up           = Unused, // Not supported by the CLR.
     // SystemVClassificationTypeComplexX87      = Unused, // Not supported by the CLR.
-    SystemVClassificationTypeMAX = 7,
+
+    // Internal flags - never returned outside of the classification implementation.
+
+    // This value represents a very special type with two eightbytes. 
+    // First ByRef, second Integer (platform int).
+    // The VM has a special Elem type for this type - ELEMENT_TYPE_TYPEDBYREF.
+    // This is the classification counterpart for that element type. It is used to detect 
+    // the special TypedReference type and specialize its classification.
+    // This type is represented as a struct with two fields. The classification needs to do
+    // special handling of it since the source/methadata type of the fieds is IntPtr. 
+    // The VM changes the first to ByRef. The second is left as IntPtr (TYP_I_IMPL really). The classification needs to match this and
+    // special handling is warranted (similar thing is done in the getGCLayout function for this type).
+    SystemVClassificationTypeTypedReference     = 8,
+    SystemVClassificationTypeMAX                = 9,
 };
 
 // Represents classification information for a struct.
@@ -298,6 +312,7 @@ struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR
     unsigned __int8             eightByteSizes[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];           // The size of the eightbytes (an eightbyte could include padding. This represents the no padding size of the eightbyte).
     unsigned __int8             eightByteOffsets[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];         // The start offset of the eightbytes (in bytes).
 
+    // Members
 
     //------------------------------------------------------------------------
     // CopyFrom: Copies a struct classification into this one.
@@ -318,7 +333,40 @@ struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR
         }
     }
 
-    // Members
+    //------------------------------------------------------------------------
+    // IsIntegralSlot: Returns whether the eightbyte at slotIndex is of integral type.
+    //
+    // Arguments:
+    //    'slotIndex' the slot number we are determining if it is of integral type.
+    //
+    // Return value:
+    //     returns true if we the eightbyte at index slotIndex is of integral type.
+    // 
+
+    bool IsIntegralSlot(unsigned slotIndex) const
+    {
+        return ((eightByteClassifications[slotIndex] == SystemVClassificationTypeInteger) ||
+                (eightByteClassifications[slotIndex] == SystemVClassificationTypeIntegerReference) ||
+                (eightByteClassifications[slotIndex] == SystemVClassificationTypeIntegerByRef));
+    }
+
+    //------------------------------------------------------------------------
+    // IsSseSlot: Returns whether the eightbyte at slotIndex is SSE type.
+    //
+    // Arguments:
+    //    'slotIndex' the slot number we are determining if it is of SSE type.
+    //
+    // Return value:
+    //     returns true if we the eightbyte at index slotIndex is of SSE type.
+    // 
+    // Follows the rules of the AMD64 System V ABI specification at www.x86-64.org/documentation/abi.pdf.
+    // Please reffer to it for definitions/examples.
+    //
+    bool IsSseSlot(unsigned slotIndex) const
+    {
+        return (eightByteClassifications[slotIndex] == SystemVClassificationTypeSSE);
+    }
+
 private:
     void Initialize()
     {
index 4830342..4fb8f3f 100644 (file)
@@ -3940,10 +3940,8 @@ void            CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg,
                 
                 regArgNum = genMapRegNumToRegArgNum(regNum, regType);
                 
-                if ((!doingFloat &&
-                    ((structDesc.eightByteClassifications[slotCounter] == SystemVClassificationTypeInteger) || 
-                     (structDesc.eightByteClassifications[slotCounter] == SystemVClassificationTypeIntegerReference))) ||
-                     (doingFloat && structDesc.eightByteClassifications[slotCounter] == SystemVClassificationTypeSSE))
+                if ((!doingFloat && (structDesc.IsIntegralSlot(slotCounter))) ||
+                     (doingFloat && (structDesc.IsSseSlot(slotCounter))))
                 {
                     // Store the reg for the first slot.
                     if (slots == 0)
index 14c79a5..3240d33 100644 (file)
     
     void                genJmpMethod(GenTreePtr jmp);
 
-#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
-    void genGetStructTypeSizeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
-                                    var_types* type0,
-                                    var_types* type1,
-                                    emitAttr* size0,
-                                    emitAttr* size1,
-                                    unsigned __int8* offset0,
-                                    unsigned __int8* offset1);
-
     bool                genStoreRegisterReturnInLclVar(GenTreePtr treeNode);
+
+    // Deals with codegen for muti-register struct returns.
+    bool                isStructReturn(GenTreePtr treeNode);
+    void                genStructReturn(GenTreePtr treeNode);
+
+    // Codegen for GT_RETURN.
+    void                genReturn(GenTreePtr treeNode);
+
+#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
+    void                getStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
+                                            var_types* type0,
+                                            var_types* type1,
+                                            unsigned __int8* offset0,
+                                            unsigned __int8* offset1);
+
+    void                getStructReturnRegisters(var_types type0,
+                                                 var_types type1,
+                                                 regNumber* retRegPtr0,
+                                                 regNumber* retRegPtr1);
 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
 
     void                genLclHeap(GenTreePtr tree);
index 2426a7a..66cad86 100644 (file)
@@ -1412,6 +1412,259 @@ void CodeGen::genCodeForBinary(GenTree* treeNode)
     genProduceReg(treeNode);
 }
 
+//------------------------------------------------------------------------
+// isStructReturn: Returns whether the 'treeNode' is returning a struct.
+//
+// Arguments:
+//    treeNode - The tree node to evaluate whether is a struct return.
+//
+// Return Value:
+//    For AMD64 *nix: returns true if the 'treeNode" is of type GT_RETURN and the
+//                    return type is a struct or it is an implicit retBuf struct return.
+//                    Otherwise returns false.
+//    For other platforms always returns false.
+//
+bool
+CodeGen::isStructReturn(GenTreePtr treeNode)
+{
+    // This method could be called for 'treeNode' of GT_RET_FILT or GT_RETURN.
+    // For the GT_RET_FILT, the return is always
+    // a bool or a void, for the end of a finally block.
+    noway_assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
+    if (treeNode->OperGet() != GT_RETURN)
+    {
+        return false;
+    }
+
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+    return varTypeIsStruct(treeNode) ||
+           (treeNode->TypeGet() == TYP_VOID && compiler->info.compRetBuffArg != BAD_VAR_NUM);
+#else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
+    assert(!varTypeIsStruct(treeNode));
+    return false;
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+}
+
+//------------------------------------------------------------------------
+// genStructReturn: Generates code for returning a struct.
+//
+// Arguments:
+//    treeNode - The GT_RETURN tree node.
+//
+// Return Value:
+//    None
+//
+void
+CodeGen::genStructReturn(GenTreePtr treeNode)
+{
+    assert(treeNode->OperGet() == GT_RETURN);
+    GenTreePtr op1 = treeNode->gtGetOp1();
+    var_types targetType = treeNode->TypeGet();
+
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+    if (targetType == TYP_VOID)
+    {
+        assert(op1 == nullptr);
+        if (compiler->info.compRetBuffArg != BAD_VAR_NUM)
+        {
+            // System V AMD64 spec requires that when a struct is returned by a hidden
+            // argument the RAX should contain the value of the hidden retbuf arg.
+            getEmitter()->emitIns_R_S(INS_mov, EA_BYREF, REG_RAX, compiler->info.compRetBuffArg, 0);
+        }        
+    }
+    else
+    {
+        noway_assert((op1->OperGet() == GT_LCL_VAR) ||
+                     (op1->OperGet() == GT_CALL));
+
+        if (op1->OperGet() == GT_LCL_VAR)
+        {
+            assert(op1->isContained());
+
+            GenTreeLclVarCommon* lclVarPtr = op1->AsLclVarCommon();
+            LclVarDsc* varDsc = &(compiler->lvaTable[lclVarPtr->gtLclNum]);
+            assert(varDsc->lvDontPromote);
+
+            CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
+            assert(typeHnd != nullptr);
+
+            SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
+            compiler->eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
+            assert(structDesc.passedInRegisters);
+            assert(structDesc.eightByteCount == CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
+
+            regNumber retReg0 = REG_NA;
+            unsigned __int8 offset0 = 0;
+            regNumber retReg1 = REG_NA;
+            unsigned __int8 offset1 = 0;
+
+            var_types type0 = TYP_UNKNOWN;
+            var_types type1 = TYP_UNKNOWN;
+
+            getStructTypeOffset(structDesc, &type0, &type1, &offset0, &offset1);
+            getStructReturnRegisters(type0, type1, &retReg0, &retReg1);
+
+            // Move the values into the return registers.
+            // 
+
+            assert(retReg0 != REG_NA && retReg1 != REG_NA);
+
+            getEmitter()->emitIns_R_S(ins_Load(type0), emitTypeSize(type0), retReg0, lclVarPtr->gtLclNum, offset0);
+            getEmitter()->emitIns_R_S(ins_Load(type1), emitTypeSize(type1), retReg1, lclVarPtr->gtLclNum, offset1);
+        }
+
+        // Nothing to do if the op1 of the return statement is a GT_CALL. The call already has the return
+        // registers in the proper return registers. 
+        // This assumes that registers never get spilled. There is an Issue 2966 created to track the need 
+        // for handling the GT_CALL case of two register returns and handle it properly for stress modes 
+        // and potential other changes that may break this assumption.
+    }
+#else
+    assert("!unreached");
+#endif   
+}
+
+//------------------------------------------------------------------------
+// genReturn: Generates code for return statement.
+//            In case of struct return, delegates to the genStructReturn method.
+//
+// Arguments:
+//    treeNode - The GT_RETURN or GT_RETFILT tree node.
+//
+// Return Value:
+//    None
+//
+void
+CodeGen::genReturn(GenTreePtr treeNode)
+{
+    assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
+    GenTreePtr op1 = treeNode->gtGetOp1();
+    var_types targetType = treeNode->TypeGet();
+
+#ifdef DEBUG
+    if (targetType == TYP_VOID)
+    {
+        assert(op1 == nullptr);
+    }
+#endif
+
+#ifdef _TARGET_X86_
+    if (treeNode->TypeGet() == TYP_LONG)
+    {
+        assert(op1 != nullptr);
+        noway_assert(op1->OperGet() == GT_LONG);
+        GenTree* loRetVal = op1->gtGetOp1();
+        GenTree* hiRetVal = op1->gtGetOp2();
+        noway_assert((loRetVal->gtRegNum != REG_NA) && (hiRetVal->gtRegNum != REG_NA));
+
+        genConsumeReg(loRetVal);
+        genConsumeReg(hiRetVal);
+        if (loRetVal->gtRegNum != REG_LNGRET_LO)
+        {
+            inst_RV_RV(ins_Copy(targetType), REG_LNGRET_LO, loRetVal->gtRegNum, TYP_INT);
+        }
+        if (hiRetVal->gtRegNum != REG_LNGRET_HI)
+        {
+            inst_RV_RV(ins_Copy(targetType), REG_LNGRET_HI, hiRetVal->gtRegNum, TYP_INT);
+        }
+    }
+    else
+#endif // !defined(_TARGET_X86_)
+    {
+        if (isStructReturn(treeNode))
+        {
+            genStructReturn(treeNode);
+        }
+        else if (targetType != TYP_VOID)
+        {
+            assert(op1 != nullptr);
+            noway_assert(op1->gtRegNum != REG_NA);
+
+            // !! NOTE !! genConsumeReg will clear op1 as GC ref after it has
+            // consumed a reg for the operand. This is because the variable
+            // is dead after return. But we are issuing more instructions
+            // like "profiler leave callback" after this consumption. So
+            // if you are issuing more instructions after this point,
+            // remember to keep the variable live up until the new method
+            // exit point where it is actually dead.
+            genConsumeReg(op1);
+
+            regNumber retReg = varTypeIsFloating(treeNode) ? REG_FLOATRET : REG_INTRET;
+#ifdef _TARGET_X86_
+            if (varTypeIsFloating(treeNode))
+            {
+                if (genIsRegCandidateLocal(op1) && !compiler->lvaTable[op1->gtLclVarCommon.gtLclNum].lvRegister)
+                {
+                    // Store local variable to its home location, if necessary.
+                    if ((op1->gtFlags & GTF_REG_VAL) != 0)
+                    {
+                        op1->gtFlags &= ~GTF_REG_VAL;
+                        inst_TT_RV(ins_Store(op1->gtType, compiler->isSIMDTypeLocalAligned(op1->gtLclVarCommon.gtLclNum)), op1, op1->gtRegNum);
+                    }
+                    // Now, load it to the fp stack.
+                    getEmitter()->emitIns_S(INS_fld, emitTypeSize(op1), op1->AsLclVarCommon()->gtLclNum, 0);
+                }
+                else
+                {
+                    // Spill the value, which should be in a register, then load it to the fp stack.
+                    // TODO-X86-CQ: Deal with things that are already in memory (don't call genConsumeReg yet).
+                    op1->gtFlags |= GTF_SPILL;
+                    regSet.rsSpillTree(op1->gtRegNum, op1);
+                    op1->gtFlags |= GTF_SPILLED;
+                    op1->gtFlags &= ~GTF_SPILL;
+
+                    TempDsc* t = regSet.rsUnspillInPlace(op1);
+                    inst_FS_ST(INS_fld, emitActualTypeSize(op1->gtType), t, 0);
+                    op1->gtFlags &= ~GTF_SPILLED;
+                    compiler->tmpRlsTemp(t);
+                }
+            }
+            else
+#endif // _TARGET_X86_
+            {
+                if (op1->gtRegNum != retReg)
+                {
+                    inst_RV_RV(ins_Copy(targetType), retReg, op1->gtRegNum, targetType);
+                }
+            }
+        }
+    }
+
+#ifdef PROFILING_SUPPORTED
+    // !! Note !!
+    // TODO-AMD64-Unix: If the profiler hook is implemented on *nix, make sure for 2 register returned structs
+    //                  the RAX and RDX needs to be kept alive. Make the necessary changes in lowerxarch.cpp
+    //                  in the handling of the GT_RETURN statement.
+    //                  Such structs containing GC pointers need to be handled by calling gcInfo.gcMarkRegSetNpt
+    //                  for the return registers containing GC refs.
+
+    // There will be a single return block while generating profiler ELT callbacks.
+    //
+    // Reason for not materializing Leave callback as a GT_PROF_HOOK node after GT_RETURN:
+    // In flowgraph and other places assert that the last node of a block marked as
+    // GT_RETURN is either a GT_RETURN or GT_JMP or a tail call.  It would be nice to
+    // maintain such an invariant irrespective of whether profiler hook needed or not.
+    // Also, there is not much to be gained by materializing it as an explicit node.
+    if (compiler->compCurBB == compiler->genReturnBB)
+    {
+        // !! NOTE !!
+        // Since we are invalidating the assumption that we would slip into the epilog
+        // right after the "return", we need to preserve the return reg's GC state
+        // across the call until actual method return.
+        if (varTypeIsGC(compiler->info.compRetType))
+        {
+            gcInfo.gcMarkRegPtrVal(REG_INTRET, compiler->info.compRetType);
+        }
+
+        genProfilingLeaveCallback();
+
+        if (varTypeIsGC(compiler->info.compRetType))
+        {
+            gcInfo.gcMarkRegSetNpt(REG_INTRET);
+        }
+    }
+#endif
+}
 
 /*****************************************************************************
  *
@@ -1650,9 +1903,7 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
 
     case GT_STORE_LCL_FLD:
         {
-#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
             if (!genStoreRegisterReturnInLclVar(treeNode))
-#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
             {
                 noway_assert(targetType != TYP_STRUCT);
                 noway_assert(!treeNode->InReg());
@@ -1676,9 +1927,7 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
 
     case GT_STORE_LCL_VAR:
         {
-#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
             if (!genStoreRegisterReturnInLclVar(treeNode))
-#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
             {
                 noway_assert(targetType != TYP_STRUCT);
                 assert(!varTypeIsFloating(targetType) || (targetType == treeNode->gtGetOp1()->TypeGet()));
@@ -1720,6 +1969,7 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
                         op1->ResetReuseRegVal();
                         containedOp1 = true;
                     }
+
                     if (containedOp1)
                     {
                         // Currently, we assume that the contained source of a GT_STORE_LCL_VAR writing to a register
@@ -1758,302 +2008,7 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
         __fallthrough;
 
     case GT_RETURN:
-        {
-            GenTreePtr op1 = treeNode->gtOp.gtOp1;
-            if (targetType == TYP_VOID)
-            {
-#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
-                if (compiler->info.compRetBuffArg != BAD_VAR_NUM)
-                {
-                    // System V AMD64 spec requires that when a struct is returned by a hidden
-                    // argument the RAX should contain the value of the hidden retbuf arg.
-                    emit->emitIns_R_S(INS_mov, EA_BYREF, REG_RAX, compiler->info.compRetBuffArg, 0);
-                }
-#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
-
-                assert(op1 == nullptr);
-            }
-#if !defined(_TARGET_64BIT_)
-            else if (treeNode->TypeGet() == TYP_LONG)
-            {
-                assert(op1 != nullptr);
-                noway_assert(op1->OperGet() == GT_LONG);
-                GenTree* loRetVal = op1->gtGetOp1();
-                GenTree* hiRetVal = op1->gtGetOp2();
-                noway_assert((loRetVal->gtRegNum != REG_NA) && (hiRetVal->gtRegNum != REG_NA));
-
-                genConsumeReg(loRetVal);
-                genConsumeReg(hiRetVal);
-                if (loRetVal->gtRegNum != REG_LNGRET_LO)
-                {
-                    inst_RV_RV(ins_Copy(targetType), REG_LNGRET_LO, loRetVal->gtRegNum, TYP_INT);
-                }
-                if (hiRetVal->gtRegNum != REG_LNGRET_HI)
-                {
-                    inst_RV_RV(ins_Copy(targetType), REG_LNGRET_HI, hiRetVal->gtRegNum, TYP_INT);
-                }
-            }
-#endif // !defined(_TARGET_64BIT_)
-            else
-            {
-#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
-                if (varTypeIsStruct(treeNode) &&
-                    treeNode->gtOp.gtOp1->OperGet() == GT_LCL_VAR)
-                {
-                    GenTreeLclVarCommon* lclVarPtr = treeNode->gtOp.gtOp1->AsLclVarCommon();
-                    LclVarDsc* varDsc = &(compiler->lvaTable[lclVarPtr->gtLclNum]);
-                    assert(varDsc->lvDontPromote);
-
-                    CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
-                    assert(typeHnd != nullptr);
-
-                    SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
-                    compiler->eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
-                    assert(structDesc.passedInRegisters);
-                    assert(structDesc.eightByteCount == CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
-
-                    regNumber retReg0 = REG_NA;
-                    emitAttr size0 = EA_UNKNOWN;
-                    unsigned offset0 = structDesc.eightByteOffsets[0];
-                    regNumber retReg1 = REG_NA;
-                    emitAttr size1 = EA_UNKNOWN;
-                    unsigned offset1 = structDesc.eightByteOffsets[1];
-
-                    bool firstIntUsed = false;
-                    bool firstFloatUsed = false;
-                    
-                    var_types type0 = TYP_UNKNOWN;
-                    var_types type1 = TYP_UNKNOWN;
-
-                    // Set the first eightbyte data
-                    switch (structDesc.eightByteClassifications[0])
-                    {
-                    case SystemVClassificationTypeInteger:
-                        if (structDesc.eightByteSizes[0] <= 4)
-                        {
-                            retReg0 = REG_INTRET;
-                            size0 = EA_4BYTE;
-                            type0 = TYP_INT;
-                            firstIntUsed = true;
-                        }
-                        else if (structDesc.eightByteSizes[0] <= 8)
-                        {
-                            retReg0 = REG_LNGRET;
-                            size0 = EA_8BYTE;
-                            type0 = TYP_LONG;
-                            firstIntUsed = true;
-                        }
-                        else
-                        {
-                            assert(false && "Bad int type.");
-                        }
-                        break;
-                    case SystemVClassificationTypeIntegerReference:
-                        assert(structDesc.eightByteSizes[0] == REGSIZE_BYTES);
-                        retReg0 = REG_LNGRET;
-                        size0 = EA_GCREF;
-                        type0 = TYP_REF;
-                        firstIntUsed = true;
-                        break;
-                    case SystemVClassificationTypeSSE:
-                        if (structDesc.eightByteSizes[0] <= 4)
-                        {
-                            retReg0 = REG_FLOATRET;
-                            size0 = EA_4BYTE;
-                            type0 = TYP_FLOAT;
-                            firstFloatUsed = true;
-                        }
-                        else if (structDesc.eightByteSizes[0] <= 8)
-                        {
-                            retReg0 = REG_DOUBLERET;
-                            size0 = EA_8BYTE;
-                            type0 = TYP_DOUBLE;
-                            firstFloatUsed = true;
-                        }
-                        else
-                        {
-                            assert(false && "Bat float type."); // Not possible.
-                        }
-                        break;
-                    default:
-                        assert(false && "Bad EightByte classification.");
-                        break;
-                    }
-
-                    // Set the second eight byte data
-                    switch (structDesc.eightByteClassifications[1])
-                    {
-                    case SystemVClassificationTypeInteger:
-                        if (structDesc.eightByteSizes[1] <= 4)
-                        {
-                            if (firstIntUsed)
-                            {
-                                retReg1 = REG_INTRET_1;
-                            }
-                            else
-                            {
-                                retReg1 = REG_INTRET;
-                            }
-                            type1 = TYP_INT;
-                            size1 = EA_4BYTE;
-                        }
-                        else if (structDesc.eightByteSizes[1] <= 8)
-                        {
-                            if (firstIntUsed)
-                            {
-                                retReg1 = REG_LNGRET_1;
-                            }
-                            else
-                            {
-                                retReg1 = REG_LNGRET;
-                            }
-                            type1 = TYP_LONG;
-                            size1 = EA_8BYTE;
-                        }
-                        else
-                        {
-                            assert(false && "Bad int type.");
-                        }
-                        break;
-                    case SystemVClassificationTypeIntegerReference:
-                        assert(structDesc.eightByteSizes[1] == REGSIZE_BYTES);
-                        if (firstIntUsed)
-                        {
-                            retReg1 = REG_LNGRET_1;
-                        }
-                        else
-                        {
-                            retReg1 = REG_LNGRET;
-                        }
-                        type1 = TYP_REF;
-                        size1 = EA_GCREF;
-                        break;
-                    case SystemVClassificationTypeSSE:
-                        if (structDesc.eightByteSizes[1] <= 4)
-                        {
-                            if (firstFloatUsed)
-                            {
-                                retReg1 = REG_FLOATRET_1;
-                            }
-                            else
-                            {
-                                retReg1 = REG_FLOATRET;
-                            }
-                            type1 = TYP_FLOAT;
-                            size1 = EA_4BYTE;
-                        }
-                        else if (structDesc.eightByteSizes[1] <= 8)
-                        {
-                            if (firstFloatUsed)
-                            {
-                                retReg1 = REG_DOUBLERET_1;
-                            }
-                            else
-                            {
-                                retReg1 = REG_DOUBLERET;
-                            }
-                            type1 = TYP_DOUBLE;
-                            size1 = EA_8BYTE;
-                        }
-                        else
-                        {
-                            assert(false && "Bat float type."); // Not possible.
-                        }
-                        break;
-                    default:
-                        assert(false && "Bad EightByte classification.");
-                        break;
-                    }
-
-                    // Move the values into the return registers.
-                    // 
-                    emit->emitIns_R_S(ins_Load(type0), size0, retReg0, lclVarPtr->gtLclNum, offset0);
-                    emit->emitIns_R_S(ins_Load(type1), size1, retReg1, lclVarPtr->gtLclNum, offset1);
-                }
-                else
-#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
-                {
-                    assert(op1 != nullptr);
-                    noway_assert(op1->gtRegNum != REG_NA);
-
-                    // !! NOTE !! genConsumeReg will clear op1 as GC ref after it has
-                    // consumed a reg for the operand. This is because the variable
-                    // is dead after return. But we are issuing more instructions
-                    // like "profiler leave callback" after this consumption. So
-                    // if you are issuing more instructions after this point,
-                    // remember to keep the variable live up until the new method
-                    // exit point where it is actually dead.
-                    genConsumeReg(op1);
-
-                    regNumber retReg = varTypeIsFloating(treeNode) ? REG_FLOATRET : REG_INTRET;
-#ifdef _TARGET_X86_
-                    if (varTypeIsFloating(treeNode))
-                    {
-                        if (genIsRegCandidateLocal(op1) && !compiler->lvaTable[op1->gtLclVarCommon.gtLclNum].lvRegister)
-                        {
-                            // Store local variable to its home location, if necessary.
-                            if ((op1->gtFlags & GTF_REG_VAL) != 0)
-                            {
-                                op1->gtFlags &= ~GTF_REG_VAL;
-                                inst_TT_RV(ins_Store(op1->gtType, compiler->isSIMDTypeLocalAligned(op1->gtLclVarCommon.gtLclNum)), op1, op1->gtRegNum);
-                            }
-                            // Now, load it to the fp stack.
-                            getEmitter()->emitIns_S(INS_fld, emitTypeSize(op1), op1->AsLclVarCommon()->gtLclNum, 0);
-                        }
-                        else
-                        {
-                            // Spill the value, which should be in a register, then load it to the fp stack.
-                            // TODO-X86-CQ: Deal with things that are already in memory (don't call genConsumeReg yet).
-                            op1->gtFlags |= GTF_SPILL;
-                            regSet.rsSpillTree(op1->gtRegNum, op1);
-                            op1->gtFlags |= GTF_SPILLED;
-                            op1->gtFlags &= ~GTF_SPILL;
-
-                            TempDsc* t = regSet.rsUnspillInPlace(op1);
-                            inst_FS_ST(INS_fld, emitActualTypeSize(op1->gtType), t, 0);
-                            op1->gtFlags &= ~GTF_SPILLED;
-                            compiler->tmpRlsTemp(t);
-                        }
-                    }
-                    else
-#endif // _TARGET_X86_
-                    {
-                        if (op1->gtRegNum != retReg)
-                        {
-                            inst_RV_RV(ins_Copy(targetType), retReg, op1->gtRegNum, targetType);
-                        }
-                    }
-                }
-            }
-
-#ifdef PROFILING_SUPPORTED
-            // There will be a single return block while generating profiler ELT callbacks.
-            //
-            // Reason for not materializing Leave callback as a GT_PROF_HOOK node after GT_RETURN:
-            // In flowgraph and other places assert that the last node of a block marked as
-            // GT_RETURN is either a GT_RETURN or GT_JMP or a tail call.  It would be nice to
-            // maintain such an invariant irrespective of whether profiler hook needed or not.
-            // Also, there is not much to be gained by materializing it as an explicit node.
-            if (compiler->compCurBB == compiler->genReturnBB)
-            {
-                // !! NOTE !!
-                // Since we are invalidating the assumption that we would slip into the epilog
-                // right after the "return", we need to preserve the return reg's GC state
-                // across the call until actual method return.
-                if (varTypeIsGC(compiler->info.compRetType))
-                {
-                    gcInfo.gcMarkRegPtrVal(REG_INTRET, compiler->info.compRetType);
-                }
-                
-                genProfilingLeaveCallback();
-
-                if (varTypeIsGC(compiler->info.compRetType))
-                {
-                    gcInfo.gcMarkRegSetNpt(REG_INTRET);
-                }
-            }
-#endif
-        }
+        genReturn(treeNode);
         break;
 
     case GT_LEA:
@@ -2629,7 +2584,6 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
     }
 }
 
-#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
 //------------------------------------------------------------------------
 // genStoreRegisterReturnInLclVar: This method handles storing double register return struct value to a 
 // local homing stack location.
@@ -2638,15 +2592,14 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
 //    treeNode  - the tree which should be homed in local frame stack location.
 //
 // Return Value:
-//    It returns true if this is a struct and storing of the returned
+//    For System V AMD64 sistems it returns true if this is a struct and storing of the returned
 //    register value is handled. It returns false otherwise.
-//
+//    For all other targets returns false.
 
 bool
 CodeGen::genStoreRegisterReturnInLclVar(GenTreePtr treeNode)
 {
-
-
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
     if (varTypeIsStruct(treeNode))
     {
         GenTreeLclVarCommon* lclVarPtr = treeNode->AsLclVarCommon();
@@ -2689,84 +2642,97 @@ CodeGen::genStoreRegisterReturnInLclVar(GenTreePtr treeNode)
         regNumber retReg0 = REG_NA;
         regNumber retReg1 = REG_NA;
 
-        emitAttr size0 = EA_UNKNOWN;
-        emitAttr size1 = EA_UNKNOWN;
-
         unsigned __int8 offset0 = 0;
         unsigned __int8 offset1 = 0;
 
         var_types type0 = TYP_UNKNOWN;
         var_types type1 = TYP_UNKNOWN;
 
-        bool firstIntUsed = false;
-        bool firstFloatUsed = false;
+        getStructTypeOffset(structDesc, &type0, &type1, &offset0, &offset1);
+        getStructReturnRegisters(type0, type1, &retReg0, &retReg1);
+
+        assert(retReg0 != REG_NA && retReg1 != REG_NA);
+
+        getEmitter()->emitIns_S_R(ins_Store(type0), emitTypeSize(type0), retReg0, lclVarPtr->gtLclNum, offset0);
+        getEmitter()->emitIns_S_R(ins_Store(type1), emitTypeSize(type1), retReg1, lclVarPtr->gtLclNum, offset1);
+
+        return true;
+    }
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+
+    return false;
+}
 
-        genGetStructTypeSizeOffset(structDesc, &type0, &type1, &size0, &size1, &offset0, &offset1);
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+//------------------------------------------------------------------------
+// getStructReturnRegisters: Returns the return registers for a specific struct types.
+//
+// Arguments:
+//    type0         - the type of the first eightbyte to be returned.
+//    type1         - the type of the second eightbyte to be returned.
+//    retRegPtr0    - returns the register for the first eightbyte.
+//    retRegPtr1    - returns the register for the second eightbyte.
+//
 
-        if (type0 != TYP_UNKNOWN)
+void
+CodeGen::getStructReturnRegisters(var_types type0,
+                                  var_types type1,
+                                  regNumber* retRegPtr0,
+                                  regNumber* retRegPtr1)
+{
+    *retRegPtr0 = REG_NA;
+    *retRegPtr1 = REG_NA;
+
+    bool firstIntUsed = false;
+    bool firstFloatUsed = false;
+
+    if (type0 != TYP_UNKNOWN)
+    {
+        if (varTypeIsIntegralOrI(type0))
         {
-            if (structDesc.eightByteClassifications[0] == SystemVClassificationTypeIntegerReference ||
-                structDesc.eightByteClassifications[0] == SystemVClassificationTypeInteger)
-            {
-                retReg0 = REG_INTRET;
-                firstIntUsed = true;
-            }
-            else if (structDesc.eightByteClassifications[0] == SystemVClassificationTypeSSE)
+            *retRegPtr0 = REG_INTRET;
+            firstIntUsed = true;
+        }
+        else if (varTypeIsFloating(type0))
+        {
+            *retRegPtr0 = REG_FLOATRET;
+            firstFloatUsed = true;
+        }
+        else
+        {
+            unreached();
+        }
+    }
+
+    if (type1 != TYP_UNKNOWN)
+    {
+        if (varTypeIsIntegralOrI(type1))
+        {
+            if (firstIntUsed)
             {
-                retReg0 = REG_FLOATRET;
-                firstFloatUsed = true;
+                *retRegPtr1 = REG_INTRET_1;
             }
             else
             {
-                assert(false && "Invalid eightbyte type");
+                *retRegPtr1 = REG_INTRET;
             }
         }
-
-        if (type1 != TYP_UNKNOWN)
+        else if (varTypeIsFloating(type1))
         {
-            if (structDesc.eightByteClassifications[1] == SystemVClassificationTypeIntegerReference ||
-                structDesc.eightByteClassifications[1] == SystemVClassificationTypeInteger)
+            if (firstFloatUsed)
             {
-                if (firstIntUsed)
-                {
-                    retReg1 = REG_INTRET_1;
-                }
-                else
-                {
-                    retReg1 = REG_INTRET;
-                }
-            }
-            else if (structDesc.eightByteClassifications[1] == SystemVClassificationTypeSSE)
-            {
-                if (firstFloatUsed)
-                {
-                    retReg1 = REG_FLOATRET_1;
-                }
-                else
-                {
-                    retReg1 = REG_FLOATRET;
-                }
+                *retRegPtr1 = REG_FLOATRET_1;
             }
             else
             {
-                assert(false && "Invalid eightbyte type");
+                *retRegPtr1 = REG_FLOATRET;
             }
         }
-
-        if (retReg0 != REG_NA)
-        {
-            getEmitter()->emitIns_S_R(ins_Store(type0), size0, retReg0, lclVarPtr->gtLclNum, offset0);
-        }
-
-        if (retReg1 != REG_NA)
+        else
         {
-            getEmitter()->emitIns_S_R(ins_Store(type1), size1, retReg1, lclVarPtr->gtLclNum, offset1);
+            unreached();
         }
-
-        return true;
     }
-
-    return false;
 }
 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
 
@@ -5032,12 +4998,12 @@ void CodeGen::genConsumePutStructArgStk(GenTreePutArgStk* putArgNode, regNumber
             GenTreeLclVarCommon* lclNode = src->AsLclVarCommon();
 
             // Generate LEA instruction to load the LclVar address in RSI.
-            getEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, srcReg, lclNode->gtLclNum, 0);
+            getEmitter()->emitIns_R_S(INS_lea, emitTypeSize(src), srcReg, lclNode->gtLclNum, 0);
         }
         else
         {
             assert(src->gtRegNum != REG_NA);
-            getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, srcReg, src->gtRegNum);
+            getEmitter()->emitIns_R_R(INS_mov, emitTypeSize(src), srcReg, src->gtRegNum);
         }
     }
 
@@ -5955,29 +5921,23 @@ void CodeGen::genCallInstruction(GenTreePtr node)
 
 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
 //------------------------------------------------------------------------
-// genGetStructTypeSizeOffset: Gets the type, size and offset of the eightbytes of a struct for System V systems.
+// getStructTypeOffset: Gets the type, size and offset of the eightbytes of a struct for System V systems.
 //
 // Arguments:
 //    'structDesc' struct description
 //    'type0'   returns the type of the first eightbyte.
 //    'type1'   returns the type of the second eightbyte.
-//    'size0'   returns the size of the first eightbyte.
-//    'size1'   returns the size of the second eightbyte.
 //    'offset0' returns the offset of the first eightbyte.
 //    'offset1' returns the offset of the second eightbyte.
 //
 
-void CodeGen::genGetStructTypeSizeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
+void CodeGen::getStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
                                          var_types* type0, 
                                          var_types* type1, 
-                                         emitAttr* size0, 
-                                         emitAttr* size1,
                                          unsigned __int8* offset0,
                                          unsigned __int8* offset1)
 {
-    *size0 = EA_UNKNOWN;
     *offset0 = structDesc.eightByteOffsets[0];
-    *size1 = EA_UNKNOWN;
     *offset1 = structDesc.eightByteOffsets[1];
 
     *type0 = TYP_UNKNOWN;
@@ -5986,97 +5946,13 @@ void CodeGen::genGetStructTypeSizeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_
     // Set the first eightbyte data
     if (structDesc.eightByteCount >= 1)
     {
-        switch (structDesc.eightByteClassifications[0])
-        {
-        case SystemVClassificationTypeInteger:
-            if (structDesc.eightByteSizes[0] <= 4)
-            {
-                *size0 = EA_4BYTE;
-                *type0 = TYP_INT;
-            }
-            else if (structDesc.eightByteSizes[0] <= 8)
-            {
-                *size0 = EA_8BYTE;
-                *type0 = TYP_LONG;
-            }
-            else
-            {
-                assert(false && "Bad int type.");
-            }
-            break;
-        case SystemVClassificationTypeIntegerReference:
-            assert(structDesc.eightByteSizes[0] == REGSIZE_BYTES);
-            *size0 = EA_GCREF;
-            *type0 = TYP_REF;
-            break;
-        case SystemVClassificationTypeSSE:
-            if (structDesc.eightByteSizes[0] <= 4)
-            {
-                *size0 = EA_4BYTE;
-                *type0 = TYP_FLOAT;
-            }
-            else if (structDesc.eightByteSizes[0] <= 8)
-            {
-                *size0 = EA_8BYTE;
-                *type0 = TYP_DOUBLE;
-            }
-            else
-            {
-                assert(false && "Bat float type."); // Not possible.
-            }
-            break;
-        default:
-            assert(false && "Bad EightByte classification.");
-            break;
-        }
+        *type0 = compiler->getEightByteType(structDesc, 0);
     }
 
     // Set the second eight byte data
     if (structDesc.eightByteCount == 2)
     {
-        switch (structDesc.eightByteClassifications[1])
-        {
-        case SystemVClassificationTypeInteger:
-            if (structDesc.eightByteSizes[1] <= 4)
-            {
-                *type1 = TYP_INT;
-                *size1 = EA_4BYTE;
-            }
-            else if (structDesc.eightByteSizes[1] <= 8)
-            {
-                *type1 = TYP_LONG;
-                *size1 = EA_8BYTE;
-            }
-            else
-            {
-                assert(false && "Bad int type.");
-            }
-            break;
-        case SystemVClassificationTypeIntegerReference:
-            assert(structDesc.eightByteSizes[1] == REGSIZE_BYTES);
-            *type1 = TYP_REF;
-            *size1 = EA_GCREF;
-            break;
-        case SystemVClassificationTypeSSE:
-            if (structDesc.eightByteSizes[1] <= 4)
-            {
-                *type1 = TYP_FLOAT;
-                *size1 = EA_4BYTE;
-            }
-            else if (structDesc.eightByteSizes[1] <= 8)
-            {
-                *type1 = TYP_DOUBLE;
-                *size1 = EA_8BYTE;
-            }
-            else
-            {
-                assert(false && "Bat float type."); // Not possible.
-            }
-            break;
-        default:
-            assert(false && "Bad EightByte classification.");
-            break;
-        }
+        *type1 = compiler->getEightByteType(structDesc, 1);
     }
 }
 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
@@ -6203,15 +6079,13 @@ void CodeGen::genJmpMethod(GenTreePtr jmp)
             compiler->eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
             assert(structDesc.passedInRegisters);
 
-            emitAttr size0 = EA_UNKNOWN;
-            emitAttr size1 = EA_UNKNOWN;
             unsigned __int8 offset0 = 0;
             unsigned __int8 offset1 = 0;
             var_types type0 = TYP_UNKNOWN;
             var_types type1 = TYP_UNKNOWN;
 
             // Get the eightbyte data
-            genGetStructTypeSizeOffset(structDesc, &type0, &type1, &size0, &size1, &offset0, &offset1);
+            getStructTypeOffset(structDesc, &type0, &type1, &offset0, &offset1);
 
             // Move the values into the right registers.
             // 
@@ -6222,14 +6096,14 @@ void CodeGen::genJmpMethod(GenTreePtr jmp)
             // and after which reg life and gc info will be recomputed for the new block in genCodeForBBList().
             if (type0 != TYP_UNKNOWN)
             {
-                getEmitter()->emitIns_R_S(ins_Load(type0), size0, varDsc->lvArgReg, varNum, offset0);
+                getEmitter()->emitIns_R_S(ins_Load(type0), emitTypeSize(type0), varDsc->lvArgReg, varNum, offset0);
                 regSet.rsMaskVars |= genRegMask(varDsc->lvArgReg);
                 gcInfo.gcMarkRegPtrVal(varDsc->lvArgReg, type0);
             }
             
             if (type1 != TYP_UNKNOWN)
             {
-                getEmitter()->emitIns_R_S(ins_Load(type1), size1, varDsc->lvOtherArgReg, varNum, offset1);
+                getEmitter()->emitIns_R_S(ins_Load(type1), emitTypeSize(type1), varDsc->lvOtherArgReg, varNum, offset1);
                 regSet.rsMaskVars |= genRegMask(varDsc->lvOtherArgReg);
                 gcInfo.gcMarkRegPtrVal(varDsc->lvOtherArgReg, type1);
             }
@@ -8113,6 +7987,7 @@ CodeGen::genPutArgStk(GenTreePtr treeNode)
 }
 
 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
+
 //---------------------------------------------------------------------
 // genPutStructArgStk - generate code for copying a struct arg on the stack by value.
 //                In case there are references to heap object in the struct,
@@ -8172,9 +8047,11 @@ CodeGen::genPutStructArgStk(GenTreePtr treeNode, unsigned baseVarNum)
         // They may now contain gc pointers (depending on their type; gcMarkRegPtrVal will "do the right thing").
         genConsumePutStructArgStk(putArgStk, REG_RDI, REG_RSI, REG_NA, baseVarNum);
         GenTreePtr   dstAddr = putArgStk;
-        GenTreePtr   srcAddr = putArgStk->gtOp.gtOp1;
+        GenTreePtr   src = putArgStk->gtOp.gtOp1;
+        assert(src->OperGet() == GT_LDOBJ);
+        GenTreePtr   srcAddr = src->gtGetOp1();
+
         gcInfo.gcMarkRegPtrVal(REG_RSI, srcAddr->TypeGet());
-        gcInfo.gcMarkRegPtrVal(REG_RDI, dstAddr->TypeGet());
 
         unsigned slots = putArgStk->gtNumSlots;
 
@@ -8219,28 +8096,38 @@ CodeGen::genPutStructArgStk(GenTreePtr treeNode, unsigned baseVarNum)
                     }
                 }
                 break;
+
+            case TYPE_GC_REF:    // Is an object ref
+            case TYPE_GC_BYREF:  // Is an interior pointer - promote it but don't scan it
+                {
+                    // We have a GC (byref or ref) pointer
+                    // TODO-Amd64-Unix: Here a better solution (for code size and CQ) would be to use movsq instruction,
+                    // but the logic for emitting a GC info record is not available (it is internal for the emitter only.)
+                    // See emitGCVarLiveUpd function. If we could call it separately, we could do instGen(INS_movsq); and emission of gc info.
+
+                    getEmitter()->emitIns_R_AR(ins_Load(srcAddr->TypeGet()), emitTypeSize(srcAddr), REG_RCX, REG_RSI, 0);
+                    getEmitter()->emitIns_S_R(ins_Store(srcAddr->TypeGet()),
+                                                        emitTypeSize(srcAddr),
+                                                        REG_RCX,
+                                                        baseVarNum,
+                                                        ((copiedSlots + putArgStk->gtSlotNum) * TARGET_POINTER_SIZE));
+
+                    getEmitter()->emitIns_R_I(INS_add, emitTypeSize(srcAddr), REG_RSI, TARGET_POINTER_SIZE);
+                    getEmitter()->emitIns_R_I(INS_add, EA_8BYTE, REG_RDI, TARGET_POINTER_SIZE);
+                    copiedSlots++;
+                    gcPtrCount--;
+                    i++;
+                }
+                break;
+
             default:
-                // We have a GC pointer
-                // TODO-Amd64-Unix: Here a better solution (for code size and CQ) would be to use movsq instruction,
-                // but the logic for emitting a GC info record is not available (it is internal for the emitter only.)
-                // See emitGCVarLiveUpd function. If we could call it separately, we could do instGen(INS_movsq); and emission of gc info.
-
-                getEmitter()->emitIns_R_AR(ins_Load(TYP_REF), EA_GCREF, REG_RCX, REG_RSI, 0);
-                getEmitter()->emitIns_S_R(ins_Store(TYP_REF),
-                                          EA_GCREF, 
-                                          REG_RCX, 
-                                          baseVarNum,
-                                          ((copiedSlots + putArgStk->gtSlotNum) * TARGET_POINTER_SIZE)); 
-                getEmitter()->emitIns_R_I(INS_add, EA_8BYTE, REG_RSI, TARGET_POINTER_SIZE);
-                getEmitter()->emitIns_R_I(INS_add, EA_8BYTE, REG_RDI, TARGET_POINTER_SIZE);
-                copiedSlots++;
-                gcPtrCount--;
-                i++;
+                unreached();
+                break;
             }
         }
 
+        assert(gcPtrCount == 0);
         gcInfo.gcMarkRegSetNpt(RBM_RSI);
-        gcInfo.gcMarkRegSetNpt(RBM_RDI);
     }
 }
 #endif //defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
index b57f094..8f5829b 100644 (file)
@@ -5737,6 +5737,9 @@ var_types Compiler::GetTypeFromClassificationAndSizes(SystemVClassificationType
     case SystemVClassificationTypeIntegerReference:
         type = TYP_REF;
         break;
+    case SystemVClassificationTypeIntegerByRef:
+        type = TYP_BYREF;
+        break;
     case SystemVClassificationTypeSSE:
         if (size <= 4)
         {
@@ -5794,6 +5797,10 @@ var_types Compiler::getEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASS
         assert(len == REGSIZE_BYTES);
         eightByteType = TYP_REF;
         break;
+    case SystemVClassificationTypeIntegerByRef:
+        assert(len == REGSIZE_BYTES);
+        eightByteType = TYP_BYREF;
+        break;
     case SystemVClassificationTypeSSE:
         if (structDesc.eightByteSizes[slotNum] <= 4)
         {
index 55d3cae..0f9deac 100644 (file)
@@ -977,14 +977,15 @@ void Compiler::dumpSystemVClassificationType(SystemVClassificationType ct)
 {
     switch (ct)
     {
-    case SystemVClassificationTypeUnknown:              printf("UNKNOWN");          break;
-    case SystemVClassificationTypeStruct:               printf("Struct");           break;
-    case SystemVClassificationTypeNoClass:              printf("NoClass");          break;
-    case SystemVClassificationTypeMemory:               printf("Memory");           break;
-    case SystemVClassificationTypeInteger:              printf("Integer");          break;
-    case SystemVClassificationTypeIntegerReference:     printf("IntegerReference"); break;
-    case SystemVClassificationTypeSSE:                  printf("SSE");              break;
-    default:                                            printf("ILLEGAL");          break;
+    case SystemVClassificationTypeUnknown:              printf("UNKNOWN");              break;
+    case SystemVClassificationTypeStruct:               printf("Struct");               break;
+    case SystemVClassificationTypeNoClass:              printf("NoClass");              break;
+    case SystemVClassificationTypeMemory:               printf("Memory");               break;
+    case SystemVClassificationTypeInteger:              printf("Integer");              break;
+    case SystemVClassificationTypeIntegerReference:     printf("IntegerReference");     break;
+    case SystemVClassificationTypeIntegerByRef:         printf("IntegerByReference");   break;
+    case SystemVClassificationTypeSSE:                  printf("SSE");                  break;
+    default:                                            printf("ILLEGAL");              break;
     }
 }
 #endif // DEBUG
index afe8aaf..9e6d787 100644 (file)
@@ -666,16 +666,16 @@ void                Compiler::lvaInitUserArgs(InitVarDscInfo *      varDscInfo)
 
                 for (unsigned int i = 0; i < structDesc.eightByteCount; i++)
                 {
-                    switch (structDesc.eightByteClassifications[i])
+                    if (structDesc.IsIntegralSlot(i))
                     {
-                    case SystemVClassificationTypeInteger:
-                    case SystemVClassificationTypeIntegerReference:
                         intRegCount++;
-                        break;
-                    case SystemVClassificationTypeSSE:
+                    }
+                    else if (structDesc.IsSseSlot(i))
+                    {
                         floatRegCount++;
-                        break;
-                    default:
+                    }
+                    else
+                    {
                         assert(false && "Invalid eightbyte classification type.");
                         break;
                     }
index dc9cff4..02747fb 100644 (file)
@@ -298,23 +298,32 @@ void Lowering::TreeNodeInfoInit(GenTree* stmt)
 #endif // !defined(_TARGET_64BIT_)
             {
 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
-                if (varTypeIsStruct(tree) &&
-                    tree->gtOp.gtOp1->OperGet() == GT_LCL_VAR)
+                if (varTypeIsStruct(tree))
                 {
+                    noway_assert((tree->gtOp.gtOp1->OperGet() == GT_LCL_VAR) ||
+                                 (tree->gtOp.gtOp1->OperGet() == GT_CALL));
+
+                    if (tree->gtOp.gtOp1->OperGet() == GT_LCL_VAR)
+                    {
 #ifdef DEBUG
-                    GenTreeLclVarCommon* lclVarPtr = tree->gtOp.gtOp1->AsLclVarCommon();
-                    LclVarDsc* varDsc = &(compiler->lvaTable[lclVarPtr->gtLclNum]);
-                    assert(varDsc->lvDontPromote);
+                        GenTreeLclVarCommon* lclVarPtr = tree->gtOp.gtOp1->AsLclVarCommon();
+                        LclVarDsc* varDsc = &(compiler->lvaTable[lclVarPtr->gtLclNum]);
+                        assert(varDsc->lvDontPromote);
 #endif // DEBUG
-                    // If this is a two eightbyte return, make the var
-                    // contained by the return expression. The code gen will put
-                    // the values in the right registers for return.
-                    info->srcCount = (tree->TypeGet() == TYP_VOID) ? 0 : 1;
-                    info->dstCount = 0;
-                    MakeSrcContained(tree, tree->gtOp.gtOp1);
-                    break;
+                        // If this is a two eightbyte return, make the var
+                        // contained by the return expression. The code gen will put
+                        // the values in the right registers for return.
+                        info->srcCount = (tree->TypeGet() == TYP_VOID) ? 0 : 1;
+                        info->dstCount = 0;
+                        MakeSrcContained(tree, tree->gtOp.gtOp1);
+                        break;
+                    }
+
+                    // If the return gtOp1 is GT_CALL, just fallthrough. The return registers should already be set properly by the GT_CALL.
                 }
 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+                // TODO-AMD64-Unix: When the GT_CALL for multi-register return structs is changed to use 2 destinations,
+                // change the code below to use 2 src for such op1s (this is the case of op1 being a GT_CALL).
                 info->srcCount = (tree->TypeGet() == TYP_VOID) ? 0 : 1;
                 info->dstCount = 0;
 
index 0936151..846332c 100644 (file)
@@ -3455,12 +3455,11 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
                 {
                     for (unsigned int i = 0; i < structDesc.eightByteCount; i++)
                     {
-                        if (structDesc.eightByteClassifications[i] == SystemVClassificationTypeInteger ||
-                            structDesc.eightByteClassifications[i] == SystemVClassificationTypeIntegerReference)
+                        if (structDesc.IsIntegralSlot(i))
                         {
                             structIntRegs++;
                         }
-                        else if (structDesc.eightByteClassifications[i] == SystemVClassificationTypeSSE)
+                        else if (structDesc.IsSseSlot(i))
                         {
                             structFloatRegs++;
                         }
@@ -3552,8 +3551,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
                 unsigned int curFloatReg = nextFltArgRegNum;
                 for (unsigned int i = 0; i < structDesc.eightByteCount; i++)
                 {
-                    if (structDesc.eightByteClassifications[i] == SystemVClassificationTypeInteger ||
-                        structDesc.eightByteClassifications[i] == SystemVClassificationTypeIntegerReference)
+                    if (structDesc.IsIntegralSlot(i))
                     {
                         if (i == 0)
                         {
@@ -3582,7 +3580,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* callNode)
 
                         curIntReg++;
                     }
-                    else if (structDesc.eightByteClassifications[i] == SystemVClassificationTypeSSE)
+                    else if (structDesc.IsSseSlot(i))
                     {
                         if (i == 0)
                         {
index 7837e51..803d5f2 100644 (file)
@@ -144,7 +144,8 @@ public:
                 if (eightByteSize == 8)
                 {
                     _ASSERTE((eightByteClassification == SystemVClassificationTypeInteger) ||
-                             (eightByteClassification == SystemVClassificationTypeIntegerReference));
+                             (eightByteClassification == SystemVClassificationTypeIntegerReference) ||
+                             (eightByteClassification == SystemVClassificationTypeIntegerByRef));
 
                     _ASSERTE(IS_ALIGNED((SIZE_T)genRegDest, 8));
                     *(UINT64*)genRegDest = *(UINT64*)src;
@@ -193,7 +194,8 @@ public:
 
             if (eightByteClassification != SystemVClassificationTypeSSE)
             {
-                if (eightByteClassification == SystemVClassificationTypeIntegerReference)
+                if ((eightByteClassification == SystemVClassificationTypeIntegerReference) ||
+                    (eightByteClassification == SystemVClassificationTypeIntegerByRef))
                 {
                     _ASSERTE(eightByteSize == 8);
                     _ASSERTE(IS_ALIGNED((SIZE_T)genRegDest, 8));
index 97b58cc..c79b2a3 100644 (file)
@@ -985,6 +985,7 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset()
                 {
                     case SystemVClassificationTypeInteger:
                     case SystemVClassificationTypeIntegerReference:
+                    case SystemVClassificationTypeIntegerByRef:
                         cGenRegs++;
                         break;
                     case SystemVClassificationTypeSSE:
index 519ccc2..a8706dc 100644 (file)
@@ -2583,7 +2583,8 @@ bool CEEInfo::getSystemVAmd64PassStructInRegisterDescriptor(
     // Make sure this is a value type.
     if (th.IsValueType())
     {
-        _ASSERTE(CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeStruct);
+        _ASSERTE((CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeStruct) ||
+                 (CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeTypedReference));
 
         // The useNativeLayout in this case tracks whether the classification
         // is for a native layout of the struct or not.
index f06138a..d423b09 100644 (file)
@@ -2288,14 +2288,16 @@ const char* GetSystemVClassificationTypeName(SystemVClassificationType t)
 {
     switch (t)
     {
-    case SystemVClassificationTypeUnknown:          return "Unknown";
-    case SystemVClassificationTypeStruct:           return "Struct";
-    case SystemVClassificationTypeNoClass:          return "NoClass";
-    case SystemVClassificationTypeMemory:           return "Memory";
-    case SystemVClassificationTypeInteger:          return "Integer";
-    case SystemVClassificationTypeIntegerReference: return "IntegerReference";
-    case SystemVClassificationTypeSSE:              return "SSE";
-    default:                                        return "ERROR";
+    case SystemVClassificationTypeUnknown:              return "Unknown";
+    case SystemVClassificationTypeStruct:               return "Struct";
+    case SystemVClassificationTypeNoClass:              return "NoClass";
+    case SystemVClassificationTypeMemory:               return "Memory";
+    case SystemVClassificationTypeInteger:              return "Integer";
+    case SystemVClassificationTypeIntegerReference:     return "IntegerReference";
+    case SystemVClassificationTypeIntegerByRef:         return "IntegerByReference";
+    case SystemVClassificationTypeSSE:                  return "SSE";
+    case SystemVClassificationTypeTypedReference:       return "TypedReference";
+    default:                                            return "ERROR";
     }
 };
 #endif // _DEBUG && LOGGING
@@ -2320,6 +2322,7 @@ static SystemVClassificationType ReClassifyField(SystemVClassificationType origi
 {
     _ASSERTE((newFieldClassification == SystemVClassificationTypeInteger) ||
              (newFieldClassification == SystemVClassificationTypeIntegerReference) ||
+             (newFieldClassification == SystemVClassificationTypeIntegerByRef) ||
              (newFieldClassification == SystemVClassificationTypeSSE));
 
     switch (newFieldClassification)
@@ -2350,6 +2353,11 @@ static SystemVClassificationType ReClassifyField(SystemVClassificationType origi
         _ASSERTE(originalClassification == SystemVClassificationTypeIntegerReference);
         return SystemVClassificationTypeIntegerReference;
 
+    case SystemVClassificationTypeIntegerByRef:
+        // IntegerByReference can only merge with IntegerByReference.
+        _ASSERTE(originalClassification == SystemVClassificationTypeIntegerByRef);
+        return SystemVClassificationTypeIntegerByRef;
+
     default:
         _ASSERTE(false); // Unexpected type.
         return SystemVClassificationTypeUnknown;
@@ -2425,7 +2433,6 @@ bool MethodTable::ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassi
         LPCUTF8 fieldName;
         pField->GetName_NoThrow(&fieldName);
 #endif // _DEBUG
-
         if (fieldClassificationType == SystemVClassificationTypeStruct)
         {
             TypeHandle th = pField->GetApproxFieldTypeHandleThrowing();
@@ -2458,6 +2465,67 @@ bool MethodTable::ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassi
             continue;
         }
 
+        if (fieldClassificationType == SystemVClassificationTypeTypedReference || 
+            CorInfoType2UnixAmd64Classification(GetClass_NoLogging()->GetInternalCorElementType()) == SystemVClassificationTypeTypedReference)
+        {
+            // The TypedReference is a very special type.
+            // In source/metadata it has two fields - Type and Value and both are defined of type IntPtr.
+            // When the VM creates a layout of the type it changes the type of the Value to ByRef type and the
+            // type of the Type field is left to IntPtr (TYPE_I internally - native int type.)
+            // This requires a special treatment of this type. The code below handles the both fields (and this entire type).
+
+            for (unsigned i = 0; i < 2; i++)
+            {
+                fieldSize = 8;
+                fieldOffset = (i == 0 ? 0 : 8);
+                normalizedFieldOffset = fieldOffset + startOffsetOfStruct;
+                fieldClassificationType = (i == 0 ? SystemVClassificationTypeIntegerByRef : SystemVClassificationTypeInteger);
+                if ((normalizedFieldOffset % fieldSize) != 0)
+                {
+                    // The spec requires that struct values on the stack from register passed fields expects
+                    // those fields to be at their natural alignment.
+
+                    LOG((LF_JIT, LL_EVERYTHING, "     %*sxxxx Field %d %s: offset %d (normalized %d), size %d not at natural alignment; not enregistering struct\n",
+                        nestingLevel * 5, "", fieldNum, fieldNum, (i == 0 ? "Value" : "Type"), fieldOffset, normalizedFieldOffset, fieldSize));
+                    return false;
+                }
+
+                helperPtr->largestFieldOffset = (int)normalizedFieldOffset;
+
+                // Set the data for a new field.
+
+                // The new field classification must not have been initialized yet.
+                _ASSERTE(helperPtr->fieldClassifications[helperPtr->currentUniqueOffsetField] == SystemVClassificationTypeNoClass);
+
+                // There are only a few field classifications that are allowed.
+                _ASSERTE((fieldClassificationType == SystemVClassificationTypeInteger) ||
+                    (fieldClassificationType == SystemVClassificationTypeIntegerReference) ||
+                    (fieldClassificationType == SystemVClassificationTypeIntegerByRef) ||
+                    (fieldClassificationType == SystemVClassificationTypeSSE));
+
+                helperPtr->fieldClassifications[helperPtr->currentUniqueOffsetField] = fieldClassificationType;
+                helperPtr->fieldSizes[helperPtr->currentUniqueOffsetField] = fieldSize;
+                helperPtr->fieldOffsets[helperPtr->currentUniqueOffsetField] = normalizedFieldOffset;
+
+                LOG((LF_JIT, LL_EVERYTHING, "     %*s**** Field %d %s: offset %d (normalized %d), size %d, currentUniqueOffsetField %d, field type classification %s, chosen field classification %s\n",
+                    nestingLevel * 5, "", fieldNum, (i == 0 ? "Value" : "Type"), fieldOffset, normalizedFieldOffset, fieldSize, helperPtr->currentUniqueOffsetField,
+                    GetSystemVClassificationTypeName(fieldClassificationType),
+                    GetSystemVClassificationTypeName(helperPtr->fieldClassifications[helperPtr->currentUniqueOffsetField])));
+
+                helperPtr->currentUniqueOffsetField++;
+                _ASSERTE(helperPtr->currentUniqueOffsetField < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT);
+#ifdef _DEBUG
+                ++fieldNum;
+#endif // _DEBUG
+            }
+
+            // Both fields of the special TypedReference struct are handled.
+            pField = pFieldEnd;
+
+            // Done classifying the System.TypedReference struct fields.
+            continue;
+        }
+
         if ((normalizedFieldOffset % fieldSize) != 0)
         {
             // The spec requires that struct values on the stack from register passed fields expects
@@ -2522,6 +2590,7 @@ bool MethodTable::ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassi
         // There are only a few field classifications that are allowed.
         _ASSERTE((fieldClassificationType == SystemVClassificationTypeInteger) ||
                  (fieldClassificationType == SystemVClassificationTypeIntegerReference) ||
+                 (fieldClassificationType == SystemVClassificationTypeIntegerByRef) ||
                  (fieldClassificationType == SystemVClassificationTypeSSE));
 
         helperPtr->fieldClassifications[helperPtr->currentUniqueOffsetField] = fieldClassificationType;
@@ -2589,6 +2658,7 @@ bool MethodTable::ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassin
             nestingLevel * 5, "", this->GetDebugClassName()));
         return false;
     }
+
 #ifdef _DEBUG
     LOG((LF_JIT, LL_EVERYTHING, "%*s**** Classify for native struct %s (%p), startOffset %d, total struct size %d\n",
         nestingLevel * 5, "", this->GetDebugClassName(), this, startOffsetOfStruct, helperPtr->structSize));
@@ -2926,6 +2996,7 @@ bool MethodTable::ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassin
         // There are only a few field classifications that are allowed.
         _ASSERTE((fieldClassificationType == SystemVClassificationTypeInteger) ||
             (fieldClassificationType == SystemVClassificationTypeIntegerReference) ||
+            (fieldClassificationType == SystemVClassificationTypeIntegerByRef) ||
             (fieldClassificationType == SystemVClassificationTypeSSE));
 
         helperPtr->fieldClassifications[helperPtr->currentUniqueOffsetField] = fieldClassificationType;
@@ -3023,7 +3094,9 @@ void  MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe
             else if ((helperPtr->eightByteClassifications[currentEightByte] == SystemVClassificationTypeInteger) ||
                 (fieldClassificationType == SystemVClassificationTypeInteger))
             {
-                _ASSERTE(fieldClassificationType != SystemVClassificationTypeIntegerReference);
+                _ASSERTE((fieldClassificationType != SystemVClassificationTypeIntegerReference) && 
+                    (fieldClassificationType != SystemVClassificationTypeIntegerByRef));
+
                 helperPtr->eightByteClassifications[currentEightByte] = SystemVClassificationTypeInteger;
             }
             else if ((helperPtr->eightByteClassifications[currentEightByte] == SystemVClassificationTypeIntegerReference) ||
@@ -3031,6 +3104,11 @@ void  MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe
             {
                 helperPtr->eightByteClassifications[currentEightByte] = SystemVClassificationTypeIntegerReference;
             }
+            else if ((helperPtr->eightByteClassifications[currentEightByte] == SystemVClassificationTypeIntegerByRef) ||
+                (fieldClassificationType == SystemVClassificationTypeIntegerByRef))
+            {
+                helperPtr->eightByteClassifications[currentEightByte] = SystemVClassificationTypeIntegerByRef;
+            }
             else
             {
                 helperPtr->eightByteClassifications[currentEightByte] = SystemVClassificationTypeSSE;
index a7cfce7..534cbd3 100644 (file)
@@ -630,43 +630,43 @@ inline
 SystemVClassificationType CorInfoType2UnixAmd64Classification(CorElementType eeType)
 {
     static const SystemVClassificationType toSystemVAmd64ClassificationTypeMap[] = {
-        SystemVClassificationTypeUnknown,           // ELEMENT_TYPE_END
-        SystemVClassificationTypeUnknown,           // ELEMENT_TYPE_VOID
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_BOOLEAN
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_CHAR
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_I1
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_U1
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_I2
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_U2
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_I4
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_U4
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_I8
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_U8
-        SystemVClassificationTypeSSE,               // ELEMENT_TYPE_R4
-        SystemVClassificationTypeSSE,               // ELEMENT_TYPE_R8
-        SystemVClassificationTypeIntegerReference,  // ELEMENT_TYPE_STRING
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_PTR
-        SystemVClassificationTypeIntegerReference,  // ELEMENT_TYPE_BYREF
-        SystemVClassificationTypeStruct,            // ELEMENT_TYPE_VALUETYPE
-        SystemVClassificationTypeIntegerReference,  // ELEMENT_TYPE_CLASS
-        SystemVClassificationTypeIntegerReference,  // ELEMENT_TYPE_VAR              - (type variable)
-        SystemVClassificationTypeIntegerReference,  // ELEMENT_TYPE_ARRAY
-        SystemVClassificationTypeIntegerReference,  // ELEMENT_TYPE_GENERICINST
-        SystemVClassificationTypeStruct,            // ELEMENT_TYPE_TYPEDBYREF
-        SystemVClassificationTypeUnknown,           // ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_I
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_U
-        SystemVClassificationTypeUnknown,           // ELEMENT_TYPE_R_UNSUPPORTED
+        SystemVClassificationTypeUnknown,               // ELEMENT_TYPE_END
+        SystemVClassificationTypeUnknown,               // ELEMENT_TYPE_VOID
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_BOOLEAN
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_CHAR
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_I1
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_U1
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_I2
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_U2
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_I4
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_U4
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_I8
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_U8
+        SystemVClassificationTypeSSE,                   // ELEMENT_TYPE_R4
+        SystemVClassificationTypeSSE,                   // ELEMENT_TYPE_R8
+        SystemVClassificationTypeIntegerReference,      // ELEMENT_TYPE_STRING
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_PTR
+        SystemVClassificationTypeIntegerByRef,          // ELEMENT_TYPE_BYREF
+        SystemVClassificationTypeStruct,                // ELEMENT_TYPE_VALUETYPE
+        SystemVClassificationTypeIntegerReference,      // ELEMENT_TYPE_CLASS
+        SystemVClassificationTypeIntegerReference,      // ELEMENT_TYPE_VAR (type variable)
+        SystemVClassificationTypeIntegerReference,      // ELEMENT_TYPE_ARRAY
+        SystemVClassificationTypeIntegerReference,      // ELEMENT_TYPE_GENERICINST
+        SystemVClassificationTypeTypedReference,        // ELEMENT_TYPE_TYPEDBYREF
+        SystemVClassificationTypeUnknown,               // ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_I
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_U
+        SystemVClassificationTypeUnknown,               // ELEMENT_TYPE_R_UNSUPPORTED
 
         // put the correct type when we know our implementation
-        SystemVClassificationTypeInteger,           // ELEMENT_TYPE_FNPTR
-        SystemVClassificationTypeIntegerReference,  // ELEMENT_TYPE_OBJECT
-        SystemVClassificationTypeIntegerReference,  // ELEMENT_TYPE_SZARRAY
-        SystemVClassificationTypeIntegerReference,  // ELEMENT_TYPE_MVAR
-
-        SystemVClassificationTypeUnknown,           // ELEMENT_TYPE_CMOD_REQD
-        SystemVClassificationTypeUnknown,           // ELEMENT_TYPE_CMOD_OPT
-        SystemVClassificationTypeUnknown,           // ELEMENT_TYPE_INTERNAL
+        SystemVClassificationTypeInteger,               // ELEMENT_TYPE_FNPTR
+        SystemVClassificationTypeIntegerReference,      // ELEMENT_TYPE_OBJECT
+        SystemVClassificationTypeIntegerReference,      // ELEMENT_TYPE_SZARRAY
+        SystemVClassificationTypeIntegerReference,      // ELEMENT_TYPE_MVAR
+
+        SystemVClassificationTypeUnknown,               // ELEMENT_TYPE_CMOD_REQD
+        SystemVClassificationTypeUnknown,               // ELEMENT_TYPE_CMOD_OPT
+        SystemVClassificationTypeUnknown,               // ELEMENT_TYPE_INTERNAL
     };
 
     _ASSERTE(sizeof(toSystemVAmd64ClassificationTypeMap) == ELEMENT_TYPE_MAX);
@@ -674,7 +674,9 @@ SystemVClassificationType CorInfoType2UnixAmd64Classification(CorElementType eeT
     // spot check of the map
     _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_I4] == SystemVClassificationTypeInteger);
     _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_PTR] == SystemVClassificationTypeInteger);
-    _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_TYPEDBYREF] == SystemVClassificationTypeStruct);
+    _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_VALUETYPE] == SystemVClassificationTypeStruct);
+    _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_TYPEDBYREF] == SystemVClassificationTypeTypedReference);
+    _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_BYREF] == SystemVClassificationTypeIntegerByRef);
 
     return (((int)eeType) < ELEMENT_TYPE_MAX) ? (toSystemVAmd64ClassificationTypeMap[eeType]) : SystemVClassificationTypeUnknown;
 };
index 705ae83..83b5eed 100644 (file)
@@ -7348,7 +7348,8 @@ void STDCALL OnHijackStructInRegsWorker(HijackArgs * pArgs)
     int orefCount = 0;
     for (int i = 0; i < eeClass->GetNumberEightBytes(); i++)
     {
-        if (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerReference)
+        if ((eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerReference) ||
+            (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerByRef))
         {
             oref[orefCount++] = ObjectToOBJECTREF(*(Object **) &pArgs->ReturnValue[i]);
         }
@@ -7396,7 +7397,8 @@ void STDCALL OnHijackStructInRegsWorker(HijackArgs * pArgs)
         orefCount = 0;
         for (int i = 0; i < eeClass->GetNumberEightBytes(); i++)
         {
-            if (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerReference)
+            if ((eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerReference) ||
+                (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerByRef))
             {
                 *((OBJECTREF *) &pArgs->ReturnValue[i]) = oref[orefCount++];
             }