summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gc/objecthandle.cpp3
-rw-r--r--src/jit/codegenarm64.cpp65
-rw-r--r--src/jit/codegenlinear.cpp6
-rw-r--r--src/jit/emitarm64.cpp13
-rw-r--r--src/jit/lsraarmarch.cpp16
-rw-r--r--src/vm/exceptionhandling.cpp6
-rw-r--r--tests/src/Interop/StringMarshalling/LPSTR/LPSTRTest.cs21
-rw-r--r--tests/src/Interop/StringMarshalling/LPSTR/LPSTRTestNative.cpp12
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;