Correctly marshal structure return values in member functions on Win-x64 and Win...
[platform/upstream/coreclr.git] / src / vm / stubgen.cpp
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 // File: StubGen.cpp
6 // 
7
8 //
9
10
11 #include "common.h"
12
13 #include "stubgen.h"
14 #include "jitinterface.h"
15 #include "ilstubcache.h"
16 #include "sigbuilder.h"
17
18 #include "formattype.h"
19 #include "typestring.h"
20
21
22 #include "field.h"
23
24 //
25 //   ....[.....\xxxxx]..0...  -> ....[xxxxx]..0...
26 //       ^     ^        ^
27
28 void DumpIL_RemoveFullPath(SString &strTokenFormatting)
29 {
30     STANDARD_VM_CONTRACT;
31     if (strTokenFormatting.IsEmpty())
32         return;
33     
34     SString::Iterator begin = strTokenFormatting.Begin();
35     SString::Iterator end = strTokenFormatting.End();
36     SString::Iterator leftBracket = strTokenFormatting.Begin();
37     
38     // Find the first '[' in the string.
39     while ((leftBracket != end) && (*leftBracket != W('[')))
40     {
41         ++leftBracket;
42     }
43     
44     if (leftBracket != end)
45     {
46         SString::Iterator lastSlash = strTokenFormatting.End() - 1;
47
48         // Find the last '\\' in the string.
49         while ((lastSlash != leftBracket) && (*lastSlash != W('\\')))
50         {
51             --lastSlash;
52         }
53
54         if (leftBracket != lastSlash)
55         {
56             strTokenFormatting.Delete(leftBracket + 1, lastSlash - leftBracket);
57         }
58     }
59 }
60
61 void DumpIL_FormatToken(TokenLookupMap* pTokenMap, mdToken token, SString &strTokenFormatting, const SString &strStubTargetSig)
62 {
63     void* pvLookupRetVal = (void*)POISONC;
64     _ASSERTE(strTokenFormatting.IsEmpty());
65
66     EX_TRY
67     {
68         if (TypeFromToken(token) == mdtMethodDef)
69         {
70             MethodDesc* pMD = pTokenMap->LookupMethodDef(token);
71             pvLookupRetVal = pMD;
72             CONSISTENCY_CHECK(CheckPointer(pMD));
73
74             pMD->GetFullMethodInfo(strTokenFormatting);
75         }
76         else if (TypeFromToken(token) == mdtTypeDef)
77         {
78             TypeHandle typeHnd = pTokenMap->LookupTypeDef(token);
79             pvLookupRetVal = typeHnd.AsPtr();
80             CONSISTENCY_CHECK(!typeHnd.IsNull());
81
82             SString typeName;
83             MethodTable *pMT = NULL;
84             if (typeHnd.IsTypeDesc())
85             {
86                 TypeDesc *pTypeDesc = typeHnd.AsTypeDesc();
87                 pMT = pTypeDesc->GetMethodTable();                
88             }
89             else
90             {
91                 pMT = typeHnd.AsMethodTable();
92             }               
93             
94             // AppendType handles NULL correctly
95             TypeString::AppendType(typeName, TypeHandle(pMT));
96             
97             if (pMT && typeHnd.IsNativeValueType())
98                 typeName.Append(W("_NativeValueType"));
99             strTokenFormatting.Set(typeName);
100         }
101         else if (TypeFromToken(token) == mdtFieldDef)
102         {
103             FieldDesc* pFD = pTokenMap->LookupFieldDef(token);
104             pvLookupRetVal = pFD;
105             CONSISTENCY_CHECK(CheckPointer(pFD));
106
107             SString typeName;
108             TypeString::AppendType(typeName, TypeHandle(pFD->GetApproxEnclosingMethodTable()));
109             
110             SString strFieldName(SString::Utf8, pFD->GetName());
111             strTokenFormatting.Printf(W("%s::%s"), typeName.GetUnicode(), strFieldName.GetUnicode());
112         }
113         else if (TypeFromToken(token) == mdtModule)
114         {
115             // Do nothing, because strTokenFormatting is already empty.
116         }
117         else if (TypeFromToken(token) == mdtSignature)
118         {
119             CONSISTENCY_CHECK(token == TOKEN_ILSTUB_TARGET_SIG);
120             strTokenFormatting.Set(strStubTargetSig);
121         }
122         else 
123         {
124             strTokenFormatting.Printf(W("%d"), token);
125         }
126         DumpIL_RemoveFullPath(strTokenFormatting);
127     }
128     EX_CATCH
129     {
130         strTokenFormatting.Printf(W("%d"), token);
131     }
132     EX_END_CATCH(SwallowAllExceptions)
133 }
134
135 void ILCodeStream::Emit(ILInstrEnum instr, INT16 iStackDelta, UINT_PTR uArg)
136 {
137     STANDARD_VM_CONTRACT;
138
139     UINT idxCurInstr = 0;
140     ILStubLinker::ILInstruction* pInstrBuffer = NULL;
141
142     if (NULL == m_pqbILInstructions)
143     {
144         m_pqbILInstructions = new ILCodeStreamBuffer();
145     }
146
147     idxCurInstr = m_uCurInstrIdx;
148
149     m_uCurInstrIdx++;
150     m_pqbILInstructions->ReSizeThrows(m_uCurInstrIdx * sizeof(ILStubLinker::ILInstruction));
151
152     pInstrBuffer = (ILStubLinker::ILInstruction*)m_pqbILInstructions->Ptr();
153
154     pInstrBuffer[idxCurInstr].uInstruction = static_cast<UINT16>(instr);
155     pInstrBuffer[idxCurInstr].iStackDelta = iStackDelta;
156     pInstrBuffer[idxCurInstr].uArg = uArg;
157 }
158
159 ILCodeLabel* ILStubLinker::NewCodeLabel()
160 {
161     STANDARD_VM_CONTRACT;
162     
163     ILCodeLabel* pCodeLabel = new ILCodeLabel();
164
165     pCodeLabel->m_pNext = m_pLabelList;
166     pCodeLabel->m_pOwningStubLinker = this;
167     pCodeLabel->m_pCodeStreamOfLabel = NULL;
168     pCodeLabel->m_idxLabeledInstruction = -1;
169
170     m_pLabelList = pCodeLabel;
171
172     return pCodeLabel;
173 }
174
175 void ILCodeStream::EmitLabel(ILCodeLabel* pCodeLabel)
176 {
177     CONTRACTL
178     {
179         STANDARD_VM_CHECK;
180         PRECONDITION_MSG(m_pOwner == pCodeLabel->m_pOwningStubLinker, "you can only use a code label in the ILStubLinker that created it!");
181     }
182     CONTRACTL_END;
183
184     pCodeLabel->m_pCodeStreamOfLabel    = this;
185     pCodeLabel->m_idxLabeledInstruction = m_uCurInstrIdx;
186
187     Emit(CEE_CODE_LABEL, 0, (UINT_PTR)pCodeLabel);
188 }
189
190 static const BYTE s_rgbOpcodeSizes[] = 
191 {
192
193 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
194     ((l) + (oprType)),
195
196 #define InlineNone            0
197 #define ShortInlineVar        1
198 #define ShortInlineI          1
199 #define InlineI               4
200 #define InlineI8              8
201 #define ShortInlineR          4
202 #define InlineR               8
203 #define InlineMethod          4
204 #define InlineSig             4
205 #define ShortInlineBrTarget   1
206 #define InlineBrTarget        4
207 #define InlineSwitch         -1
208 #define InlineType            4
209 #define InlineString          4
210 #define InlineField           4
211 #define InlineTok             4
212 #define InlineVar             2
213
214 #include "opcode.def"
215
216 #undef OPDEF
217 #undef InlineNone
218 #undef ShortInlineVar
219 #undef ShortInlineI
220 #undef InlineI
221 #undef InlineI8
222 #undef ShortInlineR
223 #undef InlineR
224 #undef InlineMethod
225 #undef InlineSig
226 #undef ShortInlineBrTarget
227 #undef InlineBrTarget
228 #undef InlineSwitch
229 #undef InlineType
230 #undef InlineString
231 #undef InlineField
232 #undef InlineTok
233 #undef InlineVar
234
235 };
236
237 struct ILOpcode
238 {
239     BYTE byte1;
240     BYTE byte2;
241 };
242
243 static const ILOpcode s_rgOpcodes[] = 
244 {
245
246 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
247     { (s1), (s2) },
248 #include "opcode.def"
249 #undef OPDEF
250
251 };
252
253 ILCodeStream::ILInstrEnum ILCodeStream::LowerOpcode(ILInstrEnum instr, ILStubLinker::ILInstruction* pInstr)
254 {
255     CONTRACTL
256     {
257         STANDARD_VM_CHECK;
258         PRECONDITION(instr == (ILInstrEnum)pInstr->uInstruction);
259     }
260     CONTRACTL_END;
261
262     //
263     // NOTE:  we do not lower branches to their smallest form because that
264     //        would introduce extra passes at link time, which isn't really
265     //        worth the savings in IL code size.
266     //
267
268     UINT_PTR uConst = pInstr->uArg;
269
270     switch (instr)
271     {
272         case CEE_LDC_I8:
273         {
274             if (uConst == (UINT_PTR)-1)
275             {
276                 instr = CEE_LDC_I4_M1;
277             }
278             else
279             if (uConst < 9)
280             {
281                 instr = (ILInstrEnum)((UINT_PTR)CEE_LDC_I4_0 + uConst);
282             }
283             else
284             if (FitsInI1(uConst))
285             {
286                 instr = CEE_LDC_I4_S;
287             }
288             else
289             if (FitsInI4(uConst))
290             {
291                 instr = CEE_LDC_I4;
292             }
293             break;
294         }
295
296         case CEE_LDARG:
297         {
298             if (uConst <= 3)
299             {
300                 instr = (ILInstrEnum)((UINT_PTR)CEE_LDARG_0 + uConst);
301                 break;
302             }
303             goto lShortForm;
304         }
305         case CEE_LDLOC:
306         {
307             if (uConst <= 3)
308             {
309                 instr = (ILInstrEnum)((UINT_PTR)CEE_LDLOC_0 + uConst);
310                 break;
311             }
312             goto lShortForm;
313         }
314         case CEE_STLOC:
315         {
316             if (uConst <= 3)
317             {
318                 instr = (ILInstrEnum)((UINT_PTR)CEE_STLOC_0 + uConst);
319                 break;
320             }
321
322 lShortForm:
323             if (FitsInI1(uConst))
324             {
325                 static const UINT_PTR c_uMakeShortDelta = ((UINT_PTR)CEE_LDARG - (UINT_PTR)CEE_LDARG_S);
326                 static_assert_no_msg(((UINT_PTR)CEE_LDARG - c_uMakeShortDelta) == (UINT_PTR)CEE_LDARG_S);
327                 static_assert_no_msg(((UINT_PTR)CEE_LDLOC - c_uMakeShortDelta) == (UINT_PTR)CEE_LDLOC_S);
328                 static_assert_no_msg(((UINT_PTR)CEE_STLOC - c_uMakeShortDelta) == (UINT_PTR)CEE_STLOC_S);
329                 
330                 instr = (ILInstrEnum)((UINT_PTR)instr - c_uMakeShortDelta);
331             }
332             break;
333         }
334
335         case CEE_LDARGA:
336         case CEE_STARG:
337         case CEE_LDLOCA:
338         {
339             if (FitsInI1(uConst))
340             {
341                 static const UINT_PTR c_uMakeShortDelta = ((UINT_PTR)CEE_LDARGA - (UINT_PTR)CEE_LDARGA_S);
342                 static_assert_no_msg(((UINT_PTR)CEE_LDARGA - c_uMakeShortDelta) == (UINT_PTR)CEE_LDARGA_S);
343                 static_assert_no_msg(((UINT_PTR)CEE_STARG  - c_uMakeShortDelta) == (UINT_PTR)CEE_STARG_S);
344                 static_assert_no_msg(((UINT_PTR)CEE_LDLOCA - c_uMakeShortDelta) == (UINT_PTR)CEE_LDLOCA_S);
345                 
346                 instr = (ILInstrEnum)((UINT_PTR)instr - c_uMakeShortDelta);
347             }
348             break;
349         }
350
351         default:
352             break;
353     }
354
355     pInstr->uInstruction = static_cast<UINT16>(instr);
356     return instr;
357 }
358
359 void ILStubLinker::PatchInstructionArgument(ILCodeLabel* pLabel, UINT_PTR uNewArg
360     DEBUG_ARG(UINT16 uExpectedInstruction))
361 {
362     LIMITED_METHOD_CONTRACT;
363
364     UINT            idx                 = pLabel->m_idxLabeledInstruction;
365     ILCodeStream*   pLabelCodeStream    = pLabel->m_pCodeStreamOfLabel;
366     ILInstruction*  pLabelInstrBuffer   = (ILInstruction*)pLabelCodeStream->m_pqbILInstructions->Ptr();
367     
368     CONSISTENCY_CHECK(pLabelInstrBuffer[idx].uInstruction == ILCodeStream::CEE_CODE_LABEL);
369     CONSISTENCY_CHECK(pLabelInstrBuffer[idx].iStackDelta == 0);
370
371     idx++;
372
373     CONSISTENCY_CHECK(idx < pLabelCodeStream->m_uCurInstrIdx);
374     CONSISTENCY_CHECK(pLabelInstrBuffer[idx].uInstruction == uExpectedInstruction);
375
376     pLabelInstrBuffer[idx].uArg = uNewArg;
377 }
378
379 ILCodeLabel::ILCodeLabel()
380 {
381     m_pNext                 = NULL;
382     m_pOwningStubLinker     = NULL;
383     m_pCodeStreamOfLabel    = NULL;
384     m_codeOffset            = -1;
385     m_idxLabeledInstruction = -1;
386 }
387
388 ILCodeLabel::~ILCodeLabel()
389 {
390 }
391
392 size_t ILCodeLabel::GetCodeOffset()
393 {
394     LIMITED_METHOD_CONTRACT;
395     
396     CONSISTENCY_CHECK(m_codeOffset != (size_t)-1);
397     return m_codeOffset;
398 }
399
400
401 void ILCodeLabel::SetCodeOffset(size_t codeOffset)
402 {
403     LIMITED_METHOD_CONTRACT;
404     
405     CONSISTENCY_CHECK((m_codeOffset == (size_t)-1) && (codeOffset != (size_t)-1));
406     m_codeOffset = codeOffset;
407 }
408
409 static const LPCSTR s_rgOpcodeNames[] = 
410 {
411 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
412     string,
413 #include "opcode.def"
414 #undef OPDEF
415
416 };
417
418 #include "openum.h"
419
420 static const BYTE s_rgbOpcodeArgType[] = 
421 {
422
423 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
424     oprType,
425 #include "opcode.def"
426 #undef OPDEF
427
428 };
429
430
431 //---------------------------------------------------------------------------------------
432 // 
433 void 
434 ILStubLinker::LogILInstruction(
435     size_t          curOffset, 
436     bool            isLabeled, 
437     INT             iCurStack, 
438     ILInstruction * pInstruction, 
439     SString *       pDumpILStubCode)
440 {
441     STANDARD_VM_CONTRACT;
442     //
443     // format label
444     //
445     SString strLabel;
446     
447     if (isLabeled)
448     {
449         strLabel.Printf(W("IL_%04x:"), curOffset);
450     }
451     else
452     {
453         strLabel.Set(W("        "));
454     }
455
456     //
457     // format opcode
458     //
459     SString strOpcode;
460
461     ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstruction->uInstruction;
462     size_t      cbOpcodeName = strlen(s_rgOpcodeNames[instr]);
463     SString strOpcodeName;
464     strOpcodeName.SetUTF8(s_rgOpcodeNames[instr]);
465     // Set the width of the opcode to 15.
466     strOpcode.Set(W("               "));
467     strOpcode.Replace(strOpcode.Begin(), (COUNT_T)cbOpcodeName, strOpcodeName);
468
469     //
470     // format argument
471     //
472
473     static const size_t c_cchPreallocateArgument = 512;
474     SString strArgument;
475     strArgument.Preallocate(c_cchPreallocateArgument);
476
477     static const size_t c_cchPreallocateTokenName = 1024;
478     SString strTokenName;
479     strTokenName.Preallocate(c_cchPreallocateTokenName);
480
481     if (ILCodeStream::IsBranchInstruction(instr))
482     {
483         size_t branchDistance = (size_t)pInstruction->uArg;
484         size_t targetOffset = curOffset + s_rgbOpcodeSizes[instr] + branchDistance;
485         strArgument.Printf(W("IL_%04x"), targetOffset);
486     }
487     else if ((ILCodeStream::ILInstrEnum)CEE_NOP == instr)
488     {
489         SString strInstruction;
490         strInstruction.Printf("%s", (char *)pInstruction->uArg);
491         strInstruction.ConvertToUnicode(strArgument);
492     }
493     else
494     {
495         switch (s_rgbOpcodeArgType[instr])
496         {
497         case InlineNone:
498             break;
499             
500         case ShortInlineVar:
501         case ShortInlineI:
502         case InlineI:
503             strArgument.Printf(W("0x%x"), pInstruction->uArg);
504             break;
505             
506         case InlineI8:
507             strArgument.Printf(W("0x%p"), (void *)pInstruction->uArg);
508             break;
509
510         case InlineMethod:
511         case InlineField:
512         case InlineType:
513         case InlineString:
514         case InlineSig:
515         case InlineRVA:
516         case InlineTok:
517             // No token value when we dump IL for ETW
518             if (pDumpILStubCode == NULL)
519                 strArgument.Printf(W("0x%08x"), pInstruction->uArg);
520
521             LPUTF8      pszFormattedStubTargetSig = NULL;
522             CQuickBytes qbTargetSig;
523
524             if (TOKEN_ILSTUB_TARGET_SIG == pInstruction->uArg)
525             {
526                 PCCOR_SIGNATURE pTargetSig;
527                 ULONG           cTargetSig;
528                 CQuickBytes     qbTempTargetSig;
529
530                 IMDInternalImport * pIMDI = MscorlibBinder::GetModule()->GetMDImport();
531
532                 cTargetSig = GetStubTargetMethodSigSize();
533                 pTargetSig = (PCCOR_SIGNATURE)qbTempTargetSig.AllocThrows(cTargetSig);
534
535                 GetStubTargetMethodSig((BYTE*)pTargetSig, cTargetSig);
536                 PrettyPrintSig(pTargetSig,   cTargetSig,  "",  &qbTargetSig, pIMDI, NULL);
537
538                 pszFormattedStubTargetSig = (LPUTF8)qbTargetSig.Ptr();
539             }
540
541             // Dump to szTokenNameBuffer if logging, otherwise dump to szArgumentBuffer to avoid an extra space because we are omitting the token
542             _ASSERTE(FitsIn<mdToken>(pInstruction->uArg));
543             SString strFormattedStubTargetSig;
544             strFormattedStubTargetSig.SetUTF8(pszFormattedStubTargetSig);
545             if (pDumpILStubCode == NULL)
546                 DumpIL_FormatToken(&m_tokenMap, static_cast<mdToken>(pInstruction->uArg), strTokenName, strFormattedStubTargetSig);
547             else
548                 DumpIL_FormatToken(&m_tokenMap, static_cast<mdToken>(pInstruction->uArg), strArgument, strFormattedStubTargetSig);
549                 
550             break;
551         }
552     }
553
554     //
555     // log it!
556     //
557     if (pDumpILStubCode)
558     {
559         pDumpILStubCode->AppendPrintf(W("%s /*(%2d)*/ %s %s %s\n"), strLabel.GetUnicode(), iCurStack, strOpcode.GetUnicode(),
560             strArgument.GetUnicode(), strTokenName.GetUnicode());
561     }
562     else
563     {
564         StackScratchBuffer strLabelBuffer;
565         StackScratchBuffer strOpcodeBuffer;
566         StackScratchBuffer strArgumentBuffer;
567         StackScratchBuffer strTokenNameBuffer;
568         LOG((LF_STUBS, LL_INFO1000, "%s (%2d) %s %s %s\n", strLabel.GetUTF8(strLabelBuffer), iCurStack, \
569             strOpcode.GetUTF8(strOpcodeBuffer), strArgument.GetUTF8(strArgumentBuffer), strTokenName.GetUTF8(strTokenNameBuffer)));
570     }
571 } // ILStubLinker::LogILInstruction
572
573 //---------------------------------------------------------------------------------------
574 // 
575 void 
576 ILStubLinker::LogILStubWorker(
577     ILInstruction * pInstrBuffer, 
578     UINT            numInstr, 
579     size_t *        pcbCode, 
580     INT *           piCurStack, 
581     SString *       pDumpILStubCode)
582 {
583     CONTRACTL
584     {
585         STANDARD_VM_CHECK;
586         PRECONDITION(CheckPointer(pcbCode));
587         PRECONDITION(CheckPointer(piCurStack));
588         PRECONDITION(CheckPointer(pDumpILStubCode, NULL_OK));
589     }
590     CONTRACTL_END;
591
592     bool isLabeled = false;
593
594     for (UINT i = 0; i < numInstr; i++)
595     {
596         ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
597         CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
598         
599         if (instr == ILCodeStream::CEE_CODE_LABEL)
600         {
601             isLabeled = true;
602             continue;
603         }
604         
605         LogILInstruction(*pcbCode, isLabeled, *piCurStack, &pInstrBuffer[i], pDumpILStubCode);
606         isLabeled = false;
607
608         //
609         // calculate the code size
610         //
611         PREFIX_ASSUME((size_t)instr < sizeof(s_rgbOpcodeSizes));
612         *pcbCode += s_rgbOpcodeSizes[instr];
613
614         // 
615         // calculate curstack
616         //
617         *piCurStack += pInstrBuffer[i].iStackDelta;
618     }
619
620     // Be sure to log any trailing label that has no associated instruction.
621     if (isLabeled)
622     {
623         if (pDumpILStubCode)
624         {
625             pDumpILStubCode->AppendPrintf(W("IL_%04x:\n"), *pcbCode);
626         }
627         else
628         {
629             LOG((LF_STUBS, LL_INFO1000, "IL_%04x:\n", *pcbCode));
630         }
631     }
632 }
633
634 static void LogJitFlags(DWORD facility, DWORD level, CORJIT_FLAGS jitFlags)
635 {
636     CONTRACTL
637     {
638         STANDARD_VM_CHECK;
639     }
640     CONTRACTL_END;
641
642     LOG((facility, level, "jitFlags:\n"));
643
644 #define LOG_FLAG(name) \
645     if (jitFlags.IsSet(name)) \
646     { \
647         LOG((facility, level, "   " #name "\n")); \
648         jitFlags.Clear(name); \
649     }
650
651     // these are all we care about at the moment
652     LOG_FLAG(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB);
653     LOG_FLAG(CORJIT_FLAGS::CORJIT_FLAG_PUBLISH_SECRET_PARAM);
654
655 #undef LOG_FLAGS
656
657     if (!jitFlags.IsEmpty())
658     {
659         LOG((facility, level, "UNKNOWN FLAGS also set\n"));
660     }
661 }
662
663 void ILStubLinker::LogILStub(CORJIT_FLAGS jitFlags, SString *pDumpILStubCode)
664 {
665     CONTRACTL
666     {
667         STANDARD_VM_CHECK;
668         PRECONDITION(CheckPointer(pDumpILStubCode, NULL_OK));
669     }
670     CONTRACTL_END;
671
672     ILCodeStream*   pCurrentStream = m_pCodeStreamList;
673     size_t          cbCode = 0;
674     INT             iCurStack = 0;
675
676     if (pDumpILStubCode == NULL)
677         LogJitFlags(LF_STUBS, LL_INFO1000, jitFlags);
678
679     while (pCurrentStream)
680     {
681         if (pCurrentStream->m_pqbILInstructions)
682         {
683             if (pDumpILStubCode)
684                 pDumpILStubCode->AppendPrintf("// %s {\n", pCurrentStream->GetStreamDescription(pCurrentStream->GetStreamType()));
685             else
686                 LOG((LF_STUBS, LL_INFO1000, "%s {\n", pCurrentStream->GetStreamDescription(pCurrentStream->GetStreamType())));
687                 
688             ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
689             LogILStubWorker(pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &cbCode, &iCurStack, pDumpILStubCode);
690
691             if (pDumpILStubCode)
692                 pDumpILStubCode->AppendPrintf("// } %s \n", pCurrentStream->GetStreamDescription(pCurrentStream->GetStreamType()));
693             else
694                 LOG((LF_STUBS, LL_INFO1000, "}\n"));
695         }
696
697         pCurrentStream = pCurrentStream->m_pNextStream;
698     }
699 }
700
701 bool ILStubLinker::FirstPassLink(ILInstruction* pInstrBuffer, UINT numInstr, size_t* pcbCode, INT* piCurStack, UINT* puMaxStack)
702 {
703     CONTRACTL
704     {
705         STANDARD_VM_CHECK;
706         PRECONDITION(CheckPointer(puMaxStack));
707     }
708     CONTRACTL_END;
709
710     bool fStackUnderflow = false;
711
712     for (UINT i = 0; i < numInstr; i++)
713     {
714         ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
715         CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
716
717         //
718         // down-size instructions
719         //
720         instr = ILCodeStream::LowerOpcode(instr, &pInstrBuffer[i]);
721
722         //
723         // fill in code label offsets
724         //
725         if (instr == ILCodeStream::CEE_CODE_LABEL)
726         {
727             ILCodeLabel* pLabel = (ILCodeLabel*)(pInstrBuffer[i].uArg);
728             pLabel->SetCodeOffset(*pcbCode);
729         }
730
731         //
732         // calculate the code size
733         //
734         PREFIX_ASSUME((size_t)instr < sizeof(s_rgbOpcodeSizes));
735         *pcbCode += s_rgbOpcodeSizes[instr];
736
737         // 
738         // calculate maxstack
739         //
740         *piCurStack += pInstrBuffer[i].iStackDelta;
741         if (*piCurStack > (INT)*puMaxStack)
742         {
743             *puMaxStack = *piCurStack;
744         }
745 #ifdef _DEBUG
746         if (*piCurStack < 0)
747         {
748             fStackUnderflow = true;
749         }
750 #endif // _DEBUG
751     }
752
753     return fStackUnderflow;
754 }
755
756 void ILStubLinker::SecondPassLink(ILInstruction* pInstrBuffer, UINT numInstr, size_t* pCurCodeOffset)
757 {
758     CONTRACTL
759     {
760         STANDARD_VM_CHECK;
761         PRECONDITION(CheckPointer(pCurCodeOffset));
762     }
763     CONTRACTL_END;
764
765     for (UINT i = 0; i < numInstr; i++)
766     {
767         ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
768         CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
769         *pCurCodeOffset += s_rgbOpcodeSizes[instr];
770
771         if (ILCodeStream::IsBranchInstruction(instr))
772         {
773             ILCodeLabel* pLabel = (ILCodeLabel*) pInstrBuffer[i].uArg;
774             
775             CONSISTENCY_CHECK(this == pLabel->m_pOwningStubLinker);
776             CONSISTENCY_CHECK(IsInCodeStreamList(pLabel->m_pCodeStreamOfLabel));
777             
778             pInstrBuffer[i].uArg = pLabel->GetCodeOffset() - *pCurCodeOffset;
779         }
780     }
781 }
782
783 size_t ILStubLinker::Link(UINT* puMaxStack)
784 {
785     CONTRACTL
786     {
787         STANDARD_VM_CHECK;
788         PRECONDITION(CheckPointer(puMaxStack));
789     }
790     CONTRACTL_END;
791
792     //
793     // Pass1: calculate code size, lower instructions to smallest form, 
794     //        fill in branch target offsets, and calculate maxstack
795     //
796
797     ILCodeStream*   pCurrentStream = m_pCodeStreamList;
798     size_t          cbCode = 0;
799     INT             iCurStack = 0;
800     UINT            uMaxStack = 0;
801     DEBUG_STMT(bool fStackUnderflow = false);
802
803     while (pCurrentStream)
804     {
805         if (pCurrentStream->m_pqbILInstructions)
806         {
807             ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
808             INDEBUG( fStackUnderflow = ) FirstPassLink(pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &cbCode, &iCurStack, &uMaxStack);
809         }
810
811         pCurrentStream = pCurrentStream->m_pNextStream;
812     }
813
814     //
815     // Pass2: go back and patch the branch instructions
816     //
817
818     pCurrentStream = m_pCodeStreamList;
819     size_t curCodeOffset = 0;
820     
821     while (pCurrentStream)
822     {
823         if (pCurrentStream->m_pqbILInstructions)
824         {
825             ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
826             SecondPassLink(pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &curCodeOffset);
827         }
828
829         pCurrentStream = pCurrentStream->m_pNextStream;
830     }
831
832 #ifdef _DEBUG
833     if (fStackUnderflow)
834     {
835         LogILStub(CORJIT_FLAGS());
836         CONSISTENCY_CHECK_MSG(false, "IL stack underflow! -- see logging output");
837     }
838 #endif // _DEBUG
839
840     *puMaxStack = uMaxStack;
841     return cbCode;
842 }
843
844 #ifdef _DEBUG
845
846 static const PCSTR s_rgOpNames[] = 
847 {
848
849 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
850      #name,
851 #include "opcode.def"
852 #undef OPDEF
853
854 };
855
856
857 #endif // _DEBUG
858
859 BYTE* ILStubLinker::GenerateCodeWorker(BYTE* pbBuffer, ILInstruction* pInstrBuffer, UINT numInstr, size_t* pcbCode)
860 {
861     CONTRACTL
862     {
863         STANDARD_VM_CHECK;
864         PRECONDITION(CheckPointer(pcbCode));
865     }
866     CONTRACTL_END;
867
868     for (UINT i = 0; i < numInstr; i++)
869     {
870         ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
871         CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
872
873         //
874         // copy the IL instructions from the various linkers into the given buffer
875         //
876         if (instr != ILCodeStream::CEE_CODE_LABEL)
877         {
878             const ILOpcode* pOpcode = &s_rgOpcodes[instr];
879
880             PREFIX_ASSUME((size_t)instr < sizeof(s_rgbOpcodeSizes));
881             int     opSize = s_rgbOpcodeSizes[instr];
882             bool    twoByteOp = (pOpcode->byte1 != 0xFF);
883             int     argSize = opSize - (twoByteOp ? 2 : 1);
884
885             if (twoByteOp)
886             {
887                 *pbBuffer++ = pOpcode->byte1;
888             }
889
890             *pbBuffer++ = pOpcode->byte2;
891
892             switch (argSize)
893             {
894                 case 0:
895                     break;
896                     
897                 case 1:
898                     *pbBuffer = (BYTE)pInstrBuffer[i].uArg;
899                     break;
900                     
901                 case 2:
902                     SET_UNALIGNED_VAL16(pbBuffer, pInstrBuffer[i].uArg);
903                     break;
904                     
905                 case 4:
906                     SET_UNALIGNED_VAL32(pbBuffer, pInstrBuffer[i].uArg);
907                     break;
908                     
909                 case 8:
910                     {
911                         UINT64 uVal = pInstrBuffer[i].uArg;
912 #ifndef _WIN64  // We don't have room on 32-bit platforms to store the CLR_NAN_64 value, so 
913                 // we use a special value to represent CLR_NAN_64 and then recreate it here.
914                         if ((instr == ILCodeStream::CEE_LDC_R8) && (((UINT32)uVal) == ILCodeStream::SPECIAL_VALUE_NAN_64_ON_32))
915                             uVal = CLR_NAN_64;
916 #endif // _WIN64
917                         SET_UNALIGNED_VAL64(pbBuffer, uVal);
918                     }
919                     break;
920
921                 default:
922                     UNREACHABLE_MSG("unexpected il opcode argument size");
923             }               
924             
925             pbBuffer += argSize;
926             *pcbCode += opSize;
927         }
928     }
929
930     return pbBuffer;
931 }
932
933 void ILStubLinker::GenerateCode(BYTE* pbBuffer, size_t cbBufferSize)
934 {
935     STANDARD_VM_CONTRACT;
936
937     ILCodeStream*   pCurrentStream = m_pCodeStreamList;
938     size_t          cbCode = 0;
939
940     while (pCurrentStream)
941     {
942         if (pCurrentStream->m_pqbILInstructions)
943         {
944             ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
945             pbBuffer = GenerateCodeWorker(pbBuffer, pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &cbCode);
946         }
947
948         pCurrentStream = pCurrentStream->m_pNextStream;
949     }
950
951     CONSISTENCY_CHECK(cbCode <= cbBufferSize);
952 }
953
954
955 #ifdef _DEBUG
956 bool ILStubLinker::IsInCodeStreamList(ILCodeStream* pcs)
957 {
958     LIMITED_METHOD_CONTRACT;
959     
960     ILCodeStream*   pCurrentStream = m_pCodeStreamList;
961     while (pCurrentStream)
962     {
963         if (pcs == pCurrentStream)
964         {
965             return true;
966         }
967
968         pCurrentStream = pCurrentStream->m_pNextStream;
969     }
970
971     return false;
972 }
973
974 // static
975 bool ILCodeStream::IsSupportedInstruction(ILInstrEnum instr)
976 {
977     LIMITED_METHOD_CONTRACT;
978     
979     CONSISTENCY_CHECK_MSG(instr != CEE_SWITCH, "CEE_SWITCH is not supported currently due to InlineSwitch in s_rgbOpcodeSizes");
980     CONSISTENCY_CHECK_MSG(((instr >= CEE_BR_S) && (instr <= CEE_BLT_UN_S)) || (CEE_LEAVE), "we only use long-form branch opcodes");
981     return true;
982 }
983 #endif // _DEBUG
984
985 LPCSTR ILCodeStream::GetStreamDescription(ILStubLinker::CodeStreamType streamType)
986 {
987     LIMITED_METHOD_CONTRACT;
988
989     static LPCSTR lpszDescriptions[] = {
990         "Initialize",
991         "Marshal",
992         "CallMethod",
993         "UnmarshalReturn",
994         "Unmarshal",
995         "ExceptionCleanup",
996         "Cleanup",
997         "ExceptionHandler",
998     };
999
1000 #ifdef _DEBUG
1001     size_t len = sizeof(lpszDescriptions)/sizeof(LPCSTR);
1002     _ASSERT(streamType >= 0 && (size_t)streamType < len);
1003 #endif // _DEBUG
1004     
1005     return lpszDescriptions[streamType];
1006 }
1007
1008 void ILCodeStream::EmitADD()
1009 {
1010     WRAPPER_NO_CONTRACT;
1011     Emit(CEE_ADD, -1, 0);
1012 }
1013 void ILCodeStream::EmitADD_OVF()
1014 {
1015     WRAPPER_NO_CONTRACT;
1016     Emit(CEE_ADD_OVF, -1, 0);
1017 }
1018 void ILCodeStream::EmitAND()
1019 {
1020     WRAPPER_NO_CONTRACT;
1021     Emit(CEE_AND, -1, 0);
1022 }
1023 void ILCodeStream::EmitARGLIST()
1024 {
1025     WRAPPER_NO_CONTRACT;
1026     Emit(CEE_ARGLIST, 1, 0);
1027 }
1028
1029 void ILCodeStream::EmitBEQ(ILCodeLabel* pCodeLabel)
1030 {
1031     WRAPPER_NO_CONTRACT;
1032     Emit(CEE_BEQ, -2, (UINT_PTR)pCodeLabel);
1033 }
1034
1035 void ILCodeStream::EmitBGE(ILCodeLabel* pCodeLabel)
1036 {
1037     WRAPPER_NO_CONTRACT;
1038     Emit(CEE_BGE, -2, (UINT_PTR)pCodeLabel);
1039 }
1040
1041 void ILCodeStream::EmitBGE_UN(ILCodeLabel* pCodeLabel)
1042 {
1043     WRAPPER_NO_CONTRACT;
1044     Emit(CEE_BGE_UN, -2, (UINT_PTR)pCodeLabel);
1045 }
1046
1047 void ILCodeStream::EmitBGT(ILCodeLabel* pCodeLabel)
1048 {
1049     WRAPPER_NO_CONTRACT;
1050     Emit(CEE_BGT, -2, (UINT_PTR)pCodeLabel);
1051 }
1052 void ILCodeStream::EmitBLE(ILCodeLabel* pCodeLabel)
1053 {
1054     WRAPPER_NO_CONTRACT;
1055     Emit(CEE_BLE, -2, (UINT_PTR)pCodeLabel);
1056 }
1057 void ILCodeStream::EmitBLE_UN(ILCodeLabel* pCodeLabel)
1058 {
1059     WRAPPER_NO_CONTRACT;
1060     Emit(CEE_BLE_UN, -2, (UINT_PTR)pCodeLabel);
1061 }
1062 void ILCodeStream::EmitBLT(ILCodeLabel* pCodeLabel)
1063 {
1064     WRAPPER_NO_CONTRACT;
1065     Emit(CEE_BLT, -2, (UINT_PTR)pCodeLabel);
1066 }
1067 void ILCodeStream::EmitBR(ILCodeLabel* pCodeLabel)
1068 {
1069     WRAPPER_NO_CONTRACT;
1070     Emit(CEE_BR, 0, (UINT_PTR)pCodeLabel);
1071 }
1072 void ILCodeStream::EmitBREAK()
1073 {
1074     WRAPPER_NO_CONTRACT;
1075     Emit(CEE_BREAK, 0, 0);
1076 }
1077 void ILCodeStream::EmitBRFALSE(ILCodeLabel* pCodeLabel)
1078 {
1079     WRAPPER_NO_CONTRACT;
1080     Emit(CEE_BRFALSE, -1, (UINT_PTR)pCodeLabel);
1081 }
1082 void ILCodeStream::EmitBRTRUE(ILCodeLabel* pCodeLabel)
1083 {
1084     WRAPPER_NO_CONTRACT;
1085     Emit(CEE_BRTRUE, -1, (UINT_PTR)pCodeLabel);
1086 }
1087 void ILCodeStream::EmitCALL(int token, int numInArgs, int numRetArgs)
1088 {
1089     WRAPPER_NO_CONTRACT;
1090     Emit(CEE_CALL, (INT16)(numRetArgs - numInArgs), token);
1091 }
1092 void ILCodeStream::EmitCALLI(int token, int numInArgs, int numRetArgs)
1093 {
1094     WRAPPER_NO_CONTRACT;
1095     Emit(CEE_CALLI, (INT16)(numRetArgs - numInArgs - 1), token);
1096 }
1097 void ILCodeStream::EmitCEQ     ()
1098 {
1099     WRAPPER_NO_CONTRACT;
1100     Emit(CEE_CEQ, -1, 0);
1101 }
1102 void ILCodeStream::EmitCGT()
1103 {
1104     WRAPPER_NO_CONTRACT;
1105     Emit(CEE_CGT, -1, 0);
1106 }
1107 void ILCodeStream::EmitCGT_UN()
1108 {
1109     WRAPPER_NO_CONTRACT;
1110     Emit(CEE_CGT_UN, -1, 0);
1111 }
1112 void ILCodeStream::EmitCLT()
1113 {
1114     WRAPPER_NO_CONTRACT;
1115     Emit(CEE_CLT, -1, 0);
1116 }
1117 void ILCodeStream::EmitCLT_UN()
1118 {
1119     WRAPPER_NO_CONTRACT;
1120     Emit(CEE_CLT_UN, -1, 0);
1121 }
1122 void ILCodeStream::EmitCONV_I()
1123 {
1124     WRAPPER_NO_CONTRACT;
1125     Emit(CEE_CONV_I, 0, 0);
1126 }
1127 void ILCodeStream::EmitCONV_I1()
1128 {
1129     WRAPPER_NO_CONTRACT;
1130     Emit(CEE_CONV_I1, 0, 0);
1131 }
1132 void ILCodeStream::EmitCONV_I2()
1133 {
1134     WRAPPER_NO_CONTRACT;
1135     Emit(CEE_CONV_I2, 0, 0);
1136 }
1137 void ILCodeStream::EmitCONV_I4()
1138 {
1139     WRAPPER_NO_CONTRACT;
1140     Emit(CEE_CONV_I4, 0, 0);
1141 }
1142 void ILCodeStream::EmitCONV_I8()
1143 {
1144     WRAPPER_NO_CONTRACT;
1145     Emit(CEE_CONV_I8, 0, 0);
1146 }
1147 void ILCodeStream::EmitCONV_U()
1148 {
1149     WRAPPER_NO_CONTRACT;
1150     Emit(CEE_CONV_U, 0, 0);
1151 }
1152 void ILCodeStream::EmitCONV_U1()
1153 {
1154     WRAPPER_NO_CONTRACT;
1155     Emit(CEE_CONV_U1, 0, 0);
1156 }
1157 void ILCodeStream::EmitCONV_U2()
1158 {
1159     WRAPPER_NO_CONTRACT;
1160     Emit(CEE_CONV_U2, 0, 0);
1161 }
1162 void ILCodeStream::EmitCONV_U4()
1163 {
1164     WRAPPER_NO_CONTRACT;
1165     Emit(CEE_CONV_U4, 0, 0);
1166 }
1167 void ILCodeStream::EmitCONV_U8()
1168 {
1169     WRAPPER_NO_CONTRACT;
1170     Emit(CEE_CONV_U8, 0, 0);
1171 }
1172 void ILCodeStream::EmitCONV_R4()
1173 {
1174     WRAPPER_NO_CONTRACT;
1175     Emit(CEE_CONV_R4, 0, 0);
1176 }
1177 void ILCodeStream::EmitCONV_R8()
1178 {
1179     WRAPPER_NO_CONTRACT;
1180     Emit(CEE_CONV_R8, 0, 0);
1181 }
1182 void ILCodeStream::EmitCONV_OVF_I4()
1183 {
1184     WRAPPER_NO_CONTRACT;
1185     Emit(CEE_CONV_OVF_I4, 0, 0);
1186 }
1187 void ILCodeStream::EmitCONV_T(CorElementType t)
1188 {
1189     STANDARD_VM_CONTRACT;
1190
1191     switch (t)
1192     {
1193     case ELEMENT_TYPE_U1:
1194         EmitCONV_U1();
1195         break;
1196     case ELEMENT_TYPE_I1:
1197         EmitCONV_I1();
1198         break;
1199     case ELEMENT_TYPE_U2:
1200         EmitCONV_U2();
1201         break;
1202     case ELEMENT_TYPE_I2:
1203         EmitCONV_I2();
1204         break;
1205     case ELEMENT_TYPE_U4:
1206         EmitCONV_U4();
1207         break;
1208     case ELEMENT_TYPE_I4:
1209         EmitCONV_I4();
1210         break;
1211     case ELEMENT_TYPE_U8:
1212         EmitCONV_U8();
1213         break;
1214     case ELEMENT_TYPE_I8:
1215         EmitCONV_I8();
1216         break;
1217     case ELEMENT_TYPE_R4:
1218         EmitCONV_R4();
1219         break;
1220     case ELEMENT_TYPE_R8:
1221         EmitCONV_R8();
1222         break;
1223     case ELEMENT_TYPE_I:
1224         EmitCONV_I();
1225         break;
1226     case ELEMENT_TYPE_U:
1227         EmitCONV_U();
1228         break;
1229     default:
1230         _ASSERTE(!"Invalid type for conversion");
1231         break;
1232     }
1233 }
1234 void ILCodeStream::EmitCPBLK()
1235 {
1236     WRAPPER_NO_CONTRACT;
1237     Emit(CEE_CPBLK, -3, 0);
1238 }
1239 void ILCodeStream::EmitCPOBJ(int token)
1240 {
1241     WRAPPER_NO_CONTRACT;
1242     Emit(CEE_CPOBJ, -2, token);
1243 }
1244 void ILCodeStream::EmitDUP     ()
1245 {
1246     WRAPPER_NO_CONTRACT;
1247     Emit(CEE_DUP, 1, 0);
1248 }
1249 void ILCodeStream::EmitENDFINALLY()
1250 {
1251     WRAPPER_NO_CONTRACT;
1252     Emit(CEE_ENDFINALLY, 0, 0);
1253 }
1254 void ILCodeStream::EmitINITBLK()
1255 {
1256     WRAPPER_NO_CONTRACT;
1257     Emit(CEE_INITBLK, -3, 0);
1258 }
1259 void ILCodeStream::EmitINITOBJ(int token)
1260 {
1261     WRAPPER_NO_CONTRACT;
1262     Emit(CEE_INITOBJ, -1, token);
1263 }
1264 void ILCodeStream::EmitJMP(int token)
1265 {
1266     WRAPPER_NO_CONTRACT;
1267     Emit(CEE_JMP, 0, token);
1268 }
1269 void ILCodeStream::EmitLDARG   (unsigned uArgIdx)
1270 {
1271     WRAPPER_NO_CONTRACT;
1272
1273     if (m_pOwner->m_fHasThis)
1274     {
1275         uArgIdx++;
1276     }
1277     Emit(CEE_LDARG, 1, uArgIdx);
1278 }
1279 void ILCodeStream::EmitLDARGA  (unsigned uArgIdx)
1280 {
1281     WRAPPER_NO_CONTRACT;
1282     if (m_pOwner->m_fHasThis)
1283     {
1284         uArgIdx++;
1285     }
1286     Emit(CEE_LDARGA, 1, uArgIdx);
1287 }
1288 void ILCodeStream::EmitLDC(DWORD_PTR uConst)
1289 {
1290     WRAPPER_NO_CONTRACT;
1291     Emit(
1292 #ifdef _WIN64
1293         CEE_LDC_I8
1294 #else
1295         CEE_LDC_I4
1296 #endif
1297         , 1, uConst);
1298 }
1299 void ILCodeStream::EmitLDC_R4(UINT32 uConst)
1300 {
1301     WRAPPER_NO_CONTRACT;
1302     Emit(CEE_LDC_R4, 1, uConst);
1303 }
1304 void ILCodeStream::EmitLDC_R8(UINT64 uConst)
1305 {
1306     STANDARD_VM_CONTRACT;
1307 #ifndef _WIN64  // We don't have room on 32-bit platforms to stor the CLR_NAN_64 value, so 
1308                 // we use a special value to represent CLR_NAN_64 and then recreate it later.
1309     CONSISTENCY_CHECK(((UINT32)uConst) != SPECIAL_VALUE_NAN_64_ON_32);
1310     if (uConst == CLR_NAN_64)
1311         uConst = SPECIAL_VALUE_NAN_64_ON_32;
1312     else
1313         CONSISTENCY_CHECK(FitsInU4(uConst));
1314 #endif // _WIN64
1315     Emit(CEE_LDC_R8, 1, (UINT_PTR)uConst);
1316 }
1317 void ILCodeStream::EmitLDELEMA(int token)
1318 {
1319     WRAPPER_NO_CONTRACT;
1320     Emit(CEE_LDELEMA, -1, token);
1321 }
1322 void ILCodeStream::EmitLDELEM_REF()
1323 {
1324     WRAPPER_NO_CONTRACT;
1325     Emit(CEE_LDELEM_REF, -1, 0);
1326 }
1327 void ILCodeStream::EmitLDFLD(int token)
1328 {
1329     WRAPPER_NO_CONTRACT;
1330     Emit(CEE_LDFLD, 0, token);
1331 }
1332 void ILCodeStream::EmitLDFLDA(int token)
1333 {
1334     WRAPPER_NO_CONTRACT;
1335     Emit(CEE_LDFLDA, 0, token);
1336 }
1337 void ILCodeStream::EmitLDFTN(int token)
1338 {
1339     WRAPPER_NO_CONTRACT;
1340     Emit(CEE_LDFTN, 1, token);
1341 }
1342 void ILCodeStream::EmitLDIND_I()
1343 {
1344     WRAPPER_NO_CONTRACT;
1345     Emit(CEE_LDIND_I, 0, 0);
1346 }
1347 void ILCodeStream::EmitLDIND_I1()
1348 {
1349     WRAPPER_NO_CONTRACT;
1350     Emit(CEE_LDIND_I1, 0, 0);
1351 }
1352 void ILCodeStream::EmitLDIND_I2()
1353 {
1354     WRAPPER_NO_CONTRACT;
1355     Emit(CEE_LDIND_I2, 0, 0);
1356 }
1357 void ILCodeStream::EmitLDIND_I4()
1358 {
1359     WRAPPER_NO_CONTRACT;
1360     Emit(CEE_LDIND_I4, 0, 0);
1361 }
1362 void ILCodeStream::EmitLDIND_I8()
1363 {
1364     WRAPPER_NO_CONTRACT;
1365     Emit(CEE_LDIND_I8, 0, 0);
1366 }
1367 void ILCodeStream::EmitLDIND_R4()
1368 {
1369     WRAPPER_NO_CONTRACT;
1370     Emit(CEE_LDIND_R4, 0, 0);
1371 }
1372 void ILCodeStream::EmitLDIND_R8()
1373 {
1374     WRAPPER_NO_CONTRACT;
1375     Emit(CEE_LDIND_R8, 0, 0);
1376 }
1377 void ILCodeStream::EmitLDIND_REF()
1378 {
1379     WRAPPER_NO_CONTRACT;
1380     Emit(CEE_LDIND_REF, 0, 0);
1381 }
1382 void ILCodeStream::EmitLDIND_T(LocalDesc* pType)
1383 {
1384     CONTRACTL
1385     {
1386         PRECONDITION(pType->cbType >= 1);
1387     }
1388     CONTRACTL_END;
1389
1390     CorElementType elementType = ELEMENT_TYPE_END;
1391
1392     bool onlyFoundModifiers = true;
1393     for(size_t i = 0; i < pType->cbType && onlyFoundModifiers; i++)
1394     {
1395         elementType = (CorElementType)pType->ElementType[i];
1396         onlyFoundModifiers = (elementType == ELEMENT_TYPE_PINNED);
1397     }
1398     
1399
1400     switch (elementType)
1401     {
1402         case ELEMENT_TYPE_I1:       EmitLDIND_I1(); break;
1403         case ELEMENT_TYPE_BOOLEAN:  // fall through
1404         case ELEMENT_TYPE_U1:       EmitLDIND_U1(); break;
1405         case ELEMENT_TYPE_I2:       EmitLDIND_I2(); break;
1406         case ELEMENT_TYPE_CHAR:     // fall through
1407         case ELEMENT_TYPE_U2:       EmitLDIND_U2(); break;
1408         case ELEMENT_TYPE_I4:       EmitLDIND_I4(); break;
1409         case ELEMENT_TYPE_U4:       EmitLDIND_U4(); break;
1410         case ELEMENT_TYPE_I8:       EmitLDIND_I8(); break;
1411         case ELEMENT_TYPE_U8:       EmitLDIND_I8(); break;
1412         case ELEMENT_TYPE_R4:       EmitLDIND_R4(); break;
1413         case ELEMENT_TYPE_R8:       EmitLDIND_R8(); break;
1414         case ELEMENT_TYPE_PTR:      // same as ELEMENT_TYPE_I
1415         case ELEMENT_TYPE_FNPTR:    // same as ELEMENT_TYPE_I
1416         case ELEMENT_TYPE_I:        EmitLDIND_I();  break;
1417         case ELEMENT_TYPE_U:        EmitLDIND_I();  break;
1418         case ELEMENT_TYPE_STRING:   // fall through
1419         case ELEMENT_TYPE_CLASS:    // fall through
1420         case ELEMENT_TYPE_ARRAY:
1421         case ELEMENT_TYPE_SZARRAY:
1422         case ELEMENT_TYPE_OBJECT:   EmitLDIND_REF(); break;
1423
1424         case ELEMENT_TYPE_INTERNAL:
1425         {
1426             CONSISTENCY_CHECK_MSG(!(pType->InternalToken.GetMethodTable()->IsValueType()), "don't know how to handle value types here");
1427             EmitLDIND_REF();
1428             break;
1429         }
1430
1431         default:
1432             UNREACHABLE_MSG("unexpected type passed to EmitLDIND_T");
1433             break;
1434     }
1435 }
1436 void ILCodeStream::EmitLDIND_U1()
1437 {
1438     WRAPPER_NO_CONTRACT;
1439     Emit(CEE_LDIND_U1, 0, 0);
1440 }
1441 void ILCodeStream::EmitLDIND_U2()
1442 {
1443     WRAPPER_NO_CONTRACT;
1444     Emit(CEE_LDIND_U2, 0, 0);
1445 }
1446 void ILCodeStream::EmitLDIND_U4()
1447 {
1448     WRAPPER_NO_CONTRACT;
1449     Emit(CEE_LDIND_U4, 0, 0);
1450 }
1451 void ILCodeStream::EmitLDLEN()
1452 {
1453     WRAPPER_NO_CONTRACT;
1454     Emit(CEE_LDLEN, 0, 0);
1455 }
1456 void ILCodeStream::EmitLDLOC   (DWORD dwLocalNum)
1457 {
1458     STANDARD_VM_CONTRACT;
1459     CONSISTENCY_CHECK(dwLocalNum != (DWORD)-1);
1460     CONSISTENCY_CHECK(dwLocalNum != (WORD)-1);
1461     Emit(CEE_LDLOC, 1, dwLocalNum);
1462 }
1463 void ILCodeStream::EmitLDLOCA  (DWORD dwLocalNum)
1464 {
1465     WRAPPER_NO_CONTRACT;
1466     Emit(CEE_LDLOCA, 1, dwLocalNum);
1467 }
1468 void ILCodeStream::EmitLDNULL()
1469 {
1470     WRAPPER_NO_CONTRACT;
1471     Emit(CEE_LDNULL, 1, 0);
1472 }
1473 void ILCodeStream::EmitLDOBJ   (int token)
1474 {
1475     WRAPPER_NO_CONTRACT;
1476     Emit(CEE_LDOBJ, 0, token);
1477 }
1478 void ILCodeStream::EmitLDSFLD(int token)
1479 {
1480     WRAPPER_NO_CONTRACT;
1481     Emit(CEE_LDSFLD, 1, token);
1482 }
1483 void ILCodeStream::EmitLDSFLDA(int token)
1484 {
1485     WRAPPER_NO_CONTRACT;
1486     Emit(CEE_LDSFLDA, 1, token);
1487 }
1488 void ILCodeStream::EmitLDTOKEN(int token)
1489 {
1490     WRAPPER_NO_CONTRACT;
1491     Emit(CEE_LDTOKEN, 1, token);
1492 }
1493 void ILCodeStream::EmitLEAVE(ILCodeLabel* pCodeLabel)
1494 {
1495     WRAPPER_NO_CONTRACT;
1496     Emit(CEE_LEAVE, 0, (UINT_PTR)pCodeLabel);
1497 }
1498 void ILCodeStream::EmitLOCALLOC()
1499 {
1500     WRAPPER_NO_CONTRACT;
1501     Emit(CEE_LOCALLOC, 0, 0);
1502 }
1503 void ILCodeStream::EmitMUL()
1504 {
1505     WRAPPER_NO_CONTRACT;
1506     Emit(CEE_MUL, -1, 0);
1507 }
1508 void ILCodeStream::EmitMUL_OVF()
1509 {
1510     WRAPPER_NO_CONTRACT;
1511     Emit(CEE_MUL_OVF, -1, 0);
1512 }
1513 void ILCodeStream::EmitNEWOBJ(int token, int numInArgs)
1514 {
1515     WRAPPER_NO_CONTRACT;
1516     Emit(CEE_NEWOBJ, (INT16)(1 - numInArgs), token);
1517 }
1518
1519 void ILCodeStream::EmitNOP(LPCSTR pszNopComment)
1520 {
1521     WRAPPER_NO_CONTRACT;
1522     Emit(CEE_NOP, 0, (UINT_PTR)pszNopComment);
1523 }
1524
1525 void ILCodeStream::EmitPOP()
1526 {
1527     WRAPPER_NO_CONTRACT;
1528     Emit(CEE_POP, -1, 0);
1529 }
1530 void ILCodeStream::EmitRET()
1531 {
1532     WRAPPER_NO_CONTRACT;
1533     INT16 iStackDelta = m_pOwner->ReturnOpcodePopsStack() ? -1 : 0;
1534     Emit(CEE_RET, iStackDelta, 0);
1535 }
1536 void ILCodeStream::EmitSHR_UN()
1537 {
1538     WRAPPER_NO_CONTRACT;
1539     Emit(CEE_SHR_UN, -1, 0);
1540 }
1541 void ILCodeStream::EmitSTARG(unsigned uArgIdx)
1542 {
1543     WRAPPER_NO_CONTRACT;
1544     Emit(CEE_STARG, -1, uArgIdx);
1545 }
1546 void ILCodeStream::EmitSTELEM_REF()
1547 {
1548     WRAPPER_NO_CONTRACT;
1549     Emit(CEE_STELEM_REF, -3, 0);
1550 }
1551 void ILCodeStream::EmitSTIND_I()
1552 {
1553     WRAPPER_NO_CONTRACT;
1554     Emit(CEE_STIND_I, -2, 0);
1555 }
1556 void ILCodeStream::EmitSTIND_I1()
1557 {
1558     WRAPPER_NO_CONTRACT;
1559     Emit(CEE_STIND_I1, -2, 0);
1560 }
1561 void ILCodeStream::EmitSTIND_I2()
1562 {
1563     WRAPPER_NO_CONTRACT;
1564     Emit(CEE_STIND_I2, -2, 0);
1565 }
1566 void ILCodeStream::EmitSTIND_I4()
1567 {
1568     WRAPPER_NO_CONTRACT;
1569     Emit(CEE_STIND_I4, -2, 0);
1570 }
1571 void ILCodeStream::EmitSTIND_I8()
1572 {
1573     WRAPPER_NO_CONTRACT;
1574     Emit(CEE_STIND_I8, -2, 0);
1575 }
1576 void ILCodeStream::EmitSTIND_R4()
1577 {
1578     WRAPPER_NO_CONTRACT;
1579     Emit(CEE_STIND_R4, -2, 0);
1580 }
1581 void ILCodeStream::EmitSTIND_R8()
1582 {
1583     WRAPPER_NO_CONTRACT;
1584     Emit(CEE_STIND_R8, -2, 0);
1585 }
1586 void ILCodeStream::EmitSTIND_REF()
1587 {
1588     WRAPPER_NO_CONTRACT;
1589     Emit(CEE_STIND_REF, -2, 0);
1590 }
1591 void ILCodeStream::EmitSTIND_T(LocalDesc* pType)
1592 {
1593     CONTRACTL
1594     {
1595         PRECONDITION(pType->cbType >= 1);
1596     }
1597     CONTRACTL_END;
1598
1599     CorElementType elementType = ELEMENT_TYPE_END;
1600
1601     bool onlyFoundModifiers = true;
1602     for(size_t i = 0; i < pType->cbType && onlyFoundModifiers; i++)
1603     {
1604         elementType = (CorElementType)pType->ElementType[i];
1605         onlyFoundModifiers = (elementType == ELEMENT_TYPE_PINNED);
1606     }
1607     switch (pType->ElementType[0])
1608     {
1609         case ELEMENT_TYPE_I1:       EmitSTIND_I1(); break;
1610         case ELEMENT_TYPE_BOOLEAN:  // fall through
1611         case ELEMENT_TYPE_U1:       EmitSTIND_I1(); break;
1612         case ELEMENT_TYPE_I2:       EmitSTIND_I2(); break;
1613         case ELEMENT_TYPE_CHAR:     // fall through
1614         case ELEMENT_TYPE_U2:       EmitSTIND_I2(); break;
1615         case ELEMENT_TYPE_I4:       EmitSTIND_I4(); break;
1616         case ELEMENT_TYPE_U4:       EmitSTIND_I4(); break;
1617         case ELEMENT_TYPE_I8:       EmitSTIND_I8(); break;
1618         case ELEMENT_TYPE_U8:       EmitSTIND_I8(); break;
1619         case ELEMENT_TYPE_R4:       EmitSTIND_R4(); break;
1620         case ELEMENT_TYPE_R8:       EmitSTIND_R8(); break;
1621         case ELEMENT_TYPE_PTR:      // same as ELEMENT_TYPE_I
1622         case ELEMENT_TYPE_FNPTR:    // same as ELEMENT_TYPE_I
1623         case ELEMENT_TYPE_I:        EmitSTIND_I();  break;
1624         case ELEMENT_TYPE_U:        EmitSTIND_I();  break;
1625         case ELEMENT_TYPE_STRING:   // fall through
1626         case ELEMENT_TYPE_CLASS:   // fall through
1627         case ELEMENT_TYPE_ARRAY:
1628         case ELEMENT_TYPE_SZARRAY:
1629         case ELEMENT_TYPE_OBJECT:   EmitSTIND_REF(); break;
1630
1631         case ELEMENT_TYPE_INTERNAL:
1632         {
1633             CONSISTENCY_CHECK_MSG(!(pType->InternalToken.GetMethodTable()->IsValueType()), "don't know how to handle value types here");
1634             EmitSTIND_REF();
1635             break;
1636         }
1637
1638         default:
1639             UNREACHABLE_MSG("unexpected type passed to EmitSTIND_T");
1640             break;
1641     }
1642 }
1643 void ILCodeStream::EmitSTFLD(int token)
1644 {
1645     WRAPPER_NO_CONTRACT;
1646     Emit(CEE_STFLD, -2, token);
1647 }
1648 void ILCodeStream::EmitSTLOC(DWORD dwLocalNum)
1649 {
1650     WRAPPER_NO_CONTRACT;
1651     Emit(CEE_STLOC, -1, dwLocalNum);
1652 }
1653 void ILCodeStream::EmitSTOBJ(int token)
1654 {
1655     WRAPPER_NO_CONTRACT;
1656     Emit(CEE_STOBJ, -2, token);
1657 }
1658 void ILCodeStream::EmitSTSFLD(int token)
1659 {
1660     WRAPPER_NO_CONTRACT;
1661     Emit(CEE_STSFLD, -1, token);
1662 }
1663 void ILCodeStream::EmitSUB()
1664 {
1665     WRAPPER_NO_CONTRACT;
1666     Emit(CEE_SUB, -1, 0);
1667 }
1668 void ILCodeStream::EmitTHROW()
1669 {
1670     WRAPPER_NO_CONTRACT;
1671     Emit(CEE_THROW, -1, 0);
1672 }
1673
1674
1675 void ILCodeStream::EmitNEWOBJ(BinderMethodID id, int numInArgs)
1676 {
1677     STANDARD_VM_CONTRACT;
1678     EmitNEWOBJ(GetToken(MscorlibBinder::GetMethod(id)), numInArgs);
1679 }
1680
1681 void ILCodeStream::EmitCALL(BinderMethodID id, int numInArgs, int numRetArgs)
1682 {
1683     STANDARD_VM_CONTRACT;
1684     EmitCALL(GetToken(MscorlibBinder::GetMethod(id)), numInArgs, numRetArgs);
1685 }
1686
1687 void ILStubLinker::SetHasThis (bool fHasThis)
1688 {
1689     LIMITED_METHOD_CONTRACT;
1690     m_fHasThis = fHasThis;
1691 }
1692
1693 void ILCodeStream::EmitLoadThis ()
1694 {
1695     WRAPPER_NO_CONTRACT;
1696     _ASSERTE(m_pOwner->m_fHasThis);
1697     // OK, this is ugly, but we add 1 to all LDARGs when
1698     // m_fHasThis is true, so we compensate for that here
1699     // so that we don't have to have a special method to 
1700     // load arguments.
1701     EmitLDARG((unsigned)-1);
1702 }
1703
1704 void ILCodeStream::EmitLoadNullPtr()
1705 {
1706     WRAPPER_NO_CONTRACT;
1707
1708     // This is the correct way to load unmanaged zero pointer. EmitLDC(0) alone works
1709     // fine in most cases but may lead to wrong code being generated on 64-bit if the
1710     // flow graph is complex.
1711     EmitLDC(0);
1712     EmitCONV_I();
1713 }
1714
1715 void ILCodeStream::EmitArgIteratorCreateAndLoad()
1716 {
1717     STANDARD_VM_CONTRACT;
1718     
1719     //
1720     // we insert the ArgIterator in the same spot that the VASigCookie will go for sanity
1721     //
1722     LocalDesc   aiLoc(MscorlibBinder::GetClass(CLASS__ARG_ITERATOR));
1723     int         aiLocNum;
1724
1725     aiLocNum = NewLocal(aiLoc);
1726
1727     EmitLDLOCA(aiLocNum);
1728     EmitDUP();
1729     EmitARGLIST();
1730     EmitLoadNullPtr();
1731     EmitCALL(METHOD__ARG_ITERATOR__CTOR2, 2, 0);
1732
1733     aiLoc.ElementType[0]    = ELEMENT_TYPE_BYREF;
1734     aiLoc.ElementType[1]    = ELEMENT_TYPE_INTERNAL;
1735     aiLoc.cbType            = 2;
1736     aiLoc.InternalToken     = MscorlibBinder::GetClass(CLASS__ARG_ITERATOR);
1737     
1738     SetStubTargetArgType(&aiLoc, false);
1739 }
1740
1741 DWORD ILStubLinker::NewLocal(CorElementType typ)
1742 {
1743     CONTRACTL
1744     {
1745         STANDARD_VM_CHECK;
1746         INJECT_FAULT(COMPlusThrowOM());
1747     }
1748     CONTRACTL_END;
1749
1750     LocalDesc locDesc(typ);
1751     return NewLocal(locDesc);
1752 }
1753
1754 StubSigBuilder::StubSigBuilder() :
1755     m_nItems(0),
1756     m_cbSig(0)
1757 {
1758     STANDARD_VM_CONTRACT;
1759
1760     m_pbSigCursor  = (BYTE*) m_qbSigBuffer.AllocThrows(INITIAL_BUFFER_SIZE);
1761 }
1762
1763 void StubSigBuilder::EnsureEnoughQuickBytes(size_t cbToAppend)
1764 {
1765     STANDARD_VM_CONTRACT;
1766
1767     SIZE_T cbBuffer = m_qbSigBuffer.Size();
1768     if ((m_cbSig + cbToAppend) >= cbBuffer)
1769     {
1770         m_qbSigBuffer.ReSizeThrows(2 * cbBuffer);
1771         m_pbSigCursor = ((BYTE*)m_qbSigBuffer.Ptr()) + m_cbSig;
1772     }
1773 }
1774
1775 DWORD StubSigBuilder::Append(LocalDesc* pLoc)
1776 {
1777     CONTRACTL
1778     {
1779         STANDARD_VM_CHECK;
1780         INJECT_FAULT(COMPlusThrowOM());
1781         PRECONDITION(CheckPointer(pLoc));
1782     }
1783     CONTRACTL_END;
1784
1785     EnsureEnoughQuickBytes(pLoc->cbType + sizeof(TypeHandle));    
1786
1787     memcpyNoGCRefs(m_pbSigCursor, pLoc->ElementType, pLoc->cbType);
1788     m_pbSigCursor   += pLoc->cbType;
1789     m_cbSig         += pLoc->cbType;
1790
1791     size_t i = 0;
1792
1793     while (i < pLoc->cbType)
1794     {
1795         CONSISTENCY_CHECK(   ELEMENT_TYPE_CLASS     != pLoc->ElementType[i]
1796                           && ELEMENT_TYPE_VALUETYPE != pLoc->ElementType[i]);
1797                 
1798         switch (pLoc->ElementType[i])
1799         {
1800             case ELEMENT_TYPE_INTERNAL:
1801                 SET_UNALIGNED_PTR(m_pbSigCursor, (UINT_PTR)pLoc->InternalToken.AsPtr());
1802                 m_pbSigCursor   += sizeof(TypeHandle);
1803                 m_cbSig         += sizeof(TypeHandle);
1804                 break;
1805
1806             case ELEMENT_TYPE_FNPTR:
1807                 {
1808                     SigPointer  ptr(pLoc->pSig);
1809
1810                     SigBuilder sigBuilder;
1811                     ptr.ConvertToInternalSignature(pLoc->pSigModule, NULL, &sigBuilder);
1812
1813                     DWORD cbFnPtrSig;
1814                     PVOID pFnPtrSig = sigBuilder.GetSignature(&cbFnPtrSig);
1815
1816                     EnsureEnoughQuickBytes(cbFnPtrSig);
1817
1818                     memcpyNoGCRefs(m_pbSigCursor, pFnPtrSig, cbFnPtrSig);
1819
1820                     m_pbSigCursor += cbFnPtrSig;
1821                     m_cbSig       += cbFnPtrSig;
1822                 }
1823                 break;
1824
1825             default: 
1826                 break;
1827         }
1828         
1829         i++;
1830     }
1831
1832     if (pLoc->ElementType[0] == ELEMENT_TYPE_ARRAY)
1833     {
1834         EnsureEnoughQuickBytes(pLoc->cbArrayBoundsInfo);
1835         
1836         memcpyNoGCRefs(m_pbSigCursor, pLoc->pSig, pLoc->cbArrayBoundsInfo);
1837         m_pbSigCursor   += pLoc->cbArrayBoundsInfo;
1838         m_cbSig         += pLoc->cbArrayBoundsInfo;
1839     }
1840
1841     _ASSERTE(m_cbSig <= m_qbSigBuffer.Size());  // we corrupted our buffer resizing if this assert fires
1842
1843     return m_nItems++;
1844 }
1845
1846 //---------------------------------------------------------------------------------------
1847 // 
1848 DWORD 
1849 LocalSigBuilder::GetSigSize()
1850 {
1851     STANDARD_VM_CONTRACT;
1852
1853     BYTE   temp[4];
1854     UINT32 cbEncoded   = CorSigCompressData(m_nItems, temp);
1855
1856     S_UINT32 cbSigSize = 
1857         S_UINT32(1) +           // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
1858         S_UINT32(cbEncoded) +   // encoded number of locals
1859         S_UINT32(m_cbSig) +     // types
1860         S_UINT32(1);            // ELEMENT_TYPE_END
1861     if (cbSigSize.IsOverflow())
1862     {
1863         IfFailThrow(COR_E_OVERFLOW);
1864     }
1865     return cbSigSize.Value();
1866 }
1867
1868 //---------------------------------------------------------------------------------------
1869 // 
1870 DWORD 
1871 LocalSigBuilder::GetSig(
1872     BYTE * pbLocalSig, 
1873     DWORD  cbBuffer)
1874 {
1875     STANDARD_VM_CONTRACT;
1876     BYTE    temp[4];
1877     size_t  cb = CorSigCompressData(m_nItems, temp);
1878
1879     _ASSERTE((1 + cb + m_cbSig + 1) == GetSigSize());
1880
1881     if ((1 + cb + m_cbSig + 1) <= cbBuffer)
1882     {
1883         pbLocalSig[0] = IMAGE_CEE_CS_CALLCONV_LOCAL_SIG;
1884         memcpyNoGCRefs(&pbLocalSig[1],      temp,                cb);
1885         memcpyNoGCRefs(&pbLocalSig[1 + cb], m_qbSigBuffer.Ptr(), m_cbSig);
1886         pbLocalSig[1 + cb + m_cbSig] = ELEMENT_TYPE_END;
1887         return (DWORD)(1 + cb + m_cbSig + 1);
1888     }
1889     else
1890     {
1891         return NULL;
1892     }
1893 }
1894
1895 FunctionSigBuilder::FunctionSigBuilder() :
1896     m_callingConv(IMAGE_CEE_CS_CALLCONV_DEFAULT)
1897 {
1898     STANDARD_VM_CONTRACT;
1899     m_qbReturnSig.ReSizeThrows(1);
1900     *(CorElementType *)m_qbReturnSig.Ptr() = ELEMENT_TYPE_VOID;
1901 }
1902
1903
1904 void FunctionSigBuilder::SetReturnType(LocalDesc* pLoc)
1905 {
1906     CONTRACTL
1907     {
1908         STANDARD_VM_CHECK;
1909         PRECONDITION(pLoc->cbType > 0);
1910     }
1911     CONTRACTL_END;
1912     
1913     m_qbReturnSig.ReSizeThrows(pLoc->cbType);
1914     memcpyNoGCRefs(m_qbReturnSig.Ptr(), pLoc->ElementType, pLoc->cbType);
1915
1916     size_t i = 0;
1917
1918     while (i < pLoc->cbType)
1919     {
1920         CONSISTENCY_CHECK(   ELEMENT_TYPE_CLASS     != pLoc->ElementType[i]
1921                           && ELEMENT_TYPE_VALUETYPE != pLoc->ElementType[i]);
1922                 
1923         switch (pLoc->ElementType[i])
1924         {
1925             case ELEMENT_TYPE_INTERNAL:
1926                 m_qbReturnSig.ReSizeThrows(m_qbReturnSig.Size() + sizeof(TypeHandle));
1927                 SET_UNALIGNED_PTR((BYTE *)m_qbReturnSig.Ptr() + m_qbReturnSig.Size() - + sizeof(TypeHandle), (UINT_PTR)pLoc->InternalToken.AsPtr());
1928                 break;
1929
1930             case ELEMENT_TYPE_FNPTR:
1931                 {
1932                     SigPointer  ptr(pLoc->pSig);
1933
1934                     SigBuilder sigBuilder;
1935                     ptr.ConvertToInternalSignature(pLoc->pSigModule, NULL, &sigBuilder);
1936
1937                     DWORD cbFnPtrSig;
1938                     PVOID pFnPtrSig = sigBuilder.GetSignature(&cbFnPtrSig);
1939
1940                     m_qbReturnSig.ReSizeThrows(m_qbReturnSig.Size() + cbFnPtrSig);
1941
1942                     memcpyNoGCRefs((BYTE *)m_qbReturnSig.Ptr() + m_qbReturnSig.Size() - cbFnPtrSig, pFnPtrSig, cbFnPtrSig);
1943                 }
1944                 break;
1945
1946             default: 
1947                 break;
1948         }
1949         
1950         i++;
1951     }
1952
1953     if (pLoc->ElementType[0] == ELEMENT_TYPE_ARRAY)
1954     {
1955         SIZE_T size = m_qbReturnSig.Size();
1956         m_qbReturnSig.ReSizeThrows(size + pLoc->cbArrayBoundsInfo);
1957         memcpyNoGCRefs((BYTE *)m_qbReturnSig.Ptr() + size, pLoc->pSig, pLoc->cbArrayBoundsInfo);
1958     }
1959 }
1960
1961 void FunctionSigBuilder::SetSig(PCCOR_SIGNATURE pSig, DWORD cSig)
1962 {
1963     STANDARD_VM_CONTRACT;
1964
1965     // parse the incoming signature
1966     SigPointer sigPtr(pSig, cSig);
1967
1968     // 1) calling convention
1969     ULONG callConv;
1970     IfFailThrow(sigPtr.GetCallingConvInfo(&callConv));
1971     SetCallingConv((CorCallingConvention)callConv);
1972
1973     // 2) number of parameters
1974     IfFailThrow(sigPtr.GetData(&m_nItems));
1975
1976     // 3) return type
1977     PCCOR_SIGNATURE ptr = sigPtr.GetPtr();
1978     IfFailThrow(sigPtr.SkipExactlyOne());
1979
1980     size_t retSigLength = sigPtr.GetPtr() - ptr;
1981
1982     m_qbReturnSig.ReSizeThrows(retSigLength);
1983     memcpyNoGCRefs(m_qbReturnSig.Ptr(), ptr, retSigLength);
1984
1985     // 4) parameters
1986     m_cbSig = 0;
1987
1988     size_t cbSigLen = (cSig - (sigPtr.GetPtr() - pSig));
1989
1990     m_pbSigCursor = (BYTE *)m_qbSigBuffer.Ptr();
1991     EnsureEnoughQuickBytes(cbSigLen);
1992
1993     memcpyNoGCRefs(m_pbSigCursor, sigPtr.GetPtr(), cbSigLen);
1994
1995     m_cbSig = cbSigLen;
1996     m_pbSigCursor += cbSigLen;
1997 }
1998
1999 //---------------------------------------------------------------------------------------
2000 // 
2001 DWORD 
2002 FunctionSigBuilder::GetSigSize()
2003 {
2004     STANDARD_VM_CONTRACT;
2005
2006     BYTE   temp[4];
2007     DWORD  cbEncodedLen     = CorSigCompressData(m_nItems, temp);
2008     SIZE_T cbEncodedRetType = m_qbReturnSig.Size();
2009
2010     CONSISTENCY_CHECK(cbEncodedRetType > 0);
2011
2012     S_UINT32 cbSigSize = 
2013         S_UINT32(1) +                   // calling convention
2014         S_UINT32(cbEncodedLen) +        // encoded number of args
2015         S_UINT32(cbEncodedRetType) +    // encoded return type
2016         S_UINT32(m_cbSig) +             // types
2017         S_UINT32(1);                    // ELEMENT_TYPE_END
2018     if (cbSigSize.IsOverflow())
2019     {
2020         IfFailThrow(COR_E_OVERFLOW);
2021     }
2022     return cbSigSize.Value();
2023 }
2024
2025 //---------------------------------------------------------------------------------------
2026 // 
2027 DWORD 
2028 FunctionSigBuilder::GetSig(
2029     BYTE * pbLocalSig, 
2030     DWORD  cbBuffer)
2031 {
2032     STANDARD_VM_CONTRACT;
2033     BYTE    tempLen[4];
2034     size_t  cbEncodedLen     = CorSigCompressData(m_nItems, tempLen);
2035     size_t  cbEncodedRetType = m_qbReturnSig.Size();
2036
2037     CONSISTENCY_CHECK(cbEncodedRetType > 0);
2038
2039     _ASSERTE((1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1) == GetSigSize());
2040
2041     if ((1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1) <= cbBuffer)
2042     {
2043         BYTE* pbCursor = pbLocalSig;
2044         *pbCursor = static_cast<BYTE>(m_callingConv);
2045         pbCursor++;
2046
2047         memcpyNoGCRefs(pbCursor, tempLen, cbEncodedLen);
2048         pbCursor += cbEncodedLen;
2049
2050         memcpyNoGCRefs(pbCursor, m_qbReturnSig.Ptr(), m_qbReturnSig.Size());
2051         pbCursor += m_qbReturnSig.Size();
2052
2053         memcpyNoGCRefs(pbCursor, m_qbSigBuffer.Ptr(), m_cbSig);
2054         pbCursor += m_cbSig;
2055         pbCursor[0] = ELEMENT_TYPE_END;
2056         return (DWORD)(1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1);
2057     }
2058     else
2059     {
2060         return NULL;
2061     }
2062 }
2063
2064 DWORD ILStubLinker::NewLocal(LocalDesc loc)
2065 {
2066     WRAPPER_NO_CONTRACT;
2067
2068     return m_localSigBuilder.NewLocal(&loc);
2069 }
2070
2071 //---------------------------------------------------------------------------------------
2072 // 
2073 DWORD 
2074 ILStubLinker::GetLocalSigSize()
2075 {
2076     LIMITED_METHOD_CONTRACT;
2077
2078     return m_localSigBuilder.GetSigSize();
2079 }
2080
2081 //---------------------------------------------------------------------------------------
2082 // 
2083 DWORD 
2084 ILStubLinker::GetLocalSig(
2085     BYTE * pbLocalSig, 
2086     DWORD  cbBuffer)
2087 {
2088     STANDARD_VM_CONTRACT;
2089
2090     DWORD dwRet = m_localSigBuilder.GetSig(pbLocalSig, cbBuffer);
2091     return dwRet;
2092 }
2093
2094 //---------------------------------------------------------------------------------------
2095 // 
2096 DWORD 
2097 ILStubLinker::GetStubTargetMethodSigSize()
2098 {
2099     STANDARD_VM_CONTRACT;
2100
2101     return m_nativeFnSigBuilder.GetSigSize();
2102 }
2103
2104 //---------------------------------------------------------------------------------------
2105 // 
2106 DWORD 
2107 ILStubLinker::GetStubTargetMethodSig(
2108     BYTE * pbSig, 
2109     DWORD  cbSig)
2110 {
2111     LIMITED_METHOD_CONTRACT;
2112
2113     DWORD dwRet = m_nativeFnSigBuilder.GetSig(pbSig, cbSig);
2114     return dwRet;
2115 }
2116
2117 void ILStubLinker::SetStubTargetMethodSig(PCCOR_SIGNATURE pSig, DWORD cSig)
2118 {
2119     STANDARD_VM_CONTRACT;
2120
2121     m_nativeFnSigBuilder.SetSig(pSig, cSig);
2122 }
2123
2124 static BOOL SigHasVoidReturnType(const Signature &signature)
2125 {
2126     CONTRACTL
2127     {
2128         THROWS;
2129         GC_NOTRIGGER;
2130     }
2131     CONTRACTL_END
2132     
2133     SigPointer ptr = signature.CreateSigPointer();
2134
2135     ULONG data;
2136     IfFailThrow(ptr.GetCallingConvInfo(&data));
2137     // Skip number of type arguments
2138     if (data & IMAGE_CEE_CS_CALLCONV_GENERIC)
2139     {
2140         IfFailThrow(ptr.GetData(NULL));
2141     }
2142
2143     // skip number of args
2144     IfFailThrow(ptr.GetData(NULL));
2145     
2146     CorElementType retType;
2147     IfFailThrow(ptr.PeekElemType(&retType));
2148
2149     return (ELEMENT_TYPE_VOID == retType);
2150 }
2151
2152
2153 ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, SigTypeContext *pTypeContext, MethodDesc *pMD,
2154                            BOOL fTargetHasThis, BOOL fStubHasThis, BOOL fIsNDirectStub, BOOL fIsReverseStub) :
2155     m_pCodeStreamList(NULL),
2156     m_stubSig(signature),
2157     m_pTypeContext(pTypeContext),
2158     m_pCode(NULL),
2159     m_pStubSigModule(pStubSigModule),
2160     m_pLabelList(NULL),
2161     m_StubHasVoidReturnType(FALSE),
2162     m_fIsReverseStub(fIsReverseStub),
2163     m_iTargetStackDelta(0),
2164     m_cbCurrentCompressedSigLen(1),
2165     m_nLocals(0),
2166     m_fHasThis(false),
2167     m_pMD(pMD)
2168 {
2169     CONTRACTL
2170     {
2171         THROWS;
2172         GC_TRIGGERS;
2173         INJECT_FAULT(COMPlusThrowOM());
2174     }
2175     CONTRACTL_END
2176
2177     m_managedSigPtr = signature.CreateSigPointer();
2178     if (!signature.IsEmpty())
2179     {
2180         // Until told otherwise, assume that the stub has the same return type as the signature.
2181         m_StubHasVoidReturnType = SigHasVoidReturnType(signature);
2182         m_StubTargetHasVoidReturnType = m_StubHasVoidReturnType;
2183         
2184         //
2185         // Get the stub's calling convention.  Set m_fHasThis to match
2186         // IMAGE_CEE_CS_CALLCONV_HASTHIS.
2187         //
2188
2189         ULONG   uStubCallingConvInfo;
2190         IfFailThrow(m_managedSigPtr.GetCallingConvInfo(&uStubCallingConvInfo));
2191
2192         if (fStubHasThis)
2193         {
2194             m_fHasThis = true;
2195         }
2196
2197         //
2198         // If target calling convention was specified, use it instead.
2199         // Otherwise, derive one based on the stub's signature.
2200         //
2201
2202         ULONG   uCallingConvInfo = uStubCallingConvInfo;
2203
2204         ULONG   uCallingConv    = (uCallingConvInfo & IMAGE_CEE_CS_CALLCONV_MASK);
2205         ULONG   uNativeCallingConv;
2206
2207         if (IMAGE_CEE_CS_CALLCONV_VARARG == uCallingConv)
2208         {
2209             //
2210             // If we have a PInvoke stub that has a VARARG calling convention
2211             // we will transition to a NATIVEVARARG calling convention for the 
2212             // target call. The JIT64 knows about this calling convention,
2213             // basically it is the same as the managed vararg calling convention 
2214             // except without a VASigCookie.        
2215             //
2216             // If our stub is not a PInvoke stub and has a vararg calling convention, 
2217             // we are most likely going to have to forward those variable arguments 
2218             // on to our call target.  Unfortunately, callsites to varargs methods 
2219             // in IL always have full signatures (that's where the VASigCookie comes 
2220             // from). But we don't have that in this case, so we play some tricks and 
2221             // pass an ArgIterator down to an assembly routine that pulls out the
2222             // variable arguments and puts them in the right spot before forwarding
2223             // to the stub target.
2224             //
2225             // The net result is that we don't want to set the native calling 
2226             // convention to be vararg for non-PInvoke stubs, so we just use 
2227             // the default callconv.
2228             //
2229             if (!fIsNDirectStub)
2230                 uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_DEFAULT;
2231             else
2232                 uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_NATIVEVARARG;
2233         }
2234         else
2235         {
2236             uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_DEFAULT;
2237         }
2238
2239         if (fTargetHasThis && !fIsNDirectStub)
2240         {
2241             // ndirect native sig never has a 'this' pointer
2242             uNativeCallingConv |= IMAGE_CEE_CS_CALLCONV_HASTHIS;
2243         }
2244
2245         if (fTargetHasThis)
2246         {
2247             m_iTargetStackDelta--;
2248         }
2249
2250         m_nativeFnSigBuilder.SetCallingConv((CorCallingConvention)uNativeCallingConv);
2251
2252         if (uStubCallingConvInfo & IMAGE_CEE_CS_CALLCONV_GENERIC)
2253             IfFailThrow(m_managedSigPtr.GetData(NULL));    // skip number of type parameters
2254
2255         IfFailThrow(m_managedSigPtr.GetData(NULL));        // skip number of parameters
2256         IfFailThrow(m_managedSigPtr.SkipExactlyOne()); // skip return type
2257     }
2258 }
2259
2260 ILStubLinker::~ILStubLinker()
2261 {
2262     CONTRACTL
2263     {
2264         NOTHROW;
2265         GC_TRIGGERS;
2266         MODE_ANY;
2267     }
2268     CONTRACTL_END;
2269     DeleteCodeLabels();
2270     DeleteCodeStreams();
2271 }
2272
2273 void ILStubLinker::DeleteCodeLabels()
2274 {
2275     CONTRACTL
2276     {
2277         NOTHROW;
2278         MODE_ANY;
2279         GC_TRIGGERS;
2280     }
2281     CONTRACTL_END;
2282     
2283     //
2284     // walk the list of labels and free each one
2285     //
2286     ILCodeLabel* pCurrent = m_pLabelList;
2287     while (pCurrent)
2288     {
2289         ILCodeLabel* pDeleteMe = pCurrent;
2290         pCurrent = pCurrent->m_pNext;
2291         delete pDeleteMe;
2292     }
2293     m_pLabelList = NULL;
2294 }
2295
2296 void ILStubLinker::DeleteCodeStreams()
2297 {
2298     CONTRACTL
2299     {
2300         NOTHROW;
2301         MODE_ANY;
2302         GC_TRIGGERS;
2303     }
2304     CONTRACTL_END;
2305
2306     ILCodeStream* pCurrent = m_pCodeStreamList;
2307     while (pCurrent)
2308     {
2309         ILCodeStream* pDeleteMe = pCurrent;
2310         pCurrent = pCurrent->m_pNextStream;
2311         delete pDeleteMe;
2312     }
2313     m_pCodeStreamList = NULL;
2314 }
2315
2316 void ILStubLinker::ClearCodeStreams()
2317 {
2318     CONTRACTL
2319     {
2320         NOTHROW;
2321         MODE_ANY;
2322         GC_TRIGGERS;
2323     }
2324     CONTRACTL_END;
2325     
2326     ILCodeStream* pCurrent = m_pCodeStreamList;
2327     while (pCurrent)
2328     {
2329         pCurrent->ClearCode();
2330         pCurrent = pCurrent->m_pNextStream;
2331     }
2332 }
2333
2334 void ILStubLinker::GetStubReturnType(LocalDesc* pLoc)
2335 {
2336     WRAPPER_NO_CONTRACT;
2337
2338     GetStubReturnType(pLoc, m_pStubSigModule);
2339 }
2340
2341 void ILStubLinker::GetStubReturnType(LocalDesc* pLoc, Module* pModule)
2342 {
2343     STANDARD_VM_CONTRACT;
2344     SigPointer ptr = m_stubSig.CreateSigPointer();
2345     ULONG uCallingConv;
2346     int   nTypeArgs = 0;
2347     int   nArgs;
2348     
2349     IfFailThrow(ptr.GetCallingConvInfo(&uCallingConv));
2350     
2351     if (uCallingConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
2352         IfFailThrow(ptr.GetData((ULONG*)&nTypeArgs));
2353
2354     IfFailThrow(ptr.GetData((ULONG*)&nArgs));
2355
2356     GetManagedTypeHelper(pLoc, pModule, ptr.GetPtr(), m_pTypeContext, m_pMD);
2357 }
2358
2359 CorCallingConvention ILStubLinker::GetStubTargetCallingConv()
2360 {
2361     LIMITED_METHOD_CONTRACT;
2362     return m_nativeFnSigBuilder.GetCallingConv();
2363 }
2364
2365 void ILStubLinker::TransformArgForJIT(LocalDesc *pLoc)
2366 {
2367     STANDARD_VM_CONTRACT;
2368     // Turn everything into blittable primitives. The reason this method is needed are
2369     // byrefs which are OK only when they ref stack data or are pinned. This condition
2370     // cannot be verified by code:NDirect.MarshalingRequired so we explicitly get rid
2371     // of them here. 
2372     switch (pLoc->ElementType[0])
2373     {
2374         // primitives
2375         case ELEMENT_TYPE_VOID:
2376         case ELEMENT_TYPE_BOOLEAN:
2377         case ELEMENT_TYPE_CHAR:
2378         case ELEMENT_TYPE_I1:
2379         case ELEMENT_TYPE_U1:
2380         case ELEMENT_TYPE_I2:
2381         case ELEMENT_TYPE_U2:
2382         case ELEMENT_TYPE_I4:
2383         case ELEMENT_TYPE_U4:
2384         case ELEMENT_TYPE_I8:
2385         case ELEMENT_TYPE_U8:
2386         case ELEMENT_TYPE_R4:
2387         case ELEMENT_TYPE_R8:
2388         case ELEMENT_TYPE_I:
2389         case ELEMENT_TYPE_U:
2390         {
2391             // no transformation needed
2392             break;
2393         }
2394
2395         case ELEMENT_TYPE_VALUETYPE:
2396         {
2397             _ASSERTE(!"Should have been replaced by a native value type!");
2398             break;
2399         }
2400
2401         case ELEMENT_TYPE_PTR:
2402         {
2403 #ifdef _TARGET_X86_
2404             if (pLoc->bIsCopyConstructed)
2405             {
2406                 // The only pointers that we don't transform to ELEMENT_TYPE_I are those that are
2407                 // ET_TYPE_CMOD_REQD<IsCopyConstructed>/ET_TYPE_CMOD_REQD<NeedsCopyConstructorModifier>
2408                 // in the original signature. This convention is understood by the UM thunk compiler
2409                 // (code:UMThunkMarshInfo.CompileNExportThunk) which will generate different thunk code.
2410                 // Such parameters come from unmanaged by value but must enter the IL stub by reference
2411                 // because we are not supposed to make a copy.
2412             }
2413             else
2414 #endif // _TARGET_X86_
2415             {
2416                 pLoc->ElementType[0] = ELEMENT_TYPE_I;
2417                 pLoc->cbType = 1;
2418             }
2419             break;
2420         }
2421
2422         case ELEMENT_TYPE_INTERNAL:
2423         {
2424             // JIT will handle structures
2425             if (pLoc->InternalToken.IsValueType())
2426             {
2427                 _ASSERTE(pLoc->InternalToken.IsBlittable());
2428                 break;
2429             }
2430             // intentional fall-thru
2431         }
2432
2433         // pointers, byrefs, strings, arrays, other ref types -> ELEMENT_TYPE_I
2434         default:
2435         {
2436             pLoc->ElementType[0] = ELEMENT_TYPE_I;
2437             pLoc->cbType = 1;
2438             break;
2439         }
2440     }
2441 }
2442
2443 Module *ILStubLinker::GetStubSigModule()
2444 {
2445     LIMITED_METHOD_CONTRACT;
2446     return m_pStubSigModule;
2447 }
2448
2449 SigTypeContext *ILStubLinker::GetStubSigTypeContext()
2450 {
2451     LIMITED_METHOD_CONTRACT;
2452     return m_pTypeContext;
2453 }
2454
2455 void ILStubLinker::SetStubTargetReturnType(CorElementType typ)
2456 {
2457     WRAPPER_NO_CONTRACT;
2458
2459     LocalDesc locDesc(typ);
2460     SetStubTargetReturnType(&locDesc);
2461 }
2462
2463 void ILStubLinker::SetStubTargetReturnType(LocalDesc* pLoc)
2464 {
2465     CONTRACTL
2466     {
2467         WRAPPER(NOTHROW);
2468         WRAPPER(GC_NOTRIGGER);
2469         WRAPPER(MODE_ANY);
2470         PRECONDITION(CheckPointer(pLoc, NULL_NOT_OK));
2471     }
2472     CONTRACTL_END;
2473     
2474     TransformArgForJIT(pLoc);
2475
2476     m_nativeFnSigBuilder.SetReturnType(pLoc);
2477
2478     // Update check for if a stub has a void return type based on the provided return type.
2479     m_StubTargetHasVoidReturnType = ((1 == pLoc->cbType) && (ELEMENT_TYPE_VOID == pLoc->ElementType[0])) ? TRUE : FALSE;
2480     if (!m_StubTargetHasVoidReturnType)
2481     {
2482         m_iTargetStackDelta++;
2483     }
2484
2485 }
2486
2487 DWORD ILStubLinker::SetStubTargetArgType(CorElementType typ, bool fConsumeStubArg /*= true*/)
2488 {
2489     STANDARD_VM_CONTRACT;
2490
2491     LocalDesc locDesc(typ);
2492     return SetStubTargetArgType(&locDesc, fConsumeStubArg);
2493 }
2494
2495 void ILStubLinker::SetStubTargetCallingConv(CorCallingConvention uNativeCallingConv)
2496 {
2497     LIMITED_METHOD_CONTRACT;
2498     m_nativeFnSigBuilder.SetCallingConv(uNativeCallingConv);
2499 }
2500
2501 static size_t GetManagedTypeForMDArray(LocalDesc* pLoc, Module* pModule, PCCOR_SIGNATURE psigManagedArg, SigTypeContext *pTypeContext)
2502 {
2503     CONTRACTL
2504     {
2505         STANDARD_VM_CHECK;
2506
2507         PRECONDITION(CheckPointer(pLoc));
2508         PRECONDITION(CheckPointer(pModule));
2509         PRECONDITION(CheckPointer(psigManagedArg));
2510         PRECONDITION(*psigManagedArg == ELEMENT_TYPE_ARRAY);
2511     }
2512     CONTRACTL_END;
2513     
2514     SigPointer      ptr;
2515     size_t          cbDest = 0;
2516     
2517     //
2518     // copy ELEMENT_TYPE_ARRAY
2519     //
2520     pLoc->ElementType[cbDest] = *psigManagedArg;
2521     psigManagedArg++;
2522     cbDest++;
2523
2524     ptr.SetSig(psigManagedArg);
2525
2526     IfFailThrow(ptr.SkipCustomModifiers());
2527
2528     psigManagedArg = ptr.GetPtr();
2529
2530     //
2531     // get array type
2532     //
2533     pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
2534
2535     pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2536     cbDest++;
2537
2538     //
2539     // get array bounds
2540     //
2541
2542     size_t          cbType;
2543     PCCOR_SIGNATURE psigNextManagedArg;
2544
2545     // find the start of the next argument
2546     ptr.SetSig(psigManagedArg - 1);     // -1 to back up to E_T_ARRAY;
2547     IfFailThrow(ptr.SkipExactlyOne());
2548
2549     psigNextManagedArg  = ptr.GetPtr();
2550
2551     // find the start of the array bounds information
2552     ptr.SetSig(psigManagedArg);
2553     IfFailThrow(ptr.SkipExactlyOne());
2554
2555     psigManagedArg = ptr.GetPtr();  // point to the array bounds info
2556     cbType = psigNextManagedArg - psigManagedArg;
2557
2558     pLoc->pSig = psigManagedArg;        // point to the array bounds info
2559     pLoc->cbArrayBoundsInfo = cbType;   // size of array bounds info
2560     pLoc->cbType = cbDest;
2561
2562     return cbDest;
2563 }
2564
2565
2566 // static
2567 void ILStubLinker::GetManagedTypeHelper(LocalDesc* pLoc, Module* pModule, PCCOR_SIGNATURE psigManagedArg, SigTypeContext *pTypeContext, MethodDesc *pMD)
2568 {
2569     CONTRACTL
2570     {
2571         STANDARD_VM_CHECK;
2572
2573         PRECONDITION(CheckPointer(pLoc));
2574         PRECONDITION(CheckPointer(pModule));
2575         PRECONDITION(CheckPointer(psigManagedArg));
2576     }
2577     CONTRACTL_END;
2578
2579     SigPointer      ptr(psigManagedArg);
2580     CorElementType  eType;
2581     LOG((LF_STUBS, LL_INFO10000, "GetManagedTypeHelper on type at %p\n", psigManagedArg));
2582
2583     IfFailThrow(ptr.PeekElemType(&eType));
2584    
2585     size_t cbDest               = 0;
2586
2587     while (eType == ELEMENT_TYPE_PTR ||
2588            eType == ELEMENT_TYPE_BYREF ||
2589            eType == ELEMENT_TYPE_SZARRAY)
2590     {
2591         pLoc->ElementType[cbDest] = static_cast<BYTE>(eType);
2592         cbDest++;
2593
2594         if (cbDest >= LocalDesc::MAX_LOCALDESC_ELEMENTS)
2595         {
2596             COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
2597         }
2598
2599         IfFailThrow(ptr.GetElemType(NULL));
2600         IfFailThrow(ptr.PeekElemType(&eType));
2601     }
2602
2603     SigPointer ptr2(ptr);
2604     IfFailThrow(ptr2.SkipCustomModifiers());
2605     psigManagedArg = ptr2.GetPtr();
2606
2607     switch (eType)
2608     {
2609         case ELEMENT_TYPE_VAR:
2610         case ELEMENT_TYPE_MVAR:
2611             {
2612                 IfFailThrow(ptr.GetElemType(NULL)); // skip ET
2613                 ULONG varNum;
2614                 IfFailThrowBF(ptr.GetData(&varNum), BFA_BAD_COMPLUS_SIG, pModule);
2615
2616                 DWORD varCount = (eType == ELEMENT_TYPE_VAR ? pTypeContext->m_classInst.GetNumArgs() :
2617                                                               pTypeContext->m_methodInst.GetNumArgs());
2618                 THROW_BAD_FORMAT_MAYBE(varNum < varCount, BFA_BAD_COMPLUS_SIG, pModule);
2619
2620                 pLoc->InternalToken = (eType == ELEMENT_TYPE_VAR ? pTypeContext->m_classInst[varNum] :
2621                                                                    pTypeContext->m_methodInst[varNum]);
2622                 
2623                 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2624                 cbDest++;
2625                 break;
2626             }
2627
2628         case ELEMENT_TYPE_CLASS:
2629         case ELEMENT_TYPE_VALUETYPE:
2630         case ELEMENT_TYPE_INTERNAL:
2631             {
2632                 pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
2633                 
2634                 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2635                 cbDest++;
2636                 break;
2637             }
2638
2639         case ELEMENT_TYPE_GENERICINST:
2640             {
2641                 pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
2642
2643                 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2644                 cbDest++;
2645                 break;
2646             }
2647
2648         case ELEMENT_TYPE_FNPTR:
2649             // save off a pointer to the managed sig
2650             // we'll convert it in bulk when we store it
2651             // in the generated sig
2652             pLoc->pSigModule = pModule;
2653             pLoc->pSig       = psigManagedArg+1;
2654             
2655             pLoc->ElementType[cbDest] = ELEMENT_TYPE_FNPTR;
2656             cbDest++;
2657             break;
2658
2659         case ELEMENT_TYPE_ARRAY:
2660             cbDest = GetManagedTypeForMDArray(pLoc, pModule, psigManagedArg, pTypeContext);
2661             break;
2662
2663         default:
2664             {
2665                 size_t          cbType;
2666                 PCCOR_SIGNATURE psigNextManagedArg;
2667             
2668                 IfFailThrow(ptr.SkipExactlyOne());
2669             
2670                 psigNextManagedArg  = ptr.GetPtr();
2671                 cbType              = psigNextManagedArg - psigManagedArg;
2672             
2673                 size_t cbNewDest;
2674                 if (!ClrSafeInt<size_t>::addition(cbDest, cbType, cbNewDest) ||
2675                     cbNewDest > LocalDesc::MAX_LOCALDESC_ELEMENTS)
2676                 {
2677                     COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
2678                 }
2679             
2680                 memcpyNoGCRefs(&pLoc->ElementType[cbDest], psigManagedArg, cbType);
2681                 cbDest = cbNewDest;
2682                 break;
2683             }
2684     }
2685
2686     if (cbDest > LocalDesc::MAX_LOCALDESC_ELEMENTS)
2687     {
2688         COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
2689     }
2690
2691     pLoc->cbType = cbDest;
2692 }
2693
2694 void ILStubLinker::GetStubTargetReturnType(LocalDesc* pLoc)
2695 {
2696     CONTRACTL
2697     {
2698         STANDARD_VM_CHECK;
2699         PRECONDITION(CheckPointer(pLoc));
2700     }
2701     CONTRACTL_END;
2702
2703     GetStubTargetReturnType(pLoc, m_pStubSigModule);
2704 }
2705
2706 void ILStubLinker::GetStubTargetReturnType(LocalDesc* pLoc, Module* pModule)
2707 {
2708     CONTRACTL
2709     {
2710         STANDARD_VM_CHECK;
2711         PRECONDITION(CheckPointer(pLoc));
2712         PRECONDITION(CheckPointer(pModule));
2713     }
2714     CONTRACTL_END;
2715
2716     GetManagedTypeHelper(pLoc, pModule, m_nativeFnSigBuilder.GetReturnSig(), m_pTypeContext, NULL);
2717 }
2718
2719 void ILStubLinker::GetStubArgType(LocalDesc* pLoc)
2720 {
2721
2722     CONTRACTL
2723     {
2724         STANDARD_VM_CHECK;
2725         PRECONDITION(CheckPointer(pLoc));
2726     }
2727     CONTRACTL_END;
2728
2729     GetStubArgType(pLoc, m_pStubSigModule);
2730 }
2731
2732 void ILStubLinker::GetStubArgType(LocalDesc* pLoc, Module* pModule)
2733 {
2734
2735     CONTRACTL
2736     {
2737         STANDARD_VM_CHECK;
2738         PRECONDITION(CheckPointer(pLoc));
2739         PRECONDITION(CheckPointer(pModule));
2740     }
2741     CONTRACTL_END;
2742
2743     GetManagedTypeHelper(pLoc, pModule, m_managedSigPtr.GetPtr(), m_pTypeContext, m_pMD);
2744 }
2745
2746 //---------------------------------------------------------------------------------------
2747 // 
2748 DWORD 
2749 ILStubLinker::SetStubTargetArgType(
2750     LocalDesc * pLoc,            // = NULL
2751     bool        fConsumeStubArg) // = true
2752 {
2753     STANDARD_VM_CONTRACT;
2754
2755     LocalDesc locDesc;
2756
2757     if (fConsumeStubArg)
2758     {
2759         _ASSERTE(m_pStubSigModule);
2760
2761         if (pLoc == NULL)
2762         {
2763             pLoc = &locDesc;
2764             GetStubArgType(pLoc, m_pStubSigModule);
2765         }
2766         
2767         IfFailThrow(m_managedSigPtr.SkipExactlyOne());
2768     }
2769
2770     TransformArgForJIT(pLoc);
2771
2772     DWORD dwArgNum = m_nativeFnSigBuilder.NewArg(pLoc);
2773     m_iTargetStackDelta--;
2774
2775     return dwArgNum;
2776 } // ILStubLinker::SetStubTargetArgType
2777
2778 //---------------------------------------------------------------------------------------
2779 // 
2780 int ILStubLinker::GetToken(MethodDesc* pMD)
2781 {
2782     STANDARD_VM_CONTRACT;
2783     return m_tokenMap.GetToken(pMD);
2784 }
2785
2786 int ILStubLinker::GetToken(MethodTable* pMT)
2787 {
2788     STANDARD_VM_CONTRACT;
2789     return m_tokenMap.GetToken(TypeHandle(pMT));
2790 }
2791
2792 int ILStubLinker::GetToken(TypeHandle th)
2793 {
2794     STANDARD_VM_CONTRACT;
2795     return m_tokenMap.GetToken(th);
2796 }
2797
2798 int ILStubLinker::GetToken(FieldDesc* pFD)
2799 {
2800     STANDARD_VM_CONTRACT;
2801     return m_tokenMap.GetToken(pFD);
2802 }
2803
2804
2805 BOOL ILStubLinker::StubHasVoidReturnType()
2806 {
2807     LIMITED_METHOD_CONTRACT;
2808     return m_StubHasVoidReturnType;
2809 }
2810
2811 void ILStubLinker::ClearCode()
2812 {
2813     CONTRACTL
2814     {
2815         NOTHROW;
2816         MODE_ANY;
2817         GC_TRIGGERS;
2818     }
2819     CONTRACTL_END;
2820
2821     DeleteCodeLabels();
2822     ClearCodeStreams();
2823 }
2824
2825 // static
2826 ILCodeStream* ILStubLinker::FindLastCodeStream(ILCodeStream* pList)
2827 {
2828     LIMITED_METHOD_CONTRACT;
2829
2830     if (NULL == pList)
2831     {
2832         return NULL;
2833     }
2834
2835     while (NULL != pList->m_pNextStream)
2836     {
2837         pList = pList->m_pNextStream;
2838     }
2839
2840     return pList;
2841 }
2842
2843 ILCodeStream* ILStubLinker::NewCodeStream(CodeStreamType codeStreamType)
2844 {
2845     STANDARD_VM_CONTRACT;
2846     
2847     NewHolder<ILCodeStream> pNewCodeStream = new ILCodeStream(this, codeStreamType);
2848
2849     if (NULL == m_pCodeStreamList)
2850     {
2851         m_pCodeStreamList = pNewCodeStream;
2852     }
2853     else
2854     {
2855         ILCodeStream* pTail = FindLastCodeStream(m_pCodeStreamList);
2856         CONSISTENCY_CHECK(NULL == pTail->m_pNextStream);
2857         pTail->m_pNextStream = pNewCodeStream;
2858     }
2859     
2860     pNewCodeStream.SuppressRelease();
2861     return pNewCodeStream;
2862 }
2863
2864 int ILCodeStream::GetToken(MethodDesc* pMD)
2865
2866     STANDARD_VM_CONTRACT;
2867     return m_pOwner->GetToken(pMD);
2868
2869 int ILCodeStream::GetToken(MethodTable* pMT)
2870
2871     STANDARD_VM_CONTRACT;
2872     return m_pOwner->GetToken(pMT);
2873
2874 int ILCodeStream::GetToken(TypeHandle th)
2875
2876     STANDARD_VM_CONTRACT;
2877     return m_pOwner->GetToken(th);
2878
2879 int ILCodeStream::GetToken(FieldDesc* pFD)
2880
2881     STANDARD_VM_CONTRACT;
2882     return m_pOwner->GetToken(pFD);
2883
2884
2885 DWORD ILCodeStream::NewLocal(CorElementType typ)
2886 {
2887     STANDARD_VM_CONTRACT;
2888     return m_pOwner->NewLocal(typ);
2889 }
2890 DWORD ILCodeStream::NewLocal(LocalDesc loc)
2891 {
2892     WRAPPER_NO_CONTRACT;
2893     return m_pOwner->NewLocal(loc);
2894 }
2895 DWORD ILCodeStream::SetStubTargetArgType(CorElementType typ, bool fConsumeStubArg)
2896 {
2897     STANDARD_VM_CONTRACT;
2898     return m_pOwner->SetStubTargetArgType(typ, fConsumeStubArg);
2899 }
2900 DWORD ILCodeStream::SetStubTargetArgType(LocalDesc* pLoc, bool fConsumeStubArg)
2901 {
2902     STANDARD_VM_CONTRACT;
2903     return m_pOwner->SetStubTargetArgType(pLoc, fConsumeStubArg);
2904 }
2905 void ILCodeStream::SetStubTargetReturnType(CorElementType typ)
2906 {
2907     STANDARD_VM_CONTRACT;
2908     m_pOwner->SetStubTargetReturnType(typ);
2909 }
2910 void ILCodeStream::SetStubTargetReturnType(LocalDesc* pLoc)
2911 {
2912     STANDARD_VM_CONTRACT;
2913     m_pOwner->SetStubTargetReturnType(pLoc);
2914 }
2915 ILCodeLabel* ILCodeStream::NewCodeLabel()
2916 {
2917     STANDARD_VM_CONTRACT;
2918     return m_pOwner->NewCodeLabel();
2919 }
2920 void ILCodeStream::ClearCode()
2921 {
2922     LIMITED_METHOD_CONTRACT;
2923     m_uCurInstrIdx = 0;
2924 }