Merge pull request #23934 from franksinankaya/gcc_cleanup_18
[platform/upstream/coreclr.git] / src / ilasm / assem.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: assem.cpp
6 //
7
8 //
9 // COM+ IL assembler
10 //
11 #include "ilasmpch.h"
12
13 #define INITGUID
14
15 #define DECLARE_DATA
16
17 #include "assembler.h"
18 #ifdef FEATURE_PAL
19 #include "coreclrloader.h"
20 CoreCLRLoader *g_loader;
21 #endif // FEATURE_PAL
22 MetaDataGetDispenserFunc metaDataGetDispenser;
23
24 void indexKeywords(Indx* indx); // defined in asmparse.y
25
26 unsigned int g_uCodePage = CP_ACP;
27 unsigned int g_uConsoleCP = CP_ACP;
28
29 char g_szSourceFileName[MAX_FILENAME_LENGTH*3];
30
31 WCHAR wzUniBuf[dwUniBuf];      // Unicode conversion global buffer
32
33 Assembler::Assembler()
34 {
35     m_pDisp = NULL;
36     m_pEmitter = NULL;
37     m_pImporter = NULL;
38
39     m_fCPlusPlus = FALSE;
40     m_fWindowsCE = FALSE;
41     char* pszFQN = new char[16];
42     strcpy_s(pszFQN,16,"<Module>");
43     m_pModuleClass = new Class(pszFQN);
44     m_lstClass.PUSH(m_pModuleClass);
45     m_hshClass.PUSH(m_pModuleClass);
46     m_pModuleClass->m_cl = mdTokenNil;
47     m_pModuleClass->m_bIsMaster = FALSE;
48
49     m_fStdMapping   = FALSE;
50     m_fDisplayTraceOutput= FALSE;
51     m_fENCMode = FALSE;
52     m_fTolerateDupMethods = FALSE;
53
54     m_pCurOutputPos = NULL;
55
56     m_CurPC             = 0;    // PC offset in method
57     m_pCurMethod        = NULL;
58     m_pCurClass         = NULL;
59     m_pCurEvent         = NULL;
60     m_pCurProp          = NULL;
61
62     m_wzMetadataVersion = NULL;
63     m_wMSVmajor = 0xFFFF;
64     m_wMSVminor = 0xFFFF;
65
66     m_wSSVersionMajor = 4;
67     m_wSSVersionMinor = 0;
68     m_fAppContainer = FALSE;
69     m_fHighEntropyVA = FALSE;
70
71     m_pCeeFileGen            = NULL;
72     m_pCeeFile               = 0;
73
74     m_pManifest         = NULL;
75
76     m_pCustomDescrList  = NULL;
77
78     m_pGlobalDataSection = NULL;
79     m_pILSection = NULL;
80     m_pTLSSection = NULL;
81
82     m_fDidCoInitialise = FALSE;
83
84     m_fDLL = FALSE;
85     m_fEntryPointPresent = FALSE;
86     m_fHaveFieldsWithRvas = FALSE;
87     m_fFoldCode = FALSE;
88     m_dwMethodsFolded = 0;
89
90     m_szScopeName[0] = 0;
91     m_crExtends = mdTypeDefNil;
92
93     m_nImplList = 0;
94     m_TyParList = NULL;
95
96     m_SEHD = NULL;
97     m_firstArgName = NULL;
98     m_lastArgName = NULL;
99     m_szNamespace = new char[2];
100     m_szNamespace[0] = 0;
101     m_NSstack.PUSH(m_szNamespace);
102
103     m_szFullNS = new char[MAX_NAMESPACE_LENGTH];
104     memset(m_szFullNS,0,MAX_NAMESPACE_LENGTH);
105     m_ulFullNSLen = MAX_NAMESPACE_LENGTH;
106
107     m_State             = STATE_OK;
108     m_fInitialisedMetaData = FALSE;
109     m_fAutoInheritFromObject = TRUE;
110
111     m_ulLastDebugLine = 0xFFFFFFFF;
112     m_ulLastDebugColumn = 0xFFFFFFFF;
113     m_ulLastDebugLineEnd = 0xFFFFFFFF;
114     m_ulLastDebugColumnEnd = 0xFFFFFFFF;
115     m_pSymWriter = NULL;
116     m_pSymDocument = NULL;
117     m_dwIncludeDebugInfo = 0;
118     m_fGeneratePDB = FALSE;
119     m_fIsMscorlib = FALSE;
120     m_fOptimize = FALSE;
121     m_tkSysObject = 0;
122     m_tkSysString = 0;
123     m_tkSysValue = 0;
124     m_tkSysEnum = 0;
125
126     m_pVTable = NULL;
127     m_pMarshal = NULL;
128     m_pPInvoke = NULL;
129
130     m_fReportProgress = TRUE;
131     m_tkCurrentCVOwner = 1; // module
132     m_pOutputBuffer = NULL;
133
134     m_dwSubsystem = (DWORD)-1;
135     m_dwComImageFlags = COMIMAGE_FLAGS_ILONLY;
136     m_dwFileAlignment = 0;
137     m_stBaseAddress = 0;
138     m_stSizeOfStackReserve = 0;
139     m_dwCeeFileFlags = ICEE_CREATE_FILE_PURE_IL;
140
141     g_szSourceFileName[0] = 0;
142
143     m_guidLang = CorSym_LanguageType_ILAssembly;
144     m_guidLangVendor = CorSym_LanguageVendor_Microsoft;
145     m_guidDoc = CorSym_DocumentType_Text;
146     for(int i=0; i<INSTR_POOL_SIZE; i++) m_Instr[i].opcode = -1;
147     m_wzResourceFile = NULL;
148     m_wzKeySourceName = NULL;
149     OnErrGo = false;
150     bClock = NULL;
151
152     m_pbsMD = NULL;
153
154     m_pOutputBuffer = new BYTE[OUTPUT_BUFFER_SIZE];
155
156     m_pCurOutputPos = m_pOutputBuffer;
157     m_pEndOutputPos = m_pOutputBuffer + OUTPUT_BUFFER_SIZE;
158
159     m_crImplList = new mdTypeRef[MAX_INTERFACES_IMPLEMENTED];
160     m_nImplListSize = MAX_INTERFACES_IMPLEMENTED;
161
162     m_pManifest = new AsmMan((void*)this);
163
164     dummyClass = new Class(NULL);
165     indexKeywords(&indxKeywords);
166 }
167
168
169 Assembler::~Assembler()
170 {
171     if(m_pbsMD) delete m_pbsMD;
172
173     if(m_pMarshal) delete m_pMarshal;
174     if(m_pManifest) delete m_pManifest;
175     if(m_pPInvoke) delete m_pPInvoke;
176
177     if(m_pVTable) delete m_pVTable;
178
179     m_lstGlobalLabel.RESET(true);
180     m_lstGlobalFixup.RESET(true);
181     m_hshClass.RESET(false);
182     m_lstClass.RESET(true);
183     while((m_ClassStack.POP()));
184     while(m_CustomDescrListStack.POP());
185     m_pCurClass = NULL;
186     dummyClass->m_szFQN = NULL;
187     delete dummyClass;
188
189     if (m_pOutputBuffer)    delete [] m_pOutputBuffer;
190     if (m_crImplList)       delete [] m_crImplList;
191     if (m_TyParList)        delete m_TyParList;
192
193     if (m_pCeeFileGen != NULL) {
194         if (m_pCeeFile)
195             m_pCeeFileGen->DestroyCeeFile(&m_pCeeFile);
196
197         DestroyICeeFileGen(&m_pCeeFileGen);
198
199         m_pCeeFileGen = NULL;
200     }
201
202     while((m_szNamespace = m_NSstack.POP())) ;
203     delete [] m_szFullNS;
204
205     m_DocWriterList.RESET(true);
206
207     m_MethodBodyList.RESET(true);
208     
209     m_TypeDefDList.RESET(true);
210
211     if (m_pSymWriter != NULL)
212     {
213         m_pSymWriter->Close();
214         m_pSymWriter->Release();
215         m_pSymWriter = NULL;
216     }
217     if (m_pImporter != NULL)
218     {
219         m_pImporter->Release();
220         m_pImporter = NULL;
221     }
222     if (m_pEmitter != NULL)
223     {
224         m_pEmitter->Release();
225         m_pEmitter = NULL;
226     }
227
228     if (m_pDisp != NULL)
229     {
230         m_pDisp->Release();
231         m_pDisp = NULL;
232     }
233
234 #ifdef FEATURE_PAL
235     if (g_loader != NULL)
236     {
237         g_loader->Finish();
238     }
239 #endif
240
241 }
242
243
244 BOOL Assembler::Init()
245 {
246 #ifdef FEATURE_PAL
247     g_loader = CoreCLRLoader::Create(g_pszExeFile);
248     if (g_loader == NULL)
249     {
250         return FALSE;
251     }
252     metaDataGetDispenser = (MetaDataGetDispenserFunc)g_loader->LoadFunction("MetaDataGetDispenser");
253 #else
254     metaDataGetDispenser = (MetaDataGetDispenserFunc)MetaDataGetDispenser;
255 #endif // FEATURE_PAL
256     if (m_pCeeFileGen != NULL) {
257         if (m_pCeeFile)
258             m_pCeeFileGen->DestroyCeeFile(&m_pCeeFile);
259         
260         DestroyICeeFileGen(&m_pCeeFileGen);
261
262         m_pCeeFileGen = NULL;
263     }
264
265     if (FAILED(CreateICeeFileGen(&m_pCeeFileGen))) return FALSE;
266
267     if (FAILED(m_pCeeFileGen->CreateCeeFileEx(&m_pCeeFile,(ULONG)m_dwCeeFileFlags))) return FALSE;
268
269     if (FAILED(m_pCeeFileGen->GetSectionCreate(m_pCeeFile, ".il", sdReadOnly, &m_pILSection))) return FALSE;
270     if (FAILED(m_pCeeFileGen->GetSectionCreate (m_pCeeFile, ".sdata", sdReadWrite, &m_pGlobalDataSection))) return FALSE;
271     if (FAILED(m_pCeeFileGen->GetSectionCreate (m_pCeeFile, ".tls", sdReadWrite, &m_pTLSSection))) return FALSE;
272
273     return TRUE;
274 }
275
276 void Assembler::SetDLL(BOOL IsDll)
277 {
278     HRESULT OK;
279     OK = m_pCeeFileGen->SetDllSwitch(m_pCeeFile, IsDll);
280     _ASSERTE(SUCCEEDED(OK));
281
282     m_fDLL = IsDll;
283 }
284
285 void Assembler::SetOBJ(BOOL IsObj)
286 {
287     HRESULT OK;
288     OK = m_pCeeFileGen->SetObjSwitch(m_pCeeFile, IsObj);
289     _ASSERTE(SUCCEEDED(OK));
290
291     m_fOBJ = IsObj;
292 }
293
294
295 void Assembler::ResetArgNameList()
296 {
297     if(m_firstArgName) delArgNameList(m_firstArgName);
298     m_firstArgName = NULL;
299     m_lastArgName = NULL;
300 }
301
302 void Assembler::ResetForNextMethod()
303 {
304
305     ResetArgNameList();
306
307     m_CurPC         = 0;
308     m_pCurOutputPos = m_pOutputBuffer;
309     m_State         = STATE_OK;
310     m_pCurMethod = NULL;
311 }
312
313 void Assembler::ResetLineNumbers()
314 {
315     // reset line number information
316     m_ulLastDebugLine = 0xFFFFFFFF;
317     m_ulLastDebugColumn = 0xFFFFFFFF;
318     m_ulLastDebugLineEnd = 0xFFFFFFFF;
319     m_ulLastDebugColumnEnd = 0xFFFFFFFF;
320 }
321
322 BOOL Assembler::AddMethod(Method *pMethod)
323 {
324     BOOL                     fIsInterface=FALSE, fIsImport=FALSE;
325     ULONG                    PEFileOffset=0;
326
327     _ASSERTE(m_pCeeFileGen != NULL);
328     if (pMethod == NULL)
329     {
330         report->error("pMethod == NULL");
331         return FALSE;
332     }
333     if(pMethod->m_pClass != NULL)
334     {
335         fIsInterface = IsTdInterface(pMethod->m_pClass->m_Attr);
336         fIsImport = IsTdImport(pMethod->m_pClass->m_Attr);
337     }
338     if(m_CurPC)
339     {
340         char sz[1024];
341         sz[0] = 0;
342         if(fIsImport) strcat_s(sz,1024," imported");
343         if(IsMdAbstract(pMethod->m_Attr)) strcat_s(sz,1024," abstract");
344         if(IsMdPinvokeImpl(pMethod->m_Attr)) strcat_s(sz,1024," pinvoke");
345         if(!IsMiIL(pMethod->m_wImplAttr)) strcat_s(sz,1024," non-IL");
346         if(IsMiRuntime(pMethod->m_wImplAttr)) strcat_s(sz,1024," runtime-supplied");
347         if(IsMiInternalCall(pMethod->m_wImplAttr)) strcat_s(sz,1024," an internal call");
348         if(strlen(sz))
349         {
350             report->error("Method cannot have body if it is%s\n",sz);
351         }
352     }
353     else // method has no body
354     {
355         if(fIsImport || IsMdAbstract(pMethod->m_Attr) || IsMdPinvokeImpl(pMethod->m_Attr)
356            || IsMiRuntime(pMethod->m_wImplAttr) || IsMiInternalCall(pMethod->m_wImplAttr)) return TRUE;
357         if(OnErrGo)
358         {
359             report->error("Method has no body\n");
360             return TRUE;
361         }
362         else
363         {
364             report->warn("Method has no body, 'ret' emitted\n");
365             Instr* pIns = GetInstr();
366             if(pIns)
367             {
368                 memset(pIns,0,sizeof(Instr));
369                 pIns->opcode = CEE_RET;
370                 EmitOpcode(pIns);
371             }
372         }
373     }
374
375     if(pMethod->m_Locals.COUNT()) pMethod->m_LocalsSig=0x11000001; // placeholder, the real token 2b defined in EmitMethod
376
377     COR_ILMETHOD_FAT fatHeader;
378     fatHeader.SetFlags(pMethod->m_Flags);
379     fatHeader.SetMaxStack(pMethod->m_MaxStack);
380     fatHeader.SetLocalVarSigTok(pMethod->m_LocalsSig);
381     fatHeader.SetCodeSize(m_CurPC);
382     bool moreSections = (pMethod->m_dwNumExceptions != 0);
383
384     // if max stack is specified <8, force fat header, otherwise (with tiny header) it will default to 8
385     if((fatHeader.GetMaxStack() < 8)&&(fatHeader.GetLocalVarSigTok()==0)&&(fatHeader.GetCodeSize()<64)&&(!moreSections))
386         fatHeader.SetFlags(fatHeader.GetFlags() | CorILMethod_InitLocals); //forces fat header but does nothing else, since LocalVarSigTok==0
387
388     unsigned codeSize = m_CurPC;
389     unsigned codeSizeAligned = codeSize;
390     if (moreSections)
391         codeSizeAligned = (codeSizeAligned + 3) & ~3;    // to insure EH section aligned
392
393     unsigned headerSize = COR_ILMETHOD::Size(&fatHeader, moreSections);
394     unsigned ehSize     = COR_ILMETHOD_SECT_EH::Size(pMethod->m_dwNumExceptions, pMethod->m_ExceptionList);
395     unsigned totalSize  = headerSize + codeSizeAligned + ehSize;
396
397     BYTE* outBuff;
398     BYTE* endbuf;
399     BinStr* pbsBody;
400     if((pbsBody = new BinStr())==NULL) return FALSE;
401     if((outBuff = pbsBody->getBuff(totalSize))==NULL) return FALSE;
402     endbuf = &outBuff[totalSize];
403
404     // Emit the header
405     outBuff += COR_ILMETHOD::Emit(headerSize, &fatHeader, moreSections, outBuff);
406
407     pMethod->m_pCode = outBuff;
408     pMethod->m_headerOffset= PEFileOffset;
409     pMethod->m_methodOffset= PEFileOffset + headerSize;
410     pMethod->m_CodeSize = codeSize;
411
412     // Emit the code
413     if (codeSizeAligned)
414     {
415         memset(outBuff,0,codeSizeAligned);
416         memcpy(outBuff, m_pOutputBuffer, codeSize);
417         outBuff += codeSizeAligned;
418     }
419
420     if(pMethod->m_dwNumExceptions)
421     {
422         // Validate the eh
423         COR_ILMETHOD_SECT_EH_CLAUSE_FAT* pEx;
424         DWORD   TryEnd,HandlerEnd, dwEx, dwEf;
425         for(dwEx = 0, pEx = pMethod->m_ExceptionList; dwEx < pMethod->m_dwNumExceptions; dwEx++, pEx++)
426         {
427             if(pEx->GetTryOffset() > m_CurPC) // i.e., pMethod->m_CodeSize
428             {
429                 report->error("Invalid SEH clause #%d: Try block starts beyond code size\n",dwEx+1);
430             }
431             TryEnd = pEx->GetTryOffset()+pEx->GetTryLength();
432             if(TryEnd > m_CurPC)
433             {
434                 report->error("Invalid SEH clause #%d: Try block ends beyond code size\n",dwEx+1);
435             }
436             if(pEx->GetHandlerOffset() > m_CurPC)
437             {
438                 report->error("Invalid SEH clause #%d: Handler block starts beyond code size\n",dwEx+1);
439             }
440             HandlerEnd = pEx->GetHandlerOffset()+pEx->GetHandlerLength();
441             if(HandlerEnd > m_CurPC)
442             {
443                 report->error("Invalid SEH clause #%d: Handler block ends beyond code size\n",dwEx+1);
444             }
445             if(pEx->Flags & COR_ILEXCEPTION_CLAUSE_FILTER)
446             {
447                 if(!((pEx->GetFilterOffset() >= TryEnd)||(pEx->GetTryOffset() >= HandlerEnd)))
448                 {
449                     report->error("Invalid SEH clause #%d: Try and Filter/Handler blocks overlap\n",dwEx+1);
450                 }
451                 for(dwEf = 0; dwEf < pMethod->m_dwNumEndfilters; dwEf++)
452                 {
453                     if(pMethod->m_EndfilterOffsetList[dwEf] == pEx->GetHandlerOffset()) break;
454                 }
455                 if(dwEf >= pMethod->m_dwNumEndfilters)
456                 {
457                     report->error("Invalid SEH clause #%d: Filter block separated from Handler, or not ending with endfilter\n",dwEx+1);
458                 }
459             }
460             else
461             if(!((pEx->GetHandlerOffset() >= TryEnd)||(pEx->GetTryOffset() >= HandlerEnd)))
462             {
463                 report->error("Invalid SEH clause #%d: Try and Handler blocks overlap\n",dwEx+1);
464             }
465
466         }
467         // Emit the eh
468         outBuff += COR_ILMETHOD_SECT_EH::Emit(ehSize, pMethod->m_dwNumExceptions,
469                                     pMethod->m_ExceptionList, false, outBuff);
470     }
471     _ASSERTE(outBuff == endbuf);
472
473     pMethod->m_pbsBody = pbsBody;
474
475     LocalMemberRefFixup*             pMRF;
476     while((pMRF = pMethod->m_LocalMemberRefFixupList.POP()))
477     {
478         pMRF->offset += (size_t)(pMethod->m_pCode);
479         m_LocalMemberRefFixupList.PUSH(pMRF); // transfer MRF to assembler's list
480     }
481
482     if(m_fReportProgress)
483     {
484         if (pMethod->IsGlobalMethod())
485             report->msg("Assembled global method %s\n", pMethod->m_szName);
486         else report->msg("Assembled method %s::%s\n", pMethod->m_pClass->m_szFQN,
487                   pMethod->m_szName);
488     }
489     return TRUE;
490 }
491
492
493 BOOL Assembler::EmitMethodBody(Method* pMethod, BinStr* pbsOut)
494 {
495     if(pMethod)
496     {
497         BinStr* pbsBody = pMethod->m_pbsBody;
498         unsigned totalSize;
499         if(pbsBody && (totalSize = pbsBody->length()))
500         {
501             unsigned headerSize = pMethod->m_methodOffset-pMethod->m_headerOffset;
502             MethodBody* pMB = NULL;
503             // ----------emit locals signature-------------------
504             unsigned uLocals;
505             if((uLocals = pMethod->m_Locals.COUNT()))
506             {
507                 VarDescr* pVD;
508                 BinStr*   pbsSig = new BinStr();
509                 unsigned cnt;
510                 HRESULT hr;
511                 DWORD   cSig;
512                 const COR_SIGNATURE* mySig;
513
514                 pbsSig->appendInt8(IMAGE_CEE_CS_CALLCONV_LOCAL_SIG);
515                 cnt = CorSigCompressData(uLocals,pbsSig->getBuff(5));
516                 pbsSig->remove(5-cnt);
517                 for(cnt = 0; (pVD = pMethod->m_Locals.PEEK(cnt)); cnt++)
518                 {
519                     if(pVD->pbsSig) pbsSig->append(pVD->pbsSig);
520                     else
521                     {
522                         report->error("Undefined type of local var slot %d in method %s\n",cnt,pMethod->m_szName);
523                         pbsSig->appendInt8(ELEMENT_TYPE_I4);
524                     }
525                 }
526
527                 cSig = pbsSig->length();
528                 mySig = (const COR_SIGNATURE *)(pbsSig->ptr());
529
530                 if (cSig > 1)    // non-empty signature
531                 {
532                     hr = m_pEmitter->GetTokenFromSig(mySig, cSig, &pMethod->m_LocalsSig);
533                     _ASSERTE(SUCCEEDED(hr));
534                 }
535                 delete pbsSig;
536                 COR_ILMETHOD_FAT* pFH; // Fat header guaranteed, because there are local vars
537                 pFH = (COR_ILMETHOD_FAT*)(pMethod->m_pbsBody->ptr());
538                 pFH->SetLocalVarSigTok(pMethod->m_LocalsSig);
539             }
540             //--------------------------------------------------------------------------------
541             if(m_fGeneratePDB && (m_pSymWriter != NULL))
542             {
543                 m_pSymWriter->OpenMethod(pMethod->m_Tok);
544                 ULONG N = pMethod->m_LinePCList.COUNT();
545                 if(pMethod->m_fEntryPoint) m_pSymWriter->SetUserEntryPoint(pMethod->m_Tok);
546                 if(N)
547                 {
548                     LinePC  *pLPC;
549                     ULONG32  *offsets=new ULONG32[N], *lines = new ULONG32[N], *columns = new ULONG32[N];
550                     ULONG32  *endlines=new ULONG32[N], *endcolumns=new ULONG32[N];
551                     if(offsets && lines && columns && endlines && endcolumns)
552                     {
553                         DocWriter* pDW;
554                         unsigned j=0;
555                         while((pDW = m_DocWriterList.PEEK(j++)))
556                         {
557                             if((m_pSymDocument = pDW->pWriter))
558                             {
559                                 int i, n;
560                                 for(i=0, n=0; (pLPC = pMethod->m_LinePCList.PEEK(i)); i++)
561                                 {
562                                     if(pLPC->pWriter == m_pSymDocument)
563                                     {
564                                         offsets[n] = pLPC->PC;
565                                         lines[n] = pLPC->Line;
566                                         columns[n] = pLPC->Column;
567                                         endlines[n] = pLPC->LineEnd;
568                                         endcolumns[n] = pLPC->ColumnEnd;
569                                         n++;
570                                     }
571                                 }
572                                 if(n) m_pSymWriter->DefineSequencePoints(m_pSymDocument,n,
573                                                                    offsets,lines,columns,endlines,endcolumns);
574                             } // end if(pSymDocument)
575                         } // end while(pDW = next doc.writer)
576                         pMethod->m_LinePCList.RESET(true);
577                     }
578                     else report->error("\nOutOfMemory!\n");
579                     delete [] offsets;
580                     delete [] lines;
581                     delete [] columns;
582                     delete [] endlines;
583                     delete [] endcolumns;
584                 }//enf if(N)
585                 HRESULT hrr;
586                 if(pMethod->m_ulLines[1])
587                     hrr = m_pSymWriter->SetMethodSourceRange(m_pSymDocument,pMethod->m_ulLines[0], pMethod->m_ulColumns[0],
588                                                        m_pSymDocument,pMethod->m_ulLines[1], pMethod->m_ulColumns[1]);
589                 EmitScope(&(pMethod->m_MainScope)); // recursively emits all nested scopes
590
591                 m_pSymWriter->CloseMethod();
592             } // end if(fIncludeDebugInfo)
593             //-----------------------------------------------------
594
595             if(m_fFoldCode)
596             {
597                 for(int k=0; (pMB = m_MethodBodyList.PEEK(k)) != NULL; k++)
598                 {
599                     if((pMB->pbsBody->length() == totalSize)
600                       && (memcmp(pMB->pbsBody->ptr(), pbsBody->ptr(),totalSize)==0))
601                     break;
602                 }
603                 if(pMB)
604                 {
605                     pMethod->m_headerOffset= pMB->RVA;
606                     pMethod->m_methodOffset= pMB->RVA + headerSize;
607                     pMethod->m_pCode = pMB->pCode;
608                     delete pbsBody;
609                     pMethod->m_pbsBody = NULL;
610                     m_dwMethodsFolded++;
611                 }
612             }
613             if(pMB == NULL)
614             {
615                 BYTE* outBuff;
616                 unsigned align = (headerSize == 1)? 1 : 4;
617                 ULONG    PEFileOffset, methodRVA;
618                 if(m_fENCMode)
619                 {
620                     if(pbsOut)
621                     {
622                         PEFileOffset = pbsOut->length();
623                         align--;
624                         while(PEFileOffset & align)
625                         {
626                             pbsOut->appendInt8(0);
627                             PEFileOffset++;
628                         }
629                         pbsOut->append(pbsBody);
630                         outBuff = (BYTE*)(pbsOut->ptr()) + (pbsOut->length() - pbsBody->length());
631                     }
632                     else return FALSE;
633
634                 }
635                 else
636                 {
637                     if (FAILED(m_pCeeFileGen->GetSectionBlock (m_pILSection, totalSize,
638                             align, (void **) &outBuff)))    return FALSE;
639                     memcpy(outBuff,pbsBody->ptr(),totalSize);
640                     // The offset where we start, (not where the alignment bytes start!
641                     if (FAILED(m_pCeeFileGen->GetSectionDataLen (m_pILSection, &PEFileOffset)))
642                         return FALSE;
643                     PEFileOffset -= totalSize;
644                 }
645
646                 pMethod->m_pCode = outBuff + headerSize;
647                 pMethod->m_headerOffset= PEFileOffset;
648                 pMethod->m_methodOffset= PEFileOffset + headerSize;
649                 DoDeferredILFixups(pMethod);
650
651                 if(m_fENCMode) methodRVA = PEFileOffset;
652                 else m_pCeeFileGen->GetMethodRVA(m_pCeeFile, PEFileOffset,&methodRVA);
653
654                 pMethod->m_headerOffset= methodRVA;
655                 pMethod->m_methodOffset= methodRVA + headerSize;
656                 if(m_fFoldCode)
657                 {
658                     if((pMB = new MethodBody)==NULL) return FALSE;
659                     pMB->pbsBody = pbsBody;
660                     pMB->RVA = methodRVA;
661                     pMB->pCode = pMethod->m_pCode;
662                     m_MethodBodyList.PUSH(pMB);
663                 }
664                 //else
665                 //    delete pbsBody;
666                 //pMethod->m_pbsBody = NULL;
667             }
668             m_pEmitter->SetRVA(pMethod->m_Tok,pMethod->m_headerOffset);
669         }
670         return TRUE;
671     }
672     else return FALSE;
673 }
674
675 ImportDescriptor* Assembler::EmitImport(BinStr* DllName)
676 {
677     int i = 0, l = 0;
678     ImportDescriptor*   pID;
679     char* sz=NULL;
680
681     if(DllName) l = DllName->length();  // No zero terminator here!
682     if(l)
683     {
684         sz = (char*)DllName->ptr();
685         while((pID=m_ImportList.PEEK(i++)))
686         {
687             if((pID->dwDllName== (DWORD) l)&& !memcmp(pID->szDllName,sz,l)) return pID;
688         }
689     }
690     else
691     {
692         while((pID=m_ImportList.PEEK(i++)))
693         {
694             if(pID->dwDllName==0) return pID;
695         }
696     }
697     if((pID = new ImportDescriptor(sz,l)))
698     {
699         m_ImportList.PUSH(pID);
700         pID->mrDll = TokenFromRid(m_ImportList.COUNT(),mdtModuleRef);
701         return pID;
702     }
703     else report->error("Failed to allocate import descriptor\n");
704     return NULL;
705 }
706
707 void Assembler::EmitImports()
708 {
709     WCHAR*               wzDllName=&wzUniBuf[0];
710     ImportDescriptor*   pID;
711     int i;
712     mdToken tk;
713     for(i=0; (pID = m_ImportList.PEEK(i)); i++)
714     {
715         WszMultiByteToWideChar(g_uCodePage,0,pID->szDllName,-1,wzDllName,dwUniBuf-1);
716         if(FAILED(m_pEmitter->DefineModuleRef(             // S_OK or error.
717                             wzDllName,            // [IN] DLL name
718                             &tk)))      // [OUT] returned
719             report->error("Failed to define module ref '%s'\n",pID->szDllName);
720         else
721             _ASSERTE(tk == pID->mrDll);
722     }
723 }
724
725 HRESULT Assembler::EmitPinvokeMap(mdToken tk, PInvokeDescriptor* pDescr)
726 {
727     WCHAR*               wzAlias=&wzUniBuf[0];
728
729     if(pDescr->szAlias) WszMultiByteToWideChar(g_uCodePage,0,pDescr->szAlias,-1,wzAlias,dwUniBuf-1);
730
731     return m_pEmitter->DefinePinvokeMap(        // Return code.
732                         tk,                     // [IN] FieldDef, MethodDef or MethodImpl.
733                         pDescr->dwAttrs,        // [IN] Flags used for mapping.
734                         (LPCWSTR)wzAlias,       // [IN] Import name.
735                         pDescr->mrDll);         // [IN] ModuleRef token for the target DLL.
736 }
737
738 void Assembler::EmitScope(Scope* pSCroot)
739 {
740     static ULONG32          scopeID;
741     static ARG_NAME_LIST    *pVarList;
742     int                     i;
743     WCHAR*                  wzVarName=&wzUniBuf[0];
744     char*                   szPhonyName=(char*)&wzUniBuf[dwUniBuf >> 1];
745     Scope*                  pSC = pSCroot;
746     if(pSC && m_pSymWriter)
747     {
748         if(SUCCEEDED(m_pSymWriter->OpenScope(pSC->dwStart,&scopeID)))
749         {
750             if(pSC->pLocals)
751             {
752                 for(pVarList = pSC->pLocals; pVarList; pVarList = pVarList->pNext)
753                 {
754                     if(pVarList->pSig)
755                     {
756                         if((pVarList->szName)&&(*(pVarList->szName))) strcpy_s(szPhonyName,dwUniBuf >> 1,pVarList->szName);
757                         else sprintf_s(szPhonyName,(dwUniBuf >> 1),"V_%d",pVarList->dwAttr);
758
759                         WszMultiByteToWideChar(g_uCodePage,0,szPhonyName,-1,wzVarName,dwUniBuf >> 1);
760
761                         m_pSymWriter->DefineLocalVariable(wzVarName,0,pVarList->pSig->length(),
762                             (BYTE*)pVarList->pSig->ptr(),ADDR_IL_OFFSET,pVarList->dwAttr,0,0,0,0);
763                     }
764                     else
765                     {
766                         report->error("Local Var '%s' has no signature\n",pVarList->szName);
767                     }
768                 }
769             }
770             for(i = 0; (pSC = pSCroot->SubScope.PEEK(i)); i++) EmitScope(pSC);
771             m_pSymWriter->CloseScope(pSCroot->dwEnd);
772         }
773     }
774 }
775
776 BOOL Assembler::EmitMethod(Method *pMethod)
777 {
778 // Emit the metadata for a method definition
779     BOOL                fSuccess = FALSE;
780     WCHAR*              wzMemberName=&wzUniBuf[0];
781     BOOL                fIsInterface;
782     DWORD               cSig;
783     ULONG               methodRVA = 0;
784     mdMethodDef         MethodToken;
785     mdTypeDef           ClassToken = mdTypeDefNil;
786     char                *pszMethodName;
787     COR_SIGNATURE       *mySig;
788
789     _ASSERTE((m_pCeeFileGen != NULL) && (pMethod != NULL));
790     fIsInterface = ((pMethod->m_pClass != NULL) && IsTdInterface(pMethod->m_pClass->m_Attr));
791
792
793     pszMethodName = pMethod->m_szName;
794     mySig = pMethod->m_pMethodSig;
795     cSig = pMethod->m_dwMethodCSig;
796
797     // If  this is an instance method, make certain the signature says so
798
799     if (!(pMethod->m_Attr & mdStatic))
800         *mySig |= IMAGE_CEE_CS_CALLCONV_HASTHIS;
801
802     ClassToken = (pMethod->IsGlobalMethod())? mdTokenNil
803                                     : pMethod->m_pClass->m_cl;
804     // Convert name to UNICODE
805     WszMultiByteToWideChar(g_uCodePage,0,pszMethodName,-1,wzMemberName,dwUniBuf-1);
806
807     if(IsMdPrivateScope(pMethod->m_Attr))
808     {
809         WCHAR* p = wcsstr(wzMemberName,W("$PST06"));
810         if(p) *p = 0;
811     }
812
813     if (FAILED(m_pEmitter->DefineMethod(ClassToken,       // parent class
814                                       wzMemberName,     // member name
815                                       pMethod->m_Attr & ~mdReservedMask,  // member attributes
816                                       mySig, // member signature
817                                       cSig,
818                                       methodRVA,                // RVA
819                                       pMethod->m_wImplAttr,                // implflags
820                                       &MethodToken)))
821     {
822         report->error("Failed to define method '%s'\n",pszMethodName);
823         goto exit;
824     }
825     pMethod->m_Tok = MethodToken;
826     //--------------------------------------------------------------------------------
827     // the only way to set mdRequireSecObject:
828     if(pMethod->m_Attr & mdRequireSecObject)
829     {
830         mdToken tkPseudoClass;
831         if(FAILED(m_pEmitter->DefineTypeRefByName(1, COR_REQUIRES_SECOBJ_ATTRIBUTE, &tkPseudoClass)))
832             report->error("Unable to define type reference '%s'\n", COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI);
833         else
834         {
835             mdToken tkPseudoCtor;
836             BYTE bSig[3] = {IMAGE_CEE_CS_CALLCONV_HASTHIS,0,ELEMENT_TYPE_VOID};
837             if(FAILED(m_pEmitter->DefineMemberRef(tkPseudoClass, W(".ctor"), (PCCOR_SIGNATURE)bSig, 3, &tkPseudoCtor)))
838                 report->error("Unable to define member reference '%s::.ctor'\n", COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI);
839             else DefineCV(new CustomDescr(MethodToken,tkPseudoCtor,NULL));
840         }
841     }
842
843     if (pMethod->m_NumTyPars)
844     {
845         ULONG i;
846         mdToken* ptk;
847         mdToken tk;
848         for(i = 0; i < pMethod->m_NumTyPars; i++)
849         {
850             //ptk = (pMethod->m_TyParBounds[i] == NULL)? NULL :  (mdToken*)(pMethod->m_TyParBounds[i]->ptr());
851             //if(FAILED(m_pEmitter->DefineGenericParam(MethodToken,i,0,pMethod->m_TyParNames[i],0,ptk,&tk)))
852             ptk = (pMethod->m_TyPars[i].Bounds() == NULL)? NULL :  (mdToken*)(pMethod->m_TyPars[i].Bounds()->ptr());
853             if(FAILED(m_pEmitter->DefineGenericParam(MethodToken,i,pMethod->m_TyPars[i].Attrs(),pMethod->m_TyPars[i].Name(),0,ptk,&tk)))
854                 report->error("Unable to define generic param'\n");
855             else
856                 EmitCustomAttributes(tk, pMethod->m_TyPars[i].CAList());
857         }
858     }
859     //--------------------------------------------------------------------------------
860     EmitSecurityInfo(MethodToken,
861                      pMethod->m_pPermissions,
862                      pMethod->m_pPermissionSets);
863     //--------------------------------------------------------------------------------
864     if (pMethod->m_fEntryPoint)
865     {
866         if(fIsInterface) report->error("Entrypoint in Interface: Method '%s'\n",pszMethodName);
867
868         if (FAILED(m_pCeeFileGen->SetEntryPoint(m_pCeeFile, MethodToken)))
869         {
870             report->error("Failed to set entry point for method '%s'\n",pszMethodName);
871             goto exit;
872         }
873
874     }
875     //--------------------------------------------------------------------------------
876     if(IsMdPinvokeImpl(pMethod->m_Attr))
877     {
878         if(pMethod->m_pPInvoke)
879         {
880             HRESULT hr;
881             if(pMethod->m_pPInvoke->szAlias == NULL) pMethod->m_pPInvoke->szAlias = pszMethodName;
882             hr = EmitPinvokeMap(MethodToken,pMethod->m_pPInvoke);
883             if(pMethod->m_pPInvoke->szAlias == pszMethodName) pMethod->m_pPInvoke->szAlias = NULL;
884
885             if(FAILED(hr))
886             {
887                 report->error("Failed to set PInvoke map for method '%s'\n",pszMethodName);
888                 goto exit;
889             }
890         }
891     }
892
893     { // add parameters to metadata
894         void const *pValue=NULL;
895         ULONG       cbValue;
896         DWORD dwCPlusTypeFlag=0;
897         mdParamDef pdef;
898         WCHAR* wzParName=&wzUniBuf[0];
899         char*  szPhonyName=(char*)&wzUniBuf[dwUniBuf >> 1];
900         if(pMethod->m_dwRetAttr || pMethod->m_pRetMarshal || pMethod->m_RetCustDList.COUNT())
901         {
902             if(pMethod->m_pRetValue)
903             {
904                 dwCPlusTypeFlag= (DWORD)*(pMethod->m_pRetValue->ptr());
905                 pValue = (void const *)(pMethod->m_pRetValue->ptr()+1);
906                 cbValue = pMethod->m_pRetValue->length()-1;
907                 if(dwCPlusTypeFlag == ELEMENT_TYPE_STRING) cbValue /= sizeof(WCHAR);
908             }
909             else
910             {
911                 pValue = NULL;
912                 cbValue = (ULONG)-1;
913                 dwCPlusTypeFlag=0;
914             }
915             m_pEmitter->DefineParam(MethodToken,0,NULL,pMethod->m_dwRetAttr,dwCPlusTypeFlag,pValue,cbValue,&pdef);
916
917             if(pMethod->m_pRetMarshal)
918             {
919                 if(FAILED(m_pEmitter->SetFieldMarshal (
920                                             pdef,                       // [IN] given a fieldDef or paramDef token
921                             (PCCOR_SIGNATURE)(pMethod->m_pRetMarshal->ptr()),   // [IN] native type specification
922                                             pMethod->m_pRetMarshal->length())))  // [IN] count of bytes of pvNativeType
923                     report->error("Failed to set param marshaling for return\n");
924
925             }
926             EmitCustomAttributes(pdef, &(pMethod->m_RetCustDList));
927         }
928         for(ARG_NAME_LIST *pAN=pMethod->m_firstArgName; pAN; pAN = pAN->pNext)
929         {
930             if(pAN->nNum >= 65535)
931             {
932                 report->error("Method '%s': Param.sequence number (%d) exceeds 65535, unable to define parameter\n",pszMethodName,pAN->nNum+1);
933                 continue;
934             }
935             if(pAN->dwName) strcpy_s(szPhonyName,dwUniBuf >> 1,pAN->szName);
936             else sprintf_s(szPhonyName,(dwUniBuf >> 1),"A_%d",pAN->nNum);
937
938             WszMultiByteToWideChar(g_uCodePage,0,szPhonyName,-1,wzParName,dwUniBuf >> 1);
939
940             if(pAN->pValue)
941             {
942                 dwCPlusTypeFlag= (DWORD)*(pAN->pValue->ptr());
943                 pValue = (void const *)(pAN->pValue->ptr()+1);
944                 cbValue = pAN->pValue->length()-1;
945                 if(dwCPlusTypeFlag == ELEMENT_TYPE_STRING) cbValue /= sizeof(WCHAR);
946             }
947             else
948             {
949                 pValue = NULL;
950                 cbValue = (ULONG)-1;
951                 dwCPlusTypeFlag=0;
952             }
953             m_pEmitter->DefineParam(MethodToken,pAN->nNum+1,wzParName,pAN->dwAttr,dwCPlusTypeFlag,pValue,cbValue,&pdef);
954             if(pAN->pMarshal)
955             {
956                 if(FAILED(m_pEmitter->SetFieldMarshal (
957                                             pdef,                       // [IN] given a fieldDef or paramDef token
958                             (PCCOR_SIGNATURE)(pAN->pMarshal->ptr()),   // [IN] native type specification
959                                             pAN->pMarshal->length())))  // [IN] count of bytes of pvNativeType
960                     report->error("Failed to set param marshaling for '%s'\n",pAN->szName);
961             }
962             EmitCustomAttributes(pdef, &(pAN->CustDList));
963         }
964     }
965     fSuccess = TRUE;
966     //--------------------------------------------------------------------------------
967     // Update method implementations for this method
968     {
969         MethodImplDescriptor*   pMID;
970         int i;
971         for(i=0;(pMID = pMethod->m_MethodImplDList.PEEK(i));i++)
972         {
973             pMID->m_tkImplementingMethod = MethodToken;
974             // don't delete it here, it's still in the general list
975         }
976     }
977     //--------------------------------------------------------------------------------
978     EmitCustomAttributes(MethodToken, &(pMethod->m_CustomDescrList));
979 exit:
980     if (fSuccess == FALSE) m_State = STATE_FAIL;
981     return fSuccess;
982 }
983
984 BOOL Assembler::EmitMethodImpls()
985 {
986     MethodImplDescriptor*   pMID;
987     BOOL ret = TRUE;
988     int i;
989     for(i=0; (pMID = m_MethodImplDList.PEEK(i)); i++)
990     {
991         if(m_fENCMode && (!pMID->m_fNew)) continue;
992         pMID->m_tkImplementingMethod = ResolveLocalMemberRef(pMID->m_tkImplementingMethod);
993         pMID->m_tkImplementedMethod = ResolveLocalMemberRef(pMID->m_tkImplementedMethod);
994         if(FAILED(m_pEmitter->DefineMethodImpl( pMID->m_tkDefiningClass,
995                                                 pMID->m_tkImplementingMethod,
996                                                 pMID->m_tkImplementedMethod)))
997         {
998             report->error("Failed to define Method Implementation");
999             ret = FALSE;
1000         }
1001         pMID->m_fNew = FALSE;
1002     }// end while
1003     return ret;
1004 }
1005
1006 mdToken Assembler::ResolveLocalMemberRef(mdToken tok)
1007 {
1008     if(TypeFromToken(tok) == 0x99000000)
1009     {
1010         tok = RidFromToken(tok);
1011         if(tok) tok = m_LocalMethodRefDList.PEEK(tok-1)->m_tkResolved;
1012     }
1013     else if(TypeFromToken(tok) == 0x98000000)
1014     {
1015         tok = RidFromToken(tok);
1016         if(tok) tok = m_LocalFieldRefDList.PEEK(tok-1)->m_tkResolved;
1017     }
1018     return tok;
1019 }
1020
1021 BOOL Assembler::EmitEvent(EventDescriptor* pED)
1022 {
1023     mdMethodDef mdAddOn=mdMethodDefNil,
1024                 mdRemoveOn=mdMethodDefNil,
1025                 mdFire=mdMethodDefNil,
1026                 *mdOthers;
1027     int                 nOthers;
1028     WCHAR*              wzMemberName=&wzUniBuf[0];
1029
1030     if(!pED) return FALSE;
1031
1032     WszMultiByteToWideChar(g_uCodePage,0,pED->m_szName,-1,wzMemberName,dwUniBuf-1);
1033
1034     mdAddOn = ResolveLocalMemberRef(pED->m_tkAddOn);
1035     if(TypeFromToken(mdAddOn) != mdtMethodDef)
1036     {
1037         report->error("Invalid Add method of event '%s'\n",pED->m_szName);
1038         return FALSE;
1039     }
1040     mdRemoveOn = ResolveLocalMemberRef(pED->m_tkRemoveOn);
1041     if(TypeFromToken(mdRemoveOn) != mdtMethodDef)
1042     {
1043         report->error("Invalid Remove method of event '%s'\n",pED->m_szName);
1044         return FALSE;
1045     }
1046     mdFire = ResolveLocalMemberRef(pED->m_tkFire);
1047     if((RidFromToken(mdFire)!=0)&&(TypeFromToken(mdFire) != mdtMethodDef))
1048     {
1049         report->error("Invalid Fire method of event '%s'\n",pED->m_szName);
1050         return FALSE;
1051     }
1052
1053     nOthers = pED->m_tklOthers.COUNT();
1054     mdOthers = new mdMethodDef[nOthers+1];
1055     if(mdOthers == NULL)
1056     {
1057         report->error("Failed to allocate Others array for event descriptor\n");
1058         nOthers = 0;
1059     }
1060     for(int j=0; j < nOthers; j++)
1061     {
1062         mdOthers[j] = ResolveLocalMemberRef((mdToken)(UINT_PTR)(pED->m_tklOthers.PEEK(j)));     // @WARNING: casting down from 'mdToken*' to 'mdToken'
1063     }
1064     mdOthers[nOthers] = mdMethodDefNil; // like null-terminator
1065
1066     if(FAILED(m_pEmitter->DefineEvent(  pED->m_tdClass,
1067                                         wzMemberName,
1068                                         pED->m_dwAttr,
1069                                         pED->m_tkEventType,
1070                                         mdAddOn,
1071                                         mdRemoveOn,
1072                                         mdFire,
1073                                         mdOthers,
1074                                         &(pED->m_edEventTok))))
1075     {
1076         report->error("Failed to define event '%s'.\n",pED->m_szName);
1077         delete [] mdOthers;
1078         return FALSE;
1079     }
1080     EmitCustomAttributes(pED->m_edEventTok, &(pED->m_CustomDescrList));
1081     return TRUE;
1082 }
1083
1084 BOOL Assembler::EmitProp(PropDescriptor* pPD)
1085 {
1086     mdMethodDef mdSet, mdGet, *mdOthers;
1087     int nOthers;
1088     WCHAR*              wzMemberName=&wzUniBuf[0];
1089
1090     if(!pPD) return FALSE;
1091
1092     WszMultiByteToWideChar(g_uCodePage,0,pPD->m_szName,-1,wzMemberName,dwUniBuf-1);
1093
1094     mdSet = ResolveLocalMemberRef(pPD->m_tkSet);
1095     if((RidFromToken(mdSet)!=0)&&(TypeFromToken(mdSet) != mdtMethodDef))
1096     {
1097         report->error("Invalid Set method of property '%s'\n",pPD->m_szName);
1098         return FALSE;
1099     }
1100     mdGet = ResolveLocalMemberRef(pPD->m_tkGet);
1101     if((RidFromToken(mdGet)!=0)&&(TypeFromToken(mdGet) != mdtMethodDef))
1102     {
1103         report->error("Invalid Get method of property '%s'\n",pPD->m_szName);
1104         return FALSE;
1105     }
1106
1107     nOthers = pPD->m_tklOthers.COUNT();
1108     mdOthers = new mdMethodDef[nOthers+1];
1109     if(mdOthers == NULL)
1110     {
1111         report->error("Failed to allocate Others array for prop descriptor\n");
1112         nOthers = 0;
1113     }
1114     for(int j=0; j < nOthers; j++)
1115     {
1116         mdOthers[j] = ResolveLocalMemberRef((mdToken)(UINT_PTR)(pPD->m_tklOthers.PEEK(j)));     // @WARNING: casting down from 'mdToken*' to 'mdToken'
1117         
1118         if((RidFromToken(mdOthers[j])!=0)&&(TypeFromToken(mdOthers[j]) != mdtMethodDef))
1119         {
1120             report->error("Invalid Other method of property '%s'\n",pPD->m_szName);
1121             delete [] mdOthers;
1122             return FALSE;
1123         }
1124         
1125     }
1126     mdOthers[nOthers] = mdMethodDefNil; // like null-terminator
1127
1128     if(FAILED(m_pEmitter->DefineProperty(   pPD->m_tdClass,
1129                                             wzMemberName,
1130                                             pPD->m_dwAttr,
1131                                             pPD->m_pSig,
1132                                             pPD->m_dwCSig,
1133                                             pPD->m_dwCPlusTypeFlag,
1134                                             pPD->m_pValue,
1135                                             pPD->m_cbValue,
1136                                             mdSet,
1137                                             mdGet,
1138                                             mdOthers,
1139                                             &(pPD->m_pdPropTok))))
1140     {
1141         report->error("Failed to define property '%s'.\n",pPD->m_szName);
1142         delete [] mdOthers;
1143         return FALSE;
1144     }
1145     EmitCustomAttributes(pPD->m_pdPropTok, &(pPD->m_CustomDescrList));
1146     return TRUE;
1147 }
1148
1149 Class *Assembler::FindCreateClass(__in __nullterminated const char *pszFQN)
1150 {
1151     Class *pSearch = NULL;
1152
1153     if(pszFQN)
1154     {
1155         dummyClass->m_szFQN = pszFQN;
1156         dummyClass->m_Hash = hash((BYTE*)pszFQN, (unsigned)strlen(pszFQN), 10);
1157         pSearch = m_hshClass.FIND(dummyClass);
1158         dummyClass->m_szFQN = NULL;
1159         dummyClass->m_Hash = 0;
1160
1161         if(!pSearch)
1162         {
1163             char* pch;
1164             DWORD dwFQN = (DWORD)strlen(pszFQN);
1165
1166             Class *pEncloser = NULL;
1167             char* pszNewFQN = new char[dwFQN+1];
1168             strcpy_s(pszNewFQN,dwFQN+1,pszFQN);
1169             if((pch = strrchr(pszNewFQN, NESTING_SEP)) != NULL)
1170             {
1171                 *pch = 0;
1172                 pEncloser = FindCreateClass(pszNewFQN);
1173                 *pch = NESTING_SEP;
1174             }
1175             pSearch = new Class(pszNewFQN);
1176             if (pSearch == NULL)
1177                 report->error("Failed to create class '%s'\n",pszNewFQN);
1178             else
1179             {
1180                 pSearch->m_pEncloser = pEncloser;
1181                 m_lstClass.PUSH(pSearch);
1182                 pSearch->m_cl = mdtTypeDef | m_lstClass.COUNT();
1183                 m_hshClass.PUSH(pSearch);
1184             }
1185         }
1186     }
1187
1188     return pSearch;
1189 }
1190
1191
1192 BOOL Assembler::EmitClass(Class *pClass)
1193 {
1194     LPCUTF8              szFullName;
1195     WCHAR*              wzFullName=&wzUniBuf[0];
1196     HRESULT             hr = E_FAIL;
1197     GUID                guid;
1198     size_t              L;
1199     mdToken             tok;
1200
1201     if(pClass == NULL) return FALSE;
1202
1203     hr = CoCreateGuid(&guid);
1204     if (FAILED(hr))
1205     {
1206         printf("Unable to create GUID\n");
1207         m_State = STATE_FAIL;
1208         return FALSE;
1209     }
1210
1211     if(pClass->m_pEncloser)
1212         szFullName = strrchr(pClass->m_szFQN,NESTING_SEP) + 1;
1213     else
1214         szFullName = pClass->m_szFQN;
1215
1216     WszMultiByteToWideChar(g_uCodePage,0,szFullName,-1,wzFullName,dwUniBuf);
1217
1218     L = wcslen(wzFullName);
1219     if((L==0)||(wzFullName[L-1]==L'.')) // Missing class name!
1220     {
1221         wcscat_s(wzFullName,dwUniBuf,W("$UNNAMED_TYPE$"));
1222     }
1223
1224     pClass->m_Attr = CheckClassFlagsIfNested(pClass->m_pEncloser, pClass->m_Attr);
1225
1226     if (pClass->m_pEncloser)
1227     {
1228         hr = m_pEmitter->DefineNestedType( wzFullName,
1229                                         pClass->m_Attr,      // attributes
1230                                         pClass->m_crExtends,  // CR extends class
1231                                         pClass->m_crImplements,// implements
1232                                         pClass->m_pEncloser->m_cl,  // Enclosing class.
1233                                         &tok);
1234     }
1235     else
1236     {
1237         hr = m_pEmitter->DefineTypeDef( wzFullName,
1238                                         pClass->m_Attr,      // attributes
1239                                         pClass->m_crExtends,  // CR extends class
1240                                         pClass->m_crImplements,// implements
1241                                         &tok);
1242     }
1243     _ASSERTE(tok == pClass->m_cl);
1244     if (FAILED(hr)) goto exit;
1245     if (pClass->m_NumTyPars)
1246     {
1247         ULONG i;
1248         mdToken* ptk;
1249         mdToken tk;
1250         for(i = 0; i < pClass->m_NumTyPars; i++)
1251         {
1252             //ptk = (pClass->m_TyParBounds[i] == NULL)? NULL :  (mdToken*)(pClass->m_TyParBounds[i]->ptr());
1253             //if(FAILED(m_pEmitter->DefineGenericParam(pClass->m_cl,i,pClass->m_TyParAttrs[i],pClass->m_TyParNames[i],0,ptk,&tk)))
1254             ptk = (pClass->m_TyPars[i].Bounds() == NULL)? NULL :  (mdToken*)(pClass->m_TyPars[i].Bounds()->ptr());
1255             if(FAILED(m_pEmitter->DefineGenericParam(pClass->m_cl,i,pClass->m_TyPars[i].Attrs(),pClass->m_TyPars[i].Name(),0,ptk,&tk)))
1256                 report->error("Unable to define generic param'\n");
1257             else
1258                 EmitCustomAttributes(tk, pClass->m_TyPars[i].CAList());
1259         }
1260     }
1261     
1262     
1263     EmitCustomAttributes(pClass->m_cl, &(pClass->m_CustDList));
1264     hr = S_OK;
1265
1266 exit:
1267     return SUCCEEDED(hr);
1268 }
1269
1270 BOOL Assembler::DoGlobalFixups()
1271 {
1272     GlobalFixup *pSearch;
1273
1274     for (int i=0; (pSearch = m_lstGlobalFixup.PEEK(i)); i++)
1275     {
1276         GlobalLabel *   pLabel = FindGlobalLabel(pSearch->m_szLabel);
1277         if (pLabel == NULL)
1278         {
1279             report->error("Unable to find forward reference global label '%s'\n",
1280                 pSearch->m_szLabel);
1281
1282             m_State = STATE_FAIL;
1283             return FALSE;
1284         }
1285         //BYTE * pReference = pSearch->m_pReference;
1286         //DWORD  GlobalOffset = pLabel->m_GlobalOffset;
1287         //memcpy(pReference,&GlobalOffset,4);
1288         SET_UNALIGNED_VAL32(pSearch->m_pReference,pLabel->m_GlobalOffset);
1289     }
1290
1291     return TRUE;
1292 }
1293
1294 state_t Assembler::AddGlobalLabel(__in __nullterminated char *pszName, HCEESECTION section)
1295 {
1296     if (FindGlobalLabel(pszName) != NULL)
1297     {
1298         report->error("Duplicate global label '%s'\n", pszName);
1299         m_State = STATE_FAIL;
1300         return m_State;
1301     }
1302
1303     ULONG GlobalOffset;
1304
1305     HRESULT hr;
1306     hr = m_pCeeFileGen->GetSectionDataLen(section, &GlobalOffset);
1307     _ASSERTE(SUCCEEDED(hr));
1308
1309     GlobalLabel *pNew = new GlobalLabel(pszName, GlobalOffset, section);
1310     if (pNew == 0)
1311     {
1312         report->error("Failed to allocate global label '%s'\n",pszName);
1313         m_State = STATE_FAIL;
1314         return m_State;
1315     }
1316
1317     m_lstGlobalLabel.PUSH(pNew);
1318     return m_State;
1319 }
1320
1321 void Assembler::AddLabel(DWORD CurPC, __in __nullterminated char *pszName)
1322 {
1323     if (m_pCurMethod->FindLabel(pszName) != NULL)
1324     {
1325         report->error("Duplicate label: '%s'\n", pszName);
1326
1327         m_State = STATE_FAIL;
1328     }
1329     else
1330     {
1331         Label *pNew = new Label(pszName, CurPC);
1332
1333         if (pNew != NULL)
1334             //m_pCurMethod->m_lstLabel.PUSH(pNew);
1335             m_lstLabel.PUSH(pNew);
1336         else
1337         {
1338             report->error("Failed to allocate label '%s'\n",pszName);
1339             m_State = STATE_FAIL;
1340         }
1341     }
1342 }
1343
1344 void Assembler::DoDeferredILFixups(Method* pMethod)
1345 { // Now that we know where in the file the code bytes will wind up,
1346   // we can update the RVAs and offsets.
1347     ILFixup *pSearch;
1348     HRESULT hr;
1349     GlobalFixup *Fix = NULL;
1350     int i;
1351     for (i=0;(pSearch = pMethod->m_lstILFixup.PEEK(i));i++)
1352     {
1353         switch(pSearch->m_Kind)
1354         {
1355             case ilGlobal:
1356                 Fix = pSearch->m_Fixup;
1357                 _ASSERTE(Fix != NULL);
1358                 Fix->m_pReference = pMethod->m_pCode+pSearch->m_OffsetInMethod;
1359                 break;
1360
1361             case ilToken:
1362                 hr = m_pCeeFileGen->AddSectionReloc(m_pILSection,
1363                                     pSearch->m_OffsetInMethod+pMethod->m_methodOffset,
1364                                     m_pILSection,
1365                                     srRelocMapToken);
1366                 _ASSERTE(SUCCEEDED(hr));
1367                 break;
1368
1369             case ilRVA:
1370                 hr = m_pCeeFileGen->AddSectionReloc(m_pILSection,
1371                                     pSearch->m_OffsetInMethod+pMethod->m_methodOffset,
1372                                     m_pGlobalDataSection,
1373                                     srRelocAbsolute);
1374                 _ASSERTE(SUCCEEDED(hr));
1375                 break;
1376
1377             default:
1378                 ;
1379         }
1380     }
1381 }
1382 /**************************************************************************/
1383 BOOL Assembler::DoFixups(Method* pMethod)
1384 {
1385     Fixup *pSearch;
1386
1387     for (int i=0; (pSearch = pMethod->m_lstFixup.PEEK(i)); i++)
1388     {
1389         Label * pLabel = pMethod->FindLabel(pSearch->m_szLabel);
1390         long    offset;
1391
1392         if (pLabel == NULL)
1393         {
1394             report->error("Unable to find forward reference label '%s' called from PC=%d\n",
1395                 pSearch->m_szLabel, pSearch->m_RelativeToPC);
1396
1397             //m_State = STATE_FAIL;
1398             return FALSE;
1399         }
1400
1401         offset = pLabel->m_PC - pSearch->m_RelativeToPC;
1402
1403         if (pSearch->m_FixupSize == 1)
1404         {
1405             if (offset > 127 || offset < -128)
1406             {
1407                 report->error("Offset of forward reference label '%s' called from PC=%d is too large for 1 byte pcrel\n",
1408                     pLabel->m_szName, pSearch->m_RelativeToPC);
1409
1410                 //m_State = STATE_FAIL;
1411                 return FALSE;
1412             }
1413
1414             *pSearch->m_pBytes = (BYTE) offset;
1415         }
1416         else if (pSearch->m_FixupSize == 4)
1417         {
1418             SET_UNALIGNED_VAL32(pSearch->m_pBytes,offset);
1419         }
1420     }
1421
1422     return TRUE;
1423 }
1424
1425
1426 OPCODE Assembler::DecodeOpcode(const BYTE *pCode, DWORD *pdwLen)
1427 {
1428     OPCODE opcode;
1429
1430     *pdwLen = 1;
1431     opcode = OPCODE(pCode[0]);
1432     switch(opcode) {
1433         case CEE_PREFIX1:
1434             opcode = OPCODE(pCode[1] + 256);
1435             if (opcode < 0 || opcode >= CEE_COUNT)
1436                 return CEE_COUNT;
1437             *pdwLen = 2;
1438             break;
1439
1440         case CEE_PREFIXREF:
1441         case CEE_PREFIX2:
1442         case CEE_PREFIX3:
1443         case CEE_PREFIX4:
1444         case CEE_PREFIX5:
1445         case CEE_PREFIX6:
1446         case CEE_PREFIX7:
1447             return CEE_COUNT;
1448         default:
1449             break;
1450     }
1451     return opcode;
1452 }
1453
1454 char* Assembler::ReflectionNotation(mdToken tk)
1455 {
1456     char *sz = (char*)&wzUniBuf[dwUniBuf>>1], *pc;
1457     *sz=0;
1458     switch(TypeFromToken(tk))
1459     {
1460         case mdtTypeDef:
1461             {
1462                 Class *pClass = m_lstClass.PEEK(RidFromToken(tk)-1);
1463                 if(pClass)
1464                 {
1465                     strcpy_s(sz,dwUniBuf>>1,pClass->m_szFQN);
1466                     pc = sz;
1467                     while((pc = strchr(pc,NESTING_SEP)) != NULL)
1468                     {
1469                         *pc = '+';
1470                         pc++;
1471                     }
1472                 }
1473             }
1474             break;
1475
1476         case mdtTypeRef:
1477             {
1478                 ULONG   N;
1479                 mdToken tkResScope;
1480                 if(SUCCEEDED(m_pImporter->GetTypeRefProps(tk,&tkResScope,wzUniBuf,dwUniBuf>>1,&N)))
1481                 {
1482                     WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,sz,dwUniBuf>>1,NULL,NULL);
1483                     if(TypeFromToken(tkResScope)==mdtAssemblyRef)
1484                     {
1485                         AsmManAssembly *pAsmRef = m_pManifest->m_AsmRefLst.PEEK(RidFromToken(tkResScope)-1);
1486                         if(pAsmRef)
1487                         {
1488                             pc = &sz[strlen(sz)];
1489                             pc+=sprintf_s(pc,(dwUniBuf >> 1),", %s, Version=%d.%d.%d.%d, Culture=",pAsmRef->szName,
1490                                     pAsmRef->usVerMajor,pAsmRef->usVerMinor,pAsmRef->usBuild,pAsmRef->usRevision);
1491                             ULONG L=0;
1492                             if(pAsmRef->pLocale && (L=pAsmRef->pLocale->length()))
1493                             {
1494                                 memcpy(wzUniBuf,pAsmRef->pLocale->ptr(),L);
1495                                 wzUniBuf[L>>1] = 0;
1496                                 WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,pc,dwUniBuf>>1,NULL,NULL);
1497                             }
1498                             else pc+=sprintf_s(pc,(dwUniBuf >> 1),"neutral");
1499                             pc = &sz[strlen(sz)];
1500                             if(pAsmRef->pPublicKeyToken && (L=pAsmRef->pPublicKeyToken->length()))
1501                             {
1502                                 pc+=sprintf_s(pc,(dwUniBuf >> 1),", Publickeytoken=");
1503                                 BYTE* pb = (BYTE*)(pAsmRef->pPublicKeyToken->ptr());
1504                                 for(N=0; N<L; N++,pb++) pc+=sprintf_s(pc,(dwUniBuf >> 1),"%2.2x",*pb);
1505                             }
1506                         }
1507                     }
1508                 }
1509             }
1510             break;
1511
1512         default:
1513             break;
1514     }
1515     return sz;
1516 }
1517
1518 /*
1519 --------------------------------------------------------------------
1520 mix -- mix 3 32-bit values reversibly.
1521 For every delta with one or two bits set, and the deltas of all three
1522   high bits or all three low bits, whether the original value of a,b,c
1523   is almost all zero or is uniformly distributed,
1524 * If mix() is run forward or backward, at least 32 bits in a,b,c
1525   have at least 1/4 probability of changing.
1526 * If mix() is run forward, every bit of c will change between 1/3 and
1527   2/3 of the time.  (Well, 22/100 and 78/100 for some 2-bit deltas.)
1528 mix() was built out of 36 single-cycle latency instructions in a 
1529   structure that could supported 2x parallelism, like so:
1530       a -= b; 
1531       a -= c; x = (c>>13);
1532       b -= c; a ^= x;
1533       b -= a; x = (a<<8);
1534       c -= a; b ^= x;
1535       c -= b; x = (b>>13);
1536       ...
1537   Unfortunately, superscalar Pentiums and Sparcs can't take advantage 
1538   of that parallelism.  They've also turned some of those single-cycle
1539   latency instructions into multi-cycle latency instructions.  Still,
1540   this is the fastest good hash I could find.  There were about 2^^68
1541   to choose from.  I only looked at a billion or so.
1542 --------------------------------------------------------------------
1543 */
1544 #define mix(a,b,c) \
1545 { \
1546   a -= b; a -= c; a ^= (c >> 13); \
1547   b -= c; b -= a; b ^= (a << 8);  \
1548   c -= a; c -= b; c ^= (b >> 13); \
1549   a -= b; a -= c; a ^= (c >> 12); \
1550   b -= c; b -= a; b ^= (a << 16); \
1551   c -= a; c -= b; c ^= (b >> 5);  \
1552   a -= b; a -= c; a ^= (c >> 3);  \
1553   b -= c; b -= a; b ^= (a << 10); \
1554   c -= a; c -= b; c ^= (b >> 15); \
1555 }
1556
1557 /*
1558 --------------------------------------------------------------------
1559 hash() -- hash a variable-length key into a 32-bit value
1560   k       : the key (the unaligned variable-length array of bytes)
1561   len     : the length of the key, counting by bytes
1562   initval : can be any 4-byte value
1563 Returns a 32-bit value.  Every bit of the key affects every bit of
1564 the return value.  Every 1-bit and 2-bit delta achieves avalanche.
1565 About 6*len+35 instructions.
1566
1567 The best hash table sizes are powers of 2.  There is no need to do
1568 mod a prime (mod is sooo slow!).  If you need less than 32 bits,
1569 use a bitmask.  For example, if you need only 10 bits, do
1570   h = (h & hashmask(10));
1571 In which case, the hash table should have hashsize(10) elements.
1572
1573 If you are hashing n strings (ub1 **)k, do it like this:
1574   for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
1575
1576 By Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use this
1577 code any way you wish, private, educational, or commercial.  It's free.
1578
1579 See http://burtleburtle.net/bob/hash/evahash.html
1580 Use for hash table lookup, or anything where one collision in 2^^32 is
1581 acceptable.  Do NOT use for cryptographic purposes.
1582 --------------------------------------------------------------------
1583 */
1584
1585 unsigned hash( 
1586      __in_ecount(length) const BYTE *k,        /* the key */
1587      unsigned  length,   /* the length of the key */
1588      unsigned  initval)  /* the previous hash, or an arbitrary value */
1589 {
1590    register unsigned a,b,c,len;
1591
1592    /* Set up the internal state */
1593    len = length;
1594    a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
1595    c = initval;         /* the previous hash value */
1596
1597    /*---------------------------------------- handle most of the key */
1598    while (len >= 12)
1599    {
1600       a += (k[0] + ((unsigned)k[1] << 8) + ((unsigned)k[2]  << 16) + ((unsigned)k[3]  << 24));
1601       b += (k[4] + ((unsigned)k[5] << 8) + ((unsigned)k[6]  << 16) + ((unsigned)k[7]  << 24));
1602       c += (k[8] + ((unsigned)k[9] << 8) + ((unsigned)k[10] << 16) + ((unsigned)k[11] << 24));
1603       mix(a,b,c);
1604       k += 12; len -= 12;
1605    }
1606
1607    /*------------------------------------- handle the last 11 bytes */
1608    c += length;
1609    switch(len)              /* all the case statements fall through */
1610    {
1611        case 11: c+=((unsigned)k[10] << 24);
1612        case 10: c+=((unsigned)k[9] << 16);
1613        case 9 : c+=((unsigned)k[8] << 8);
1614           /* the first byte of c is reserved for the length */
1615        case 8 : b+=((unsigned)k[7] << 24);
1616        case 7 : b+=((unsigned)k[6] << 16);
1617        case 6 : b+=((unsigned)k[5] << 8);
1618        case 5 : b+=k[4];
1619        case 4 : a+=((unsigned)k[3] << 24);
1620        case 3 : a+=((unsigned)k[2] << 16);
1621        case 2 : a+=((unsigned)k[1] << 8);
1622        case 1 : a+=k[0];
1623      /* case 0: nothing left to add */
1624    }
1625    mix(a,b,c);
1626    /*-------------------------------------------- report the result */
1627    return c;
1628 }
1629