diff options
-rw-r--r-- | src/gc/objecthandle.cpp | 3 | ||||
-rw-r--r-- | src/jit/codegenarm64.cpp | 65 | ||||
-rw-r--r-- | src/jit/codegenlinear.cpp | 6 | ||||
-rw-r--r-- | src/jit/emitarm64.cpp | 13 | ||||
-rw-r--r-- | src/jit/lsraarmarch.cpp | 16 | ||||
-rw-r--r-- | src/vm/exceptionhandling.cpp | 6 | ||||
-rw-r--r-- | tests/src/Interop/StringMarshalling/LPSTR/LPSTRTest.cs | 21 | ||||
-rw-r--r-- | tests/src/Interop/StringMarshalling/LPSTR/LPSTRTestNative.cpp | 12 |
8 files changed, 115 insertions, 27 deletions
diff --git a/src/gc/objecthandle.cpp b/src/gc/objecthandle.cpp index dd43ec23d5..7df915fb72 100644 --- a/src/gc/objecthandle.cpp +++ b/src/gc/objecthandle.cpp @@ -608,7 +608,8 @@ HandleTableBucketHolder::~HandleTableBucketHolder() } delete [] m_bucket->pTable; } - delete m_bucket; + + // we do not own m_bucket, so we shouldn't delete it here. } bool Ref_Initialize() diff --git a/src/jit/codegenarm64.cpp b/src/jit/codegenarm64.cpp index 7de19f9043..c075c0ac18 100644 --- a/src/jit/codegenarm64.cpp +++ b/src/jit/codegenarm64.cpp @@ -3461,19 +3461,32 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode) gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_SRC_BYREF, srcAddrType); gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_DST_BYREF, dstAddr->TypeGet()); - // Temp register used to perform the sequence of loads and stores. - regNumber tmpReg = cpObjNode->GetSingleTempReg(); + unsigned slots = cpObjNode->gtSlots; + + // Temp register(s) used to perform the sequence of loads and stores. + regNumber tmpReg = cpObjNode->ExtractTempReg(); + regNumber tmpReg2 = REG_NA; + assert(genIsValidIntReg(tmpReg)); + assert(tmpReg != REG_WRITE_BARRIER_SRC_BYREF); + assert(tmpReg != REG_WRITE_BARRIER_DST_BYREF); - unsigned slots = cpObjNode->gtSlots; - emitter* emit = getEmitter(); + if (slots > 1) + { + tmpReg2 = cpObjNode->GetSingleTempReg(); + assert(tmpReg2 != tmpReg); + assert(genIsValidIntReg(tmpReg2)); + assert(tmpReg2 != REG_WRITE_BARRIER_DST_BYREF); + assert(tmpReg2 != REG_WRITE_BARRIER_SRC_BYREF); + } + + emitter* emit = getEmitter(); BYTE* gcPtrs = cpObjNode->gtGcPtrs; // If we can prove it's on the stack we don't need to use the write barrier. if (dstOnStack) { - // TODO-ARM64-CQ: Consider using LDP/STP to save codesize. for (unsigned i = 0; i < slots; ++i) { emitAttr attr = EA_8BYTE; @@ -3482,10 +3495,23 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode) else if (gcPtrs[i] == GCT_BYREF) attr = EA_BYREF; - emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE, - INS_OPTS_POST_INDEX); - emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE, - INS_OPTS_POST_INDEX); + // Check if two or more remaining slots and use a ldp/stp sequence + // TODO-ARM64-CQ: Current limitations only allows using ldp/stp when both of the GC types match + if ((i + 1 < slots) && (gcPtrs[i] == gcPtrs[i + 1])) + { + emit->emitIns_R_R_R_I(INS_ldp, attr, tmpReg, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF, + 2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX); + emit->emitIns_R_R_R_I(INS_stp, attr, tmpReg, tmpReg2, REG_WRITE_BARRIER_DST_BYREF, + 2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX); + ++i; // extra increment of i, since we are copying two items + } + else + { + emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE, + INS_OPTS_POST_INDEX); + emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE, + INS_OPTS_POST_INDEX); + } } } else @@ -3498,11 +3524,22 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode) switch (gcPtrs[i]) { case TYPE_GC_NONE: - // TODO-ARM64-CQ: Consider using LDP/STP to save codesize in case of contigous NON-GC slots. - emit->emitIns_R_R_I(INS_ldr, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE, - INS_OPTS_POST_INDEX); - emit->emitIns_R_R_I(INS_str, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE, - INS_OPTS_POST_INDEX); + // Check if the next slot's type is also TYP_GC_NONE and use ldp/stp + if ((i + 1 < slots) && (gcPtrs[i + 1] == TYPE_GC_NONE)) + { + emit->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, tmpReg, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF, + 2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX); + emit->emitIns_R_R_R_I(INS_stp, EA_8BYTE, tmpReg, tmpReg2, REG_WRITE_BARRIER_DST_BYREF, + 2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX); + ++i; // extra increment of i, since we are copying two items + } + else + { + emit->emitIns_R_R_I(INS_ldr, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE, + INS_OPTS_POST_INDEX); + emit->emitIns_R_R_I(INS_str, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE, + INS_OPTS_POST_INDEX); + } break; default: diff --git a/src/jit/codegenlinear.cpp b/src/jit/codegenlinear.cpp index c8fcd88c10..b0fb36f370 100644 --- a/src/jit/codegenlinear.cpp +++ b/src/jit/codegenlinear.cpp @@ -1087,7 +1087,11 @@ void CodeGen::genCheckConsumeNode(GenTree* const node) if (verbose) { - if ((node->gtDebugFlags & GTF_DEBUG_NODE_CG_CONSUMED) != 0) + if (node->gtUseNum == -1) + { + // nothing wrong if the node was not consumed + } + else if ((node->gtDebugFlags & GTF_DEBUG_NODE_CG_CONSUMED) != 0) { printf("Node was consumed twice:\n"); compiler->gtDispTree(node, nullptr, nullptr, true); diff --git a/src/jit/emitarm64.cpp b/src/jit/emitarm64.cpp index 0328cb6712..1a56e863e5 100644 --- a/src/jit/emitarm64.cpp +++ b/src/jit/emitarm64.cpp @@ -9331,8 +9331,17 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) { // INS_ldp etc... // We assume that "idReg1" and "idReg2" are the destination register for all instructions - emitGCregDeadUpd(id->idReg1(), dst); - emitGCregDeadUpd(id->idReg2(), dst); + // TODO-ARM64-CQ: Current limitations only allows using ldp/stp when both of the GC types match + if (id->idGCref() != GCT_NONE) + { + emitGCregLiveUpd(id->idGCref(), id->idReg1(), dst); + emitGCregLiveUpd(id->idGCref(), id->idReg2(), dst); + } + else + { + emitGCregDeadUpd(id->idReg1(), dst); + emitGCregDeadUpd(id->idReg2(), dst); + } } else { diff --git a/src/jit/lsraarmarch.cpp b/src/jit/lsraarmarch.cpp index 7d999d880f..93cd17872c 100644 --- a/src/jit/lsraarmarch.cpp +++ b/src/jit/lsraarmarch.cpp @@ -792,7 +792,20 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode) // a temporary register to perform the sequence of loads and stores. blkNode->gtLsraInfo.internalIntCount = 1; + if (size >= 2 * REGSIZE_BYTES) + { + // We will use ldp/stp to reduce code size and improve performance + // so we need to reserve an extra internal register + blkNode->gtLsraInfo.internalIntCount++; + } + + // We can't use the special Write Barrier registers, so exclude them from the mask + regMaskTP internalIntCandidates = RBM_ALLINT & ~(RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF); + blkNode->gtLsraInfo.setInternalCandidates(l, internalIntCandidates); + + // If we have a dest address we want it in RBM_WRITE_BARRIER_DST_BYREF. dstAddr->gtLsraInfo.setSrcCandidates(l, RBM_WRITE_BARRIER_DST_BYREF); + // If we have a source address we want it in REG_WRITE_BARRIER_SRC_BYREF. // Otherwise, if it is a local, codegen will put its address in REG_WRITE_BARRIER_SRC_BYREF, // which is killed by a StoreObj (and thus needn't be reserved). @@ -824,7 +837,8 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode) if (size >= 2 * REGSIZE_BYTES) { - // Use ldp/stp to reduce code size and improve performance + // We will use ldp/stp to reduce code size and improve performance + // so we need to reserve an extra internal register internalIntCount++; } diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp index 7030ef5e91..abea194b92 100644 --- a/src/vm/exceptionhandling.cpp +++ b/src/vm/exceptionhandling.cpp @@ -25,11 +25,15 @@ #define VSD_STUB_CAN_THROW_AV #endif // _TARGET_ARM_ || _TARGET_X86_ +#if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_) +// ARM/ARM64 uses Caller-SP to locate PSPSym in the funclet frame. +#define USE_CALLER_SP_IN_FUNCLET +#endif // _TARGET_ARM_ || _TARGET_ARM64_ + #if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_) || defined(_TARGET_X86_) #define ADJUST_PC_UNWOUND_TO_CALL #define STACK_RANGE_BOUNDS_ARE_CALLER_SP #define USE_FUNCLET_CALL_HELPER -#define USE_CALLER_SP_IN_FUNCLET // For ARM/ARM64, EstablisherFrame is Caller-SP (SP just before executing call instruction). // This has been confirmed by AaronGi from the kernel team for Windows. // diff --git a/tests/src/Interop/StringMarshalling/LPSTR/LPSTRTest.cs b/tests/src/Interop/StringMarshalling/LPSTR/LPSTRTest.cs index 12cff70438..74a2087eca 100644 --- a/tests/src/Interop/StringMarshalling/LPSTR/LPSTRTest.cs +++ b/tests/src/Interop/StringMarshalling/LPSTR/LPSTRTest.cs @@ -31,6 +31,25 @@ class Test } #endregion + #region "Helper" + // ************************************************************ + // Returns the appropriate exit code + // ************************************************************* + static int ExitTest() + { + if (fails == 0) + { + Console.WriteLine("PASS"); + return 100; + } + else + { + Console.WriteLine("FAIL - " + fails + " failure(s) occurred"); + return 101; + } + } + #endregion + #region ReversePInvoke public static string Call_DelMarshal_InOut(string s) @@ -219,6 +238,6 @@ class Test ReportFailure("Method ReverseP_MarshalStrB_InOut[Managed Side],return value is false"); } #endregion - return 100; + return ExitTest(); } } diff --git a/tests/src/Interop/StringMarshalling/LPSTR/LPSTRTestNative.cpp b/tests/src/Interop/StringMarshalling/LPSTR/LPSTRTestNative.cpp index b440c52ef5..485d949abb 100644 --- a/tests/src/Interop/StringMarshalling/LPSTR/LPSTRTestNative.cpp +++ b/tests/src/Interop/StringMarshalling/LPSTR/LPSTRTestNative.cpp @@ -123,16 +123,16 @@ extern "C" DLL_EXPORT int __cdecl Writeline(char * pFormat, int i, char c, doubl } -typedef LPCTSTR (__stdcall * Test_DelMarshal_InOut)(/*[in]*/ LPCSTR s); +typedef LPCWSTR (__stdcall * Test_DelMarshal_InOut)(/*[in]*/ LPCSTR s); extern "C" DLL_EXPORT BOOL __cdecl RPinvoke_DelMarshal_InOut(Test_DelMarshal_InOut d, /*[in]*/ LPCSTR s) { - LPCTSTR str = d(s); - const char *ret = "Return"; + LPCWSTR str = d(s); + LPCWSTR ret = W("Return"); - size_t lenstr = _tcslen(str); - size_t lenret = _tcslen(ret); + size_t lenstr = wcslen(str); + size_t lenret = wcslen(ret); - if((lenret != lenstr)||(_tcsncmp(str,ret,lenstr)!=0)) + if((lenret != lenstr)||(wcsncmp(str,ret,lenstr)!=0)) { printf("Error in RPinvoke_DelMarshal_InOut, Returned value didn't match\n"); return FALSE; |