Merge pull request #23934 from franksinankaya/gcc_cleanup_18
[platform/upstream/coreclr.git] / src / ilasm / assembler.h
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 /************************************************************************/
5 /*                           Assembler.h                                */
6 /************************************************************************/
7
8 #ifndef Assember_h
9 #define Assember_h
10
11 #define NEW_INLINE_NAMES
12
13 #include "binstr.h"
14
15 #include "specstrings.h"
16
17 #include "asmenum.h"
18 #include "asmtemplates.h"
19
20 // Disable the "initialization of static local vars is no thread safe" error
21 #ifdef _MSC_VER
22 #pragma warning(disable : 4640)
23 #endif
24
25 #ifdef ResetEvent
26 #undef ResetEvent
27 #endif
28
29 #define OUTPUT_BUFFER_SIZE          8192      // initial size of asm code for a single method
30 #define OUTPUT_BUFFER_INCREMENT     1024      // size of code buffer increment when it's full
31 #define MAX_FILENAME_LENGTH         2048      //256
32 #define MAX_SIGNATURE_LENGTH        256       // unused
33 #define MAX_LABEL_SIZE              256       //64
34 #define MAX_CALL_SIG_SIZE           32        // unused
35 #define MAX_SCOPE_LENGTH            _MAX_PATH // follow the RegMeta::SetModuleProps limitation
36
37 #define MAX_NAMESPACE_LENGTH        1024      //256    //64
38 #define MAX_MEMBER_NAME_LENGTH      1024      //256    //64
39
40 #define MAX_INTERFACES_IMPLEMENTED  16        // initial number; extended by 16 when needed
41 #define GLOBAL_DATA_SIZE            8192      // initial size of global data buffer
42 #define GLOBAL_DATA_INCREMENT       1024      // size of global data buffer increment when it's full
43 #define MAX_METHODS                 1024      // unused
44 #define MAX_INPUT_LINE_LEN          1024      // unused
45 #define MAX_TYPAR                   8
46 #define BASE_OBJECT_CLASSNAME   "System.Object"
47 #define MAX_MANIFEST_RESOURCES      1024
48
49 // Fully-qualified class name separators:
50 #define NESTING_SEP     ((char)0xF8)
51
52 #define dwUniBuf 16384
53
54 #ifdef FEATURE_PAL
55 #include "coreclrloader.h"
56 extern CoreCLRLoader *g_loader;
57 extern char *g_pszExeFile;
58 #endif
59 typedef int(STDAPICALLTYPE *MetaDataGetDispenserFunc) (
60     REFCLSID    rclsid,                 // The class to desired.
61     REFIID      riid,                   // Interface wanted on class factory.
62     LPVOID FAR  *ppv);                  // Return interface pointer here.
63
64 extern MetaDataGetDispenserFunc metaDataGetDispenser;
65
66 extern WCHAR   wzUniBuf[]; // Unicode conversion global buffer (assem.cpp)
67
68 class Class;
69 class Method;
70 class PermissionDecl;
71 class PermissionSetDecl;
72
73 unsigned hash(                // defined in assem.cpp
74      __in_ecount(length) const BYTE *k,        /* the key */
75      unsigned  length,   /* the length of the key */
76      unsigned  initval);  /* the previous hash, or an arbitrary value */
77
78 struct MemberRefDescriptor
79 {
80     mdToken             m_tdClass;
81     Class*              m_pClass;
82     char*               m_szName;
83     DWORD               m_dwName;
84     BinStr*             m_pSigBinStr;
85     mdToken             m_tkResolved;
86 };
87 typedef FIFO<MemberRefDescriptor> MemberRefDList;
88
89
90 struct MethodImplDescriptor
91 {
92     mdToken             m_tkImplementedMethod;
93     mdToken             m_tkImplementingMethod;
94     mdToken             m_tkDefiningClass;
95     BOOL                m_fNew;
96 };
97 typedef FIFO<MethodImplDescriptor> MethodImplDList;
98
99 struct LocalMemberRefFixup
100 {
101     mdToken tk;
102     size_t  offset;
103     BOOL    m_fNew;
104     LocalMemberRefFixup(mdToken TK, size_t Offset)
105     {
106         tk = TK;
107         offset = Offset;
108         m_fNew = TRUE;
109     }
110 };
111 typedef FIFO<LocalMemberRefFixup> LocalMemberRefFixupList;
112
113 struct CustomDescr
114 {
115     mdToken tkType;
116     mdToken tkOwner;
117     mdToken tkInterfacePair; // Needed for InterfaceImpl CA's
118     BinStr* pBlob;
119     CustomDescr(mdToken tko, mdToken tk, BinStr* pblob) { tkType = tk; pBlob = pblob; tkOwner = tko; tkInterfacePair = 0; };
120     CustomDescr(mdToken tk, BinStr* pblob) { tkType = tk; pBlob = pblob; tkOwner = 0; tkInterfacePair = 0;};
121     CustomDescr(CustomDescr* pOrig) { tkType = pOrig->tkType; pBlob = new BinStr(); pBlob->append(pOrig->pBlob); tkOwner = pOrig->tkOwner; tkInterfacePair = pOrig->tkInterfacePair; };
122     ~CustomDescr() { if(pBlob) delete pBlob; };
123 };
124 typedef FIFO<CustomDescr> CustomDescrList;
125 typedef LIFO<CustomDescrList> CustomDescrListStack;
126 /**************************************************************************/
127 #include "typar.hpp"
128 #include "method.hpp"
129 #include "iceefilegen.h"
130 #include "asmman.hpp"
131
132 #include "nvpair.h"
133
134
135 typedef enum
136 {
137     STATE_OK,
138     STATE_FAIL,
139     STATE_ENDMETHOD,
140     STATE_ENDFILE
141 } state_t;
142
143
144 class GlobalLabel
145 {
146 public:
147     LPCUTF8         m_szName;
148     DWORD           m_GlobalOffset; 
149     HCEESECTION     m_Section;
150     unsigned        m_Hash;
151
152     GlobalLabel(LPCUTF8 pszName, DWORD GlobalOffset, HCEESECTION section)
153     {
154         m_GlobalOffset  = GlobalOffset;
155         m_Section       = section;
156         m_szName = pszName;
157         m_Hash = hash((const BYTE*)pszName, (unsigned)strlen(pszName),10);
158     }
159
160     ~GlobalLabel(){ delete [] m_szName; }
161
162     int ComparedTo(GlobalLabel* L)
163     { 
164         return (m_Hash == L->m_Hash) ? strcmp(m_szName, L->m_szName)
165                                      : ((m_Hash > L->m_Hash) ? 1 : -1);
166     }
167
168     //int ComparedTo(GlobalLabel* L) { return strcmp(m_szName,L->m_szName); };
169     //int Compare(char* L) { return strcmp(L, m_szNam); };
170     //char* NameOf() { return m_szName; };
171 };
172 //typedef SORTEDARRAY<GlobalLabel> GlobalLabelList;
173 typedef RBTREE<GlobalLabel> GlobalLabelList;
174 //typedef FIFO_INDEXED<GlobalLabel> GlobalLabelList;
175
176 class CeeFileGenWriter;
177 class CeeSection;
178
179 class BinStr;
180
181 /************************************************************************/
182 /* represents an object that knows how to report errors back to the user */
183
184 class ErrorReporter
185 {
186 public:
187     virtual void error(const char* fmt, ...) = 0;
188     virtual void warn(const char* fmt, ...) = 0;
189     virtual void msg(const char* fmt, ...) = 0; 
190 };
191
192 /**************************************************************************/
193 /* represents a switch table before the lables are bound */
194
195 struct Labels {
196     Labels(__in __nullterminated char* aLabel, Labels* aNext, bool aIsLabel) : Label(aLabel), Next(aNext), isLabel(aIsLabel) {}
197     ~Labels() { if(isLabel && Label) delete [] Label; delete Next; }
198         
199     char*       Label;
200     Labels*     Next;
201     bool        isLabel;
202 };
203
204 /**************************************************************************/
205 /* descriptor of the structured exception handling construct  */
206 struct SEH_Descriptor
207 {
208     DWORD       sehClause;  // catch/filter/finally
209     DWORD       tryFrom;    // start of try block
210     DWORD       tryTo;      // end of try block
211     DWORD       sehHandler; // start of exception handler
212     DWORD       sehHandlerTo; // end of exception handler
213     union {
214         DWORD       sehFilter;  // start of filter block
215         mdTypeRef   cException; // what to catch
216     };
217
218     SEH_Descriptor()
219     {
220         memset(this, 0, sizeof(*this));
221     }
222 };
223
224
225 typedef LIFO<char> StringStack;
226 typedef LIFO<SEH_Descriptor> SEHD_Stack;
227
228 typedef FIFO<Method> MethodList;
229 //typedef SORTEDARRAY<Method> MethodSortedList;
230 typedef FIFO<mdToken> TokenList;
231 /**************************************************************************/
232 /* The field, event and property descriptor structures            */
233
234 struct FieldDescriptor
235 {
236     mdTypeDef       m_tdClass;
237     char*           m_szName;
238     DWORD           m_dwName;
239     mdFieldDef      m_fdFieldTok;
240     ULONG           m_ulOffset;
241     char*           m_rvaLabel;         // if field has RVA associated with it, label for it goes here. 
242     BinStr*         m_pbsSig;
243     Class*                      m_pClass;
244     BinStr*                     m_pbsValue;
245     BinStr*                     m_pbsMarshal;
246         PInvokeDescriptor*      m_pPInvoke;
247     CustomDescrList     m_CustomDescrList;
248     DWORD                       m_dwAttr;
249     BOOL            m_fNew;
250     // Security attributes
251     PermissionDecl* m_pPermissions;
252     PermissionSetDecl* m_pPermissionSets;
253     FieldDescriptor()  { m_szName = NULL; m_pbsSig = NULL; m_fNew = TRUE; };
254     ~FieldDescriptor() { if(m_szName) delete [] m_szName; if(m_pbsSig) delete m_pbsSig; };
255 };
256 typedef FIFO<FieldDescriptor> FieldDList;
257
258 struct EventDescriptor
259 {
260     mdTypeDef           m_tdClass;
261     char*               m_szName;
262     DWORD               m_dwAttr;
263     mdToken             m_tkEventType;
264     mdToken             m_tkAddOn;
265     mdToken             m_tkRemoveOn;
266     mdToken             m_tkFire;
267     TokenList           m_tklOthers;
268     mdEvent             m_edEventTok;
269     BOOL                m_fNew;
270     CustomDescrList     m_CustomDescrList;
271     ~EventDescriptor() { m_tklOthers.RESET(false); };
272 };
273 typedef FIFO<EventDescriptor> EventDList;
274
275 struct PropDescriptor
276 {
277     mdTypeDef           m_tdClass;
278     char*               m_szName;
279     DWORD               m_dwAttr;
280     COR_SIGNATURE*      m_pSig;
281     DWORD               m_dwCSig;
282     DWORD               m_dwCPlusTypeFlag;
283     PVOID               m_pValue;
284     DWORD                               m_cbValue;
285     mdToken             m_tkSet;
286     mdToken             m_tkGet;
287     TokenList           m_tklOthers;
288     mdProperty          m_pdPropTok;
289     BOOL                m_fNew;
290     CustomDescrList     m_CustomDescrList;
291     ~PropDescriptor() { m_tklOthers.RESET(false); };
292 };
293 typedef FIFO<PropDescriptor> PropDList;
294
295 struct ImportDescriptor
296 {
297     char*   szDllName;
298 //    char   szDllName[MAX_FILENAME_LENGTH];
299     DWORD  dwDllName;
300     mdModuleRef mrDll;
301     ImportDescriptor(__in __nullterminated char* sz, DWORD l)
302     {
303         if((sz != NULL)&&(l > 0))
304         {
305             szDllName = new char[l+1];
306             if(szDllName != NULL)
307             {
308                 memcpy(szDllName,sz,l);
309                 szDllName[l] = 0;
310                 dwDllName = l;
311             }
312         }
313         else
314         {
315             szDllName = NULL;
316             dwDllName = 0;
317         }
318     };
319     ~ImportDescriptor() { delete [] szDllName; };
320 };
321 typedef FIFO<ImportDescriptor> ImportList;
322
323
324 /**************************************************************************/
325 #include "class.hpp"
326 typedef LIFO<Class> ClassStack;
327 typedef FIFO<Class> ClassList;
328 //typedef SORTEDARRAY<Class> ClassHash;
329 typedef RBTREE<Class> ClassHash;
330 //typedef FIFO_INDEXED<Class> ClassHash;
331
332 /**************************************************************************/
333 /* Classes to hold lists of security permissions and permission sets. We build
334    these lists as we find security directives in the input stream and drain
335    them every time we see a class or method declaration (to which the
336    security info is attached). */
337
338 class PermissionDecl
339 {
340 public:
341     PermissionDecl(CorDeclSecurity action, mdToken type, NVPair *pairs)
342     {
343         m_Action = action;
344         m_TypeSpec = type;
345         m_pbsBlob = NULL;
346         BuildConstructorBlob(action, pairs);
347         m_Next = NULL;
348     }
349
350     PermissionDecl(CorDeclSecurity action, mdToken type, BinStr* pbsPairs)
351     {
352         m_Action = action;
353         m_TypeSpec = type;
354         
355         m_pbsBlob = new BinStr();
356         m_pbsBlob->appendInt16(VAL16(1));     // prolog 0x01 0x00
357         m_pbsBlob->appendInt32((int)action);  // 4-byte action
358         if(pbsPairs)                          // name-value pairs if any
359         {
360             if(pbsPairs->length() > 2)
361                 m_pbsBlob->appendFrom(pbsPairs,2);
362             delete pbsPairs;
363         }
364         if(m_pbsBlob->length() == 6) // no pairs added
365             m_pbsBlob->appendInt16(0);
366         m_Blob = m_pbsBlob->ptr();
367         m_BlobLength = m_pbsBlob->length();
368         m_Next = NULL;
369     }
370
371     ~PermissionDecl()
372     {
373         if(m_pbsBlob) delete m_pbsBlob;
374         else delete [] m_Blob;
375     }
376
377     CorDeclSecurity     m_Action;
378     mdToken             m_TypeSpec;
379     BYTE               *m_Blob;
380     BinStr             *m_pbsBlob;
381     long                m_BlobLength;
382     PermissionDecl     *m_Next;
383
384 private:
385     void BuildConstructorBlob(CorDeclSecurity action, NVPair *pairs)
386     {
387         NVPair *p = pairs;
388         int count = 0;
389         int bytes = 8;
390         int length;
391         int i;
392         BYTE *pBlob;
393
394         // Calculate number of name/value pairs and the memory required for the
395         // custom attribute blob.
396         while (p) {
397             BYTE *pVal = (BYTE*)p->Value()->ptr();
398             count++;
399             bytes += 2; // One byte field/property specifier, one byte type code
400
401             length = (int)strlen((const char *)p->Name()->ptr());
402             bytes += CPackedLen::Size(length) + length;
403
404             switch (pVal[0]) {
405             case SERIALIZATION_TYPE_BOOLEAN:
406                 bytes += 1;
407                 break;
408             case SERIALIZATION_TYPE_I4:
409                 bytes += 4;
410                 break;
411             case SERIALIZATION_TYPE_STRING:
412                 length = (int)strlen((const char *)&pVal[1]);
413                 bytes += CPackedLen::Size(length) + length;
414                 break;
415             case SERIALIZATION_TYPE_ENUM:
416                 length = (int)strlen((const char *)&pVal[1]);
417                 bytes += CPackedLen::Size((ULONG)length) + length;
418                 bytes += 4;
419                 break;
420             }
421             p = p->Next();
422         }
423
424         m_Blob = new BYTE[bytes];
425         if(m_Blob==NULL)
426         {
427             fprintf(stderr,"\nOut of memory!\n");
428             return;
429         }
430
431         m_Blob[0] = 0x01;           // Version
432         m_Blob[1] = 0x00;
433         m_Blob[2] = (BYTE)action;   // Constructor arg (security action code)
434         m_Blob[3] = 0x00;
435         m_Blob[4] = 0x00;
436         m_Blob[5] = 0x00;
437         m_Blob[6] = (BYTE)count;    // Property/field count
438         m_Blob[7] = (BYTE)(count >> 8);
439
440         for (i = 0, pBlob = &m_Blob[8], p = pairs; i < count; i++, p = p->Next()) {
441             BYTE *pVal = (BYTE*)p->Value()->ptr();
442             char *szType;
443
444             // Set field/property setter type.
445             *pBlob++ = SERIALIZATION_TYPE_PROPERTY;
446
447             // Set type code. There's additional info for enums (the enum class
448             // name).
449             *pBlob++ = pVal[0];
450             if (pVal[0] == SERIALIZATION_TYPE_ENUM) {
451                 szType = (char *)&pVal[1];
452                 length = (int)strlen(szType);
453                 pBlob = (BYTE*)CPackedLen::PutLength(pBlob, length);
454                 strcpy_s((char *)pBlob, bytes, szType);
455                 pBlob += length;
456             }
457
458             // Record the field/property name.
459             length = (int)strlen((const char *)p->Name()->ptr());
460             pBlob = (BYTE*)CPackedLen::PutLength(pBlob, length);
461             strcpy_s((char *)pBlob, bytes-(pBlob-m_Blob), (const char *)p->Name()->ptr());
462             pBlob += length;
463
464             // Record the serialized value.
465             switch (pVal[0]) {
466             case SERIALIZATION_TYPE_BOOLEAN:
467                 *pBlob++ = pVal[1];
468                 break;
469             case SERIALIZATION_TYPE_I4:
470                 *(__int32*)pBlob = *(__int32*)&pVal[1];
471                 pBlob += 4;
472                 break;
473             case SERIALIZATION_TYPE_STRING:
474                 length = (int)strlen((const char *)&pVal[1]);
475                 pBlob = (BYTE*)CPackedLen::PutLength(pBlob, length);
476                 strcpy_s((char *)pBlob, bytes-(pBlob-m_Blob), (const char *)&pVal[1]);
477                 pBlob += length;
478                 break;
479             case SERIALIZATION_TYPE_ENUM:
480                 length = (int)strlen((const char *)&pVal[1]);
481                 // We can have enums with base type of I1, I2 and I4.
482                 switch (pVal[1 + length + 1]) {
483                 case 1:
484                     *(__int8*)pBlob = *(__int8*)&pVal[1 + length + 2];
485                     pBlob += 1;
486                     break;
487                 case 2:
488                     *(__int16*)pBlob = *(__int16*)&pVal[1 + length + 2];
489                     pBlob += 2;
490                     break;
491                 case 4:
492                     *(__int32*)pBlob = *(__int32*)&pVal[1 + length + 2];
493                     pBlob += 4;
494                     break;
495                 default:
496                     _ASSERTE(!"Invalid enum size");
497                 }
498                 break;
499             }
500
501         }
502
503         _ASSERTE((pBlob - m_Blob) == bytes);
504
505         m_BlobLength = (long)bytes;
506     }
507 };
508
509 class PermissionSetDecl
510 {
511 public:
512     PermissionSetDecl(CorDeclSecurity action, BinStr *value)
513     {
514         m_Action = action;
515         m_Value = value;
516         m_Next = NULL;
517     }
518
519     ~PermissionSetDecl()
520     {
521         delete m_Value;
522     }
523
524     CorDeclSecurity     m_Action;
525     BinStr             *m_Value;
526     PermissionSetDecl  *m_Next;
527 };
528
529 struct VTFEntry
530 {
531     char*   m_szLabel;
532     WORD    m_wCount;
533     WORD    m_wType;
534     VTFEntry(WORD wCount, WORD wType, __in __nullterminated char* szLabel) { m_wCount = wCount; m_wType = wType; m_szLabel = szLabel; }
535     ~VTFEntry() { delete m_szLabel; }
536 };
537 typedef FIFO<VTFEntry> VTFList;
538
539 struct  EATEntry
540 {
541         DWORD   dwStubRVA;
542         DWORD   dwOrdinal;
543         char*   szAlias;
544 };
545 typedef FIFO<EATEntry> EATList;
546
547 struct DocWriter
548 {
549     char* Name;
550     ISymUnmanagedDocumentWriter* pWriter;
551     DocWriter() { Name=NULL; pWriter=NULL; };
552     ~DocWriter() { delete [] Name; if(pWriter) pWriter->Release();};
553 };
554 typedef FIFO<DocWriter> DocWriterList;
555 /**************************************************************************/
556 /* The assembler object does all the code generation (dealing with meta-data)
557    writing a PE file etc etc. But does NOT deal with syntax (that is what
558    AsmParse is for).  Thus the API below is how AsmParse 'controls' the 
559    Assember.  Note that the Assembler object does know about the 
560    AsmParse object (that is Assember is more fundamental than AsmParse) */
561 struct Instr
562 {
563     int opcode;
564     unsigned linenum;
565         unsigned column;
566     unsigned linenum_end;
567         unsigned column_end;
568     unsigned pc;
569     ISymUnmanagedDocumentWriter* pWriter;
570 };
571 #define INSTR_POOL_SIZE 16
572
573 // For code folding:
574 struct MethodBody
575 {
576     BinStr* pbsBody;
577     unsigned RVA;
578     BYTE*   pCode;
579 };
580 typedef FIFO<MethodBody> MethodBodyList;
581
582 struct Clockwork
583 {
584     DWORD  cBegin;
585     DWORD  cEnd;
586     DWORD  cParsBegin;
587     DWORD  cParsEnd;
588     DWORD  cMDInitBegin;
589     DWORD  cMDInitEnd;
590     DWORD  cMDEmitBegin;
591     DWORD  cMDEmitEnd;
592     DWORD  cMDEmit1;
593     DWORD  cMDEmit2;
594     DWORD  cMDEmit3;
595     DWORD  cMDEmit4;
596     DWORD  cRef2DefBegin;
597     DWORD  cRef2DefEnd;
598     DWORD  cFilegenBegin;
599     DWORD  cFilegenEnd;
600 };
601
602 struct TypeDefDescr
603 {
604     char* m_szName;
605     union
606     {
607         BinStr* m_pbsTypeSpec;
608         CustomDescr* m_pCA;
609     };
610     mdToken m_tkTypeSpec;
611     TypeDefDescr(__in_opt __nullterminated char *pszName, BinStr* pbsTypeSpec, mdToken tkTypeSpec)
612     {
613         m_szName = pszName;
614         m_pbsTypeSpec = pbsTypeSpec;
615         m_tkTypeSpec = tkTypeSpec;
616     };
617     ~TypeDefDescr() { delete [] m_szName; delete m_pbsTypeSpec; };
618     int ComparedTo(TypeDefDescr* T) { return strcmp(m_szName,T->m_szName); };
619     //int Compare(char* T) { return strcmp(T,m_szName); };
620 };
621 typedef SORTEDARRAY<TypeDefDescr> TypeDefDList;
622
623 struct Indx
624 {
625     void* table[128];
626     Indx() { memset(table,0,sizeof(table)); };
627     ~Indx()
628     {
629         for(int i = 1; i < 128; i++) delete ((Indx*)(table[i]));
630     };
631     void IndexString(__in_z __in char* psz, void* pkywd)
632     {
633         int i = (int) *psz;
634         if(i == 0)
635             table[0] = pkywd;
636         else
637         {
638             _ASSERTE((i > 0)&&(i <= 127));
639             Indx* pInd = (Indx*)(table[i]);
640             if(pInd == NULL)
641             {
642                 pInd = new Indx;
643                 _ASSERTE(pInd);
644                 table[i] = pInd;
645             }
646             pInd->IndexString(psz+1,pkywd);
647         }
648     }
649     void*  FindString(__in __nullterminated char* psz)
650     {
651         if(*psz > 0)
652         {
653             unsigned char uch = (unsigned char) *psz;
654             if(table[uch] != NULL)
655                 return ((Indx*)(table[uch]))->FindString(psz+1); 
656         }
657         else if(*psz == 0) return table[0];
658         return NULL;
659     }
660 };
661
662 class Assembler {
663 public:
664     Assembler();
665     ~Assembler();
666     //--------------------------------------------------------  
667         GlobalLabelList m_lstGlobalLabel;
668         GlobalFixupList m_lstGlobalFixup;
669
670     LabelList       m_lstLabel;
671
672     Class *                     m_pModuleClass;
673     ClassList           m_lstClass;
674     ClassHash           m_hshClass;
675
676     Indx            indxKeywords;
677
678     BYTE *  m_pOutputBuffer;
679     BYTE *  m_pCurOutputPos;
680     BYTE *  m_pEndOutputPos;
681
682
683     DWORD   m_CurPC;
684     BOOL    m_fStdMapping;
685     BOOL    m_fDisplayTraceOutput;
686     BOOL    m_fInitialisedMetaData;
687     BOOL    m_fAutoInheritFromObject;
688     BOOL    m_fReportProgress;
689     BOOL    m_fIsMscorlib;
690     BOOL    m_fTolerateDupMethods;
691     BOOL    m_fENCMode;
692     BOOL    m_fOptimize;
693     mdToken m_tkSysObject;
694     mdToken m_tkSysString;
695     mdToken m_tkSysValue;
696     mdToken m_tkSysEnum;
697     BOOL    m_fDidCoInitialise;
698
699     IMetaDataDispenserEx *m_pDisp;
700     IMetaDataEmit2      *m_pEmitter;
701     ICeeFileGen        *m_pCeeFileGen;
702     IMetaDataImport2    *m_pImporter;                   // Import interface.
703     HCEEFILE m_pCeeFile;
704     HCEESECTION m_pGlobalDataSection;
705     HCEESECTION m_pILSection;
706     HCEESECTION m_pTLSSection;
707     HCEESECTION m_pCurSection;      // The section EmitData* things go to
708
709     AsmMan*     m_pManifest;
710
711     char    m_szScopeName[MAX_SCOPE_LENGTH];
712     char    *m_szNamespace; //[MAX_NAMESPACE_LENGTH];
713     char    *m_szFullNS; //[MAX_NAMESPACE_LENGTH];
714         unsigned        m_ulFullNSLen;
715
716     WCHAR   *m_wzMetadataVersion;
717
718     StringStack m_NSstack;
719     mdTypeSpec      m_crExtends;
720
721     //    char    m_szExtendsClause[MAX_CLASSNAME_LENGTH];
722
723     // The (resizable) array of "implements" types
724     mdToken   *m_crImplList;
725     int     m_nImplList;
726     int     m_nImplListSize;
727     
728     TyParList       *m_TyParList;
729     
730     Method *m_pCurMethod;
731     Class   *m_pCurClass;
732     ClassStack m_ClassStack; // for nested classes
733     Class   *dummyClass; // for FindCreateClass
734
735     // moved to Class
736     //MethodList  m_MethodList;
737
738     BOOL    m_fCPlusPlus;
739     BOOL    m_fWindowsCE;
740     BOOL    m_fDLL;
741     BOOL    m_fOBJ;
742     BOOL    m_fEntryPointPresent;
743     BOOL    m_fHaveFieldsWithRvas;
744     BOOL    m_fFoldCode;
745     DWORD   m_dwMethodsFolded;
746
747     state_t m_State;
748
749     BinStr* m_pbsMD;
750
751     Instr   m_Instr[INSTR_POOL_SIZE]; // 16
752     inline  Instr* GetInstr() 
753     {
754         int i;
755         for(i=0; (i<INSTR_POOL_SIZE)&&(m_Instr[i].opcode != -1); i++);
756         if(i<INSTR_POOL_SIZE) return &m_Instr[i];
757         report->error("Instruction pool exhausted: source contains invalid instructions\n");
758         return NULL;
759     }
760     // Labels, fixups and IL fixups are defined in Method.hpp,.cpp
761     void AddLabel(DWORD CurPC, __in __nullterminated char *pszName);
762     void AddDeferredFixup(__in __nullterminated char *pszLabel, BYTE *pBytes, DWORD RelativeToPC, BYTE FixupSize);
763     void AddDeferredILFixup(ILFixupType Kind);
764     void AddDeferredILFixup(ILFixupType Kind, GlobalFixup *GFixup);
765     void DoDeferredILFixups(Method* pMethod);
766     BOOL DoFixups(Method* pMethod);
767     //--------------------------------------------------------------------------------
768     void    ClearImplList(void);
769     void    AddToImplList(mdToken);
770     void    ClearBoundList(void);
771     //--------------------------------------------------------------------------------
772     BOOL Init();
773     void ProcessLabel(__in_z __in char *pszName);
774     GlobalLabel *FindGlobalLabel(LPCUTF8 pszName);
775     GlobalFixup *AddDeferredGlobalFixup(__in __nullterminated char *pszLabel, BYTE* reference);
776     //void AddDeferredDescrFixup(__in __nullterminated char *pszLabel);
777     BOOL DoGlobalFixups();
778     BOOL DoDescrFixups();
779     OPCODE DecodeOpcode(const BYTE *pCode, DWORD *pdwLen);
780     BOOL AddMethod(Method *pMethod);
781     void SetTLSSection() { m_pCurSection = m_pTLSSection; }
782     void SetILSection() { m_pCurSection = m_pILSection; }
783     void SetDataSection()       { m_pCurSection = m_pGlobalDataSection; }
784     BOOL EmitMethod(Method *pMethod);
785     BOOL EmitMethodBody(Method* pMethod, BinStr* pbsOut);
786     BOOL EmitClass(Class *pClass);
787     HRESULT CreatePEFile(__in __nullterminated WCHAR *pwzOutputFilename);
788     HRESULT CreateTLSDirectory();
789     HRESULT CreateDebugDirectory();
790     HRESULT InitMetaData();
791     Class *FindCreateClass(__in __nullterminated const char *pszFQN);
792     BOOL EmitFieldRef(__in_z __in char *pszArg, int opcode);
793     BOOL EmitSwitchData(__in_z __in char *pszArg);
794     mdToken ResolveClassRef(mdToken tkResScope, __in __nullterminated const char *pszClassName, Class** ppClass);
795     mdToken ResolveTypeSpec(BinStr* typeSpec);
796     mdToken GetBaseAsmRef();
797     mdToken GetAsmRef(__in __nullterminated const char* szName);
798     mdToken GetModRef(__in __nullterminated char* szName);
799     mdToken GetInterfaceImpl(mdToken tsClass, mdToken tsInterface);
800     char* ReflectionNotation(mdToken tk);
801     HRESULT ConvLocalSig(__in char* localsSig, CQuickBytes* corSig, DWORD* corSigLen, BYTE*& localTypes);
802     DWORD GetCurrentILSectionOffset();
803     BOOL EmitCALLISig(__in char *p);
804     void AddException(DWORD pcStart, DWORD pcEnd, DWORD pcHandler, DWORD pcHandlerTo, mdTypeRef crException, BOOL isFilter, BOOL isFault, BOOL isFinally);
805     state_t CheckLocalTypeConsistancy(int instr, unsigned arg);
806     state_t AddGlobalLabel(__in __nullterminated char *pszName, HCEESECTION section);
807     void SetDLL(BOOL);
808     void SetOBJ(BOOL);
809     void ResetForNextMethod();
810     void ResetLineNumbers();
811     void SetStdMapping(BOOL val = TRUE) { m_fStdMapping = val; };
812
813     //--------------------------------------------------------------------------------
814     BOOL isShort(unsigned instr) { return ((OpcodeInfo[instr].Type & 16) != 0); };
815     unsigned ShortOf(unsigned opcode);
816     void SetErrorReporter(ErrorReporter* aReport) { report = aReport; if(m_pManifest) m_pManifest->SetErrorReporter(aReport); }
817
818     void StartNameSpace(__in __nullterminated char* name);
819     void EndNameSpace();
820     void StartClass(__in __nullterminated char* name, DWORD attr, TyParList *typars);
821     DWORD CheckClassFlagsIfNested(Class* pEncloser, DWORD attr);
822     void AddClass();
823     void EndClass();
824     void StartMethod(__in __nullterminated char* name, BinStr* sig, CorMethodAttr flags, BinStr* retMarshal, DWORD retAttr, TyParList *typars = NULL);
825     void EndMethod();
826
827     void AddField(__inout_z __inout char* name, BinStr* sig, CorFieldAttr flags, __in __nullterminated char* rvaLabel, BinStr* pVal, ULONG ulOffset);
828         BOOL EmitField(FieldDescriptor* pFD);
829     void EmitByte(int val);
830     //void EmitTry(enum CorExceptionFlag kind, char* beginLabel, char* endLabel, char* handleLabel, char* filterOrClass);
831     void EmitMaxStack(unsigned val);
832     void EmitLocals(BinStr* sig);
833     void EmitEntryPoint();
834     void EmitZeroInit();
835     void SetImplAttr(unsigned short attrval);
836
837     // Emits zeros if the buffer parameter is NULL.
838     void EmitData(__in_opt void *buffer, unsigned len);
839
840     void EmitDD(__in __nullterminated char *str);
841     void EmitDataString(BinStr* str);
842
843     void EmitInstrVar(Instr* instr, int var);
844     void EmitInstrVarByName(Instr* instr, __in __nullterminated char* label);
845     void EmitInstrI(Instr* instr, int val);
846     void EmitInstrI8(Instr* instr, __int64* val);
847     void EmitInstrR(Instr* instr, double* val);
848     void EmitInstrBrOffset(Instr* instr, int offset);
849     void EmitInstrBrTarget(Instr* instr, __in __nullterminated char* label);
850     mdToken MakeMemberRef(mdToken typeSpec, __in __nullterminated char* name, BinStr* sig);
851     mdToken MakeMethodSpec(mdToken tkParent, BinStr* sig);
852     void SetMemberRefFixup(mdToken tk, unsigned opcode_len);
853     mdToken MakeTypeRef(mdToken tkResScope, LPCUTF8 szFullName);
854     void EmitInstrStringLiteral(Instr* instr, BinStr* literal, BOOL ConvertToUnicode, BOOL Swap = FALSE);
855     void EmitInstrSig(Instr* instr, BinStr* sig);
856     void EmitInstrSwitch(Instr* instr, Labels* targets);
857     void EmitLabel(__in __nullterminated char* label);
858     void EmitDataLabel(__in __nullterminated char* label);
859
860     unsigned OpcodeLen(Instr* instr); //returns opcode length
861     // Emit just the opcode (no parameters to the instruction stream.
862     void EmitOpcode(Instr* instr);
863
864     // Emit primitive types to the instruction stream.
865     void EmitBytes(BYTE*, unsigned len);
866
867     ErrorReporter* report;
868
869         BOOL EmitFieldsMethods(Class* pClass);
870         BOOL EmitEventsProps(Class* pClass);
871
872     // named args/vars paraphernalia:
873 public:
874     void addArgName(__in_opt __nullterminated char *szNewName, BinStr* pbSig, BinStr* pbMarsh, DWORD dwAttr)
875     {
876         if(pbSig && (*(pbSig->ptr()) == ELEMENT_TYPE_VOID))
877             report->error("Illegal use of type 'void'\n");
878         if(m_lastArgName)
879         {
880             m_lastArgName->pNext = new ARG_NAME_LIST(m_lastArgName->nNum+1,szNewName,pbSig,pbMarsh,dwAttr);
881             m_lastArgName = m_lastArgName->pNext;
882         }
883         else
884         {
885             m_lastArgName = new ARG_NAME_LIST(0,szNewName,pbSig,pbMarsh,dwAttr);
886             m_firstArgName = m_lastArgName;
887         }
888     };
889     ARG_NAME_LIST *getArgNameList(void)
890     { ARG_NAME_LIST *pRet = m_firstArgName; m_firstArgName=NULL; m_lastArgName=NULL; return pRet;};
891     // Added because recursive destructor of ARG_NAME_LIST may overflow the system stack
892     void delArgNameList(ARG_NAME_LIST *pFirst)
893     {
894         ARG_NAME_LIST *pArgList=pFirst, *pArgListNext;
895         for(; pArgList; pArgListNext=pArgList->pNext,
896                         delete pArgList, 
897                         pArgList=pArgListNext);
898     };
899
900     ARG_NAME_LIST   *findArg(ARG_NAME_LIST *pFirst, int num)
901     {
902         ARG_NAME_LIST *pAN;
903         for(pAN=pFirst; pAN; pAN = pAN->pNext)
904         {
905             if(pAN->nNum == num) return pAN;
906         }
907         return NULL;
908     };
909     ARG_NAME_LIST *m_firstArgName;
910     ARG_NAME_LIST *m_lastArgName;
911     void ResetArgNameList();
912
913     // Structured exception handling paraphernalia:
914 public:
915     SEH_Descriptor  *m_SEHD;    // current descriptor ptr
916     void NewSEHDescriptor(void); //sets m_SEHD
917     void SetTryLabels(__in __nullterminated char * szFrom, __in __nullterminated char *szTo);
918     void SetFilterLabel(__in __nullterminated char *szFilter);
919     void SetCatchClass(mdToken catchClass);
920     void SetHandlerLabels(__in __nullterminated char *szHandlerFrom, __in __nullterminated char *szHandlerTo);
921     void EmitTry(void);         //uses m_SEHD
922
923 //private:
924     SEHD_Stack  m_SEHDstack;
925
926     // Events and Properties paraphernalia:
927 public:
928     void EndEvent(void);    //emits event definition
929     void EndProp(void);     //emits property definition
930     void ResetEvent(__inout_z __inout char * szName, mdToken typeSpec, DWORD dwAttr);
931     void ResetProp(__inout_z __inout char * szName, BinStr* bsType, DWORD dwAttr, BinStr* bsValue);
932     void SetEventMethod(int MethodCode, mdToken tk);
933     void SetPropMethod(int MethodCode, mdToken tk);
934     BOOL EmitEvent(EventDescriptor* pED);   // impl. in ASSEM.CPP
935     BOOL EmitProp(PropDescriptor* pPD); // impl. in ASSEM.CPP
936     EventDescriptor*    m_pCurEvent;
937     PropDescriptor*     m_pCurProp;
938
939 private:
940     MemberRefDList           m_LocalMethodRefDList;
941     MemberRefDList           m_LocalFieldRefDList;
942     LocalMemberRefFixupList  m_LocalMemberRefFixupList;
943     MethodBodyList           m_MethodBodyList;
944     MemberRefDList           m_MethodSpecList;
945 public:
946     HRESULT ResolveLocalMemberRefs();
947     HRESULT DoLocalMemberRefFixups();
948     mdToken ResolveLocalMemberRef(mdToken tok);
949
950     // PInvoke paraphernalia
951 public:
952     PInvokeDescriptor*  m_pPInvoke;
953     ImportList  m_ImportList;
954     void SetPinvoke(BinStr* DllName, int Ordinal, BinStr* Alias, int Attrs);
955     HRESULT EmitPinvokeMap(mdToken tk, PInvokeDescriptor* pDescr);
956     ImportDescriptor* EmitImport(BinStr* DllName);
957     void EmitImports();
958
959     // Debug metadata paraphernalia
960 public:
961     ISymUnmanagedWriter* m_pSymWriter;
962     ISymUnmanagedDocumentWriter* m_pSymDocument;
963     DocWriterList m_DocWriterList;
964     ULONG m_ulCurLine; // set by Parser
965     ULONG m_ulCurColumn; // set by Parser
966     ULONG m_ulLastDebugLine;
967     ULONG m_ulLastDebugColumn;
968     ULONG m_ulLastDebugLineEnd;
969     ULONG m_ulLastDebugColumnEnd;
970     DWORD m_dwIncludeDebugInfo;
971     BOOL  m_fGeneratePDB;
972     char m_szSourceFileName[MAX_FILENAME_LENGTH*3+1];
973     WCHAR m_wzOutputFileName[MAX_FILENAME_LENGTH];
974     WCHAR m_wzSourceFileName[MAX_FILENAME_LENGTH];
975         GUID    m_guidLang;
976         GUID    m_guidLangVendor;
977         GUID    m_guidDoc;
978
979     // Security paraphernalia
980 public:
981     void AddPermissionDecl(CorDeclSecurity action, mdToken type, NVPair *pairs)
982     {
983         PermissionDecl *decl = new PermissionDecl(action, type, pairs);
984         if(decl==NULL)
985         {
986             report->error("\nOut of memory!\n");
987             return;
988         }
989         if (m_pCurMethod) {
990             decl->m_Next = m_pCurMethod->m_pPermissions;
991             m_pCurMethod->m_pPermissions = decl;
992         } else if (m_pCurClass) {
993             decl->m_Next = m_pCurClass->m_pPermissions;
994             m_pCurClass->m_pPermissions = decl;
995         } else if (m_pManifest && m_pManifest->m_pAssembly) {
996             decl->m_Next = m_pManifest->m_pAssembly->m_pPermissions;
997             m_pManifest->m_pAssembly->m_pPermissions = decl;
998         } else {
999             report->error("Cannot declare security permissions without the owner\n");
1000             delete decl;
1001         }
1002     };
1003
1004     void AddPermissionDecl(CorDeclSecurity action, mdToken type, BinStr *pbsPairs)
1005     {
1006         PermissionDecl *decl = new PermissionDecl(action, type, pbsPairs);
1007         if(decl==NULL)
1008         {
1009             report->error("\nOut of memory!\n");
1010             return;
1011         }
1012         if (m_pCurMethod) {
1013             decl->m_Next = m_pCurMethod->m_pPermissions;
1014             m_pCurMethod->m_pPermissions = decl;
1015         } else if (m_pCurClass) {
1016             decl->m_Next = m_pCurClass->m_pPermissions;
1017             m_pCurClass->m_pPermissions = decl;
1018         } else if (m_pManifest && m_pManifest->m_pAssembly) {
1019             decl->m_Next = m_pManifest->m_pAssembly->m_pPermissions;
1020             m_pManifest->m_pAssembly->m_pPermissions = decl;
1021         } else {
1022             report->error("Cannot declare security permissions without the owner\n");
1023             delete decl;
1024         }
1025     };
1026
1027     void AddPermissionSetDecl(CorDeclSecurity action, BinStr *value)
1028     {
1029         PermissionSetDecl *decl = new PermissionSetDecl(action, value);
1030         if(decl==NULL)
1031         {
1032             report->error("\nOut of memory!\n");
1033             return;
1034         }
1035         if (m_pCurMethod) {
1036             decl->m_Next = m_pCurMethod->m_pPermissionSets;
1037             m_pCurMethod->m_pPermissionSets = decl;
1038         } else if (m_pCurClass) {
1039             decl->m_Next = m_pCurClass->m_pPermissionSets;
1040             m_pCurClass->m_pPermissionSets = decl;
1041         } else if (m_pManifest && m_pManifest->m_pAssembly) {
1042             decl->m_Next = m_pManifest->m_pAssembly->m_pPermissionSets;
1043             m_pManifest->m_pAssembly->m_pPermissionSets = decl;
1044         } else {
1045             report->error("Cannot declare security permission sets without the owner\n");
1046             delete decl;
1047         }
1048     };
1049     void EmitSecurityInfo(mdToken           token,
1050                           PermissionDecl*   pPermissions,
1051                           PermissionSetDecl*pPermissionSets);
1052     BinStr* EncodeSecAttr(__in __nullterminated char* szReflName, BinStr* pbsSecAttrBlob, unsigned nProps);
1053
1054     HRESULT AllocateStrongNameSignature();
1055
1056     // Custom values paraphernalia:
1057 public:
1058     mdToken m_tkCurrentCVOwner;
1059     CustomDescrList* m_pCustomDescrList;
1060     CustomDescrListStack m_CustomDescrListStack;
1061     CustomDescrList  m_CustomDescrList;
1062
1063     void DefineCV(CustomDescr* pCD)
1064     {
1065         if(pCD)
1066         {
1067             ULONG           cTemp = 0;
1068             void *          pBlobBody = NULL;
1069             mdToken         cv;
1070             mdToken tkOwnerType, tkTypeType = TypeFromToken(pCD->tkType);
1071
1072             if((tkTypeType != 0x99000000)&&(tkTypeType != 0x98000000))
1073             {
1074                 tkOwnerType = TypeFromToken(pCD->tkOwner);
1075                 if((tkOwnerType != 0x99000000)&&(tkOwnerType != 0x98000000))
1076                 {
1077                     if(pCD->pBlob)
1078                     {
1079                         pBlobBody = (void *)(pCD->pBlob->ptr());
1080                         cTemp = pCD->pBlob->length();
1081                     }
1082                     if (pCD->tkInterfacePair)
1083                     {
1084                         pCD->tkOwner = GetInterfaceImpl(pCD->tkOwner, pCD->tkInterfacePair);
1085                     }
1086                     m_pEmitter->DefineCustomAttribute(pCD->tkOwner,pCD->tkType,pBlobBody,cTemp,&cv);
1087                                 
1088                     delete pCD;
1089                     return;
1090                 }
1091             }
1092             m_CustomDescrList.PUSH(pCD);
1093         }
1094     };
1095     void EmitCustomAttributes(mdToken tok, CustomDescrList* pCDL)
1096     {
1097         CustomDescr *pCD;
1098         if(pCDL == NULL || RidFromToken(tok)==0) return;
1099         while((pCD = pCDL->POP()))
1100         {
1101             pCD->tkOwner = tok;
1102             DefineCV(pCD);
1103         }
1104     };
1105
1106     void EmitUnresolvedCustomAttributes(); // implementation: writer.cpp
1107     // VTable blob (if any)
1108 public:
1109     BinStr *m_pVTable;
1110     // Field marshaling
1111     BinStr *m_pMarshal;
1112     // VTable fixup list
1113     VTFList m_VTFList;
1114         // Export Address Table entries list
1115         EATList m_EATList;
1116         HRESULT CreateExportDirectory();
1117         DWORD   EmitExportStub(DWORD dwVTFSlotRVA);
1118
1119     // Method implementation paraphernalia:
1120 private:
1121     MethodImplDList m_MethodImplDList;
1122 public:
1123     void AddMethodImpl(mdToken tkImplementedTypeSpec, __in __nullterminated char* szImplementedName, BinStr* pImplementedSig, 
1124                     mdToken tkImplementingTypeSpec, __in_opt __nullterminated char* szImplementingName, BinStr* pImplementingSig);
1125     BOOL EmitMethodImpls();
1126     // lexical scope handling paraphernalia:
1127     void EmitScope(Scope* pSCroot); // struct Scope - see Method.hpp
1128     // source file name paraphernalia
1129     BOOL m_fSourceFileSet;
1130     void SetSourceFileName(__in __nullterminated char* szName);
1131     void SetSourceFileName(BinStr* pbsName);
1132     // header flags
1133     DWORD   m_dwSubsystem;
1134     WORD    m_wSSVersionMajor;
1135     WORD    m_wSSVersionMinor;
1136     DWORD   m_dwComImageFlags;
1137         DWORD   m_dwFileAlignment;
1138         ULONGLONG       m_stBaseAddress;
1139     size_t  m_stSizeOfStackReserve;
1140     DWORD   m_dwCeeFileFlags;
1141     WORD    m_wMSVmajor;
1142     WORD    m_wMSVminor;
1143     BOOL    m_fAppContainer;
1144     BOOL    m_fHighEntropyVA;
1145
1146     // Former globals
1147     WCHAR *m_wzResourceFile;
1148     WCHAR *m_wzKeySourceName;
1149     bool OnErrGo;
1150     void SetCodePage(unsigned val) { g_uCodePage = val; };
1151     Clockwork* bClock;
1152     void SetClock(Clockwork* val) { bClock = val; };
1153     // ENC paraphernalia
1154     HRESULT InitMetaDataForENC(__in __nullterminated WCHAR* wzOrigFileName);
1155     BOOL EmitFieldsMethodsENC(Class* pClass);
1156     BOOL EmitEventsPropsENC(Class* pClass);
1157     HRESULT CreateDeltaFiles(__in __nullterminated WCHAR *pwzOutputFilename);
1158
1159     // Syntactic sugar paraphernalia
1160 private:
1161     TypeDefDList m_TypeDefDList;
1162 public:
1163     void AddTypeDef(BinStr* pbsTypeSpec, __in_z __in char* szName)
1164     {
1165         m_TypeDefDList.PUSH(new TypeDefDescr(szName, pbsTypeSpec, ResolveTypeSpec(pbsTypeSpec)));
1166     };
1167     void AddTypeDef(mdToken tkTypeSpec, __in_z __in char* szName)
1168     {
1169         m_TypeDefDList.PUSH(new TypeDefDescr(szName, NULL, tkTypeSpec));
1170     };
1171     void AddTypeDef(CustomDescr* pCA, __in_z __in char* szName)
1172     {
1173         TypeDefDescr* pNew = new TypeDefDescr(szName,NULL,mdtCustomAttribute);
1174         pNew->m_pCA = pCA;
1175         m_TypeDefDList.PUSH(pNew);
1176     };
1177     TypeDefDescr* FindTypeDef(__in_z __in char* szName)
1178     {
1179         CHECK_LOCAL_STATIC_VAR(static TypeDefDescr X(NULL, NULL, 0));
1180
1181         X.m_szName = szName;
1182         TypeDefDescr* Y = m_TypeDefDList.FIND(&X);
1183         X.m_szName = NULL; // to avoid deletion when X goes out of scope
1184         return Y;
1185         //return m_TypeDefDList.FIND(szName);
1186     };
1187     unsigned NumTypeDefs() {return m_TypeDefDList.COUNT();};
1188 private:
1189     HRESULT GetCAName(mdToken tkCA, __out LPWSTR *ppszName);
1190 };
1191
1192 #endif  // Assember_h
1193
1194 #ifdef _MSC_VER
1195 #pragma warning(default : 4640)
1196 #endif
1197
1198