diff options
Diffstat (limited to 'src/vm/i386/stublinkerx86.cpp')
-rw-r--r-- | src/vm/i386/stublinkerx86.cpp | 824 |
1 files changed, 99 insertions, 725 deletions
diff --git a/src/vm/i386/stublinkerx86.cpp b/src/vm/i386/stublinkerx86.cpp index 983fc3f36a..a658307bb2 100644 --- a/src/vm/i386/stublinkerx86.cpp +++ b/src/vm/i386/stublinkerx86.cpp @@ -2936,7 +2936,7 @@ void StubLinkerCPU::EmitSharedComMethodStubEpilog(TADDR pFrameVptr, //======================================================================== #endif // defined(FEATURE_COMINTEROP) && defined(_TARGET_X86_) -#ifndef FEATURE_STUBS_AS_IL +#if !defined(FEATURE_STUBS_AS_IL) && defined(_TARGET_X86_) /*============================================================================== Pushes a TransitionFrame on the stack If you make any changes to the prolog instruction sequence, be sure @@ -2955,44 +2955,6 @@ VOID StubLinkerCPU::EmitMethodStubProlog(TADDR pFrameVptr, int transitionBlockOf { STANDARD_VM_CONTRACT; -#ifdef _TARGET_AMD64_ - X86EmitPushReg(kR15); // CalleeSavedRegisters - X86EmitPushReg(kR14); - X86EmitPushReg(kR13); - X86EmitPushReg(kR12); - X86EmitPushReg(kRBP); - X86EmitPushReg(kRBX); - X86EmitPushReg(kRSI); - X86EmitPushReg(kRDI); - - // Push m_datum - X86EmitPushReg(SCRATCH_REGISTER_X86REG); - - // push edx ;leave room for m_next (edx is an arbitrary choice) - X86EmitPushReg(kEDX); - - // push Frame vptr - X86EmitPushImmPtr((LPVOID) pFrameVptr); - - // mov rsi, rsp - X86EmitR2ROp(0x8b, kRSI, (X86Reg)4 /*kESP*/); - UnwindSetFramePointer(kRSI); - - // Save ArgumentRegisters - #define ARGUMENT_REGISTER(regname) X86EmitRegSave(k##regname, SecureDelegateFrame::GetOffsetOfTransitionBlock() + \ - sizeof(TransitionBlock) + offsetof(ArgumentRegisters, regname)); - ENUM_ARGUMENT_REGISTERS(); - #undef ARGUMENT_REGISTER - - _ASSERTE(((Frame*)&pFrameVptr)->GetGSCookiePtr() == PTR_GSCookie(PBYTE(&pFrameVptr) - sizeof(GSCookie))); - X86EmitPushImmPtr((LPVOID)GetProcessGSCookie()); - - // sub rsp, 4*sizeof(void*) ;; allocate callee scratch area and ensure rsp is 16-byte-aligned - const INT32 padding = sizeof(ArgumentRegisters) + ((sizeof(FramedMethodFrame) % (2 * sizeof(LPVOID))) ? 0 : sizeof(LPVOID)); - X86EmitSubEsp(padding); -#endif // _TARGET_AMD64_ - -#ifdef _TARGET_X86_ // push ebp ;; save callee-saved register // mov ebp,esp // push ebx ;; save callee-saved register @@ -3022,7 +2984,6 @@ VOID StubLinkerCPU::EmitMethodStubProlog(TADDR pFrameVptr, int transitionBlockOf X86EmitMovRegSP(kESI); X86EmitPushImmPtr((LPVOID)GetProcessGSCookie()); -#endif // _TARGET_X86_ // ebx <-- GetThread() X86EmitCurrentThreadFetch(kEBX, 0); @@ -3030,14 +2991,7 @@ VOID StubLinkerCPU::EmitMethodStubProlog(TADDR pFrameVptr, int transitionBlockOf #if _DEBUG // call ObjectRefFlush -#ifdef _TARGET_AMD64_ - - // mov rcx, rbx - X86EmitR2ROp(0x8b, kECX, kEBX); // arg in reg - -#else // !_TARGET_AMD64_ X86EmitPushReg(kEBX); // arg on stack -#endif // _TARGET_AMD64_ // Make the call X86EmitCall(NewExternalCodeLabel((LPVOID) Thread::ObjectRefFlush), sizeof(void*)); @@ -3058,40 +3012,16 @@ VOID StubLinkerCPU::EmitMethodStubProlog(TADDR pFrameVptr, int transitionBlockOf if (Frame::ShouldLogTransitions()) { // call LogTransition -#ifdef _TARGET_AMD64_ - - // mov rcx, rsi - X86EmitR2ROp(0x8b, kECX, kESI); // arg in reg - -#else // !_TARGET_AMD64_ X86EmitPushReg(kESI); // arg on stack -#endif // _TARGET_AMD64_ - - X86EmitCall(NewExternalCodeLabel((LPVOID) Frame::LogTransition), sizeof(void*)); - -#ifdef _TARGET_AMD64_ - // Reload parameter registers - // mov r, [esp+offs] - #define ARGUMENT_REGISTER(regname) X86EmitEspOffset(0x8b, k##regname, sizeof(ArgumentRegisters) + \ - sizeof(TransitionFrame) + offsetof(ArgumentRegisters, regname)); - ENUM_ARGUMENT_REGISTERS(); - #undef ARGUMENT_REGISTER -#endif // _TARGET_AMD64_ + X86EmitCall(NewExternalCodeLabel((LPVOID) Frame::LogTransition), sizeof(void*)); } #endif // _DEBUG -#ifdef _TARGET_AMD64_ - // OK for the debugger to examine the new frame now - // (Note that if it's not OK yet for some stub, another patch label - // can be emitted later which will override this one.) - EmitPatchLabel(); -#else // For x86, the patch label can be specified only after the GSCookie is pushed // Otherwise the debugger will see a Frame without a valid GSCookie -#endif } /*============================================================================== @@ -3115,15 +3045,9 @@ VOID StubLinkerCPU::EmitMethodStubEpilog(WORD numArgBytes, int transitionBlockOf // mov [ebx + Thread.GetFrame()], edi ;; restore previous frame X86EmitIndexRegStore(kEBX, Thread::GetOffsetOfCurrentFrame(), kEDI); -#ifdef _TARGET_X86_ // deallocate Frame X86EmitAddEsp(sizeof(GSCookie) + transitionBlockOffset + TransitionBlock::GetOffsetOfCalleeSavedRegisters()); -#elif defined(_TARGET_AMD64_) - // lea rsp, [rsi + <offset of preserved registers>] - X86EmitOffsetModRM(0x8d, (X86Reg)4 /*kRSP*/, kRSI, transitionBlockOffset + TransitionBlock::GetOffsetOfCalleeSavedRegisters()); -#endif // _TARGET_AMD64_ - // pop edi ; restore callee-saved registers // pop esi // pop ebx @@ -3133,14 +3057,7 @@ VOID StubLinkerCPU::EmitMethodStubEpilog(WORD numArgBytes, int transitionBlockOf X86EmitPopReg(kEBX); X86EmitPopReg(kEBP); -#ifdef _TARGET_AMD64_ - X86EmitPopReg(kR12); - X86EmitPopReg(kR13); - X86EmitPopReg(kR14); - X86EmitPopReg(kR15); -#endif - -#if defined(_TARGET_AMD64_) || defined(UNIX_X86_ABI) +#if defined(UNIX_X86_ABI) // Caller deallocates argument space. (Bypasses ASSERT in // X86EmitReturn.) numArgBytes = 0; @@ -3158,23 +3075,19 @@ VOID StubLinkerCPU::EmitCheckGSCookie(X86Reg frameReg, int gsCookieOffset) #ifdef _DEBUG // cmp dword ptr[frameReg-gsCookieOffset], gsCookie -#ifdef _TARGET_X86_ X86EmitCmpRegIndexImm32(frameReg, gsCookieOffset, GetProcessGSCookie()); -#else - X64EmitCmp32RegIndexImm32(frameReg, gsCookieOffset, (INT32)GetProcessGSCookie()); -#endif - + CodeLabel * pLabel = NewCodeLabel(); X86EmitCondJump(pLabel, X86CondCode::kJE); - + X86EmitCall(NewExternalCodeLabel((LPVOID) JIT_FailFast), 0); EmitLabel(pLabel); #endif } -#endif // !FEATURE_STUBS_AS_IL - +#endif // !defined(FEATURE_STUBS_AS_IL) && defined(_TARGET_X86_) +#ifdef _TARGET_X86_ // This method unboxes the THIS pointer and then calls pRealMD // If it's shared code for a method in a generic value class, then also extract the vtable pointer // and pass it as an extra argument. Thus this stub generator really covers both @@ -3189,7 +3102,7 @@ VOID StubLinkerCPU::EmitUnboxMethodStub(MethodDesc* pUnboxMD) } CONTRACTL_END; -#ifdef FEATURE_STUBS_AS_IL +#ifdef FEATURE_INSTANTIATINGSTUB_AS_IL _ASSERTE(!pUnboxMD->RequiresInstMethodTableArg()); #else if (pUnboxMD->RequiresInstMethodTableArg()) @@ -3202,42 +3115,109 @@ VOID StubLinkerCPU::EmitUnboxMethodStub(MethodDesc* pUnboxMD) // // unboxing a value class simply means adding sizeof(void*) to the THIS pointer // -#ifdef _TARGET_AMD64_ X86EmitAddReg(THIS_kREG, sizeof(void*)); + EmitTailJumpToMethod(pUnboxMD); +} +#endif //_TARGET_X86_ - // Use direct call if possible - if (pUnboxMD->HasStableEntryPoint()) +#if defined(FEATURE_SHARE_GENERIC_CODE) && defined(_TARGET_AMD64_) +VOID StubLinkerCPU::EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, struct ShuffleEntry *pShuffleEntryArray, void* extraArg) +{ + STANDARD_VM_CONTRACT; + + for (ShuffleEntry* pEntry = pShuffleEntryArray; pEntry->srcofs != ShuffleEntry::SENTINEL; pEntry++) { - X86EmitRegLoad(kRAX, pUnboxMD->GetStableEntryPoint());// MOV RAX, DWORD + _ASSERTE((pEntry->srcofs & ShuffleEntry::REGMASK) && (pEntry->dstofs & ShuffleEntry::REGMASK)); + // Source in a general purpose or float register, destination in the same kind of a register or on stack + int srcRegIndex = pEntry->srcofs & ShuffleEntry::OFSREGMASK; + + // Both the srcofs and dstofs must be of the same kind of registers - float or general purpose. + _ASSERTE((pEntry->dstofs & ShuffleEntry::FPREGMASK) == (pEntry->srcofs & ShuffleEntry::FPREGMASK)); + int dstRegIndex = pEntry->dstofs & ShuffleEntry::OFSREGMASK; + + if (pEntry->srcofs & ShuffleEntry::FPREGMASK) + { + // movdqa dstReg, srcReg + X64EmitMovXmmXmm((X86Reg)(kXMM0 + dstRegIndex), (X86Reg)(kXMM0 + srcRegIndex)); + } + else + { + // mov dstReg, srcReg + X86EmitMovRegReg(c_argRegs[dstRegIndex], c_argRegs[srcRegIndex]); + } } - else + + MetaSig msig(pSharedMD); + ArgIterator argit(&msig); + + if (argit.HasParamType()) { - X86EmitRegLoad(kRAX, (UINT_PTR)pUnboxMD->GetAddrOfSlot()); // MOV RAX, DWORD - - X86EmitIndexRegLoad(kRAX, kRAX); // MOV RAX, [RAX] + int paramTypeArgOffset = argit.GetParamTypeArgOffset(); + int paramTypeArgIndex = TransitionBlock::GetArgumentIndexFromOffset(paramTypeArgOffset); + + if (extraArg == NULL) + { + if (pSharedMD->RequiresInstMethodTableArg()) + { + // Unboxing stub case + // Extract MethodTable pointer (the hidden arg) from the object instance. + X86EmitIndexRegLoad(c_argRegs[paramTypeArgIndex], THIS_kREG); + } + } + else + { + X86EmitRegLoad(c_argRegs[paramTypeArgIndex], (UINT_PTR)extraArg); + } } - Emit16(X86_INSTR_JMP_EAX); // JMP EAX -#else // _TARGET_AMD64_ - X86EmitAddReg(THIS_kREG, sizeof(void*)); + if (extraArg == NULL) + { + // Unboxing stub case + // Skip over the MethodTable* to find the address of the unboxed value type. + X86EmitAddReg(THIS_kREG, sizeof(void*)); + } + + EmitTailJumpToMethod(pSharedMD); +} +#endif // defined(FEATURE_SHARE_GENERIC_CODE) && defined(_TARGET_AMD64_) +#ifdef _TARGET_AMD64_ +VOID StubLinkerCPU::EmitLoadMethodAddressIntoAX(MethodDesc *pMD) +{ + if (pMD->HasStableEntryPoint()) + { + X86EmitRegLoad(kRAX, pMD->GetStableEntryPoint());// MOV RAX, DWORD + } + else + { + X86EmitRegLoad(kRAX, (UINT_PTR)pMD->GetAddrOfSlot()); // MOV RAX, DWORD + + X86EmitIndexRegLoad(kRAX, kRAX); // MOV RAX, [RAX] + } +} +#endif +VOID StubLinkerCPU::EmitTailJumpToMethod(MethodDesc *pMD) +{ +#ifdef _TARGET_AMD64_ + EmitLoadMethodAddressIntoAX(pMD); + Emit16(X86_INSTR_JMP_EAX); +#else // Use direct call if possible - if (pUnboxMD->HasStableEntryPoint()) + if (pMD->HasStableEntryPoint()) { - X86EmitNearJump(NewExternalCodeLabel((LPVOID) pUnboxMD->GetStableEntryPoint())); + X86EmitNearJump(NewExternalCodeLabel((LPVOID) pMD->GetStableEntryPoint())); } else { // jmp [slot] Emit16(0x25ff); - Emit32((DWORD)(size_t)pUnboxMD->GetAddrOfSlot()); + Emit32((DWORD)(size_t)pMD->GetAddrOfSlot()); } #endif //_TARGET_AMD64_ } - -#if defined(FEATURE_SHARE_GENERIC_CODE) && !defined(FEATURE_STUBS_AS_IL) -// The stub generated by this method passes an extra dictionary argument before jumping to +#if defined(FEATURE_SHARE_GENERIC_CODE) && !defined(FEATURE_INSTANTIATINGSTUB_AS_IL) && defined(_TARGET_X86_) +// The stub generated by this method passes an extra dictionary argument before jumping to // shared-instantiation generic code. // // pMD is either @@ -3258,126 +3238,6 @@ VOID StubLinkerCPU::EmitInstantiatingMethodStub(MethodDesc* pMD, void* extra) MetaSig msig(pMD); ArgIterator argit(&msig); -#ifdef _TARGET_AMD64_ - int paramTypeArgOffset = argit.GetParamTypeArgOffset(); - int paramTypeArgIndex = TransitionBlock::GetArgumentIndexFromOffset(paramTypeArgOffset); - - CorElementType argTypes[5]; - - int firstRealArg = paramTypeArgIndex + 1; - int argNum = firstRealArg; - - // - // Compute types of the 4 register args and first stack arg - // - - CorElementType sigType; - while ((sigType = msig.NextArgNormalized()) != ELEMENT_TYPE_END) - { - argTypes[argNum++] = sigType; - if (argNum > 4) - break; - } - msig.Reset(); - - BOOL fUseInstantiatingMethodStubWorker = FALSE; - - if (argNum > 4) - { - // - // We will need to go through assembly helper. - // - fUseInstantiatingMethodStubWorker = TRUE; - - // Allocate space for frame before pushing the arguments for the assembly helper - X86EmitSubEsp((INT32)(AlignUp(sizeof(void *) /* extra stack param */ + sizeof(GSCookie) + sizeof(StubHelperFrame), 16) - sizeof(void *) /* return address */)); - - // - // Store extra arg stack arg param for the helper. - // - CorElementType argType = argTypes[--argNum]; - switch (argType) - { - case ELEMENT_TYPE_R4: - // movss dword ptr [rsp], xmm? - X64EmitMovSSToMem(kXMM3, (X86Reg)4 /*kRSP*/); - break; - case ELEMENT_TYPE_R8: - // movsd qword ptr [rsp], xmm? - X64EmitMovSDToMem(kXMM3, (X86Reg)4 /*kRSP*/); - break; - default: - X86EmitIndexRegStoreRSP(0, kR9); - break; - } - } - - // - // Shuffle the register arguments - // - while (argNum > firstRealArg) - { - CorElementType argType = argTypes[--argNum]; - - switch (argType) - { - case ELEMENT_TYPE_R4: - case ELEMENT_TYPE_R8: - // mov xmm#, xmm#-1 - X64EmitMovXmmXmm((X86Reg)argNum, (X86Reg)(argNum - 1)); - break; - default: - //mov reg#, reg#-1 - X86EmitMovRegReg(c_argRegs[argNum], c_argRegs[argNum-1]); - break; - } - } - - // - // Setup the hidden instantiation argument - // - if (extra != NULL) - { - X86EmitRegLoad(c_argRegs[paramTypeArgIndex], (UINT_PTR)extra); - } - else - { - X86EmitIndexRegLoad(c_argRegs[paramTypeArgIndex], THIS_kREG); - - X86EmitAddReg(THIS_kREG, sizeof(void*)); - } - - // Use direct call if possible - if (pMD->HasStableEntryPoint()) - { - X86EmitRegLoad(kRAX, pMD->GetStableEntryPoint());// MOV RAX, DWORD - } - else - { - X86EmitRegLoad(kRAX, (UINT_PTR)pMD->GetAddrOfSlot()); // MOV RAX, DWORD - - X86EmitIndexRegLoad(kRAX, kRAX); // MOV RAX, [RAX] - } - - if (fUseInstantiatingMethodStubWorker) - { - X86EmitPushReg(kRAX); - - UINT cbStack = argit.SizeOfArgStack(); - _ASSERTE(cbStack > 0); - - X86EmitPushImm32((AlignUp(cbStack, 16) / sizeof(void*)) - 1); // -1 for extra stack arg - - X86EmitRegLoad(kRAX, GetEEFuncEntryPoint(InstantiatingMethodStubWorker));// MOV RAX, DWORD - } - else - { - _ASSERTE(argit.SizeOfArgStack() == 0); - } - - Emit16(X86_INSTR_JMP_EAX); - -#else int paramTypeArgOffset = argit.GetParamTypeArgOffset(); // It's on the stack @@ -3421,21 +3281,9 @@ VOID StubLinkerCPU::EmitInstantiatingMethodStub(MethodDesc* pMD, void* extra) // Unboxing stub case. X86EmitAddReg(THIS_kREG, sizeof(void*)); } - - // Use direct call if possible - if (pMD->HasStableEntryPoint()) - { - X86EmitNearJump(NewExternalCodeLabel((LPVOID) pMD->GetStableEntryPoint())); - } - else - { - // jmp [slot] - Emit16(0x25ff); - Emit32((DWORD)(size_t)pMD->GetAddrOfSlot()); - } -#endif // + EmitTailJumpToMethod(pMD); } -#endif // FEATURE_SHARE_GENERIC_CODE && FEATURE_STUBS_AS_IL +#endif // defined(FEATURE_SHARE_GENERIC_CODE) && !defined(FEATURE_INSTANTIATINGSTUB_AS_IL) && defined(_TARGET_X86_) #if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) @@ -3840,7 +3688,6 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) // Unix: mov r11, rdi X86EmitMovRegReg(kR11, THIS_kREG); -#ifdef UNIX_AMD64_ABI for (ShuffleEntry* pEntry = pShuffleEntryArray; pEntry->srcofs != ShuffleEntry::SENTINEL; pEntry++) { if (pEntry->srcofs == ShuffleEntry::HELPERREG) @@ -3962,80 +3809,6 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) X86EmitIndexRegStore (SCRATCH_REGISTER_X86REG, (pEntry->dstofs + 1) * sizeof(void*), kR10); } } -#else // UNIX_AMD64_ABI - UINT step = 1; - - if (pShuffleEntryArray->argtype == ELEMENT_TYPE_END) - { - // Special handling of open instance methods with return buffer. Move "this" - // by two slots, and leave the "retbufptr" between the two slots intact. - - // mov rcx, r8 - X86EmitMovRegReg(kRCX, kR8); - - // Skip this entry - pShuffleEntryArray++; - - // Skip this entry and leave retbufptr intact - step += 2; - } - - // Now shuffle the args by one position: - // steps 1-3 : reg args (rcx, rdx, r8) - // step 4 : stack->reg arg (r9) - // step >4 : stack args - - for(; - pShuffleEntryArray->srcofs != ShuffleEntry::SENTINEL; - step++, pShuffleEntryArray++) - { - switch (step) - { - case 1: - case 2: - case 3: - switch (pShuffleEntryArray->argtype) - { - case ELEMENT_TYPE_R4: - case ELEMENT_TYPE_R8: - // mov xmm-1#, xmm# - X64EmitMovXmmXmm((X86Reg)(step - 1), (X86Reg)(step)); - break; - default: - // mov argRegs[step-1], argRegs[step] - X86EmitMovRegReg(c_argRegs[step-1], c_argRegs[step]); - break; - } - break; - - case 4: - { - switch (pShuffleEntryArray->argtype) - { - case ELEMENT_TYPE_R4: - X64EmitMovSSFromMem(kXMM3, kRAX, 0x28); - break; - - case ELEMENT_TYPE_R8: - X64EmitMovSDFromMem(kXMM3, kRAX, 0x28); - break; - - default: - // mov r9, [rax + 28h] - X86EmitIndexRegLoad (kR9, SCRATCH_REGISTER_X86REG, 5*sizeof(void*)); - } - break; - } - default: - - // mov r10, [rax + (step+1)*sizeof(void*)] - X86EmitIndexRegLoad (kR10, SCRATCH_REGISTER_X86REG, (step+1)*sizeof(void*)); - - // mov [rax + step*sizeof(void*)], r10 - X86EmitIndexRegStore (SCRATCH_REGISTER_X86REG, step*sizeof(void*), kR10); - } - } -#endif // UNIX_AMD64_ABI // mov r10, [r11 + Delegate._methodptraux] X86EmitIndexRegLoad(kR10, kR11, DelegateObject::GetOffsetOfMethodPtrAux()); @@ -4140,6 +3913,7 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) #if !defined(CROSSGEN_COMPILE) && !defined(FEATURE_STUBS_AS_IL) +#if defined(_TARGET_X86_) && !defined(FEATURE_MULTICASTSTUB_AS_IL) //=========================================================================== // Computes hash code for MulticastDelegate.Invoke() UINT_PTR StubLinkerCPU::HashMulticastInvoke(MetaSig* pSig) @@ -4155,58 +3929,9 @@ UINT_PTR StubLinkerCPU::HashMulticastInvoke(MetaSig* pSig) UINT numStackBytes = argit.SizeOfArgStack(); - if (numStackBytes > 0x7FFF) + if (numStackBytes > 0x7FFF) COMPlusThrow(kNotSupportedException, W("NotSupported_TooManyArgs")); -#ifdef _TARGET_AMD64_ - // Generate a hash key as follows: - // UINT Arg0Type:2; // R4 (1), R8 (2), other (3) - // UINT Arg1Type:2; // R4 (1), R8 (2), other (3) - // UINT Arg2Type:2; // R4 (1), R8 (2), other (3) - // UINT Arg3Type:2; // R4 (1), R8 (2), other (3) - // UINT NumArgs:24; // number of arguments - // (This should cover all the prestub variations) - - _ASSERTE(!(numStackBytes & 7)); - UINT hash = (numStackBytes / sizeof(void*)) << 8; - - UINT argNum = 0; - - // NextArg() doesn't take into account the "this" pointer. - // That's why we have to special case it here. - if (argit.HasThis()) - { - hash |= 3 << (2*argNum); - argNum++; - } - - if (argit.HasRetBuffArg()) - { - hash |= 3 << (2*argNum); - argNum++; - } - - for (; argNum < 4; argNum++) - { - switch (pSig->NextArgNormalized()) - { - case ELEMENT_TYPE_END: - argNum = 4; - break; - case ELEMENT_TYPE_R4: - hash |= 1 << (2*argNum); - break; - case ELEMENT_TYPE_R8: - hash |= 2 << (2*argNum); - break; - default: - hash |= 3 << (2*argNum); - break; - } - } - -#else // _TARGET_AMD64_ - // check if the function is returning a float, in which case the stub has to take // care of popping the floating point stack except for the last invocation @@ -4218,10 +3943,10 @@ UINT_PTR StubLinkerCPU::HashMulticastInvoke(MetaSig* pSig) { hash |= 2; } -#endif // _TARGET_AMD64_ return hash; } +#endif // defined(_TARGET_X86_) && !defined(FEATURE_MULTICASTSTUB_AS_IL) #ifdef _TARGET_X86_ //=========================================================================== @@ -4260,6 +3985,7 @@ VOID StubLinkerCPU::EmitDelegateInvoke() } #endif // _TARGET_X86_ +#if defined(_TARGET_X86_) && !defined(FEATURE_MULTICASTSTUB_AS_IL) VOID StubLinkerCPU::EmitMulticastInvoke(UINT_PTR hash) { STANDARD_VM_CONTRACT; @@ -4274,60 +4000,8 @@ VOID StubLinkerCPU::EmitMulticastInvoke(UINT_PTR hash) // Push a MulticastFrame on the stack. EmitMethodStubProlog(MulticastFrame::GetMethodFrameVPtr(), MulticastFrame::GetOffsetOfTransitionBlock()); -#ifdef _TARGET_X86_ // Frame is ready to be inspected by debugger for patch location EmitPatchLabel(); -#else // _TARGET_AMD64_ - - // Save register arguments in their home locations. - // Non-FP registers are already saved by EmitMethodStubProlog. - // (Assumes Sig.NextArg() does not enum RetBuffArg or "this".) - - int argNum = 0; - __int32 argOfs = MulticastFrame::GetOffsetOfTransitionBlock() + TransitionBlock::GetOffsetOfArgs(); - CorElementType argTypes[4]; - CorElementType argType; - - // 'this' - argOfs += sizeof(void*); - argTypes[argNum] = ELEMENT_TYPE_I8; - argNum++; - - do - { - argType = ELEMENT_TYPE_END; - - switch ((hash >> (2 * argNum)) & 3) - { - case 0: - argType = ELEMENT_TYPE_END; - break; - case 1: - argType = ELEMENT_TYPE_R4; - - // movss dword ptr [rsp + argOfs], xmm? - X64EmitMovSSToMem((X86Reg)argNum, kRSI, argOfs); - break; - case 2: - argType = ELEMENT_TYPE_R8; - - // movsd qword ptr [rsp + argOfs], xmm? - X64EmitMovSDToMem((X86Reg)argNum, kRSI, argOfs); - break; - default: - argType = ELEMENT_TYPE_I; - break; - } - - argOfs += sizeof(void*); - argTypes[argNum] = argType; - argNum++; - } - while (argNum < 4 && ELEMENT_TYPE_END != argType); - - _ASSERTE(4 == argNum || ELEMENT_TYPE_END == argTypes[argNum-1]); - -#endif // _TARGET_AMD64_ // TODO: on AMD64, pick different regs for locals so don't need the pushes @@ -4354,102 +4028,6 @@ VOID StubLinkerCPU::EmitMulticastInvoke(UINT_PTR hash) // je ENDLOOP X86EmitCondJump(pEndLoopLabel, X86CondCode::kJZ); -#ifdef _TARGET_AMD64_ - - INT32 numStackBytes = (INT32)((hash >> 8) * sizeof(void *)); - - INT32 stackUsed, numStackArgs, ofs; - - // Push any stack args, plus an extra location - // for rsp alignment if needed - - numStackArgs = numStackBytes / sizeof(void*); - - // 1 push above, so stack is currently misaligned - const unsigned STACK_ALIGN_ADJUST = 8; - - if (!numStackArgs) - { - // sub rsp, 28h ;; 4 reg arg home locs + rsp alignment - stackUsed = 0x20 + STACK_ALIGN_ADJUST; - X86EmitSubEsp(stackUsed); - } - else - { - stackUsed = numStackArgs * sizeof(void*); - - // If the stack is misaligned, then an odd number of arguments - // will naturally align the stack. - if ( ((numStackArgs & 1) == 0) - != (STACK_ALIGN_ADJUST == 0)) - { - X86EmitPushReg(kRAX); - stackUsed += sizeof(void*); - } - - ofs = MulticastFrame::GetOffsetOfTransitionBlock() + - TransitionBlock::GetOffsetOfArgs() + sizeof(ArgumentRegisters) + numStackBytes; - - while (numStackArgs--) - { - ofs -= sizeof(void*); - - // push [rsi + ofs] ;; Push stack args - X86EmitIndexPush(kESI, ofs); - } - - // sub rsp, 20h ;; Create 4 reg arg home locations - X86EmitSubEsp(0x20); - - stackUsed += 0x20; - } - - for( - argNum = 0, argOfs = MulticastFrame::GetOffsetOfTransitionBlock() + TransitionBlock::GetOffsetOfArgs(); - argNum < 4 && argTypes[argNum] != ELEMENT_TYPE_END; - argNum++, argOfs += sizeof(void*) - ) - { - switch (argTypes[argNum]) - { - case ELEMENT_TYPE_R4: - // movss xmm?, dword ptr [rsi + argOfs] - X64EmitMovSSFromMem((X86Reg)argNum, kRSI, argOfs); - break; - case ELEMENT_TYPE_R8: - // movsd xmm?, qword ptr [rsi + argOfs] - X64EmitMovSDFromMem((X86Reg)argNum, kRSI, argOfs); - break; - default: - if (c_argRegs[argNum] != THIS_kREG) - { - // mov r*, [rsi + dstOfs] - X86EmitIndexRegLoad(c_argRegs[argNum], kESI,argOfs); - } - break; - } // switch - } - - // mov SCRATCHREG, [rcx+Delegate._invocationList] ;;fetch invocation list - X86EmitIndexRegLoad(SCRATCH_REGISTER_X86REG, THIS_kREG, DelegateObject::GetOffsetOfInvocationList()); - - // mov SCRATCHREG, [SCRATCHREG+m_Array+rdi*8] ;; index into invocation list - X86EmitOp(0x8b, kEAX, SCRATCH_REGISTER_X86REG, static_cast<int>(PtrArray::GetDataOffset()), kEDI, sizeof(void*), k64BitOp); - - // mov THISREG, [SCRATCHREG+Delegate.object] ;;replace "this" pointer - X86EmitIndexRegLoad(THIS_kREG, SCRATCH_REGISTER_X86REG, DelegateObject::GetOffsetOfTarget()); - - // call [SCRATCHREG+Delegate.target] ;; call current subscriber - X86EmitOffsetModRM(0xff, (X86Reg)2, SCRATCH_REGISTER_X86REG, DelegateObject::GetOffsetOfMethodPtr()); - - // add rsp, stackUsed ;; Clean up stack - X86EmitAddEsp(stackUsed); - - // inc edi - Emit16(0xC7FF); - -#else // _TARGET_AMD64_ - UINT16 numStackBytes = static_cast<UINT16>(hash & ~3); // ..repush & reenregister args.. @@ -4508,8 +4086,6 @@ VOID StubLinkerCPU::EmitMulticastInvoke(UINT_PTR hash) EmitLabel(pNoFloatStackPopLabel); } -#endif // _TARGET_AMD64_ - // The debugger may need to stop here, so grab the offset of this code. EmitPatchLabel(); @@ -4527,210 +4103,8 @@ VOID StubLinkerCPU::EmitMulticastInvoke(UINT_PTR hash) // Epilog EmitMethodStubEpilog(numStackBytes, MulticastFrame::GetOffsetOfTransitionBlock()); } +#endif // defined(_TARGET_X86_) && !defined(FEATURE_MULTICASTSTUB_AS_IL) -VOID StubLinkerCPU::EmitSecureDelegateInvoke(UINT_PTR hash) -{ - STANDARD_VM_CONTRACT; - - int thisRegOffset = SecureDelegateFrame::GetOffsetOfTransitionBlock() + - TransitionBlock::GetOffsetOfArgumentRegisters() + offsetof(ArgumentRegisters, THIS_REG); - - // push the methoddesc on the stack - // mov eax, [ecx + offsetof(_invocationCount)] - X86EmitIndexRegLoad(SCRATCH_REGISTER_X86REG, THIS_kREG, DelegateObject::GetOffsetOfInvocationCount()); - - // Push a SecureDelegateFrame on the stack. - EmitMethodStubProlog(SecureDelegateFrame::GetMethodFrameVPtr(), SecureDelegateFrame::GetOffsetOfTransitionBlock()); - -#ifdef _TARGET_X86_ - // Frame is ready to be inspected by debugger for patch location - EmitPatchLabel(); -#else // _TARGET_AMD64_ - - // Save register arguments in their home locations. - // Non-FP registers are already saved by EmitMethodStubProlog. - // (Assumes Sig.NextArg() does not enum RetBuffArg or "this".) - - int argNum = 0; - __int32 argOfs = SecureDelegateFrame::GetOffsetOfTransitionBlock() + TransitionBlock::GetOffsetOfArgs(); - CorElementType argTypes[4]; - CorElementType argType; - - // 'this' - argOfs += sizeof(void*); - argTypes[argNum] = ELEMENT_TYPE_I8; - argNum++; - - do - { - argType = ELEMENT_TYPE_END; - - switch ((hash >> (2 * argNum)) & 3) - { - case 0: - argType = ELEMENT_TYPE_END; - break; - case 1: - argType = ELEMENT_TYPE_R4; - - // movss dword ptr [rsp + argOfs], xmm? - X64EmitMovSSToMem((X86Reg)argNum, kRSI, argOfs); - break; - case 2: - argType = ELEMENT_TYPE_R8; - - // movsd qword ptr [rsp + argOfs], xmm? - X64EmitMovSSToMem((X86Reg)argNum, kRSI, argOfs); - break; - default: - argType = ELEMENT_TYPE_I; - break; - } - - argOfs += sizeof(void*); - argTypes[argNum] = argType; - argNum++; - } - while (argNum < 4 && ELEMENT_TYPE_END != argType); - - _ASSERTE(4 == argNum || ELEMENT_TYPE_END == argTypes[argNum-1]); - -#endif // _TARGET_AMD64_ - - // mov ecx, [esi + this] ;; get delegate - X86EmitIndexRegLoad(THIS_kREG, kESI, thisRegOffset); - -#ifdef _TARGET_AMD64_ - - INT32 numStackBytes = (INT32)((hash >> 8) * sizeof(void *)); - - INT32 stackUsed, numStackArgs, ofs; - - // Push any stack args, plus an extra location - // for rsp alignment if needed - - numStackArgs = numStackBytes / sizeof(void*); - - // 1 push above, so stack is currently misaligned - const unsigned STACK_ALIGN_ADJUST = 0; - - if (!numStackArgs) - { - // sub rsp, 28h ;; 4 reg arg home locs + rsp alignment - stackUsed = 0x20 + STACK_ALIGN_ADJUST; - X86EmitSubEsp(stackUsed); - } - else - { - stackUsed = numStackArgs * sizeof(void*); - - // If the stack is misaligned, then an odd number of arguments - // will naturally align the stack. - if ( ((numStackArgs & 1) == 0) - != (STACK_ALIGN_ADJUST == 0)) - { - X86EmitPushReg(kRAX); - stackUsed += sizeof(void*); - } - - ofs = SecureDelegateFrame::GetOffsetOfTransitionBlock() + - TransitionBlock::GetOffsetOfArgs() + sizeof(ArgumentRegisters) + numStackBytes; - - while (numStackArgs--) - { - ofs -= sizeof(void*); - - // push [rsi + ofs] ;; Push stack args - X86EmitIndexPush(kESI, ofs); - } - - // sub rsp, 20h ;; Create 4 reg arg home locations - X86EmitSubEsp(0x20); - - stackUsed += 0x20; - } - - int thisArgNum = 0; - - for( - argNum = 0, argOfs = SecureDelegateFrame::GetOffsetOfTransitionBlock() + TransitionBlock::GetOffsetOfArgs(); - argNum < 4 && argTypes[argNum] != ELEMENT_TYPE_END; - argNum++, argOfs += sizeof(void*) - ) - { - switch (argTypes[argNum]) - { - case ELEMENT_TYPE_R4: - // movss xmm?, dword ptr [rsi + argOfs] - X64EmitMovSSFromMem((X86Reg)argNum, kRSI, argOfs); - break; - case ELEMENT_TYPE_R8: - // movsd xmm?, qword ptr [rsi + argOfs] - X64EmitMovSDFromMem((X86Reg)argNum, kRSI, argOfs); - break; - default: - if (c_argRegs[argNum] != THIS_kREG) - { - // mov r*, [rsi + dstOfs] - X86EmitIndexRegLoad(c_argRegs[argNum], kESI,argOfs); - } - break; - } // switch - } - - // mov SCRATCHREG, [rcx+Delegate._invocationList] ;;fetch the inner delegate - X86EmitIndexRegLoad(SCRATCH_REGISTER_X86REG, THIS_kREG, DelegateObject::GetOffsetOfInvocationList()); - - // mov THISREG, [SCRATCHREG+Delegate.object] ;;replace "this" pointer - X86EmitIndexRegLoad(c_argRegs[thisArgNum], SCRATCH_REGISTER_X86REG, DelegateObject::GetOffsetOfTarget()); - - // call [SCRATCHREG+Delegate.target] ;; call current subscriber - X86EmitOffsetModRM(0xff, (X86Reg)2, SCRATCH_REGISTER_X86REG, DelegateObject::GetOffsetOfMethodPtr()); - - // add rsp, stackUsed ;; Clean up stack - X86EmitAddEsp(stackUsed); - -#else // _TARGET_AMD64_ - - UINT16 numStackBytes = static_cast<UINT16>(hash & ~3); - - // ..repush & reenregister args.. - INT32 ofs = numStackBytes + SecureDelegateFrame::GetOffsetOfTransitionBlock() + TransitionBlock::GetOffsetOfArgs(); - while (ofs != SecureDelegateFrame::GetOffsetOfTransitionBlock() + TransitionBlock::GetOffsetOfArgs()) - { - ofs -= sizeof(void*); - X86EmitIndexPush(kESI, ofs); - } - - #define ARGUMENT_REGISTER(regname) if (k##regname != THIS_kREG) { X86EmitIndexRegLoad(k##regname, kESI, \ - offsetof(ArgumentRegisters, regname) + SecureDelegateFrame::GetOffsetOfTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters()); } - - ENUM_ARGUMENT_REGISTERS_BACKWARD(); - - #undef ARGUMENT_REGISTER - - // mov SCRATCHREG, [ecx+Delegate._invocationList] ;;fetch the inner delegate - X86EmitIndexRegLoad(SCRATCH_REGISTER_X86REG, THIS_kREG, DelegateObject::GetOffsetOfInvocationList()); - - // mov THISREG, [SCRATCHREG+Delegate.object] ;;replace "this" pointer - X86EmitIndexRegLoad(THIS_kREG, SCRATCH_REGISTER_X86REG, DelegateObject::GetOffsetOfTarget()); - - // call [SCRATCHREG+Delegate.target] ;; call current subscriber - X86EmitOffsetModRM(0xff, (X86Reg)2, SCRATCH_REGISTER_X86REG, DelegateObject::GetOffsetOfMethodPtr()); - INDEBUG(Emit8(0x90)); // Emit a nop after the call in debug so that - // we know that this is a call that can directly call - // managed code - -#endif // _TARGET_AMD64_ - - // The debugger may need to stop here, so grab the offset of this code. - EmitPatchLabel(); - - EmitCheckGSCookie(kESI, SecureDelegateFrame::GetOffsetOfGSCookie()); - - // Epilog - EmitMethodStubEpilog(numStackBytes, SecureDelegateFrame::GetOffsetOfTransitionBlock()); -} #endif // !CROSSGEN_COMPILE && !FEATURE_STUBS_AS_IL #if !defined(CROSSGEN_COMPILE) && !defined(FEATURE_ARRAYSTUB_AS_IL) |