3 * Routines for accessing the metadata
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "tabledefs.h"
21 #include "mono-endian.h"
23 #include "tokentype.h"
24 #include "class-internals.h"
25 #include "metadata-internals.h"
26 #include "verify-internals.h"
29 #include "debug-helpers.h"
30 #include "abi-details.h"
31 #include "cominterop.h"
32 #include <mono/metadata/exception-internals.h>
33 #include <mono/utils/mono-error-internals.h>
34 #include <mono/utils/mono-memory-model.h>
35 #include <mono/utils/bsearch.h>
36 #include <mono/utils/atomic.h>
37 #include <mono/utils/unlocked.h>
38 #include <mono/utils/mono-counters.h>
40 static gint32 img_set_cache_hit
, img_set_cache_miss
, img_set_count
;
43 /* Auxiliary structure used for caching inflated signatures */
45 MonoMethodSignature
*sig
;
46 MonoGenericContext context
;
47 } MonoInflatedMethodSignature
;
49 static gboolean
do_mono_metadata_parse_type (MonoType
*type
, MonoImage
*m
, MonoGenericContainer
*container
, gboolean transient
,
50 const char *ptr
, const char **rptr
, MonoError
*error
);
52 static gboolean
do_mono_metadata_type_equal (MonoType
*t1
, MonoType
*t2
, gboolean signature_only
);
53 static gboolean
mono_metadata_class_equal (MonoClass
*c1
, MonoClass
*c2
, gboolean signature_only
);
54 static gboolean
mono_metadata_fnptr_equal (MonoMethodSignature
*s1
, MonoMethodSignature
*s2
, gboolean signature_only
);
55 static gboolean
_mono_metadata_generic_class_equal (const MonoGenericClass
*g1
, const MonoGenericClass
*g2
,
56 gboolean signature_only
);
57 static void free_generic_inst (MonoGenericInst
*ginst
);
58 static void free_generic_class (MonoGenericClass
*ginst
);
59 static void free_inflated_method (MonoMethodInflated
*method
);
60 static void free_inflated_signature (MonoInflatedMethodSignature
*sig
);
61 static void free_aggregate_modifiers (MonoAggregateModContainer
*amods
);
62 static void mono_metadata_field_info_full (MonoImage
*meta
, guint32 index
, guint32
*offset
, guint32
*rva
, MonoMarshalSpec
**marshal_spec
, gboolean alloc_from_image
);
64 static MonoType
* mono_signature_get_params_internal (MonoMethodSignature
*sig
, gpointer
*iter
);
67 * This enumeration is used to describe the data types in the metadata
78 /* Index into Blob heap */
81 /* Index into String heap */
87 /* Pointer into a table */
90 /* HasConstant:Parent pointer (Param, Field or Property) */
93 /* HasCustomAttribute index. Indexes any table except CustomAttribute */
96 /* CustomAttributeType encoded index */
99 /* HasDeclSecurity index: TypeDef Method or Assembly */
102 /* Implementation coded index: File, Export AssemblyRef */
105 /* HasFieldMarshal coded index: Field or Param table */
108 /* MemberForwardedIndex: Field or Method */
111 /* TypeDefOrRef coded index: typedef, typeref, typespec */
114 /* MemberRefParent coded index: typeref, moduleref, method, memberref, typesepc, typedef */
117 /* MethodDefOrRef coded index: Method or Member Ref table */
120 /* HasSemantic coded index: Event or Property */
123 /* ResolutionScope coded index: Module, ModuleRef, AssemblytRef, TypeRef */
126 /* CustomDebugInformation parent encoded index */
127 MONO_MT_HASCUSTDEBUG_IDX
130 const static unsigned char TableSchemas
[] = {
131 #define ASSEMBLY_SCHEMA_OFFSET 0
132 MONO_MT_UINT32
, /* "HashId" }, */
133 MONO_MT_UINT16
, /* "Major" }, */
134 MONO_MT_UINT16
, /* "Minor" }, */
135 MONO_MT_UINT16
, /* "BuildNumber" }, */
136 MONO_MT_UINT16
, /* "RevisionNumber" }, */
137 MONO_MT_UINT32
, /* "Flags" }, */
138 MONO_MT_BLOB_IDX
, /* "PublicKey" }, */
139 MONO_MT_STRING_IDX
, /* "Name" }, */
140 MONO_MT_STRING_IDX
, /* "Culture" }, */
143 #define ASSEMBLYOS_SCHEMA_OFFSET ASSEMBLY_SCHEMA_OFFSET + 10
144 MONO_MT_UINT32
, /* "OSPlatformID" }, */
145 MONO_MT_UINT32
, /* "OSMajor" }, */
146 MONO_MT_UINT32
, /* "OSMinor" }, */
149 #define ASSEMBLYPROC_SCHEMA_OFFSET ASSEMBLYOS_SCHEMA_OFFSET + 4
150 MONO_MT_UINT32
, /* "Processor" }, */
153 #define ASSEMBLYREF_SCHEMA_OFFSET ASSEMBLYPROC_SCHEMA_OFFSET + 2
154 MONO_MT_UINT16
, /* "Major" }, */
155 MONO_MT_UINT16
, /* "Minor" }, */
156 MONO_MT_UINT16
, /* "Build" }, */
157 MONO_MT_UINT16
, /* "Revision" }, */
158 MONO_MT_UINT32
, /* "Flags" }, */
159 MONO_MT_BLOB_IDX
, /* "PublicKeyOrToken" }, */
160 MONO_MT_STRING_IDX
, /* "Name" }, */
161 MONO_MT_STRING_IDX
, /* "Culture" }, */
162 MONO_MT_BLOB_IDX
, /* "HashValue" }, */
165 #define ASSEMBLYREFOS_SCHEMA_OFFSET ASSEMBLYREF_SCHEMA_OFFSET + 10
166 MONO_MT_UINT32
, /* "OSPlatformID" }, */
167 MONO_MT_UINT32
, /* "OSMajorVersion" }, */
168 MONO_MT_UINT32
, /* "OSMinorVersion" }, */
169 MONO_MT_TABLE_IDX
, /* "AssemblyRef:AssemblyRef" }, */
172 #define ASSEMBLYREFPROC_SCHEMA_OFFSET ASSEMBLYREFOS_SCHEMA_OFFSET + 5
173 MONO_MT_UINT32
, /* "Processor" }, */
174 MONO_MT_TABLE_IDX
, /* "AssemblyRef:AssemblyRef" }, */
177 #define CLASS_LAYOUT_SCHEMA_OFFSET ASSEMBLYREFPROC_SCHEMA_OFFSET + 3
178 MONO_MT_UINT16
, /* "PackingSize" }, */
179 MONO_MT_UINT32
, /* "ClassSize" }, */
180 MONO_MT_TABLE_IDX
, /* "Parent:TypeDef" }, */
183 #define CONSTANT_SCHEMA_OFFSET CLASS_LAYOUT_SCHEMA_OFFSET + 4
184 MONO_MT_UINT8
, /* "Type" }, */
185 MONO_MT_UINT8
, /* "PaddingZero" }, */
186 MONO_MT_CONST_IDX
, /* "Parent" }, */
187 MONO_MT_BLOB_IDX
, /* "Value" }, */
190 #define CUSTOM_ATTR_SCHEMA_OFFSET CONSTANT_SCHEMA_OFFSET + 5
191 MONO_MT_HASCAT_IDX
, /* "Parent" }, */
192 MONO_MT_CAT_IDX
, /* "Type" }, */
193 MONO_MT_BLOB_IDX
, /* "Value" }, */
196 #define DECL_SEC_SCHEMA_OFFSET CUSTOM_ATTR_SCHEMA_OFFSET + 4
197 MONO_MT_UINT16
, /* "Action" }, */
198 MONO_MT_HASDEC_IDX
, /* "Parent" }, */
199 MONO_MT_BLOB_IDX
, /* "PermissionSet" }, */
202 #define EVENTMAP_SCHEMA_OFFSET DECL_SEC_SCHEMA_OFFSET + 4
203 MONO_MT_TABLE_IDX
, /* "Parent:TypeDef" }, */
204 MONO_MT_TABLE_IDX
, /* "EventList:Event" }, */
207 #define EVENT_SCHEMA_OFFSET EVENTMAP_SCHEMA_OFFSET + 3
208 MONO_MT_UINT16
, /* "EventFlags#EventAttribute" }, */
209 MONO_MT_STRING_IDX
, /* "Name" }, */
210 MONO_MT_TDOR_IDX
, /* "EventType" }, TypeDef or TypeRef or TypeSpec */
213 #define EVENT_POINTER_SCHEMA_OFFSET EVENT_SCHEMA_OFFSET + 4
214 MONO_MT_TABLE_IDX
, /* "Event" }, */
217 #define EXPORTED_TYPE_SCHEMA_OFFSET EVENT_POINTER_SCHEMA_OFFSET + 2
218 MONO_MT_UINT32
, /* "Flags" }, */
219 MONO_MT_TABLE_IDX
, /* "TypeDefId" }, */
220 MONO_MT_STRING_IDX
, /* "TypeName" }, */
221 MONO_MT_STRING_IDX
, /* "TypeNameSpace" }, */
222 MONO_MT_IMPL_IDX
, /* "Implementation" }, */
225 #define FIELD_SCHEMA_OFFSET EXPORTED_TYPE_SCHEMA_OFFSET + 6
226 MONO_MT_UINT16
, /* "Flags" }, */
227 MONO_MT_STRING_IDX
, /* "Name" }, */
228 MONO_MT_BLOB_IDX
, /* "Signature" }, */
231 #define FIELD_LAYOUT_SCHEMA_OFFSET FIELD_SCHEMA_OFFSET + 4
232 MONO_MT_UINT32
, /* "Offset" }, */
233 MONO_MT_TABLE_IDX
, /* "Field:Field" }, */
236 #define FIELD_MARSHAL_SCHEMA_OFFSET FIELD_LAYOUT_SCHEMA_OFFSET + 3
237 MONO_MT_HFM_IDX
, /* "Parent" }, */
238 MONO_MT_BLOB_IDX
, /* "NativeType" }, */
241 #define FIELD_RVA_SCHEMA_OFFSET FIELD_MARSHAL_SCHEMA_OFFSET + 3
242 MONO_MT_UINT32
, /* "RVA" }, */
243 MONO_MT_TABLE_IDX
, /* "Field:Field" }, */
246 #define FIELD_POINTER_SCHEMA_OFFSET FIELD_RVA_SCHEMA_OFFSET + 3
247 MONO_MT_TABLE_IDX
, /* "Field" }, */
250 #define FILE_SCHEMA_OFFSET FIELD_POINTER_SCHEMA_OFFSET + 2
251 MONO_MT_UINT32
, /* "Flags" }, */
252 MONO_MT_STRING_IDX
, /* "Name" }, */
253 MONO_MT_BLOB_IDX
, /* "Value" }, */
256 #define IMPLMAP_SCHEMA_OFFSET FILE_SCHEMA_OFFSET + 4
257 MONO_MT_UINT16
, /* "MappingFlag" }, */
258 MONO_MT_MF_IDX
, /* "MemberForwarded" }, */
259 MONO_MT_STRING_IDX
, /* "ImportName" }, */
260 MONO_MT_TABLE_IDX
, /* "ImportScope:ModuleRef" }, */
263 #define IFACEMAP_SCHEMA_OFFSET IMPLMAP_SCHEMA_OFFSET + 5
264 MONO_MT_TABLE_IDX
, /* "Class:TypeDef" }, */
265 MONO_MT_TDOR_IDX
, /* "Interface=TypeDefOrRef" }, */
268 #define MANIFEST_SCHEMA_OFFSET IFACEMAP_SCHEMA_OFFSET + 3
269 MONO_MT_UINT32
, /* "Offset" }, */
270 MONO_MT_UINT32
, /* "Flags" }, */
271 MONO_MT_STRING_IDX
, /* "Name" }, */
272 MONO_MT_IMPL_IDX
, /* "Implementation" }, */
275 #define MEMBERREF_SCHEMA_OFFSET MANIFEST_SCHEMA_OFFSET + 5
276 MONO_MT_MRP_IDX
, /* "Class" }, */
277 MONO_MT_STRING_IDX
, /* "Name" }, */
278 MONO_MT_BLOB_IDX
, /* "Signature" }, */
281 #define METHOD_SCHEMA_OFFSET MEMBERREF_SCHEMA_OFFSET + 4
282 MONO_MT_UINT32
, /* "RVA" }, */
283 MONO_MT_UINT16
, /* "ImplFlags#MethodImplAttributes" }, */
284 MONO_MT_UINT16
, /* "Flags#MethodAttribute" }, */
285 MONO_MT_STRING_IDX
, /* "Name" }, */
286 MONO_MT_BLOB_IDX
, /* "Signature" }, */
287 MONO_MT_TABLE_IDX
, /* "ParamList:Param" }, */
290 #define METHOD_IMPL_SCHEMA_OFFSET METHOD_SCHEMA_OFFSET + 7
291 MONO_MT_TABLE_IDX
, /* "Class:TypeDef" }, */
292 MONO_MT_MDOR_IDX
, /* "MethodBody" }, */
293 MONO_MT_MDOR_IDX
, /* "MethodDeclaration" }, */
296 #define METHOD_SEMA_SCHEMA_OFFSET METHOD_IMPL_SCHEMA_OFFSET + 4
297 MONO_MT_UINT16
, /* "MethodSemantic" }, */
298 MONO_MT_TABLE_IDX
, /* "Method:Method" }, */
299 MONO_MT_HS_IDX
, /* "Association" }, */
302 #define METHOD_POINTER_SCHEMA_OFFSET METHOD_SEMA_SCHEMA_OFFSET + 4
303 MONO_MT_TABLE_IDX
, /* "Method" }, */
306 #define MODULE_SCHEMA_OFFSET METHOD_POINTER_SCHEMA_OFFSET + 2
307 MONO_MT_UINT16
, /* "Generation" }, */
308 MONO_MT_STRING_IDX
, /* "Name" }, */
309 MONO_MT_GUID_IDX
, /* "MVID" }, */
310 MONO_MT_GUID_IDX
, /* "EncID" }, */
311 MONO_MT_GUID_IDX
, /* "EncBaseID" }, */
314 #define MODULEREF_SCHEMA_OFFSET MODULE_SCHEMA_OFFSET + 6
315 MONO_MT_STRING_IDX
, /* "Name" }, */
318 #define NESTED_CLASS_SCHEMA_OFFSET MODULEREF_SCHEMA_OFFSET + 2
319 MONO_MT_TABLE_IDX
, /* "NestedClass:TypeDef" }, */
320 MONO_MT_TABLE_IDX
, /* "EnclosingClass:TypeDef" }, */
323 #define PARAM_SCHEMA_OFFSET NESTED_CLASS_SCHEMA_OFFSET + 3
324 MONO_MT_UINT16
, /* "Flags" }, */
325 MONO_MT_UINT16
, /* "Sequence" }, */
326 MONO_MT_STRING_IDX
, /* "Name" }, */
329 #define PARAM_POINTER_SCHEMA_OFFSET PARAM_SCHEMA_OFFSET + 4
330 MONO_MT_TABLE_IDX
, /* "Param" }, */
333 #define PROPERTY_SCHEMA_OFFSET PARAM_POINTER_SCHEMA_OFFSET + 2
334 MONO_MT_UINT16
, /* "Flags" }, */
335 MONO_MT_STRING_IDX
, /* "Name" }, */
336 MONO_MT_BLOB_IDX
, /* "Type" }, */
339 #define PROPERTY_POINTER_SCHEMA_OFFSET PROPERTY_SCHEMA_OFFSET + 4
340 MONO_MT_TABLE_IDX
, /* "Property" }, */
343 #define PROPERTY_MAP_SCHEMA_OFFSET PROPERTY_POINTER_SCHEMA_OFFSET + 2
344 MONO_MT_TABLE_IDX
, /* "Parent:TypeDef" }, */
345 MONO_MT_TABLE_IDX
, /* "PropertyList:Property" }, */
348 #define STDALON_SIG_SCHEMA_OFFSET PROPERTY_MAP_SCHEMA_OFFSET + 3
349 MONO_MT_BLOB_IDX
, /* "Signature" }, */
352 #define TYPEDEF_SCHEMA_OFFSET STDALON_SIG_SCHEMA_OFFSET + 2
353 MONO_MT_UINT32
, /* "Flags" }, */
354 MONO_MT_STRING_IDX
, /* "Name" }, */
355 MONO_MT_STRING_IDX
, /* "Namespace" }, */
356 MONO_MT_TDOR_IDX
, /* "Extends" }, */
357 MONO_MT_TABLE_IDX
, /* "FieldList:Field" }, */
358 MONO_MT_TABLE_IDX
, /* "MethodList:Method" }, */
361 #define TYPEREF_SCHEMA_OFFSET TYPEDEF_SCHEMA_OFFSET + 7
362 MONO_MT_RS_IDX
, /* "ResolutionScope=ResolutionScope" }, */
363 MONO_MT_STRING_IDX
, /* "Name" }, */
364 MONO_MT_STRING_IDX
, /* "Namespace" }, */
367 #define TYPESPEC_SCHEMA_OFFSET TYPEREF_SCHEMA_OFFSET + 4
368 MONO_MT_BLOB_IDX
, /* "Signature" }, */
371 #define GENPARAM_SCHEMA_OFFSET TYPESPEC_SCHEMA_OFFSET + 2
372 MONO_MT_UINT16
, /* "Number" }, */
373 MONO_MT_UINT16
, /* "Flags" }, */
374 MONO_MT_TABLE_IDX
, /* "Owner" }, TypeDef or MethodDef */
375 MONO_MT_STRING_IDX
, /* "Name" }, */
378 #define METHOD_SPEC_SCHEMA_OFFSET GENPARAM_SCHEMA_OFFSET + 5
379 MONO_MT_MDOR_IDX
, /* "Method" }, */
380 MONO_MT_BLOB_IDX
, /* "Signature" }, */
383 #define GEN_CONSTRAINT_SCHEMA_OFFSET METHOD_SPEC_SCHEMA_OFFSET + 3
384 MONO_MT_TABLE_IDX
, /* "GenericParam" }, */
385 MONO_MT_TDOR_IDX
, /* "Constraint" }, */
388 #define DOCUMENT_SCHEMA_OFFSET GEN_CONSTRAINT_SCHEMA_OFFSET + 3
389 MONO_MT_BLOB_IDX
, /* Name */
390 MONO_MT_GUID_IDX
, /* HashAlgorithm */
391 MONO_MT_BLOB_IDX
, /* Hash */
392 MONO_MT_GUID_IDX
, /* Language */
395 #define METHODBODY_SCHEMA_OFFSET DOCUMENT_SCHEMA_OFFSET + 5
396 MONO_MT_TABLE_IDX
, /* Document */
397 MONO_MT_BLOB_IDX
, /* SequencePoints */
400 #define LOCALSCOPE_SCHEMA_OFFSET METHODBODY_SCHEMA_OFFSET + 3
401 MONO_MT_TABLE_IDX
, /* Method */
402 MONO_MT_TABLE_IDX
, /* ImportScope */
403 MONO_MT_TABLE_IDX
, /* VariableList */
404 MONO_MT_TABLE_IDX
, /* ConstantList */
405 MONO_MT_UINT32
, /* StartOffset */
406 MONO_MT_UINT32
, /* Length */
409 #define LOCALVARIABLE_SCHEMA_OFFSET LOCALSCOPE_SCHEMA_OFFSET + 7
410 MONO_MT_UINT16
, /* Attributes */
411 MONO_MT_UINT16
, /* Index */
412 MONO_MT_STRING_IDX
, /* Name */
415 #define LOCALCONSTANT_SCHEMA_OFFSET LOCALVARIABLE_SCHEMA_OFFSET + 4
416 MONO_MT_STRING_IDX
, /* Name (String heap index) */
417 MONO_MT_BLOB_IDX
, /* Signature (Blob heap index, LocalConstantSig blob) */
420 #define IMPORTSCOPE_SCHEMA_OFFSET LOCALCONSTANT_SCHEMA_OFFSET + 3
421 MONO_MT_TABLE_IDX
, /* Parent (ImportScope row id or nil) */
422 MONO_MT_BLOB_IDX
, /* Imports (Blob index, encoding: Imports blob) */
425 #define ASYNCMETHOD_SCHEMA_OFFSET IMPORTSCOPE_SCHEMA_OFFSET + 3
426 MONO_MT_TABLE_IDX
, /* MoveNextMethod (MethodDef row id) */
427 MONO_MT_TABLE_IDX
, /* KickoffMethod (MethodDef row id) */
430 #define CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET ASYNCMETHOD_SCHEMA_OFFSET + 3
431 MONO_MT_HASCUSTDEBUG_IDX
, /* Parent (HasCustomDebugInformation coded index) */
432 MONO_MT_GUID_IDX
, /* Kind (Guid heap index) */
433 MONO_MT_BLOB_IDX
, /* Value (Blob heap index) */
436 #define NULL_SCHEMA_OFFSET CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET + 4
440 /* Must be the same order as MONO_TABLE_* */
441 const static unsigned char
442 table_description
[] = {
443 MODULE_SCHEMA_OFFSET
,
444 TYPEREF_SCHEMA_OFFSET
,
445 TYPEDEF_SCHEMA_OFFSET
,
446 FIELD_POINTER_SCHEMA_OFFSET
,
448 METHOD_POINTER_SCHEMA_OFFSET
,
449 METHOD_SCHEMA_OFFSET
,
450 PARAM_POINTER_SCHEMA_OFFSET
,
452 IFACEMAP_SCHEMA_OFFSET
,
453 MEMBERREF_SCHEMA_OFFSET
, /* 0xa */
454 CONSTANT_SCHEMA_OFFSET
,
455 CUSTOM_ATTR_SCHEMA_OFFSET
,
456 FIELD_MARSHAL_SCHEMA_OFFSET
,
457 DECL_SEC_SCHEMA_OFFSET
,
458 CLASS_LAYOUT_SCHEMA_OFFSET
,
459 FIELD_LAYOUT_SCHEMA_OFFSET
, /* 0x10 */
460 STDALON_SIG_SCHEMA_OFFSET
,
461 EVENTMAP_SCHEMA_OFFSET
,
462 EVENT_POINTER_SCHEMA_OFFSET
,
464 PROPERTY_MAP_SCHEMA_OFFSET
,
465 PROPERTY_POINTER_SCHEMA_OFFSET
,
466 PROPERTY_SCHEMA_OFFSET
,
467 METHOD_SEMA_SCHEMA_OFFSET
,
468 METHOD_IMPL_SCHEMA_OFFSET
,
469 MODULEREF_SCHEMA_OFFSET
, /* 0x1a */
470 TYPESPEC_SCHEMA_OFFSET
,
471 IMPLMAP_SCHEMA_OFFSET
,
472 FIELD_RVA_SCHEMA_OFFSET
,
475 ASSEMBLY_SCHEMA_OFFSET
, /* 0x20 */
476 ASSEMBLYPROC_SCHEMA_OFFSET
,
477 ASSEMBLYOS_SCHEMA_OFFSET
,
478 ASSEMBLYREF_SCHEMA_OFFSET
,
479 ASSEMBLYREFPROC_SCHEMA_OFFSET
,
480 ASSEMBLYREFOS_SCHEMA_OFFSET
,
482 EXPORTED_TYPE_SCHEMA_OFFSET
,
483 MANIFEST_SCHEMA_OFFSET
,
484 NESTED_CLASS_SCHEMA_OFFSET
,
485 GENPARAM_SCHEMA_OFFSET
, /* 0x2a */
486 METHOD_SPEC_SCHEMA_OFFSET
,
487 GEN_CONSTRAINT_SCHEMA_OFFSET
,
491 DOCUMENT_SCHEMA_OFFSET
, /* 0x30 */
492 METHODBODY_SCHEMA_OFFSET
,
493 LOCALSCOPE_SCHEMA_OFFSET
,
494 LOCALVARIABLE_SCHEMA_OFFSET
,
495 LOCALCONSTANT_SCHEMA_OFFSET
,
496 IMPORTSCOPE_SCHEMA_OFFSET
,
497 ASYNCMETHOD_SCHEMA_OFFSET
,
498 CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET
501 // This, instead of an array of pointers, to optimize away a pointer and a relocation per string.
502 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
503 #define MSGSTRFIELD1(line) str##line
504 static const struct msgstr_t
{
505 #define TABLEDEF(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
506 #include "mono/cil/tables.def"
509 #define TABLEDEF(a,b) b,
510 #include "mono/cil/tables.def"
513 static const gint16 tableidx
[] = {
514 #define TABLEDEF(a,b) offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
515 #include "mono/cil/tables.def"
519 /* On legacy, if TRUE (but also see DISABLE_DESKTOP_LOADER #define), Mono will check
520 * that the public key token, culture and version of a candidate assembly matches
521 * the requested strong name. On netcore, it will check the culture and version.
522 * If FALSE, as long as the name matches, the candidate will be allowed.
524 static gboolean check_assembly_names_strictly
= FALSE
;
526 // Amount initially reserved in each imageset's mempool.
527 // FIXME: This number is arbitrary, a more practical number should be found
528 #define INITIAL_IMAGE_SET_SIZE 1024
531 * mono_meta_table_name:
532 * \param table table index
534 * Returns the name of the given ECMA metadata logical format table
535 * as described in ECMA 335, Partition II, Section 22.
537 * \returns the name for the \p table index
540 mono_meta_table_name (int table
)
542 if ((table
< 0) || (table
> MONO_TABLE_LAST
))
545 return (const char*)&tablestr
+ tableidx
[table
];
548 /* The guy who wrote the spec for this should not be allowed near a
551 If e is a coded token(see clause 23.1.7) that points into table ti out of n possible tables t0, .. tn-1,
552 then it is stored as e << (log n) & tag{ t0, .. tn-1}[ ti] using 2 bytes if the maximum number of
553 rows of tables t0, ..tn-1, is less than 2^16 - (log n), and using 4 bytes otherwise. The family of
554 finite maps tag{ t0, ..tn-1} is defined below. Note that to decode a physical row, you need the
555 inverse of this mapping.
558 #define rtsize(meta,s,b) (((s) < (1 << (b)) ? 2 : 4))
561 idx_size (MonoImage
*meta
, int idx
)
563 if (meta
->referenced_tables
&& (meta
->referenced_tables
& ((guint64
)1 << idx
)))
564 return meta
->referenced_table_rows
[idx
] < 65536 ? 2 : 4;
566 return meta
->tables
[idx
].rows
< 65536 ? 2 : 4;
570 get_nrows (MonoImage
*meta
, int idx
)
572 if (meta
->referenced_tables
&& (meta
->referenced_tables
& ((guint64
)1 << idx
)))
573 return meta
->referenced_table_rows
[idx
];
575 return meta
->tables
[idx
].rows
;
578 /* Reference: Partition II - 23.2.6 */
580 * mono_metadata_compute_size:
581 * \param meta metadata context
582 * \param tableindex metadata table number
583 * \param result_bitfield pointer to \c guint32 where to store additional info
585 * \c mono_metadata_compute_size computes the length in bytes of a single
586 * row in a metadata table. The size of each column is encoded in the
587 * \p result_bitfield return value along with the number of columns in the table.
588 * the resulting bitfield should be handed to the \c mono_metadata_table_size
589 * and \c mono_metadata_table_count macros.
590 * This is a Mono runtime internal only function.
593 mono_metadata_compute_size (MonoImage
*meta
, int tableindex
, guint32
*result_bitfield
)
595 guint32 bitfield
= 0;
596 int size
= 0, field_size
= 0;
599 const unsigned char *description
= TableSchemas
+ table_description
[tableindex
];
601 for (i
= 0; (code
= description
[i
]) != MONO_MT_END
; i
++){
604 field_size
= 4; break;
607 field_size
= 2; break;
610 field_size
= 1; break;
612 case MONO_MT_BLOB_IDX
:
613 field_size
= meta
->idx_blob_wide
? 4 : 2; break;
615 case MONO_MT_STRING_IDX
:
616 field_size
= meta
->idx_string_wide
? 4 : 2; break;
618 case MONO_MT_GUID_IDX
:
619 field_size
= meta
->idx_guid_wide
? 4 : 2; break;
621 case MONO_MT_TABLE_IDX
:
622 /* Uhm, a table index can point to other tables besides the current one
623 * so, it's not correct to use the rowcount of the current table to
624 * get the size for this column - lupus
626 switch (tableindex
) {
627 case MONO_TABLE_ASSEMBLYREFOS
:
629 field_size
= idx_size (meta
, MONO_TABLE_ASSEMBLYREF
); break;
630 case MONO_TABLE_ASSEMBLYREFPROCESSOR
:
632 field_size
= idx_size (meta
, MONO_TABLE_ASSEMBLYREF
); break;
633 case MONO_TABLE_CLASSLAYOUT
:
635 field_size
= idx_size (meta
, MONO_TABLE_TYPEDEF
); break;
636 case MONO_TABLE_EVENTMAP
:
637 g_assert (i
== 0 || i
== 1);
638 field_size
= i
? idx_size (meta
, MONO_TABLE_EVENT
):
639 idx_size (meta
, MONO_TABLE_TYPEDEF
);
641 case MONO_TABLE_EVENT_POINTER
:
643 field_size
= idx_size (meta
, MONO_TABLE_EVENT
); break;
644 case MONO_TABLE_EXPORTEDTYPE
:
646 /* the index is in another metadata file, so it must be 4 */
647 field_size
= 4; break;
648 case MONO_TABLE_FIELDLAYOUT
:
650 field_size
= idx_size (meta
, MONO_TABLE_FIELD
); break;
651 case MONO_TABLE_FIELDRVA
:
653 field_size
= idx_size (meta
, MONO_TABLE_FIELD
); break;
654 case MONO_TABLE_FIELD_POINTER
:
656 field_size
= idx_size (meta
, MONO_TABLE_FIELD
); break;
657 case MONO_TABLE_IMPLMAP
:
659 field_size
= idx_size (meta
, MONO_TABLE_MODULEREF
); break;
660 case MONO_TABLE_INTERFACEIMPL
:
662 field_size
= idx_size (meta
, MONO_TABLE_TYPEDEF
); break;
663 case MONO_TABLE_METHOD
:
665 field_size
= idx_size (meta
, MONO_TABLE_PARAM
); break;
666 case MONO_TABLE_METHODIMPL
:
668 field_size
= idx_size (meta
, MONO_TABLE_TYPEDEF
); break;
669 case MONO_TABLE_METHODSEMANTICS
:
671 field_size
= idx_size (meta
, MONO_TABLE_METHOD
); break;
672 case MONO_TABLE_METHOD_POINTER
:
674 field_size
= idx_size (meta
, MONO_TABLE_METHOD
); break;
675 case MONO_TABLE_NESTEDCLASS
:
676 g_assert (i
== 0 || i
== 1);
677 field_size
= idx_size (meta
, MONO_TABLE_TYPEDEF
); break;
678 case MONO_TABLE_PARAM_POINTER
:
680 field_size
= idx_size (meta
, MONO_TABLE_PARAM
); break;
681 case MONO_TABLE_PROPERTYMAP
:
682 g_assert (i
== 0 || i
== 1);
683 field_size
= i
? idx_size (meta
, MONO_TABLE_PROPERTY
):
684 idx_size (meta
, MONO_TABLE_TYPEDEF
);
686 case MONO_TABLE_PROPERTY_POINTER
:
688 field_size
= idx_size (meta
, MONO_TABLE_PROPERTY
); break;
689 case MONO_TABLE_TYPEDEF
:
690 g_assert (i
== 4 || i
== 5);
691 field_size
= i
== 4 ? idx_size (meta
, MONO_TABLE_FIELD
):
692 idx_size (meta
, MONO_TABLE_METHOD
);
694 case MONO_TABLE_GENERICPARAM
:
696 n
= MAX (get_nrows (meta
, MONO_TABLE_METHOD
), get_nrows (meta
, MONO_TABLE_TYPEDEF
));
697 /*This is a coded token for 2 tables, so takes 1 bit */
698 field_size
= rtsize (meta
, n
, 16 - MONO_TYPEORMETHOD_BITS
);
700 case MONO_TABLE_GENERICPARAMCONSTRAINT
:
702 field_size
= idx_size (meta
, MONO_TABLE_GENERICPARAM
);
704 case MONO_TABLE_LOCALSCOPE
:
707 // FIXME: This table is in another file
708 field_size
= idx_size (meta
, MONO_TABLE_METHOD
);
711 field_size
= idx_size (meta
, MONO_TABLE_IMPORTSCOPE
);
714 field_size
= idx_size (meta
, MONO_TABLE_LOCALVARIABLE
);
717 field_size
= idx_size (meta
, MONO_TABLE_LOCALCONSTANT
);
720 g_assert_not_reached ();
724 case MONO_TABLE_METHODBODY
:
726 field_size
= idx_size (meta
, MONO_TABLE_DOCUMENT
); break;
727 case MONO_TABLE_IMPORTSCOPE
:
729 field_size
= idx_size (meta
, MONO_TABLE_IMPORTSCOPE
); break;
730 case MONO_TABLE_STATEMACHINEMETHOD
:
731 g_assert(i
== 0 || i
== 1);
732 field_size
= idx_size(meta
, MONO_TABLE_METHOD
); break;
734 g_error ("Can't handle MONO_MT_TABLE_IDX for table %d element %d", tableindex
, i
);
739 * HasConstant: ParamDef, FieldDef, Property
741 case MONO_MT_CONST_IDX
:
742 n
= MAX (get_nrows (meta
, MONO_TABLE_PARAM
),
743 get_nrows (meta
, MONO_TABLE_FIELD
));
744 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_PROPERTY
));
746 /* 2 bits to encode tag */
747 field_size
= rtsize (meta
, n
, 16-2);
751 * HasCustomAttribute: points to any table but
754 case MONO_MT_HASCAT_IDX
:
756 * We believe that since the signature and
757 * permission are indexing the Blob heap,
758 * we should consider the blob size first
760 /* I'm not a believer - lupus
761 if (meta->idx_blob_wide){
766 n
= MAX (get_nrows (meta
, MONO_TABLE_METHOD
),
767 get_nrows (meta
, MONO_TABLE_FIELD
));
768 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_TYPEREF
));
769 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_TYPEDEF
));
770 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_PARAM
));
771 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_INTERFACEIMPL
));
772 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_MEMBERREF
));
773 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_MODULE
));
774 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_DECLSECURITY
));
775 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_PROPERTY
));
776 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_EVENT
));
777 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_STANDALONESIG
));
778 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_MODULEREF
));
779 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_TYPESPEC
));
780 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_ASSEMBLY
));
781 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_ASSEMBLYREF
));
782 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_FILE
));
783 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_EXPORTEDTYPE
));
784 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_MANIFESTRESOURCE
));
785 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_GENERICPARAM
));
786 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_GENERICPARAMCONSTRAINT
));
787 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_METHODSPEC
));
789 /* 5 bits to encode */
790 field_size
= rtsize (meta
, n
, 16-5);
794 * HasCustomAttribute: points to any table but
798 case MONO_MT_HASCUSTDEBUG_IDX
:
799 n
= MAX(get_nrows (meta
, MONO_TABLE_METHOD
),
800 get_nrows (meta
, MONO_TABLE_FIELD
));
801 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_TYPEREF
));
802 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_TYPEDEF
));
803 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_PARAM
));
804 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_INTERFACEIMPL
));
805 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_MEMBERREF
));
806 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_MODULE
));
807 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_DECLSECURITY
));
808 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_PROPERTY
));
809 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_EVENT
));
810 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_STANDALONESIG
));
811 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_MODULEREF
));
812 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_TYPESPEC
));
813 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_ASSEMBLY
));
814 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_ASSEMBLYREF
));
815 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_FILE
));
816 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_EXPORTEDTYPE
));
817 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_MANIFESTRESOURCE
));
818 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_GENERICPARAM
));
819 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_GENERICPARAMCONSTRAINT
));
820 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_METHODSPEC
));
821 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_DOCUMENT
));
822 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_LOCALSCOPE
));
823 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_LOCALVARIABLE
));
824 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_LOCALCONSTANT
));
825 n
= MAX(n
, get_nrows (meta
, MONO_TABLE_IMPORTSCOPE
));
827 /* 5 bits to encode */
828 field_size
= rtsize(meta
, n
, 16 - 5);
832 * CustomAttributeType: MethodDef, MemberRef.
834 case MONO_MT_CAT_IDX
:
835 n
= MAX (get_nrows (meta
, MONO_TABLE_METHOD
),
836 get_nrows (meta
, MONO_TABLE_MEMBERREF
));
838 /* 3 bits to encode */
839 field_size
= rtsize (meta
, n
, 16-3);
843 * HasDeclSecurity: Typedef, MethodDef, Assembly
845 case MONO_MT_HASDEC_IDX
:
846 n
= MAX (get_nrows (meta
, MONO_TABLE_TYPEDEF
),
847 get_nrows (meta
, MONO_TABLE_METHOD
));
848 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_ASSEMBLY
));
850 /* 2 bits to encode */
851 field_size
= rtsize (meta
, n
, 16-2);
855 * Implementation: File, AssemblyRef, ExportedType
857 case MONO_MT_IMPL_IDX
:
858 n
= MAX (get_nrows (meta
, MONO_TABLE_FILE
),
859 get_nrows (meta
, MONO_TABLE_ASSEMBLYREF
));
860 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_EXPORTEDTYPE
));
862 /* 2 bits to encode tag */
863 field_size
= rtsize (meta
, n
, 16-2);
867 * HasFieldMarshall: FieldDef, ParamDef
869 case MONO_MT_HFM_IDX
:
870 n
= MAX (get_nrows (meta
, MONO_TABLE_FIELD
),
871 get_nrows (meta
, MONO_TABLE_PARAM
));
873 /* 1 bit used to encode tag */
874 field_size
= rtsize (meta
, n
, 16-1);
878 * MemberForwarded: FieldDef, MethodDef
881 n
= MAX (get_nrows (meta
, MONO_TABLE_FIELD
),
882 get_nrows (meta
, MONO_TABLE_METHOD
));
884 /* 1 bit used to encode tag */
885 field_size
= rtsize (meta
, n
, 16-1);
889 * TypeDefOrRef: TypeDef, ParamDef, TypeSpec
891 * It is TypeDef, _TypeRef_, TypeSpec, instead.
893 case MONO_MT_TDOR_IDX
:
894 n
= MAX (get_nrows (meta
, MONO_TABLE_TYPEDEF
),
895 get_nrows (meta
, MONO_TABLE_TYPEREF
));
896 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_TYPESPEC
));
898 /* 2 bits to encode */
899 field_size
= rtsize (meta
, n
, 16-2);
903 * MemberRefParent: TypeDef, TypeRef, MethodDef, ModuleRef, TypeSpec, MemberRef
905 case MONO_MT_MRP_IDX
:
906 n
= MAX (get_nrows (meta
, MONO_TABLE_TYPEDEF
),
907 get_nrows (meta
, MONO_TABLE_TYPEREF
));
908 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_METHOD
));
909 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_MODULEREF
));
910 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_TYPESPEC
));
912 /* 3 bits to encode */
913 field_size
= rtsize (meta
, n
, 16 - 3);
917 * MethodDefOrRef: MethodDef, MemberRef
919 case MONO_MT_MDOR_IDX
:
920 n
= MAX (get_nrows (meta
, MONO_TABLE_METHOD
),
921 get_nrows (meta
, MONO_TABLE_MEMBERREF
));
923 /* 1 bit used to encode tag */
924 field_size
= rtsize (meta
, n
, 16-1);
928 * HasSemantics: Property, Event
931 n
= MAX (get_nrows (meta
, MONO_TABLE_PROPERTY
),
932 get_nrows (meta
, MONO_TABLE_EVENT
));
934 /* 1 bit used to encode tag */
935 field_size
= rtsize (meta
, n
, 16-1);
939 * ResolutionScope: Module, ModuleRef, AssemblyRef, TypeRef
942 n
= MAX (get_nrows (meta
, MONO_TABLE_MODULE
),
943 get_nrows (meta
, MONO_TABLE_MODULEREF
));
944 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_ASSEMBLYREF
));
945 n
= MAX (n
, get_nrows (meta
, MONO_TABLE_TYPEREF
));
947 /* 2 bits used to encode tag (ECMA spec claims 3) */
948 field_size
= rtsize (meta
, n
, 16 - 2);
953 * encode field size as follows (we just need to
960 bitfield
|= (field_size
-1) << shift
;
963 /*g_print ("table %02x field %d size %d\n", tableindex, i, field_size);*/
966 *result_bitfield
= (i
<< 24) | bitfield
;
971 * mono_metadata_compute_table_bases:
972 * \param meta metadata context to compute table values
974 * Computes the table bases for the metadata structure.
975 * This is an internal function used by the image loader code.
978 mono_metadata_compute_table_bases (MonoImage
*meta
)
981 const char *base
= meta
->tables_base
;
983 for (i
= 0; i
< MONO_TABLE_NUM
; i
++) {
984 MonoTableInfo
*table
= &meta
->tables
[i
];
985 if (table
->rows
== 0)
988 table
->row_size
= mono_metadata_compute_size (meta
, i
, &table
->size_bitfield
);
990 base
+= table
->rows
* table
->row_size
;
995 * mono_metadata_locate:
996 * \param meta metadata context
997 * \param table table code.
998 * \param idx index of element to retrieve from \p table.
1000 * \returns a pointer to the \p idx element in the metadata table
1001 * whose code is \p table.
1004 mono_metadata_locate (MonoImage
*meta
, int table
, int idx
)
1006 /* idx == 0 refers always to NULL */
1007 g_return_val_if_fail (idx
> 0 && idx
<= meta
->tables
[table
].rows
, ""); /*FIXME shouldn't we return NULL here?*/
1009 return meta
->tables
[table
].base
+ (meta
->tables
[table
].row_size
* (idx
- 1));
1013 * mono_metadata_locate_token:
1014 * \param meta metadata context
1015 * \param token metadata token
1017 * \returns a pointer to the data in the metadata represented by the
1021 mono_metadata_locate_token (MonoImage
*meta
, guint32 token
)
1023 return mono_metadata_locate (meta
, token
>> 24, token
& 0xffffff);
1027 * mono_metadata_string_heap:
1028 * \param meta metadata context
1029 * \param index index into the string heap.
1030 * \returns an in-memory pointer to the \p index in the string heap.
1033 mono_metadata_string_heap (MonoImage
*meta
, guint32 index
)
1035 g_assert (index
< meta
->heap_strings
.size
);
1036 g_return_val_if_fail (index
< meta
->heap_strings
.size
, "");
1037 return meta
->heap_strings
.data
+ index
;
1041 * mono_metadata_string_heap_checked:
1042 * \param meta metadata context
1043 * \param index index into the string heap.
1044 * \param error set on error
1045 * \returns an in-memory pointer to the \p index in the string heap.
1046 * On failure returns NULL and sets \p error.
1049 mono_metadata_string_heap_checked (MonoImage
*meta
, guint32 index
, MonoError
*error
)
1051 if (G_UNLIKELY (!(index
< meta
->heap_strings
.size
))) {
1052 mono_error_set_bad_image_by_name (error
, meta
->name
? meta
->name
: "unknown image", "string heap index %ud out bounds %u", index
, meta
->heap_strings
.size
);
1055 return meta
->heap_strings
.data
+ index
;
1059 * mono_metadata_user_string:
1060 * \param meta metadata context
1061 * \param index index into the user string heap.
1062 * \returns an in-memory pointer to the \p index in the user string heap (<code>#US</code>).
1065 mono_metadata_user_string (MonoImage
*meta
, guint32 index
)
1067 g_assert (index
< meta
->heap_us
.size
);
1068 g_return_val_if_fail (index
< meta
->heap_us
.size
, "");
1069 return meta
->heap_us
.data
+ index
;
1073 * mono_metadata_blob_heap:
1074 * \param meta metadata context
1075 * \param index index into the blob.
1076 * \returns an in-memory pointer to the \p index in the Blob heap.
1079 mono_metadata_blob_heap (MonoImage
*meta
, guint32 index
)
1081 /* Some tools can produce assemblies with a size 0 Blob stream. If a
1082 * blob value is optional, if the index == 0 and heap_blob.size == 0
1083 * assertion is hit, consider updating caller to use
1084 * mono_metadata_blob_heap_null_ok and handling a null return value. */
1085 g_assert (!(index
== 0 && meta
->heap_blob
.size
== 0));
1086 g_assert (index
< meta
->heap_blob
.size
);
1087 return meta
->heap_blob
.data
+ index
;
1091 * mono_metadata_blob_heap_null_ok:
1092 * \param meta metadata context
1093 * \param index index into the blob.
1094 * \return an in-memory pointer to the \p index in the Blob heap.
1095 * If the Blob heap is empty or missing and index is 0 returns NULL, instead of asserting.
1098 mono_metadata_blob_heap_null_ok (MonoImage
*meta
, guint32 index
)
1100 if (G_UNLIKELY (index
== 0 && meta
->heap_blob
.size
== 0))
1103 return mono_metadata_blob_heap (meta
, index
);
1107 * mono_metadata_blob_heap_checked:
1108 * \param meta metadata context
1109 * \param index index into the blob.
1110 * \param error set on error
1111 * \returns an in-memory pointer to the \p index in the Blob heap. On failure sets \p error and returns NULL;
1112 * If the Blob heap is empty or missing and \p index is 0 returns NULL, without setting error.
1116 mono_metadata_blob_heap_checked (MonoImage
*meta
, guint32 index
, MonoError
*error
)
1118 if (G_UNLIKELY (index
== 0 && meta
->heap_blob
.size
== 0))
1120 if (G_UNLIKELY (!(index
< meta
->heap_blob
.size
))) {
1121 mono_error_set_bad_image_by_name (error
, meta
->name
? meta
->name
: "unknown image", "blob heap index %u out of bounds %u", index
, meta
->heap_blob
.size
);
1124 return meta
->heap_blob
.data
+ index
;
1128 * mono_metadata_guid_heap:
1129 * \param meta metadata context
1130 * \param index index into the guid heap.
1131 * \returns an in-memory pointer to the \p index in the guid heap.
1134 mono_metadata_guid_heap (MonoImage
*meta
, guint32 index
)
1137 index
*= 16; /* adjust for guid size and 1-based index */
1138 g_return_val_if_fail (index
< meta
->heap_guid
.size
, "");
1139 return meta
->heap_guid
.data
+ index
;
1142 static const unsigned char *
1143 dword_align (const unsigned char *ptr
)
1145 return (const unsigned char *) (((gsize
) (ptr
+ 3)) & ~3);
1149 * mono_metadata_decode_row:
1150 * \param t table to extract information from.
1151 * \param idx index in table.
1152 * \param res array of \p res_size cols to store the results in
1154 * This decompresses the metadata element \p idx in table \p t
1155 * into the \c guint32 \p res array that has \p res_size elements
1158 mono_metadata_decode_row (const MonoTableInfo
*t
, int idx
, guint32
*res
, int res_size
)
1160 guint32 bitfield
= t
->size_bitfield
;
1161 int i
, count
= mono_metadata_table_count (bitfield
);
1164 g_assert (idx
< t
->rows
);
1165 g_assert (idx
>= 0);
1166 data
= t
->base
+ idx
* t
->row_size
;
1168 g_assert (res_size
== count
);
1170 for (i
= 0; i
< count
; i
++) {
1171 int n
= mono_metadata_table_size (bitfield
, i
);
1175 res
[i
] = *data
; break;
1177 res
[i
] = read16 (data
); break;
1179 res
[i
] = read32 (data
); break;
1181 g_assert_not_reached ();
1188 * mono_metadata_decode_row_checked:
1189 * \param image the \c MonoImage the table belongs to
1190 * \param t table to extract information from.
1191 * \param idx index in the table.
1192 * \param res array of \p res_size cols to store the results in
1193 * \param error set on bounds error
1196 * This decompresses the metadata element \p idx in the table \p t
1197 * into the \c guint32 \p res array that has \p res_size elements.
1199 * \returns TRUE if the read succeeded. Otherwise sets \p error and returns FALSE.
1202 mono_metadata_decode_row_checked (const MonoImage
*image
, const MonoTableInfo
*t
, int idx
, guint32
*res
, int res_size
, MonoError
*error
)
1204 guint32 bitfield
= t
->size_bitfield
;
1205 int i
, count
= mono_metadata_table_count (bitfield
);
1207 const char *image_name
= image
&& image
->name
? image
->name
: "unknown image";
1209 if (G_UNLIKELY (! (idx
< t
->rows
&& idx
>= 0))) {
1210 mono_error_set_bad_image_by_name (error
, image_name
, "row index %d out of bounds: %d rows", idx
, t
->rows
);
1213 const char *data
= t
->base
+ idx
* t
->row_size
;
1215 if (G_UNLIKELY (res_size
!= count
)) {
1216 mono_error_set_bad_image_by_name (error
, image_name
, "res_size %d != count %d", res_size
, count
);
1220 for (i
= 0; i
< count
; i
++) {
1221 int n
= mono_metadata_table_size (bitfield
, i
);
1225 res
[i
] = *data
; break;
1227 res
[i
] = read16 (data
); break;
1229 res
[i
] = read32 (data
); break;
1231 mono_error_set_bad_image_by_name (error
, image_name
, "unexpected table [%d] size %d", i
, n
);
1241 * mono_metadata_decode_row_col:
1242 * \param t table to extract information from.
1243 * \param idx index for row in table.
1244 * \param col column in the row.
1246 * This function returns the value of column \p col from the \p idx
1247 * row in the table \p t .
1250 mono_metadata_decode_row_col (const MonoTableInfo
*t
, int idx
, guint col
)
1252 guint32 bitfield
= t
->size_bitfield
;
1257 g_assert (idx
< t
->rows
);
1258 g_assert (col
< mono_metadata_table_count (bitfield
));
1259 data
= t
->base
+ idx
* t
->row_size
;
1261 n
= mono_metadata_table_size (bitfield
, 0);
1262 for (i
= 0; i
< col
; ++i
) {
1264 n
= mono_metadata_table_size (bitfield
, i
+ 1);
1270 return read16 (data
);
1272 return read32 (data
);
1274 g_assert_not_reached ();
1280 * mono_metadata_decode_blob_size:
1281 * \param ptr pointer to a blob object
1282 * \param rptr the new position of the pointer
1284 * This decodes a compressed size as described by 24.2.4 (#US and #Blob a blob or user string object)
1286 * \returns the size of the blob object
1289 mono_metadata_decode_blob_size (const char *xptr
, const char **rptr
)
1291 const unsigned char *ptr
= (const unsigned char *)xptr
;
1294 if ((*ptr
& 0x80) == 0){
1295 size
= ptr
[0] & 0x7f;
1297 } else if ((*ptr
& 0x40) == 0){
1298 size
= ((ptr
[0] & 0x3f) << 8) + ptr
[1];
1301 size
= ((ptr
[0] & 0x1f) << 24) +
1313 * mono_metadata_decode_value:
1314 * \param ptr pointer to decode from
1315 * \param rptr the new position of the pointer
1317 * This routine decompresses 32-bit values as specified in the "Blob and
1318 * Signature" section (23.2)
1320 * \returns the decoded value
1323 mono_metadata_decode_value (const char *_ptr
, const char **rptr
)
1325 const unsigned char *ptr
= (const unsigned char *) _ptr
;
1326 unsigned char b
= *ptr
;
1329 if ((b
& 0x80) == 0){
1332 } else if ((b
& 0x40) == 0){
1333 len
= ((b
& 0x3f) << 8 | ptr
[1]);
1336 len
= ((b
& 0x1f) << 24) |
1349 * mono_metadata_decode_signed_value:
1350 * \param ptr pointer to decode from
1351 * \param rptr the new position of the pointer
1353 * This routine decompresses 32-bit signed values
1354 * (not specified in the spec)
1356 * \returns the decoded value
1359 mono_metadata_decode_signed_value (const char *ptr
, const char **rptr
)
1361 guint32 uval
= mono_metadata_decode_value (ptr
, rptr
);
1362 gint32 ival
= uval
>> 1;
1365 /* ival is a truncated 2's complement negative number. */
1367 /* 6 bits = 7 bits for compressed representation (top bit is '0') - 1 sign bit */
1370 /* 13 bits = 14 bits for compressed representation (top bits are '10') - 1 sign bit */
1371 return ival
- 0x2000;
1372 if (ival
< 0x10000000)
1373 /* 28 bits = 29 bits for compressed representation (top bits are '110') - 1 sign bit */
1374 return ival
- 0x10000000;
1375 g_assert (ival
< 0x20000000);
1376 g_warning ("compressed signed value appears to use 29 bits for compressed representation: %x (raw: %8x)", ival
, uval
);
1377 return ival
- 0x20000000;
1381 * mono_metadata_translate_token_index:
1382 * Translates the given 1-based index into the \c Method, \c Field, \c Event, or \c Param tables
1383 * using the \c *Ptr tables in uncompressed metadata, if they are available.
1385 * FIXME: The caller is not forced to call this function, which is error-prone, since
1386 * forgetting to call it would only show up as a bug on uncompressed metadata.
1389 mono_metadata_translate_token_index (MonoImage
*image
, int table
, guint32 idx
)
1391 if (!image
->uncompressed_metadata
)
1395 case MONO_TABLE_METHOD
:
1396 if (image
->tables
[MONO_TABLE_METHOD_POINTER
].rows
)
1397 return mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_METHOD_POINTER
], idx
- 1, MONO_METHOD_POINTER_METHOD
);
1400 case MONO_TABLE_FIELD
:
1401 if (image
->tables
[MONO_TABLE_FIELD_POINTER
].rows
)
1402 return mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_FIELD_POINTER
], idx
- 1, MONO_FIELD_POINTER_FIELD
);
1405 case MONO_TABLE_EVENT
:
1406 if (image
->tables
[MONO_TABLE_EVENT_POINTER
].rows
)
1407 return mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_EVENT_POINTER
], idx
- 1, MONO_EVENT_POINTER_EVENT
);
1410 case MONO_TABLE_PROPERTY
:
1411 if (image
->tables
[MONO_TABLE_PROPERTY_POINTER
].rows
)
1412 return mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_PROPERTY_POINTER
], idx
- 1, MONO_PROPERTY_POINTER_PROPERTY
);
1415 case MONO_TABLE_PARAM
:
1416 if (image
->tables
[MONO_TABLE_PARAM_POINTER
].rows
)
1417 return mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_PARAM_POINTER
], idx
- 1, MONO_PARAM_POINTER_PARAM
);
1426 * mono_metadata_decode_table_row:
1428 * Same as \c mono_metadata_decode_row, but takes an \p image + \p table ID pair, and takes
1429 * uncompressed metadata into account, so it should be used to access the
1430 * \c Method, \c Field, \c Param and \c Event tables when the access is made from metadata, i.e.
1431 * \p idx is retrieved from a metadata table, like \c MONO_TYPEDEF_FIELD_LIST.
1434 mono_metadata_decode_table_row (MonoImage
*image
, int table
, int idx
, guint32
*res
, int res_size
)
1436 if (image
->uncompressed_metadata
)
1437 idx
= mono_metadata_translate_token_index (image
, table
, idx
+ 1) - 1;
1439 mono_metadata_decode_row (&image
->tables
[table
], idx
, res
, res_size
);
1443 * mono_metadata_decode_table_row_col:
1445 * Same as \c mono_metadata_decode_row_col, but takes an \p image + \p table ID pair, and takes
1446 * uncompressed metadata into account, so it should be used to access the
1447 * \c Method, \c Field, \c Param and \c Event tables.
1449 guint32
mono_metadata_decode_table_row_col (MonoImage
*image
, int table
, int idx
, guint col
)
1451 if (image
->uncompressed_metadata
)
1452 idx
= mono_metadata_translate_token_index (image
, table
, idx
+ 1) - 1;
1454 return mono_metadata_decode_row_col (&image
->tables
[table
], idx
, col
);
1458 * mono_metadata_parse_typedef_or_ref:
1459 * \param m a metadata context.
1460 * \param ptr a pointer to an encoded TypedefOrRef in \p m
1461 * \param rptr pointer updated to match the end of the decoded stream
1462 * \returns a token valid in the \p m metadata decoded from
1463 * the compressed representation.
1466 mono_metadata_parse_typedef_or_ref (MonoImage
*m
, const char *ptr
, const char **rptr
)
1469 token
= mono_metadata_decode_value (ptr
, &ptr
);
1472 return mono_metadata_token_from_dor (token
);
1476 * mono_metadata_parse_custom_mod:
1477 * \param m a metadata context.
1478 * \param dest storage where the info about the custom modifier is stored (may be NULL)
1479 * \param ptr a pointer to (possibly) the start of a custom modifier list
1480 * \param rptr pointer updated to match the end of the decoded stream
1482 * Checks if \p ptr points to a type custom modifier compressed representation.
1484 * \returns TRUE if a custom modifier was found, FALSE if not.
1487 mono_metadata_parse_custom_mod (MonoImage
*m
, MonoCustomMod
*dest
, const char *ptr
, const char **rptr
)
1489 MonoCustomMod local
;
1490 if ((*ptr
== MONO_TYPE_CMOD_OPT
) || (*ptr
== MONO_TYPE_CMOD_REQD
)) {
1493 dest
->required
= *ptr
== MONO_TYPE_CMOD_REQD
? 1 : 0;
1494 dest
->token
= mono_metadata_parse_typedef_or_ref (m
, ptr
+ 1, rptr
);
1501 * mono_metadata_parse_array_internal:
1502 * @m: a metadata context.
1503 * @transient: whenever to allocate data from the heap
1504 * @ptr: a pointer to an encoded array description.
1505 * @rptr: pointer updated to match the end of the decoded stream
1507 * Decodes the compressed array description found in the metadata @m at @ptr.
1509 * Returns: a #MonoArrayType structure describing the array type
1510 * and dimensions. Memory is allocated from the heap or from the image mempool, depending
1511 * on the value of @transient.
1513 * LOCKING: Acquires the loader lock
1515 static MonoArrayType
*
1516 mono_metadata_parse_array_internal (MonoImage
*m
, MonoGenericContainer
*container
,
1517 gboolean transient
, const char *ptr
, const char **rptr
, MonoError
*error
)
1520 MonoArrayType
*array
;
1523 etype
= mono_metadata_parse_type_checked (m
, container
, 0, FALSE
, ptr
, &ptr
, error
); //FIXME this doesn't respect @transient
1527 array
= transient
? (MonoArrayType
*)g_malloc0 (sizeof (MonoArrayType
)) : (MonoArrayType
*)mono_image_alloc0 (m
, sizeof (MonoArrayType
));
1528 array
->eklass
= mono_class_from_mono_type_internal (etype
);
1529 array
->rank
= mono_metadata_decode_value (ptr
, &ptr
);
1531 array
->numsizes
= mono_metadata_decode_value (ptr
, &ptr
);
1532 if (array
->numsizes
)
1533 array
->sizes
= transient
? (int *)g_malloc0 (sizeof (int) * array
->numsizes
) : (int *)mono_image_alloc0 (m
, sizeof (int) * array
->numsizes
);
1534 for (i
= 0; i
< array
->numsizes
; ++i
)
1535 array
->sizes
[i
] = mono_metadata_decode_value (ptr
, &ptr
);
1537 array
->numlobounds
= mono_metadata_decode_value (ptr
, &ptr
);
1538 if (array
->numlobounds
)
1539 array
->lobounds
= transient
? (int *)g_malloc0 (sizeof (int) * array
->numlobounds
) : (int *)mono_image_alloc0 (m
, sizeof (int) * array
->numlobounds
);
1540 for (i
= 0; i
< array
->numlobounds
; ++i
)
1541 array
->lobounds
[i
] = mono_metadata_decode_signed_value (ptr
, &ptr
);
1549 * mono_metadata_parse_array:
1552 mono_metadata_parse_array (MonoImage
*m
, const char *ptr
, const char **rptr
)
1555 MonoArrayType
*ret
= mono_metadata_parse_array_internal (m
, NULL
, FALSE
, ptr
, rptr
, error
);
1556 mono_error_cleanup (error
);
1562 * mono_metadata_free_array:
1563 * \param array array description
1565 * Frees the array description returned from \c mono_metadata_parse_array.
1568 mono_metadata_free_array (MonoArrayType
*array
)
1570 g_free (array
->sizes
);
1571 g_free (array
->lobounds
);
1576 * need to add common field and param attributes combinations:
1579 * public static literal
1582 * private static literal
1584 static const MonoType
1586 /* data, attrs, type, nmods, byref, pinned */
1587 {{NULL
}, 0, MONO_TYPE_VOID
, 0, 0, 0},
1588 {{NULL
}, 0, MONO_TYPE_BOOLEAN
, 0, 0, 0},
1589 {{NULL
}, 0, MONO_TYPE_BOOLEAN
, 0, 1, 0},
1590 {{NULL
}, 0, MONO_TYPE_CHAR
, 0, 0, 0},
1591 {{NULL
}, 0, MONO_TYPE_CHAR
, 0, 1, 0},
1592 {{NULL
}, 0, MONO_TYPE_I1
, 0, 0, 0},
1593 {{NULL
}, 0, MONO_TYPE_I1
, 0, 1, 0},
1594 {{NULL
}, 0, MONO_TYPE_U1
, 0, 0, 0},
1595 {{NULL
}, 0, MONO_TYPE_U1
, 0, 1, 0},
1596 {{NULL
}, 0, MONO_TYPE_I2
, 0, 0, 0},
1597 {{NULL
}, 0, MONO_TYPE_I2
, 0, 1, 0},
1598 {{NULL
}, 0, MONO_TYPE_U2
, 0, 0, 0},
1599 {{NULL
}, 0, MONO_TYPE_U2
, 0, 1, 0},
1600 {{NULL
}, 0, MONO_TYPE_I4
, 0, 0, 0},
1601 {{NULL
}, 0, MONO_TYPE_I4
, 0, 1, 0},
1602 {{NULL
}, 0, MONO_TYPE_U4
, 0, 0, 0},
1603 {{NULL
}, 0, MONO_TYPE_U4
, 0, 1, 0},
1604 {{NULL
}, 0, MONO_TYPE_I8
, 0, 0, 0},
1605 {{NULL
}, 0, MONO_TYPE_I8
, 0, 1, 0},
1606 {{NULL
}, 0, MONO_TYPE_U8
, 0, 0, 0},
1607 {{NULL
}, 0, MONO_TYPE_U8
, 0, 1, 0},
1608 {{NULL
}, 0, MONO_TYPE_R4
, 0, 0, 0},
1609 {{NULL
}, 0, MONO_TYPE_R4
, 0, 1, 0},
1610 {{NULL
}, 0, MONO_TYPE_R8
, 0, 0, 0},
1611 {{NULL
}, 0, MONO_TYPE_R8
, 0, 1, 0},
1612 {{NULL
}, 0, MONO_TYPE_STRING
, 0, 0, 0},
1613 {{NULL
}, 0, MONO_TYPE_STRING
, 0, 1, 0},
1614 {{NULL
}, 0, MONO_TYPE_OBJECT
, 0, 0, 0},
1615 {{NULL
}, 0, MONO_TYPE_OBJECT
, 0, 1, 0},
1616 {{NULL
}, 0, MONO_TYPE_TYPEDBYREF
, 0, 0, 0},
1617 {{NULL
}, 0, MONO_TYPE_I
, 0, 0, 0},
1618 {{NULL
}, 0, MONO_TYPE_I
, 0, 1, 0},
1619 {{NULL
}, 0, MONO_TYPE_U
, 0, 0, 0},
1620 {{NULL
}, 0, MONO_TYPE_U
, 0, 1, 0},
1623 #define NBUILTIN_TYPES() (sizeof (builtin_types) / sizeof (builtin_types [0]))
1625 static GHashTable
*type_cache
= NULL
;
1626 static gint32 next_generic_inst_id
= 0;
1628 /* Protected by image_sets_mutex */
1629 static MonoImageSet
*mscorlib_image_set
;
1630 /* Protected by image_sets_mutex */
1631 static GPtrArray
*image_sets
;
1632 static mono_mutex_t image_sets_mutex
;
1634 static guint
mono_generic_class_hash (gconstpointer data
);
1637 * MonoTypes with modifies are never cached, so we never check or use that field.
1640 mono_type_hash (gconstpointer data
)
1642 const MonoType
*type
= (const MonoType
*) data
;
1643 if (type
->type
== MONO_TYPE_GENERICINST
)
1644 return mono_generic_class_hash (type
->data
.generic_class
);
1646 return type
->type
| (type
->byref
<< 8) | (type
->attrs
<< 9);
1650 mono_type_equal (gconstpointer ka
, gconstpointer kb
)
1652 const MonoType
*a
= (const MonoType
*) ka
;
1653 const MonoType
*b
= (const MonoType
*) kb
;
1655 if (a
->type
!= b
->type
|| a
->byref
!= b
->byref
|| a
->attrs
!= b
->attrs
|| a
->pinned
!= b
->pinned
)
1657 /* need other checks */
1662 mono_metadata_generic_inst_hash (gconstpointer data
)
1664 const MonoGenericInst
*ginst
= (const MonoGenericInst
*) data
;
1668 g_assert (ginst
->type_argv
);
1670 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
1672 g_assert (ginst
->type_argv
[i
]);
1673 hash
+= mono_metadata_type_hash (ginst
->type_argv
[i
]);
1676 return hash
^ (ginst
->is_open
<< 8);
1680 mono_generic_inst_equal_full (const MonoGenericInst
*a
, const MonoGenericInst
*b
, gboolean signature_only
)
1684 // An optimization: if the ids of two insts are the same, we know they are the same inst and don't check contents.
1685 // Furthermore, because we perform early de-duping, if the ids differ, we know the contents differ.
1686 #ifndef MONO_SMALL_CONFIG // Optimization does not work in MONO_SMALL_CONFIG: There are no IDs
1687 if (a
->id
&& b
->id
) { // "id 0" means "object has no id"-- de-duping hasn't been performed yet, must check contents.
1690 // In signature-comparison mode id equality implies object equality, but this is not true for inequality.
1691 // Two separate objects could have signature-equavalent contents.
1692 if (!signature_only
)
1697 if (a
->is_open
!= b
->is_open
|| a
->type_argc
!= b
->type_argc
)
1699 for (i
= 0; i
< a
->type_argc
; ++i
) {
1700 if (!do_mono_metadata_type_equal (a
->type_argv
[i
], b
->type_argv
[i
], signature_only
))
1707 mono_metadata_generic_inst_equal (gconstpointer ka
, gconstpointer kb
)
1709 const MonoGenericInst
*a
= (const MonoGenericInst
*) ka
;
1710 const MonoGenericInst
*b
= (const MonoGenericInst
*) kb
;
1712 return mono_generic_inst_equal_full (a
, b
, FALSE
);
1716 mono_generic_class_hash (gconstpointer data
)
1718 const MonoGenericClass
*gclass
= (const MonoGenericClass
*) data
;
1719 guint hash
= mono_metadata_type_hash (m_class_get_byval_arg (gclass
->container_class
));
1722 hash
+= gclass
->is_tb_open
;
1723 hash
+= mono_metadata_generic_context_hash (&gclass
->context
);
1729 mono_generic_class_equal (gconstpointer ka
, gconstpointer kb
)
1731 const MonoGenericClass
*a
= (const MonoGenericClass
*) ka
;
1732 const MonoGenericClass
*b
= (const MonoGenericClass
*) kb
;
1734 return _mono_metadata_generic_class_equal (a
, b
, FALSE
);
1738 * mono_metadata_init:
1740 * Initialize the global variables of this module.
1741 * This is a Mono runtime internal function.
1744 mono_metadata_init (void)
1748 /* We guard against double initialization due to how pedump in verification mode works.
1749 Until runtime initialization is properly factored to work with what it needs we need workarounds like this.
1750 FIXME: https://bugzilla.xamarin.com/show_bug.cgi?id=58793
1752 static gboolean inited
;
1758 type_cache
= g_hash_table_new (mono_type_hash
, mono_type_equal
);
1760 for (i
= 0; i
< NBUILTIN_TYPES (); ++i
)
1761 g_hash_table_insert (type_cache
, (gpointer
) &builtin_types
[i
], (gpointer
) &builtin_types
[i
]);
1763 mono_os_mutex_init_recursive (&image_sets_mutex
);
1765 mono_counters_register ("ImgSet Cache Hit", MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &img_set_cache_hit
);
1766 mono_counters_register ("ImgSet Cache Miss", MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &img_set_cache_miss
);
1767 mono_counters_register ("ImgSet Count", MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &img_set_count
);
1771 * mono_metadata_cleanup:
1773 * Free all resources used by this module.
1774 * This is a Mono runtime internal function.
1777 mono_metadata_cleanup (void)
1779 g_hash_table_destroy (type_cache
);
1781 g_ptr_array_free (image_sets
, TRUE
);
1783 mono_os_mutex_destroy (&image_sets_mutex
);
1787 * mono_metadata_parse_type:
1788 * \param m metadata context
1789 * \param mode kind of type that may be found at \p ptr
1790 * \param opt_attrs optional attributes to store in the returned type
1791 * \param ptr pointer to the type representation
1792 * \param rptr pointer updated to match the end of the decoded stream
1793 * \param transient whenever to allocate the result from the heap or from a mempool
1795 * Decode a compressed type description found at \p ptr in \p m .
1796 * \p mode can be one of \c MONO_PARSE_MOD_TYPE, \c MONO_PARSE_PARAM, \c MONO_PARSE_RET,
1797 * \c MONO_PARSE_FIELD, \c MONO_PARSE_LOCAL, \c MONO_PARSE_TYPE.
1798 * This function can be used to decode type descriptions in method signatures,
1799 * field signatures, locals signatures etc.
1801 * To parse a generic type, \c generic_container points to the current class'es
1802 * (the \c generic_container field in the <code>MonoClass</code>) or the current generic method's
1803 * (stored in <code>image->property_hash</code>) generic container.
1804 * When we encounter a \c MONO_TYPE_VAR or \c MONO_TYPE_MVAR, it's looked up in
1805 * this \c MonoGenericContainer.
1807 * LOCKING: Acquires the loader lock.
1809 * \returns a \c MonoType structure representing the decoded type.
1812 mono_metadata_parse_type_internal (MonoImage
*m
, MonoGenericContainer
*container
,
1813 short opt_attrs
, gboolean transient
, const char *ptr
, const char **rptr
, MonoError
*error
)
1815 MonoType
*type
, *cached
;
1817 gboolean byref
= FALSE
;
1818 gboolean pinned
= FALSE
;
1819 const char *tmp_ptr
;
1820 int count
= 0; // Number of mod arguments
1826 * According to the spec, custom modifiers should come before the byref
1827 * flag, but the IL produced by ilasm from the following signature:
1828 * object modopt(...) &
1829 * starts with a byref flag, followed by the modifiers. (bug #49802)
1830 * Also, this type seems to be different from 'object & modopt(...)'. Maybe
1831 * it would be better to treat byref as real type constructor instead of
1833 * Also, pinned should come before anything else, but some MSV++ produced
1834 * assemblies violate this (#bug 61990).
1837 /* Count the modifiers first */
1842 case MONO_TYPE_PINNED
:
1843 case MONO_TYPE_BYREF
:
1846 case MONO_TYPE_CMOD_REQD
:
1847 case MONO_TYPE_CMOD_OPT
:
1849 mono_metadata_parse_custom_mod (m
, NULL
, tmp_ptr
, &tmp_ptr
);
1856 MonoCustomModContainer
*cmods
= NULL
;
1858 if (count
) { // There are mods, so the MonoType will be of nonstandard size.
1860 mono_error_set_bad_image (error
, m
, "Invalid type with more than 64 modifiers");
1864 size_t size
= mono_sizeof_type_with_mods (count
, FALSE
);
1865 type
= transient
? (MonoType
*)g_malloc0 (size
) : (MonoType
*)mono_image_alloc0 (m
, size
);
1866 type
->has_cmods
= TRUE
;
1868 cmods
= mono_type_get_cmods (type
);
1869 cmods
->count
= count
;
1871 } else { // The type is of standard size, so we can allocate it on the stack.
1873 memset (type
, 0, MONO_SIZEOF_TYPE
);
1876 /* Iterate again, but now parse pinned, byref and custom modifiers */
1878 /* cmods are encoded in reverse order from how we normally see them.
1879 * "int32 modopt (Foo) modopt (Bar)" is encoded as "cmod_opt [typedef_or_ref "Bar"] cmod_opt [typedef_or_ref "Foo"] I4"
1883 case MONO_TYPE_PINNED
:
1887 case MONO_TYPE_BYREF
:
1891 case MONO_TYPE_CMOD_REQD
:
1892 case MONO_TYPE_CMOD_OPT
:
1893 mono_metadata_parse_custom_mod (m
, &(cmods
->modifiers
[--count
]), ptr
, &ptr
);
1900 // either there were no cmods, or else we iterated through all of cmods backwards to populate it.
1901 g_assert (count
== 0);
1903 type
->attrs
= opt_attrs
;
1904 type
->byref
= byref
;
1905 type
->pinned
= pinned
? 1 : 0;
1907 if (!do_mono_metadata_parse_type (type
, m
, container
, transient
, ptr
, &ptr
, error
))
1913 // Possibly we can return an already-allocated type instead of the one we decoded
1914 if (!type
->has_cmods
&& !transient
) {
1915 /* no need to free type here, because it is on the stack */
1916 if ((type
->type
== MONO_TYPE_CLASS
|| type
->type
== MONO_TYPE_VALUETYPE
) && !type
->pinned
&& !type
->attrs
) {
1917 MonoType
*ret
= type
->byref
? m_class_get_this_arg (type
->data
.klass
) : m_class_get_byval_arg (type
->data
.klass
);
1919 /* Consider the case:
1921 class Foo<T> { class Bar {} }
1922 class Test : Foo<Test>.Bar {}
1924 When Foo<Test> is being expanded, 'Test' isn't yet initialized. It's actually in
1925 a really pristine state: it doesn't even know whether 'Test' is a reference or a value type.
1927 We ensure that the MonoClass is in a state that we can canonicalize to:
1929 klass->_byval_arg.data.klass == klass
1930 klass->this_arg.data.klass == klass
1932 If we can't canonicalize 'type', it doesn't matter, since later users of 'type' will do it.
1934 LOCKING: even though we don't explicitly hold a lock, in the problematic case 'ret' is a field
1935 of a MonoClass which currently holds the loader lock. 'type' is local.
1937 if (ret
->data
.klass
== type
->data
.klass
) {
1941 /* No need to use locking since nobody is modifying the hash table */
1942 if ((cached
= (MonoType
*)g_hash_table_lookup (type_cache
, type
))) {
1947 /* printf ("%x %x %c %s\n", type->attrs, type->num_mods, type->pinned ? 'p' : ' ', mono_type_full_name (type)); */
1949 if (type
== &stype
) { // Type was allocated on the stack, so we need to copy it to safety
1950 type
= transient
? (MonoType
*)g_malloc (MONO_SIZEOF_TYPE
) : (MonoType
*)mono_image_alloc (m
, MONO_SIZEOF_TYPE
);
1951 memcpy (type
, &stype
, MONO_SIZEOF_TYPE
);
1958 mono_metadata_parse_type_checked (MonoImage
*m
, MonoGenericContainer
*container
,
1959 short opt_attrs
, gboolean transient
, const char *ptr
, const char **rptr
, MonoError
*error
)
1961 return mono_metadata_parse_type_internal (m
, container
, opt_attrs
, transient
, ptr
, rptr
, error
);
1965 * LOCKING: Acquires the loader lock.
1968 mono_metadata_parse_type (MonoImage
*m
, MonoParseTypeMode mode
, short opt_attrs
,
1969 const char *ptr
, const char **rptr
)
1972 MonoType
* type
= mono_metadata_parse_type_internal (m
, NULL
, opt_attrs
, FALSE
, ptr
, rptr
, error
);
1973 mono_error_cleanup (error
);
1978 mono_metadata_method_has_param_attrs (MonoImage
*m
, int def
)
1980 MonoTableInfo
*paramt
= &m
->tables
[MONO_TABLE_PARAM
];
1981 MonoTableInfo
*methodt
= &m
->tables
[MONO_TABLE_METHOD
];
1982 guint lastp
, i
, param_index
= mono_metadata_decode_row_col (methodt
, def
- 1, MONO_METHOD_PARAMLIST
);
1984 if (def
< methodt
->rows
)
1985 lastp
= mono_metadata_decode_row_col (methodt
, def
, MONO_METHOD_PARAMLIST
);
1987 lastp
= m
->tables
[MONO_TABLE_PARAM
].rows
+ 1;
1989 for (i
= param_index
; i
< lastp
; ++i
) {
1990 guint32 flags
= mono_metadata_decode_row_col (paramt
, i
- 1, MONO_PARAM_FLAGS
);
1999 * mono_metadata_get_param_attrs:
2001 * @m The image to loader parameter attributes from
2002 * @def method def token (one based)
2003 * @param_count number of params to decode including the return value
2005 * Return the parameter attributes for the method whose MethodDef index is DEF. The
2006 * returned memory needs to be freed by the caller. If all the param attributes are
2007 * 0, then NULL is returned.
2010 mono_metadata_get_param_attrs (MonoImage
*m
, int def
, int param_count
)
2012 MonoTableInfo
*paramt
= &m
->tables
[MONO_TABLE_PARAM
];
2013 MonoTableInfo
*methodt
= &m
->tables
[MONO_TABLE_METHOD
];
2014 guint32 cols
[MONO_PARAM_SIZE
];
2015 guint lastp
, i
, param_index
= mono_metadata_decode_row_col (methodt
, def
- 1, MONO_METHOD_PARAMLIST
);
2018 if (def
< methodt
->rows
)
2019 lastp
= mono_metadata_decode_row_col (methodt
, def
, MONO_METHOD_PARAMLIST
);
2021 lastp
= paramt
->rows
+ 1;
2023 for (i
= param_index
; i
< lastp
; ++i
) {
2024 mono_metadata_decode_row (paramt
, i
- 1, cols
, MONO_PARAM_SIZE
);
2025 if (cols
[MONO_PARAM_FLAGS
]) {
2027 pattrs
= g_new0 (int, param_count
);
2028 /* at runtime we just ignore this kind of malformed file:
2029 * the verifier can signal the error to the user
2031 if (cols
[MONO_PARAM_SEQUENCE
] >= param_count
)
2033 pattrs
[cols
[MONO_PARAM_SEQUENCE
]] = cols
[MONO_PARAM_FLAGS
];
2042 * mono_metadata_parse_signature:
2043 * \param image metadata context
2044 * \param token metadata token
2046 * Decode a method signature stored in the \c StandAloneSig table
2048 * \returns a \c MonoMethodSignature describing the signature.
2050 MonoMethodSignature
*
2051 mono_metadata_parse_signature (MonoImage
*image
, guint32 token
)
2054 MonoMethodSignature
*ret
;
2055 ret
= mono_metadata_parse_signature_checked (image
, token
, error
);
2056 mono_error_cleanup (error
);
2061 * mono_metadata_parse_signature_checked:
2062 * @image: metadata context
2063 * @token: metadata token
2064 * @error: set on error
2066 * Decode a method signature stored in the STANDALONESIG table
2068 * Returns: a MonoMethodSignature describing the signature. On failure
2069 * returns NULL and sets @error.
2071 MonoMethodSignature
*
2072 mono_metadata_parse_signature_checked (MonoImage
*image
, guint32 token
, MonoError
*error
)
2076 MonoTableInfo
*tables
= image
->tables
;
2077 guint32 idx
= mono_metadata_token_index (token
);
2081 if (image_is_dynamic (image
)) {
2082 return (MonoMethodSignature
*)mono_lookup_dynamic_token (image
, token
, NULL
, error
);
2085 g_assert (mono_metadata_token_table(token
) == MONO_TABLE_STANDALONESIG
);
2087 sig
= mono_metadata_decode_row_col (&tables
[MONO_TABLE_STANDALONESIG
], idx
- 1, 0);
2089 ptr
= mono_metadata_blob_heap (image
, sig
);
2090 mono_metadata_decode_blob_size (ptr
, &ptr
);
2092 return mono_metadata_parse_method_signature_full (image
, NULL
, 0, ptr
, NULL
, error
);
2096 * mono_metadata_signature_alloc:
2097 * \param image metadata context
2098 * \param nparams number of parameters in the signature
2100 * Allocate a \c MonoMethodSignature structure with the specified number of params.
2101 * The return type and the params types need to be filled later.
2102 * This is a Mono runtime internal function.
2104 * LOCKING: Assumes the loader lock is held.
2106 * \returns the new \c MonoMethodSignature structure.
2108 MonoMethodSignature
*
2109 mono_metadata_signature_alloc (MonoImage
*m
, guint32 nparams
)
2111 MonoMethodSignature
*sig
;
2113 sig
= (MonoMethodSignature
*)mono_image_alloc0 (m
, MONO_SIZEOF_METHOD_SIGNATURE
+ ((gint32
)nparams
) * sizeof (MonoType
*));
2114 sig
->param_count
= nparams
;
2115 sig
->sentinelpos
= -1;
2120 static MonoMethodSignature
*
2121 mono_metadata_signature_dup_internal_with_padding (MonoImage
*image
, MonoMemPool
*mp
, MonoMethodSignature
*sig
, size_t padding
)
2123 int sigsize
, sig_header_size
;
2124 MonoMethodSignature
*ret
;
2125 sigsize
= sig_header_size
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*) + padding
;
2127 sigsize
+= mono_sizeof_type (sig
->ret
);
2130 ret
= (MonoMethodSignature
*)mono_image_alloc (image
, sigsize
);
2132 ret
= (MonoMethodSignature
*)mono_mempool_alloc (mp
, sigsize
);
2134 ret
= (MonoMethodSignature
*)g_malloc (sigsize
);
2137 memcpy (ret
, sig
, sig_header_size
- padding
);
2139 // Copy return value because of ownership semantics.
2141 // Danger! Do not alter padding use without changing the dup_add_this below
2142 intptr_t end_of_header
= (intptr_t)( (char*)(ret
) + sig_header_size
);
2143 ret
->ret
= (MonoType
*)end_of_header
;
2144 memcpy (ret
->ret
, sig
->ret
, mono_sizeof_type (sig
->ret
));
2150 static MonoMethodSignature
*
2151 mono_metadata_signature_dup_internal (MonoImage
*image
, MonoMemPool
*mp
, MonoMethodSignature
*sig
)
2153 return mono_metadata_signature_dup_internal_with_padding (image
, mp
, sig
, 0);
2156 * signature_dup_add_this:
2158 * Make a copy of @sig, adding an explicit this argument.
2160 MonoMethodSignature
*
2161 mono_metadata_signature_dup_add_this (MonoImage
*image
, MonoMethodSignature
*sig
, MonoClass
*klass
)
2163 MonoMethodSignature
*ret
;
2164 ret
= mono_metadata_signature_dup_internal_with_padding (image
, NULL
, sig
, sizeof (MonoType
*));
2166 ret
->param_count
= sig
->param_count
+ 1;
2167 ret
->hasthis
= FALSE
;
2169 for (int i
= sig
->param_count
- 1; i
>= 0; i
--)
2170 ret
->params
[i
+ 1] = sig
->params
[i
];
2171 ret
->params
[0] = m_class_is_valuetype (klass
) ? m_class_get_this_arg (klass
) : m_class_get_byval_arg (klass
);
2173 for (int i
= sig
->param_count
- 1; i
>= 0; i
--)
2174 g_assert(ret
->params
[i
+ 1]->type
== sig
->params
[i
]->type
&& ret
->params
[i
+1]->type
!= MONO_TYPE_END
);
2175 g_assert (ret
->ret
->type
== sig
->ret
->type
&& ret
->ret
->type
!= MONO_TYPE_END
);
2182 MonoMethodSignature
*
2183 mono_metadata_signature_dup_full (MonoImage
*image
, MonoMethodSignature
*sig
)
2185 MonoMethodSignature
*ret
= mono_metadata_signature_dup_internal (image
, NULL
, sig
);
2187 for (int i
= 0 ; i
< sig
->param_count
; i
++)
2188 g_assert(ret
->params
[i
]->type
== sig
->params
[i
]->type
);
2189 g_assert (ret
->ret
->type
== sig
->ret
->type
);
2194 /*The mempool is accessed without synchronization*/
2195 MonoMethodSignature
*
2196 mono_metadata_signature_dup_mempool (MonoMemPool
*mp
, MonoMethodSignature
*sig
)
2198 return mono_metadata_signature_dup_internal (NULL
, mp
, sig
);
2202 * mono_metadata_signature_dup:
2203 * \param sig method signature
2205 * Duplicate an existing \c MonoMethodSignature so it can be modified.
2206 * This is a Mono runtime internal function.
2208 * \returns the new \c MonoMethodSignature structure.
2210 MonoMethodSignature
*
2211 mono_metadata_signature_dup (MonoMethodSignature
*sig
)
2213 return mono_metadata_signature_dup_full (NULL
, sig
);
2217 * mono_metadata_signature_size:
2219 * Return the amount of memory allocated to SIG.
2222 mono_metadata_signature_size (MonoMethodSignature
*sig
)
2224 return MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
2228 * mono_metadata_parse_method_signature_full:
2229 * \param m metadata context
2230 * \param generic_container: generics container
2231 * \param def the \c MethodDef index or 0 for \c Ref signatures.
2232 * \param ptr pointer to the signature metadata representation
2233 * \param rptr pointer updated to match the end of the decoded stream
2234 * \param error set on error
2237 * Decode a method signature stored at \p ptr.
2238 * This is a Mono runtime internal function.
2240 * LOCKING: Assumes the loader lock is held.
2242 * \returns a \c MonoMethodSignature describing the signature. On error sets
2243 * \p error and returns \c NULL.
2245 MonoMethodSignature
*
2246 mono_metadata_parse_method_signature_full (MonoImage
*m
, MonoGenericContainer
*container
,
2247 int def
, const char *ptr
, const char **rptr
, MonoError
*error
)
2249 MonoMethodSignature
*method
;
2250 int i
, *pattrs
= NULL
;
2251 guint32 hasthis
= 0, explicit_this
= 0, call_convention
, param_count
;
2252 guint32 gen_param_count
= 0;
2253 gboolean is_open
= FALSE
;
2258 gen_param_count
= 1;
2263 call_convention
= *ptr
& 0x0F;
2265 if (gen_param_count
)
2266 gen_param_count
= mono_metadata_decode_value (ptr
, &ptr
);
2267 param_count
= mono_metadata_decode_value (ptr
, &ptr
);
2270 pattrs
= mono_metadata_get_param_attrs (m
, def
, param_count
+ 1); /*Must be + 1 since signature's param count doesn't account for the return value */
2272 method
= mono_metadata_signature_alloc (m
, param_count
);
2273 method
->hasthis
= hasthis
;
2274 method
->explicit_this
= explicit_this
;
2275 method
->call_convention
= call_convention
;
2276 method
->generic_param_count
= gen_param_count
;
2278 switch (method
->call_convention
) {
2279 case MONO_CALL_DEFAULT
:
2280 case MONO_CALL_VARARG
:
2281 method
->pinvoke
= 0;
2284 case MONO_CALL_STDCALL
:
2285 case MONO_CALL_THISCALL
:
2286 case MONO_CALL_FASTCALL
:
2287 method
->pinvoke
= 1;
2291 if (call_convention
!= 0xa) {
2292 method
->ret
= mono_metadata_parse_type_checked (m
, container
, pattrs
? pattrs
[0] : 0, FALSE
, ptr
, &ptr
, error
);
2294 mono_metadata_free_method_signature (method
);
2298 is_open
= mono_class_is_open_constructed_type (method
->ret
);
2301 for (i
= 0; i
< method
->param_count
; ++i
) {
2302 if (*ptr
== MONO_TYPE_SENTINEL
) {
2303 if (method
->call_convention
!= MONO_CALL_VARARG
|| def
) {
2304 mono_error_set_bad_image (error
, m
, "Found sentinel for methoddef or no vararg");
2308 if (method
->sentinelpos
>= 0) {
2309 mono_error_set_bad_image (error
, m
, "Found sentinel twice in the same signature.");
2313 method
->sentinelpos
= i
;
2316 method
->params
[i
] = mono_metadata_parse_type_checked (m
, container
, pattrs
? pattrs
[i
+1] : 0, FALSE
, ptr
, &ptr
, error
);
2317 if (!method
->params
[i
]) {
2318 mono_metadata_free_method_signature (method
);
2323 is_open
= mono_class_is_open_constructed_type (method
->params
[i
]);
2326 /* The sentinel could be missing if the caller does not pass any additional arguments */
2327 if (!def
&& method
->call_convention
== MONO_CALL_VARARG
&& method
->sentinelpos
< 0)
2328 method
->sentinelpos
= method
->param_count
;
2330 method
->has_type_parameters
= is_open
;
2332 if (def
&& (method
->call_convention
== MONO_CALL_VARARG
))
2333 method
->sentinelpos
= method
->param_count
;
2340 * Add signature to a cache and increase ref count...
2347 * mono_metadata_parse_method_signature:
2348 * \param m metadata context
2349 * \param def the \c MethodDef index or 0 for \c Ref signatures.
2350 * \param ptr pointer to the signature metadata representation
2351 * \param rptr pointer updated to match the end of the decoded stream
2353 * Decode a method signature stored at \p ptr.
2354 * This is a Mono runtime internal function.
2356 * LOCKING: Assumes the loader lock is held.
2358 * \returns a \c MonoMethodSignature describing the signature.
2360 MonoMethodSignature
*
2361 mono_metadata_parse_method_signature (MonoImage
*m
, int def
, const char *ptr
, const char **rptr
)
2364 * This function MUST NOT be called by runtime code as it does error handling incorrectly.
2365 * Use mono_metadata_parse_method_signature_full instead.
2366 * It's ok to asser on failure as we no longer use it.
2369 MonoMethodSignature
*ret
;
2370 ret
= mono_metadata_parse_method_signature_full (m
, NULL
, def
, ptr
, rptr
, error
);
2371 mono_error_assert_ok (error
);
2377 * mono_metadata_free_method_signature:
2378 * \param sig signature to destroy
2380 * Free the memory allocated in the signature \p sig.
2381 * This method needs to be robust and work also on partially-built
2382 * signatures, so it does extra checks.
2385 mono_metadata_free_method_signature (MonoMethodSignature
*sig
)
2387 /* Everything is allocated from mempools */
2391 mono_metadata_free_type (sig->ret);
2392 for (i = 0; i < sig->param_count; ++i) {
2393 if (sig->params [i])
2394 mono_metadata_free_type (sig->params [i]);
2400 mono_metadata_free_inflated_signature (MonoMethodSignature
*sig
)
2404 /* Allocated in inflate_generic_signature () */
2406 mono_metadata_free_type (sig
->ret
);
2407 for (i
= 0; i
< sig
->param_count
; ++i
) {
2408 if (sig
->params
[i
])
2409 mono_metadata_free_type (sig
->params
[i
]);
2415 inflated_method_equal (gconstpointer a
, gconstpointer b
)
2417 const MonoMethodInflated
*ma
= (const MonoMethodInflated
*)a
;
2418 const MonoMethodInflated
*mb
= (const MonoMethodInflated
*)b
;
2419 if (ma
->declaring
!= mb
->declaring
)
2421 return mono_metadata_generic_context_equal (&ma
->context
, &mb
->context
);
2425 inflated_method_hash (gconstpointer a
)
2427 const MonoMethodInflated
*ma
= (const MonoMethodInflated
*)a
;
2428 return (mono_metadata_generic_context_hash (&ma
->context
) ^ mono_aligned_addr_hash (ma
->declaring
));
2432 inflated_signature_equal (gconstpointer a
, gconstpointer b
)
2434 const MonoInflatedMethodSignature
*sig1
= (const MonoInflatedMethodSignature
*)a
;
2435 const MonoInflatedMethodSignature
*sig2
= (const MonoInflatedMethodSignature
*)b
;
2437 /* sig->sig is assumed to be canonized */
2438 if (sig1
->sig
!= sig2
->sig
)
2440 /* The generic instances are canonized */
2441 return mono_metadata_generic_context_equal (&sig1
->context
, &sig2
->context
);
2445 inflated_signature_hash (gconstpointer a
)
2447 const MonoInflatedMethodSignature
*sig
= (const MonoInflatedMethodSignature
*)a
;
2449 /* sig->sig is assumed to be canonized */
2450 return mono_metadata_generic_context_hash (&sig
->context
) ^ mono_aligned_addr_hash (sig
->sig
);
2454 dump_ginst (MonoGenericInst *ginst)
2459 g_print ("Ginst: <");
2460 for (i = 0; i < ginst->type_argc; ++i) {
2463 name = mono_type_get_name (ginst->type_argv [i]);
2464 g_print ("%s", name);
2471 aggregate_modifiers_equal (gconstpointer ka
, gconstpointer kb
)
2473 MonoAggregateModContainer
*amods1
= (MonoAggregateModContainer
*)ka
;
2474 MonoAggregateModContainer
*amods2
= (MonoAggregateModContainer
*)kb
;
2475 if (amods1
->count
!= amods2
->count
)
2477 for (int i
= 0; i
< amods1
->count
; ++i
) {
2478 if (amods1
->modifiers
[i
].required
!= amods2
->modifiers
[i
].required
)
2480 if (!mono_metadata_type_equal_full (amods1
->modifiers
[i
].type
, amods2
->modifiers
[i
].type
, TRUE
))
2487 aggregate_modifiers_hash (gconstpointer a
)
2489 const MonoAggregateModContainer
*amods
= (const MonoAggregateModContainer
*)a
;
2491 for (int i
= 0; i
< amods
->count
; ++i
)
2493 // hash details borrowed from mono_metadata_generic_inst_hash
2495 hash
^= (amods
->modifiers
[i
].required
<< 8);
2496 hash
+= mono_metadata_type_hash (amods
->modifiers
[i
].type
);
2502 static gboolean
type_in_image (MonoType
*type
, MonoImage
*image
);
2503 static gboolean
aggregate_modifiers_in_image (MonoAggregateModContainer
*amods
, MonoImage
*image
);
2506 signature_in_image (MonoMethodSignature
*sig
, MonoImage
*image
)
2508 gpointer iter
= NULL
;
2511 while ((p
= mono_signature_get_params (sig
, &iter
)) != NULL
)
2512 if (type_in_image (p
, image
))
2515 return type_in_image (mono_signature_get_return_type (sig
), image
);
2519 ginst_in_image (MonoGenericInst
*ginst
, MonoImage
*image
)
2523 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
2524 if (type_in_image (ginst
->type_argv
[i
], image
))
2532 gclass_in_image (MonoGenericClass
*gclass
, MonoImage
*image
)
2534 return m_class_get_image (gclass
->container_class
) == image
||
2535 ginst_in_image (gclass
->context
.class_inst
, image
);
2539 type_in_image (MonoType
*type
, MonoImage
*image
)
2542 if (type
->has_cmods
&& mono_type_is_aggregate_mods (type
))
2543 if (aggregate_modifiers_in_image (mono_type_get_amods (type
), image
))
2546 switch (type
->type
) {
2547 case MONO_TYPE_GENERICINST
:
2548 return gclass_in_image (type
->data
.generic_class
, image
);
2550 type
= type
->data
.type
;
2552 case MONO_TYPE_SZARRAY
:
2553 type
= m_class_get_byval_arg (type
->data
.klass
);
2555 case MONO_TYPE_ARRAY
:
2556 type
= m_class_get_byval_arg (type
->data
.array
->eklass
);
2558 case MONO_TYPE_FNPTR
:
2559 return signature_in_image (type
->data
.method
, image
);
2561 case MONO_TYPE_MVAR
:
2562 return image
== mono_get_image_for_generic_param (type
->data
.generic_param
);
2564 /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type_internal () */
2565 return image
== m_class_get_image (mono_class_from_mono_type_internal (type
));
2570 mono_type_in_image (MonoType
*type
, MonoImage
*image
)
2572 return type_in_image (type
, image
);
2576 aggregate_modifiers_in_image (MonoAggregateModContainer
*amods
, MonoImage
*image
)
2578 for (int i
= 0; i
< amods
->count
; i
++)
2579 if (type_in_image (amods
->modifiers
[i
].type
, image
))
2585 image_sets_lock (void)
2587 mono_os_mutex_lock (&image_sets_mutex
);
2591 image_sets_unlock (void)
2593 mono_os_mutex_unlock (&image_sets_mutex
);
2597 #define HASH_TABLE_SIZE 1103
2598 static MonoImageSet
*img_set_cache
[HASH_TABLE_SIZE
];
2601 mix_hash (uintptr_t source
)
2603 unsigned int hash
= source
;
2606 hash
= (((hash
* 215497) >> 16) ^ ((hash
* 1823231) + hash
));
2608 // Mix in highest bits on 64-bit systems only
2609 if (sizeof (source
) > 4)
2610 hash
= hash
^ ((source
>> 31) >> 1);
2616 hash_images (MonoImage
**images
, int nimages
)
2620 for (i
= 0; i
< nimages
; ++i
)
2621 res
+= mix_hash ((size_t)images
[i
]);
2627 compare_img_set (MonoImageSet
*set
, MonoImage
**images
, int nimages
)
2631 if (set
->nimages
!= nimages
)
2634 for (j
= 0; j
< nimages
; ++j
) {
2635 for (k
= 0; k
< nimages
; ++k
)
2636 if (set
->images
[k
] == images
[j
])
2637 break; // Break on match
2639 // If we iterated all the way through set->images, images[j] was *not* found.
2641 break; // Break on "image not found"
2644 // If we iterated all the way through images without breaking, all items in images were found in set->images
2645 return j
== nimages
;
2649 static MonoImageSet
*
2650 img_set_cache_get (MonoImage
**images
, int nimages
)
2652 guint32 hash_code
= hash_images (images
, nimages
);
2653 int index
= hash_code
% HASH_TABLE_SIZE
;
2654 MonoImageSet
*img
= img_set_cache
[index
];
2655 if (!img
|| !compare_img_set (img
, images
, nimages
)) {
2656 UnlockedIncrement (&img_set_cache_miss
);
2659 UnlockedIncrement (&img_set_cache_hit
);
2664 img_set_cache_add (MonoImageSet
*set
)
2666 guint32 hash_code
= hash_images (set
->images
, set
->nimages
);
2667 int index
= hash_code
% HASH_TABLE_SIZE
;
2668 img_set_cache
[index
] = set
;
2672 img_set_cache_remove (MonoImageSet
*is
)
2674 guint32 hash_code
= hash_images (is
->images
, is
->nimages
);
2675 int index
= hash_code
% HASH_TABLE_SIZE
;
2676 if (img_set_cache
[index
] == is
)
2677 img_set_cache
[index
] = NULL
;
2682 * Return a MonoImageSet representing the set of images in IMAGES.
2684 static MonoImageSet
*
2685 get_image_set (MonoImage
**images
, int nimages
)
2691 /* Common case: Image set contains corlib only. If we've seen that case before, we cached the set. */
2692 if (nimages
== 1 && images
[0] == mono_defaults
.corlib
&& mscorlib_image_set
)
2693 return mscorlib_image_set
;
2695 /* Happens with empty generic instances */
2696 // FIXME: Is corlib the correct thing to return here? If so, why? This may be an artifact of generic instances previously defaulting to allocating from corlib.
2698 return mscorlib_image_set
;
2700 set
= img_set_cache_get (images
, nimages
);
2707 image_sets
= g_ptr_array_new ();
2709 // Before we go on, we should check to see whether a MonoImageSet with these images already exists.
2710 // We can search the referred-by imagesets of any one of our images to do this. Arbitrarily pick one here:
2711 if (images
[0] == mono_defaults
.corlib
&& nimages
> 1)
2712 l
= images
[1]->image_sets
; // Prefer not to search the imagesets of corlib-- that will be a long list.
2714 l
= images
[0]->image_sets
;
2717 while (l
) // Iterate over selected list, looking for an imageset with members equal to our target one
2719 set
= (MonoImageSet
*)l
->data
;
2721 if (set
->nimages
== nimages
) { // Member count differs, this can't be it
2722 // Compare all members to all members-- order might be different
2723 for (j
= 0; j
< nimages
; ++j
) {
2724 for (k
= 0; k
< nimages
; ++k
)
2725 if (set
->images
[k
] == images
[j
])
2726 break; // Break on match
2728 // If we iterated all the way through set->images, images[j] was *not* found.
2730 break; // Break on "image not found"
2733 // If we iterated all the way through images without breaking, all items in images were found in set->images
2735 // Break on "found a set with equal members".
2736 // This happens in case of a hash collision with a previously cached set.
2744 // If we iterated all the way through l without breaking, the imageset does not already exist and we should create it
2746 set
= g_new0 (MonoImageSet
, 1);
2747 set
->nimages
= nimages
;
2748 set
->images
= g_new0 (MonoImage
*, nimages
);
2749 mono_os_mutex_init_recursive (&set
->lock
);
2750 for (i
= 0; i
< nimages
; ++i
)
2751 set
->images
[i
] = images
[i
];
2752 set
->gclass_cache
= mono_conc_hashtable_new_full (mono_generic_class_hash
, mono_generic_class_equal
, NULL
, (GDestroyNotify
)free_generic_class
);
2753 set
->ginst_cache
= g_hash_table_new_full (mono_metadata_generic_inst_hash
, mono_metadata_generic_inst_equal
, NULL
, (GDestroyNotify
)free_generic_inst
);
2754 set
->gmethod_cache
= g_hash_table_new_full (inflated_method_hash
, inflated_method_equal
, NULL
, (GDestroyNotify
)free_inflated_method
);
2755 set
->gsignature_cache
= g_hash_table_new_full (inflated_signature_hash
, inflated_signature_equal
, NULL
, (GDestroyNotify
)free_inflated_signature
);
2757 set
->szarray_cache
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, NULL
);
2758 set
->array_cache
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, NULL
);
2760 set
->aggregate_modifiers_cache
= g_hash_table_new_full (aggregate_modifiers_hash
, aggregate_modifiers_equal
, NULL
, (GDestroyNotify
)free_aggregate_modifiers
);
2762 for (i
= 0; i
< nimages
; ++i
)
2763 set
->images
[i
]->image_sets
= g_slist_prepend (set
->images
[i
]->image_sets
, set
);
2765 g_ptr_array_add (image_sets
, set
);
2766 UnlockedIncrement (&img_set_count
); /* locked by image_sets_lock () */
2769 /* Cache the set. If there was a cache collision, the previously cached value will be replaced. */
2770 img_set_cache_add (set
);
2772 if (nimages
== 1 && images
[0] == mono_defaults
.corlib
) {
2773 mono_memory_barrier ();
2774 mscorlib_image_set
= set
;
2777 image_sets_unlock ();
2783 delete_image_set (MonoImageSet
*set
)
2787 mono_conc_hashtable_destroy (set
->gclass_cache
);
2788 g_hash_table_destroy (set
->ginst_cache
);
2789 g_hash_table_destroy (set
->gmethod_cache
);
2790 g_hash_table_destroy (set
->gsignature_cache
);
2792 g_hash_table_destroy (set
->szarray_cache
);
2793 g_hash_table_destroy (set
->array_cache
);
2795 g_hash_table_destroy (set
->ptr_cache
);
2797 g_hash_table_destroy (set
->aggregate_modifiers_cache
);
2799 for (i
= 0; i
< set
->gshared_types_len
; ++i
) {
2800 if (set
->gshared_types
[i
])
2801 g_hash_table_destroy (set
->gshared_types
[i
]);
2803 g_free (set
->gshared_types
);
2805 mono_wrapper_caches_free (&set
->wrapper_caches
);
2809 for (i
= 0; i
< set
->nimages
; ++i
)
2810 set
->images
[i
]->image_sets
= g_slist_remove (set
->images
[i
]->image_sets
, set
);
2812 g_ptr_array_remove (image_sets
, set
);
2814 image_sets_unlock ();
2816 img_set_cache_remove (set
);
2819 mono_mempool_destroy (set
->mempool
);
2820 g_free (set
->images
);
2821 mono_os_mutex_destroy (&set
->lock
);
2826 mono_image_set_lock (MonoImageSet
*set
)
2828 mono_os_mutex_lock (&set
->lock
);
2832 mono_image_set_unlock (MonoImageSet
*set
)
2834 mono_os_mutex_unlock (&set
->lock
);
2838 mono_image_set_alloc (MonoImageSet
*set
, guint size
)
2842 mono_image_set_lock (set
);
2844 set
->mempool
= mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE
);
2845 res
= mono_mempool_alloc (set
->mempool
, size
);
2846 mono_image_set_unlock (set
);
2852 mono_image_set_alloc0 (MonoImageSet
*set
, guint size
)
2856 mono_image_set_lock (set
);
2858 set
->mempool
= mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE
);
2859 res
= mono_mempool_alloc0 (set
->mempool
, size
);
2860 mono_image_set_unlock (set
);
2866 mono_image_set_strdup (MonoImageSet
*set
, const char *s
)
2870 mono_image_set_lock (set
);
2872 set
->mempool
= mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE
);
2873 res
= mono_mempool_strdup (set
->mempool
, s
);
2874 mono_image_set_unlock (set
);
2879 // Get a descriptive string for a MonoImageSet
2880 // Callers are obligated to free buffer with g_free after use
2882 mono_image_set_description (MonoImageSet
*set
)
2884 GString
*result
= g_string_new (NULL
);
2886 g_string_append (result
, "[");
2887 for (img
= 0; img
< set
->nimages
; img
++)
2890 g_string_append (result
, ", ");
2891 g_string_append (result
, set
->images
[img
]->name
);
2893 g_string_append (result
, "]");
2894 return g_string_free (result
, FALSE
);
2898 * Structure used by the collect_..._images functions to store the image list.
2901 MonoImage
*image_buf
[64];
2903 int nimages
, images_len
;
2907 collect_data_init (CollectData
*data
)
2909 data
->images
= data
->image_buf
;
2910 data
->images_len
= 64;
2915 collect_data_free (CollectData
*data
)
2917 if (data
->images
!= data
->image_buf
)
2918 g_free (data
->images
);
2922 enlarge_data (CollectData
*data
)
2924 int new_len
= data
->images_len
< 16 ? 16 : data
->images_len
* 2;
2925 MonoImage
**d
= g_new (MonoImage
*, new_len
);
2928 g_assert_not_reached ();
2929 memcpy (d
, data
->images
, data
->images_len
);
2930 if (data
->images
!= data
->image_buf
)
2931 g_free (data
->images
);
2933 data
->images_len
= new_len
;
2937 add_image (MonoImage
*image
, CollectData
*data
)
2941 /* The arrays are small, so use a linear search instead of a hash table */
2942 for (i
= 0; i
< data
->nimages
; ++i
)
2943 if (data
->images
[i
] == image
)
2946 if (data
->nimages
== data
->images_len
)
2947 enlarge_data (data
);
2949 data
->images
[data
->nimages
++] = image
;
2953 collect_type_images (MonoType
*type
, CollectData
*data
);
2956 collect_ginst_images (MonoGenericInst
*ginst
, CollectData
*data
)
2960 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
2961 collect_type_images (ginst
->type_argv
[i
], data
);
2966 collect_gclass_images (MonoGenericClass
*gclass
, CollectData
*data
)
2968 add_image (m_class_get_image (gclass
->container_class
), data
);
2969 if (gclass
->context
.class_inst
)
2970 collect_ginst_images (gclass
->context
.class_inst
, data
);
2974 collect_signature_images (MonoMethodSignature
*sig
, CollectData
*data
)
2976 gpointer iter
= NULL
;
2979 collect_type_images (mono_signature_get_return_type (sig
), data
);
2980 while ((p
= mono_signature_get_params (sig
, &iter
)) != NULL
)
2981 collect_type_images (p
, data
);
2985 collect_inflated_signature_images (MonoInflatedMethodSignature
*sig
, CollectData
*data
)
2987 collect_signature_images (sig
->sig
, data
);
2988 if (sig
->context
.class_inst
)
2989 collect_ginst_images (sig
->context
.class_inst
, data
);
2990 if (sig
->context
.method_inst
)
2991 collect_ginst_images (sig
->context
.method_inst
, data
);
2995 collect_method_images (MonoMethodInflated
*method
, CollectData
*data
)
2997 MonoMethod
*m
= method
->declaring
;
2999 add_image (m_class_get_image (method
->declaring
->klass
), data
);
3000 if (method
->context
.class_inst
)
3001 collect_ginst_images (method
->context
.class_inst
, data
);
3002 if (method
->context
.method_inst
)
3003 collect_ginst_images (method
->context
.method_inst
, data
);
3005 * Dynamic assemblies have no references, so the images they depend on can be unloaded before them.
3007 if (image_is_dynamic (m_class_get_image (m
->klass
)))
3008 collect_signature_images (mono_method_signature_internal (m
), data
);
3012 collect_aggregate_modifiers_images (MonoAggregateModContainer
*amods
, CollectData
*data
)
3014 for (int i
= 0; i
< amods
->count
; ++i
)
3015 collect_type_images (amods
->modifiers
[i
].type
, data
);
3019 collect_type_images (MonoType
*type
, CollectData
*data
)
3022 if (G_UNLIKELY (type
->has_cmods
&& mono_type_is_aggregate_mods (type
))) {
3023 collect_aggregate_modifiers_images (mono_type_get_amods (type
), data
);
3026 switch (type
->type
) {
3027 case MONO_TYPE_GENERICINST
:
3028 collect_gclass_images (type
->data
.generic_class
, data
);
3031 type
= type
->data
.type
;
3033 case MONO_TYPE_SZARRAY
:
3034 type
= m_class_get_byval_arg (type
->data
.klass
);
3036 case MONO_TYPE_ARRAY
:
3037 type
= m_class_get_byval_arg (type
->data
.array
->eklass
);
3039 case MONO_TYPE_FNPTR
:
3040 //return signature_in_image (type->data.method, image);
3041 g_assert_not_reached ();
3043 case MONO_TYPE_MVAR
:
3045 MonoImage
*image
= mono_get_image_for_generic_param (type
->data
.generic_param
);
3046 add_image (image
, data
);
3049 case MONO_TYPE_CLASS
:
3050 case MONO_TYPE_VALUETYPE
:
3051 add_image (m_class_get_image (mono_class_from_mono_type_internal (type
)), data
);
3054 add_image (mono_defaults
.corlib
, data
);
3061 } CleanForImageUserData
;
3064 steal_gclass_in_image (gpointer key
, gpointer value
, gpointer data
)
3066 MonoGenericClass
*gclass
= (MonoGenericClass
*)key
;
3067 CleanForImageUserData
*user_data
= (CleanForImageUserData
*)data
;
3069 g_assert (gclass_in_image (gclass
, user_data
->image
));
3071 user_data
->list
= g_slist_prepend (user_data
->list
, gclass
);
3076 steal_ginst_in_image (gpointer key
, gpointer value
, gpointer data
)
3078 MonoGenericInst
*ginst
= (MonoGenericInst
*)key
;
3079 CleanForImageUserData
*user_data
= (CleanForImageUserData
*)data
;
3081 // This doesn't work during corlib compilation
3082 //g_assert (ginst_in_image (ginst, user_data->image));
3084 user_data
->list
= g_slist_prepend (user_data
->list
, ginst
);
3089 steal_aggregate_modifiers_in_image (gpointer key
, gpointer value
, gpointer data
)
3091 MonoAggregateModContainer
*amods
= (MonoAggregateModContainer
*)key
;
3092 CleanForImageUserData
*user_data
= (CleanForImageUserData
*)data
;
3094 g_assert (aggregate_modifiers_in_image (amods
, user_data
->image
));
3096 user_data
->list
= g_slist_prepend (user_data
->list
, amods
);
3101 inflated_method_in_image (gpointer key
, gpointer value
, gpointer data
)
3103 MonoImage
*image
= (MonoImage
*)data
;
3104 MonoMethodInflated
*method
= (MonoMethodInflated
*)key
;
3107 // https://bugzilla.novell.com/show_bug.cgi?id=458168
3108 g_assert (m_class_get_image (method
->declaring
->klass
) == image
||
3109 (method
->context
.class_inst
&& ginst_in_image (method
->context
.class_inst
, image
)) ||
3110 (method
->context
.method_inst
&& ginst_in_image (method
->context
.method_inst
, image
)) || (((MonoMethod
*)method
)->signature
&& signature_in_image (mono_method_signature_internal ((MonoMethod
*)method
), image
)));
3116 inflated_signature_in_image (gpointer key
, gpointer value
, gpointer data
)
3118 MonoImage
*image
= (MonoImage
*)data
;
3119 MonoInflatedMethodSignature
*sig
= (MonoInflatedMethodSignature
*)key
;
3121 return signature_in_image (sig
->sig
, image
) ||
3122 (sig
->context
.class_inst
&& ginst_in_image (sig
->context
.class_inst
, image
)) ||
3123 (sig
->context
.method_inst
&& ginst_in_image (sig
->context
.method_inst
, image
));
3127 class_in_image (gpointer key
, gpointer value
, gpointer data
)
3129 MonoImage
*image
= (MonoImage
*)data
;
3130 MonoClass
*klass
= (MonoClass
*)key
;
3132 g_assert (type_in_image (m_class_get_byval_arg (klass
), image
));
3138 check_gmethod (gpointer key
, gpointer value
, gpointer data
)
3140 MonoMethodInflated
*method
= (MonoMethodInflated
*)key
;
3141 MonoImage
*image
= (MonoImage
*)data
;
3143 if (method
->context
.class_inst
)
3144 g_assert (!ginst_in_image (method
->context
.class_inst
, image
));
3145 if (method
->context
.method_inst
)
3146 g_assert (!ginst_in_image (method
->context
.method_inst
, image
));
3147 if (((MonoMethod
*)method
)->signature
)
3148 g_assert (!signature_in_image (mono_method_signature_internal ((MonoMethod
*)method
), image
));
3154 * Run a consistency check on the image set data structures.
3156 static G_GNUC_UNUSED
void
3157 check_image_sets (MonoImage
*image
)
3160 GSList
*l
= image
->image_sets
;
3165 for (i
= 0; i
< image_sets
->len
; ++i
) {
3166 MonoImageSet
*set
= (MonoImageSet
*)g_ptr_array_index (image_sets
, i
);
3168 if (!g_slist_find (l
, set
)) {
3169 g_hash_table_foreach (set
->gmethod_cache
, check_gmethod
, image
);
3175 mono_metadata_clean_for_image (MonoImage
*image
)
3177 CleanForImageUserData ginst_data
, gclass_data
, amods_data
;
3178 GSList
*l
, *set_list
;
3180 //check_image_sets (image);
3183 * The data structures could reference each other so we delete them in two phases.
3184 * This is required because of the hashing functions in gclass/ginst_cache.
3186 ginst_data
.image
= gclass_data
.image
= image
;
3187 ginst_data
.list
= gclass_data
.list
= NULL
;
3188 amods_data
.image
= image
;
3189 amods_data
.list
= NULL
;
3191 /* Collect the items to delete */
3192 /* delete_image_set () modifies the lists so make a copy */
3193 for (l
= image
->image_sets
; l
; l
= l
->next
) {
3194 MonoImageSet
*set
= (MonoImageSet
*)l
->data
;
3196 mono_image_set_lock (set
);
3197 mono_conc_hashtable_foreach_steal (set
->gclass_cache
, steal_gclass_in_image
, &gclass_data
);
3198 g_hash_table_foreach_steal (set
->ginst_cache
, steal_ginst_in_image
, &ginst_data
);
3199 g_hash_table_foreach_remove (set
->gmethod_cache
, inflated_method_in_image
, image
);
3200 g_hash_table_foreach_remove (set
->gsignature_cache
, inflated_signature_in_image
, image
);
3202 g_hash_table_foreach_steal (set
->szarray_cache
, class_in_image
, image
);
3203 g_hash_table_foreach_steal (set
->array_cache
, class_in_image
, image
);
3205 g_hash_table_foreach_steal (set
->ptr_cache
, class_in_image
, image
);
3207 g_hash_table_foreach_steal (set
->aggregate_modifiers_cache
, steal_aggregate_modifiers_in_image
, &amods_data
);
3209 mono_image_set_unlock (set
);
3212 /* Delete the removed items */
3213 for (l
= ginst_data
.list
; l
; l
= l
->next
)
3214 free_generic_inst ((MonoGenericInst
*)l
->data
);
3215 for (l
= gclass_data
.list
; l
; l
= l
->next
)
3216 free_generic_class ((MonoGenericClass
*)l
->data
);
3217 for (l
= amods_data
.list
; l
; l
= l
->next
)
3218 free_aggregate_modifiers ((MonoAggregateModContainer
*)l
->data
);
3219 g_slist_free (ginst_data
.list
);
3220 g_slist_free (gclass_data
.list
);
3221 /* delete_image_set () modifies the lists so make a copy */
3222 set_list
= g_slist_copy (image
->image_sets
);
3223 for (l
= set_list
; l
; l
= l
->next
) {
3224 MonoImageSet
*set
= (MonoImageSet
*)l
->data
;
3226 delete_image_set (set
);
3228 g_slist_free (set_list
);
3232 free_inflated_method (MonoMethodInflated
*imethod
)
3234 MonoMethod
*method
= (MonoMethod
*)imethod
;
3236 if (method
->signature
)
3237 mono_metadata_free_inflated_signature (method
->signature
);
3239 if (method
->wrapper_type
)
3240 g_free (((MonoMethodWrapper
*)method
)->method_data
);
3246 free_generic_inst (MonoGenericInst
*ginst
)
3250 /* The ginst itself is allocated from the image set mempool */
3251 for (i
= 0; i
< ginst
->type_argc
; ++i
)
3252 mono_metadata_free_type (ginst
->type_argv
[i
]);
3256 free_generic_class (MonoGenericClass
*gclass
)
3258 /* The gclass itself is allocated from the image set mempool */
3259 if (gclass
->cached_class
&& m_class_get_interface_id (gclass
->cached_class
))
3260 mono_unload_interface_id (gclass
->cached_class
);
3264 free_inflated_signature (MonoInflatedMethodSignature
*sig
)
3266 mono_metadata_free_inflated_signature (sig
->sig
);
3271 free_aggregate_modifiers (MonoAggregateModContainer
*amods
)
3273 for (int i
= 0; i
< amods
->count
; i
++)
3274 mono_metadata_free_type (amods
->modifiers
[i
].type
);
3275 /* the container itself is allocated in the image set mempool */
3279 * mono_metadata_get_inflated_signature:
3281 * Given an inflated signature and a generic context, return a canonical copy of the
3282 * signature. The returned signature might be equal to SIG or it might be a cached copy.
3284 MonoMethodSignature
*
3285 mono_metadata_get_inflated_signature (MonoMethodSignature
*sig
, MonoGenericContext
*context
)
3287 MonoInflatedMethodSignature helper
;
3288 MonoInflatedMethodSignature
*res
;
3293 helper
.context
.class_inst
= context
->class_inst
;
3294 helper
.context
.method_inst
= context
->method_inst
;
3296 collect_data_init (&data
);
3298 collect_inflated_signature_images (&helper
, &data
);
3300 set
= get_image_set (data
.images
, data
.nimages
);
3302 collect_data_free (&data
);
3304 mono_image_set_lock (set
);
3306 res
= (MonoInflatedMethodSignature
*)g_hash_table_lookup (set
->gsignature_cache
, &helper
);
3308 res
= g_new0 (MonoInflatedMethodSignature
, 1);
3310 res
->context
.class_inst
= context
->class_inst
;
3311 res
->context
.method_inst
= context
->method_inst
;
3312 g_hash_table_insert (set
->gsignature_cache
, res
, res
);
3315 mono_image_set_unlock (set
);
3321 mono_metadata_get_image_set_for_type (MonoType
*type
)
3324 CollectData image_set_data
;
3326 collect_data_init (&image_set_data
);
3327 collect_type_images (type
, &image_set_data
);
3328 set
= get_image_set (image_set_data
.images
, image_set_data
.nimages
);
3329 collect_data_free (&image_set_data
);
3335 mono_metadata_get_image_set_for_class (MonoClass
*klass
)
3337 return mono_metadata_get_image_set_for_type (m_class_get_byval_arg (klass
));
3341 mono_metadata_get_image_set_for_method (MonoMethodInflated
*method
)
3344 CollectData image_set_data
;
3346 collect_data_init (&image_set_data
);
3347 collect_method_images (method
, &image_set_data
);
3348 set
= get_image_set (image_set_data
.images
, image_set_data
.nimages
);
3349 collect_data_free (&image_set_data
);
3355 mono_metadata_get_image_set_for_aggregate_modifiers (MonoAggregateModContainer
*amods
)
3358 CollectData image_set_data
;
3359 collect_data_init (&image_set_data
);
3360 collect_aggregate_modifiers_images (amods
, &image_set_data
);
3361 set
= get_image_set (image_set_data
.images
, image_set_data
.nimages
);
3362 collect_data_free (&image_set_data
);
3368 mono_metadata_merge_image_sets (MonoImageSet
*set1
, MonoImageSet
*set2
)
3370 MonoImage
**images
= g_newa (MonoImage
*, set1
->nimages
+ set2
->nimages
);
3372 /* Add images from set1 */
3373 memcpy (images
, set1
->images
, sizeof (MonoImage
*) * set1
->nimages
);
3375 int nimages
= set1
->nimages
;
3377 /* Add images from set2 */
3378 for (int i
= 0; i
< set2
->nimages
; ++i
) {
3380 for (j
= 0; j
< set1
->nimages
; ++j
) {
3381 if (set2
->images
[i
] == set1
->images
[j
])
3384 if (j
== set1
->nimages
)
3385 images
[nimages
++] = set2
->images
[i
];
3387 return get_image_set (images
, nimages
);
3391 type_is_gtd (MonoType
*type
)
3393 switch (type
->type
) {
3394 case MONO_TYPE_CLASS
:
3395 case MONO_TYPE_VALUETYPE
:
3396 return mono_class_is_gtd (type
->data
.klass
);
3403 * mono_metadata_get_generic_inst:
3405 * Given a list of types, return a MonoGenericInst that represents that list.
3406 * The returned MonoGenericInst has its own copy of the list of types. The list
3407 * passed in the argument can be freed, modified or disposed of.
3411 mono_metadata_get_generic_inst (int type_argc
, MonoType
**type_argv
)
3413 MonoGenericInst
*ginst
;
3416 int size
= MONO_SIZEOF_GENERIC_INST
+ type_argc
* sizeof (MonoType
*);
3418 for (i
= 0; i
< type_argc
; ++i
)
3419 if (mono_class_is_open_constructed_type (type_argv
[i
]))
3421 is_open
= (i
< type_argc
);
3423 ginst
= (MonoGenericInst
*)g_alloca (size
);
3424 memset (ginst
, 0, sizeof (MonoGenericInst
));
3425 ginst
->is_open
= is_open
;
3426 ginst
->type_argc
= type_argc
;
3427 memcpy (ginst
->type_argv
, type_argv
, type_argc
* sizeof (MonoType
*));
3429 for (i
= 0; i
< type_argc
; ++i
) {
3430 MonoType
*t
= ginst
->type_argv
[i
];
3431 if (type_is_gtd (t
)) {
3432 ginst
->type_argv
[i
] = mono_class_gtd_get_canonical_inst (t
->data
.klass
);
3436 return mono_metadata_get_canonical_generic_inst (ginst
);
3440 * mono_metadata_get_canonical_generic_inst:
3441 * \param candidate an arbitrary generic instantiation
3443 * \returns the canonical generic instantiation that represents the given
3444 * candidate by identifying the image set for the candidate instantiation and
3445 * finding the instance in the image set or adding a copy of the given instance
3448 * The returned MonoGenericInst has its own copy of the list of types. The list
3449 * passed in the argument can be freed, modified or disposed of.
3453 mono_metadata_get_canonical_generic_inst (MonoGenericInst
*candidate
)
3456 int type_argc
= candidate
->type_argc
;
3457 gboolean is_open
= candidate
->is_open
;
3460 collect_data_init (&data
);
3462 collect_ginst_images (candidate
, &data
);
3464 set
= get_image_set (data
.images
, data
.nimages
);
3466 collect_data_free (&data
);
3468 mono_image_set_lock (set
);
3470 MonoGenericInst
*ginst
= (MonoGenericInst
*)g_hash_table_lookup (set
->ginst_cache
, candidate
);
3472 int size
= MONO_SIZEOF_GENERIC_INST
+ type_argc
* sizeof (MonoType
*);
3473 ginst
= (MonoGenericInst
*)mono_image_set_alloc0 (set
, size
);
3474 #ifndef MONO_SMALL_CONFIG
3475 ginst
->id
= mono_atomic_inc_i32 (&next_generic_inst_id
);
3477 ginst
->is_open
= is_open
;
3478 ginst
->type_argc
= type_argc
;
3480 for (int i
= 0; i
< type_argc
; ++i
)
3481 ginst
->type_argv
[i
] = mono_metadata_type_dup (NULL
, candidate
->type_argv
[i
]);
3483 g_hash_table_insert (set
->ginst_cache
, ginst
, ginst
);
3486 mono_image_set_unlock (set
);
3490 MonoAggregateModContainer
*
3491 mono_metadata_get_canonical_aggregate_modifiers (MonoAggregateModContainer
*candidate
)
3493 g_assert (candidate
->count
> 0);
3494 MonoImageSet
*set
= mono_metadata_get_image_set_for_aggregate_modifiers (candidate
);
3496 mono_image_set_lock (set
);
3498 MonoAggregateModContainer
*amods
= (MonoAggregateModContainer
*)g_hash_table_lookup (set
->aggregate_modifiers_cache
, candidate
);
3500 size_t size
= mono_sizeof_aggregate_modifiers (candidate
->count
);
3501 amods
= (MonoAggregateModContainer
*)mono_image_set_alloc0 (set
, size
);
3502 amods
->count
= candidate
->count
;
3503 for (int i
= 0; i
< candidate
->count
; ++i
) {
3504 amods
->modifiers
[i
].required
= candidate
->modifiers
[i
].required
;
3505 amods
->modifiers
[i
].type
= mono_metadata_type_dup (NULL
, candidate
->modifiers
[i
].type
);
3508 g_hash_table_insert (set
->aggregate_modifiers_cache
, amods
, amods
);
3510 mono_image_set_unlock (set
);
3515 mono_metadata_is_type_builder_generic_type_definition (MonoClass
*container_class
, MonoGenericInst
*inst
, gboolean is_dynamic
)
3517 MonoGenericContainer
*container
= mono_class_get_generic_container (container_class
);
3519 if (!is_dynamic
|| m_class_was_typebuilder (container_class
) || container
->type_argc
!= inst
->type_argc
)
3521 return inst
== container
->context
.class_inst
;
3525 * mono_metadata_lookup_generic_class:
3527 * Returns a MonoGenericClass with the given properties.
3531 mono_metadata_lookup_generic_class (MonoClass
*container_class
, MonoGenericInst
*inst
, gboolean is_dynamic
)
3533 MonoGenericClass
*gclass
;
3534 MonoGenericClass helper
;
3535 gboolean is_tb_open
= mono_metadata_is_type_builder_generic_type_definition (container_class
, inst
, is_dynamic
);
3539 g_assert (mono_class_get_generic_container (container_class
)->type_argc
== inst
->type_argc
);
3541 memset (&helper
, 0, sizeof(helper
)); // act like g_new0
3542 helper
.container_class
= container_class
;
3543 helper
.context
.class_inst
= inst
;
3544 helper
.is_dynamic
= is_dynamic
; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
3545 helper
.is_tb_open
= is_tb_open
;
3547 collect_data_init (&data
);
3549 collect_gclass_images (&helper
, &data
);
3551 set
= get_image_set (data
.images
, data
.nimages
);
3553 collect_data_free (&data
);
3555 gclass
= (MonoGenericClass
*)mono_conc_hashtable_lookup (set
->gclass_cache
, &helper
);
3557 /* A tripwire just to keep us honest */
3558 g_assert (!helper
.cached_class
);
3563 gclass
= mono_image_set_new0 (set
, MonoGenericClass
, 1);
3565 gclass
->is_dynamic
= 1;
3567 gclass
->is_tb_open
= is_tb_open
;
3568 gclass
->container_class
= container_class
;
3569 gclass
->context
.class_inst
= inst
;
3570 gclass
->context
.method_inst
= NULL
;
3571 gclass
->owner
= set
;
3572 if (inst
== mono_class_get_generic_container (container_class
)->context
.class_inst
&& !is_tb_open
)
3573 gclass
->cached_class
= container_class
;
3575 mono_image_set_lock (set
);
3577 MonoGenericClass
*gclass2
= (MonoGenericClass
*)mono_conc_hashtable_insert (set
->gclass_cache
, gclass
, gclass
);
3581 // g_hash_table_insert (set->gclass_cache, gclass, gclass);
3583 mono_image_set_unlock (set
);
3589 * mono_metadata_inflate_generic_inst:
3591 * Instantiate the generic instance @ginst with the context @context.
3592 * Check @error for success.
3596 mono_metadata_inflate_generic_inst (MonoGenericInst
*ginst
, MonoGenericContext
*context
, MonoError
*error
)
3598 MonoType
**type_argv
;
3599 MonoGenericInst
*nginst
= NULL
;
3604 if (!ginst
->is_open
)
3607 type_argv
= g_new0 (MonoType
*, ginst
->type_argc
);
3609 for (i
= 0; i
< ginst
->type_argc
; i
++) {
3610 type_argv
[i
] = mono_class_inflate_generic_type_checked (ginst
->type_argv
[i
], context
, error
);
3616 nginst
= mono_metadata_get_generic_inst (ginst
->type_argc
, type_argv
);
3619 for (i
= 0; i
< count
; i
++)
3620 mono_metadata_free_type (type_argv
[i
]);
3627 mono_metadata_parse_generic_inst (MonoImage
*m
, MonoGenericContainer
*container
,
3628 int count
, const char *ptr
, const char **rptr
, MonoError
*error
)
3630 MonoType
**type_argv
;
3631 MonoGenericInst
*ginst
= NULL
;
3632 int i
, parse_count
= 0;
3635 type_argv
= g_new0 (MonoType
*, count
);
3637 for (i
= 0; i
< count
; i
++) {
3638 /* this can be a transient type, mono_metadata_get_generic_inst will allocate
3639 * a canonical one, if needed.
3641 MonoType
*t
= mono_metadata_parse_type_checked (m
, container
, 0, TRUE
, ptr
, &ptr
, error
);
3651 g_assert (parse_count
== count
);
3652 ginst
= mono_metadata_get_generic_inst (count
, type_argv
);
3655 for (i
= 0; i
< parse_count
; i
++)
3656 mono_metadata_free_type (type_argv
[i
]);
3663 do_mono_metadata_parse_generic_class (MonoType
*type
, MonoImage
*m
, MonoGenericContainer
*container
,
3664 const char *ptr
, const char **rptr
, MonoError
*error
)
3666 MonoGenericInst
*inst
;
3673 // XXX how about transient?
3674 gtype
= mono_metadata_parse_type_checked (m
, NULL
, 0, FALSE
, ptr
, &ptr
, error
);
3678 gklass
= mono_class_from_mono_type_internal (gtype
);
3679 if (!mono_class_is_gtd (gklass
)) {
3680 mono_error_set_bad_image (error
, m
, "Generic instance with non-generic definition");
3684 count
= mono_metadata_decode_value (ptr
, &ptr
);
3685 inst
= mono_metadata_parse_generic_inst (m
, container
, count
, ptr
, &ptr
, error
);
3692 type
->data
.generic_class
= mono_metadata_lookup_generic_class (gklass
, inst
, FALSE
);
3698 * @gc: The generic container to normalize
3699 * @type: The kind of generic parameters the resulting generic-container should contain
3702 static MonoGenericContainer
*
3703 select_container (MonoGenericContainer
*gc
, MonoTypeEnum type
)
3705 gboolean is_var
= (type
== MONO_TYPE_VAR
);
3709 g_assert (is_var
|| type
== MONO_TYPE_MVAR
);
3712 if (gc
->is_method
|| gc
->parent
)
3714 * The current MonoGenericContainer is a generic method -> its `parent'
3715 * points to the containing class'es container.
3723 MonoGenericContainer
*
3724 mono_get_anonymous_container_for_image (MonoImage
*image
, gboolean is_mvar
)
3726 MonoGenericContainer
**container_pointer
;
3728 container_pointer
= &image
->anonymous_generic_method_container
;
3730 container_pointer
= &image
->anonymous_generic_class_container
;
3731 MonoGenericContainer
*result
= *container_pointer
;
3733 // This container has never been created; make it now.
3736 // Note this is never deallocated anywhere-- it exists for the lifetime of the image it's allocated from
3737 result
= (MonoGenericContainer
*)mono_image_alloc0 (image
, sizeof (MonoGenericContainer
));
3738 result
->owner
.image
= image
;
3739 result
->is_anonymous
= TRUE
;
3740 result
->is_method
= is_mvar
;
3742 // If another thread already made a container, use that and leak this new one.
3743 // (Technically it would currently be safe to just assign instead of CASing.)
3744 MonoGenericContainer
*exchange
= (MonoGenericContainer
*)mono_atomic_cas_ptr ((volatile gpointer
*)container_pointer
, result
, NULL
);
3751 #define FAST_GPARAM_CACHE_SIZE 16
3753 static MonoGenericParam
*
3754 lookup_anon_gparam (MonoImage
*image
, MonoGenericContainer
*container
, gint32 param_num
, gboolean is_mvar
)
3756 if (param_num
>= 0 && param_num
< FAST_GPARAM_CACHE_SIZE
) {
3757 MonoGenericParam
*cache
= is_mvar
? image
->mvar_gparam_cache_fast
: image
->var_gparam_cache_fast
;
3760 return &cache
[param_num
];
3762 MonoGenericParam key
;
3763 memset (&key
, 0, sizeof (key
));
3764 key
.owner
= container
;
3765 key
.num
= param_num
;
3766 key
.gshared_constraint
= NULL
;
3767 MonoConcurrentHashTable
*cache
= is_mvar
? image
->mvar_gparam_cache
: image
->var_gparam_cache
;
3770 return (MonoGenericParam
*)mono_conc_hashtable_lookup (cache
, &key
);
3774 static MonoGenericParam
*
3775 publish_anon_gparam_fast (MonoImage
*image
, MonoGenericContainer
*container
, gint32 param_num
)
3777 g_assert (param_num
>= 0 && param_num
< FAST_GPARAM_CACHE_SIZE
);
3778 MonoGenericParam
**cache
= container
->is_method
? &image
->mvar_gparam_cache_fast
: &image
->var_gparam_cache_fast
;
3780 mono_image_lock (image
);
3782 *cache
= (MonoGenericParam
*)mono_image_alloc0 (image
, sizeof (MonoGenericParam
) * FAST_GPARAM_CACHE_SIZE
);
3783 for (gint32 i
= 0; i
< FAST_GPARAM_CACHE_SIZE
; ++i
) {
3784 MonoGenericParam
*param
= &(*cache
)[i
];
3785 param
->owner
= container
;
3789 mono_image_unlock (image
);
3791 return &(*cache
)[param_num
];
3795 * publish_anon_gparam_slow:
3797 * Publish \p gparam anonymous generic parameter to the anon gparam cache for \p image.
3799 * LOCKING: takes the image lock.
3801 static MonoGenericParam
*
3802 publish_anon_gparam_slow (MonoImage
*image
, MonoGenericParam
*gparam
)
3804 MonoConcurrentHashTable
**cache
= gparam
->owner
->is_method
? &image
->mvar_gparam_cache
: &image
->var_gparam_cache
;
3806 mono_image_lock (image
);
3808 MonoConcurrentHashTable
*ht
= mono_conc_hashtable_new ((GHashFunc
)mono_metadata_generic_param_hash
,
3809 (GEqualFunc
) mono_metadata_generic_param_equal
);
3810 mono_atomic_store_release (cache
, ht
);
3812 mono_image_unlock (image
);
3814 MonoGenericParam
*other
= (MonoGenericParam
*)mono_conc_hashtable_insert (*cache
, gparam
, gparam
);
3815 // If another thread published first return their param, otherwise return ours.
3816 return other
? other
: gparam
;
3820 * mono_metadata_create_anon_gparam:
3821 * \param image the MonoImage that owns the anonymous generic parameter
3822 * \param param_num the parameter number
3823 * \param is_mvar TRUE if this is a method generic parameter, FALSE if it's a class generic parameter.
3825 * Returns: a new, or exisisting \c MonoGenericParam for an anonymous generic parameter with the given properties.
3827 * LOCKING: takes the image lock.
3830 mono_metadata_create_anon_gparam (MonoImage
*image
, gint32 param_num
, gboolean is_mvar
)
3832 MonoGenericContainer
*container
= mono_get_anonymous_container_for_image (image
, is_mvar
);
3833 MonoGenericParam
*gparam
= lookup_anon_gparam (image
, container
, param_num
, is_mvar
);
3836 if (param_num
>= 0 && param_num
< FAST_GPARAM_CACHE_SIZE
) {
3837 return publish_anon_gparam_fast (image
, container
, param_num
);
3839 // Create a candidate generic param and try to insert it in the cache.
3840 // If multiple threads both try to publish the same param, all but one
3841 // will leak, but that's okay.
3842 gparam
= (MonoGenericParam
*)mono_image_alloc0 (image
, sizeof (MonoGenericParam
));
3843 gparam
->owner
= container
;
3844 gparam
->num
= param_num
;
3846 return publish_anon_gparam_slow (image
, gparam
);
3851 * mono_metadata_parse_generic_param:
3852 * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
3853 * see mono_metadata_parse_type_checked() for details.
3854 * Internal routine to parse a generic type parameter.
3855 * LOCKING: Acquires the loader lock
3857 static MonoGenericParam
*
3858 mono_metadata_parse_generic_param (MonoImage
*m
, MonoGenericContainer
*generic_container
,
3859 MonoTypeEnum type
, const char *ptr
, const char **rptr
, MonoError
*error
)
3861 int index
= mono_metadata_decode_value (ptr
, &ptr
);
3867 generic_container
= select_container (generic_container
, type
);
3868 if (!generic_container
) {
3869 gboolean is_mvar
= FALSE
;
3874 case MONO_TYPE_MVAR
:
3878 g_error ("Cerating generic param object with invalid MonoType"); // This is not a generic param
3881 return mono_metadata_create_anon_gparam (m
, index
, is_mvar
);
3884 if (index
>= generic_container
->type_argc
) {
3885 mono_error_set_bad_image (error
, m
, "Invalid generic %s parameter index %d, max index is %d",
3886 generic_container
->is_method
? "method" : "type",
3887 index
, generic_container
->type_argc
);
3891 //This can't return NULL
3892 return mono_generic_container_get_param (generic_container
, index
);
3896 * mono_metadata_get_shared_type:
3898 * Return a shared instance of TYPE, if available, NULL otherwise.
3899 * Shared MonoType instances help save memory. Their contents should not be modified
3900 * by the caller. They do not need to be freed as their lifetime is bound by either
3901 * the lifetime of the runtime (builtin types), or the lifetime of the MonoClass
3902 * instance they are embedded in. If they are freed, they should be freed using
3903 * mono_metadata_free_type () instead of g_free ().
3906 mono_metadata_get_shared_type (MonoType
*type
)
3910 /* No need to use locking since nobody is modifying the hash table */
3911 if ((cached
= (MonoType
*)g_hash_table_lookup (type_cache
, type
)))
3914 switch (type
->type
){
3915 case MONO_TYPE_CLASS
:
3916 case MONO_TYPE_VALUETYPE
:
3917 if (type
== m_class_get_byval_arg (type
->data
.klass
))
3919 if (type
== m_class_get_this_arg (type
->data
.klass
))
3930 compare_type_literals (MonoImage
*image
, int class_type
, int type_type
, MonoError
*error
)
3934 /* _byval_arg.type can be zero if we're decoding a type that references a class been loading.
3935 * See mcs/test/gtest-440. and #650936.
3936 * FIXME This better be moved to the metadata verifier as it can catch more cases.
3940 /* NET 1.1 assemblies might encode string and object in a denormalized way.
3943 if (class_type
== type_type
)
3946 if (type_type
== MONO_TYPE_CLASS
) {
3947 if (class_type
== MONO_TYPE_STRING
|| class_type
== MONO_TYPE_OBJECT
)
3949 //XXX stringify this argument
3950 mono_error_set_bad_image (error
, image
, "Expected reference type but got type kind %d", class_type
);
3954 g_assert (type_type
== MONO_TYPE_VALUETYPE
);
3955 switch (class_type
) {
3956 case MONO_TYPE_BOOLEAN
:
3957 case MONO_TYPE_CHAR
:
3970 case MONO_TYPE_CLASS
:
3973 //XXX stringify this argument
3974 mono_error_set_bad_image (error
, image
, "Expected value type but got type kind %d", class_type
);
3980 verify_var_type_and_container (MonoImage
*image
, int var_type
, MonoGenericContainer
*container
, MonoError
*error
)
3983 if (var_type
== MONO_TYPE_MVAR
) {
3984 if (!container
->is_method
) { //MVAR and a method container
3985 mono_error_set_bad_image (error
, image
, "MVAR parsed in a context without a method container");
3989 if (!(!container
->is_method
|| //VAR and class container
3990 (container
->is_method
&& container
->parent
))) { //VAR and method container with parent
3991 mono_error_set_bad_image (error
, image
, "VAR parsed in a context without a class container");
3999 * do_mono_metadata_parse_type:
4000 * @type: MonoType to be filled in with the return value
4002 * @generic_context: generics_context
4003 * @transient: whenever to allocate data from the heap
4004 * @ptr: pointer to the encoded type
4005 * @rptr: pointer where the end of the encoded type is saved
4007 * Internal routine used to "fill" the contents of @type from an
4008 * allocated pointer. This is done this way to avoid doing too
4009 * many mini-allocations (particularly for the MonoFieldType which
4010 * most of the time is just a MonoType, but sometimes might be augmented).
4012 * This routine is used by mono_metadata_parse_type and
4013 * mono_metadata_parse_field_type
4015 * This extracts a Type as specified in Partition II (22.2.12)
4017 * Returns: FALSE if the type could not be loaded
4020 do_mono_metadata_parse_type (MonoType
*type
, MonoImage
*m
, MonoGenericContainer
*container
,
4021 gboolean transient
, const char *ptr
, const char **rptr
, MonoError
*error
)
4025 type
->type
= (MonoTypeEnum
)mono_metadata_decode_value (ptr
, &ptr
);
4027 switch (type
->type
){
4028 case MONO_TYPE_VOID
:
4029 case MONO_TYPE_BOOLEAN
:
4030 case MONO_TYPE_CHAR
:
4043 case MONO_TYPE_STRING
:
4044 case MONO_TYPE_OBJECT
:
4045 case MONO_TYPE_TYPEDBYREF
:
4047 case MONO_TYPE_VALUETYPE
:
4048 case MONO_TYPE_CLASS
: {
4051 token
= mono_metadata_parse_typedef_or_ref (m
, ptr
, &ptr
);
4052 klass
= mono_class_get_checked (m
, token
, error
);
4053 type
->data
.klass
= klass
;
4057 if (!compare_type_literals (m
, m_class_get_byval_arg (klass
)->type
, type
->type
, error
))
4062 case MONO_TYPE_SZARRAY
: {
4063 MonoType
*etype
= mono_metadata_parse_type_checked (m
, container
, 0, transient
, ptr
, &ptr
, error
);
4067 type
->data
.klass
= mono_class_from_mono_type_internal (etype
);
4070 mono_metadata_free_type (etype
);
4072 g_assert (type
->data
.klass
); //This was previously a check for NULL, but mcfmt should never fail. It can return a borken MonoClass, but should return at least something.
4075 case MONO_TYPE_PTR
: {
4076 type
->data
.type
= mono_metadata_parse_type_checked (m
, container
, 0, transient
, ptr
, &ptr
, error
);
4077 if (!type
->data
.type
)
4081 case MONO_TYPE_FNPTR
: {
4082 type
->data
.method
= mono_metadata_parse_method_signature_full (m
, container
, 0, ptr
, &ptr
, error
);
4083 if (!type
->data
.method
)
4087 case MONO_TYPE_ARRAY
: {
4088 type
->data
.array
= mono_metadata_parse_array_internal (m
, container
, transient
, ptr
, &ptr
, error
);
4089 if (!type
->data
.array
)
4093 case MONO_TYPE_MVAR
:
4094 case MONO_TYPE_VAR
: {
4095 if (container
&& !verify_var_type_and_container (m
, type
->type
, container
, error
))
4098 type
->data
.generic_param
= mono_metadata_parse_generic_param (m
, container
, type
->type
, ptr
, &ptr
, error
);
4099 if (!type
->data
.generic_param
)
4104 case MONO_TYPE_GENERICINST
: {
4105 if (!do_mono_metadata_parse_generic_class (type
, m
, container
, ptr
, &ptr
, error
))
4110 mono_error_set_bad_image (error
, m
, "type 0x%02x not handled in do_mono_metadata_parse_type on image %s", type
->type
, m
->name
);
4120 * mono_metadata_free_type:
4121 * \param type type to free
4123 * Free the memory allocated for type \p type which is allocated on the heap.
4126 mono_metadata_free_type (MonoType
*type
)
4128 if (type
>= builtin_types
&& type
< builtin_types
+ NBUILTIN_TYPES ())
4131 switch (type
->type
){
4132 case MONO_TYPE_OBJECT
:
4133 case MONO_TYPE_STRING
:
4134 if (!type
->data
.klass
)
4137 case MONO_TYPE_CLASS
:
4138 case MONO_TYPE_VALUETYPE
:
4139 if (type
== m_class_get_byval_arg (type
->data
.klass
) || type
== m_class_get_this_arg (type
->data
.klass
))
4143 mono_metadata_free_type (type
->data
.type
);
4145 case MONO_TYPE_FNPTR
:
4146 mono_metadata_free_method_signature (type
->data
.method
);
4148 case MONO_TYPE_ARRAY
:
4149 mono_metadata_free_array (type
->data
.array
);
4160 hex_dump (const char *buffer
, int base
, int count
)
4162 int show_header
= 1;
4170 for (i
= 0; i
< count
; i
++){
4173 printf ("\n0x%08x: ", (unsigned char) base
+ i
);
4175 printf ("%02x ", (unsigned char) (buffer
[i
]));
4182 * @ptr: Points to the beginning of the Section Data (25.3)
4184 static MonoExceptionClause
*
4185 parse_section_data (MonoImage
*m
, int *num_clauses
, const unsigned char *ptr
, MonoError
*error
)
4187 unsigned char sect_data_flags
;
4189 guint32 sect_data_len
;
4190 MonoExceptionClause
* clauses
= NULL
;
4195 /* align on 32-bit boundary */
4196 ptr
= dword_align (ptr
);
4197 sect_data_flags
= *ptr
;
4200 is_fat
= sect_data_flags
& METHOD_HEADER_SECTION_FAT_FORMAT
;
4202 sect_data_len
= (ptr
[2] << 16) | (ptr
[1] << 8) | ptr
[0];
4205 sect_data_len
= ptr
[0];
4209 if (sect_data_flags
& METHOD_HEADER_SECTION_EHTABLE
) {
4210 const unsigned char *p
= dword_align (ptr
);
4212 *num_clauses
= is_fat
? sect_data_len
/ 24: sect_data_len
/ 12;
4213 /* we could just store a pointer if we don't need to byteswap */
4214 clauses
= (MonoExceptionClause
*)g_malloc0 (sizeof (MonoExceptionClause
) * (*num_clauses
));
4215 for (i
= 0; i
< *num_clauses
; ++i
) {
4216 MonoExceptionClause
*ec
= &clauses
[i
];
4219 ec
->flags
= read32 (p
);
4220 ec
->try_offset
= read32 (p
+ 4);
4221 ec
->try_len
= read32 (p
+ 8);
4222 ec
->handler_offset
= read32 (p
+ 12);
4223 ec
->handler_len
= read32 (p
+ 16);
4224 tof_value
= read32 (p
+ 20);
4227 ec
->flags
= read16 (p
);
4228 ec
->try_offset
= read16 (p
+ 2);
4229 ec
->try_len
= *(p
+ 4);
4230 ec
->handler_offset
= read16 (p
+ 5);
4231 ec
->handler_len
= *(p
+ 7);
4232 tof_value
= read32 (p
+ 8);
4235 if (ec
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
4236 ec
->data
.filter_offset
= tof_value
;
4237 } else if (ec
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) {
4238 ec
->data
.catch_class
= NULL
;
4240 ec
->data
.catch_class
= mono_class_get_checked (m
, tof_value
, error
);
4241 if (!is_ok (error
)) {
4247 ec
->data
.catch_class
= NULL
;
4249 /* g_print ("try %d: %x %04x-%04x %04x\n", i, ec->flags, ec->try_offset, ec->try_offset+ec->try_len, ec->try_len); */
4253 if (sect_data_flags
& METHOD_HEADER_SECTION_MORE_SECTS
)
4254 ptr
+= sect_data_len
- 4; /* LAMESPEC: it seems the size includes the header */
4261 * mono_method_get_header_summary:
4262 * @method: The method to get the header.
4263 * @summary: Where to store the header
4266 * Returns: TRUE if the header was properly decoded.
4269 mono_method_get_header_summary (MonoMethod
*method
, MonoMethodHeaderSummary
*summary
)
4275 unsigned char flags
, format
;
4279 /*Only the GMD has a pointer to the metadata.*/
4280 while (method
->is_inflated
)
4281 method
= ((MonoMethodInflated
*)method
)->declaring
;
4283 summary
->code
= NULL
;
4284 summary
->code_size
= 0;
4285 summary
->max_stack
= 0;
4286 summary
->has_clauses
= FALSE
;
4287 summary
->has_locals
= FALSE
;
4289 /*FIXME extract this into a MACRO and share it with mono_method_get_header*/
4290 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) || (method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) || (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) || (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
))
4293 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
|| method
->sre_method
) {
4294 MonoMethodHeader
*header
= ((MonoMethodWrapper
*)method
)->header
;
4297 summary
->code
= header
->code
;
4298 summary
->code_size
= header
->code_size
;
4299 summary
->max_stack
= header
->max_stack
;
4300 summary
->has_clauses
= header
->num_clauses
> 0;
4301 summary
->has_locals
= header
->num_locals
> 0;
4306 idx
= mono_metadata_token_index (method
->token
);
4307 img
= m_class_get_image (method
->klass
);
4308 rva
= mono_metadata_decode_row_col (&img
->tables
[MONO_TABLE_METHOD
], idx
- 1, MONO_METHOD_RVA
);
4310 /*We must run the verifier since we'll be decoding it.*/
4311 if (!mono_verifier_verify_method_header (img
, rva
, error
)) {
4312 mono_error_cleanup (error
);
4316 ptr
= mono_image_rva_map (img
, rva
);
4320 flags
= *(const unsigned char *)ptr
;
4321 format
= flags
& METHOD_HEADER_FORMAT_MASK
;
4324 case METHOD_HEADER_TINY_FORMAT
:
4326 summary
->max_stack
= 8;
4327 summary
->code
= (unsigned char *) ptr
;
4328 summary
->code_size
= flags
>> 2;
4330 case METHOD_HEADER_FAT_FORMAT
:
4331 fat_flags
= read16 (ptr
);
4333 summary
->max_stack
= read16 (ptr
);
4335 summary
->code_size
= read32 (ptr
);
4337 summary
->has_locals
= !!read32 (ptr
);
4339 if (fat_flags
& METHOD_HEADER_MORE_SECTS
)
4340 summary
->has_clauses
= TRUE
;
4341 summary
->code
= (unsigned char *) ptr
;
4350 * mono_metadata_parse_mh_full:
4351 * @m: metadata context
4352 * @generic_context: generics context
4353 * @ptr: pointer to the method header.
4355 * Decode the method header at @ptr, including pointer to the IL code,
4356 * info about local variables and optional exception tables.
4357 * This is a Mono runtime internal function.
4359 * LOCKING: Acquires the loader lock.
4361 * Returns: a transient MonoMethodHeader allocated from the heap.
4364 mono_metadata_parse_mh_full (MonoImage
*m
, MonoGenericContainer
*container
, const char *ptr
, MonoError
*error
)
4366 MonoMethodHeader
*mh
= NULL
;
4367 unsigned char flags
= *(const unsigned char *) ptr
;
4368 unsigned char format
= flags
& METHOD_HEADER_FORMAT_MASK
;
4370 guint32 local_var_sig_tok
, max_stack
, code_size
, init_locals
;
4371 const unsigned char *code
;
4372 MonoExceptionClause
* clauses
= NULL
;
4373 int num_clauses
= 0;
4374 MonoTableInfo
*t
= &m
->tables
[MONO_TABLE_STANDALONESIG
];
4375 guint32 cols
[MONO_STAND_ALONE_SIGNATURE_SIZE
];
4380 mono_error_set_bad_image (error
, m
, "Method header with null pointer");
4385 case METHOD_HEADER_TINY_FORMAT
:
4386 mh
= (MonoMethodHeader
*)g_malloc0 (MONO_SIZEOF_METHOD_HEADER
);
4389 mh
->is_transient
= TRUE
;
4390 local_var_sig_tok
= 0;
4391 mh
->code_size
= flags
>> 2;
4392 mh
->code
= (unsigned char*)ptr
;
4394 case METHOD_HEADER_FAT_FORMAT
:
4395 fat_flags
= read16 (ptr
);
4397 max_stack
= read16 (ptr
);
4399 code_size
= read32 (ptr
);
4401 local_var_sig_tok
= read32 (ptr
);
4404 if (fat_flags
& METHOD_HEADER_INIT_LOCALS
)
4409 code
= (unsigned char*)ptr
;
4411 if (!(fat_flags
& METHOD_HEADER_MORE_SECTS
))
4415 * There are more sections
4417 ptr
= (char*)code
+ code_size
;
4420 mono_error_set_bad_image (error
, m
, "Invalid method header format %d", format
);
4424 if (local_var_sig_tok
) {
4425 int idx
= (local_var_sig_tok
& 0xffffff)-1;
4426 if (idx
>= t
->rows
|| idx
< 0) {
4427 mono_error_set_bad_image (error
, m
, "Invalid method header local vars signature token 0x%8x", idx
);
4430 mono_metadata_decode_row (t
, idx
, cols
, 1);
4432 if (!mono_verifier_verify_standalone_signature (m
, cols
[MONO_STAND_ALONE_SIGNATURE
], error
))
4435 if (fat_flags
& METHOD_HEADER_MORE_SECTS
) {
4436 clauses
= parse_section_data (m
, &num_clauses
, (const unsigned char*)ptr
, error
);
4437 goto_if_nok (error
, fail
);
4439 if (local_var_sig_tok
) {
4440 const char *locals_ptr
;
4443 locals_ptr
= mono_metadata_blob_heap (m
, cols
[MONO_STAND_ALONE_SIGNATURE
]);
4444 mono_metadata_decode_blob_size (locals_ptr
, &locals_ptr
);
4445 if (*locals_ptr
!= 0x07)
4446 g_warning ("wrong signature for locals blob");
4448 len
= mono_metadata_decode_value (locals_ptr
, &locals_ptr
);
4449 mh
= (MonoMethodHeader
*)g_malloc0 (MONO_SIZEOF_METHOD_HEADER
+ len
* sizeof (MonoType
*) + num_clauses
* sizeof (MonoExceptionClause
));
4450 mh
->num_locals
= len
;
4451 for (i
= 0; i
< len
; ++i
) {
4452 mh
->locals
[i
] = mono_metadata_parse_type_internal (m
, container
, 0, TRUE
, locals_ptr
, &locals_ptr
, error
);
4453 goto_if_nok (error
, fail
);
4456 mh
= (MonoMethodHeader
*)g_malloc0 (MONO_SIZEOF_METHOD_HEADER
+ num_clauses
* sizeof (MonoExceptionClause
));
4459 mh
->code_size
= code_size
;
4460 mh
->max_stack
= max_stack
;
4461 mh
->is_transient
= TRUE
;
4462 mh
->init_locals
= init_locals
;
4464 MonoExceptionClause
* clausesp
= (MonoExceptionClause
*)&mh
->locals
[mh
->num_locals
];
4465 memcpy (clausesp
, clauses
, num_clauses
* sizeof (MonoExceptionClause
));
4467 mh
->clauses
= clausesp
;
4468 mh
->num_clauses
= num_clauses
;
4479 * mono_metadata_parse_mh:
4480 * \param generic_context generics context
4481 * \param ptr pointer to the method header.
4483 * Decode the method header at \p ptr, including pointer to the IL code,
4484 * info about local variables and optional exception tables.
4486 * \returns a transient \c MonoMethodHeader allocated from the heap.
4489 mono_metadata_parse_mh (MonoImage
*m
, const char *ptr
)
4492 MonoMethodHeader
*header
= mono_metadata_parse_mh_full (m
, NULL
, ptr
, error
);
4493 mono_error_cleanup (error
);
4498 * mono_metadata_free_mh:
4499 * \param mh a method header
4501 * Free the memory allocated for the method header.
4504 mono_metadata_free_mh (MonoMethodHeader
*mh
)
4508 /* If it is not transient it means it's part of a wrapper method,
4509 * or a SRE-generated method, so the lifetime in that case is
4510 * dictated by the method's own lifetime
4512 if (mh
&& mh
->is_transient
) {
4513 for (i
= 0; i
< mh
->num_locals
; ++i
)
4514 mono_metadata_free_type (mh
->locals
[i
]);
4520 * mono_method_header_get_code:
4521 * \param header a \c MonoMethodHeader pointer
4522 * \param code_size memory location for returning the code size
4523 * \param max_stack memory location for returning the max stack
4525 * Method header accessor to retreive info about the IL code properties:
4526 * a pointer to the IL code itself, the size of the code and the max number
4527 * of stack slots used by the code.
4529 * \returns pointer to the IL code represented by the method header.
4531 const unsigned char*
4532 mono_method_header_get_code (MonoMethodHeader
*header
, guint32
* code_size
, guint32
* max_stack
)
4535 *code_size
= header
->code_size
;
4537 *max_stack
= header
->max_stack
;
4538 return header
->code
;
4542 * mono_method_header_get_locals:
4543 * \param header a \c MonoMethodHeader pointer
4544 * \param num_locals memory location for returning the number of local variables
4545 * \param init_locals memory location for returning the init_locals flag
4547 * Method header accessor to retreive info about the local variables:
4548 * an array of local types, the number of locals and whether the locals
4549 * are supposed to be initialized to 0 on method entry
4551 * \returns pointer to an array of types of the local variables
4554 mono_method_header_get_locals (MonoMethodHeader
*header
, guint32
* num_locals
, gboolean
*init_locals
)
4557 *num_locals
= header
->num_locals
;
4559 *init_locals
= header
->init_locals
;
4560 return header
->locals
;
4564 * mono_method_header_get_num_clauses:
4565 * @header: a MonoMethodHeader pointer
4567 * Method header accessor to retreive the number of exception clauses.
4569 * Returns: the number of exception clauses present
4572 mono_method_header_get_num_clauses (MonoMethodHeader
*header
)
4574 return header
->num_clauses
;
4578 * mono_method_header_get_clauses:
4579 * \param header a \c MonoMethodHeader pointer
4580 * \param method \c MonoMethod the header belongs to
4581 * \param iter pointer to a iterator
4582 * \param clause pointer to a \c MonoExceptionClause structure which will be filled with the info
4584 * Get the info about the exception clauses in the method. Set \c *iter to NULL to
4585 * initiate the iteration, then call the method repeatedly until it returns FALSE.
4586 * At each iteration, the structure pointed to by clause if filled with the
4587 * exception clause information.
4589 * \returns TRUE if clause was filled with info, FALSE if there are no more exception
4593 mono_method_header_get_clauses (MonoMethodHeader
*header
, MonoMethod
*method
, gpointer
*iter
, MonoExceptionClause
*clause
)
4595 MonoExceptionClause
*sc
;
4596 /* later we'll be able to use this interface to parse the clause info on demand,
4597 * without allocating anything.
4599 if (!iter
|| !header
->num_clauses
)
4602 *iter
= sc
= header
->clauses
;
4606 sc
= (MonoExceptionClause
*)*iter
;
4608 if (sc
< header
->clauses
+ header
->num_clauses
) {
4617 * mono_metadata_parse_field_type:
4618 * \param m metadata context to extract information from
4619 * \param ptr pointer to the field signature
4620 * \param rptr pointer updated to match the end of the decoded stream
4622 * Parses the field signature, and returns the type information for it.
4624 * \returns The \c MonoType that was extracted from \p ptr .
4627 mono_metadata_parse_field_type (MonoImage
*m
, short field_flags
, const char *ptr
, const char **rptr
)
4630 MonoType
* type
= mono_metadata_parse_type_internal (m
, NULL
, field_flags
, FALSE
, ptr
, rptr
, error
);
4631 mono_error_cleanup (error
);
4636 * mono_metadata_parse_param:
4637 * \param m metadata context to extract information from
4638 * \param ptr pointer to the param signature
4639 * \param rptr pointer updated to match the end of the decoded stream
4641 * Parses the param signature, and returns the type information for it.
4643 * \returns The \c MonoType that was extracted from \p ptr .
4646 mono_metadata_parse_param (MonoImage
*m
, const char *ptr
, const char **rptr
)
4649 MonoType
* type
= mono_metadata_parse_type_internal (m
, NULL
, 0, FALSE
, ptr
, rptr
, error
);
4650 mono_error_cleanup (error
);
4655 * mono_metadata_token_from_dor:
4656 * \param dor_token A \c TypeDefOrRef coded index
4658 * \p dor_token is a \c TypeDefOrRef coded index: it contains either
4659 * a \c TypeDef, \c TypeRef or \c TypeSpec in the lower bits, and the upper
4660 * bits contain an index into the table.
4662 * \returns an expanded token
4665 mono_metadata_token_from_dor (guint32 dor_index
)
4669 table
= dor_index
& 0x03;
4670 idx
= dor_index
>> 2;
4673 case 0: /* TypeDef */
4674 return MONO_TOKEN_TYPE_DEF
| idx
;
4675 case 1: /* TypeRef */
4676 return MONO_TOKEN_TYPE_REF
| idx
;
4677 case 2: /* TypeSpec */
4678 return MONO_TOKEN_TYPE_SPEC
| idx
;
4680 g_assert_not_reached ();
4687 * We use this to pass context information to the row locator
4690 int idx
; /* The index that we are trying to locate */
4691 int col_idx
; /* The index in the row where idx may be stored */
4692 MonoTableInfo
*t
; /* pointer to the table */
4697 * How the row locator works.
4702 * ___|___------> _______
4705 * A column in the rows of table A references an index in table B.
4706 * For example A may be the TYPEDEF table and B the METHODDEF table.
4708 * Given an index in table B we want to get the row in table A
4709 * where the column n references our index in B.
4711 * In the locator_t structure:
4713 * col_idx is the column number
4714 * index is the index in table B
4715 * result will be the index in table A
4718 * Table A Table B column (in table A)
4719 * TYPEDEF METHODDEF MONO_TYPEDEF_METHOD_LIST
4720 * TYPEDEF FIELD MONO_TYPEDEF_FIELD_LIST
4721 * PROPERTYMAP PROPERTY MONO_PROPERTY_MAP_PROPERTY_LIST
4722 * INTERFIMPL TYPEDEF MONO_INTERFACEIMPL_CLASS
4723 * METHODSEM PROPERTY ASSOCIATION (encoded index)
4725 * Note that we still don't support encoded indexes.
4729 typedef_locator (const void *a
, const void *b
)
4731 locator_t
*loc
= (locator_t
*) a
;
4732 const char *bb
= (const char *) b
;
4733 int typedef_index
= (bb
- loc
->t
->base
) / loc
->t
->row_size
;
4734 guint32 col
, col_next
;
4736 col
= mono_metadata_decode_row_col (loc
->t
, typedef_index
, loc
->col_idx
);
4742 * Need to check that the next row is valid.
4744 if (typedef_index
+ 1 < loc
->t
->rows
) {
4745 col_next
= mono_metadata_decode_row_col (loc
->t
, typedef_index
+ 1, loc
->col_idx
);
4746 if (loc
->idx
>= col_next
)
4749 if (col
== col_next
)
4753 loc
->result
= typedef_index
;
4759 table_locator (const void *a
, const void *b
)
4761 locator_t
*loc
= (locator_t
*) a
;
4762 const char *bb
= (const char *) b
;
4763 guint32 table_index
= (bb
- loc
->t
->base
) / loc
->t
->row_size
;
4766 col
= mono_metadata_decode_row_col (loc
->t
, table_index
, loc
->col_idx
);
4768 if (loc
->idx
== col
) {
4769 loc
->result
= table_index
;
4779 declsec_locator (const void *a
, const void *b
)
4781 locator_t
*loc
= (locator_t
*) a
;
4782 const char *bb
= (const char *) b
;
4783 guint32 table_index
= (bb
- loc
->t
->base
) / loc
->t
->row_size
;
4786 col
= mono_metadata_decode_row_col (loc
->t
, table_index
, loc
->col_idx
);
4788 if (loc
->idx
== col
) {
4789 loc
->result
= table_index
;
4801 * Return the 1-based row index in TABLE, which must be one of the *Ptr tables,
4802 * which contains IDX.
4805 search_ptr_table (MonoImage
*image
, int table
, int idx
)
4807 MonoTableInfo
*ptrdef
= &image
->tables
[table
];
4810 /* Use a linear search to find our index in the table */
4811 for (i
= 0; i
< ptrdef
->rows
; i
++)
4812 /* All the Ptr tables have the same structure */
4813 if (mono_metadata_decode_row_col (ptrdef
, i
, 0) == idx
)
4816 if (i
< ptrdef
->rows
)
4823 * mono_metadata_typedef_from_field:
4824 * \param meta metadata context
4825 * \param index FieldDef token
4827 * \returns the 1-based index into the \c TypeDef table of the type that
4828 * declared the field described by \p index, or 0 if not found.
4831 mono_metadata_typedef_from_field (MonoImage
*meta
, guint32 index
)
4833 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_TYPEDEF
];
4839 loc
.idx
= mono_metadata_token_index (index
);
4840 loc
.col_idx
= MONO_TYPEDEF_FIELD_LIST
;
4843 if (meta
->uncompressed_metadata
)
4844 loc
.idx
= search_ptr_table (meta
, MONO_TABLE_FIELD_POINTER
, loc
.idx
);
4846 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, typedef_locator
))
4849 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4850 return loc
.result
+ 1;
4854 * mono_metadata_typedef_from_method:
4855 * \param meta metadata context
4856 * \param index \c MethodDef token
4857 * \returns the 1-based index into the \c TypeDef table of the type that
4858 * declared the method described by \p index. 0 if not found.
4861 mono_metadata_typedef_from_method (MonoImage
*meta
, guint32 index
)
4863 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_TYPEDEF
];
4869 loc
.idx
= mono_metadata_token_index (index
);
4870 loc
.col_idx
= MONO_TYPEDEF_METHOD_LIST
;
4873 if (meta
->uncompressed_metadata
)
4874 loc
.idx
= search_ptr_table (meta
, MONO_TABLE_METHOD_POINTER
, loc
.idx
);
4876 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, typedef_locator
))
4879 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4880 return loc
.result
+ 1;
4884 * mono_metadata_interfaces_from_typedef_full:
4885 * \param meta metadata context
4886 * \param index typedef token
4887 * \param interfaces Out parameter used to store the interface array
4888 * \param count Out parameter used to store the number of interfaces
4889 * \param heap_alloc_result if TRUE the result array will be \c g_malloc'd
4890 * \param context The generic context
4891 * \param error set on error
4893 * The array of interfaces that the \p index typedef token implements is returned in
4894 * \p interfaces. The number of elements in the array is returned in \p count.
4896 * \returns \c TRUE on success, \c FALSE on failure and sets \p error.
4899 mono_metadata_interfaces_from_typedef_full (MonoImage
*meta
, guint32 index
, MonoClass
***interfaces
, guint
*count
, gboolean heap_alloc_result
, MonoGenericContext
*context
, MonoError
*error
)
4901 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_INTERFACEIMPL
];
4904 guint32 cols
[MONO_INTERFACEIMPL_SIZE
];
4915 loc
.idx
= mono_metadata_token_index (index
);
4916 loc
.col_idx
= MONO_INTERFACEIMPL_CLASS
;
4919 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
4924 * We may end up in the middle of the rows...
4927 if (loc
.idx
== mono_metadata_decode_row_col (tdef
, start
- 1, MONO_INTERFACEIMPL_CLASS
))
4933 while (pos
< tdef
->rows
) {
4934 mono_metadata_decode_row (tdef
, pos
, cols
, MONO_INTERFACEIMPL_SIZE
);
4935 if (cols
[MONO_INTERFACEIMPL_CLASS
] != loc
.idx
)
4940 if (heap_alloc_result
)
4941 result
= g_new0 (MonoClass
*, pos
- start
);
4943 result
= (MonoClass
**)mono_image_alloc0 (meta
, sizeof (MonoClass
*) * (pos
- start
));
4946 while (pos
< tdef
->rows
) {
4949 mono_metadata_decode_row (tdef
, pos
, cols
, MONO_INTERFACEIMPL_SIZE
);
4950 if (cols
[MONO_INTERFACEIMPL_CLASS
] != loc
.idx
)
4952 iface
= mono_class_get_and_inflate_typespec_checked (
4953 meta
, mono_metadata_token_from_dor (cols
[MONO_INTERFACEIMPL_INTERFACE
]), context
, error
);
4956 result
[pos
- start
] = iface
;
4959 *count
= pos
- start
;
4960 *interfaces
= result
;
4965 * mono_metadata_interfaces_from_typedef:
4966 * \param meta metadata context
4967 * \param index typedef token
4968 * \param count Out parameter used to store the number of interfaces
4970 * The array of interfaces that the \p index typedef token implements is returned in
4971 * \p interfaces. The number of elements in the array is returned in \p count. The returned
4972 * array is allocated with \c g_malloc and the caller must free it.
4974 * LOCKING: Acquires the loader lock .
4976 * \returns the interface array on success, NULL on failure.
4979 mono_metadata_interfaces_from_typedef (MonoImage
*meta
, guint32 index
, guint
*count
)
4982 MonoClass
**interfaces
= NULL
;
4985 rv
= mono_metadata_interfaces_from_typedef_full (meta
, index
, &interfaces
, count
, TRUE
, NULL
, error
);
4986 mono_error_assert_ok (error
);
4994 * mono_metadata_nested_in_typedef:
4995 * \param meta metadata context
4996 * \param index typedef token
4997 * \returns the 1-based index into the TypeDef table of the type
4998 * where the type described by \p index is nested.
4999 * Returns 0 if \p index describes a non-nested type.
5002 mono_metadata_nested_in_typedef (MonoImage
*meta
, guint32 index
)
5004 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_NESTEDCLASS
];
5010 loc
.idx
= mono_metadata_token_index (index
);
5011 loc
.col_idx
= MONO_NESTED_CLASS_NESTED
;
5014 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
5017 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5018 return mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_NESTED_CLASS_ENCLOSING
) | MONO_TOKEN_TYPE_DEF
;
5022 * mono_metadata_nesting_typedef:
5023 * \param meta metadata context
5024 * \param index typedef token
5025 * \returns the 1-based index into the \c TypeDef table of the first type
5026 * that is nested inside the type described by \p index. The search starts at
5027 * \p start_index. Returns 0 if no such type is found.
5030 mono_metadata_nesting_typedef (MonoImage
*meta
, guint32 index
, guint32 start_index
)
5032 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_NESTEDCLASS
];
5034 guint32 class_index
= mono_metadata_token_index (index
);
5039 start
= start_index
;
5041 while (start
<= tdef
->rows
) {
5042 if (class_index
== mono_metadata_decode_row_col (tdef
, start
- 1, MONO_NESTED_CLASS_ENCLOSING
))
5048 if (start
> tdef
->rows
)
5055 * mono_metadata_packing_from_typedef:
5056 * \param meta metadata context
5057 * \param index token representing a type
5058 * \returns the info stored in the \c ClassLayout table for the given typedef token
5059 * into the \p packing and \p size pointers.
5060 * Returns 0 if the info is not found.
5063 mono_metadata_packing_from_typedef (MonoImage
*meta
, guint32 index
, guint32
*packing
, guint32
*size
)
5065 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_CLASSLAYOUT
];
5067 guint32 cols
[MONO_CLASS_LAYOUT_SIZE
];
5072 loc
.idx
= mono_metadata_token_index (index
);
5073 loc
.col_idx
= MONO_CLASS_LAYOUT_PARENT
;
5076 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
5079 mono_metadata_decode_row (tdef
, loc
.result
, cols
, MONO_CLASS_LAYOUT_SIZE
);
5081 *packing
= cols
[MONO_CLASS_LAYOUT_PACKING_SIZE
];
5083 *size
= cols
[MONO_CLASS_LAYOUT_CLASS_SIZE
];
5085 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5086 return loc
.result
+ 1;
5090 * mono_metadata_custom_attrs_from_index:
5091 * \param meta metadata context
5092 * \param index token representing the parent
5093 * \returns: the 1-based index into the \c CustomAttribute table of the first
5094 * attribute which belongs to the metadata object described by \p index.
5095 * Returns 0 if no such attribute is found.
5098 mono_metadata_custom_attrs_from_index (MonoImage
*meta
, guint32 index
)
5100 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_CUSTOMATTRIBUTE
];
5107 loc
.col_idx
= MONO_CUSTOM_ATTR_PARENT
;
5110 /* FIXME: Index translation */
5112 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
5115 /* Find the first entry by searching backwards */
5116 while ((loc
.result
> 0) && (mono_metadata_decode_row_col (tdef
, loc
.result
- 1, MONO_CUSTOM_ATTR_PARENT
) == index
))
5119 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5120 return loc
.result
+ 1;
5124 * mono_metadata_declsec_from_index:
5125 * \param meta metadata context
5126 * \param index token representing the parent
5127 * \returns the 0-based index into the \c DeclarativeSecurity table of the first
5128 * attribute which belongs to the metadata object described by \p index.
5129 * Returns \c -1 if no such attribute is found.
5132 mono_metadata_declsec_from_index (MonoImage
*meta
, guint32 index
)
5134 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_DECLSECURITY
];
5141 loc
.col_idx
= MONO_DECL_SECURITY_PARENT
;
5144 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, declsec_locator
))
5147 /* Find the first entry by searching backwards */
5148 while ((loc
.result
> 0) && (mono_metadata_decode_row_col (tdef
, loc
.result
- 1, MONO_DECL_SECURITY_PARENT
) == index
))
5155 * mono_metadata_localscope_from_methoddef:
5156 * @meta: metadata context
5157 * @index: methoddef index
5159 * Returns: the 1-based index into the LocalScope table of the first
5160 * scope which belongs to the method described by @index.
5161 * Returns 0 if no such row is found.
5164 mono_metadata_localscope_from_methoddef (MonoImage
*meta
, guint32 index
)
5166 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_LOCALSCOPE
];
5173 loc
.col_idx
= MONO_LOCALSCOPE_METHOD
;
5176 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
5179 /* Find the first entry by searching backwards */
5180 while ((loc
.result
> 0) && (mono_metadata_decode_row_col (tdef
, loc
.result
- 1, MONO_LOCALSCOPE_METHOD
) == index
))
5183 return loc
.result
+ 1;
5188 mono_backtrace (int limit
)
5193 backtrace (array
, limit
);
5194 names
= backtrace_symbols (array
, limit
);
5195 for (i
=0; i
< limit
; ++i
) {
5196 g_print ("\t%s\n", names
[i
]);
5202 static int i8_align
;
5205 * mono_type_set_alignment:
5207 * Set the alignment used by runtime to layout fields etc. of type TYPE to ALIGN.
5208 * This should only be used in AOT mode since the resulting layout will not match the
5212 mono_type_set_alignment (MonoTypeEnum type
, int align
)
5214 /* Support only a few types whose alignment is abi dependent */
5220 g_assert_not_reached ();
5227 * \param t the type to return the size of
5228 * \returns The number of bytes required to hold an instance of this
5232 mono_type_size (MonoType
*t
, int *align
)
5234 MonoTypeEnum simple_type
;
5241 *align
= MONO_ABI_ALIGNOF (gpointer
);
5242 return MONO_ABI_SIZEOF (gpointer
);
5245 simple_type
= t
->type
;
5247 switch (simple_type
) {
5248 case MONO_TYPE_VOID
:
5251 case MONO_TYPE_BOOLEAN
:
5252 *align
= MONO_ABI_ALIGNOF (gint8
);
5256 *align
= MONO_ABI_ALIGNOF (gint8
);
5258 case MONO_TYPE_CHAR
:
5261 *align
= MONO_ABI_ALIGNOF (gint16
);
5265 *align
= MONO_ABI_ALIGNOF (gint32
);
5268 *align
= MONO_ABI_ALIGNOF (float);
5272 *align
= MONO_ABI_ALIGNOF (gint64
);
5275 *align
= MONO_ABI_ALIGNOF (double);
5279 *align
= MONO_ABI_ALIGNOF (gpointer
);
5280 return MONO_ABI_SIZEOF (gpointer
);
5281 case MONO_TYPE_VALUETYPE
: {
5282 if (m_class_is_enumtype (t
->data
.klass
))
5283 return mono_type_size (mono_class_enum_basetype_internal (t
->data
.klass
), align
);
5285 return mono_class_value_size (t
->data
.klass
, (guint32
*)align
);
5287 case MONO_TYPE_STRING
:
5288 case MONO_TYPE_OBJECT
:
5289 case MONO_TYPE_CLASS
:
5290 case MONO_TYPE_SZARRAY
:
5292 case MONO_TYPE_FNPTR
:
5293 case MONO_TYPE_ARRAY
:
5294 *align
= MONO_ABI_ALIGNOF (gpointer
);
5295 return MONO_ABI_SIZEOF (gpointer
);
5296 case MONO_TYPE_TYPEDBYREF
:
5297 return mono_class_value_size (mono_defaults
.typed_reference_class
, (guint32
*)align
);
5298 case MONO_TYPE_GENERICINST
: {
5299 MonoGenericClass
*gclass
= t
->data
.generic_class
;
5300 MonoClass
*container_class
= gclass
->container_class
;
5302 // g_assert (!gclass->inst->is_open);
5304 if (m_class_is_valuetype (container_class
)) {
5305 if (m_class_is_enumtype (container_class
))
5306 return mono_type_size (mono_class_enum_basetype_internal (container_class
), align
);
5308 return mono_class_value_size (mono_class_from_mono_type_internal (t
), (guint32
*)align
);
5310 *align
= MONO_ABI_ALIGNOF (gpointer
);
5311 return MONO_ABI_SIZEOF (gpointer
);
5315 case MONO_TYPE_MVAR
:
5316 if (!t
->data
.generic_param
->gshared_constraint
|| t
->data
.generic_param
->gshared_constraint
->type
== MONO_TYPE_VALUETYPE
) {
5317 *align
= MONO_ABI_ALIGNOF (gpointer
);
5318 return MONO_ABI_SIZEOF (gpointer
);
5320 /* The gparam can only match types given by gshared_constraint */
5321 return mono_type_size (t
->data
.generic_param
->gshared_constraint
, align
);
5325 g_error ("mono_type_size: type 0x%02x unknown", t
->type
);
5331 * mono_type_stack_size:
5332 * \param t the type to return the size it uses on the stack
5333 * \returns The number of bytes required to hold an instance of this
5334 * type on the runtime stack
5337 mono_type_stack_size (MonoType
*t
, int *align
)
5339 return mono_type_stack_size_internal (t
, align
, FALSE
);
5343 mono_type_stack_size_internal (MonoType
*t
, int *align
, gboolean allow_open
)
5346 MonoTypeEnum simple_type
;
5347 int stack_slot_size
= TARGET_SIZEOF_VOID_P
;
5348 int stack_slot_align
= TARGET_SIZEOF_VOID_P
;
5350 g_assert (t
!= NULL
);
5356 *align
= stack_slot_align
;
5357 return stack_slot_size
;
5360 simple_type
= t
->type
;
5361 switch (simple_type
) {
5362 case MONO_TYPE_BOOLEAN
:
5363 case MONO_TYPE_CHAR
:
5372 case MONO_TYPE_STRING
:
5373 case MONO_TYPE_OBJECT
:
5374 case MONO_TYPE_CLASS
:
5375 case MONO_TYPE_SZARRAY
:
5377 case MONO_TYPE_FNPTR
:
5378 case MONO_TYPE_ARRAY
:
5379 *align
= stack_slot_align
;
5380 return stack_slot_size
;
5382 case MONO_TYPE_MVAR
:
5383 g_assert (allow_open
);
5384 if (!t
->data
.generic_param
->gshared_constraint
|| t
->data
.generic_param
->gshared_constraint
->type
== MONO_TYPE_VALUETYPE
) {
5385 *align
= stack_slot_align
;
5386 return stack_slot_size
;
5388 /* The gparam can only match types given by gshared_constraint */
5389 return mono_type_stack_size_internal (t
->data
.generic_param
->gshared_constraint
, align
, allow_open
);
5391 case MONO_TYPE_TYPEDBYREF
:
5392 *align
= stack_slot_align
;
5393 return stack_slot_size
* 3;
5395 *align
= MONO_ABI_ALIGNOF (float);
5396 return sizeof (float);
5399 *align
= MONO_ABI_ALIGNOF (gint64
);
5400 return sizeof (gint64
);
5402 *align
= MONO_ABI_ALIGNOF (double);
5403 return sizeof (double);
5404 case MONO_TYPE_VALUETYPE
: {
5407 if (m_class_is_enumtype (t
->data
.klass
))
5408 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (t
->data
.klass
), align
, allow_open
);
5410 size
= mono_class_value_size (t
->data
.klass
, (guint32
*)align
);
5412 *align
= *align
+ stack_slot_align
- 1;
5413 *align
&= ~(stack_slot_align
- 1);
5415 size
+= stack_slot_size
- 1;
5416 size
&= ~(stack_slot_size
- 1);
5421 case MONO_TYPE_GENERICINST
: {
5422 MonoGenericClass
*gclass
= t
->data
.generic_class
;
5423 MonoClass
*container_class
= gclass
->container_class
;
5426 g_assert (!gclass
->context
.class_inst
->is_open
);
5428 if (m_class_is_valuetype (container_class
)) {
5429 if (m_class_is_enumtype (container_class
))
5430 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (container_class
), align
, allow_open
);
5432 guint32 size
= mono_class_value_size (mono_class_from_mono_type_internal (t
), (guint32
*)align
);
5434 *align
= *align
+ stack_slot_align
- 1;
5435 *align
&= ~(stack_slot_align
- 1);
5437 size
+= stack_slot_size
- 1;
5438 size
&= ~(stack_slot_size
- 1);
5443 *align
= stack_slot_align
;
5444 return stack_slot_size
;
5448 g_error ("type 0x%02x unknown", t
->type
);
5454 mono_type_generic_inst_is_valuetype (MonoType
*type
)
5456 g_assert (type
->type
== MONO_TYPE_GENERICINST
);
5457 return m_class_is_valuetype (type
->data
.generic_class
->container_class
);
5461 * mono_metadata_generic_class_is_valuetype:
5464 mono_metadata_generic_class_is_valuetype (MonoGenericClass
*gclass
)
5466 return m_class_is_valuetype (gclass
->container_class
);
5470 _mono_metadata_generic_class_equal (const MonoGenericClass
*g1
, const MonoGenericClass
*g2
, gboolean signature_only
)
5472 MonoGenericInst
*i1
= g1
->context
.class_inst
;
5473 MonoGenericInst
*i2
= g2
->context
.class_inst
;
5475 if (g1
->is_dynamic
!= g2
->is_dynamic
)
5477 if (!mono_metadata_class_equal (g1
->container_class
, g2
->container_class
, signature_only
))
5479 if (!mono_generic_inst_equal_full (i1
, i2
, signature_only
))
5481 return g1
->is_tb_open
== g2
->is_tb_open
;
5485 _mono_metadata_generic_class_container_equal (const MonoGenericClass
*g1
, MonoClass
*c2
, gboolean signature_only
)
5487 MonoGenericInst
*i1
= g1
->context
.class_inst
;
5488 MonoGenericInst
*i2
= mono_class_get_generic_container (c2
)->context
.class_inst
;
5490 if (!mono_metadata_class_equal (g1
->container_class
, c2
, signature_only
))
5492 if (!mono_generic_inst_equal_full (i1
, i2
, signature_only
))
5494 return !g1
->is_tb_open
;
5498 mono_metadata_generic_context_hash (const MonoGenericContext
*context
)
5500 /* FIXME: check if this seed is good enough */
5501 guint hash
= 0xc01dfee7;
5502 if (context
->class_inst
)
5503 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_generic_inst_hash (context
->class_inst
);
5504 if (context
->method_inst
)
5505 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_generic_inst_hash (context
->method_inst
);
5510 mono_metadata_generic_context_equal (const MonoGenericContext
*g1
, const MonoGenericContext
*g2
)
5512 return g1
->class_inst
== g2
->class_inst
&& g1
->method_inst
== g2
->method_inst
;
5516 * mono_metadata_str_hash:
5518 * This should be used instead of g_str_hash for computing hash codes visible
5519 * outside this module, since g_str_hash () is not guaranteed to be stable
5520 * (its not the same in eglib for example).
5523 mono_metadata_str_hash (gconstpointer v1
)
5525 /* Same as g_str_hash () in glib */
5526 char *p
= (char *) v1
;
5531 hash
= (hash
<< 5) - hash
+ *p
;
5538 * mono_metadata_type_hash:
5540 * Computes a hash value for \p t1 to be used in \c GHashTable.
5541 * The returned hash is guaranteed to be the same across executions.
5544 mono_metadata_type_hash (MonoType
*t1
)
5546 guint hash
= t1
->type
;
5548 hash
|= t1
->byref
<< 6; /* do not collide with t1->type values */
5550 case MONO_TYPE_VALUETYPE
:
5551 case MONO_TYPE_CLASS
:
5552 case MONO_TYPE_SZARRAY
: {
5553 MonoClass
*klass
= t1
->data
.klass
;
5555 * Dynamic classes must not be hashed on their type since it can change
5556 * during runtime. For example, if we hash a reference type that is
5557 * later made into a valuetype.
5559 * This is specially problematic with generic instances since they are
5560 * inserted in a bunch of hash tables before been finished.
5562 if (image_is_dynamic (m_class_get_image (klass
)))
5563 return (t1
->byref
<< 6) | mono_metadata_str_hash (m_class_get_name (klass
));
5564 return ((hash
<< 5) - hash
) ^ mono_metadata_str_hash (m_class_get_name (klass
));
5567 return ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (t1
->data
.type
);
5568 case MONO_TYPE_ARRAY
:
5569 return ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (m_class_get_byval_arg (t1
->data
.array
->eklass
));
5570 case MONO_TYPE_GENERICINST
:
5571 return ((hash
<< 5) - hash
) ^ mono_generic_class_hash (t1
->data
.generic_class
);
5573 case MONO_TYPE_MVAR
:
5574 return ((hash
<< 5) - hash
) ^ mono_metadata_generic_param_hash (t1
->data
.generic_param
);
5581 mono_metadata_generic_param_hash (MonoGenericParam
*p
)
5584 MonoGenericParamInfo
*info
;
5586 hash
= (mono_generic_param_num (p
) << 2);
5587 if (p
->gshared_constraint
)
5588 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (p
->gshared_constraint
);
5589 info
= mono_generic_param_info (p
);
5590 /* Can't hash on the owner klass/method, since those might not be set when this is called */
5591 if (!p
->owner
->is_anonymous
)
5592 hash
= ((hash
<< 5) - hash
) ^ info
->token
;
5597 mono_metadata_generic_param_equal_internal (MonoGenericParam
*p1
, MonoGenericParam
*p2
, gboolean signature_only
)
5601 if (mono_generic_param_num (p1
) != mono_generic_param_num (p2
))
5603 if (p1
->gshared_constraint
&& p2
->gshared_constraint
) {
5604 if (!mono_metadata_type_equal (p1
->gshared_constraint
, p2
->gshared_constraint
))
5607 if (p1
->gshared_constraint
!= p2
->gshared_constraint
)
5612 * We have to compare the image as well because if we didn't,
5613 * the generic_inst_cache lookup wouldn't care about the image
5614 * of generic params, so what could happen is that a generic
5615 * inst with params from image A is put into the cache, then
5616 * image B gets that generic inst from the cache, image A is
5617 * unloaded, so the inst is deleted, but image B still retains
5620 if (mono_generic_param_owner (p1
) == mono_generic_param_owner (p2
))
5624 * If `signature_only' is true, we're comparing two (method) signatures.
5625 * In this case, the owner of two type parameters doesn't need to match.
5628 return signature_only
;
5632 mono_metadata_generic_param_equal (MonoGenericParam
*p1
, MonoGenericParam
*p2
)
5634 return mono_metadata_generic_param_equal_internal (p1
, p2
, TRUE
);
5638 mono_metadata_class_equal (MonoClass
*c1
, MonoClass
*c2
, gboolean signature_only
)
5642 if (mono_class_is_ginst (c1
) && mono_class_is_ginst (c2
))
5643 return _mono_metadata_generic_class_equal (mono_class_get_generic_class (c1
), mono_class_get_generic_class (c2
), signature_only
);
5644 if (mono_class_is_ginst (c1
) && mono_class_is_gtd (c2
))
5645 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c1
), c2
, signature_only
);
5646 if (mono_class_is_gtd (c1
) && mono_class_is_ginst (c2
))
5647 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c2
), c1
, signature_only
);
5648 MonoType
*c1_type
= m_class_get_byval_arg (c1
);
5649 MonoType
*c2_type
= m_class_get_byval_arg (c2
);
5650 if ((c1_type
->type
== MONO_TYPE_VAR
) && (c2_type
->type
== MONO_TYPE_VAR
))
5651 return mono_metadata_generic_param_equal_internal (
5652 c1_type
->data
.generic_param
, c2_type
->data
.generic_param
, signature_only
);
5653 if ((c1_type
->type
== MONO_TYPE_MVAR
) && (c2_type
->type
== MONO_TYPE_MVAR
))
5654 return mono_metadata_generic_param_equal_internal (
5655 c1_type
->data
.generic_param
, c2_type
->data
.generic_param
, signature_only
);
5656 if (signature_only
&&
5657 (c1_type
->type
== MONO_TYPE_SZARRAY
) && (c2_type
->type
== MONO_TYPE_SZARRAY
))
5658 return mono_metadata_class_equal (c1_type
->data
.klass
, c2_type
->data
.klass
, signature_only
);
5659 if (signature_only
&&
5660 (c1_type
->type
== MONO_TYPE_ARRAY
) && (c2_type
->type
== MONO_TYPE_ARRAY
))
5661 return do_mono_metadata_type_equal (c1_type
, c2_type
, signature_only
);
5666 mono_metadata_fnptr_equal (MonoMethodSignature
*s1
, MonoMethodSignature
*s2
, gboolean signature_only
)
5668 gpointer iter1
= 0, iter2
= 0;
5672 if (s1
->call_convention
!= s2
->call_convention
)
5674 if (s1
->sentinelpos
!= s2
->sentinelpos
)
5676 if (s1
->hasthis
!= s2
->hasthis
)
5678 if (s1
->explicit_this
!= s2
->explicit_this
)
5680 if (! do_mono_metadata_type_equal (s1
->ret
, s2
->ret
, signature_only
))
5682 if (s1
->param_count
!= s2
->param_count
)
5686 MonoType
*t1
= mono_signature_get_params (s1
, &iter1
);
5687 MonoType
*t2
= mono_signature_get_params (s2
, &iter2
);
5689 if (t1
== NULL
|| t2
== NULL
)
5691 if (! do_mono_metadata_type_equal (t1
, t2
, signature_only
))
5697 mono_metadata_custom_modifiers_equal (MonoType
*t1
, MonoType
*t2
, gboolean signature_only
)
5700 // The CLI itself shall treat required and optional modifiers in the same manner.
5701 // Two signatures that differ only by the addition of a custom modifier
5702 // (required or optional) shall not be considered to match.
5703 int count
= mono_type_custom_modifier_count (t1
);
5704 if (count
!= mono_type_custom_modifier_count (t2
))
5707 for (int i
=0; i
< count
; i
++) {
5708 // FIXME: propagate error to caller
5710 gboolean cm1_required
, cm2_required
;
5712 MonoType
*cm1_type
= mono_type_get_custom_modifier (t1
, i
, &cm1_required
, error
);
5713 mono_error_assert_ok (error
);
5714 MonoType
*cm2_type
= mono_type_get_custom_modifier (t2
, i
, &cm2_required
, error
);
5715 mono_error_assert_ok (error
);
5717 if (cm1_required
!= cm2_required
)
5720 if (!do_mono_metadata_type_equal (cm1_type
, cm2_type
, signature_only
))
5727 * mono_metadata_type_equal:
5730 * @signature_only: If true, treat ginsts as equal which are instantiated separately but have equal positional value
5732 * Determine if @t1 and @t2 represent the same type.
5733 * Returns: #TRUE if @t1 and @t2 are equal.
5736 do_mono_metadata_type_equal (MonoType
*t1
, MonoType
*t2
, gboolean signature_only
)
5738 if (t1
->type
!= t2
->type
|| t1
->byref
!= t2
->byref
)
5741 gboolean cmod_reject
= FALSE
;
5743 if (t1
->has_cmods
!= t2
->has_cmods
)
5745 else if (t1
->has_cmods
&& t2
->has_cmods
) {
5746 cmod_reject
= !mono_metadata_custom_modifiers_equal (t1
, t2
, signature_only
);
5749 gboolean result
= FALSE
;
5752 case MONO_TYPE_VOID
:
5753 case MONO_TYPE_BOOLEAN
:
5754 case MONO_TYPE_CHAR
:
5765 case MONO_TYPE_STRING
:
5768 case MONO_TYPE_OBJECT
:
5769 case MONO_TYPE_TYPEDBYREF
:
5772 case MONO_TYPE_VALUETYPE
:
5773 case MONO_TYPE_CLASS
:
5774 case MONO_TYPE_SZARRAY
:
5775 result
= mono_metadata_class_equal (t1
->data
.klass
, t2
->data
.klass
, signature_only
);
5778 result
= do_mono_metadata_type_equal (t1
->data
.type
, t2
->data
.type
, signature_only
);
5780 case MONO_TYPE_ARRAY
:
5781 if (t1
->data
.array
->rank
!= t2
->data
.array
->rank
)
5784 result
= mono_metadata_class_equal (t1
->data
.array
->eklass
, t2
->data
.array
->eklass
, signature_only
);
5786 case MONO_TYPE_GENERICINST
:
5787 result
= _mono_metadata_generic_class_equal (
5788 t1
->data
.generic_class
, t2
->data
.generic_class
, signature_only
);
5791 result
= mono_metadata_generic_param_equal_internal (
5792 t1
->data
.generic_param
, t2
->data
.generic_param
, signature_only
);
5794 case MONO_TYPE_MVAR
:
5795 result
= mono_metadata_generic_param_equal_internal (
5796 t1
->data
.generic_param
, t2
->data
.generic_param
, signature_only
);
5798 case MONO_TYPE_FNPTR
:
5799 result
= mono_metadata_fnptr_equal (t1
->data
.method
, t2
->data
.method
, signature_only
);
5802 g_error ("implement type compare for %0x!", t1
->type
);
5806 return result
&& !cmod_reject
;
5810 * mono_metadata_type_equal:
5813 mono_metadata_type_equal (MonoType
*t1
, MonoType
*t2
)
5815 return do_mono_metadata_type_equal (t1
, t2
, FALSE
);
5819 * mono_metadata_type_equal_full:
5821 * \param t2 another type
5822 * \param signature_only if signature only comparison should be made
5824 * Determine if \p t1 and \p t2 are signature compatible if \p signature_only is TRUE, otherwise
5825 * behaves the same way as mono_metadata_type_equal.
5826 * The function mono_metadata_type_equal(a, b) is just a shortcut for mono_metadata_type_equal_full(a, b, FALSE).
5827 * \returns TRUE if \p t1 and \p t2 are equal taking \p signature_only into account.
5830 mono_metadata_type_equal_full (MonoType
*t1
, MonoType
*t2
, gboolean signature_only
)
5832 return do_mono_metadata_type_equal (t1
, t2
, signature_only
);
5836 * mono_metadata_signature_equal:
5837 * \param sig1 a signature
5838 * \param sig2 another signature
5840 * Determine if \p sig1 and \p sig2 represent the same signature, with the
5841 * same number of arguments and the same types.
5842 * \returns TRUE if \p sig1 and \p sig2 are equal.
5845 mono_metadata_signature_equal (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
5849 if (sig1
->hasthis
!= sig2
->hasthis
|| sig1
->param_count
!= sig2
->param_count
)
5852 if (sig1
->generic_param_count
!= sig2
->generic_param_count
)
5856 * We're just comparing the signatures of two methods here:
5858 * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
5859 * U and V are equal here.
5861 * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
5864 for (i
= 0; i
< sig1
->param_count
; i
++) {
5865 MonoType
*p1
= sig1
->params
[i
];
5866 MonoType
*p2
= sig2
->params
[i
];
5868 /* if (p1->attrs != p2->attrs)
5871 if (!do_mono_metadata_type_equal (p1
, p2
, TRUE
))
5875 if (!do_mono_metadata_type_equal (sig1
->ret
, sig2
->ret
, TRUE
))
5881 mono_type_get_custom_modifier (const MonoType
*ty
, uint8_t idx
, gboolean
*required
, MonoError
*error
)
5883 g_assert (ty
->has_cmods
);
5884 if (mono_type_is_aggregate_mods (ty
)) {
5885 MonoAggregateModContainer
*amods
= mono_type_get_amods (ty
);
5886 g_assert (idx
< amods
->count
);
5887 MonoSingleCustomMod
*cmod
= &amods
->modifiers
[idx
];
5889 *required
= !!cmod
->required
;
5892 MonoCustomModContainer
*cmods
= mono_type_get_cmods (ty
);
5893 g_assert (idx
< cmods
->count
);
5894 MonoCustomMod
*cmod
= &cmods
->modifiers
[idx
];
5896 *required
= !!cmod
->required
;
5897 MonoImage
*image
= cmods
->image
;
5898 uint32_t token
= cmod
->token
;
5899 return mono_type_get_checked (image
, token
, NULL
, error
);
5905 * mono_metadata_type_dup:
5906 * \param image image to alloc memory from
5907 * \param original type to duplicate
5908 * \returns copy of type allocated from the image's mempool (or from the heap, if \p image is null).
5911 mono_metadata_type_dup (MonoImage
*image
, const MonoType
*o
)
5913 return mono_metadata_type_dup_with_cmods (image
, o
, o
);
5917 deep_type_dup_fixup (MonoImage
*image
, MonoType
*r
, const MonoType
*o
);
5920 custom_modifier_copy (MonoAggregateModContainer
*dest
, uint8_t dest_offset
, const MonoType
*source
)
5922 if (mono_type_is_aggregate_mods (source
)) {
5923 MonoAggregateModContainer
*src_cmods
= mono_type_get_amods (source
);
5924 memcpy (&dest
->modifiers
[dest_offset
], &src_cmods
->modifiers
[0], src_cmods
->count
* sizeof (MonoSingleCustomMod
));
5925 dest_offset
+= src_cmods
->count
;
5927 MonoCustomModContainer
*src_cmods
= mono_type_get_cmods (source
);
5928 for (int i
= 0; i
< src_cmods
->count
; i
++) {
5929 ERROR_DECL (error
); // XXX FIXME: AK - propagate the error to the caller.
5930 MonoSingleCustomMod
*cmod
= &dest
->modifiers
[dest_offset
++];
5931 cmod
->type
= mono_type_get_checked (src_cmods
->image
, src_cmods
->modifiers
[i
].token
, NULL
, error
);
5932 mono_error_assert_ok (error
);
5933 cmod
->required
= src_cmods
->modifiers
[i
].required
;
5939 /* makes a dup of 'o' but also appends the custom modifiers from 'cmods_source' */
5941 do_metadata_type_dup_append_cmods (MonoImage
*image
, const MonoType
*o
, const MonoType
*cmods_source
)
5943 g_assert (o
!= cmods_source
);
5944 g_assert (o
->has_cmods
);
5945 g_assert (cmods_source
->has_cmods
);
5946 if (!mono_type_is_aggregate_mods (o
) &&
5947 !mono_type_is_aggregate_mods (cmods_source
) &&
5948 mono_type_get_cmods (o
)->image
== mono_type_get_cmods (cmods_source
)->image
) {
5949 /* the uniform case: all the cmods are from the same image. */
5950 MonoCustomModContainer
*o_cmods
= mono_type_get_cmods (o
);
5951 MonoCustomModContainer
*extra_cmods
= mono_type_get_cmods (cmods_source
);
5952 uint8_t total_cmods
= o_cmods
->count
+ extra_cmods
->count
;
5953 gboolean aggregate
= FALSE
;
5954 size_t sizeof_dup
= mono_sizeof_type_with_mods (total_cmods
, aggregate
);
5955 MonoType
*r
= image
? (MonoType
*)mono_image_alloc0 (image
, sizeof_dup
) : (MonoType
*)g_malloc0 (sizeof_dup
);
5957 mono_type_with_mods_init (r
, total_cmods
, aggregate
);
5959 /* copy the original type o, not including its modifiers */
5960 memcpy (r
, o
, mono_sizeof_type_with_mods (0, FALSE
));
5961 deep_type_dup_fixup (image
, r
, o
);
5963 /* The modifier order matters to Roslyn, they expect the extra cmods to come first:
5965 * Suppose we substitute 'int32 modopt(IsLong)' for 'T' in 'void Test
5966 * (T modopt(IsConst))'. Roslyn expects the result to be 'void Test
5967 * (int32 modopt(IsLong) modopt(IsConst))'.
5969 * but! cmods are encoded in IL in reverse order, so 'int32 modopt(IsConst) modopt(IsLong)' is
5970 * encoded as `cmod_opt [typeref IsLong] cmod_opt [typeref IsConst] I4`
5971 * so in our array, extra_cmods (IsLong) come first, followed by o_cmods (IsConst)
5973 * (Here 'o' is 'int32 modopt(IsLong)' and cmods_source is 'T modopt(IsConst)')
5975 /* append the modifiers from cmods_source and o */
5976 MonoCustomModContainer
*r_container
= mono_type_get_cmods (r
);
5977 uint8_t dest_offset
= 0;
5978 r_container
->image
= extra_cmods
->image
;
5980 memcpy (&r_container
->modifiers
[dest_offset
], &o_cmods
->modifiers
[0], o_cmods
->count
* sizeof (MonoCustomMod
));
5981 dest_offset
+= o_cmods
->count
;
5982 memcpy (&r_container
->modifiers
[dest_offset
], &extra_cmods
->modifiers
[0], extra_cmods
->count
* sizeof (MonoCustomMod
));
5983 dest_offset
+= extra_cmods
->count
;
5984 g_assert (dest_offset
== total_cmods
);
5988 /* The aggregate case: either o_cmods or extra_cmods has aggregate cmods, or they're both simple but from different images. */
5989 uint8_t total_cmods
= 0;
5990 total_cmods
+= mono_type_custom_modifier_count (o
);
5991 total_cmods
+= mono_type_custom_modifier_count (cmods_source
);
5993 gboolean aggregate
= TRUE
;
5994 size_t sizeof_dup
= mono_sizeof_type_with_mods (total_cmods
, aggregate
);
5996 /* FIXME: if image, and the images of the custom modifiers from
5997 * o and cmods_source are all different, we need an image
5999 MonoType
*r
= image
? (MonoType
*)mono_image_alloc0 (image
, sizeof_dup
) : (MonoType
*)g_malloc0 (sizeof_dup
);
6001 mono_type_with_mods_init (r
, total_cmods
, aggregate
);
6003 memcpy (r
, o
, mono_sizeof_type_with_mods (0, FALSE
));
6004 deep_type_dup_fixup (image
, r
, o
);
6006 /* Try not to blow up the stack. See comment on
6007 * MONO_MAX_EXPECTED_CMODS. Since here we're appending all the
6008 * mods together, it's possible we'll end up with more than the
6009 * maximum allowed. If that ever happens in practice, we
6010 * should redefine the bound and possibly make this function
6011 * fail dynamically instead of asserting.
6013 g_assert (total_cmods
< MONO_MAX_EXPECTED_CMODS
);
6014 size_t r_container_size
= mono_sizeof_aggregate_modifiers (total_cmods
);
6015 MonoAggregateModContainer
*r_container_candidate
= g_alloca (r_container_size
);
6016 memset (r_container_candidate
, 0, r_container_size
);
6017 uint8_t dest_offset
= 0;
6019 dest_offset
= custom_modifier_copy (r_container_candidate
, dest_offset
, o
);
6020 dest_offset
= custom_modifier_copy (r_container_candidate
, dest_offset
, cmods_source
);
6021 g_assert (dest_offset
== total_cmods
);
6022 r_container_candidate
->count
= total_cmods
;
6024 mono_type_set_amods (r
, mono_metadata_get_canonical_aggregate_modifiers (r_container_candidate
));
6031 * Works the same way as mono_metadata_type_dup but pick cmods from @cmods_source
6034 mono_metadata_type_dup_with_cmods (MonoImage
*image
, const MonoType
*o
, const MonoType
*cmods_source
)
6036 if (o
->has_cmods
&& o
!= cmods_source
&& cmods_source
->has_cmods
) {
6037 return do_metadata_type_dup_append_cmods (image
, o
, cmods_source
);
6042 /* if we get here, either o and cmods_source alias, or else exactly one of them has cmods. */
6044 uint8_t num_mods
= MAX (mono_type_custom_modifier_count (o
), mono_type_custom_modifier_count (cmods_source
));
6045 gboolean aggregate
= mono_type_is_aggregate_mods (o
) || mono_type_is_aggregate_mods (cmods_source
);
6046 size_t sizeof_r
= mono_sizeof_type_with_mods (num_mods
, aggregate
);
6048 r
= image
? (MonoType
*)mono_image_alloc0 (image
, sizeof_r
) : (MonoType
*)g_malloc0 (sizeof_r
);
6050 if (cmods_source
->has_cmods
) {
6051 /* FIXME: if it's aggregate what do we assert here? */
6052 g_assert (!image
|| (!aggregate
&& image
== mono_type_get_cmods (cmods_source
)->image
));
6053 memcpy (r
, cmods_source
, mono_sizeof_type (cmods_source
));
6056 memcpy (r
, o
, mono_sizeof_type (o
));
6058 /* reset custom mod count and aggregateness to be correct. */
6059 mono_type_with_mods_init (r
, num_mods
, aggregate
);
6061 mono_type_set_amods (r
, mono_type_is_aggregate_mods (o
) ? mono_type_get_amods (o
) : mono_type_get_amods (cmods_source
));
6062 deep_type_dup_fixup (image
, r
, o
);
6068 deep_type_dup_fixup (MonoImage
*image
, MonoType
*r
, const MonoType
*o
)
6070 if (o
->type
== MONO_TYPE_PTR
) {
6071 r
->data
.type
= mono_metadata_type_dup (image
, o
->data
.type
);
6072 } else if (o
->type
== MONO_TYPE_ARRAY
) {
6073 r
->data
.array
= mono_dup_array_type (image
, o
->data
.array
);
6074 } else if (o
->type
== MONO_TYPE_FNPTR
) {
6075 /*FIXME the dup'ed signature is leaked mono_metadata_free_type*/
6076 r
->data
.method
= mono_metadata_signature_deep_dup (image
, o
->data
.method
);
6081 * mono_signature_hash:
6084 mono_signature_hash (MonoMethodSignature
*sig
)
6086 guint i
, res
= sig
->ret
->type
;
6088 for (i
= 0; i
< sig
->param_count
; i
++)
6089 res
= (res
<< 5) - res
+ mono_type_hash (sig
->params
[i
]);
6095 * mono_metadata_encode_value:
6096 * @value: value to encode
6097 * @buf: buffer where to write the compressed representation
6098 * @endbuf: pointer updated to point at the end of the encoded output
6100 * Encodes the value @value in the compressed representation used
6101 * in metadata and stores the result in @buf. @buf needs to be big
6102 * enough to hold the data (4 bytes).
6105 mono_metadata_encode_value (guint32 value
, char *buf
, char **endbuf
)
6111 else if (value
< 0x4000) {
6112 p
[0] = 0x80 | (value
>> 8);
6113 p
[1] = value
& 0xff;
6116 p
[0] = (value
>> 24) | 0xc0;
6117 p
[1] = (value
>> 16) & 0xff;
6118 p
[2] = (value
>> 8) & 0xff;
6119 p
[3] = value
& 0xff;
6127 * mono_metadata_field_info:
6128 * \param meta the Image the field is defined in
6129 * \param index the index in the field table representing the field
6130 * \param offset a pointer to an integer where to store the offset that may have been specified for the field in a FieldLayout table
6131 * \param rva a pointer to the RVA of the field data in the image that may have been defined in a \c FieldRVA table
6132 * \param marshal_spec a pointer to the marshal spec that may have been defined for the field in a \c FieldMarshal table.
6134 * Gather info for field \p index that may have been defined in the \c FieldLayout,
6135 * \c FieldRVA and \c FieldMarshal tables.
6136 * Either of \p offset, \p rva and \p marshal_spec can be NULL if you're not interested
6140 mono_metadata_field_info (MonoImage
*meta
, guint32 index
, guint32
*offset
, guint32
*rva
,
6141 MonoMarshalSpec
**marshal_spec
)
6143 mono_metadata_field_info_full (meta
, index
, offset
, rva
, marshal_spec
, FALSE
);
6147 mono_metadata_field_info_with_mempool (MonoImage
*meta
, guint32 index
, guint32
*offset
, guint32
*rva
,
6148 MonoMarshalSpec
**marshal_spec
)
6150 mono_metadata_field_info_full (meta
, index
, offset
, rva
, marshal_spec
, TRUE
);
6154 mono_metadata_field_info_full (MonoImage
*meta
, guint32 index
, guint32
*offset
, guint32
*rva
,
6155 MonoMarshalSpec
**marshal_spec
, gboolean alloc_from_image
)
6157 MonoTableInfo
*tdef
;
6160 loc
.idx
= index
+ 1;
6161 if (meta
->uncompressed_metadata
)
6162 loc
.idx
= search_ptr_table (meta
, MONO_TABLE_FIELD_POINTER
, loc
.idx
);
6165 tdef
= &meta
->tables
[MONO_TABLE_FIELDLAYOUT
];
6167 loc
.col_idx
= MONO_FIELD_LAYOUT_FIELD
;
6170 if (tdef
->base
&& mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
)) {
6171 *offset
= mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_FIELD_LAYOUT_OFFSET
);
6173 *offset
= (guint32
)-1;
6177 tdef
= &meta
->tables
[MONO_TABLE_FIELDRVA
];
6179 loc
.col_idx
= MONO_FIELD_RVA_FIELD
;
6182 if (tdef
->base
&& mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
)) {
6184 * LAMESPEC: There is no signature, no nothing, just the raw data.
6186 *rva
= mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_FIELD_RVA_RVA
);
6194 if ((p
= mono_metadata_get_marshal_info (meta
, index
, TRUE
))) {
6195 *marshal_spec
= mono_metadata_parse_marshal_spec_full (alloc_from_image
? meta
: NULL
, meta
, p
);
6202 * mono_metadata_get_constant_index:
6203 * \param meta the Image the field is defined in
6204 * \param index the token that may have a row defined in the constants table
6205 * \param hint possible position for the row
6207 * \p token must be a \c FieldDef, \c ParamDef or \c PropertyDef token.
6209 * \returns the index into the \c Constants table or 0 if not found.
6212 mono_metadata_get_constant_index (MonoImage
*meta
, guint32 token
, guint32 hint
)
6214 MonoTableInfo
*tdef
;
6216 guint32 index
= mono_metadata_token_index (token
);
6218 tdef
= &meta
->tables
[MONO_TABLE_CONSTANT
];
6219 index
<<= MONO_HASCONSTANT_BITS
;
6220 switch (mono_metadata_token_table (token
)) {
6221 case MONO_TABLE_FIELD
:
6222 index
|= MONO_HASCONSTANT_FIEDDEF
;
6224 case MONO_TABLE_PARAM
:
6225 index
|= MONO_HASCONSTANT_PARAM
;
6227 case MONO_TABLE_PROPERTY
:
6228 index
|= MONO_HASCONSTANT_PROPERTY
;
6231 g_warning ("Not a valid token for the constant table: 0x%08x", token
);
6235 loc
.col_idx
= MONO_CONSTANT_PARENT
;
6238 /* FIXME: Index translation */
6240 if ((hint
> 0) && (hint
< tdef
->rows
) && (mono_metadata_decode_row_col (tdef
, hint
- 1, MONO_CONSTANT_PARENT
) == index
))
6243 if (tdef
->base
&& mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
)) {
6244 return loc
.result
+ 1;
6250 * mono_metadata_events_from_typedef:
6251 * \param meta metadata context
6252 * \param index 0-based index (in the \c TypeDef table) describing a type
6253 * \returns the 0-based index in the \c Event table for the events in the
6254 * type. The last event that belongs to the type (plus 1) is stored
6255 * in the \p end_idx pointer.
6258 mono_metadata_events_from_typedef (MonoImage
*meta
, guint32 index
, guint
*end_idx
)
6262 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_EVENTMAP
];
6270 loc
.col_idx
= MONO_EVENT_MAP_PARENT
;
6271 loc
.idx
= index
+ 1;
6273 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
6276 start
= mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_EVENT_MAP_EVENTLIST
);
6277 if (loc
.result
+ 1 < tdef
->rows
) {
6278 end
= mono_metadata_decode_row_col (tdef
, loc
.result
+ 1, MONO_EVENT_MAP_EVENTLIST
) - 1;
6280 end
= meta
->tables
[MONO_TABLE_EVENT
].rows
;
6288 * mono_metadata_methods_from_event:
6289 * \param meta metadata context
6290 * \param index 0-based index (in the \c Event table) describing a event
6291 * \returns the 0-based index in the \c MethodDef table for the methods in the
6292 * event. The last method that belongs to the event (plus 1) is stored
6293 * in the \p end_idx pointer.
6296 mono_metadata_methods_from_event (MonoImage
*meta
, guint32 index
, guint
*end_idx
)
6300 guint32 cols
[MONO_METHOD_SEMA_SIZE
];
6301 MonoTableInfo
*msemt
= &meta
->tables
[MONO_TABLE_METHODSEMANTICS
];
6307 if (meta
->uncompressed_metadata
)
6308 index
= search_ptr_table (meta
, MONO_TABLE_EVENT_POINTER
, index
+ 1) - 1;
6311 loc
.col_idx
= MONO_METHOD_SEMA_ASSOCIATION
;
6312 loc
.idx
= ((index
+ 1) << MONO_HAS_SEMANTICS_BITS
) | MONO_HAS_SEMANTICS_EVENT
; /* Method association coded index */
6314 if (!mono_binary_search (&loc
, msemt
->base
, msemt
->rows
, msemt
->row_size
, table_locator
))
6319 * We may end up in the middle of the rows...
6322 if (loc
.idx
== mono_metadata_decode_row_col (msemt
, start
- 1, MONO_METHOD_SEMA_ASSOCIATION
))
6328 while (end
< msemt
->rows
) {
6329 mono_metadata_decode_row (msemt
, end
, cols
, MONO_METHOD_SEMA_SIZE
);
6330 if (cols
[MONO_METHOD_SEMA_ASSOCIATION
] != loc
.idx
)
6339 * mono_metadata_properties_from_typedef:
6340 * \param meta metadata context
6341 * \param index 0-based index (in the \c TypeDef table) describing a type
6342 * \returns the 0-based index in the \c Property table for the properties in the
6343 * type. The last property that belongs to the type (plus 1) is stored
6344 * in the \p end_idx pointer.
6347 mono_metadata_properties_from_typedef (MonoImage
*meta
, guint32 index
, guint
*end_idx
)
6351 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_PROPERTYMAP
];
6359 loc
.col_idx
= MONO_PROPERTY_MAP_PARENT
;
6360 loc
.idx
= index
+ 1;
6362 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
6365 start
= mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_PROPERTY_MAP_PROPERTY_LIST
);
6366 if (loc
.result
+ 1 < tdef
->rows
) {
6367 end
= mono_metadata_decode_row_col (tdef
, loc
.result
+ 1, MONO_PROPERTY_MAP_PROPERTY_LIST
) - 1;
6369 end
= meta
->tables
[MONO_TABLE_PROPERTY
].rows
;
6377 * mono_metadata_methods_from_property:
6378 * \param meta metadata context
6379 * \param index 0-based index (in the \c PropertyDef table) describing a property
6380 * \returns the 0-based index in the \c MethodDef table for the methods in the
6381 * property. The last method that belongs to the property (plus 1) is stored
6382 * in the \p end_idx pointer.
6385 mono_metadata_methods_from_property (MonoImage
*meta
, guint32 index
, guint
*end_idx
)
6389 guint32 cols
[MONO_METHOD_SEMA_SIZE
];
6390 MonoTableInfo
*msemt
= &meta
->tables
[MONO_TABLE_METHODSEMANTICS
];
6396 if (meta
->uncompressed_metadata
)
6397 index
= search_ptr_table (meta
, MONO_TABLE_PROPERTY_POINTER
, index
+ 1) - 1;
6400 loc
.col_idx
= MONO_METHOD_SEMA_ASSOCIATION
;
6401 loc
.idx
= ((index
+ 1) << MONO_HAS_SEMANTICS_BITS
) | MONO_HAS_SEMANTICS_PROPERTY
; /* Method association coded index */
6403 if (!mono_binary_search (&loc
, msemt
->base
, msemt
->rows
, msemt
->row_size
, table_locator
))
6408 * We may end up in the middle of the rows...
6411 if (loc
.idx
== mono_metadata_decode_row_col (msemt
, start
- 1, MONO_METHOD_SEMA_ASSOCIATION
))
6417 while (end
< msemt
->rows
) {
6418 mono_metadata_decode_row (msemt
, end
, cols
, MONO_METHOD_SEMA_SIZE
);
6419 if (cols
[MONO_METHOD_SEMA_ASSOCIATION
] != loc
.idx
)
6428 * mono_metadata_implmap_from_method:
6431 mono_metadata_implmap_from_method (MonoImage
*meta
, guint32 method_idx
)
6434 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_IMPLMAP
];
6439 /* No index translation seems to be needed */
6442 loc
.col_idx
= MONO_IMPLMAP_MEMBER
;
6443 loc
.idx
= ((method_idx
+ 1) << MONO_MEMBERFORWD_BITS
) | MONO_MEMBERFORWD_METHODDEF
;
6445 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
6448 return loc
.result
+ 1;
6452 * mono_type_create_from_typespec:
6453 * \param image context where the image is created
6454 * \param type_spec typespec token
6455 * \deprecated use \c mono_type_create_from_typespec_checked that has proper error handling
6457 * Creates a \c MonoType representing the \c TypeSpec indexed by the \p type_spec
6461 mono_type_create_from_typespec (MonoImage
*image
, guint32 type_spec
)
6464 MonoType
*type
= mono_type_create_from_typespec_checked (image
, type_spec
, error
);
6466 g_error ("Could not create typespec %x due to %s", type_spec
, mono_error_get_message (error
));
6471 mono_type_create_from_typespec_checked (MonoImage
*image
, guint32 type_spec
, MonoError
*error
)
6474 guint32 idx
= mono_metadata_token_index (type_spec
);
6476 guint32 cols
[MONO_TYPESPEC_SIZE
];
6478 MonoType
*type
, *type2
;
6482 type
= (MonoType
*)mono_conc_hashtable_lookup (image
->typespec_cache
, GUINT_TO_POINTER (type_spec
));
6486 t
= &image
->tables
[MONO_TABLE_TYPESPEC
];
6488 mono_metadata_decode_row (t
, idx
-1, cols
, MONO_TYPESPEC_SIZE
);
6489 ptr
= mono_metadata_blob_heap (image
, cols
[MONO_TYPESPEC_SIGNATURE
]);
6491 if (!mono_verifier_verify_typespec_signature (image
, cols
[MONO_TYPESPEC_SIGNATURE
], type_spec
, error
))
6494 mono_metadata_decode_value (ptr
, &ptr
);
6496 type
= mono_metadata_parse_type_checked (image
, NULL
, 0, TRUE
, ptr
, &ptr
, error
);
6500 type2
= mono_metadata_type_dup (image
, type
);
6501 mono_metadata_free_type (type
);
6503 mono_image_lock (image
);
6505 /* We might leak some data in the image mempool if found */
6506 type
= (MonoType
*)mono_conc_hashtable_insert (image
->typespec_cache
, GUINT_TO_POINTER (type_spec
), type2
);
6510 mono_image_unlock (image
);
6517 mono_image_strndup (MonoImage
*image
, const char *data
, guint len
)
6521 return g_strndup (data
, len
);
6522 res
= (char *)mono_image_alloc (image
, len
+ 1);
6523 memcpy (res
, data
, len
);
6529 * mono_metadata_parse_marshal_spec:
6532 mono_metadata_parse_marshal_spec (MonoImage
*image
, const char *ptr
)
6534 return mono_metadata_parse_marshal_spec_full (NULL
, image
, ptr
);
6538 * If IMAGE is non-null, memory will be allocated from its mempool, otherwise it will be allocated using malloc.
6539 * PARENT_IMAGE is the image containing the marshal spec.
6542 mono_metadata_parse_marshal_spec_full (MonoImage
*image
, MonoImage
*parent_image
, const char *ptr
)
6544 MonoMarshalSpec
*res
;
6546 const char *start
= ptr
;
6548 /* fixme: this is incomplete, but I cant find more infos in the specs */
6551 res
= (MonoMarshalSpec
*)mono_image_alloc0 (image
, sizeof (MonoMarshalSpec
));
6553 res
= g_new0 (MonoMarshalSpec
, 1);
6555 len
= mono_metadata_decode_value (ptr
, &ptr
);
6556 res
->native
= (MonoMarshalNative
)*ptr
++;
6558 if (res
->native
== MONO_NATIVE_LPARRAY
) {
6559 res
->data
.array_data
.param_num
= -1;
6560 res
->data
.array_data
.num_elem
= -1;
6561 res
->data
.array_data
.elem_mult
= -1;
6563 if (ptr
- start
<= len
)
6564 res
->data
.array_data
.elem_type
= (MonoMarshalNative
)*ptr
++;
6565 if (ptr
- start
<= len
)
6566 res
->data
.array_data
.param_num
= mono_metadata_decode_value (ptr
, &ptr
);
6567 if (ptr
- start
<= len
)
6568 res
->data
.array_data
.num_elem
= mono_metadata_decode_value (ptr
, &ptr
);
6569 if (ptr
- start
<= len
) {
6571 * LAMESPEC: Older spec versions say this parameter comes before
6572 * num_elem. Never spec versions don't talk about elem_mult at
6573 * all, but csc still emits it, and it is used to distinguish
6574 * between param_num being 0, and param_num being omitted.
6575 * So if (param_num == 0) && (num_elem > 0), then
6576 * elem_mult == 0 -> the array size is num_elem
6577 * elem_mult == 1 -> the array size is @param_num + num_elem
6579 res
->data
.array_data
.elem_mult
= mono_metadata_decode_value (ptr
, &ptr
);
6583 if (res
->native
== MONO_NATIVE_BYVALTSTR
) {
6584 if (ptr
- start
<= len
)
6585 res
->data
.array_data
.num_elem
= mono_metadata_decode_value (ptr
, &ptr
);
6588 if (res
->native
== MONO_NATIVE_BYVALARRAY
) {
6589 if (ptr
- start
<= len
)
6590 res
->data
.array_data
.num_elem
= mono_metadata_decode_value (ptr
, &ptr
);
6593 if (res
->native
== MONO_NATIVE_CUSTOM
) {
6594 /* skip unused type guid */
6595 len
= mono_metadata_decode_value (ptr
, &ptr
);
6597 /* skip unused native type name */
6598 len
= mono_metadata_decode_value (ptr
, &ptr
);
6600 /* read custom marshaler type name */
6601 len
= mono_metadata_decode_value (ptr
, &ptr
);
6602 res
->data
.custom_data
.custom_name
= mono_image_strndup (image
, ptr
, len
);
6604 /* read cookie string */
6605 len
= mono_metadata_decode_value (ptr
, &ptr
);
6606 res
->data
.custom_data
.cookie
= mono_image_strndup (image
, ptr
, len
);
6607 res
->data
.custom_data
.image
= parent_image
;
6610 if (res
->native
== MONO_NATIVE_SAFEARRAY
) {
6611 res
->data
.safearray_data
.elem_type
= (MonoMarshalVariant
)0;
6612 res
->data
.safearray_data
.num_elem
= 0;
6613 if (ptr
- start
<= len
)
6614 res
->data
.safearray_data
.elem_type
= (MonoMarshalVariant
)*ptr
++;
6615 if (ptr
- start
<= len
)
6616 res
->data
.safearray_data
.num_elem
= *ptr
++;
6622 * mono_metadata_free_marshal_spec:
6625 mono_metadata_free_marshal_spec (MonoMarshalSpec
*spec
)
6630 if (spec
->native
== MONO_NATIVE_CUSTOM
) {
6631 g_free (spec
->data
.custom_data
.custom_name
);
6632 g_free (spec
->data
.custom_data
.cookie
);
6638 * mono_type_to_unmanaged:
6639 * The value pointed to by \p conv will contain the kind of marshalling required for this
6640 * particular type one of the \c MONO_MARSHAL_CONV_ enumeration values.
6641 * \returns A \c MonoMarshalNative enumeration value (<code>MONO_NATIVE_</code>) value
6642 * describing the underlying native reprensetation of the type.
6644 guint32
// FIXMEcxx MonoMarshalNative
6645 mono_type_to_unmanaged (MonoType
*type
, MonoMarshalSpec
*mspec
, gboolean as_field
,
6646 gboolean unicode
, MonoMarshalConv
*conv
)
6648 MonoMarshalConv dummy_conv
;
6654 *conv
= MONO_MARSHAL_CONV_NONE
;
6657 return MONO_NATIVE_UINT
;
6661 case MONO_TYPE_BOOLEAN
:
6663 switch (mspec
->native
) {
6664 case MONO_NATIVE_VARIANTBOOL
:
6665 *conv
= MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
;
6666 return MONO_NATIVE_VARIANTBOOL
;
6667 case MONO_NATIVE_BOOLEAN
:
6668 *conv
= MONO_MARSHAL_CONV_BOOL_I4
;
6669 return MONO_NATIVE_BOOLEAN
;
6670 case MONO_NATIVE_I1
:
6671 case MONO_NATIVE_U1
:
6672 return mspec
->native
;
6674 g_error ("cant marshal bool to native type %02x", mspec
->native
);
6677 *conv
= MONO_MARSHAL_CONV_BOOL_I4
;
6678 return MONO_NATIVE_BOOLEAN
;
6679 case MONO_TYPE_CHAR
:
6681 switch (mspec
->native
) {
6682 case MONO_NATIVE_U2
:
6683 case MONO_NATIVE_U1
:
6684 return mspec
->native
;
6686 g_error ("cant marshal char to native type %02x", mspec
->native
);
6689 return unicode
? MONO_NATIVE_U2
: MONO_NATIVE_U1
;
6690 case MONO_TYPE_I1
: return MONO_NATIVE_I1
;
6691 case MONO_TYPE_U1
: return MONO_NATIVE_U1
;
6692 case MONO_TYPE_I2
: return MONO_NATIVE_I2
;
6693 case MONO_TYPE_U2
: return MONO_NATIVE_U2
;
6694 case MONO_TYPE_I4
: return MONO_NATIVE_I4
;
6695 case MONO_TYPE_U4
: return MONO_NATIVE_U4
;
6696 case MONO_TYPE_I8
: return MONO_NATIVE_I8
;
6697 case MONO_TYPE_U8
: return MONO_NATIVE_U8
;
6698 case MONO_TYPE_R4
: return MONO_NATIVE_R4
;
6699 case MONO_TYPE_R8
: return MONO_NATIVE_R8
;
6700 case MONO_TYPE_STRING
:
6702 switch (mspec
->native
) {
6703 case MONO_NATIVE_BSTR
:
6704 *conv
= MONO_MARSHAL_CONV_STR_BSTR
;
6705 return MONO_NATIVE_BSTR
;
6706 case MONO_NATIVE_LPSTR
:
6707 *conv
= MONO_MARSHAL_CONV_STR_LPSTR
;
6708 return MONO_NATIVE_LPSTR
;
6709 case MONO_NATIVE_LPWSTR
:
6710 *conv
= MONO_MARSHAL_CONV_STR_LPWSTR
;
6711 return MONO_NATIVE_LPWSTR
;
6712 case MONO_NATIVE_LPTSTR
:
6713 *conv
= MONO_MARSHAL_CONV_STR_LPTSTR
;
6714 return MONO_NATIVE_LPTSTR
;
6715 case MONO_NATIVE_ANSIBSTR
:
6716 *conv
= MONO_MARSHAL_CONV_STR_ANSIBSTR
;
6717 return MONO_NATIVE_ANSIBSTR
;
6718 case MONO_NATIVE_TBSTR
:
6719 *conv
= MONO_MARSHAL_CONV_STR_TBSTR
;
6720 return MONO_NATIVE_TBSTR
;
6721 case MONO_NATIVE_UTF8STR
:
6722 *conv
= MONO_MARSHAL_CONV_STR_UTF8STR
;
6723 return MONO_NATIVE_UTF8STR
;
6724 case MONO_NATIVE_BYVALTSTR
:
6726 *conv
= MONO_MARSHAL_CONV_STR_BYVALWSTR
;
6728 *conv
= MONO_MARSHAL_CONV_STR_BYVALSTR
;
6729 return MONO_NATIVE_BYVALTSTR
;
6731 g_error ("Can not marshal string to native type '%02x': Invalid managed/unmanaged type combination (String fields must be paired with LPStr, LPWStr, BStr or ByValTStr).", mspec
->native
);
6735 *conv
= MONO_MARSHAL_CONV_STR_LPWSTR
;
6736 return MONO_NATIVE_LPWSTR
;
6739 *conv
= MONO_MARSHAL_CONV_STR_LPSTR
;
6740 return MONO_NATIVE_LPSTR
;
6742 case MONO_TYPE_PTR
: return MONO_NATIVE_UINT
;
6743 case MONO_TYPE_VALUETYPE
: /*FIXME*/
6744 if (m_class_is_enumtype (type
->data
.klass
)) {
6745 t
= mono_class_enum_basetype_internal (type
->data
.klass
)->type
;
6748 if (type
->data
.klass
== mono_class_try_get_handleref_class ()){
6749 *conv
= MONO_MARSHAL_CONV_HANDLEREF
;
6750 return MONO_NATIVE_INT
;
6752 return MONO_NATIVE_STRUCT
;
6753 case MONO_TYPE_SZARRAY
:
6754 case MONO_TYPE_ARRAY
:
6756 switch (mspec
->native
) {
6757 case MONO_NATIVE_BYVALARRAY
:
6758 if ((m_class_get_element_class (type
->data
.klass
) == mono_defaults
.char_class
) && !unicode
)
6759 *conv
= MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
;
6761 *conv
= MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
;
6762 return MONO_NATIVE_BYVALARRAY
;
6763 case MONO_NATIVE_SAFEARRAY
:
6764 *conv
= MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
;
6765 return MONO_NATIVE_SAFEARRAY
;
6766 case MONO_NATIVE_LPARRAY
:
6767 *conv
= MONO_MARSHAL_CONV_ARRAY_LPARRAY
;
6768 return MONO_NATIVE_LPARRAY
;
6770 g_error ("cant marshal array as native type %02x", mspec
->native
);
6774 *conv
= MONO_MARSHAL_CONV_ARRAY_LPARRAY
;
6775 return MONO_NATIVE_LPARRAY
;
6776 case MONO_TYPE_I
: return MONO_NATIVE_INT
;
6777 case MONO_TYPE_U
: return MONO_NATIVE_UINT
;
6778 case MONO_TYPE_CLASS
:
6779 case MONO_TYPE_OBJECT
: {
6780 /* FIXME : we need to handle ArrayList and StringBuilder here, probably */
6782 switch (mspec
->native
) {
6783 case MONO_NATIVE_STRUCT
:
6784 *conv
= MONO_MARSHAL_CONV_OBJECT_STRUCT
;
6785 return MONO_NATIVE_STRUCT
;
6786 case MONO_NATIVE_CUSTOM
:
6787 return MONO_NATIVE_CUSTOM
;
6788 case MONO_NATIVE_INTERFACE
:
6789 *conv
= MONO_MARSHAL_CONV_OBJECT_INTERFACE
;
6790 return MONO_NATIVE_INTERFACE
;
6791 case MONO_NATIVE_IDISPATCH
:
6792 *conv
= MONO_MARSHAL_CONV_OBJECT_IDISPATCH
;
6793 return MONO_NATIVE_IDISPATCH
;
6794 case MONO_NATIVE_IUNKNOWN
:
6795 *conv
= MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
;
6796 return MONO_NATIVE_IUNKNOWN
;
6797 case MONO_NATIVE_FUNC
:
6798 if (t
== MONO_TYPE_CLASS
&& (type
->data
.klass
== mono_defaults
.multicastdelegate_class
||
6799 type
->data
.klass
== mono_defaults
.delegate_class
||
6800 m_class_get_parent (type
->data
.klass
) == mono_defaults
.multicastdelegate_class
)) {
6801 *conv
= MONO_MARSHAL_CONV_DEL_FTN
;
6802 return MONO_NATIVE_FUNC
;
6806 g_error ("cant marshal object as native type %02x", mspec
->native
);
6809 if (t
== MONO_TYPE_CLASS
&& (type
->data
.klass
== mono_defaults
.multicastdelegate_class
||
6810 type
->data
.klass
== mono_defaults
.delegate_class
||
6811 m_class_get_parent (type
->data
.klass
) == mono_defaults
.multicastdelegate_class
)) {
6812 *conv
= MONO_MARSHAL_CONV_DEL_FTN
;
6813 return MONO_NATIVE_FUNC
;
6815 if (mono_class_try_get_safehandle_class () && type
->data
.klass
!= NULL
&&
6816 mono_class_is_subclass_of_internal (type
->data
.klass
, mono_class_try_get_safehandle_class (), FALSE
)){
6817 *conv
= MONO_MARSHAL_CONV_SAFEHANDLE
;
6818 return MONO_NATIVE_INT
;
6821 if (t
== MONO_TYPE_CLASS
&& mono_cominterop_is_interface (type
->data
.klass
)){
6822 *conv
= MONO_MARSHAL_CONV_OBJECT_INTERFACE
;
6823 return MONO_NATIVE_INTERFACE
;
6826 *conv
= MONO_MARSHAL_CONV_OBJECT_STRUCT
;
6827 return MONO_NATIVE_STRUCT
;
6829 case MONO_TYPE_FNPTR
: return MONO_NATIVE_FUNC
;
6830 case MONO_TYPE_GENERICINST
:
6831 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
6834 case MONO_TYPE_TYPEDBYREF
:
6836 g_error ("type 0x%02x not handled in marshal", t
);
6838 return MONO_NATIVE_MAX
;
6842 * mono_metadata_get_marshal_info:
6845 mono_metadata_get_marshal_info (MonoImage
*meta
, guint32 idx
, gboolean is_field
)
6848 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_FIELDMARSHAL
];
6854 loc
.col_idx
= MONO_FIELD_MARSHAL_PARENT
;
6855 loc
.idx
= ((idx
+ 1) << MONO_HAS_FIELD_MARSHAL_BITS
) | (is_field
? MONO_HAS_FIELD_MARSHAL_FIELDSREF
: MONO_HAS_FIELD_MARSHAL_PARAMDEF
);
6857 /* FIXME: Index translation */
6859 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
6862 return mono_metadata_blob_heap (meta
, mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_FIELD_MARSHAL_NATIVE_TYPE
));
6866 mono_method_from_method_def_or_ref (MonoImage
*m
, guint32 tok
, MonoGenericContext
*context
, MonoError
*error
)
6868 MonoMethod
*result
= NULL
;
6869 guint32 idx
= tok
>> MONO_METHODDEFORREF_BITS
;
6873 switch (tok
& MONO_METHODDEFORREF_MASK
) {
6874 case MONO_METHODDEFORREF_METHODDEF
:
6875 result
= mono_get_method_checked (m
, MONO_TOKEN_METHOD_DEF
| idx
, NULL
, context
, error
);
6877 case MONO_METHODDEFORREF_METHODREF
:
6878 result
= mono_get_method_checked (m
, MONO_TOKEN_MEMBER_REF
| idx
, NULL
, context
, error
);
6881 mono_error_set_bad_image (error
, m
, "Invalid MethodDefOfRef token %x", tok
);
6888 * mono_class_get_overrides_full:
6890 * Compute the method overrides belonging to class @type_token in @overrides, and the number of overrides in @num_overrides.
6894 mono_class_get_overrides_full (MonoImage
*image
, guint32 type_token
, MonoMethod
***overrides
, gint32
*num_overrides
, MonoGenericContext
*generic_context
, MonoError
*error
)
6897 MonoTableInfo
*tdef
= &image
->tables
[MONO_TABLE_METHODIMPL
];
6900 guint32 cols
[MONO_METHODIMPL_SIZE
];
6901 MonoMethod
**result
;
6913 loc
.col_idx
= MONO_METHODIMPL_CLASS
;
6914 loc
.idx
= mono_metadata_token_index (type_token
);
6916 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
6922 * We may end up in the middle of the rows...
6925 if (loc
.idx
== mono_metadata_decode_row_col (tdef
, start
- 1, MONO_METHODIMPL_CLASS
))
6930 while (end
< tdef
->rows
) {
6931 if (loc
.idx
== mono_metadata_decode_row_col (tdef
, end
, MONO_METHODIMPL_CLASS
))
6937 result
= g_new (MonoMethod
*, num
* 2);
6938 for (i
= 0; i
< num
; ++i
) {
6941 if (!mono_verifier_verify_methodimpl_row (image
, start
+ i
, error
))
6944 mono_metadata_decode_row (tdef
, start
+ i
, cols
, MONO_METHODIMPL_SIZE
);
6945 method
= mono_method_from_method_def_or_ref (image
, cols
[MONO_METHODIMPL_DECLARATION
], generic_context
, error
);
6949 result
[i
* 2] = method
;
6950 method
= mono_method_from_method_def_or_ref (image
, cols
[MONO_METHODIMPL_BODY
], generic_context
, error
);
6954 result
[i
* 2 + 1] = method
;
6957 if (!is_ok (error
)) {
6963 *overrides
= result
;
6965 *num_overrides
= num
;
6970 * mono_guid_to_string:
6972 * Converts a 16 byte Microsoft GUID to the standard string representation.
6975 mono_guid_to_string (const guint8
*guid
)
6977 return g_strdup_printf ("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
6978 guid
[3], guid
[2], guid
[1], guid
[0],
6982 guid
[10], guid
[11], guid
[12], guid
[13], guid
[14], guid
[15]);
6986 * mono_guid_to_string_minimal:
6988 * Converts a 16 byte Microsoft GUID to lower case no '-' representation..
6991 mono_guid_to_string_minimal (const guint8
*guid
)
6993 return g_strdup_printf ("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
6994 guid
[3], guid
[2], guid
[1], guid
[0],
6998 guid
[10], guid
[11], guid
[12], guid
[13], guid
[14], guid
[15]);
7001 get_constraints (MonoImage
*image
, int owner
, MonoClass
***constraints
, MonoGenericContainer
*container
, MonoError
*error
)
7003 MonoTableInfo
*tdef
= &image
->tables
[MONO_TABLE_GENERICPARAMCONSTRAINT
];
7004 guint32 cols
[MONO_GENPARCONSTRAINT_SIZE
];
7005 guint32 i
, token
, found
;
7006 MonoClass
*klass
, **res
;
7007 GSList
*cons
= NULL
, *tmp
;
7008 MonoGenericContext
*context
= &container
->context
;
7012 *constraints
= NULL
;
7014 for (i
= 0; i
< tdef
->rows
; ++i
) {
7015 mono_metadata_decode_row (tdef
, i
, cols
, MONO_GENPARCONSTRAINT_SIZE
);
7016 if (cols
[MONO_GENPARCONSTRAINT_GENERICPAR
] == owner
) {
7017 token
= mono_metadata_token_from_dor (cols
[MONO_GENPARCONSTRAINT_CONSTRAINT
]);
7018 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, context
, error
);
7020 g_slist_free (cons
);
7023 cons
= g_slist_append (cons
, klass
);
7026 /* contiguous list finished */
7033 res
= (MonoClass
**)mono_image_alloc0 (image
, sizeof (MonoClass
*) * (found
+ 1));
7034 for (i
= 0, tmp
= cons
; i
< found
; ++i
, tmp
= tmp
->next
) {
7035 res
[i
] = (MonoClass
*)tmp
->data
;
7037 g_slist_free (cons
);
7043 * mono_metadata_get_generic_param_row:
7046 * @token: TypeOrMethodDef token, owner for GenericParam
7047 * @owner: coded token, set on return
7049 * Returns: 1-based row-id in the GenericParam table whose
7050 * owner is @token. 0 if not found.
7053 mono_metadata_get_generic_param_row (MonoImage
*image
, guint32 token
, guint32
*owner
)
7055 MonoTableInfo
*tdef
= &image
->tables
[MONO_TABLE_GENERICPARAM
];
7062 if (mono_metadata_token_table (token
) == MONO_TABLE_TYPEDEF
)
7063 *owner
= MONO_TYPEORMETHOD_TYPE
;
7064 else if (mono_metadata_token_table (token
) == MONO_TABLE_METHOD
)
7065 *owner
= MONO_TYPEORMETHOD_METHOD
;
7067 g_error ("wrong token %x to get_generic_param_row", token
);
7070 *owner
|= mono_metadata_token_index (token
) << MONO_TYPEORMETHOD_BITS
;
7073 loc
.col_idx
= MONO_GENERICPARAM_OWNER
;
7076 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
7079 /* Find the first entry by searching backwards */
7080 while ((loc
.result
> 0) && (mono_metadata_decode_row_col (tdef
, loc
.result
- 1, MONO_GENERICPARAM_OWNER
) == loc
.idx
))
7083 return loc
.result
+ 1;
7087 mono_metadata_has_generic_params (MonoImage
*image
, guint32 token
)
7090 return mono_metadata_get_generic_param_row (image
, token
, &owner
);
7094 * Memory is allocated from IMAGE's mempool.
7097 mono_metadata_load_generic_param_constraints_checked (MonoImage
*image
, guint32 token
,
7098 MonoGenericContainer
*container
, MonoError
*error
)
7101 guint32 start_row
, i
, owner
;
7104 if (! (start_row
= mono_metadata_get_generic_param_row (image
, token
, &owner
)))
7106 for (i
= 0; i
< container
->type_argc
; i
++) {
7107 if (!get_constraints (image
, start_row
+ i
, &mono_generic_container_get_param_info (container
, i
)->constraints
, container
, error
)) {
7115 * mono_metadata_load_generic_params:
7117 * Load the type parameters from the type or method definition @token.
7119 * Use this method after parsing a type or method definition to figure out whether it's a generic
7120 * type / method. When parsing a method definition, @parent_container points to the generic container
7121 * of the current class, if any.
7123 * Note: This method does not load the constraints: for typedefs, this has to be done after fully
7124 * creating the type.
7126 * Returns: NULL if @token is not a generic type or method definition or the new generic container.
7128 * LOCKING: Acquires the loader lock
7131 MonoGenericContainer
*
7132 mono_metadata_load_generic_params (MonoImage
*image
, guint32 token
, MonoGenericContainer
*parent_container
, gpointer real_owner
)
7134 MonoTableInfo
*tdef
= &image
->tables
[MONO_TABLE_GENERICPARAM
];
7135 guint32 cols
[MONO_GENERICPARAM_SIZE
];
7136 guint32 i
, owner
= 0, n
;
7137 MonoGenericContainer
*container
;
7138 MonoGenericParamFull
*params
;
7139 MonoGenericContext
*context
;
7140 gboolean is_method
= mono_metadata_token_table (token
) == MONO_TABLE_METHOD
;
7141 gboolean is_anonymous
= real_owner
== NULL
;
7143 if (!(i
= mono_metadata_get_generic_param_row (image
, token
, &owner
)))
7145 mono_metadata_decode_row (tdef
, i
- 1, cols
, MONO_GENERICPARAM_SIZE
);
7148 container
= (MonoGenericContainer
*)mono_image_alloc0 (image
, sizeof (MonoGenericContainer
));
7149 container
->is_anonymous
= is_anonymous
;
7151 container
->owner
.image
= image
;
7154 container
->owner
.method
= (MonoMethod
*)real_owner
;
7156 container
->owner
.klass
= (MonoClass
*)real_owner
;
7160 params
= (MonoGenericParamFull
*)g_realloc (params
, sizeof (MonoGenericParamFull
) * n
);
7161 memset (¶ms
[n
- 1], 0, sizeof (MonoGenericParamFull
));
7162 params
[n
- 1].owner
= container
;
7163 params
[n
- 1].num
= cols
[MONO_GENERICPARAM_NUMBER
];
7164 params
[n
- 1].info
.token
= i
| MONO_TOKEN_GENERIC_PARAM
;
7165 params
[n
- 1].info
.flags
= cols
[MONO_GENERICPARAM_FLAGS
];
7166 params
[n
- 1].info
.name
= mono_metadata_string_heap (image
, cols
[MONO_GENERICPARAM_NAME
]);
7167 if (params
[n
- 1].num
!= n
- 1)
7168 g_warning ("GenericParam table unsorted or hole in generic param sequence: token %d", i
);
7169 if (++i
> tdef
->rows
)
7171 mono_metadata_decode_row (tdef
, i
- 1, cols
, MONO_GENERICPARAM_SIZE
);
7172 } while (cols
[MONO_GENERICPARAM_OWNER
] == owner
);
7174 container
->type_argc
= n
;
7175 container
->type_params
= (MonoGenericParamFull
*)mono_image_alloc0 (image
, sizeof (MonoGenericParamFull
) * n
);
7176 memcpy (container
->type_params
, params
, sizeof (MonoGenericParamFull
) * n
);
7178 container
->parent
= parent_container
;
7181 container
->is_method
= 1;
7183 g_assert (container
->parent
== NULL
|| container
->is_method
);
7185 context
= &container
->context
;
7186 if (container
->is_method
) {
7187 context
->class_inst
= container
->parent
? container
->parent
->context
.class_inst
: NULL
;
7188 context
->method_inst
= mono_get_shared_generic_inst (container
);
7190 context
->class_inst
= mono_get_shared_generic_inst (container
);
7197 mono_get_shared_generic_inst (MonoGenericContainer
*container
)
7199 MonoType
**type_argv
;
7201 MonoGenericInst
*nginst
;
7204 type_argv
= g_new0 (MonoType
*, container
->type_argc
);
7205 helper
= g_new0 (MonoType
, container
->type_argc
);
7207 for (i
= 0; i
< container
->type_argc
; i
++) {
7208 MonoType
*t
= &helper
[i
];
7210 t
->type
= container
->is_method
? MONO_TYPE_MVAR
: MONO_TYPE_VAR
;
7211 t
->data
.generic_param
= mono_generic_container_get_param (container
, i
);
7216 nginst
= mono_metadata_get_generic_inst (container
->type_argc
, type_argv
);
7225 * mono_type_is_byref:
7226 * \param type the \c MonoType operated on
7227 * \returns TRUE if \p type represents a type passed by reference,
7231 mono_type_is_byref (MonoType
*type
)
7234 MONO_ENTER_GC_UNSAFE
; // FIXME slow
7235 result
= mono_type_is_byref_internal (type
);
7236 MONO_EXIT_GC_UNSAFE
;
7241 * mono_type_get_type:
7242 * \param type the \c MonoType operated on
7243 * \returns the IL type value for \p type. This is one of the \c MonoTypeEnum
7244 * enum members like \c MONO_TYPE_I4 or \c MONO_TYPE_STRING.
7247 mono_type_get_type (MonoType
*type
)
7249 return mono_type_get_type_internal (type
);
7253 * mono_type_get_signature:
7254 * \param type the \c MonoType operated on
7255 * It is only valid to call this function if \p type is a \c MONO_TYPE_FNPTR .
7256 * \returns the \c MonoMethodSignature pointer that describes the signature
7257 * of the function pointer \p type represents.
7259 MonoMethodSignature
*
7260 mono_type_get_signature (MonoType
*type
)
7262 return mono_type_get_signature_internal (type
);
7266 * mono_type_get_class:
7267 * \param type the \c MonoType operated on
7268 * It is only valid to call this function if \p type is a \c MONO_TYPE_CLASS or a
7269 * \c MONO_TYPE_VALUETYPE . For more general functionality, use \c mono_class_from_mono_type_internal,
7271 * \returns the \c MonoClass pointer that describes the class that \p type represents.
7274 mono_type_get_class (MonoType
*type
)
7276 /* FIXME: review the runtime users before adding the assert here */
7277 return mono_type_get_class_internal (type
);
7281 * mono_type_get_array_type:
7282 * \param type the \c MonoType operated on
7283 * It is only valid to call this function if \p type is a \c MONO_TYPE_ARRAY .
7284 * \returns a \c MonoArrayType struct describing the array type that \p type
7285 * represents. The info includes details such as rank, array element type
7286 * and the sizes and bounds of multidimensional arrays.
7289 mono_type_get_array_type (MonoType
*type
)
7291 return mono_type_get_array_type_internal (type
);
7295 * mono_type_get_ptr_type:
7296 * \pararm type the \c MonoType operated on
7297 * It is only valid to call this function if \p type is a \c MONO_TYPE_PTR .
7298 * \returns the \c MonoType pointer that describes the type that \p type
7299 * represents a pointer to.
7302 mono_type_get_ptr_type (MonoType
*type
)
7304 g_assert (type
->type
== MONO_TYPE_PTR
);
7305 return type
->data
.type
;
7309 * mono_type_get_modifiers:
7312 mono_type_get_modifiers (MonoType
*type
, gboolean
*is_required
, gpointer
*iter
)
7314 /* FIXME: implement */
7319 * mono_type_is_struct:
7320 * \param type the \c MonoType operated on
7321 * \returns TRUE if \p type is a struct, that is a \c ValueType but not an enum
7322 * or a basic type like \c System.Int32 . FALSE otherwise.
7325 mono_type_is_struct (MonoType
*type
)
7327 return (!type
->byref
&& ((type
->type
== MONO_TYPE_VALUETYPE
&&
7328 !m_class_is_enumtype (type
->data
.klass
)) || (type
->type
== MONO_TYPE_TYPEDBYREF
) ||
7329 ((type
->type
== MONO_TYPE_GENERICINST
) &&
7330 mono_metadata_generic_class_is_valuetype (type
->data
.generic_class
) &&
7331 !m_class_is_enumtype (type
->data
.generic_class
->container_class
))));
7335 * mono_type_is_void:
7336 * \param type the \c MonoType operated on
7337 * \returns TRUE if \p type is \c System.Void . FALSE otherwise.
7340 mono_type_is_void (MonoType
*type
)
7342 return (type
&& (type
->type
== MONO_TYPE_VOID
) && !type
->byref
);
7346 * mono_type_is_pointer:
7347 * \param type the \c MonoType operated on
7348 * \returns TRUE if \p type is a managed or unmanaged pointer type. FALSE otherwise.
7351 mono_type_is_pointer (MonoType
*type
)
7353 return (type
&& ((type
->byref
|| (type
->type
== MONO_TYPE_I
) || type
->type
== MONO_TYPE_STRING
)
7354 || (type
->type
== MONO_TYPE_SZARRAY
) || (type
->type
== MONO_TYPE_CLASS
) ||
7355 (type
->type
== MONO_TYPE_U
) || (type
->type
== MONO_TYPE_OBJECT
) ||
7356 (type
->type
== MONO_TYPE_ARRAY
) || (type
->type
== MONO_TYPE_PTR
) ||
7357 (type
->type
== MONO_TYPE_FNPTR
)));
7361 * mono_type_is_reference:
7362 * \param type the \c MonoType operated on
7363 * \returns TRUE if \p type represents an object reference. FALSE otherwise.
7366 mono_type_is_reference (MonoType
*type
)
7368 /* NOTE: changing this function to return TRUE more often may have
7369 * consequences for generic sharing in the AOT compiler. In
7370 * particular, returning TRUE for generic parameters with a 'class'
7371 * constraint may cause crashes.
7373 return (type
&& (((type
->type
== MONO_TYPE_STRING
) ||
7374 (type
->type
== MONO_TYPE_SZARRAY
) || (type
->type
== MONO_TYPE_CLASS
) ||
7375 (type
->type
== MONO_TYPE_OBJECT
) || (type
->type
== MONO_TYPE_ARRAY
)) ||
7376 ((type
->type
== MONO_TYPE_GENERICINST
) &&
7377 !mono_metadata_generic_class_is_valuetype (type
->data
.generic_class
))));
7381 mono_type_is_generic_parameter (MonoType
*type
)
7383 return !type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
);
7387 * mono_signature_get_return_type:
7388 * \param sig the method signature inspected
7389 * \returns the return type of the method signature \p sig
7392 mono_signature_get_return_type (MonoMethodSignature
*sig
)
7395 MONO_ENTER_GC_UNSAFE
;
7397 MONO_EXIT_GC_UNSAFE
;
7402 * mono_signature_get_params:
7403 * \param sig the method signature inspected
7404 * \param iter pointer to an iterator
7405 * Iterates over the parameters for the method signature \p sig.
7406 * A \c void* pointer must be initialized to NULL to start the iteration
7407 * and its address is passed to this function repeteadly until it returns
7409 * \returns the next parameter type of the method signature \p sig,
7410 * NULL when finished.
7413 mono_signature_get_params (MonoMethodSignature
*sig
, gpointer
*iter
)
7416 MONO_ENTER_GC_UNSAFE
;
7417 result
= mono_signature_get_params_internal (sig
, iter
);
7418 MONO_EXIT_GC_UNSAFE
;
7423 mono_signature_get_params_internal (MonoMethodSignature
*sig
, gpointer
*iter
)
7429 /* start from the first */
7430 if (sig
->param_count
) {
7431 *iter
= &sig
->params
[0];
7432 return sig
->params
[0];
7438 type
= (MonoType
**)*iter
;
7440 if (type
< &sig
->params
[sig
->param_count
]) {
7448 * mono_signature_get_param_count:
7449 * \param sig the method signature inspected
7450 * \returns the number of parameters in the method signature \p sig.
7453 mono_signature_get_param_count (MonoMethodSignature
*sig
)
7455 return sig
->param_count
;
7459 * mono_signature_get_call_conv:
7460 * \param sig the method signature inspected
7461 * \returns the call convention of the method signature \p sig.
7464 mono_signature_get_call_conv (MonoMethodSignature
*sig
)
7466 return sig
->call_convention
;
7470 * mono_signature_vararg_start:
7471 * \param sig the method signature inspected
7472 * \returns the number of the first vararg parameter in the
7473 * method signature \param sig. \c -1 if this is not a vararg signature.
7476 mono_signature_vararg_start (MonoMethodSignature
*sig
)
7478 return sig
->sentinelpos
;
7482 * mono_signature_is_instance:
7483 * \param sig the method signature inspected
7484 * \returns TRUE if this the method signature \p sig has an implicit
7485 * first instance argument. FALSE otherwise.
7488 mono_signature_is_instance (MonoMethodSignature
*sig
)
7490 return sig
->hasthis
;
7494 * mono_signature_param_is_out
7495 * \param sig the method signature inspected
7496 * \param param_num the 0-based index of the inspected parameter
7497 * \returns TRUE if the parameter is an out parameter, FALSE
7501 mono_signature_param_is_out (MonoMethodSignature
*sig
, int param_num
)
7503 g_assert (param_num
>= 0 && param_num
< sig
->param_count
);
7504 return (sig
->params
[param_num
]->attrs
& PARAM_ATTRIBUTE_OUT
) != 0;
7508 * mono_signature_explicit_this:
7509 * \param sig the method signature inspected
7510 * \returns TRUE if this the method signature \p sig has an explicit
7511 * instance argument. FALSE otherwise.
7514 mono_signature_explicit_this (MonoMethodSignature
*sig
)
7516 return sig
->explicit_this
;
7519 /* for use with allocated memory blocks (assumes alignment is to 8 bytes) */
7521 mono_aligned_addr_hash (gconstpointer ptr
)
7523 /* Same hashing we use for objects */
7524 return (GPOINTER_TO_UINT (ptr
) >> 3) * 2654435761u;
7528 * If @field belongs to an inflated generic class, return the corresponding field of the
7529 * generic type definition class.
7532 mono_metadata_get_corresponding_field_from_generic_type_definition (MonoClassField
*field
)
7537 if (!mono_class_is_ginst (field
->parent
))
7540 gtd
= mono_class_get_generic_class (field
->parent
)->container_class
;
7541 offset
= field
- m_class_get_fields (field
->parent
);
7542 return m_class_get_fields (gtd
) + offset
;
7546 * If @event belongs to an inflated generic class, return the corresponding event of the
7547 * generic type definition class.
7550 mono_metadata_get_corresponding_event_from_generic_type_definition (MonoEvent
*event
)
7555 if (!mono_class_is_ginst (event
->parent
))
7558 gtd
= mono_class_get_generic_class (event
->parent
)->container_class
;
7559 offset
= event
- mono_class_get_event_info (event
->parent
)->events
;
7560 return mono_class_get_event_info (gtd
)->events
+ offset
;
7564 * If @property belongs to an inflated generic class, return the corresponding property of the
7565 * generic type definition class.
7568 mono_metadata_get_corresponding_property_from_generic_type_definition (MonoProperty
*property
)
7570 MonoClassPropertyInfo
*info
;
7574 if (!mono_class_is_ginst (property
->parent
))
7577 info
= mono_class_get_property_info (property
->parent
);
7578 gtd
= mono_class_get_generic_class (property
->parent
)->container_class
;
7579 offset
= property
- info
->properties
;
7580 return mono_class_get_property_info (gtd
)->properties
+ offset
;
7584 mono_method_get_wrapper_cache (MonoMethod
*method
)
7586 if (method
->is_inflated
) {
7587 MonoMethodInflated
*imethod
= (MonoMethodInflated
*)method
;
7588 return &imethod
->owner
->wrapper_caches
;
7590 return &m_class_get_image (method
->klass
)->wrapper_caches
;
7594 // This is support for the mempool reference tracking feature in checked-build, but lives in metadata.c due to use of static variables of this file.
7597 * mono_find_image_set_owner:
7599 * Find the imageset, if any, which a given pointer is located in the memory of.
7602 mono_find_image_set_owner (void *ptr
)
7604 MonoImageSet
*owner
= NULL
;
7611 for (i
= 0; !owner
&& i
< image_sets
->len
; ++i
) {
7612 MonoImageSet
*set
= (MonoImageSet
*)g_ptr_array_index (image_sets
, i
);
7613 if (mono_mempool_contains_addr (set
->mempool
, ptr
))
7618 image_sets_unlock ();
7624 mono_loader_set_strict_assembly_name_check (gboolean enabled
)
7626 check_assembly_names_strictly
= enabled
;
7630 mono_loader_get_strict_assembly_name_check (void)
7632 #if !defined(DISABLE_DESKTOP_LOADER) || defined(ENABLE_NETCORE)
7633 return check_assembly_names_strictly
;
7641 mono_type_is_aggregate_mods (const MonoType
*t
)
7646 MonoTypeWithModifiers
*full
= (MonoTypeWithModifiers
*)t
;
7648 return full
->is_aggregate
;
7651 MonoCustomModContainer
*
7652 mono_type_get_cmods (const MonoType
*t
)
7657 MonoTypeWithModifiers
*full
= (MonoTypeWithModifiers
*)t
;
7659 g_assert (!full
->is_aggregate
);
7660 return &full
->mods
.cmods
;
7663 MonoAggregateModContainer
*
7664 mono_type_get_amods (const MonoType
*t
)
7669 MonoTypeWithModifiers
*full
= (MonoTypeWithModifiers
*)t
;
7671 g_assert (full
->is_aggregate
);
7672 return full
->mods
.amods
;
7676 mono_sizeof_aggregate_modifiers (uint8_t num_mods
)
7679 accum
+= offsetof (MonoAggregateModContainer
, modifiers
);
7680 accum
+= sizeof (MonoSingleCustomMod
) * num_mods
;
7685 mono_sizeof_type_with_mods (uint8_t num_mods
, gboolean is_aggregate
)
7688 return sizeof (MonoType
);
7690 accum
+= offsetof (MonoTypeWithModifiers
, mods
);
7692 if (!is_aggregate
) {
7693 accum
+= offsetof (struct _MonoCustomModContainer
, modifiers
);
7694 accum
+= sizeof (MonoCustomMod
) * num_mods
;
7696 accum
+= offsetof (MonoAggregateModContainer
, modifiers
);
7697 accum
+= sizeof (MonoAggregateModContainer
*);
7703 mono_sizeof_type (const MonoType
*ty
)
7705 if (ty
->has_cmods
) {
7706 if (!mono_type_is_aggregate_mods (ty
)) {
7707 MonoCustomModContainer
*cmods
= mono_type_get_cmods (ty
);
7708 return mono_sizeof_type_with_mods (cmods
->count
, FALSE
);
7710 MonoAggregateModContainer
*amods
= mono_type_get_amods (ty
);
7711 return mono_sizeof_type_with_mods (amods
->count
, TRUE
);
7714 return sizeof (MonoType
);
7718 mono_type_set_amods (MonoType
*t
, MonoAggregateModContainer
*amods
)
7720 g_assert (t
->has_cmods
);
7721 MonoTypeWithModifiers
*t_full
= (MonoTypeWithModifiers
*)t
;
7722 g_assert (t_full
->is_aggregate
);
7723 g_assert (t_full
->mods
.amods
== NULL
);
7724 t_full
->mods
.amods
= amods
;