[x86/Linux] Use CDECL instead of STDCALL (dotnet/coreclr#10410)
authorJonghyun Park <parjong@gmail.com>
Thu, 30 Mar 2017 21:20:01 +0000 (06:20 +0900)
committerBruce Forstall <brucefo@microsoft.com>
Thu, 30 Mar 2017 21:20:01 +0000 (14:20 -0700)
[x86/Linux] Use CDECL instead of STDCALL

Use STDCALL/THISCALL/FASTCALL if callconv is explicitly specified

Merge two adjustment (argument/alignment) into one

Commit migrated from https://github.com/dotnet/coreclr/commit/5e03cb09e3754e4a3430ba424a1352b9c01ff098

src/coreclr/src/inc/corinfo.h
src/coreclr/src/jit/codegencommon.cpp
src/coreclr/src/jit/codegenlinear.h
src/coreclr/src/jit/codegenxarch.cpp
src/coreclr/src/jit/importer.cpp
src/coreclr/src/vm/comdelegate.cpp
src/coreclr/src/vm/fcall.h
src/coreclr/src/vm/i386/jithelp.S
src/coreclr/src/vm/i386/stublinkerx86.cpp

index f7560b2..00c42ce 100644 (file)
@@ -747,6 +747,17 @@ enum CorInfoCallConv
     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
index 5e65397..e9546f8 100644 (file)
@@ -1639,7 +1639,7 @@ void CodeGen::genDefineTempLabel(BasicBlock* label)
 
 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
@@ -9720,17 +9720,25 @@ void CodeGen::genFnEpilog(BasicBlock* block)
         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);
index 9fa5bdb..b038858 100644 (file)
@@ -176,7 +176,7 @@ void genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode);
 
 void genAlignStackBeforeCall(GenTreePutArgStk* putArgStk);
 void genAlignStackBeforeCall(GenTreeCall* call);
-void genRemoveAlignmentAfterCall(GenTreeCall* call);
+void genRemoveAlignmentAfterCall(GenTreeCall* call, unsigned bias = 0);
 
 #if defined(UNIX_X86_ABI)
 
index 5d26612..9833b09 100644 (file)
@@ -5005,16 +5005,30 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
     }
 
 #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
@@ -5187,8 +5201,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
         // clang-format on
     }
 
-    genRemoveAlignmentAfterCall(call);
-
     // if it was a pinvoke we may have needed to get the address of a label
     if (genPendingCallLabel)
     {
@@ -5197,11 +5209,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
         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?
@@ -5302,6 +5309,8 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
         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.
@@ -5332,11 +5341,15 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
     }
 
     // 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.
@@ -7566,19 +7579,35 @@ void CodeGen::genAlignStackBeforeCall(GenTreeCall* call)
 //
 // 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_
index 599abf9..eaf647a 100644 (file)
@@ -6967,6 +6967,14 @@ var_types Compiler::impImportCall(OPCODE                  opcode,
     }
 #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)
     {
index 20ae695..2682c2d 100644 (file)
@@ -277,7 +277,14 @@ VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, SArray<S
         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;
 
index 0e96557..c3f026b 100644 (file)
@@ -377,7 +377,7 @@ LPVOID __FCThrowArgument(LPVOID me, enum RuntimeExceptionKind reKind, LPCWSTR ar
 
 // 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
index d7cbba0..dd3f804 100644 (file)
@@ -562,7 +562,7 @@ LEAF_ENTRY JIT_Dbl2LngP4x87, _TEXT
     // restore stack
     add     esp, 8
 
-    ret     8
+    ret
 LEAF_END JIT_Dbl2LngP4x87, _TEXT
 
 // *********************************************************************/
@@ -588,7 +588,7 @@ LEAF_ENTRY JIT_Dbl2LngSSE3, _TEXT
     // restore stack
     add     esp, 8
 
-    ret     8
+    ret
 LEAF_END JIT_Dbl2LngSSE3, _TEXT
 
 // *********************************************************************/
@@ -605,7 +605,7 @@ 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
 
 // *********************************************************************/
index d951314..9742f96 100644 (file)
@@ -1251,7 +1251,7 @@ VOID StubLinkerCPU::X86EmitReturn(WORD wArgBytes)
     CONTRACTL
     {
         STANDARD_VM_CHECK;
-#ifdef _TARGET_AMD64_
+#if defined(_TARGET_AMD64_) || defined(UNIX_X86_ABI)
         PRECONDITION(wArgBytes == 0);
 #endif
 
@@ -3268,7 +3268,7 @@ VOID StubLinkerCPU::EmitMethodStubEpilog(WORD numArgBytes, int transitionBlockOf
     X86EmitPopReg(kR15);
 #endif
 
-#ifdef _TARGET_AMD64_
+#if defined(_TARGET_AMD64_) || defined(UNIX_X86_ABI)
     // Caller deallocates argument space.  (Bypasses ASSERT in
     // X86EmitReturn.)
     numArgBytes = 0;
@@ -4223,6 +4223,10 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray)
     if (haveMemMemMove)
         X86EmitPopReg(SCRATCH_REGISTER_X86REG);
 
+#ifdef UNIX_X86_ABI
+    _ASSERTE(pWalk->stacksizedelta == 0);
+#endif
+
     if (pWalk->stacksizedelta)
         X86EmitAddEsp(pWalk->stacksizedelta);
 
@@ -5717,8 +5721,12 @@ COPY_VALUE_CLASS:
     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.