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
28void 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
61void 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
135void 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
159ILCodeLabel* 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
175void 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
190static 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
237struct ILOpcode
238{
239 BYTE byte1;
240 BYTE byte2;
241};
242
243static 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
253ILCodeStream::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
322lShortForm:
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
359void 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
379ILCodeLabel::ILCodeLabel()
380{
381 m_pNext = NULL;
382 m_pOwningStubLinker = NULL;
383 m_pCodeStreamOfLabel = NULL;
384 m_codeOffset = -1;
385 m_idxLabeledInstruction = -1;
386}
387
388ILCodeLabel::~ILCodeLabel()
389{
390}
391
392size_t ILCodeLabel::GetCodeOffset()
393{
394 LIMITED_METHOD_CONTRACT;
395
396 CONSISTENCY_CHECK(m_codeOffset != (size_t)-1);
397 return m_codeOffset;
398}
399
400
401void 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
409static 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
420static 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//
433void
434ILStubLinker::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//
575void
576ILStubLinker::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
634static 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
663void 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
701bool 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
756void 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
783size_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
846static 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
859BYTE* 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
933void 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
956bool 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
975bool 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
985LPCSTR 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
1008void ILCodeStream::EmitADD()
1009{
1010 WRAPPER_NO_CONTRACT;
1011 Emit(CEE_ADD, -1, 0);
1012}
1013void ILCodeStream::EmitADD_OVF()
1014{
1015 WRAPPER_NO_CONTRACT;
1016 Emit(CEE_ADD_OVF, -1, 0);
1017}
1018void ILCodeStream::EmitAND()
1019{
1020 WRAPPER_NO_CONTRACT;
1021 Emit(CEE_AND, -1, 0);
1022}
1023void ILCodeStream::EmitARGLIST()
1024{
1025 WRAPPER_NO_CONTRACT;
1026 Emit(CEE_ARGLIST, 1, 0);
1027}
1028
1029void ILCodeStream::EmitBEQ(ILCodeLabel* pCodeLabel)
1030{
1031 WRAPPER_NO_CONTRACT;
1032 Emit(CEE_BEQ, -2, (UINT_PTR)pCodeLabel);
1033}
1034
1035void ILCodeStream::EmitBGE(ILCodeLabel* pCodeLabel)
1036{
1037 WRAPPER_NO_CONTRACT;
1038 Emit(CEE_BGE, -2, (UINT_PTR)pCodeLabel);
1039}
1040
1041void ILCodeStream::EmitBGE_UN(ILCodeLabel* pCodeLabel)
1042{
1043 WRAPPER_NO_CONTRACT;
1044 Emit(CEE_BGE_UN, -2, (UINT_PTR)pCodeLabel);
1045}
1046
1047void ILCodeStream::EmitBGT(ILCodeLabel* pCodeLabel)
1048{
1049 WRAPPER_NO_CONTRACT;
1050 Emit(CEE_BGT, -2, (UINT_PTR)pCodeLabel);
1051}
1052void ILCodeStream::EmitBLE(ILCodeLabel* pCodeLabel)
1053{
1054 WRAPPER_NO_CONTRACT;
1055 Emit(CEE_BLE, -2, (UINT_PTR)pCodeLabel);
1056}
1057void ILCodeStream::EmitBLE_UN(ILCodeLabel* pCodeLabel)
1058{
1059 WRAPPER_NO_CONTRACT;
1060 Emit(CEE_BLE_UN, -2, (UINT_PTR)pCodeLabel);
1061}
1062void ILCodeStream::EmitBLT(ILCodeLabel* pCodeLabel)
1063{
1064 WRAPPER_NO_CONTRACT;
1065 Emit(CEE_BLT, -2, (UINT_PTR)pCodeLabel);
1066}
1067void ILCodeStream::EmitBR(ILCodeLabel* pCodeLabel)
1068{
1069 WRAPPER_NO_CONTRACT;
1070 Emit(CEE_BR, 0, (UINT_PTR)pCodeLabel);
1071}
1072void ILCodeStream::EmitBREAK()
1073{
1074 WRAPPER_NO_CONTRACT;
1075 Emit(CEE_BREAK, 0, 0);
1076}
1077void ILCodeStream::EmitBRFALSE(ILCodeLabel* pCodeLabel)
1078{
1079 WRAPPER_NO_CONTRACT;
1080 Emit(CEE_BRFALSE, -1, (UINT_PTR)pCodeLabel);
1081}
1082void ILCodeStream::EmitBRTRUE(ILCodeLabel* pCodeLabel)
1083{
1084 WRAPPER_NO_CONTRACT;
1085 Emit(CEE_BRTRUE, -1, (UINT_PTR)pCodeLabel);
1086}
1087void ILCodeStream::EmitCALL(int token, int numInArgs, int numRetArgs)
1088{
1089 WRAPPER_NO_CONTRACT;
1090 Emit(CEE_CALL, (INT16)(numRetArgs - numInArgs), token);
1091}
1092void ILCodeStream::EmitCALLI(int token, int numInArgs, int numRetArgs)
1093{
1094 WRAPPER_NO_CONTRACT;
1095 Emit(CEE_CALLI, (INT16)(numRetArgs - numInArgs - 1), token);
1096}
1097void ILCodeStream::EmitCEQ ()
1098{
1099 WRAPPER_NO_CONTRACT;
1100 Emit(CEE_CEQ, -1, 0);
1101}
1102void ILCodeStream::EmitCGT()
1103{
1104 WRAPPER_NO_CONTRACT;
1105 Emit(CEE_CGT, -1, 0);
1106}
1107void ILCodeStream::EmitCGT_UN()
1108{
1109 WRAPPER_NO_CONTRACT;
1110 Emit(CEE_CGT_UN, -1, 0);
1111}
1112void ILCodeStream::EmitCLT()
1113{
1114 WRAPPER_NO_CONTRACT;
1115 Emit(CEE_CLT, -1, 0);
1116}
1117void ILCodeStream::EmitCLT_UN()
1118{
1119 WRAPPER_NO_CONTRACT;
1120 Emit(CEE_CLT_UN, -1, 0);
1121}
1122void ILCodeStream::EmitCONV_I()
1123{
1124 WRAPPER_NO_CONTRACT;
1125 Emit(CEE_CONV_I, 0, 0);
1126}
1127void ILCodeStream::EmitCONV_I1()
1128{
1129 WRAPPER_NO_CONTRACT;
1130 Emit(CEE_CONV_I1, 0, 0);
1131}
1132void ILCodeStream::EmitCONV_I2()
1133{
1134 WRAPPER_NO_CONTRACT;
1135 Emit(CEE_CONV_I2, 0, 0);
1136}
1137void ILCodeStream::EmitCONV_I4()
1138{
1139 WRAPPER_NO_CONTRACT;
1140 Emit(CEE_CONV_I4, 0, 0);
1141}
1142void ILCodeStream::EmitCONV_I8()
1143{
1144 WRAPPER_NO_CONTRACT;
1145 Emit(CEE_CONV_I8, 0, 0);
1146}
1147void ILCodeStream::EmitCONV_U()
1148{
1149 WRAPPER_NO_CONTRACT;
1150 Emit(CEE_CONV_U, 0, 0);
1151}
1152void ILCodeStream::EmitCONV_U1()
1153{
1154 WRAPPER_NO_CONTRACT;
1155 Emit(CEE_CONV_U1, 0, 0);
1156}
1157void ILCodeStream::EmitCONV_U2()
1158{
1159 WRAPPER_NO_CONTRACT;
1160 Emit(CEE_CONV_U2, 0, 0);
1161}
1162void ILCodeStream::EmitCONV_U4()
1163{
1164 WRAPPER_NO_CONTRACT;
1165 Emit(CEE_CONV_U4, 0, 0);
1166}
1167void ILCodeStream::EmitCONV_U8()
1168{
1169 WRAPPER_NO_CONTRACT;
1170 Emit(CEE_CONV_U8, 0, 0);
1171}
1172void ILCodeStream::EmitCONV_R4()
1173{
1174 WRAPPER_NO_CONTRACT;
1175 Emit(CEE_CONV_R4, 0, 0);
1176}
1177void ILCodeStream::EmitCONV_R8()
1178{
1179 WRAPPER_NO_CONTRACT;
1180 Emit(CEE_CONV_R8, 0, 0);
1181}
1182void ILCodeStream::EmitCONV_OVF_I4()
1183{
1184 WRAPPER_NO_CONTRACT;
1185 Emit(CEE_CONV_OVF_I4, 0, 0);
1186}
1187void 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}
1234void ILCodeStream::EmitCPBLK()
1235{
1236 WRAPPER_NO_CONTRACT;
1237 Emit(CEE_CPBLK, -3, 0);
1238}
1239void ILCodeStream::EmitCPOBJ(int token)
1240{
1241 WRAPPER_NO_CONTRACT;
1242 Emit(CEE_CPOBJ, -2, token);
1243}
1244void ILCodeStream::EmitDUP ()
1245{
1246 WRAPPER_NO_CONTRACT;
1247 Emit(CEE_DUP, 1, 0);
1248}
1249void ILCodeStream::EmitENDFINALLY()
1250{
1251 WRAPPER_NO_CONTRACT;
1252 Emit(CEE_ENDFINALLY, 0, 0);
1253}
1254void ILCodeStream::EmitINITBLK()
1255{
1256 WRAPPER_NO_CONTRACT;
1257 Emit(CEE_INITBLK, -3, 0);
1258}
1259void ILCodeStream::EmitINITOBJ(int token)
1260{
1261 WRAPPER_NO_CONTRACT;
1262 Emit(CEE_INITOBJ, -1, token);
1263}
1264void ILCodeStream::EmitJMP(int token)
1265{
1266 WRAPPER_NO_CONTRACT;
1267 Emit(CEE_JMP, 0, token);
1268}
1269void 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}
1279void 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}
1288void 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}
1299void ILCodeStream::EmitLDC_R4(UINT32 uConst)
1300{
1301 WRAPPER_NO_CONTRACT;
1302 Emit(CEE_LDC_R4, 1, uConst);
1303}
1304void 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}
1317void ILCodeStream::EmitLDELEM_REF()
1318{
1319 WRAPPER_NO_CONTRACT;
1320 Emit(CEE_LDELEM_REF, -1, 0);
1321}
1322void ILCodeStream::EmitLDFLD(int token)
1323{
1324 WRAPPER_NO_CONTRACT;
1325 Emit(CEE_LDFLD, 0, token);
1326}
1327void ILCodeStream::EmitLDFLDA(int token)
1328{
1329 WRAPPER_NO_CONTRACT;
1330 Emit(CEE_LDFLDA, 0, token);
1331}
1332void ILCodeStream::EmitLDFTN(int token)
1333{
1334 WRAPPER_NO_CONTRACT;
1335 Emit(CEE_LDFTN, 1, token);
1336}
1337void ILCodeStream::EmitLDIND_I()
1338{
1339 WRAPPER_NO_CONTRACT;
1340 Emit(CEE_LDIND_I, 0, 0);
1341}
1342void ILCodeStream::EmitLDIND_I1()
1343{
1344 WRAPPER_NO_CONTRACT;
1345 Emit(CEE_LDIND_I1, 0, 0);
1346}
1347void ILCodeStream::EmitLDIND_I2()
1348{
1349 WRAPPER_NO_CONTRACT;
1350 Emit(CEE_LDIND_I2, 0, 0);
1351}
1352void ILCodeStream::EmitLDIND_I4()
1353{
1354 WRAPPER_NO_CONTRACT;
1355 Emit(CEE_LDIND_I4, 0, 0);
1356}
1357void ILCodeStream::EmitLDIND_I8()
1358{
1359 WRAPPER_NO_CONTRACT;
1360 Emit(CEE_LDIND_I8, 0, 0);
1361}
1362void ILCodeStream::EmitLDIND_R4()
1363{
1364 WRAPPER_NO_CONTRACT;
1365 Emit(CEE_LDIND_R4, 0, 0);
1366}
1367void ILCodeStream::EmitLDIND_R8()
1368{
1369 WRAPPER_NO_CONTRACT;
1370 Emit(CEE_LDIND_R8, 0, 0);
1371}
1372void ILCodeStream::EmitLDIND_REF()
1373{
1374 WRAPPER_NO_CONTRACT;
1375 Emit(CEE_LDIND_REF, 0, 0);
1376}
1377void ILCodeStream::EmitLDIND_T(LocalDesc* pType)
1378{
1379 CONTRACTL
1380 {
1381 PRECONDITION(pType->cbType == 1);
1382 }
1383 CONTRACTL_END;
1384
1385 switch (pType->ElementType[0])
1386 {
1387 case ELEMENT_TYPE_I1: EmitLDIND_I1(); break;
1388 case ELEMENT_TYPE_BOOLEAN: // fall through
1389 case ELEMENT_TYPE_U1: EmitLDIND_U1(); break;
1390 case ELEMENT_TYPE_I2: EmitLDIND_I2(); break;
1391 case ELEMENT_TYPE_CHAR: // fall through
1392 case ELEMENT_TYPE_U2: EmitLDIND_U2(); break;
1393 case ELEMENT_TYPE_I4: EmitLDIND_I4(); break;
1394 case ELEMENT_TYPE_U4: EmitLDIND_U4(); break;
1395 case ELEMENT_TYPE_I8: EmitLDIND_I8(); break;
1396 case ELEMENT_TYPE_U8: EmitLDIND_I8(); break;
1397 case ELEMENT_TYPE_R4: EmitLDIND_R4(); break;
1398 case ELEMENT_TYPE_R8: EmitLDIND_R8(); break;
1399 case ELEMENT_TYPE_PTR: // same as ELEMENT_TYPE_I
1400 case ELEMENT_TYPE_FNPTR: // same as ELEMENT_TYPE_I
1401 case ELEMENT_TYPE_I: EmitLDIND_I(); break;
1402 case ELEMENT_TYPE_U: EmitLDIND_I(); break;
1403 case ELEMENT_TYPE_STRING: // fall through
1404 case ELEMENT_TYPE_CLASS: // fall through
1405 case ELEMENT_TYPE_ARRAY:
1406 case ELEMENT_TYPE_SZARRAY:
1407 case ELEMENT_TYPE_OBJECT: EmitLDIND_REF(); break;
1408
1409 case ELEMENT_TYPE_INTERNAL:
1410 {
1411 CONSISTENCY_CHECK_MSG(!(pType->InternalToken.GetMethodTable()->IsValueType()), "don't know how to handle value types here");
1412 EmitLDIND_REF();
1413 break;
1414 }
1415
1416 default:
1417 UNREACHABLE_MSG("unexpected type passed to EmitLDIND_T");
1418 break;
1419 }
1420}
1421void ILCodeStream::EmitLDIND_U1()
1422{
1423 WRAPPER_NO_CONTRACT;
1424 Emit(CEE_LDIND_U1, 0, 0);
1425}
1426void ILCodeStream::EmitLDIND_U2()
1427{
1428 WRAPPER_NO_CONTRACT;
1429 Emit(CEE_LDIND_U2, 0, 0);
1430}
1431void ILCodeStream::EmitLDIND_U4()
1432{
1433 WRAPPER_NO_CONTRACT;
1434 Emit(CEE_LDIND_U4, 0, 0);
1435}
1436void ILCodeStream::EmitLDLEN()
1437{
1438 WRAPPER_NO_CONTRACT;
1439 Emit(CEE_LDLEN, 0, 0);
1440}
1441void ILCodeStream::EmitLDLOC (DWORD dwLocalNum)
1442{
1443 STANDARD_VM_CONTRACT;
1444 CONSISTENCY_CHECK(dwLocalNum != (DWORD)-1);
1445 CONSISTENCY_CHECK(dwLocalNum != (WORD)-1);
1446 Emit(CEE_LDLOC, 1, dwLocalNum);
1447}
1448void ILCodeStream::EmitLDLOCA (DWORD dwLocalNum)
1449{
1450 WRAPPER_NO_CONTRACT;
1451 Emit(CEE_LDLOCA, 1, dwLocalNum);
1452}
1453void ILCodeStream::EmitLDNULL()
1454{
1455 WRAPPER_NO_CONTRACT;
1456 Emit(CEE_LDNULL, 1, 0);
1457}
1458void ILCodeStream::EmitLDOBJ (int token)
1459{
1460 WRAPPER_NO_CONTRACT;
1461 Emit(CEE_LDOBJ, 0, token);
1462}
1463void ILCodeStream::EmitLDSFLD(int token)
1464{
1465 WRAPPER_NO_CONTRACT;
1466 Emit(CEE_LDSFLD, 1, token);
1467}
1468void ILCodeStream::EmitLDSFLDA(int token)
1469{
1470 WRAPPER_NO_CONTRACT;
1471 Emit(CEE_LDSFLDA, 1, token);
1472}
1473void ILCodeStream::EmitLDTOKEN(int token)
1474{
1475 WRAPPER_NO_CONTRACT;
1476 Emit(CEE_LDTOKEN, 1, token);
1477}
1478void ILCodeStream::EmitLEAVE(ILCodeLabel* pCodeLabel)
1479{
1480 WRAPPER_NO_CONTRACT;
1481 Emit(CEE_LEAVE, 0, (UINT_PTR)pCodeLabel);
1482}
1483void ILCodeStream::EmitLOCALLOC()
1484{
1485 WRAPPER_NO_CONTRACT;
1486 Emit(CEE_LOCALLOC, 0, 0);
1487}
1488void ILCodeStream::EmitMUL()
1489{
1490 WRAPPER_NO_CONTRACT;
1491 Emit(CEE_MUL, -1, 0);
1492}
1493void ILCodeStream::EmitMUL_OVF()
1494{
1495 WRAPPER_NO_CONTRACT;
1496 Emit(CEE_MUL_OVF, -1, 0);
1497}
1498void ILCodeStream::EmitNEWOBJ(int token, int numInArgs)
1499{
1500 WRAPPER_NO_CONTRACT;
1501 Emit(CEE_NEWOBJ, (INT16)(1 - numInArgs), token);
1502}
1503
1504void ILCodeStream::EmitNOP(LPCSTR pszNopComment)
1505{
1506 WRAPPER_NO_CONTRACT;
1507 Emit(CEE_NOP, 0, (UINT_PTR)pszNopComment);
1508}
1509
1510void ILCodeStream::EmitPOP()
1511{
1512 WRAPPER_NO_CONTRACT;
1513 Emit(CEE_POP, -1, 0);
1514}
1515void ILCodeStream::EmitRET()
1516{
1517 WRAPPER_NO_CONTRACT;
1518 INT16 iStackDelta = m_pOwner->m_StubHasVoidReturnType ? 0 : -1;
1519 Emit(CEE_RET, iStackDelta, 0);
1520}
1521void ILCodeStream::EmitSHR_UN()
1522{
1523 WRAPPER_NO_CONTRACT;
1524 Emit(CEE_SHR_UN, -1, 0);
1525}
1526void ILCodeStream::EmitSTARG(unsigned uArgIdx)
1527{
1528 WRAPPER_NO_CONTRACT;
1529 Emit(CEE_STARG, -1, uArgIdx);
1530}
1531void ILCodeStream::EmitSTELEM_REF()
1532{
1533 WRAPPER_NO_CONTRACT;
1534 Emit(CEE_STELEM_REF, -3, 0);
1535}
1536void ILCodeStream::EmitSTIND_I()
1537{
1538 WRAPPER_NO_CONTRACT;
1539 Emit(CEE_STIND_I, -2, 0);
1540}
1541void ILCodeStream::EmitSTIND_I1()
1542{
1543 WRAPPER_NO_CONTRACT;
1544 Emit(CEE_STIND_I1, -2, 0);
1545}
1546void ILCodeStream::EmitSTIND_I2()
1547{
1548 WRAPPER_NO_CONTRACT;
1549 Emit(CEE_STIND_I2, -2, 0);
1550}
1551void ILCodeStream::EmitSTIND_I4()
1552{
1553 WRAPPER_NO_CONTRACT;
1554 Emit(CEE_STIND_I4, -2, 0);
1555}
1556void ILCodeStream::EmitSTIND_I8()
1557{
1558 WRAPPER_NO_CONTRACT;
1559 Emit(CEE_STIND_I8, -2, 0);
1560}
1561void ILCodeStream::EmitSTIND_R4()
1562{
1563 WRAPPER_NO_CONTRACT;
1564 Emit(CEE_STIND_R4, -2, 0);
1565}
1566void ILCodeStream::EmitSTIND_R8()
1567{
1568 WRAPPER_NO_CONTRACT;
1569 Emit(CEE_STIND_R8, -2, 0);
1570}
1571void ILCodeStream::EmitSTIND_REF()
1572{
1573 WRAPPER_NO_CONTRACT;
1574 Emit(CEE_STIND_REF, -2, 0);
1575}
1576void ILCodeStream::EmitSTIND_T(LocalDesc* pType)
1577{
1578 CONTRACTL
1579 {
1580 PRECONDITION(pType->cbType == 1);
1581 }
1582 CONTRACTL_END;
1583
1584 switch (pType->ElementType[0])
1585 {
1586 case ELEMENT_TYPE_I1: EmitSTIND_I1(); break;
1587 case ELEMENT_TYPE_BOOLEAN: // fall through
1588 case ELEMENT_TYPE_U1: EmitSTIND_I1(); break;
1589 case ELEMENT_TYPE_I2: EmitSTIND_I2(); break;
1590 case ELEMENT_TYPE_CHAR: // fall through
1591 case ELEMENT_TYPE_U2: EmitSTIND_I2(); break;
1592 case ELEMENT_TYPE_I4: EmitSTIND_I4(); break;
1593 case ELEMENT_TYPE_U4: EmitSTIND_I4(); break;
1594 case ELEMENT_TYPE_I8: EmitSTIND_I8(); break;
1595 case ELEMENT_TYPE_U8: EmitSTIND_I8(); break;
1596 case ELEMENT_TYPE_R4: EmitSTIND_R4(); break;
1597 case ELEMENT_TYPE_R8: EmitSTIND_R8(); break;
1598 case ELEMENT_TYPE_PTR: // same as ELEMENT_TYPE_I
1599 case ELEMENT_TYPE_FNPTR: // same as ELEMENT_TYPE_I
1600 case ELEMENT_TYPE_I: EmitSTIND_I(); break;
1601 case ELEMENT_TYPE_U: EmitSTIND_I(); break;
1602 case ELEMENT_TYPE_STRING: // fall through
1603 case ELEMENT_TYPE_CLASS: // fall through
1604 case ELEMENT_TYPE_ARRAY:
1605 case ELEMENT_TYPE_SZARRAY:
1606 case ELEMENT_TYPE_OBJECT: EmitSTIND_REF(); break;
1607
1608 case ELEMENT_TYPE_INTERNAL:
1609 {
1610 CONSISTENCY_CHECK_MSG(!(pType->InternalToken.GetMethodTable()->IsValueType()), "don't know how to handle value types here");
1611 EmitSTIND_REF();
1612 break;
1613 }
1614
1615 default:
1616 UNREACHABLE_MSG("unexpected type passed to EmitSTIND_T");
1617 break;
1618 }
1619}
1620void ILCodeStream::EmitSTFLD(int token)
1621{
1622 WRAPPER_NO_CONTRACT;
1623 Emit(CEE_STFLD, -2, token);
1624}
1625void ILCodeStream::EmitSTLOC(DWORD dwLocalNum)
1626{
1627 WRAPPER_NO_CONTRACT;
1628 Emit(CEE_STLOC, -1, dwLocalNum);
1629}
1630void ILCodeStream::EmitSTOBJ(int token)
1631{
1632 WRAPPER_NO_CONTRACT;
1633 Emit(CEE_STOBJ, -2, token);
1634}
1635void ILCodeStream::EmitSTSFLD(int token)
1636{
1637 WRAPPER_NO_CONTRACT;
1638 Emit(CEE_STSFLD, -1, token);
1639}
1640void ILCodeStream::EmitSUB()
1641{
1642 WRAPPER_NO_CONTRACT;
1643 Emit(CEE_SUB, -1, 0);
1644}
1645void ILCodeStream::EmitTHROW()
1646{
1647 WRAPPER_NO_CONTRACT;
1648 Emit(CEE_THROW, -1, 0);
1649}
1650
1651
1652void ILCodeStream::EmitNEWOBJ(BinderMethodID id, int numInArgs)
1653{
1654 STANDARD_VM_CONTRACT;
1655 EmitNEWOBJ(GetToken(MscorlibBinder::GetMethod(id)), numInArgs);
1656}
1657
1658void ILCodeStream::EmitCALL(BinderMethodID id, int numInArgs, int numRetArgs)
1659{
1660 STANDARD_VM_CONTRACT;
1661 EmitCALL(GetToken(MscorlibBinder::GetMethod(id)), numInArgs, numRetArgs);
1662}
1663
1664
1665
1666
1667
1668
1669void ILStubLinker::SetHasThis (bool fHasThis)
1670{
1671 LIMITED_METHOD_CONTRACT;
1672 m_fHasThis = fHasThis;
1673}
1674
1675void ILCodeStream::EmitLoadThis ()
1676{
1677 WRAPPER_NO_CONTRACT;
1678 _ASSERTE(m_pOwner->m_fHasThis);
1679 // OK, this is ugly, but we add 1 to all LDARGs when
1680 // m_fHasThis is true, so we compensate for that here
1681 // so that we don't have to have a special method to
1682 // load arguments.
1683 EmitLDARG((unsigned)-1);
1684}
1685
1686void ILCodeStream::EmitLoadNullPtr()
1687{
1688 WRAPPER_NO_CONTRACT;
1689
1690 // This is the correct way to load unmanaged zero pointer. EmitLDC(0) alone works
1691 // fine in most cases but may lead to wrong code being generated on 64-bit if the
1692 // flow graph is complex.
1693 EmitLDC(0);
1694 EmitCONV_I();
1695}
1696
1697void ILCodeStream::EmitArgIteratorCreateAndLoad()
1698{
1699 STANDARD_VM_CONTRACT;
1700
1701 //
1702 // we insert the ArgIterator in the same spot that the VASigCookie will go for sanity
1703 //
1704 LocalDesc aiLoc(MscorlibBinder::GetClass(CLASS__ARG_ITERATOR));
1705 int aiLocNum;
1706
1707 aiLocNum = NewLocal(aiLoc);
1708
1709 EmitLDLOCA(aiLocNum);
1710 EmitDUP();
1711 EmitARGLIST();
1712 EmitLoadNullPtr();
1713 EmitCALL(METHOD__ARG_ITERATOR__CTOR2, 2, 0);
1714
1715 aiLoc.ElementType[0] = ELEMENT_TYPE_BYREF;
1716 aiLoc.ElementType[1] = ELEMENT_TYPE_INTERNAL;
1717 aiLoc.cbType = 2;
1718 aiLoc.InternalToken = MscorlibBinder::GetClass(CLASS__ARG_ITERATOR);
1719
1720 SetStubTargetArgType(&aiLoc, false);
1721}
1722
1723DWORD ILStubLinker::NewLocal(CorElementType typ)
1724{
1725 CONTRACTL
1726 {
1727 STANDARD_VM_CHECK;
1728 INJECT_FAULT(COMPlusThrowOM());
1729 }
1730 CONTRACTL_END;
1731
1732 LocalDesc locDesc(typ);
1733 return NewLocal(locDesc);
1734}
1735
1736StubSigBuilder::StubSigBuilder() :
1737 m_nItems(0),
1738 m_cbSig(0)
1739{
1740 STANDARD_VM_CONTRACT;
1741
1742 m_pbSigCursor = (BYTE*) m_qbSigBuffer.AllocThrows(INITIAL_BUFFER_SIZE);
1743}
1744
1745void StubSigBuilder::EnsureEnoughQuickBytes(size_t cbToAppend)
1746{
1747 STANDARD_VM_CONTRACT;
1748
1749 SIZE_T cbBuffer = m_qbSigBuffer.Size();
1750 if ((m_cbSig + cbToAppend) >= cbBuffer)
1751 {
1752 m_qbSigBuffer.ReSizeThrows(2 * cbBuffer);
1753 m_pbSigCursor = ((BYTE*)m_qbSigBuffer.Ptr()) + m_cbSig;
1754 }
1755}
1756
1757DWORD StubSigBuilder::Append(LocalDesc* pLoc)
1758{
1759 CONTRACTL
1760 {
1761 STANDARD_VM_CHECK;
1762 INJECT_FAULT(COMPlusThrowOM());
1763 PRECONDITION(CheckPointer(pLoc));
1764 }
1765 CONTRACTL_END;
1766
1767 EnsureEnoughQuickBytes(pLoc->cbType + sizeof(TypeHandle));
1768
1769 memcpyNoGCRefs(m_pbSigCursor, pLoc->ElementType, pLoc->cbType);
1770 m_pbSigCursor += pLoc->cbType;
1771 m_cbSig += pLoc->cbType;
1772
1773 size_t i = 0;
1774
1775 while (i < pLoc->cbType)
1776 {
1777 CONSISTENCY_CHECK( ELEMENT_TYPE_CLASS != pLoc->ElementType[i]
1778 && ELEMENT_TYPE_VALUETYPE != pLoc->ElementType[i]);
1779
1780 switch (pLoc->ElementType[i])
1781 {
1782 case ELEMENT_TYPE_INTERNAL:
1783 SET_UNALIGNED_PTR(m_pbSigCursor, (UINT_PTR)pLoc->InternalToken.AsPtr());
1784 m_pbSigCursor += sizeof(TypeHandle);
1785 m_cbSig += sizeof(TypeHandle);
1786 break;
1787
1788 case ELEMENT_TYPE_FNPTR:
1789 {
1790 SigPointer ptr(pLoc->pSig);
1791
1792 SigBuilder sigBuilder;
1793 ptr.ConvertToInternalSignature(pLoc->pSigModule, NULL, &sigBuilder);
1794
1795 DWORD cbFnPtrSig;
1796 PVOID pFnPtrSig = sigBuilder.GetSignature(&cbFnPtrSig);
1797
1798 EnsureEnoughQuickBytes(cbFnPtrSig);
1799
1800 memcpyNoGCRefs(m_pbSigCursor, pFnPtrSig, cbFnPtrSig);
1801
1802 m_pbSigCursor += cbFnPtrSig;
1803 m_cbSig += cbFnPtrSig;
1804 }
1805 break;
1806
1807 default:
1808 break;
1809 }
1810
1811 i++;
1812 }
1813
1814 if (pLoc->ElementType[0] == ELEMENT_TYPE_ARRAY)
1815 {
1816 EnsureEnoughQuickBytes(pLoc->cbArrayBoundsInfo);
1817
1818 memcpyNoGCRefs(m_pbSigCursor, pLoc->pSig, pLoc->cbArrayBoundsInfo);
1819 m_pbSigCursor += pLoc->cbArrayBoundsInfo;
1820 m_cbSig += pLoc->cbArrayBoundsInfo;
1821 }
1822
1823 _ASSERTE(m_cbSig <= m_qbSigBuffer.Size()); // we corrupted our buffer resizing if this assert fires
1824
1825 return m_nItems++;
1826}
1827
1828//---------------------------------------------------------------------------------------
1829//
1830DWORD
1831LocalSigBuilder::GetSigSize()
1832{
1833 STANDARD_VM_CONTRACT;
1834
1835 BYTE temp[4];
1836 UINT32 cbEncoded = CorSigCompressData(m_nItems, temp);
1837
1838 S_UINT32 cbSigSize =
1839 S_UINT32(1) + // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
1840 S_UINT32(cbEncoded) + // encoded number of locals
1841 S_UINT32(m_cbSig) + // types
1842 S_UINT32(1); // ELEMENT_TYPE_END
1843 if (cbSigSize.IsOverflow())
1844 {
1845 IfFailThrow(COR_E_OVERFLOW);
1846 }
1847 return cbSigSize.Value();
1848}
1849
1850//---------------------------------------------------------------------------------------
1851//
1852DWORD
1853LocalSigBuilder::GetSig(
1854 BYTE * pbLocalSig,
1855 DWORD cbBuffer)
1856{
1857 STANDARD_VM_CONTRACT;
1858 BYTE temp[4];
1859 size_t cb = CorSigCompressData(m_nItems, temp);
1860
1861 _ASSERTE((1 + cb + m_cbSig + 1) == GetSigSize());
1862
1863 if ((1 + cb + m_cbSig + 1) <= cbBuffer)
1864 {
1865 pbLocalSig[0] = IMAGE_CEE_CS_CALLCONV_LOCAL_SIG;
1866 memcpyNoGCRefs(&pbLocalSig[1], temp, cb);
1867 memcpyNoGCRefs(&pbLocalSig[1 + cb], m_qbSigBuffer.Ptr(), m_cbSig);
1868 pbLocalSig[1 + cb + m_cbSig] = ELEMENT_TYPE_END;
1869 return (DWORD)(1 + cb + m_cbSig + 1);
1870 }
1871 else
1872 {
1873 return NULL;
1874 }
1875}
1876
1877FunctionSigBuilder::FunctionSigBuilder() :
1878 m_callingConv(IMAGE_CEE_CS_CALLCONV_DEFAULT)
1879{
1880 STANDARD_VM_CONTRACT;
1881 m_qbReturnSig.ReSizeThrows(1);
1882 *(CorElementType *)m_qbReturnSig.Ptr() = ELEMENT_TYPE_VOID;
1883}
1884
1885
1886void FunctionSigBuilder::SetReturnType(LocalDesc* pLoc)
1887{
1888 CONTRACTL
1889 {
1890 STANDARD_VM_CHECK;
1891 PRECONDITION(pLoc->cbType > 0);
1892 }
1893 CONTRACTL_END;
1894
1895 m_qbReturnSig.ReSizeThrows(pLoc->cbType);
1896 memcpyNoGCRefs(m_qbReturnSig.Ptr(), pLoc->ElementType, pLoc->cbType);
1897
1898 size_t i = 0;
1899
1900 while (i < pLoc->cbType)
1901 {
1902 CONSISTENCY_CHECK( ELEMENT_TYPE_CLASS != pLoc->ElementType[i]
1903 && ELEMENT_TYPE_VALUETYPE != pLoc->ElementType[i]);
1904
1905 switch (pLoc->ElementType[i])
1906 {
1907 case ELEMENT_TYPE_INTERNAL:
1908 m_qbReturnSig.ReSizeThrows(m_qbReturnSig.Size() + sizeof(TypeHandle));
1909 SET_UNALIGNED_PTR((BYTE *)m_qbReturnSig.Ptr() + m_qbReturnSig.Size() - + sizeof(TypeHandle), (UINT_PTR)pLoc->InternalToken.AsPtr());
1910 break;
1911
1912 case ELEMENT_TYPE_FNPTR:
1913 {
1914 SigPointer ptr(pLoc->pSig);
1915
1916 SigBuilder sigBuilder;
1917 ptr.ConvertToInternalSignature(pLoc->pSigModule, NULL, &sigBuilder);
1918
1919 DWORD cbFnPtrSig;
1920 PVOID pFnPtrSig = sigBuilder.GetSignature(&cbFnPtrSig);
1921
1922 m_qbReturnSig.ReSizeThrows(m_qbReturnSig.Size() + cbFnPtrSig);
1923
1924 memcpyNoGCRefs((BYTE *)m_qbReturnSig.Ptr() + m_qbReturnSig.Size() - cbFnPtrSig, pFnPtrSig, cbFnPtrSig);
1925 }
1926 break;
1927
1928 default:
1929 break;
1930 }
1931
1932 i++;
1933 }
1934
1935 if (pLoc->ElementType[0] == ELEMENT_TYPE_ARRAY)
1936 {
1937 SIZE_T size = m_qbReturnSig.Size();
1938 m_qbReturnSig.ReSizeThrows(size + pLoc->cbArrayBoundsInfo);
1939 memcpyNoGCRefs((BYTE *)m_qbReturnSig.Ptr() + size, pLoc->pSig, pLoc->cbArrayBoundsInfo);
1940 }
1941}
1942
1943void FunctionSigBuilder::SetSig(PCCOR_SIGNATURE pSig, DWORD cSig)
1944{
1945 STANDARD_VM_CONTRACT;
1946
1947 // parse the incoming signature
1948 SigPointer sigPtr(pSig, cSig);
1949
1950 // 1) calling convention
1951 ULONG callConv;
1952 IfFailThrow(sigPtr.GetCallingConvInfo(&callConv));
1953 SetCallingConv((CorCallingConvention)callConv);
1954
1955 // 2) number of parameters
1956 IfFailThrow(sigPtr.GetData(&m_nItems));
1957
1958 // 3) return type
1959 PCCOR_SIGNATURE ptr = sigPtr.GetPtr();
1960 IfFailThrow(sigPtr.SkipExactlyOne());
1961
1962 size_t retSigLength = sigPtr.GetPtr() - ptr;
1963
1964 m_qbReturnSig.ReSizeThrows(retSigLength);
1965 memcpyNoGCRefs(m_qbReturnSig.Ptr(), ptr, retSigLength);
1966
1967 // 4) parameters
1968 m_cbSig = 0;
1969
1970 size_t cbSigLen = (cSig - (sigPtr.GetPtr() - pSig));
1971
1972 m_pbSigCursor = (BYTE *)m_qbSigBuffer.Ptr();
1973 EnsureEnoughQuickBytes(cbSigLen);
1974
1975 memcpyNoGCRefs(m_pbSigCursor, sigPtr.GetPtr(), cbSigLen);
1976
1977 m_cbSig = cbSigLen;
1978 m_pbSigCursor += cbSigLen;
1979}
1980
1981//---------------------------------------------------------------------------------------
1982//
1983DWORD
1984FunctionSigBuilder::GetSigSize()
1985{
1986 STANDARD_VM_CONTRACT;
1987
1988 BYTE temp[4];
1989 DWORD cbEncodedLen = CorSigCompressData(m_nItems, temp);
1990 SIZE_T cbEncodedRetType = m_qbReturnSig.Size();
1991
1992 CONSISTENCY_CHECK(cbEncodedRetType > 0);
1993
1994 S_UINT32 cbSigSize =
1995 S_UINT32(1) + // calling convention
1996 S_UINT32(cbEncodedLen) + // encoded number of args
1997 S_UINT32(cbEncodedRetType) + // encoded return type
1998 S_UINT32(m_cbSig) + // types
1999 S_UINT32(1); // ELEMENT_TYPE_END
2000 if (cbSigSize.IsOverflow())
2001 {
2002 IfFailThrow(COR_E_OVERFLOW);
2003 }
2004 return cbSigSize.Value();
2005}
2006
2007//---------------------------------------------------------------------------------------
2008//
2009DWORD
2010FunctionSigBuilder::GetSig(
2011 BYTE * pbLocalSig,
2012 DWORD cbBuffer)
2013{
2014 STANDARD_VM_CONTRACT;
2015 BYTE tempLen[4];
2016 size_t cbEncodedLen = CorSigCompressData(m_nItems, tempLen);
2017 size_t cbEncodedRetType = m_qbReturnSig.Size();
2018
2019 CONSISTENCY_CHECK(cbEncodedRetType > 0);
2020
2021 _ASSERTE((1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1) == GetSigSize());
2022
2023 if ((1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1) <= cbBuffer)
2024 {
2025 BYTE* pbCursor = pbLocalSig;
2026 *pbCursor = static_cast<BYTE>(m_callingConv);
2027 pbCursor++;
2028
2029 memcpyNoGCRefs(pbCursor, tempLen, cbEncodedLen);
2030 pbCursor += cbEncodedLen;
2031
2032 memcpyNoGCRefs(pbCursor, m_qbReturnSig.Ptr(), m_qbReturnSig.Size());
2033 pbCursor += m_qbReturnSig.Size();
2034
2035 memcpyNoGCRefs(pbCursor, m_qbSigBuffer.Ptr(), m_cbSig);
2036 pbCursor += m_cbSig;
2037 pbCursor[0] = ELEMENT_TYPE_END;
2038 return (DWORD)(1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1);
2039 }
2040 else
2041 {
2042 return NULL;
2043 }
2044}
2045
2046DWORD ILStubLinker::NewLocal(LocalDesc loc)
2047{
2048 WRAPPER_NO_CONTRACT;
2049
2050 return m_localSigBuilder.NewLocal(&loc);
2051}
2052
2053//---------------------------------------------------------------------------------------
2054//
2055DWORD
2056ILStubLinker::GetLocalSigSize()
2057{
2058 LIMITED_METHOD_CONTRACT;
2059
2060 return m_localSigBuilder.GetSigSize();
2061}
2062
2063//---------------------------------------------------------------------------------------
2064//
2065DWORD
2066ILStubLinker::GetLocalSig(
2067 BYTE * pbLocalSig,
2068 DWORD cbBuffer)
2069{
2070 STANDARD_VM_CONTRACT;
2071
2072 DWORD dwRet = m_localSigBuilder.GetSig(pbLocalSig, cbBuffer);
2073 return dwRet;
2074}
2075
2076//---------------------------------------------------------------------------------------
2077//
2078DWORD
2079ILStubLinker::GetStubTargetMethodSigSize()
2080{
2081 STANDARD_VM_CONTRACT;
2082
2083 return m_nativeFnSigBuilder.GetSigSize();
2084}
2085
2086//---------------------------------------------------------------------------------------
2087//
2088DWORD
2089ILStubLinker::GetStubTargetMethodSig(
2090 BYTE * pbSig,
2091 DWORD cbSig)
2092{
2093 LIMITED_METHOD_CONTRACT;
2094
2095 DWORD dwRet = m_nativeFnSigBuilder.GetSig(pbSig, cbSig);
2096 return dwRet;
2097}
2098
2099void ILStubLinker::SetStubTargetMethodSig(PCCOR_SIGNATURE pSig, DWORD cSig)
2100{
2101 STANDARD_VM_CONTRACT;
2102
2103 m_nativeFnSigBuilder.SetSig(pSig, cSig);
2104}
2105
2106static BOOL SigHasVoidReturnType(const Signature &signature)
2107{
2108 CONTRACTL
2109 {
2110 THROWS;
2111 GC_NOTRIGGER;
2112 }
2113 CONTRACTL_END
2114
2115 SigPointer ptr = signature.CreateSigPointer();
2116
2117 ULONG data;
2118 IfFailThrow(ptr.GetCallingConvInfo(&data));
2119 // Skip number of type arguments
2120 if (data & IMAGE_CEE_CS_CALLCONV_GENERIC)
2121 {
2122 IfFailThrow(ptr.GetData(NULL));
2123 }
2124
2125 // skip number of args
2126 IfFailThrow(ptr.GetData(NULL));
2127
2128 CorElementType retType;
2129 IfFailThrow(ptr.PeekElemType(&retType));
2130
2131 return (ELEMENT_TYPE_VOID == retType);
2132}
2133
2134
2135ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, SigTypeContext *pTypeContext, MethodDesc *pMD,
2136 BOOL fTargetHasThis, BOOL fStubHasThis, BOOL fIsNDirectStub) :
2137 m_pCodeStreamList(NULL),
2138 m_stubSig(signature),
2139 m_pTypeContext(pTypeContext),
2140 m_pCode(NULL),
2141 m_pStubSigModule(pStubSigModule),
2142 m_pLabelList(NULL),
2143 m_StubHasVoidReturnType(0),
2144 m_iTargetStackDelta(0),
2145 m_cbCurrentCompressedSigLen(1),
2146 m_nLocals(0),
2147 m_fHasThis(false),
2148 m_pMD(pMD)
2149{
2150 CONTRACTL
2151 {
2152 THROWS;
2153 GC_TRIGGERS;
2154 INJECT_FAULT(COMPlusThrowOM());
2155 }
2156 CONTRACTL_END
2157
2158 m_managedSigPtr = signature.CreateSigPointer();
2159 if (!signature.IsEmpty())
2160 {
2161 m_StubHasVoidReturnType = SigHasVoidReturnType(signature);
2162
2163 //
2164 // Get the stub's calling convention. Set m_fHasThis to match
2165 // IMAGE_CEE_CS_CALLCONV_HASTHIS.
2166 //
2167
2168 ULONG uStubCallingConvInfo;
2169 IfFailThrow(m_managedSigPtr.GetCallingConvInfo(&uStubCallingConvInfo));
2170
2171 if (fStubHasThis)
2172 {
2173 m_fHasThis = true;
2174 }
2175
2176 //
2177 // If target calling convention was specified, use it instead.
2178 // Otherwise, derive one based on the stub's signature.
2179 //
2180
2181 ULONG uCallingConvInfo = uStubCallingConvInfo;
2182
2183 ULONG uCallingConv = (uCallingConvInfo & IMAGE_CEE_CS_CALLCONV_MASK);
2184 ULONG uNativeCallingConv;
2185
2186 if (IMAGE_CEE_CS_CALLCONV_VARARG == uCallingConv)
2187 {
2188 //
2189 // If we have a PInvoke stub that has a VARARG calling convention
2190 // we will transition to a NATIVEVARARG calling convention for the
2191 // target call. The JIT64 knows about this calling convention,
2192 // basically it is the same as the managed vararg calling convention
2193 // except without a VASigCookie.
2194 //
2195 // If our stub is not a PInvoke stub and has a vararg calling convention,
2196 // we are most likely going to have to forward those variable arguments
2197 // on to our call target. Unfortunately, callsites to varargs methods
2198 // in IL always have full signatures (that's where the VASigCookie comes
2199 // from). But we don't have that in this case, so we play some tricks and
2200 // pass an ArgIterator down to an assembly routine that pulls out the
2201 // variable arguments and puts them in the right spot before forwarding
2202 // to the stub target.
2203 //
2204 // The net result is that we don't want to set the native calling
2205 // convention to be vararg for non-PInvoke stubs, so we just use
2206 // the default callconv.
2207 //
2208 if (!fIsNDirectStub)
2209 uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_DEFAULT;
2210 else
2211 uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_NATIVEVARARG;
2212 }
2213 else
2214 {
2215 uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_DEFAULT;
2216 }
2217
2218 if (fTargetHasThis && !fIsNDirectStub)
2219 {
2220 // ndirect native sig never has a 'this' pointer
2221 uNativeCallingConv |= IMAGE_CEE_CS_CALLCONV_HASTHIS;
2222 }
2223
2224 if (fTargetHasThis)
2225 {
2226 m_iTargetStackDelta--;
2227 }
2228
2229 m_nativeFnSigBuilder.SetCallingConv((CorCallingConvention)uNativeCallingConv);
2230
2231 if (uStubCallingConvInfo & IMAGE_CEE_CS_CALLCONV_GENERIC)
2232 IfFailThrow(m_managedSigPtr.GetData(NULL)); // skip number of type parameters
2233
2234 IfFailThrow(m_managedSigPtr.GetData(NULL)); // skip number of parameters
2235 IfFailThrow(m_managedSigPtr.SkipExactlyOne()); // skip return type
2236 }
2237}
2238
2239ILStubLinker::~ILStubLinker()
2240{
2241 CONTRACTL
2242 {
2243 NOTHROW;
2244 GC_TRIGGERS;
2245 MODE_ANY;
2246 }
2247 CONTRACTL_END;
2248 DeleteCodeLabels();
2249 DeleteCodeStreams();
2250}
2251
2252void ILStubLinker::DeleteCodeLabels()
2253{
2254 CONTRACTL
2255 {
2256 NOTHROW;
2257 MODE_ANY;
2258 GC_TRIGGERS;
2259 }
2260 CONTRACTL_END;
2261
2262 //
2263 // walk the list of labels and free each one
2264 //
2265 ILCodeLabel* pCurrent = m_pLabelList;
2266 while (pCurrent)
2267 {
2268 ILCodeLabel* pDeleteMe = pCurrent;
2269 pCurrent = pCurrent->m_pNext;
2270 delete pDeleteMe;
2271 }
2272 m_pLabelList = NULL;
2273}
2274
2275void ILStubLinker::DeleteCodeStreams()
2276{
2277 CONTRACTL
2278 {
2279 NOTHROW;
2280 MODE_ANY;
2281 GC_TRIGGERS;
2282 }
2283 CONTRACTL_END;
2284
2285 ILCodeStream* pCurrent = m_pCodeStreamList;
2286 while (pCurrent)
2287 {
2288 ILCodeStream* pDeleteMe = pCurrent;
2289 pCurrent = pCurrent->m_pNextStream;
2290 delete pDeleteMe;
2291 }
2292 m_pCodeStreamList = NULL;
2293}
2294
2295void ILStubLinker::ClearCodeStreams()
2296{
2297 CONTRACTL
2298 {
2299 NOTHROW;
2300 MODE_ANY;
2301 GC_TRIGGERS;
2302 }
2303 CONTRACTL_END;
2304
2305 ILCodeStream* pCurrent = m_pCodeStreamList;
2306 while (pCurrent)
2307 {
2308 pCurrent->ClearCode();
2309 pCurrent = pCurrent->m_pNextStream;
2310 }
2311}
2312
2313void ILStubLinker::GetStubReturnType(LocalDesc* pLoc)
2314{
2315 WRAPPER_NO_CONTRACT;
2316
2317 GetStubReturnType(pLoc, m_pStubSigModule);
2318}
2319
2320void ILStubLinker::GetStubReturnType(LocalDesc* pLoc, Module* pModule)
2321{
2322 STANDARD_VM_CONTRACT;
2323 SigPointer ptr = m_stubSig.CreateSigPointer();
2324 ULONG uCallingConv;
2325 int nTypeArgs = 0;
2326 int nArgs;
2327
2328 IfFailThrow(ptr.GetCallingConvInfo(&uCallingConv));
2329
2330 if (uCallingConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
2331 IfFailThrow(ptr.GetData((ULONG*)&nTypeArgs));
2332
2333 IfFailThrow(ptr.GetData((ULONG*)&nArgs));
2334
2335 GetManagedTypeHelper(pLoc, pModule, ptr.GetPtr(), m_pTypeContext, m_pMD);
2336}
2337
2338CorCallingConvention ILStubLinker::GetStubTargetCallingConv()
2339{
2340 LIMITED_METHOD_CONTRACT;
2341 return m_nativeFnSigBuilder.GetCallingConv();
2342}
2343
2344void ILStubLinker::TransformArgForJIT(LocalDesc *pLoc)
2345{
2346 STANDARD_VM_CONTRACT;
2347 // Turn everything into blittable primitives. The reason this method is needed are
2348 // byrefs which are OK only when they ref stack data or are pinned. This condition
2349 // cannot be verified by code:NDirect.MarshalingRequired so we explicitly get rid
2350 // of them here.
2351 switch (pLoc->ElementType[0])
2352 {
2353 // primitives
2354 case ELEMENT_TYPE_VOID:
2355 case ELEMENT_TYPE_BOOLEAN:
2356 case ELEMENT_TYPE_CHAR:
2357 case ELEMENT_TYPE_I1:
2358 case ELEMENT_TYPE_U1:
2359 case ELEMENT_TYPE_I2:
2360 case ELEMENT_TYPE_U2:
2361 case ELEMENT_TYPE_I4:
2362 case ELEMENT_TYPE_U4:
2363 case ELEMENT_TYPE_I8:
2364 case ELEMENT_TYPE_U8:
2365 case ELEMENT_TYPE_R4:
2366 case ELEMENT_TYPE_R8:
2367 case ELEMENT_TYPE_I:
2368 case ELEMENT_TYPE_U:
2369 {
2370 // no transformation needed
2371 break;
2372 }
2373
2374 case ELEMENT_TYPE_VALUETYPE:
2375 {
2376 _ASSERTE(!"Should have been replaced by a native value type!");
2377 break;
2378 }
2379
2380 case ELEMENT_TYPE_PTR:
2381 {
2382#ifdef _TARGET_X86_
2383 if (pLoc->bIsCopyConstructed)
2384 {
2385 // The only pointers that we don't transform to ELEMENT_TYPE_I are those that are
2386 // ET_TYPE_CMOD_REQD<IsCopyConstructed>/ET_TYPE_CMOD_REQD<NeedsCopyConstructorModifier>
2387 // in the original signature. This convention is understood by the UM thunk compiler
2388 // (code:UMThunkMarshInfo.CompileNExportThunk) which will generate different thunk code.
2389 // Such parameters come from unmanaged by value but must enter the IL stub by reference
2390 // because we are not supposed to make a copy.
2391 }
2392 else
2393#endif // _TARGET_X86_
2394 {
2395 pLoc->ElementType[0] = ELEMENT_TYPE_I;
2396 pLoc->cbType = 1;
2397 }
2398 break;
2399 }
2400
2401 case ELEMENT_TYPE_INTERNAL:
2402 {
2403 // JIT will handle structures
2404 if (pLoc->InternalToken.IsValueType())
2405 {
2406 _ASSERTE(pLoc->InternalToken.IsBlittable());
2407 break;
2408 }
2409 // intentional fall-thru
2410 }
2411
2412 // pointers, byrefs, strings, arrays, other ref types -> ELEMENT_TYPE_I
2413 default:
2414 {
2415 pLoc->ElementType[0] = ELEMENT_TYPE_I;
2416 pLoc->cbType = 1;
2417 break;
2418 }
2419 }
2420}
2421
2422Module *ILStubLinker::GetStubSigModule()
2423{
2424 LIMITED_METHOD_CONTRACT;
2425 return m_pStubSigModule;
2426}
2427
2428SigTypeContext *ILStubLinker::GetStubSigTypeContext()
2429{
2430 LIMITED_METHOD_CONTRACT;
2431 return m_pTypeContext;
2432}
2433
2434void ILStubLinker::SetStubTargetReturnType(CorElementType typ)
2435{
2436 WRAPPER_NO_CONTRACT;
2437
2438 LocalDesc locDesc(typ);
2439 SetStubTargetReturnType(&locDesc);
2440}
2441
2442void ILStubLinker::SetStubTargetReturnType(LocalDesc* pLoc)
2443{
2444 CONTRACTL
2445 {
2446 WRAPPER(NOTHROW);
2447 WRAPPER(GC_NOTRIGGER);
2448 WRAPPER(MODE_ANY);
2449 PRECONDITION(CheckPointer(pLoc, NULL_NOT_OK));
2450 }
2451 CONTRACTL_END;
2452
2453 TransformArgForJIT(pLoc);
2454
2455 m_nativeFnSigBuilder.SetReturnType(pLoc);
2456
2457 if ((1 != pLoc->cbType) || (ELEMENT_TYPE_VOID != pLoc->ElementType[0]))
2458 {
2459 m_iTargetStackDelta++;
2460 }
2461}
2462
2463DWORD ILStubLinker::SetStubTargetArgType(CorElementType typ, bool fConsumeStubArg /*= true*/)
2464{
2465 STANDARD_VM_CONTRACT;
2466
2467 LocalDesc locDesc(typ);
2468 return SetStubTargetArgType(&locDesc, fConsumeStubArg);
2469}
2470
2471void ILStubLinker::SetStubTargetCallingConv(CorCallingConvention uNativeCallingConv)
2472{
2473 LIMITED_METHOD_CONTRACT;
2474 m_nativeFnSigBuilder.SetCallingConv(uNativeCallingConv);
2475}
2476
2477static size_t GetManagedTypeForMDArray(LocalDesc* pLoc, Module* pModule, PCCOR_SIGNATURE psigManagedArg, SigTypeContext *pTypeContext)
2478{
2479 CONTRACTL
2480 {
2481 STANDARD_VM_CHECK;
2482
2483 PRECONDITION(CheckPointer(pLoc));
2484 PRECONDITION(CheckPointer(pModule));
2485 PRECONDITION(CheckPointer(psigManagedArg));
2486 PRECONDITION(*psigManagedArg == ELEMENT_TYPE_ARRAY);
2487 }
2488 CONTRACTL_END;
2489
2490 SigPointer ptr;
2491 size_t cbDest = 0;
2492
2493 //
2494 // copy ELEMENT_TYPE_ARRAY
2495 //
2496 pLoc->ElementType[cbDest] = *psigManagedArg;
2497 psigManagedArg++;
2498 cbDest++;
2499
2500 ptr.SetSig(psigManagedArg);
2501
2502 IfFailThrow(ptr.SkipCustomModifiers());
2503
2504 psigManagedArg = ptr.GetPtr();
2505
2506 //
2507 // get array type
2508 //
2509 pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
2510
2511 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2512 cbDest++;
2513
2514 //
2515 // get array bounds
2516 //
2517
2518 size_t cbType;
2519 PCCOR_SIGNATURE psigNextManagedArg;
2520
2521 // find the start of the next argument
2522 ptr.SetSig(psigManagedArg - 1); // -1 to back up to E_T_ARRAY;
2523 IfFailThrow(ptr.SkipExactlyOne());
2524
2525 psigNextManagedArg = ptr.GetPtr();
2526
2527 // find the start of the array bounds information
2528 ptr.SetSig(psigManagedArg);
2529 IfFailThrow(ptr.SkipExactlyOne());
2530
2531 psigManagedArg = ptr.GetPtr(); // point to the array bounds info
2532 cbType = psigNextManagedArg - psigManagedArg;
2533
2534 pLoc->pSig = psigManagedArg; // point to the array bounds info
2535 pLoc->cbArrayBoundsInfo = cbType; // size of array bounds info
2536 pLoc->cbType = cbDest;
2537
2538 return cbDest;
2539}
2540
2541
2542// static
2543void ILStubLinker::GetManagedTypeHelper(LocalDesc* pLoc, Module* pModule, PCCOR_SIGNATURE psigManagedArg, SigTypeContext *pTypeContext, MethodDesc *pMD)
2544{
2545 CONTRACTL
2546 {
2547 STANDARD_VM_CHECK;
2548
2549 PRECONDITION(CheckPointer(pLoc));
2550 PRECONDITION(CheckPointer(pModule));
2551 PRECONDITION(CheckPointer(psigManagedArg));
2552 }
2553 CONTRACTL_END;
2554
2555 SigPointer ptr(psigManagedArg);
2556 CorElementType eType;
2557 LOG((LF_STUBS, LL_INFO10000, "GetManagedTypeHelper on type at %p\n", psigManagedArg));
2558
2559 IfFailThrow(ptr.PeekElemType(&eType));
2560
2561 size_t cbDest = 0;
2562
2563 while (eType == ELEMENT_TYPE_PTR ||
2564 eType == ELEMENT_TYPE_BYREF ||
2565 eType == ELEMENT_TYPE_SZARRAY)
2566 {
2567 pLoc->ElementType[cbDest] = static_cast<BYTE>(eType);
2568 cbDest++;
2569
2570 if (cbDest >= LocalDesc::MAX_LOCALDESC_ELEMENTS)
2571 {
2572 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
2573 }
2574
2575 IfFailThrow(ptr.GetElemType(NULL));
2576 IfFailThrow(ptr.PeekElemType(&eType));
2577 }
2578
2579 SigPointer ptr2(ptr);
2580 IfFailThrow(ptr2.SkipCustomModifiers());
2581 psigManagedArg = ptr2.GetPtr();
2582
2583 switch (eType)
2584 {
2585 case ELEMENT_TYPE_VAR:
2586 case ELEMENT_TYPE_MVAR:
2587 {
2588 IfFailThrow(ptr.GetElemType(NULL)); // skip ET
2589 ULONG varNum;
2590 IfFailThrowBF(ptr.GetData(&varNum), BFA_BAD_COMPLUS_SIG, pModule);
2591
2592 DWORD varCount = (eType == ELEMENT_TYPE_VAR ? pTypeContext->m_classInst.GetNumArgs() :
2593 pTypeContext->m_methodInst.GetNumArgs());
2594 THROW_BAD_FORMAT_MAYBE(varNum < varCount, BFA_BAD_COMPLUS_SIG, pModule);
2595
2596 pLoc->InternalToken = (eType == ELEMENT_TYPE_VAR ? pTypeContext->m_classInst[varNum] :
2597 pTypeContext->m_methodInst[varNum]);
2598
2599 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2600 cbDest++;
2601 break;
2602 }
2603
2604 case ELEMENT_TYPE_CLASS:
2605 case ELEMENT_TYPE_VALUETYPE:
2606 case ELEMENT_TYPE_INTERNAL:
2607 {
2608 pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
2609
2610 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2611 cbDest++;
2612 break;
2613 }
2614
2615 case ELEMENT_TYPE_GENERICINST:
2616 {
2617 pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
2618
2619 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2620 cbDest++;
2621 break;
2622 }
2623
2624 case ELEMENT_TYPE_FNPTR:
2625 // save off a pointer to the managed sig
2626 // we'll convert it in bulk when we store it
2627 // in the generated sig
2628 pLoc->pSigModule = pModule;
2629 pLoc->pSig = psigManagedArg+1;
2630
2631 pLoc->ElementType[cbDest] = ELEMENT_TYPE_FNPTR;
2632 cbDest++;
2633 break;
2634
2635 case ELEMENT_TYPE_ARRAY:
2636 cbDest = GetManagedTypeForMDArray(pLoc, pModule, psigManagedArg, pTypeContext);
2637 break;
2638
2639 default:
2640 {
2641 size_t cbType;
2642 PCCOR_SIGNATURE psigNextManagedArg;
2643
2644 IfFailThrow(ptr.SkipExactlyOne());
2645
2646 psigNextManagedArg = ptr.GetPtr();
2647 cbType = psigNextManagedArg - psigManagedArg;
2648
2649 size_t cbNewDest;
2650 if (!ClrSafeInt<size_t>::addition(cbDest, cbType, cbNewDest) ||
2651 cbNewDest > LocalDesc::MAX_LOCALDESC_ELEMENTS)
2652 {
2653 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
2654 }
2655
2656 memcpyNoGCRefs(&pLoc->ElementType[cbDest], psigManagedArg, cbType);
2657 cbDest = cbNewDest;
2658 break;
2659 }
2660 }
2661
2662 if (cbDest > LocalDesc::MAX_LOCALDESC_ELEMENTS)
2663 {
2664 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
2665 }
2666
2667 pLoc->cbType = cbDest;
2668}
2669
2670void ILStubLinker::GetStubTargetReturnType(LocalDesc* pLoc)
2671{
2672 CONTRACTL
2673 {
2674 STANDARD_VM_CHECK;
2675 PRECONDITION(CheckPointer(pLoc));
2676 }
2677 CONTRACTL_END;
2678
2679 GetStubTargetReturnType(pLoc, m_pStubSigModule);
2680}
2681
2682void ILStubLinker::GetStubTargetReturnType(LocalDesc* pLoc, Module* pModule)
2683{
2684 CONTRACTL
2685 {
2686 STANDARD_VM_CHECK;
2687 PRECONDITION(CheckPointer(pLoc));
2688 PRECONDITION(CheckPointer(pModule));
2689 }
2690 CONTRACTL_END;
2691
2692 GetManagedTypeHelper(pLoc, pModule, m_nativeFnSigBuilder.GetReturnSig(), m_pTypeContext, NULL);
2693}
2694
2695void ILStubLinker::GetStubArgType(LocalDesc* pLoc)
2696{
2697
2698 CONTRACTL
2699 {
2700 STANDARD_VM_CHECK;
2701 PRECONDITION(CheckPointer(pLoc));
2702 }
2703 CONTRACTL_END;
2704
2705 GetStubArgType(pLoc, m_pStubSigModule);
2706}
2707
2708void ILStubLinker::GetStubArgType(LocalDesc* pLoc, Module* pModule)
2709{
2710
2711 CONTRACTL
2712 {
2713 STANDARD_VM_CHECK;
2714 PRECONDITION(CheckPointer(pLoc));
2715 PRECONDITION(CheckPointer(pModule));
2716 }
2717 CONTRACTL_END;
2718
2719 GetManagedTypeHelper(pLoc, pModule, m_managedSigPtr.GetPtr(), m_pTypeContext, m_pMD);
2720}
2721
2722//---------------------------------------------------------------------------------------
2723//
2724DWORD
2725ILStubLinker::SetStubTargetArgType(
2726 LocalDesc * pLoc, // = NULL
2727 bool fConsumeStubArg) // = true
2728{
2729 STANDARD_VM_CONTRACT;
2730
2731 LocalDesc locDesc;
2732
2733 if (fConsumeStubArg)
2734 {
2735 _ASSERTE(m_pStubSigModule);
2736
2737 if (pLoc == NULL)
2738 {
2739 pLoc = &locDesc;
2740 GetStubArgType(pLoc, m_pStubSigModule);
2741 }
2742
2743 IfFailThrow(m_managedSigPtr.SkipExactlyOne());
2744 }
2745
2746 TransformArgForJIT(pLoc);
2747
2748 DWORD dwArgNum = m_nativeFnSigBuilder.NewArg(pLoc);
2749 m_iTargetStackDelta--;
2750
2751 return dwArgNum;
2752} // ILStubLinker::SetStubTargetArgType
2753
2754//---------------------------------------------------------------------------------------
2755//
2756int ILStubLinker::GetToken(MethodDesc* pMD)
2757{
2758 STANDARD_VM_CONTRACT;
2759 return m_tokenMap.GetToken(pMD);
2760}
2761
2762int ILStubLinker::GetToken(MethodTable* pMT)
2763{
2764 STANDARD_VM_CONTRACT;
2765 return m_tokenMap.GetToken(TypeHandle(pMT));
2766}
2767
2768int ILStubLinker::GetToken(TypeHandle th)
2769{
2770 STANDARD_VM_CONTRACT;
2771 return m_tokenMap.GetToken(th);
2772}
2773
2774int ILStubLinker::GetToken(FieldDesc* pFD)
2775{
2776 STANDARD_VM_CONTRACT;
2777 return m_tokenMap.GetToken(pFD);
2778}
2779
2780
2781BOOL ILStubLinker::StubHasVoidReturnType()
2782{
2783 LIMITED_METHOD_CONTRACT;
2784 return m_StubHasVoidReturnType;
2785}
2786
2787void ILStubLinker::ClearCode()
2788{
2789 CONTRACTL
2790 {
2791 NOTHROW;
2792 MODE_ANY;
2793 GC_TRIGGERS;
2794 }
2795 CONTRACTL_END;
2796
2797 DeleteCodeLabels();
2798 ClearCodeStreams();
2799}
2800
2801// static
2802ILCodeStream* ILStubLinker::FindLastCodeStream(ILCodeStream* pList)
2803{
2804 LIMITED_METHOD_CONTRACT;
2805
2806 if (NULL == pList)
2807 {
2808 return NULL;
2809 }
2810
2811 while (NULL != pList->m_pNextStream)
2812 {
2813 pList = pList->m_pNextStream;
2814 }
2815
2816 return pList;
2817}
2818
2819ILCodeStream* ILStubLinker::NewCodeStream(CodeStreamType codeStreamType)
2820{
2821 STANDARD_VM_CONTRACT;
2822
2823 NewHolder<ILCodeStream> pNewCodeStream = new ILCodeStream(this, codeStreamType);
2824
2825 if (NULL == m_pCodeStreamList)
2826 {
2827 m_pCodeStreamList = pNewCodeStream;
2828 }
2829 else
2830 {
2831 ILCodeStream* pTail = FindLastCodeStream(m_pCodeStreamList);
2832 CONSISTENCY_CHECK(NULL == pTail->m_pNextStream);
2833 pTail->m_pNextStream = pNewCodeStream;
2834 }
2835
2836 pNewCodeStream.SuppressRelease();
2837 return pNewCodeStream;
2838}
2839
2840int ILCodeStream::GetToken(MethodDesc* pMD)
2841{
2842 STANDARD_VM_CONTRACT;
2843 return m_pOwner->GetToken(pMD);
2844}
2845int ILCodeStream::GetToken(MethodTable* pMT)
2846{
2847 STANDARD_VM_CONTRACT;
2848 return m_pOwner->GetToken(pMT);
2849}
2850int ILCodeStream::GetToken(TypeHandle th)
2851{
2852 STANDARD_VM_CONTRACT;
2853 return m_pOwner->GetToken(th);
2854}
2855int ILCodeStream::GetToken(FieldDesc* pFD)
2856{
2857 STANDARD_VM_CONTRACT;
2858 return m_pOwner->GetToken(pFD);
2859}
2860
2861DWORD ILCodeStream::NewLocal(CorElementType typ)
2862{
2863 STANDARD_VM_CONTRACT;
2864 return m_pOwner->NewLocal(typ);
2865}
2866DWORD ILCodeStream::NewLocal(LocalDesc loc)
2867{
2868 WRAPPER_NO_CONTRACT;
2869 return m_pOwner->NewLocal(loc);
2870}
2871DWORD ILCodeStream::SetStubTargetArgType(CorElementType typ, bool fConsumeStubArg)
2872{
2873 STANDARD_VM_CONTRACT;
2874 return m_pOwner->SetStubTargetArgType(typ, fConsumeStubArg);
2875}
2876DWORD ILCodeStream::SetStubTargetArgType(LocalDesc* pLoc, bool fConsumeStubArg)
2877{
2878 STANDARD_VM_CONTRACT;
2879 return m_pOwner->SetStubTargetArgType(pLoc, fConsumeStubArg);
2880}
2881void ILCodeStream::SetStubTargetReturnType(CorElementType typ)
2882{
2883 STANDARD_VM_CONTRACT;
2884 m_pOwner->SetStubTargetReturnType(typ);
2885}
2886void ILCodeStream::SetStubTargetReturnType(LocalDesc* pLoc)
2887{
2888 STANDARD_VM_CONTRACT;
2889 m_pOwner->SetStubTargetReturnType(pLoc);
2890}
2891ILCodeLabel* ILCodeStream::NewCodeLabel()
2892{
2893 STANDARD_VM_CONTRACT;
2894 return m_pOwner->NewCodeLabel();
2895}
2896void ILCodeStream::ClearCode()
2897{
2898 LIMITED_METHOD_CONTRACT;
2899 m_uCurInstrIdx = 0;
2900}
2901