2 // The .NET Foundation licenses this file to you under the MIT license.
5 #error Should only include "cGenCpu.h" for RISCV64 builds
15 #define USE_REDIRECT_FOR_GCSTRESS
18 EXTERN_C void getFPReturn(int fpSize, INT64 *pRetVal);
19 EXTERN_C void setFPReturn(int fpSize, INT64 retVal);
22 class ComCallMethodDesc;
24 extern PCODE GetPreStubEntryPoint();
26 #define COMMETHOD_PREPAD 24 // # extra bytes to allocate in addition to sizeof(ComCallMethodDesc)
27 #ifdef FEATURE_COMINTEROP
28 #define COMMETHOD_CALL_PRESTUB_SIZE 24
29 #define COMMETHOD_CALL_PRESTUB_ADDRESS_OFFSET 16 // the offset of the call target address inside the prestub
30 #endif // FEATURE_COMINTEROP
32 #define STACK_ALIGN_SIZE 16
34 #define JUMP_ALLOCATE_SIZE 40 // # bytes to allocate for a jump instruction
35 #define BACK_TO_BACK_JUMP_ALLOCATE_SIZE 40 // # bytes to allocate for a back to back jump instruction
37 #define HAS_NDIRECT_IMPORT_PRECODE 1
39 #define USE_INDIRECT_CODEHEADER
41 #define HAS_FIXUP_PRECODE 1
43 // ThisPtrRetBufPrecode one is necessary for closed delegates over static methods with return buffer
44 #define HAS_THISPTR_RETBUF_PRECODE 1
46 #define CODE_SIZE_ALIGN 8
47 #define CACHE_LINE_SIZE 64
48 #define LOG2SLOT LOG2_PTRSIZE
50 #define ENREGISTERED_RETURNTYPE_MAXSIZE 16 // bytes (two FP registers: f10 and f11
51 #define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE 16 // bytes (two int registers: a0 and a1)
52 #define ENREGISTERED_PARAMTYPE_MAXSIZE 16 // bytes (max value type size that can be passed by value)
54 #define CALLDESCR_ARGREGS 1 // CallDescrWorker has ArgumentRegister parameter
55 #define CALLDESCR_FPARGREGS 1 // CallDescrWorker has FloatArgumentRegisters parameter
57 #define FLOAT_REGISTER_SIZE 8 // each register in FloatArgumentRegisters is 8 bytes.
59 // Given a return address retrieved during stackwalk,
60 // this is the offset by which it should be decremented to arrive at the callsite.
61 #define STACKWALK_CONTROLPC_ADJUST_OFFSET 4
63 //**********************************************************************
65 //**********************************************************************
67 inline unsigned StackElemSize(unsigned parmSize, bool isValueType, bool isFloatHfa)
69 const unsigned stackSlotSize = 8;
70 return ALIGN_UP(parmSize, stackSlotSize);
76 // Create alias for optimized implementations of helpers provided on this platform
78 #define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain
79 #define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain
80 #define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
81 #define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
83 //**********************************************************************
85 //**********************************************************************
87 //--------------------------------------------------------------------
88 // This represents the callee saved (non-volatile) integer registers saved as
89 // of a FramedMethodFrame.
90 //--------------------------------------------------------------------
91 typedef DPTR(struct CalleeSavedRegisters) PTR_CalleeSavedRegisters;
92 struct CalleeSavedRegisters {
93 INT64 fp; // frame pointer
94 INT64 ra; // return register
95 INT64 s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11;
99 //--------------------------------------------------------------------
100 // This represents the arguments that are stored in volatile integer registers.
101 // This should not overlap the CalleeSavedRegisters since those are already
102 // saved separately and it would be wasteful to save the same register twice.
103 // If we do use a non-volatile register as an argument, then the ArgIterator
104 // will probably have to communicate this back to the PromoteCallerStack
105 // routine to avoid a double promotion.
106 //--------------------------------------------------------------------
107 #define NUM_ARGUMENT_REGISTERS 8
108 typedef DPTR(struct ArgumentRegisters) PTR_ArgumentRegisters;
109 struct ArgumentRegisters {
110 INT64 a[NUM_ARGUMENT_REGISTERS]; // a0 ....a7
113 #define ARGUMENTREGISTERS_SIZE sizeof(ArgumentRegisters)
116 //--------------------------------------------------------------------
117 // This represents the floating point argument registers which are saved
118 // as part of the NegInfo for a FramedMethodFrame. Note that these
119 // might not be saved by all stubs: typically only those that call into
120 // C++ helpers will need to preserve the values in these volatile
122 //--------------------------------------------------------------------
123 #define NUM_FLOAT_ARGUMENT_REGISTERS 8
124 typedef DPTR(struct FloatArgumentRegisters) PTR_FloatArgumentRegisters;
125 struct FloatArgumentRegisters {
126 //TODO: not supports RISCV64-SIMD.
127 double f[NUM_FLOAT_ARGUMENT_REGISTERS]; // f0-f7
130 //**********************************************************************
132 //**********************************************************************
134 #ifdef PROFILING_SUPPORTED
136 struct PROFILE_PLATFORM_SPECIFIC_DATA
140 ArgumentRegisters argumentRegisters;
141 FunctionID functionId;
142 FloatArgumentRegisters floatArgumentRegisters;
147 // Scratch space to reconstruct struct passed in two registers
148 BYTE buffer[sizeof(ArgumentRegisters) + sizeof(FloatArgumentRegisters)];
150 #endif // PROFILING_SUPPORTED
152 //**********************************************************************
153 // Exception handling
154 //**********************************************************************
156 inline PCODE GetIP(const T_CONTEXT * context) {
157 LIMITED_METHOD_DAC_CONTRACT;
161 inline void SetIP(T_CONTEXT *context, PCODE ip) {
162 LIMITED_METHOD_DAC_CONTRACT;
166 inline TADDR GetSP(const T_CONTEXT * context) {
167 LIMITED_METHOD_DAC_CONTRACT;
168 return TADDR(context->Sp);
171 inline TADDR GetRA(const T_CONTEXT * context) {
172 LIMITED_METHOD_DAC_CONTRACT;
176 inline void SetRA( T_CONTEXT * context, TADDR ip) {
177 LIMITED_METHOD_DAC_CONTRACT;
181 inline TADDR GetReg(T_CONTEXT * context, int Regnum)
183 LIMITED_METHOD_DAC_CONTRACT;
184 _ASSERTE(Regnum >= 0 && Regnum < 32 );
185 return (TADDR)(&context->R0 + Regnum);
188 inline void SetReg(T_CONTEXT * context, int Regnum, PCODE RegContent)
190 LIMITED_METHOD_DAC_CONTRACT;
191 _ASSERTE(Regnum >= 0 && Regnum <=28 );
192 *(&context->R0 + Regnum) = RegContent;
195 extern "C" LPVOID __stdcall GetCurrentSP();
197 inline void SetSP(T_CONTEXT *context, TADDR sp) {
198 LIMITED_METHOD_DAC_CONTRACT;
199 context->Sp = DWORD64(sp);
202 inline void SetFP(T_CONTEXT *context, TADDR fp) {
203 LIMITED_METHOD_DAC_CONTRACT;
204 context->Fp = DWORD64(fp);
207 inline TADDR GetFP(const T_CONTEXT * context)
209 LIMITED_METHOD_DAC_CONTRACT;
210 return (TADDR)(context->Fp);
214 inline TADDR GetMem(PCODE address, SIZE_T size, bool signExtend)
217 LIMITED_METHOD_DAC_CONTRACT;
224 mem = *(int32_t*)address;
226 mem = *(uint32_t*)address;
229 mem = *(uint64_t*)address;
238 _ASSERTE(!"Memory read within jitted Code Failed, this should not happen!!!!");
240 EX_END_CATCH(SwallowAllExceptions);
244 #ifdef FEATURE_COMINTEROP
245 void emitCOMStubCall (ComCallMethodDesc *pCOMMethodRX, ComCallMethodDesc *pCOMMethodRW, PCODE target);
246 #endif // FEATURE_COMINTEROP
248 inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode, bool hasCodeExecutedBefore = false)
250 return FlushInstructionCache(GetCurrentProcess(), pCodeAddr, sizeOfCode);
253 //------------------------------------------------------------------------
254 inline void emitJump(LPBYTE pBufferRX, LPBYTE pBufferRW, LPVOID target)
256 LIMITED_METHOD_CONTRACT;
257 UINT32* pCode = (UINT32*)pBufferRW;
259 // We require 8-byte alignment so the LD instruction is aligned properly
260 _ASSERTE(((UINT_PTR)pCode & 7) == 0);
267 pCode[0] = 0x00000097; // auipc ra, 0
268 pCode[1] = 0x0100b083; // ld ra, 16(ra)
269 pCode[2] = 0x00008067; // jalr x0, ra, 0
270 pCode[3] = 0x00000013; // padding nop.
272 // Ensure that the updated instructions get updated in the I-Cache
273 ClrFlushInstructionCache(pBufferRX, 16);
275 *((LPVOID *)(pCode + 4)) = target; // 64-bit target address
278 //------------------------------------------------------------------------
279 // Given the same pBuffer that was used by emitJump this method
280 // decodes the instructions and returns the jump target
281 inline PCODE decodeJump(PCODE pCode)
283 LIMITED_METHOD_CONTRACT;
285 TADDR pInstr = PCODEToPINSTR(pCode);
287 return *dac_cast<PTR_PCODE>(pInstr + 4 * sizeof(UINT32));
290 //------------------------------------------------------------------------
291 inline void emitBackToBackJump(LPBYTE pBufferRX, LPBYTE pBufferRW, LPVOID target)
294 emitJump(pBufferRX, pBufferRW, target);
297 //------------------------------------------------------------------------
298 inline PCODE decodeBackToBackJump(PCODE pBuffer)
301 return decodeJump(pBuffer);
304 //----------------------------------------------------------------------
309 IntReg(int reg):reg(reg)
311 _ASSERTE(0 <= reg && reg < 32);
314 operator int () { return reg; }
315 operator int () const { return reg; }
316 int operator == (IntReg other) { return reg == other.reg; }
317 int operator != (IntReg other) { return reg != other.reg; }
318 WORD Mask() const { return 1 << reg; }
324 FloatReg(int reg):reg(reg)
326 _ASSERTE(0 <= reg && reg < 32);
329 operator int () { return reg; }
330 operator int () const { return reg; }
331 int operator == (FloatReg other) { return reg == other.reg; }
332 int operator != (FloatReg other) { return reg != other.reg; }
333 WORD Mask() const { return 1 << reg; }
339 CondCode(int cond):cond(cond)
341 _ASSERTE(0 <= cond && cond < 16);
345 const IntReg RegSp = IntReg(2);
346 const IntReg RegFp = IntReg(8);
347 const IntReg RegRa = IntReg(1);
349 #define GetEEFuncEntryPoint(pfn) GFN_TADDR(pfn)
351 class StubLinkerCPU : public StubLinker
355 static bool isValidSimm12(int value) {
356 return -( ((int)1) << 11 ) <= value && value < ( ((int)1) << 11 );
358 static bool isValidSimm13(int value) {
359 return -(((int)1) << 12) <= value && value < (((int)1) << 12);
361 static bool isValidUimm20(int value) {
362 return (0 == (value >> 20));
364 void EmitCallManagedMethod(MethodDesc *pMD, BOOL fTailCall);
365 void EmitCallLabel(CodeLabel *target, BOOL fTailCall, BOOL fIndirect);
367 void EmitShuffleThunk(struct ShuffleEntry *pShuffleEntryArray);
369 #if defined(FEATURE_SHARE_GENERIC_CODE)
370 void EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, struct ShuffleEntry *pShuffleEntryArray, void* extraArg);
371 #endif // FEATURE_SHARE_GENERIC_CODE
373 void EmitMovConstant(IntReg target, UINT64 constant);
374 void EmitJumpRegister(IntReg regTarget);
375 void EmitMovReg(IntReg dest, IntReg source);
376 void EmitMovReg(FloatReg dest, FloatReg source);
378 void EmitSubImm(IntReg Xd, IntReg Xn, unsigned int value);
379 void EmitAddImm(IntReg Xd, IntReg Xn, unsigned int value);
380 void EmitSllImm(IntReg Xd, IntReg Xn, unsigned int value);
381 void EmitLuImm(IntReg Xd, unsigned int value);
383 void EmitLoad(IntReg dest, IntReg srcAddr, int offset = 0);
384 void EmitLoad(FloatReg dest, IntReg srcAddr, int offset = 0);
385 void EmitStore(IntReg src, IntReg destAddr, int offset = 0);
386 void EmitStore(FloatReg src, IntReg destAddr, int offset = 0);
388 void EmitProlog(unsigned short cIntRegArgs, unsigned short cFpRegArgs, unsigned short cbStackSpace = 0);
392 extern "C" void SinglecastDelegateInvokeStub();
395 // preferred alignment for data
396 #define DATA_ALIGNMENT 8
399 struct DECLSPEC_ALIGN(16) UMEntryThunkCode
404 TADDR m_pvSecretParam;
406 void Encode(UMEntryThunkCode *pEntryThunkCodeRX, BYTE* pTargetCode, void* pvSecretParam);
409 LPCBYTE GetEntryPoint() const
411 LIMITED_METHOD_CONTRACT;
413 return (LPCBYTE)this;
416 static int GetEntryPointOffset()
418 LIMITED_METHOD_CONTRACT;
432 size_t ReturnValue[2];
440 size_t FPReturnValue[2];
442 DWORD64 Fp; // frame pointer
443 DWORD64 Gp, Tp, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11;
447 size_t ReturnAddress;
451 // Precode to shuffle this and retbuf for closed delegates over static methods with return buffer
452 struct ThisPtrRetBufPrecode {
454 static const int Type = 0x93;
460 void Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator);
462 TADDR GetMethodDesc()
464 LIMITED_METHOD_DAC_CONTRACT;
466 return m_pMethodDesc;
471 LIMITED_METHOD_DAC_CONTRACT;
475 #ifndef DACCESS_COMPILE
476 BOOL SetTargetInterlocked(TADDR target, TADDR expected)
485 ExecutableWriterHolder<ThisPtrRetBufPrecode> precodeWriterHolder(this, sizeof(ThisPtrRetBufPrecode));
486 return (TADDR)InterlockedCompareExchange64(
487 (LONGLONG*)&precodeWriterHolder.GetRW()->m_pTarget, (TADDR)target, (TADDR)expected) == expected;
489 #endif // !DACCESS_COMPILE
491 typedef DPTR(ThisPtrRetBufPrecode) PTR_ThisPtrRetBufPrecode;
493 #endif // __cgencpu_h__