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 | // sigparser.h |
6 | // |
7 | |
8 | // |
9 | |
10 | #ifndef _H_SIGPARSER |
11 | #define _H_SIGPARSER |
12 | |
13 | #include "utilcode.h" |
14 | #include "corhdr.h" |
15 | #include "corinfo.h" |
16 | #include "corpriv.h" |
17 | |
18 | //--------------------------------------------------------------------------------------- |
19 | // These macros define how arguments are mapped to the stack in the managed calling convention. |
20 | // We assume to be walking a method's signature left-to-right, in the virtual calling convention. |
21 | // See MethodDesc::Call for details on this virtual calling convention. |
22 | // These macros tell us whether the arguments we see as we proceed with the signature walk are mapped |
23 | // to increasing or decreasing stack addresses. This is valid only for arguments that go on the stack. |
24 | //--------------------------------------------------------------------------------------- |
25 | #if defined(_TARGET_X86_) |
26 | #define STACK_GROWS_DOWN_ON_ARGS_WALK |
27 | #else |
28 | #define STACK_GROWS_UP_ON_ARGS_WALK |
29 | #endif |
30 | |
31 | |
32 | //------------------------------------------------------------------------ |
33 | // Encapsulates how compressed integers and typeref tokens are encoded into |
34 | // a bytestream. |
35 | // |
36 | // As you use this class please understand the implicit normalizations |
37 | // on the CorElementType's returned by the various methods, especially |
38 | // for variable types (e.g. !0 in generic signatures), string types |
39 | // (i.e. E_T_STRING), object types (E_T_OBJECT), constructed types |
40 | // (e.g. List<int>) and enums. |
41 | //------------------------------------------------------------------------ |
42 | class SigParser |
43 | { |
44 | protected: |
45 | // This type is performance critical - do not add fields to it. |
46 | // (If you must, check for managed types that may use a SigParser or SigPointer inline, like ArgIterator.) |
47 | PCCOR_SIGNATURE m_ptr; |
48 | DWORD m_dwLen; |
49 | |
50 | //------------------------------------------------------------------------ |
51 | // Skips specified number of bytes WITHOUT VALIDATION. Only to be used |
52 | // when it is known that it won't overflow the signature buffer. |
53 | //------------------------------------------------------------------------ |
54 | FORCEINLINE void SkipBytes(ULONG cb) |
55 | { |
56 | SUPPORTS_DAC; |
57 | _ASSERT(cb <= m_dwLen); |
58 | m_ptr += cb; |
59 | m_dwLen -= cb; |
60 | } |
61 | |
62 | public: |
63 | //------------------------------------------------------------------------ |
64 | // Constructor. |
65 | //------------------------------------------------------------------------ |
66 | SigParser() { |
67 | LIMITED_METHOD_DAC_CONTRACT; |
68 | m_ptr = NULL; |
69 | m_dwLen = 0; |
70 | } |
71 | |
72 | SigParser(const SigParser &sig); |
73 | |
74 | //------------------------------------------------------------------------ |
75 | // Initialize |
76 | //------------------------------------------------------------------------ |
77 | FORCEINLINE SigParser(PCCOR_SIGNATURE ptr) |
78 | { |
79 | LIMITED_METHOD_CONTRACT; |
80 | |
81 | m_ptr = ptr; |
82 | // We don't know the size of the signature, so we'll say it's "big enough" |
83 | m_dwLen = 0xffffffff; |
84 | } |
85 | |
86 | FORCEINLINE SigParser(PCCOR_SIGNATURE ptr, DWORD len) |
87 | { |
88 | LIMITED_METHOD_CONTRACT; |
89 | |
90 | m_ptr = ptr; |
91 | m_dwLen = len; |
92 | } |
93 | |
94 | inline void SetSig(PCCOR_SIGNATURE ptr) |
95 | { |
96 | LIMITED_METHOD_CONTRACT; |
97 | |
98 | m_ptr = ptr; |
99 | // We don't know the size of the signature, so we'll say it's "big enough" |
100 | m_dwLen = 0xffffffff; |
101 | } |
102 | |
103 | inline void SetSig(PCCOR_SIGNATURE ptr, DWORD len) |
104 | { |
105 | LIMITED_METHOD_CONTRACT; |
106 | |
107 | m_ptr = ptr; |
108 | m_dwLen = len; |
109 | } |
110 | |
111 | |
112 | inline BOOL IsNull() const |
113 | { |
114 | LIMITED_METHOD_CONTRACT; |
115 | |
116 | return (m_ptr == NULL); |
117 | } |
118 | |
119 | // Returns represented signature as pointer and size. |
120 | void |
121 | GetSignature( |
122 | PCCOR_SIGNATURE * pSig, |
123 | DWORD * pcbSigSize) |
124 | { |
125 | *pSig = m_ptr; |
126 | *pcbSigSize = m_dwLen; |
127 | } |
128 | |
129 | |
130 | //========================================================================= |
131 | // The RAW interface for reading signatures. You see exactly the signature, |
132 | // apart from custom modifiers which for historical reasons tend to get eaten. |
133 | // |
134 | // DO NOT USE THESE METHODS UNLESS YOU'RE TOTALLY SURE YOU WANT |
135 | // THE RAW signature. You nearly always want GetElemTypeClosed() or |
136 | // PeekElemTypeClosed() or one of the MetaSig functions. See the notes above. |
137 | // These functions will return E_T_INTERNAL, E_T_VAR, E_T_MVAR and such |
138 | // so the caller must be able to deal with those |
139 | //========================================================================= |
140 | |
141 | //------------------------------------------------------------------------ |
142 | // Remove one compressed integer (using CorSigUncompressData) from |
143 | // the head of the stream and return it. |
144 | //------------------------------------------------------------------------ |
145 | __checkReturn |
146 | FORCEINLINE HRESULT GetData(ULONG* data) |
147 | { |
148 | WRAPPER_NO_CONTRACT; |
149 | SUPPORTS_DAC; |
150 | |
151 | ULONG sizeOfData = 0; |
152 | ULONG tempData; |
153 | |
154 | if (data == NULL) |
155 | data = &tempData; |
156 | |
157 | HRESULT hr = CorSigUncompressData(m_ptr, m_dwLen, data, &sizeOfData); |
158 | |
159 | if (SUCCEEDED(hr)) |
160 | { |
161 | SkipBytes(sizeOfData); |
162 | } |
163 | |
164 | return hr; |
165 | } |
166 | |
167 | |
168 | //------------------------------------------------------------------------- |
169 | // Remove one byte and return it. |
170 | //------------------------------------------------------------------------- |
171 | __checkReturn |
172 | FORCEINLINE HRESULT GetByte(BYTE *data) |
173 | { |
174 | LIMITED_METHOD_CONTRACT; |
175 | |
176 | if (m_dwLen > 0) |
177 | { |
178 | if (data != NULL) |
179 | *data = *m_ptr; |
180 | |
181 | SkipBytes(1); |
182 | |
183 | return S_OK; |
184 | } |
185 | |
186 | if (data != NULL) |
187 | *data = 0; |
188 | return META_E_BAD_SIGNATURE; |
189 | } |
190 | |
191 | //------------------------------------------------------------------------- |
192 | // Peek at value of one byte and return it. |
193 | //------------------------------------------------------------------------- |
194 | __checkReturn |
195 | FORCEINLINE HRESULT PeekByte(BYTE *data) |
196 | { |
197 | LIMITED_METHOD_CONTRACT; |
198 | |
199 | if (m_dwLen > 0) |
200 | { |
201 | if (data != NULL) |
202 | *data = *m_ptr; |
203 | |
204 | return S_OK; |
205 | } |
206 | |
207 | if (data != NULL) |
208 | *data = 0; |
209 | return META_E_BAD_SIGNATURE; |
210 | } |
211 | |
212 | //------------------------------------------------------------------------- |
213 | // The element type as defined in CorElementType. No normalization for |
214 | // generics (E_T_VAR, E_T_MVAR,..) or dynamic methods (E_T_INTERNAL occurs) |
215 | //------------------------------------------------------------------------- |
216 | __checkReturn |
217 | HRESULT GetElemTypeSlow(CorElementType * etype) |
218 | { |
219 | WRAPPER_NO_CONTRACT; |
220 | SUPPORTS_DAC; |
221 | |
222 | CorElementType tmpEType; |
223 | |
224 | if (etype == NULL) |
225 | etype = &tmpEType; |
226 | |
227 | SigParser sigTemp(*this); |
228 | |
229 | HRESULT hr = sigTemp.SkipCustomModifiers(); |
230 | |
231 | if (SUCCEEDED(hr)) |
232 | { |
233 | BYTE bElemType = 0; |
234 | hr = sigTemp.GetByte(&bElemType); |
235 | *etype = (CorElementType)bElemType; |
236 | |
237 | if (SUCCEEDED(hr)) |
238 | { |
239 | *this = sigTemp; |
240 | return S_OK; |
241 | } |
242 | } |
243 | |
244 | *etype = ELEMENT_TYPE_END; |
245 | |
246 | return META_E_BAD_SIGNATURE; |
247 | } |
248 | |
249 | // Inlined version |
250 | __checkReturn |
251 | FORCEINLINE HRESULT GetElemType(CorElementType * etype) |
252 | { |
253 | WRAPPER_NO_CONTRACT; |
254 | SUPPORTS_DAC; |
255 | |
256 | if (m_dwLen > 0) |
257 | { |
258 | CorElementType typ = (CorElementType) * m_ptr; |
259 | |
260 | if (typ < ELEMENT_TYPE_CMOD_REQD) // fast path with no modifiers: single byte |
261 | { |
262 | if (etype != NULL) |
263 | { |
264 | * etype = typ; |
265 | } |
266 | |
267 | SkipBytes(1); |
268 | |
269 | return S_OK; |
270 | } |
271 | } |
272 | |
273 | // Slower/normal path |
274 | return GetElemTypeSlow(etype); |
275 | } |
276 | |
277 | // Note: Calling convention is always one byte, not four bytes |
278 | __checkReturn |
279 | HRESULT GetCallingConvInfo(ULONG * data) |
280 | { |
281 | WRAPPER_NO_CONTRACT; |
282 | SUPPORTS_DAC; |
283 | |
284 | ULONG tmpData; |
285 | |
286 | if (data == NULL) |
287 | data = &tmpData; |
288 | |
289 | HRESULT hr = CorSigUncompressCallingConv(m_ptr, m_dwLen, data); |
290 | if (SUCCEEDED(hr)) |
291 | { |
292 | SkipBytes(1); |
293 | } |
294 | |
295 | return hr; |
296 | } |
297 | |
298 | __checkReturn |
299 | HRESULT GetCallingConv(ULONG* data) // @REVISIT_TODO: Calling convention is one byte, not four. |
300 | { |
301 | WRAPPER_NO_CONTRACT; |
302 | ULONG info; |
303 | HRESULT hr = GetCallingConvInfo(&info); |
304 | |
305 | if (SUCCEEDED(hr) && data != NULL) |
306 | { |
307 | *data = IMAGE_CEE_CS_CALLCONV_MASK & info; |
308 | } |
309 | |
310 | return hr; |
311 | } |
312 | |
313 | //------------------------------------------------------------------------ |
314 | // Non-destructive read of compressed integer. |
315 | //------------------------------------------------------------------------ |
316 | __checkReturn |
317 | HRESULT PeekData(ULONG *data) const |
318 | { |
319 | WRAPPER_NO_CONTRACT; |
320 | _ASSERTE(data != NULL); |
321 | |
322 | ULONG sizeOfData = 0; |
323 | return CorSigUncompressData(m_ptr, m_dwLen, data, &sizeOfData); |
324 | } |
325 | |
326 | |
327 | //------------------------------------------------------------------------ |
328 | // Non-destructive read of element type. |
329 | // |
330 | // This routine makes it look as if the String type is encoded |
331 | // via ELEMENT_TYPE_CLASS followed by a token for the String class, |
332 | // rather than the ELEMENT_TYPE_STRING. This is partially to avoid |
333 | // rewriting client code which depended on this behavior previously. |
334 | // But it also seems like the right thing to do generally. |
335 | // No normalization for generics (E_T_VAR, E_T_MVAR,..) or |
336 | // dynamic methods (E_T_INTERNAL occurs) |
337 | //------------------------------------------------------------------------ |
338 | __checkReturn |
339 | HRESULT PeekElemTypeSlow(CorElementType *etype) const |
340 | { |
341 | WRAPPER_NO_CONTRACT; |
342 | SUPPORTS_DAC; |
343 | |
344 | _ASSERTE(etype != NULL); |
345 | |
346 | SigParser sigTemp(*this); |
347 | HRESULT hr = sigTemp.GetElemType(etype); |
348 | if (SUCCEEDED(hr) && (*etype == ELEMENT_TYPE_STRING || *etype == ELEMENT_TYPE_OBJECT)) |
349 | *etype = ELEMENT_TYPE_CLASS; |
350 | |
351 | return hr; |
352 | } |
353 | |
354 | // inline version |
355 | __checkReturn |
356 | FORCEINLINE HRESULT PeekElemType(CorElementType *etype) const |
357 | { |
358 | WRAPPER_NO_CONTRACT; |
359 | SUPPORTS_DAC; |
360 | |
361 | _ASSERTE(etype != NULL); |
362 | |
363 | if (m_dwLen > 0) |
364 | { |
365 | CorElementType typ = (CorElementType) * m_ptr; |
366 | |
367 | if (typ < ELEMENT_TYPE_CMOD_REQD) // fast path with no modifiers: single byte |
368 | { |
369 | if ((typ == ELEMENT_TYPE_STRING) || (typ == ELEMENT_TYPE_OBJECT)) |
370 | { |
371 | *etype = ELEMENT_TYPE_CLASS; |
372 | } |
373 | else |
374 | { |
375 | *etype = typ; |
376 | } |
377 | |
378 | return S_OK; |
379 | } |
380 | } |
381 | |
382 | return PeekElemTypeSlow(etype); |
383 | } |
384 | |
385 | //------------------------------------------------------------------------- |
386 | // Returns the raw size of the type next in the signature, or returns |
387 | // E_INVALIDARG for base types that have variables sizes. |
388 | //------------------------------------------------------------------------- |
389 | __checkReturn |
390 | HRESULT PeekElemTypeSize(ULONG *pSize) |
391 | { |
392 | WRAPPER_NO_CONTRACT; |
393 | HRESULT hr = S_OK; |
394 | |
395 | DWORD dwSize = 0; |
396 | |
397 | if (pSize == NULL) |
398 | { |
399 | pSize = &dwSize; |
400 | } |
401 | |
402 | SigParser sigTemp(*this); |
403 | |
404 | hr = sigTemp.SkipAnyVASentinel(); |
405 | |
406 | if (FAILED(hr)) |
407 | { |
408 | return hr; |
409 | } |
410 | |
411 | *pSize = 0; |
412 | |
413 | BYTE bElementType = 0; |
414 | hr = sigTemp.GetByte(&bElementType); |
415 | |
416 | if (FAILED(hr)) |
417 | { |
418 | return hr; |
419 | } |
420 | |
421 | switch (bElementType) |
422 | { |
423 | case ELEMENT_TYPE_I8: |
424 | case ELEMENT_TYPE_U8: |
425 | case ELEMENT_TYPE_R8: |
426 | #ifdef _WIN64 |
427 | case ELEMENT_TYPE_I: |
428 | case ELEMENT_TYPE_U: |
429 | #endif // WIN64 |
430 | |
431 | *pSize = 8; |
432 | break; |
433 | |
434 | case ELEMENT_TYPE_I4: |
435 | case ELEMENT_TYPE_U4: |
436 | case ELEMENT_TYPE_R4: |
437 | #ifndef _WIN64 |
438 | case ELEMENT_TYPE_I: |
439 | case ELEMENT_TYPE_U: |
440 | #endif // _WIN64 |
441 | |
442 | *pSize = 4; |
443 | break; |
444 | |
445 | case ELEMENT_TYPE_I2: |
446 | case ELEMENT_TYPE_U2: |
447 | case ELEMENT_TYPE_CHAR: |
448 | *pSize = 2; |
449 | break; |
450 | |
451 | case ELEMENT_TYPE_I1: |
452 | case ELEMENT_TYPE_U1: |
453 | case ELEMENT_TYPE_BOOLEAN: |
454 | *pSize = 1; |
455 | break; |
456 | |
457 | case ELEMENT_TYPE_STRING: |
458 | case ELEMENT_TYPE_PTR: |
459 | case ELEMENT_TYPE_BYREF: |
460 | case ELEMENT_TYPE_CLASS: |
461 | case ELEMENT_TYPE_OBJECT: |
462 | case ELEMENT_TYPE_FNPTR: |
463 | case ELEMENT_TYPE_TYPEDBYREF: |
464 | case ELEMENT_TYPE_ARRAY: |
465 | case ELEMENT_TYPE_SZARRAY: |
466 | *pSize = sizeof(void *); |
467 | break; |
468 | |
469 | case ELEMENT_TYPE_VOID: |
470 | break; |
471 | |
472 | case ELEMENT_TYPE_END: |
473 | case ELEMENT_TYPE_CMOD_REQD: |
474 | case ELEMENT_TYPE_CMOD_OPT: |
475 | _ASSERTE(!"Asked for the size of an element that doesn't have a size!" ); |
476 | return E_INVALIDARG; |
477 | |
478 | case ELEMENT_TYPE_VALUETYPE: |
479 | _ASSERTE(!"Asked for the size of an element that doesn't have a size!" ); |
480 | return E_INVALIDARG; |
481 | |
482 | default: |
483 | |
484 | _ASSERTE( !"CorSigGetElementTypeSize given invalid signature to size!" ); |
485 | return META_E_BAD_SIGNATURE; |
486 | } |
487 | |
488 | return hr; |
489 | } |
490 | |
491 | //------------------------------------------------------------------------ |
492 | // Is this at the Sentinal (the ... in a varargs signature) that marks |
493 | // the begining of varguments that are not decared at the target |
494 | |
495 | bool AtSentinel() const |
496 | { |
497 | if (m_dwLen > 0) |
498 | return *m_ptr == ELEMENT_TYPE_SENTINEL; |
499 | else |
500 | return false; |
501 | } |
502 | |
503 | //------------------------------------------------------------------------ |
504 | // Removes a compressed metadata token and returns it. |
505 | // WARNING: dynamic methods do not have tokens so this api is completely |
506 | // broken in that case. Make sure you call this function if |
507 | // you are absolutely sure E_T_INTERNAL was not in the sig |
508 | //------------------------------------------------------------------------ |
509 | __checkReturn |
510 | FORCEINLINE |
511 | HRESULT GetToken(mdToken * token) |
512 | { |
513 | WRAPPER_NO_CONTRACT; |
514 | DWORD dwLen; |
515 | mdToken tempToken; |
516 | |
517 | if (token == NULL) |
518 | token = &tempToken; |
519 | |
520 | HRESULT hr = CorSigUncompressToken(m_ptr, m_dwLen, token, &dwLen); |
521 | |
522 | if (SUCCEEDED(hr)) |
523 | { |
524 | SkipBytes(dwLen); |
525 | } |
526 | |
527 | return hr; |
528 | } |
529 | |
530 | //------------------------------------------------------------------------ |
531 | // Removes a pointer value and returns it. Used for ELEMENT_TYPE_INTERNAL. |
532 | __checkReturn |
533 | FORCEINLINE |
534 | HRESULT GetPointer(void ** pPtr) |
535 | { |
536 | WRAPPER_NO_CONTRACT; |
537 | |
538 | if (m_dwLen < sizeof(void *)) |
539 | { // Not enough data to read a pointer |
540 | if (pPtr != NULL) |
541 | { |
542 | *pPtr = NULL; |
543 | } |
544 | return META_E_BAD_SIGNATURE; |
545 | } |
546 | if (pPtr != NULL) |
547 | { |
548 | *pPtr = *(void * UNALIGNED *)m_ptr; |
549 | } |
550 | SkipBytes(sizeof(void *)); |
551 | |
552 | return S_OK; |
553 | } |
554 | |
555 | //------------------------------------------------------------------------ |
556 | // Tests if two SigParsers point to the same location in the stream. |
557 | //------------------------------------------------------------------------ |
558 | FORCEINLINE BOOL Equals(SigParser sp) const |
559 | { |
560 | LIMITED_METHOD_CONTRACT; |
561 | |
562 | return m_ptr == sp.m_ptr; |
563 | } |
564 | |
565 | __checkReturn |
566 | HRESULT SkipCustomModifiers() |
567 | { |
568 | WRAPPER_NO_CONTRACT; |
569 | SUPPORTS_DAC; |
570 | |
571 | HRESULT hr = S_OK; |
572 | |
573 | SigParser sigTemp(*this); |
574 | |
575 | hr = sigTemp.SkipAnyVASentinel(); |
576 | |
577 | if (FAILED(hr)) |
578 | { |
579 | return hr; |
580 | } |
581 | |
582 | BYTE bElementType = 0; |
583 | |
584 | hr = sigTemp.PeekByte(&bElementType); |
585 | if (FAILED(hr)) |
586 | return hr; |
587 | |
588 | while ((ELEMENT_TYPE_CMOD_REQD == bElementType) || |
589 | (ELEMENT_TYPE_CMOD_OPT == bElementType)) |
590 | { |
591 | sigTemp.SkipBytes(1); |
592 | |
593 | mdToken token; |
594 | |
595 | hr = sigTemp.GetToken(&token); |
596 | |
597 | if (FAILED(hr)) |
598 | return hr; |
599 | |
600 | hr = sigTemp.PeekByte(&bElementType); |
601 | if (FAILED(hr)) |
602 | return hr; |
603 | } |
604 | |
605 | // Following custom modifiers must be an element type value which is less than ELEMENT_TYPE_MAX, or one of the other element types |
606 | // that we support while parsing various signatures |
607 | if (bElementType >= ELEMENT_TYPE_MAX) |
608 | { |
609 | switch (bElementType) |
610 | { |
611 | case ELEMENT_TYPE_VAR_ZAPSIG: |
612 | case ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG: |
613 | case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG: |
614 | case ELEMENT_TYPE_CANON_ZAPSIG: |
615 | case ELEMENT_TYPE_MODULE_ZAPSIG: |
616 | case ELEMENT_TYPE_PINNED: |
617 | break; |
618 | default: |
619 | return META_E_BAD_SIGNATURE; |
620 | } |
621 | } |
622 | |
623 | *this = sigTemp; |
624 | return hr; |
625 | }// SkipCustomModifiers |
626 | |
627 | __checkReturn |
628 | HRESULT SkipFunkyAndCustomModifiers() |
629 | { |
630 | WRAPPER_NO_CONTRACT; |
631 | SUPPORTS_DAC; |
632 | |
633 | SigParser sigTemp(*this); |
634 | HRESULT hr = S_OK; |
635 | hr = sigTemp.SkipAnyVASentinel(); |
636 | |
637 | if (FAILED(hr)) |
638 | { |
639 | return hr; |
640 | } |
641 | |
642 | BYTE bElementType = 0; |
643 | |
644 | hr = sigTemp.PeekByte(&bElementType); |
645 | if (FAILED(hr)) |
646 | return hr; |
647 | |
648 | while (ELEMENT_TYPE_CMOD_REQD == bElementType || |
649 | ELEMENT_TYPE_CMOD_OPT == bElementType || |
650 | ELEMENT_TYPE_MODIFIER == bElementType || |
651 | ELEMENT_TYPE_PINNED == bElementType) |
652 | { |
653 | sigTemp.SkipBytes(1); |
654 | |
655 | mdToken token; |
656 | |
657 | hr = sigTemp.GetToken(&token); |
658 | |
659 | if (FAILED(hr)) |
660 | return hr; |
661 | |
662 | hr = sigTemp.PeekByte(&bElementType); |
663 | if (FAILED(hr)) |
664 | return hr; |
665 | } |
666 | |
667 | // Following custom modifiers must be an element type value which is less than ELEMENT_TYPE_MAX, or one of the other element types |
668 | // that we support while parsing various signatures |
669 | if (bElementType >= ELEMENT_TYPE_MAX) |
670 | { |
671 | switch (bElementType) |
672 | { |
673 | case ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG: |
674 | case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG: |
675 | case ELEMENT_TYPE_CANON_ZAPSIG: |
676 | case ELEMENT_TYPE_MODULE_ZAPSIG: |
677 | case ELEMENT_TYPE_PINNED: |
678 | break; |
679 | default: |
680 | return META_E_BAD_SIGNATURE; |
681 | } |
682 | } |
683 | |
684 | *this = sigTemp; |
685 | return hr; |
686 | }// SkipFunkyAndCustomModifiers |
687 | |
688 | |
689 | __checkReturn |
690 | HRESULT SkipAnyVASentinel() |
691 | { |
692 | WRAPPER_NO_CONTRACT; |
693 | |
694 | HRESULT hr = S_OK; |
695 | BYTE bElementType = 0; |
696 | |
697 | hr = PeekByte(&bElementType); |
698 | if (FAILED(hr)) |
699 | return hr; |
700 | |
701 | if (bElementType == ELEMENT_TYPE_SENTINEL) |
702 | { |
703 | SkipBytes(1); |
704 | } |
705 | |
706 | return hr; |
707 | }// SkipAnyVASentinel |
708 | |
709 | //------------------------------------------------------------------------ |
710 | // Assumes that the SigParser points to the start of an element type |
711 | // (i.e. function parameter, function return type or field type.) |
712 | // Advances the pointer to the first data after the element type. |
713 | //------------------------------------------------------------------------ |
714 | __checkReturn |
715 | HRESULT SkipExactlyOne(); |
716 | |
717 | //------------------------------------------------------------------------ |
718 | // Skip only the method header of the signature, not the signature of |
719 | // the arguments. |
720 | //------------------------------------------------------------------------ |
721 | __checkReturn |
722 | HRESULT (ULONG *pcArgs); |
723 | |
724 | //------------------------------------------------------------------------ |
725 | // Skip a sub signature (as immediately follows an ELEMENT_TYPE_FNPTR). |
726 | //------------------------------------------------------------------------ |
727 | __checkReturn |
728 | HRESULT SkipSignature(); |
729 | |
730 | public: |
731 | |
732 | //------------------------------------------------------------------------ |
733 | // Return pointer |
734 | // PLEASE DON'T USE THIS. |
735 | // |
736 | // Return the internal pointer. It's hard to resist, but please try |
737 | // not to use this. Certainly don't use it if there's any chance of the |
738 | // signature containing generic type variables. |
739 | // |
740 | // It's currently only used for working on the |
741 | // signatures stored in TypeSpec tokens (we should add a new abstraction, |
742 | // i.e. on MetaSig for this) and a couple of places to do with COM |
743 | // and native interop signature parsing. |
744 | // <REVISIT_TODO>We should try to get rid of these uses as well. </REVISIT_TODO> |
745 | //------------------------------------------------------------------------ |
746 | PCCOR_SIGNATURE GetPtr() const |
747 | { |
748 | LIMITED_METHOD_DAC_CONTRACT; |
749 | return m_ptr; |
750 | } |
751 | |
752 | }; // class SigParser |
753 | |
754 | //------------------------------------------------------------------------ |
755 | FORCEINLINE |
756 | SigParser::SigParser( |
757 | const SigParser &sig) |
758 | : m_ptr(sig.m_ptr), m_dwLen(sig.m_dwLen) |
759 | { |
760 | LIMITED_METHOD_DAC_CONTRACT; |
761 | } |
762 | |
763 | /*****************************************************************/ |
764 | /* CorTypeInfo is a single global table that you can hang information |
765 | about ELEMENT_TYPE_* */ |
766 | |
767 | class CorTypeInfo |
768 | { |
769 | protected: |
770 | struct CorTypeInfoEntry |
771 | { |
772 | LPCUTF8 nameSpace; |
773 | LPCUTF8 className; |
774 | CorElementType type : 8; |
775 | unsigned size : 8; |
776 | CorInfoGCType gcType : 3; |
777 | unsigned isArray : 1; |
778 | unsigned isPrim : 1; |
779 | unsigned isFloat : 1; |
780 | unsigned isModifier : 1; |
781 | unsigned isGenVar : 1; |
782 | // 1 more byte here to use for 32-bit |
783 | }; |
784 | |
785 | protected: |
786 | FORCEINLINE static const CorTypeInfoEntry &GetTypeInfo(CorElementType type) |
787 | { |
788 | CONTRACTL |
789 | { |
790 | THROWS; |
791 | GC_NOTRIGGER; |
792 | SUPPORTS_DAC; |
793 | #ifdef MODE_ANY |
794 | MODE_ANY; |
795 | #endif |
796 | } |
797 | CONTRACTL_END; |
798 | |
799 | if (type >= (CorElementType)_countof(info)) |
800 | { |
801 | ThrowHR(COR_E_BADIMAGEFORMAT); |
802 | } |
803 | return info[type]; |
804 | } |
805 | FORCEINLINE static const CorTypeInfoEntry &GetTypeInfo_NoThrow(CorElementType type) |
806 | { |
807 | LIMITED_METHOD_DAC_CONTRACT; |
808 | |
809 | if (type >= (CorElementType)_countof(info)) |
810 | { |
811 | return info[ELEMENT_TYPE_END]; |
812 | } |
813 | return info[type]; |
814 | } |
815 | |
816 | public: |
817 | |
818 | FORCEINLINE static LPCUTF8 GetName(CorElementType type) |
819 | { |
820 | WRAPPER_NO_CONTRACT; |
821 | |
822 | return GetTypeInfo(type).className; |
823 | } |
824 | |
825 | FORCEINLINE static LPCUTF8 GetNamespace(CorElementType type) |
826 | { |
827 | WRAPPER_NO_CONTRACT; |
828 | |
829 | return GetTypeInfo(type).nameSpace; |
830 | } |
831 | |
832 | static void CheckConsistency() |
833 | { |
834 | LIMITED_METHOD_CONTRACT; |
835 | |
836 | for (int i = 0; i < (int)_countof(info); i++) |
837 | { |
838 | _ASSERTE(info[i].type == i); |
839 | } |
840 | } |
841 | |
842 | FORCEINLINE static CorInfoGCType GetGCType(CorElementType type) |
843 | { |
844 | WRAPPER_NO_CONTRACT; |
845 | |
846 | return GetTypeInfo(type).gcType; |
847 | } |
848 | FORCEINLINE static CorInfoGCType GetGCType_NoThrow(CorElementType type) |
849 | { |
850 | LIMITED_METHOD_DAC_CONTRACT; |
851 | |
852 | return GetTypeInfo_NoThrow(type).gcType; |
853 | } |
854 | |
855 | static BOOL IsObjRef(CorElementType type) |
856 | { |
857 | WRAPPER_NO_CONTRACT; |
858 | SUPPORTS_DAC; |
859 | |
860 | return (GetGCType(type) == TYPE_GC_REF); |
861 | } |
862 | static BOOL IsObjRef_NoThrow(CorElementType type) |
863 | { |
864 | WRAPPER_NO_CONTRACT; |
865 | SUPPORTS_DAC; |
866 | |
867 | return (GetGCType_NoThrow(type) == TYPE_GC_REF); |
868 | } |
869 | |
870 | FORCEINLINE static BOOL IsGenericVariable(CorElementType type) |
871 | { |
872 | WRAPPER_NO_CONTRACT; |
873 | |
874 | return GetTypeInfo(type).isGenVar; |
875 | } |
876 | FORCEINLINE static BOOL IsGenericVariable_NoThrow(CorElementType type) |
877 | { |
878 | WRAPPER_NO_CONTRACT; |
879 | |
880 | return GetTypeInfo_NoThrow(type).isGenVar; |
881 | } |
882 | |
883 | FORCEINLINE static BOOL IsArray(CorElementType type) |
884 | { |
885 | WRAPPER_NO_CONTRACT; |
886 | |
887 | return GetTypeInfo(type).isArray; |
888 | } |
889 | FORCEINLINE static BOOL IsArray_NoThrow(CorElementType type) |
890 | { |
891 | WRAPPER_NO_CONTRACT; |
892 | |
893 | return GetTypeInfo_NoThrow(type).isArray; |
894 | } |
895 | |
896 | FORCEINLINE static BOOL IsFloat(CorElementType type) |
897 | { |
898 | WRAPPER_NO_CONTRACT; |
899 | |
900 | return GetTypeInfo(type).isFloat; |
901 | } |
902 | FORCEINLINE static BOOL IsFloat_NoThrow(CorElementType type) |
903 | { |
904 | WRAPPER_NO_CONTRACT; |
905 | |
906 | return GetTypeInfo_NoThrow(type).isFloat; |
907 | } |
908 | |
909 | FORCEINLINE static BOOL IsModifier(CorElementType type) |
910 | { |
911 | WRAPPER_NO_CONTRACT; |
912 | |
913 | return GetTypeInfo(type).isModifier; |
914 | } |
915 | FORCEINLINE static BOOL IsModifier_NoThrow(CorElementType type) |
916 | { |
917 | WRAPPER_NO_CONTRACT; |
918 | |
919 | return GetTypeInfo_NoThrow(type).isModifier; |
920 | } |
921 | |
922 | FORCEINLINE static BOOL IsPrimitiveType(CorElementType type) |
923 | { |
924 | WRAPPER_NO_CONTRACT; |
925 | |
926 | return GetTypeInfo(type).isPrim; |
927 | } |
928 | FORCEINLINE static BOOL IsPrimitiveType_NoThrow(CorElementType type) |
929 | { |
930 | WRAPPER_NO_CONTRACT; |
931 | |
932 | return GetTypeInfo_NoThrow(type).isPrim; |
933 | } |
934 | |
935 | FORCEINLINE static unsigned Size(CorElementType type) |
936 | { |
937 | WRAPPER_NO_CONTRACT; |
938 | |
939 | return GetTypeInfo(type).size; |
940 | } |
941 | FORCEINLINE static unsigned Size_NoThrow(CorElementType type) |
942 | { |
943 | WRAPPER_NO_CONTRACT; |
944 | |
945 | return GetTypeInfo_NoThrow(type).size; |
946 | } |
947 | |
948 | static CorElementType FindPrimitiveType(LPCUTF8 name); |
949 | |
950 | protected: |
951 | static const CorTypeInfoEntry info[ELEMENT_TYPE_MAX]; |
952 | |
953 | }; // class CorTypeInfo |
954 | |
955 | |
956 | // Returns the address of the payload inside the stackelem |
957 | inline void* StackElemEndianessFixup(void* pStackElem, UINT cbSize) { |
958 | LIMITED_METHOD_CONTRACT; |
959 | |
960 | BYTE *pRetVal = (BYTE*)pStackElem; |
961 | |
962 | #if BIGENDIAN |
963 | switch (cbSize) |
964 | { |
965 | case 1: |
966 | pRetVal += sizeof(void*)-1; |
967 | break; |
968 | case 2: |
969 | pRetVal += sizeof(void*)-2; |
970 | break; |
971 | #ifdef _WIN64 |
972 | case 4: |
973 | pRetVal += sizeof(void*)-4; |
974 | break; |
975 | #endif |
976 | default: |
977 | // nothing to do |
978 | break; |
979 | } |
980 | #endif |
981 | |
982 | return pRetVal; |
983 | } |
984 | |
985 | #endif /* _H_SIGINFOBASE */ |
986 | |