CORINFO_CALLCONV_PARAMTYPE = 0x80, // Passed last. Same as CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG
};
+#ifdef UNIX_X86_ABI
+inline bool IsCallerPop(CorInfoCallConv callConv)
+{
+ unsigned int umask = CORINFO_CALLCONV_STDCALL
+ | CORINFO_CALLCONV_THISCALL
+ | CORINFO_CALLCONV_FASTCALL;
+
+ return !(callConv & umask);
+}
+#endif // UNIX_X86_ABI
+
enum CorInfoUnmanagedCallConv
{
// These correspond to CorUnmanagedCallingConvention
void CodeGen::genAdjustSP(ssize_t delta)
{
-#ifdef _TARGET_X86_
+#if defined(_TARGET_X86_) && !defined(UNIX_X86_ABI)
if (delta == sizeof(int))
inst_RV(INS_pop, REG_ECX, TYP_INT);
else
unsigned stkArgSize = 0; // Zero on all platforms except x86
#if defined(_TARGET_X86_)
-
- noway_assert(compiler->compArgSize >= intRegState.rsCalleeRegArgCount * sizeof(void*));
- stkArgSize = compiler->compArgSize - intRegState.rsCalleeRegArgCount * sizeof(void*);
-
- noway_assert(compiler->compArgSize < 0x10000); // "ret" only has 2 byte operand
+ bool fCalleePop = true;
// varargs has caller pop
if (compiler->info.compIsVarArgs)
- stkArgSize = 0;
+ fCalleePop = false;
+
+#ifdef UNIX_X86_ABI
+ if (IsCallerPop(compiler->info.compMethodInfo->args.callConv))
+ fCalleePop = false;
+#endif // UNIX_X86_ABI
-#endif // defined(_TARGET_X86_)
+ if (fCalleePop)
+ {
+ noway_assert(compiler->compArgSize >= intRegState.rsCalleeRegArgCount * sizeof(void*));
+ stkArgSize = compiler->compArgSize - intRegState.rsCalleeRegArgCount * sizeof(void*);
+
+ noway_assert(compiler->compArgSize < 0x10000); // "ret" only has 2 byte operand
+ }
+#endif // _TARGET_X86_
/* Return, popping our arguments (if any) */
instGen_Return(stkArgSize);
void genAlignStackBeforeCall(GenTreePutArgStk* putArgStk);
void genAlignStackBeforeCall(GenTreeCall* call);
-void genRemoveAlignmentAfterCall(GenTreeCall* call);
+void genRemoveAlignmentAfterCall(GenTreeCall* call, unsigned bias = 0);
#if defined(UNIX_X86_ABI)
}
#if defined(_TARGET_X86_)
+ bool fCallerPop = (call->gtFlags & GTF_CALL_POP_ARGS) != 0;
+
+#ifdef UNIX_X86_ABI
+ {
+ CorInfoCallConv callConv = CORINFO_CALLCONV_DEFAULT;
+
+ if ((callType != CT_HELPER) && call->callSig)
+ {
+ callConv = call->callSig->callConv;
+ }
+
+ fCallerPop |= IsCallerPop(callConv);
+ }
+#endif // UNIX_X86_ABI
+
// If the callee pops the arguments, we pass a positive value as the argSize, and the emitter will
// adjust its stack level accordingly.
// If the caller needs to explicitly pop its arguments, we must pass a negative value, and then do the
// pop when we're done.
ssize_t argSizeForEmitter = stackArgBytes;
- if ((call->gtFlags & GTF_CALL_POP_ARGS) != 0)
+ if (fCallerPop)
{
argSizeForEmitter = -stackArgBytes;
}
-
#endif // defined(_TARGET_X86_)
#ifdef FEATURE_AVX_SUPPORT
// clang-format on
}
- genRemoveAlignmentAfterCall(call);
-
// if it was a pinvoke we may have needed to get the address of a label
if (genPendingCallLabel)
{
genPendingCallLabel = nullptr;
}
-#if defined(_TARGET_X86_)
- // The call will pop its arguments.
- SubtractStackLevel(stackArgBytes);
-#endif // defined(_TARGET_X86_)
-
// Update GC info:
// All Callee arg registers are trashed and no longer contain any GC pointers.
// TODO-XArch-Bug?: As a matter of fact shouldn't we be killing all of callee trashed regs here?
gcInfo.gcMarkRegSetNpt(RBM_INTRET);
}
+ unsigned stackAdjustBias = 0;
+
#if defined(_TARGET_X86_)
//-------------------------------------------------------------------------
// Create a label for tracking of region protected by the monitor in synchronized methods.
}
// Is the caller supposed to pop the arguments?
- if (((call->gtFlags & GTF_CALL_POP_ARGS) != 0) && (stackArgBytes != 0))
+ if (fCallerPop && (stackArgBytes != 0))
{
- genAdjustSP(stackArgBytes);
+ stackAdjustBias = stackArgBytes;
}
+
+ SubtractStackLevel(stackArgBytes);
#endif // _TARGET_X86_
+
+ genRemoveAlignmentAfterCall(call, stackAdjustBias);
}
// Produce code for a GT_JMP node.
//
// Arguments:
// call - the call node.
+// bias - additional stack adjustment
//
-void CodeGen::genRemoveAlignmentAfterCall(GenTreeCall* call)
+// Note:
+// When bias > 0, caller should adjust stack level appropriately as
+// bias is not considered when adjusting stack level.
+//
+void CodeGen::genRemoveAlignmentAfterCall(GenTreeCall* call, unsigned bias)
{
+#if defined(_TARGET_X86_)
#if defined(UNIX_X86_ABI)
// Put back the stack pointer if there was any padding for stack alignment
- unsigned padStkAlign = call->fgArgInfo->GetStkAlign();
- if (padStkAlign != 0)
+ unsigned padStkAlign = call->fgArgInfo->GetStkAlign();
+ unsigned padStkAdjust = padStkAlign + bias;
+
+ if (padStkAdjust != 0)
{
- inst_RV_IV(INS_add, REG_SPBASE, padStkAlign, EA_PTRSIZE);
+ inst_RV_IV(INS_add, REG_SPBASE, padStkAdjust, EA_PTRSIZE);
SubtractStackLevel(padStkAlign);
SubtractNestedAlignment(padStkAlign);
}
-#endif // UNIX_X86_ABI
+#else // UNIX_X86_ABI
+ if (bias != 0)
+ {
+ genAdjustSP(bias);
+ }
+#endif // !UNIX_X86_ABI_
+#else // _TARGET_X86_
+ assert(bias == 0);
+#endif // !_TARGET_X86
}
#ifdef _TARGET_X86_
}
#endif // !FEATURE_VARARG
+#ifdef UNIX_X86_ABI
+ if (call->gtCall.callSig == nullptr)
+ {
+ call->gtCall.callSig = new (this, CMK_CorSig) CORINFO_SIG_INFO;
+ *call->gtCall.callSig = *sig;
+ }
+#endif // UNIX_X86_ABI
+
if ((sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_VARARG ||
(sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_NATIVEVARARG)
{
COMPlusThrow(kVerificationException);
}
- UINT stackSizeDelta = stackSizeSrc - stackSizeDst;
+ UINT stackSizeDelta;
+
+#ifdef UNIX_X86_ABI
+ // Stack does not shrink as UNIX_X86_ABI uses CDECL (instead of STDCALL).
+ stackSizeDelta = 0;
+#else
+ stackSizeDelta = stackSizeSrc - stackSizeDst;
+#endif
INT ofsSrc, ofsDst;
// Choose the appropriate calling convention for FCALL helpers on the basis of the JIT calling convention
#ifdef __GNUC__
-#define F_CALL_CONV __attribute__((stdcall, regparm(3)))
+#define F_CALL_CONV __attribute__((cdecl, regparm(3)))
// GCC fastcall convention (simulated via stdcall) is different from MSVC fastcall convention. GCC can use up
// to 3 registers to store parameters. The registers used are EAX, EDX, ECX. Dummy parameters and reordering
// restore stack
add esp, 8
- ret 8
+ ret
LEAF_END JIT_Dbl2LngP4x87, _TEXT
// *********************************************************************/
// restore stack
add esp, 8
- ret 8
+ ret
LEAF_END JIT_Dbl2LngSSE3, _TEXT
// *********************************************************************/
LEAF_ENTRY JIT_Dbl2IntSSE2, _TEXT
movsd xmm0, [esp + 4]
cvttsd2si eax, xmm0
- ret 8
+ ret
LEAF_END JIT_Dbl2IntSSE2, _TEXT
// *********************************************************************/
CONTRACTL
{
STANDARD_VM_CHECK;
-#ifdef _TARGET_AMD64_
+#if defined(_TARGET_AMD64_) || defined(UNIX_X86_ABI)
PRECONDITION(wArgBytes == 0);
#endif
X86EmitPopReg(kR15);
#endif
-#ifdef _TARGET_AMD64_
+#if defined(_TARGET_AMD64_) || defined(UNIX_X86_ABI)
// Caller deallocates argument space. (Bypasses ASSERT in
// X86EmitReturn.)
numArgBytes = 0;
if (haveMemMemMove)
X86EmitPopReg(SCRATCH_REGISTER_X86REG);
+#ifdef UNIX_X86_ABI
+ _ASSERTE(pWalk->stacksizedelta == 0);
+#endif
+
if (pWalk->stacksizedelta)
X86EmitAddEsp(pWalk->stacksizedelta);
X86EmitPopReg(kFactorReg);
X86EmitPopReg(kTotalReg);
+#ifndef UNIX_X86_ABI
// ret N
X86EmitReturn(pArrayOpScript->m_cbretpop);
+#else
+ X86EmitReturn(0);
+#endif
#endif // !_TARGET_AMD64_
// Exception points must clean up the stack for all those extra args.