Deal with cross-bitness compilation warnings Pt.2 (#19781)
[platform/upstream/coreclr.git] / src / vm / arm / cgencpu.h
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5
6
7 #ifndef _TARGET_ARM_
8 #error Should only include "cGenCpu.h" for ARM builds
9 #endif
10
11 #ifndef __cgencpu_h__
12 #define __cgencpu_h__
13
14 #include "utilcode.h"
15
16 // preferred alignment for data
17 #define DATA_ALIGNMENT 4
18
19 #define DISPATCH_STUB_FIRST_WORD 0xf8d0
20 #define RESOLVE_STUB_FIRST_WORD 0xf8d0
21
22 class MethodDesc;
23 class FramedMethodFrame;
24 class Module;
25 struct DeclActionInfo;
26 class ComCallMethodDesc;
27 class BaseDomain;
28 class ZapNode;
29 struct ArgLocDesc;
30
31 extern PCODE GetPreStubEntryPoint();
32
33 #ifndef FEATURE_PAL
34 #define USE_REDIRECT_FOR_GCSTRESS
35 #endif // FEATURE_PAL
36
37 // CPU-dependent functions
38 Stub * GenerateInitPInvokeFrameHelper();
39
40 EXTERN_C void checkStack(void);
41
42 #define THUMB_CODE      1
43
44 #ifdef CROSSGEN_COMPILE
45 #define GetEEFuncEntryPoint(pfn) 0x1001
46 #else
47 #define GetEEFuncEntryPoint(pfn) (GFN_TADDR(pfn) | THUMB_CODE)
48 #endif
49
50 //**********************************************************************
51
52 #define COMMETHOD_PREPAD                        12   // # extra bytes to allocate in addition to sizeof(ComCallMethodDesc)
53 #ifdef FEATURE_COMINTEROP
54 #define COMMETHOD_CALL_PRESTUB_SIZE             12
55 #define COMMETHOD_CALL_PRESTUB_ADDRESS_OFFSET   8   // the offset of the call target address inside the prestub
56 #endif // FEATURE_COMINTEROP
57
58 #define STACK_ALIGN_SIZE                        4
59
60 #define JUMP_ALLOCATE_SIZE                      8   // # bytes to allocate for a jump instruction
61 #define BACK_TO_BACK_JUMP_ALLOCATE_SIZE         8   // # bytes to allocate for a back to back jump instruction
62
63 #define HAS_COMPACT_ENTRYPOINTS                 1
64
65 #define HAS_NDIRECT_IMPORT_PRECODE              1
66
67 #define USE_INDIRECT_CODEHEADER
68
69
70 EXTERN_C void getFPReturn(int fpSize, INT64 *pRetVal);
71 EXTERN_C void setFPReturn(int fpSize, INT64 retVal);
72
73 #define HAS_FIXUP_PRECODE                       1
74 #define HAS_FIXUP_PRECODE_CHUNKS                1
75
76 // ThisPtrRetBufPrecode one is necessary for closed delegates over static methods with return buffer
77 #define HAS_THISPTR_RETBUF_PRECODE              1
78
79 #define CODE_SIZE_ALIGN                         4
80 #define CACHE_LINE_SIZE                         32  // As per Intel Optimization Manual the cache line size is 32 bytes
81 #define LOG2SLOT                                LOG2_PTRSIZE
82
83 #define ENREGISTERED_RETURNTYPE_MAXSIZE         32  // bytes (maximum HFA size is 4 doubles)
84 #define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE 4   // bytes
85
86 #define CALLDESCR_ARGREGS                       1   // CallDescrWorker has ArgumentRegister parameter
87 #define CALLDESCR_FPARGREGS                     1   // CallDescrWorker has FloatArgumentRegisters parameter
88
89 // Given a return address retrieved during stackwalk,
90 // this is the offset by which it should be decremented to arrive at the callsite.
91 #define STACKWALK_CONTROLPC_ADJUST_OFFSET 2
92
93 // Max offset for unconditional thumb branch
94 #define MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB 2048
95
96 // Offset of pc register
97 #define PC_REG_RELATIVE_OFFSET 4
98
99 //=======================================================================
100 // IMPORTANT: This value is used to figure out how much to allocate
101 // for a fixed array of FieldMarshaler's. That means it must be at least
102 // as large as the largest FieldMarshaler subclass. This requirement
103 // is guarded by an assert.
104 //=======================================================================
105 #ifdef _WIN64
106 #define MAXFIELDMARSHALERSIZE               40
107 #else
108 #define MAXFIELDMARSHALERSIZE               24
109 #endif
110
111 //**********************************************************************
112 // Parameter size
113 //**********************************************************************
114
115 typedef INT32 StackElemType;
116 #define STACK_ELEM_SIZE sizeof(StackElemType)
117
118 // !! This expression assumes STACK_ELEM_SIZE is a power of 2.
119 #define StackElemSize(parmSize) (((parmSize) + STACK_ELEM_SIZE - 1) & ~((ULONG)(STACK_ELEM_SIZE - 1)))
120
121 //**********************************************************************
122 // Frames
123 //**********************************************************************
124
125 //--------------------------------------------------------------------
126 // This represents the callee saved (non-volatile) registers saved as
127 // of a FramedMethodFrame.
128 //--------------------------------------------------------------------
129 typedef DPTR(struct CalleeSavedRegisters) PTR_CalleeSavedRegisters;
130 struct CalleeSavedRegisters {
131     INT32 r4, r5, r6, r7, r8, r9, r10;
132     INT32 r11; // frame pointer
133     INT32 r14; // link register
134 };
135
136 //--------------------------------------------------------------------
137 // This represents the arguments that are stored in volatile registers.
138 // This should not overlap the CalleeSavedRegisters since those are already
139 // saved separately and it would be wasteful to save the same register twice.
140 // If we do use a non-volatile register as an argument, then the ArgIterator
141 // will probably have to communicate this back to the PromoteCallerStack
142 // routine to avoid a double promotion.
143 //--------------------------------------------------------------------
144 typedef DPTR(struct ArgumentRegisters) PTR_ArgumentRegisters;
145 struct ArgumentRegisters {
146     INT32 r[4]; // r0, r1, r2, r3
147 };
148 #define NUM_ARGUMENT_REGISTERS 4
149
150 //--------------------------------------------------------------------
151 // This represents the floating point argument registers which are saved
152 // as part of the NegInfo for a FramedMethodFrame. Note that these
153 // might not be saved by all stubs: typically only those that call into
154 // C++ helpers will need to preserve the values in these volatile
155 // registers.
156 //--------------------------------------------------------------------
157 typedef DPTR(struct FloatArgumentRegisters) PTR_FloatArgumentRegisters;
158 struct FloatArgumentRegisters {
159     union
160     {
161         float   s[16];  // s0-s15
162         double  d[8];   // d0-d7
163     };
164 };
165
166 // forward decl
167 struct REGDISPLAY;
168 typedef REGDISPLAY *PREGDISPLAY;
169
170 // Sufficient context for Try/Catch restoration.
171 struct EHContext {
172     INT32 r[16]; // note: includes r15(pc)
173     void Setup(PCODE resumePC, PREGDISPLAY regs);
174
175     inline TADDR GetSP() {
176         LIMITED_METHOD_CONTRACT;
177         return (TADDR)r[13];
178     }
179     inline void SetSP(LPVOID esp) {
180         LIMITED_METHOD_CONTRACT;
181         r[13] = (INT32)(size_t)esp;
182     }
183
184     inline LPVOID GetFP() {
185         LIMITED_METHOD_CONTRACT;
186         return (LPVOID)(UINT_PTR)r[11];
187     }
188
189     inline void SetArg(LPVOID arg) {
190         LIMITED_METHOD_CONTRACT;
191         r[0] = (INT32)(size_t)arg;
192     }
193 };
194
195 #define ARGUMENTREGISTERS_SIZE sizeof(ArgumentRegisters)
196
197 //**********************************************************************
198 // Exception handling
199 //**********************************************************************
200
201 inline PCODE GetIP(const T_CONTEXT * context) {
202     LIMITED_METHOD_DAC_CONTRACT;
203     return PCODE(context->Pc);
204 }
205
206 inline void SetIP(T_CONTEXT *context, PCODE eip) {
207     LIMITED_METHOD_DAC_CONTRACT;
208     context->Pc = DWORD(eip);
209 }
210
211 inline TADDR GetSP(const T_CONTEXT * context) {
212     LIMITED_METHOD_DAC_CONTRACT;
213     return TADDR(context->Sp);
214 }
215
216 inline PCODE GetLR(const T_CONTEXT * context) {
217     LIMITED_METHOD_DAC_CONTRACT;
218     return PCODE(context->Lr);
219 }
220
221 extern "C" LPVOID __stdcall GetCurrentSP();
222
223 inline void SetSP(T_CONTEXT *context, TADDR esp) {
224     LIMITED_METHOD_DAC_CONTRACT;
225     context->Sp = DWORD(esp);
226 }
227
228 inline void SetFP(T_CONTEXT *context, TADDR ebp) {
229     LIMITED_METHOD_DAC_CONTRACT;
230     context->R11 = DWORD(ebp);
231 }
232
233 inline TADDR GetFP(const T_CONTEXT * context)
234 {
235     LIMITED_METHOD_DAC_CONTRACT;
236     return (TADDR)(context->R11);
237 }
238
239 inline void ClearITState(T_CONTEXT *context) {
240     LIMITED_METHOD_DAC_CONTRACT;
241     context->Cpsr = context->Cpsr & 0xf9ff03ff;
242 }
243
244 #ifdef FEATURE_COMINTEROP
245 void emitCOMStubCall (ComCallMethodDesc *pCOMMethod, PCODE target);
246 #endif // FEATURE_COMINTEROP
247
248 //------------------------------------------------------------------------
249 inline void emitUnconditionalBranchThumb(LPBYTE pBuffer, int16_t offset)
250 {
251     LIMITED_METHOD_CONTRACT;
252
253     uint16_t *pInstr = (uint16_t *) pBuffer;
254
255     // offset from -2KB to +2KB
256     _ASSERTE (offset >= - MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB && offset < MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB);
257
258     if (offset >= 0)
259     {
260         offset = offset >> 1;
261     }
262     else
263     {
264         offset = ((MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB + offset) >> 1) | 0x400;
265     }
266
267     *pInstr = 0xE000 | offset;
268 }
269
270 //------------------------------------------------------------------------
271 inline int16_t decodeUnconditionalBranchThumb(LPBYTE pBuffer)
272 {
273     LIMITED_METHOD_CONTRACT;
274
275     uint16_t *pInstr = (uint16_t *) pBuffer;
276
277     int16_t offset = (~0xE000) & (*pInstr);
278
279     if ((offset & 0x400) == 0)
280     {
281         offset = offset << 1;
282     }
283     else
284     {
285         offset = (~0x400) & offset;
286         offset = (offset << 1) - MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB;
287     }
288
289     // offset from -2KB to +2KB
290     _ASSERTE (offset >= - MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB && offset < MAX_OFFSET_UNCONDITIONAL_BRANCH_THUMB);
291
292     return offset;
293 }
294
295 //------------------------------------------------------------------------
296 inline void emitJump(LPBYTE pBuffer, LPVOID target)
297 {
298     LIMITED_METHOD_CONTRACT;
299
300     // The PC-relative load we emit below requires 4-byte alignment for the offset to be calculated correctly.
301     _ASSERTE(((UINT_PTR)pBuffer & 3) == 0);
302
303     DWORD * pCode = (DWORD *)pBuffer;
304
305     // ldr pc, [pc, #0]
306     pCode[0] = 0xf000f8df;
307     pCode[1] = (DWORD)target;
308 }
309
310 //------------------------------------------------------------------------
311 //  Given the same pBuffer that was used by emitJump this method
312 //  decodes the instructions and returns the jump target
313 inline PCODE decodeJump(PCODE pCode)
314 {
315     LIMITED_METHOD_CONTRACT;
316
317     TADDR pInstr = PCODEToPINSTR(pCode);
318
319     return *dac_cast<PTR_PCODE>(pInstr + sizeof(DWORD));
320 }
321
322 //
323 // On IA64 back to back jumps should be separated by a nop bundle to get
324 // the best performance from the hardware's branch prediction logic.
325 // For all other platforms back to back jumps don't require anything special
326 // That is why we have these two wrapper functions that call emitJump and decodeJump
327 //
328
329 //------------------------------------------------------------------------
330 inline BOOL isJump(PCODE pCode)
331 {
332     LIMITED_METHOD_DAC_CONTRACT;
333
334     TADDR pInstr = PCODEToPINSTR(pCode);
335
336     return *dac_cast<PTR_DWORD>(pInstr) == 0xf000f8df;
337 }
338
339 //------------------------------------------------------------------------
340 inline BOOL isBackToBackJump(PCODE pBuffer)
341 {
342     WRAPPER_NO_CONTRACT;
343     SUPPORTS_DAC;
344     return isJump(pBuffer);
345 }
346
347 //------------------------------------------------------------------------
348 inline void emitBackToBackJump(LPBYTE pBuffer, LPVOID target)
349 {
350     WRAPPER_NO_CONTRACT;
351     emitJump(pBuffer, target);
352 }
353
354 //------------------------------------------------------------------------
355 inline PCODE decodeBackToBackJump(PCODE pBuffer)
356 {
357     WRAPPER_NO_CONTRACT;
358     return decodeJump(pBuffer);
359 }
360
361 //----------------------------------------------------------------------
362 #include "stublink.h"
363 struct ArrayOpScript;
364
365 inline BOOL IsThumbCode(PCODE pCode)
366 {
367     return (pCode & THUMB_CODE) != 0;
368 }
369
370 struct ThumbReg
371 {
372     int reg;
373     ThumbReg(int reg):reg(reg)
374     {
375         _ASSERTE(0 <= reg && reg < 16);
376     }
377
378     operator int ()
379     {
380         return reg;
381     }
382
383     int operator == (ThumbReg other)
384     {
385         return reg == other.reg;
386     }
387
388     int operator != (ThumbReg other)
389     {
390         return reg != other.reg;
391     }
392
393     WORD Mask() const
394     {
395         return 1 << reg;
396     }
397
398 };
399
400 struct ThumbCond
401 {
402     int cond;
403     ThumbCond(int cond):cond(cond)
404     {
405         _ASSERTE(0 <= cond && cond < 16);
406     }
407 };
408
409 struct ThumbVFPSingleReg
410 {
411     int reg;
412     ThumbVFPSingleReg(int reg):reg(reg)
413     {
414         _ASSERTE(0 <= reg && reg < 31);
415     }
416
417     operator int ()
418     {
419         return reg;
420     }
421
422     int operator == (ThumbVFPSingleReg other)
423     {
424         return reg == other.reg;
425     }
426
427     int operator != (ThumbVFPSingleReg other)
428     {
429         return reg != other.reg;
430     }
431
432     WORD Mask() const
433     {
434         return 1 << reg;
435     }
436
437 };
438
439 struct ThumbVFPDoubleReg
440 {
441     int reg;
442     ThumbVFPDoubleReg(int reg):reg(reg)
443     {
444         _ASSERTE(0 <= reg && reg < 31);
445     }
446
447     operator int ()
448     {
449         return reg;
450     }
451
452     int operator == (ThumbVFPDoubleReg other)
453     {
454         return reg == other.reg;
455     }
456
457     int operator != (ThumbVFPDoubleReg other)
458     {
459         return reg != other.reg;
460     }
461
462     WORD Mask() const
463     {
464         return 1 << reg;
465     }
466 };
467
468 const ThumbReg thumbRegFp = ThumbReg(11);
469 const ThumbReg thumbRegSp = ThumbReg(13);
470 const ThumbReg thumbRegLr = ThumbReg(14);
471 const ThumbReg thumbRegPc = ThumbReg(15);
472
473 const ThumbCond thumbCondEq = ThumbCond(0);
474 const ThumbCond thumbCondNe = ThumbCond(1);
475 const ThumbCond thumbCondCs = ThumbCond(2);
476 const ThumbCond thumbCondCc = ThumbCond(3);
477 const ThumbCond thumbCondMi = ThumbCond(4);
478 const ThumbCond thumbCondPl = ThumbCond(5);
479 const ThumbCond thumbCondVs = ThumbCond(6);
480 const ThumbCond thumbCondVc = ThumbCond(7);
481 const ThumbCond thumbCondHi = ThumbCond(8);
482 const ThumbCond thumbCondLs = ThumbCond(9);
483 const ThumbCond thumbCondGe = ThumbCond(10);
484 const ThumbCond thumbCondLt = ThumbCond(11);
485 const ThumbCond thumbCondGt = ThumbCond(12);
486 const ThumbCond thumbCondLe = ThumbCond(13);
487 const ThumbCond thumbCondAl = ThumbCond(14);
488
489 class StubLinkerCPU : public StubLinker
490 {
491 public:
492     static void Init();
493
494     void ThumbEmitProlog(UINT cCalleeSavedRegs, UINT cbStackFrame, BOOL fPushArgRegs)
495     {
496         _ASSERTE(!m_fProlog);
497
498         // Record the parameters of this prolog so that we can generate a matching epilog and unwind info.
499         DescribeProlog(cCalleeSavedRegs, cbStackFrame, fPushArgRegs);
500
501         // Trivial prologs (which is all that we support initially) consist of between one and three
502         // instructions.
503
504         // 1) Push argument registers. This is all or nothing (if we push, we push R0-R3).
505         if (fPushArgRegs)
506         {
507             // push {r0-r3}
508             ThumbEmitPush(ThumbReg(0).Mask() | ThumbReg(1).Mask() | ThumbReg(2).Mask() | ThumbReg(3).Mask());
509         }
510
511         // 2) Push callee saved registers. We always start pushing at R4, and only saved consecutive registers
512         //    from there (max is R11). Additionally we always assume LR is saved for these types of prolog.
513         // push {r4-rX,lr}
514         WORD wRegisters = thumbRegLr.Mask();
515         for (unsigned int i = 4; i < (4 + cCalleeSavedRegs); i++)
516             wRegisters |= ThumbReg(i).Mask();
517         ThumbEmitPush(wRegisters);
518
519         // 3) Reserve space on the stack for the rest of the frame. 
520         if (cbStackFrame)
521         {
522             // sub sp, #cbStackFrame
523             ThumbEmitSubSp(cbStackFrame);
524         }
525     }
526
527     void ThumbEmitEpilog()
528     {
529         // Generate an epilog matching a prolog generated by ThumbEmitProlog.
530         _ASSERTE(m_fProlog);
531
532         // If additional stack space for a frame was allocated remove it now.
533         if (m_cbStackFrame)
534         {
535             // add sp, #m_cbStackFrame
536             ThumbEmitAddSp(m_cbStackFrame);
537         }
538
539         // Pop callee saved registers (we always have at least LR). If no argument registers were saved then
540         // we can restore LR back into PC and we're done. Otherwise LR needs to be restored into LR.
541         // pop {r4-rX,lr|pc}
542         WORD wRegisters = m_fPushArgRegs ? thumbRegLr.Mask() : thumbRegPc.Mask();
543         for (unsigned int i = 4; i < (4 + m_cCalleeSavedRegs); i++)
544             wRegisters |= ThumbReg(i).Mask();
545         ThumbEmitPop(wRegisters);
546
547         if (!m_fPushArgRegs)
548             return;
549
550         // We pushed the argument registers. These aren't restored, but we need to reclaim the stack space.
551         // add sp, #16
552         ThumbEmitAddSp(16);
553
554         // Return. The return address has been restored into LR at this point.
555         // bx lr
556         ThumbEmitJumpRegister(thumbRegLr);
557     }
558
559     void ThumbEmitGetThread(ThumbReg dest);
560
561     void ThumbEmitNop()
562     {
563         // nop
564         Emit16(0xbf00);
565     }
566
567     void ThumbEmitBreakpoint()
568     {
569         // Permanently undefined instruction #0xfe (see ARMv7-A A6.2.6). The debugger seems to accept this as
570         // a reasonable breakpoint substitute (it's what DebugBreak uses). Bkpt #0, on the other hand, always
571         // seems to flow directly to the kernel debugger (even if we ignore it there it doesn't seem to be
572         // picked up by the user mode debugger).
573 #ifdef __linux__
574         Emit16(0xde01);
575 #else
576         Emit16(0xdefe);
577 #endif
578     }
579
580     void ThumbEmitMovConstant(ThumbReg dest, int constant)
581     {
582         _ASSERT(dest != thumbRegPc);
583
584         //Emit 2 Byte instructions when dest reg < 8 & constant <256
585         if(dest <= 7 && constant < 256 && constant >= 0)
586         {
587             Emit16((WORD)(0x2000 | dest<<8 | (WORD)constant));
588         }
589         else // emit 4 byte instructions
590         {
591             WORD wConstantLow = (WORD)(constant & 0xffff);
592             WORD wConstantHigh = (WORD)(constant >> 16);
593
594             // movw regDest, #wConstantLow
595             Emit16((WORD)(0xf240 | (wConstantLow >> 12) | ((wConstantLow & 0x0800) ? 0x0400 : 0x0000)));
596             Emit16((WORD)((dest << 8) | (((wConstantLow >> 8) & 0x0007) << 12) | (wConstantLow & 0x00ff)));
597
598             if (wConstantHigh)
599             {
600                 // movt regDest, #wConstantHighw
601                 Emit16((WORD)(0xf2c0 | (wConstantHigh >> 12) | ((wConstantHigh & 0x0800) ? 0x0400 : 0x0000)));
602                 Emit16((WORD)((dest << 8) | (((wConstantHigh >> 8) & 0x0007) << 12) | (wConstantHigh & 0x00ff)));
603             }
604         }
605     }
606
607     void ThumbEmitLoadRegIndirect(ThumbReg dest, ThumbReg source, int offset)
608     {
609         _ASSERTE((offset >= 0) && (offset <= 4095));
610
611         // ldr regDest, [regSource + #offset]
612         if ((dest < 8) && (source < 8) && ((offset & 0x3) == 0) && (offset < 125))
613         {
614             // Encoding T1
615             Emit16((WORD)(0x6800 | ((offset >> 2) << 6) | (source << 3) | dest));
616         }
617         else
618         {
619             // Encoding T3
620             Emit16((WORD)(0xf8d0 | source));
621             Emit16((WORD)((dest << 12) | offset));
622         }
623     }
624
625     void ThumbEmitLoadIndirectPostIncrement(ThumbReg dest, ThumbReg source, int offset)
626     {
627         _ASSERTE((offset >= 0) && (offset <= 255));
628
629         // ldr regDest, [regSource], #offset
630         Emit16((WORD)(0xf850 | source));
631         Emit16((WORD)(0x0b00 | (dest << 12) | offset));
632     }
633
634     void ThumbEmitStoreRegIndirect(ThumbReg source, ThumbReg dest, int offset)
635     {
636         _ASSERTE((offset >= -255) && (offset <= 4095));
637
638         // str regSource, [regDest + #offset]
639         if (offset < 0)
640         {
641             Emit16((WORD)(0xf840 | dest));
642             Emit16((WORD)(0x0C00 | (source << 12) | (UINT8)(-offset)));
643         }
644         else
645         if ((dest < 8) && (source < 8) && ((offset & 0x3) == 0) && (offset < 125))
646         {
647             // Encoding T1
648             Emit16((WORD)(0x6000 | ((offset >> 2) << 6) | (dest << 3) | source));
649         }
650         else
651         {
652             // Encoding T3
653             Emit16((WORD)(0xf8c0 | dest));
654             Emit16((WORD)((source << 12) | offset));
655         }
656     }
657
658     void ThumbEmitStoreIndirectPostIncrement(ThumbReg source, ThumbReg dest, int offset)
659     {
660         _ASSERTE((offset >= 0) && (offset <= 255));
661
662         // str regSource, [regDest], #offset
663         Emit16((WORD)(0xf840 | dest));
664         Emit16((WORD)(0x0b00 | (source << 12) | offset));
665     }
666
667     void ThumbEmitLoadOffsetScaledReg(ThumbReg dest, ThumbReg base, ThumbReg offset, int shift)
668     {
669         _ASSERTE(shift >=0 && shift <=3);       
670
671         Emit16((WORD)(0xf850 | base));
672         Emit16((WORD)((dest << 12) | (shift << 4) | offset));
673     }
674
675     void ThumbEmitCallRegister(ThumbReg target)
676     {
677         // blx regTarget
678         Emit16((WORD)(0x4780 | (target << 3)));
679     }
680
681     void ThumbEmitJumpRegister(ThumbReg target)
682     {
683         // bx regTarget
684         Emit16((WORD)(0x4700 | (target << 3)));
685     }
686
687     void ThumbEmitMovRegReg(ThumbReg dest, ThumbReg source)
688     {
689         // mov regDest, regSource
690         Emit16((WORD)(0x4600 | ((dest > 7) ? 0x0080 : 0x0000) | (source << 3) | (dest & 0x0007)));
691     }
692
693     //Assuming SP is only subtracted in prolog
694     void ThumbEmitSubSp(int value)
695     {
696         _ASSERTE(value >= 0);
697         _ASSERTE((value & 0x3) == 0);
698
699         if(value < 512)
700         {
701             // encoding T1
702             // sub sp, sp, #(value >> 2)
703             Emit16((WORD)(0xb080 | (value >> 2)));
704         }
705         else if(value < 4096)
706         {
707             // Using 32-bit encoding
708             Emit16((WORD)(0xf2ad| ((value & 0x0800) >> 1)));
709             Emit16((WORD)(0x0d00| ((value & 0x0700) << 4) | (value & 0x00ff)));
710         }
711         else
712         {
713             // For values >= 4K (pageSize) must check for guard page
714
715 #ifndef CROSSGEN_COMPILE
716             // mov r4, value
717             ThumbEmitMovConstant(ThumbReg(4), value);
718             // mov r12, checkStack
719             ThumbEmitMovConstant(ThumbReg(12), (int)checkStack);
720             // bl r12
721             ThumbEmitCallRegister(ThumbReg(12));
722 #endif
723
724             // sub sp,sp,r4
725             Emit16((WORD)0xebad);
726             Emit16((WORD)0x0d04);
727         }
728     }
729
730     void ThumbEmitAddSp(int value)
731     {
732         _ASSERTE(value >= 0);
733         _ASSERTE((value & 0x3) == 0);
734
735         if(value < 512)
736         {
737             // encoding T2
738             // add sp, sp, #(value >> 2)
739             Emit16((WORD)(0xb000 | (value >> 2)));
740         }
741         else if(value < 4096)
742         {
743             // Using 32-bit encoding T4
744             Emit16((WORD)(0xf20d| ((value & 0x0800) >> 1)));
745             Emit16((WORD)(0x0d00| ((value & 0x0700) << 4) | (value & 0x00ff)));
746         }
747         else
748         {
749             //Must use temp register for values >=4096
750             ThumbEmitMovConstant(ThumbReg(12), value);
751             // add sp,sp,r12
752             Emit16((WORD)0x44e5);
753         }
754     }
755
756     void ThumbEmitAddReg(ThumbReg dest, ThumbReg source)
757     {
758
759         _ASSERTE(dest != source);
760         Emit16((WORD)(0x4400 | ((dest & 0x8)<<4) | (source<<3) | (dest & 0x7)));
761     }
762
763     void ThumbEmitAdd(ThumbReg dest, ThumbReg source, unsigned int value)
764     {
765
766         if(value<4096)
767         {
768             // addw dest, source, #value
769             unsigned int i = (value & 0x800) >> 11;
770             unsigned int imm3 = (value & 0x700) >> 8;
771             unsigned int imm8 = value & 0xff;
772             Emit16((WORD)(0xf200 | (i << 10) | source));
773             Emit16((WORD)((imm3 << 12) | (dest << 8) | imm8));
774         }
775         else
776         {
777             // if immediate is more than 4096 only ADD (register) will work
778             // move immediate to dest reg and call ADD(reg)
779             // this will not work if dest is same as source. 
780             _ASSERTE(dest != source);
781             ThumbEmitMovConstant(dest, value);
782             ThumbEmitAddReg(dest, source);
783         }
784     }
785
786     void ThumbEmitSub(ThumbReg dest, ThumbReg source, unsigned int value)
787     {
788         _ASSERTE(value < 4096);
789
790         // subw dest, source, #value
791         unsigned int i = (value & 0x800) >> 11;
792         unsigned int imm3 = (value & 0x700) >> 8;
793         unsigned int imm8 = value & 0xff;
794         Emit16((WORD)(0xf2a0 | (i << 10) | source));
795         Emit16((WORD)((imm3 << 12) | (dest << 8) | imm8));
796     }
797
798     void ThumbEmitCmpReg(ThumbReg reg1, ThumbReg reg2)
799     {
800         if(reg1 < 8 && reg2 <8)
801         {
802             Emit16((WORD)(0x4280 | reg2 << 3 | reg1));
803         }
804         else 
805         {
806             _ASSERTE(reg1 != ThumbReg(15) && reg2 != ThumbReg(15));
807             Emit16((WORD)(0x4500 | reg2 << 3 | (reg1 & 0x7) | (reg1 & 0x8 ? 0x80 : 0x0)));
808         }
809     }
810     
811     void ThumbEmitIncrement(ThumbReg dest, unsigned int value)
812     {
813         while (value)
814         {
815             if (value >= 4095)
816             {
817                 // addw <dest>, <dest>, #4095
818                 ThumbEmitAdd(dest, dest, 4095);
819                 value -= 4095;
820             }
821             else if (value <= 255)
822             {
823                 // add <dest>, #value
824                 Emit16((WORD)(0x3000 | (dest << 8) | value));
825                 break;
826             }
827             else
828             {
829                 // addw <dest>, <dest>, #value
830                 ThumbEmitAdd(dest, dest, value);
831                 break;
832             }
833         }
834     }
835
836     void ThumbEmitPush(WORD registers)
837     {
838         _ASSERTE(registers != 0);
839         _ASSERTE((registers & 0xa000) == 0); // Pushing SP or PC undefined
840
841         // push {registers}
842         if (CountBits(registers) == 1)
843         {
844             // Encoding T3 (exactly one register, high or low)
845             WORD reg = 15;
846             while ((registers & (WORD)(1 << reg)) == 0)
847             {
848                 reg--;
849             }
850             Emit16(0xf84d);
851             Emit16(0x0d04 | (reg << 12));
852         }
853         else if ((registers & 0xbf00) == 0)
854         {
855             // Encoding T1 (low registers plus maybe LR)
856             Emit16(0xb400 | (registers & thumbRegLr.Mask() ? 0x0100: 0x0000) | (registers & 0x00ff));
857         }
858         else
859         {
860             // Encoding T2 (two or more registers, high or low)
861             Emit16(0xe92d);
862             Emit16(registers);
863         }
864     }
865
866     void ThumbEmitLoadStoreMultiple(ThumbReg base, bool load, WORD registers)
867     {
868         _ASSERTE(CountBits(registers) > 1);
869         _ASSERTE((registers & 0xFF00) == 0); // This only supports the small encoding
870         _ASSERTE(base < 8); // This only supports the small encoding
871         _ASSERTE((base.Mask() & registers) == 0); // This only supports the small encoding
872
873         // (LDM|STM) base, {registers}
874         WORD flag = load ? 0x0800 : 0;
875         Emit16(0xc000 | flag | ((base & 7) << 8) | (registers & 0xFF));
876     }
877
878     void ThumbEmitPop(WORD registers)
879     {
880         _ASSERTE(registers != 0);
881         _ASSERTE((registers & 0xc000) != 0xc000); // Popping PC and LR together undefined
882
883         // pop {registers}
884         if (CountBits(registers) == 1)
885         {
886             // Encoding T3 (exactly one register, high or low)
887             WORD reg = 15;
888             while ((registers & (WORD)(1 << reg)) == 0)
889             {
890                 reg--;
891             }
892             Emit16(0xf85d);
893             Emit16(0x0b04 | (reg << 12));
894         }
895         else if ((registers & 0x7f00) == 0)
896         {
897             // Encoding T1 (low registers plus maybe PC)
898             Emit16(0xbc00 | (registers & thumbRegPc.Mask() ? 0x0100: 0x0000) | (registers & 0x00ff));
899         }
900         else
901         {
902             // Encoding T2 (two or more registers, high or low)
903             Emit16(0xe8bd);
904             Emit16(registers);
905         }
906     }
907
908     void ThumbEmitLoadVFPSingleRegIndirect(ThumbVFPSingleReg dest, ThumbReg source, int offset)
909     {
910         _ASSERTE((offset >= -1020) && (offset <= 1020));
911         _ASSERTE(offset%4==0);
912
913         Emit16((WORD) (0xed10 | ((offset > 0 ? 0x1: 0x0) << 7) | ((dest & 0x1) << 6) | source));
914         Emit16((WORD) (0x0a00 | ((dest & 0x1e) << 11) | (abs(offset)>>2)));
915     }
916
917     void ThumbEmitLoadVFPDoubleRegIndirect(ThumbVFPDoubleReg dest, ThumbReg source, int offset)
918     {
919         _ASSERTE((offset >= -1020) && (offset <= 1020));
920         _ASSERTE(offset%4==0);
921
922         Emit16((WORD) (0xed10 | ((offset > 0 ? 0x1: 0x0) << 7) | ((dest & 0x10) << 6) | source));
923         Emit16((WORD) (0x0b00 | ((dest & 0xf) << 12) | (abs(offset)>>2)));
924     }
925
926 #ifdef FEATURE_INTERPRETER
927     void ThumbEmitStoreMultipleVFPDoubleReg(ThumbVFPDoubleReg source, ThumbReg dest, unsigned numRegs)
928     {
929         _ASSERTE((numRegs + source) <= 16);
930
931         // The third nibble is 0x8; the 0x4 bit (D) is zero because the source reg number must be less
932         // than 16 for double registers.
933         Emit16((WORD) (0xec80 | 0x80 | dest));
934         Emit16((WORD) (((source & 0xf) << 12) | 0xb00 | numRegs));
935     }
936
937     void ThumbEmitLoadMultipleVFPDoubleReg(ThumbVFPDoubleReg dest, ThumbReg source, unsigned numRegs)
938     {
939         _ASSERTE((numRegs + dest) <= 16);
940
941         // The third nibble is 0x8; the 0x4 bit (D) is zero because the source reg number must be less
942         // than 16 for double registers.
943         Emit16((WORD) (0xec90 | 0x80 | source));
944         Emit16((WORD) (((dest & 0xf) << 12) | 0xb00 | numRegs));
945     }
946 #endif // FEATURE_INTERPRETER
947
948     void EmitStubLinkFrame(TADDR pFrameVptr, int offsetOfFrame, int offsetOfTransitionBlock);
949     void EmitStubUnlinkFrame();
950
951     void ThumbEmitCondFlagJump(CodeLabel * target,UINT cond);
952
953     void ThumbEmitCondRegJump(CodeLabel *target, BOOL nonzero, ThumbReg reg);
954
955     void ThumbEmitNearJump(CodeLabel *target);
956
957     // Scratches r12.
958     void ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall);
959
960     void EmitUnboxMethodStub(MethodDesc* pRealMD);
961     static UINT_PTR HashMulticastInvoke(MetaSig* pSig);
962
963     void EmitMulticastInvoke(UINT_PTR hash);
964     void EmitSecureDelegateInvoke(UINT_PTR hash);
965     void EmitShuffleThunk(struct ShuffleEntry *pShuffleEntryArray);
966 #if defined(FEATURE_SHARE_GENERIC_CODE)  
967     void EmitInstantiatingMethodStub(MethodDesc* pSharedMD, void* extra);
968 #endif // FEATURE_SHARE_GENERIC_CODE
969
970     static Stub * CreateTailCallCopyArgsThunk(CORINFO_SIG_INFO * pSig,
971                                               MethodDesc* pMD,
972                                               CorInfoHelperTailCallSpecialHandling flags);
973
974 private:
975     void ThumbCopyOneTailCallArg(UINT * pnSrcAlign, const ArgLocDesc * pArgLoc, UINT * pcbStackSpace);
976     void ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *pMD, void *pHiddenArg);
977 };
978
979 extern "C" void SinglecastDelegateInvokeStub();
980
981 // SEH info forward declarations
982
983 inline BOOL IsUnmanagedValueTypeReturnedByRef(UINT sizeofvaluetype) 
984 {
985     LIMITED_METHOD_CONTRACT;
986
987     // structure that dont fit in the machine-word size are returned
988     // by reference.
989     return (sizeofvaluetype > 4);
990 }
991
992 #ifdef _MSC_VER
993 #pragma warning(push)
994 #pragma warning(disable:4359) // Prevent "warning C4359: 'UMEntryThunkCode': Alignment specifier is less than actual alignment (8), and will be ignored." in crossbitness scenario
995 #endif // _MSC_VER
996
997 struct DECLSPEC_ALIGN(4) UMEntryThunkCode
998 {
999     WORD        m_code[4];
1000
1001     TADDR       m_pTargetCode;
1002     TADDR       m_pvSecretParam;
1003
1004     void Encode(BYTE* pTargetCode, void* pvSecretParam);
1005     void Poison();
1006
1007     LPCBYTE GetEntryPoint() const
1008     {
1009         LIMITED_METHOD_CONTRACT;
1010
1011         return (LPCBYTE)((TADDR)this | THUMB_CODE);
1012     }
1013
1014     static int GetEntryPointOffset()
1015     {
1016         LIMITED_METHOD_CONTRACT;
1017
1018         return 0;
1019     }
1020 };
1021
1022 #ifdef _MSC_VER
1023 #pragma warning(pop)
1024 #endif // _MSC_VER
1025
1026 struct HijackArgs
1027 {
1028     union
1029     {
1030         DWORD R0;
1031         size_t ReturnValue[1]; // this may not be the return value when return is >32bits 
1032                                // or return value is in VFP reg but it works for us as 
1033                                // this is only used by functions OnHijackWorker()
1034     };
1035
1036     //
1037     // Non-volatile Integer registers
1038     //
1039     DWORD R4;
1040     DWORD R5;
1041     DWORD R6;
1042     DWORD R7;
1043     DWORD R8;
1044     DWORD R9;
1045     DWORD R10;
1046     DWORD R11;
1047
1048     union
1049     {
1050         DWORD Lr;
1051         size_t ReturnAddress;
1052     };
1053 };
1054
1055 // ClrFlushInstructionCache is used when we want to call FlushInstructionCache
1056 // for a specific architecture in the common code, but not for other architectures.
1057 // On IA64 ClrFlushInstructionCache calls the Kernel FlushInstructionCache function
1058 // to flush the instruction cache. 
1059 // We call ClrFlushInstructionCache whenever we create or modify code in the heap. 
1060 // Currently ClrFlushInstructionCache has no effect on X86
1061 //
1062
1063 inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode)
1064 {
1065 #ifdef CROSSGEN_COMPILE
1066     // The code won't be executed when we are cross-compiling so flush instruction cache is unnecessary
1067     return TRUE;
1068 #else
1069     return FlushInstructionCache(GetCurrentProcess(), pCodeAddr, sizeOfCode);
1070 #endif
1071 }
1072
1073 //
1074 // JIT HELPER ALIASING FOR PORTABILITY.
1075 //
1076 // Create alias for optimized implementations of helpers provided on this platform
1077 //
1078 #define JIT_GetSharedGCStaticBase           JIT_GetSharedGCStaticBase_SingleAppDomain
1079 #define JIT_GetSharedNonGCStaticBase        JIT_GetSharedNonGCStaticBase_SingleAppDomain
1080 #define JIT_GetSharedGCStaticBaseNoCtor     JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
1081 #define JIT_GetSharedNonGCStaticBaseNoCtor  JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
1082
1083 #ifndef FEATURE_PAL
1084 #define JIT_Stelem_Ref                      JIT_Stelem_Ref
1085 #endif
1086
1087 //------------------------------------------------------------------------
1088 //
1089 // Precode definitions
1090 //
1091 //------------------------------------------------------------------------
1092 //
1093 // Note: If you introduce new precode implementation below, then please
1094 //       update PrecodeStubManager::CheckIsStub_Internal to account for it.
1095
1096 EXTERN_C VOID STDCALL PrecodeFixupThunk();
1097
1098 #define PRECODE_ALIGNMENT           sizeof(void*)
1099 #define SIZEOF_PRECODE_BASE         CODE_SIZE_ALIGN
1100 #define OFFSETOF_PRECODE_TYPE       0
1101
1102 // Invalid precode type
1103 struct InvalidPrecode {
1104     static const int Type = 0;
1105 };
1106
1107 struct StubPrecode {
1108
1109     static const int Type = 0xdf;
1110
1111     // ldr r12, [pc, #8]    ; =m_pMethodDesc
1112     // ldr pc, [pc, #0]     ; =m_pTarget
1113     // dcd pTarget
1114     // dcd pMethodDesc
1115     WORD    m_rgCode[4];
1116     TADDR   m_pTarget;
1117     TADDR   m_pMethodDesc;
1118
1119     void Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator);
1120
1121     TADDR GetMethodDesc()
1122     {
1123         LIMITED_METHOD_DAC_CONTRACT; 
1124         return m_pMethodDesc;
1125     }
1126
1127     PCODE GetTarget()
1128     {
1129         LIMITED_METHOD_DAC_CONTRACT; 
1130         return m_pTarget;
1131     }
1132
1133     void ResetTargetInterlocked()
1134     {
1135         CONTRACTL
1136         {
1137             THROWS;
1138             GC_TRIGGERS;
1139         }
1140         CONTRACTL_END;
1141
1142         EnsureWritableExecutablePages(&m_pTarget);
1143         InterlockedExchange((LONG*)&m_pTarget, (LONG)GetPreStubEntryPoint());
1144     }
1145
1146     BOOL SetTargetInterlocked(TADDR target, TADDR expected)
1147     {
1148         CONTRACTL
1149         {
1150             THROWS;
1151             GC_TRIGGERS;
1152         }
1153         CONTRACTL_END;
1154
1155         EnsureWritableExecutablePages(&m_pTarget);
1156         return (TADDR)InterlockedCompareExchange(
1157             (LONG*)&m_pTarget, (LONG)target, (LONG)expected) == expected;
1158     }
1159
1160 #ifdef FEATURE_PREJIT
1161     void Fixup(DataImage *image);
1162 #endif
1163 };
1164 typedef DPTR(StubPrecode) PTR_StubPrecode;
1165
1166
1167 struct NDirectImportPrecode {
1168
1169     static const int Type = 0xe0;
1170
1171     // ldr r12, [pc, #4]    ; =m_pMethodDesc
1172     // ldr pc, [pc, #4]     ; =m_pTarget
1173     // dcd pMethodDesc
1174     // dcd pTarget
1175     WORD    m_rgCode[4];
1176     TADDR   m_pMethodDesc;  // Notice that the fields are reversed compared to StubPrecode. Precode::GetType
1177                             // takes advantage of this to detect NDirectImportPrecode.
1178     TADDR   m_pTarget;
1179
1180     void Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator);
1181
1182     TADDR GetMethodDesc()
1183     {
1184         LIMITED_METHOD_DAC_CONTRACT; 
1185         return m_pMethodDesc;
1186     }
1187
1188     PCODE GetTarget()
1189     {
1190         LIMITED_METHOD_DAC_CONTRACT; 
1191         return m_pTarget;
1192     }
1193
1194     LPVOID GetEntrypoint()
1195     {
1196         LIMITED_METHOD_CONTRACT;
1197         return (LPVOID)(dac_cast<TADDR>(this) + THUMB_CODE);
1198     }
1199
1200 #ifdef FEATURE_PREJIT
1201     void Fixup(DataImage *image);
1202 #endif
1203 };
1204 typedef DPTR(NDirectImportPrecode) PTR_NDirectImportPrecode;
1205
1206
1207 struct FixupPrecode {
1208
1209     static const int Type = 0xfc;
1210
1211     // mov r12, pc
1212     // ldr pc, [pc, #4]     ; =m_pTarget
1213     // dcb m_MethodDescChunkIndex
1214     // dcb m_PrecodeChunkIndex
1215     // dcd m_pTarget
1216     WORD    m_rgCode[3];
1217     BYTE    m_MethodDescChunkIndex;
1218     BYTE    m_PrecodeChunkIndex;
1219     TADDR   m_pTarget;
1220
1221     void Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, int iMethodDescChunkIndex = 0, int iPrecodeChunkIndex = 0);
1222
1223     TADDR GetBase()
1224     {
1225         LIMITED_METHOD_CONTRACT;
1226         SUPPORTS_DAC;
1227
1228         return dac_cast<TADDR>(this) + (m_PrecodeChunkIndex + 1) * sizeof(FixupPrecode);
1229     }
1230
1231     TADDR GetMethodDesc();
1232
1233     PCODE GetTarget()
1234     {
1235         LIMITED_METHOD_DAC_CONTRACT; 
1236         return m_pTarget;
1237     }
1238
1239     void ResetTargetInterlocked()
1240     {
1241         CONTRACTL
1242         {
1243             THROWS;
1244             GC_TRIGGERS;
1245         }
1246         CONTRACTL_END;
1247
1248         EnsureWritableExecutablePages(&m_pTarget);
1249         InterlockedExchange((LONG*)&m_pTarget, (LONG)GetEEFuncEntryPoint(PrecodeFixupThunk));
1250     }
1251
1252     BOOL SetTargetInterlocked(TADDR target, TADDR expected)
1253     {
1254         CONTRACTL
1255         {
1256             THROWS;
1257             GC_TRIGGERS;
1258         }
1259         CONTRACTL_END;
1260
1261         EnsureWritableExecutablePages(&m_pTarget);
1262         return (TADDR)InterlockedCompareExchange(
1263             (LONG*)&m_pTarget, (LONG)target, (LONG)expected) == expected;
1264     }
1265
1266     static BOOL IsFixupPrecodeByASM(PCODE addr)
1267     {
1268         PTR_WORD pInstr = dac_cast<PTR_WORD>(PCODEToPINSTR(addr));
1269
1270         return 
1271            (pInstr[0] == 0x46fc) &&
1272            (pInstr[1] == 0xf8df) &&
1273            (pInstr[2] == 0xf004);
1274     }
1275
1276 #ifdef FEATURE_PREJIT
1277     // Partial initialization. Used to save regrouped chunks.
1278     void InitForSave(int iPrecodeChunkIndex);
1279
1280     void Fixup(DataImage *image, MethodDesc * pMD);
1281 #endif
1282
1283 #ifdef DACCESS_COMPILE
1284     void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
1285 #endif
1286 };
1287 typedef DPTR(FixupPrecode) PTR_FixupPrecode;
1288
1289
1290 // Precode to shuffle this and retbuf for closed delegates over static methods with return buffer
1291 struct ThisPtrRetBufPrecode {
1292
1293     static const int Type = 0x84;
1294
1295     // mov r12, r0
1296     // mov r0, r1
1297     // mov r1, r12
1298     // ldr pc, [pc, #0]     ; =m_pTarget
1299     // dcd pTarget
1300     // dcd pMethodDesc
1301     WORD    m_rgCode[6];
1302     TADDR   m_pTarget;
1303     TADDR   m_pMethodDesc;
1304
1305     void Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator);
1306
1307     TADDR GetMethodDesc()
1308     {
1309         LIMITED_METHOD_DAC_CONTRACT; 
1310
1311         return m_pMethodDesc;
1312     }
1313
1314     PCODE GetTarget()
1315     { 
1316         LIMITED_METHOD_DAC_CONTRACT; 
1317         return m_pTarget;
1318     }
1319
1320     BOOL SetTargetInterlocked(TADDR target, TADDR expected)
1321     {
1322         CONTRACTL
1323         {
1324             THROWS;
1325             GC_TRIGGERS;
1326         }
1327         CONTRACTL_END;
1328
1329         EnsureWritableExecutablePages(&m_pTarget);
1330         return FastInterlockCompareExchange((LONG*)&m_pTarget, (LONG)target, (LONG)expected) == (LONG)expected;
1331     }
1332 };
1333 typedef DPTR(ThisPtrRetBufPrecode) PTR_ThisPtrRetBufPrecode;
1334
1335
1336 #ifdef HAS_REMOTING_PRECODE
1337
1338 // Precode with embedded remoting interceptor
1339 struct RemotingPrecode {
1340
1341     static const int Type = 0x02;
1342
1343     // push {r1,lr}
1344     // ldr r1, [pc, #16]    ; =m_pPrecodeRemotingThunk
1345     // blx r1
1346     // pop {r1,lr}
1347     // ldr pc, [pc, #12]    ; =m_pLocalTarget
1348     // nop                  ; padding for alignment
1349     // dcd m_pMethodDesc
1350     // dcd m_pPrecodeRemotingThunk
1351     // dcd m_pLocalTarget
1352     WORD    m_rgCode[8];
1353     TADDR   m_pMethodDesc;
1354     TADDR   m_pPrecodeRemotingThunk;
1355     TADDR   m_pLocalTarget;
1356
1357     void Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator = NULL);
1358
1359     TADDR GetMethodDesc()
1360     {
1361         LIMITED_METHOD_DAC_CONTRACT; 
1362         return m_pMethodDesc;
1363     }
1364
1365     PCODE GetTarget()
1366     { 
1367         LIMITED_METHOD_DAC_CONTRACT; 
1368         return m_pLocalTarget;
1369     }
1370
1371     BOOL SetTargetInterlocked(TADDR target, TADDR expected)
1372     {
1373         CONTRACTL
1374         {
1375             THROWS;
1376             GC_TRIGGERS;
1377         }
1378         CONTRACTL_END;
1379
1380         EnsureWritableExecutablePages(&m_pLocalTarget);
1381         return FastInterlockCompareExchange((LONG*)&m_pLocalTarget, (LONG)target, (LONG)expected) == (LONG)expected;
1382     }
1383
1384 #ifdef FEATURE_PREJIT
1385     void Fixup(DataImage *image, ZapNode *pCodeNode);
1386 #endif
1387 };
1388 typedef DPTR(RemotingPrecode) PTR_RemotingPrecode;
1389
1390 EXTERN_C void PrecodeRemotingThunk();
1391
1392 #endif // HAS_REMOTING_PRECODE
1393
1394 //**********************************************************************
1395 // Miscellaneous
1396 //**********************************************************************
1397
1398 // Given the first halfword value of an ARM (Thumb) instruction (which is either an entire
1399 // 16-bit instruction, or the high-order halfword of a 32-bit instruction), determine how many bytes
1400 // the instruction is (2 or 4) and return that.
1401 inline size_t GetARMInstructionLength(WORD instr)
1402 {
1403     // From the ARM Architecture Reference Manual, A6.1 "Thumb instruction set encoding":
1404     // If bits [15:11] of the halfword being decoded take any of the following values, the halfword is the first
1405     // halfword of a 32-bit instruction:
1406     //   0b11101
1407     //   0b11110
1408     //   0b11111
1409     // Otherwise, the halfword is a 16-bit instruction.
1410     if ((instr & 0xf800) > 0xe000)
1411     {
1412         return 4;
1413     }
1414     else 
1415     {
1416         return 2;
1417     }
1418 }
1419
1420 // Given a pointer to an ARM (Thumb) instruction address, determine how many bytes
1421 // the instruction is (2 or 4) and return that.
1422 inline size_t GetARMInstructionLength(PBYTE pInstr)
1423 {
1424     return GetARMInstructionLength(*(WORD*)pInstr);
1425 }
1426
1427 EXTERN_C void FCallMemcpy(BYTE* dest, BYTE* src, int len);
1428
1429 #endif // __cgencpu_h__