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 if (image
== mono_get_image_for_generic_param (type
->data
.generic_param
))
2564 else if (type
->data
.generic_param
->gshared_constraint
) {
2565 type
= type
->data
.generic_param
->gshared_constraint
;
2570 /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type_internal () */
2571 return image
== m_class_get_image (mono_class_from_mono_type_internal (type
));
2576 mono_type_in_image (MonoType
*type
, MonoImage
*image
)
2578 return type_in_image (type
, image
);
2582 aggregate_modifiers_in_image (MonoAggregateModContainer
*amods
, MonoImage
*image
)
2584 for (int i
= 0; i
< amods
->count
; i
++)
2585 if (type_in_image (amods
->modifiers
[i
].type
, image
))
2591 image_sets_lock (void)
2593 mono_os_mutex_lock (&image_sets_mutex
);
2597 image_sets_unlock (void)
2599 mono_os_mutex_unlock (&image_sets_mutex
);
2603 #define HASH_TABLE_SIZE 1103
2604 static MonoImageSet
*img_set_cache
[HASH_TABLE_SIZE
];
2607 mix_hash (uintptr_t source
)
2609 unsigned int hash
= source
;
2612 hash
= (((hash
* 215497) >> 16) ^ ((hash
* 1823231) + hash
));
2614 // Mix in highest bits on 64-bit systems only
2615 if (sizeof (source
) > 4)
2616 hash
= hash
^ ((source
>> 31) >> 1);
2622 hash_images (MonoImage
**images
, int nimages
)
2626 for (i
= 0; i
< nimages
; ++i
)
2627 res
+= mix_hash ((size_t)images
[i
]);
2633 compare_img_set (MonoImageSet
*set
, MonoImage
**images
, int nimages
)
2637 if (set
->nimages
!= nimages
)
2640 for (j
= 0; j
< nimages
; ++j
) {
2641 for (k
= 0; k
< nimages
; ++k
)
2642 if (set
->images
[k
] == images
[j
])
2643 break; // Break on match
2645 // If we iterated all the way through set->images, images[j] was *not* found.
2647 break; // Break on "image not found"
2650 // If we iterated all the way through images without breaking, all items in images were found in set->images
2651 return j
== nimages
;
2655 static MonoImageSet
*
2656 img_set_cache_get (MonoImage
**images
, int nimages
)
2658 guint32 hash_code
= hash_images (images
, nimages
);
2659 int index
= hash_code
% HASH_TABLE_SIZE
;
2660 MonoImageSet
*img
= img_set_cache
[index
];
2661 if (!img
|| !compare_img_set (img
, images
, nimages
)) {
2662 UnlockedIncrement (&img_set_cache_miss
);
2665 UnlockedIncrement (&img_set_cache_hit
);
2670 img_set_cache_add (MonoImageSet
*set
)
2672 guint32 hash_code
= hash_images (set
->images
, set
->nimages
);
2673 int index
= hash_code
% HASH_TABLE_SIZE
;
2674 img_set_cache
[index
] = set
;
2678 img_set_cache_remove (MonoImageSet
*is
)
2680 guint32 hash_code
= hash_images (is
->images
, is
->nimages
);
2681 int index
= hash_code
% HASH_TABLE_SIZE
;
2682 if (img_set_cache
[index
] == is
)
2683 img_set_cache
[index
] = NULL
;
2688 * Return a MonoImageSet representing the set of images in IMAGES.
2690 static MonoImageSet
*
2691 get_image_set (MonoImage
**images
, int nimages
)
2697 /* Common case: Image set contains corlib only. If we've seen that case before, we cached the set. */
2698 if (nimages
== 1 && images
[0] == mono_defaults
.corlib
&& mscorlib_image_set
)
2699 return mscorlib_image_set
;
2701 /* Happens with empty generic instances */
2702 // 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.
2704 return mscorlib_image_set
;
2706 set
= img_set_cache_get (images
, nimages
);
2713 image_sets
= g_ptr_array_new ();
2715 // Before we go on, we should check to see whether a MonoImageSet with these images already exists.
2716 // We can search the referred-by imagesets of any one of our images to do this. Arbitrarily pick one here:
2717 if (images
[0] == mono_defaults
.corlib
&& nimages
> 1)
2718 l
= images
[1]->image_sets
; // Prefer not to search the imagesets of corlib-- that will be a long list.
2720 l
= images
[0]->image_sets
;
2723 while (l
) // Iterate over selected list, looking for an imageset with members equal to our target one
2725 set
= (MonoImageSet
*)l
->data
;
2727 if (set
->nimages
== nimages
) { // Member count differs, this can't be it
2728 // Compare all members to all members-- order might be different
2729 for (j
= 0; j
< nimages
; ++j
) {
2730 for (k
= 0; k
< nimages
; ++k
)
2731 if (set
->images
[k
] == images
[j
])
2732 break; // Break on match
2734 // If we iterated all the way through set->images, images[j] was *not* found.
2736 break; // Break on "image not found"
2739 // If we iterated all the way through images without breaking, all items in images were found in set->images
2741 // Break on "found a set with equal members".
2742 // This happens in case of a hash collision with a previously cached set.
2750 // If we iterated all the way through l without breaking, the imageset does not already exist and we should create it
2752 set
= g_new0 (MonoImageSet
, 1);
2753 set
->nimages
= nimages
;
2754 set
->images
= g_new0 (MonoImage
*, nimages
);
2755 mono_os_mutex_init_recursive (&set
->lock
);
2756 for (i
= 0; i
< nimages
; ++i
)
2757 set
->images
[i
] = images
[i
];
2758 set
->gclass_cache
= mono_conc_hashtable_new_full (mono_generic_class_hash
, mono_generic_class_equal
, NULL
, (GDestroyNotify
)free_generic_class
);
2759 set
->ginst_cache
= g_hash_table_new_full (mono_metadata_generic_inst_hash
, mono_metadata_generic_inst_equal
, NULL
, (GDestroyNotify
)free_generic_inst
);
2760 set
->gmethod_cache
= g_hash_table_new_full (inflated_method_hash
, inflated_method_equal
, NULL
, (GDestroyNotify
)free_inflated_method
);
2761 set
->gsignature_cache
= g_hash_table_new_full (inflated_signature_hash
, inflated_signature_equal
, NULL
, (GDestroyNotify
)free_inflated_signature
);
2763 set
->szarray_cache
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, NULL
);
2764 set
->array_cache
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, NULL
);
2766 set
->aggregate_modifiers_cache
= g_hash_table_new_full (aggregate_modifiers_hash
, aggregate_modifiers_equal
, NULL
, (GDestroyNotify
)free_aggregate_modifiers
);
2768 for (i
= 0; i
< nimages
; ++i
)
2769 set
->images
[i
]->image_sets
= g_slist_prepend (set
->images
[i
]->image_sets
, set
);
2771 g_ptr_array_add (image_sets
, set
);
2772 UnlockedIncrement (&img_set_count
); /* locked by image_sets_lock () */
2775 /* Cache the set. If there was a cache collision, the previously cached value will be replaced. */
2776 img_set_cache_add (set
);
2778 if (nimages
== 1 && images
[0] == mono_defaults
.corlib
) {
2779 mono_memory_barrier ();
2780 mscorlib_image_set
= set
;
2783 image_sets_unlock ();
2789 delete_image_set (MonoImageSet
*set
)
2793 mono_conc_hashtable_destroy (set
->gclass_cache
);
2794 g_hash_table_destroy (set
->ginst_cache
);
2795 g_hash_table_destroy (set
->gmethod_cache
);
2796 g_hash_table_destroy (set
->gsignature_cache
);
2798 g_hash_table_destroy (set
->szarray_cache
);
2799 g_hash_table_destroy (set
->array_cache
);
2801 g_hash_table_destroy (set
->ptr_cache
);
2803 g_hash_table_destroy (set
->aggregate_modifiers_cache
);
2805 for (i
= 0; i
< set
->gshared_types_len
; ++i
) {
2806 if (set
->gshared_types
[i
])
2807 g_hash_table_destroy (set
->gshared_types
[i
]);
2809 g_free (set
->gshared_types
);
2811 mono_wrapper_caches_free (&set
->wrapper_caches
);
2815 for (i
= 0; i
< set
->nimages
; ++i
)
2816 set
->images
[i
]->image_sets
= g_slist_remove (set
->images
[i
]->image_sets
, set
);
2818 g_ptr_array_remove (image_sets
, set
);
2820 image_sets_unlock ();
2822 img_set_cache_remove (set
);
2825 mono_mempool_destroy (set
->mempool
);
2826 g_free (set
->images
);
2827 mono_os_mutex_destroy (&set
->lock
);
2832 mono_image_set_lock (MonoImageSet
*set
)
2834 mono_os_mutex_lock (&set
->lock
);
2838 mono_image_set_unlock (MonoImageSet
*set
)
2840 mono_os_mutex_unlock (&set
->lock
);
2844 mono_image_set_alloc (MonoImageSet
*set
, guint size
)
2848 mono_image_set_lock (set
);
2850 set
->mempool
= mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE
);
2851 res
= mono_mempool_alloc (set
->mempool
, size
);
2852 mono_image_set_unlock (set
);
2858 mono_image_set_alloc0 (MonoImageSet
*set
, guint size
)
2862 mono_image_set_lock (set
);
2864 set
->mempool
= mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE
);
2865 res
= mono_mempool_alloc0 (set
->mempool
, size
);
2866 mono_image_set_unlock (set
);
2872 mono_image_set_strdup (MonoImageSet
*set
, const char *s
)
2876 mono_image_set_lock (set
);
2878 set
->mempool
= mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE
);
2879 res
= mono_mempool_strdup (set
->mempool
, s
);
2880 mono_image_set_unlock (set
);
2885 // Get a descriptive string for a MonoImageSet
2886 // Callers are obligated to free buffer with g_free after use
2888 mono_image_set_description (MonoImageSet
*set
)
2890 GString
*result
= g_string_new (NULL
);
2892 g_string_append (result
, "[");
2893 for (img
= 0; img
< set
->nimages
; img
++)
2896 g_string_append (result
, ", ");
2897 g_string_append (result
, set
->images
[img
]->name
);
2899 g_string_append (result
, "]");
2900 return g_string_free (result
, FALSE
);
2904 * Structure used by the collect_..._images functions to store the image list.
2907 MonoImage
*image_buf
[64];
2909 int nimages
, images_len
;
2913 collect_data_init (CollectData
*data
)
2915 data
->images
= data
->image_buf
;
2916 data
->images_len
= 64;
2921 collect_data_free (CollectData
*data
)
2923 if (data
->images
!= data
->image_buf
)
2924 g_free (data
->images
);
2928 enlarge_data (CollectData
*data
)
2930 int new_len
= data
->images_len
< 16 ? 16 : data
->images_len
* 2;
2931 MonoImage
**d
= g_new (MonoImage
*, new_len
);
2934 g_assert_not_reached ();
2935 memcpy (d
, data
->images
, data
->images_len
);
2936 if (data
->images
!= data
->image_buf
)
2937 g_free (data
->images
);
2939 data
->images_len
= new_len
;
2943 add_image (MonoImage
*image
, CollectData
*data
)
2947 /* The arrays are small, so use a linear search instead of a hash table */
2948 for (i
= 0; i
< data
->nimages
; ++i
)
2949 if (data
->images
[i
] == image
)
2952 if (data
->nimages
== data
->images_len
)
2953 enlarge_data (data
);
2955 data
->images
[data
->nimages
++] = image
;
2959 collect_type_images (MonoType
*type
, CollectData
*data
);
2962 collect_ginst_images (MonoGenericInst
*ginst
, CollectData
*data
)
2966 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
2967 collect_type_images (ginst
->type_argv
[i
], data
);
2972 collect_gclass_images (MonoGenericClass
*gclass
, CollectData
*data
)
2974 add_image (m_class_get_image (gclass
->container_class
), data
);
2975 if (gclass
->context
.class_inst
)
2976 collect_ginst_images (gclass
->context
.class_inst
, data
);
2980 collect_signature_images (MonoMethodSignature
*sig
, CollectData
*data
)
2982 gpointer iter
= NULL
;
2985 collect_type_images (mono_signature_get_return_type (sig
), data
);
2986 while ((p
= mono_signature_get_params (sig
, &iter
)) != NULL
)
2987 collect_type_images (p
, data
);
2991 collect_inflated_signature_images (MonoInflatedMethodSignature
*sig
, CollectData
*data
)
2993 collect_signature_images (sig
->sig
, data
);
2994 if (sig
->context
.class_inst
)
2995 collect_ginst_images (sig
->context
.class_inst
, data
);
2996 if (sig
->context
.method_inst
)
2997 collect_ginst_images (sig
->context
.method_inst
, data
);
3001 collect_method_images (MonoMethodInflated
*method
, CollectData
*data
)
3003 MonoMethod
*m
= method
->declaring
;
3005 add_image (m_class_get_image (method
->declaring
->klass
), data
);
3006 if (method
->context
.class_inst
)
3007 collect_ginst_images (method
->context
.class_inst
, data
);
3008 if (method
->context
.method_inst
)
3009 collect_ginst_images (method
->context
.method_inst
, data
);
3011 * Dynamic assemblies have no references, so the images they depend on can be unloaded before them.
3013 if (image_is_dynamic (m_class_get_image (m
->klass
)))
3014 collect_signature_images (mono_method_signature_internal (m
), data
);
3018 collect_aggregate_modifiers_images (MonoAggregateModContainer
*amods
, CollectData
*data
)
3020 for (int i
= 0; i
< amods
->count
; ++i
)
3021 collect_type_images (amods
->modifiers
[i
].type
, data
);
3025 collect_type_images (MonoType
*type
, CollectData
*data
)
3028 if (G_UNLIKELY (type
->has_cmods
&& mono_type_is_aggregate_mods (type
))) {
3029 collect_aggregate_modifiers_images (mono_type_get_amods (type
), data
);
3032 switch (type
->type
) {
3033 case MONO_TYPE_GENERICINST
:
3034 collect_gclass_images (type
->data
.generic_class
, data
);
3037 type
= type
->data
.type
;
3039 case MONO_TYPE_SZARRAY
:
3040 type
= m_class_get_byval_arg (type
->data
.klass
);
3042 case MONO_TYPE_ARRAY
:
3043 type
= m_class_get_byval_arg (type
->data
.array
->eklass
);
3045 case MONO_TYPE_FNPTR
:
3046 collect_signature_images (type
->data
.method
, data
);
3049 case MONO_TYPE_MVAR
:
3051 MonoImage
*image
= mono_get_image_for_generic_param (type
->data
.generic_param
);
3052 add_image (image
, data
);
3053 type
= type
->data
.generic_param
->gshared_constraint
;
3058 case MONO_TYPE_CLASS
:
3059 case MONO_TYPE_VALUETYPE
:
3060 add_image (m_class_get_image (mono_class_from_mono_type_internal (type
)), data
);
3063 add_image (mono_defaults
.corlib
, data
);
3070 } CleanForImageUserData
;
3073 steal_gclass_in_image (gpointer key
, gpointer value
, gpointer data
)
3075 MonoGenericClass
*gclass
= (MonoGenericClass
*)key
;
3076 CleanForImageUserData
*user_data
= (CleanForImageUserData
*)data
;
3078 g_assert (gclass_in_image (gclass
, user_data
->image
));
3080 user_data
->list
= g_slist_prepend (user_data
->list
, gclass
);
3085 steal_ginst_in_image (gpointer key
, gpointer value
, gpointer data
)
3087 MonoGenericInst
*ginst
= (MonoGenericInst
*)key
;
3088 CleanForImageUserData
*user_data
= (CleanForImageUserData
*)data
;
3090 // This doesn't work during corlib compilation
3091 //g_assert (ginst_in_image (ginst, user_data->image));
3093 user_data
->list
= g_slist_prepend (user_data
->list
, ginst
);
3098 steal_aggregate_modifiers_in_image (gpointer key
, gpointer value
, gpointer data
)
3100 MonoAggregateModContainer
*amods
= (MonoAggregateModContainer
*)key
;
3101 CleanForImageUserData
*user_data
= (CleanForImageUserData
*)data
;
3103 g_assert (aggregate_modifiers_in_image (amods
, user_data
->image
));
3105 user_data
->list
= g_slist_prepend (user_data
->list
, amods
);
3110 inflated_method_in_image (gpointer key
, gpointer value
, gpointer data
)
3112 MonoImage
*image
= (MonoImage
*)data
;
3113 MonoMethodInflated
*method
= (MonoMethodInflated
*)key
;
3116 // https://bugzilla.novell.com/show_bug.cgi?id=458168
3117 g_assert (m_class_get_image (method
->declaring
->klass
) == image
||
3118 (method
->context
.class_inst
&& ginst_in_image (method
->context
.class_inst
, image
)) ||
3119 (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
)));
3125 inflated_signature_in_image (gpointer key
, gpointer value
, gpointer data
)
3127 MonoImage
*image
= (MonoImage
*)data
;
3128 MonoInflatedMethodSignature
*sig
= (MonoInflatedMethodSignature
*)key
;
3130 return signature_in_image (sig
->sig
, image
) ||
3131 (sig
->context
.class_inst
&& ginst_in_image (sig
->context
.class_inst
, image
)) ||
3132 (sig
->context
.method_inst
&& ginst_in_image (sig
->context
.method_inst
, image
));
3136 class_in_image (gpointer key
, gpointer value
, gpointer data
)
3138 MonoImage
*image
= (MonoImage
*)data
;
3139 MonoClass
*klass
= (MonoClass
*)key
;
3141 g_assert (type_in_image (m_class_get_byval_arg (klass
), image
));
3147 check_gmethod (gpointer key
, gpointer value
, gpointer data
)
3149 MonoMethodInflated
*method
= (MonoMethodInflated
*)key
;
3150 MonoImage
*image
= (MonoImage
*)data
;
3152 if (method
->context
.class_inst
)
3153 g_assert (!ginst_in_image (method
->context
.class_inst
, image
));
3154 if (method
->context
.method_inst
)
3155 g_assert (!ginst_in_image (method
->context
.method_inst
, image
));
3156 if (((MonoMethod
*)method
)->signature
)
3157 g_assert (!signature_in_image (mono_method_signature_internal ((MonoMethod
*)method
), image
));
3163 * Run a consistency check on the image set data structures.
3165 static G_GNUC_UNUSED
void
3166 check_image_sets (MonoImage
*image
)
3169 GSList
*l
= image
->image_sets
;
3174 for (i
= 0; i
< image_sets
->len
; ++i
) {
3175 MonoImageSet
*set
= (MonoImageSet
*)g_ptr_array_index (image_sets
, i
);
3177 if (!g_slist_find (l
, set
)) {
3178 g_hash_table_foreach (set
->gmethod_cache
, check_gmethod
, image
);
3184 mono_metadata_clean_for_image (MonoImage
*image
)
3186 CleanForImageUserData ginst_data
, gclass_data
, amods_data
;
3187 GSList
*l
, *set_list
;
3189 //check_image_sets (image);
3192 * The data structures could reference each other so we delete them in two phases.
3193 * This is required because of the hashing functions in gclass/ginst_cache.
3195 ginst_data
.image
= gclass_data
.image
= image
;
3196 ginst_data
.list
= gclass_data
.list
= NULL
;
3197 amods_data
.image
= image
;
3198 amods_data
.list
= NULL
;
3200 /* Collect the items to delete */
3201 /* delete_image_set () modifies the lists so make a copy */
3202 for (l
= image
->image_sets
; l
; l
= l
->next
) {
3203 MonoImageSet
*set
= (MonoImageSet
*)l
->data
;
3205 mono_image_set_lock (set
);
3206 mono_conc_hashtable_foreach_steal (set
->gclass_cache
, steal_gclass_in_image
, &gclass_data
);
3207 g_hash_table_foreach_steal (set
->ginst_cache
, steal_ginst_in_image
, &ginst_data
);
3208 g_hash_table_foreach_remove (set
->gmethod_cache
, inflated_method_in_image
, image
);
3209 g_hash_table_foreach_remove (set
->gsignature_cache
, inflated_signature_in_image
, image
);
3211 g_hash_table_foreach_steal (set
->szarray_cache
, class_in_image
, image
);
3212 g_hash_table_foreach_steal (set
->array_cache
, class_in_image
, image
);
3214 g_hash_table_foreach_steal (set
->ptr_cache
, class_in_image
, image
);
3216 g_hash_table_foreach_steal (set
->aggregate_modifiers_cache
, steal_aggregate_modifiers_in_image
, &amods_data
);
3218 mono_image_set_unlock (set
);
3221 /* Delete the removed items */
3222 for (l
= ginst_data
.list
; l
; l
= l
->next
)
3223 free_generic_inst ((MonoGenericInst
*)l
->data
);
3224 for (l
= gclass_data
.list
; l
; l
= l
->next
)
3225 free_generic_class ((MonoGenericClass
*)l
->data
);
3226 for (l
= amods_data
.list
; l
; l
= l
->next
)
3227 free_aggregate_modifiers ((MonoAggregateModContainer
*)l
->data
);
3228 g_slist_free (ginst_data
.list
);
3229 g_slist_free (gclass_data
.list
);
3230 /* delete_image_set () modifies the lists so make a copy */
3231 set_list
= g_slist_copy (image
->image_sets
);
3232 for (l
= set_list
; l
; l
= l
->next
) {
3233 MonoImageSet
*set
= (MonoImageSet
*)l
->data
;
3235 delete_image_set (set
);
3237 g_slist_free (set_list
);
3241 free_inflated_method (MonoMethodInflated
*imethod
)
3243 MonoMethod
*method
= (MonoMethod
*)imethod
;
3245 if (method
->signature
)
3246 mono_metadata_free_inflated_signature (method
->signature
);
3248 if (method
->wrapper_type
)
3249 g_free (((MonoMethodWrapper
*)method
)->method_data
);
3255 free_generic_inst (MonoGenericInst
*ginst
)
3259 /* The ginst itself is allocated from the image set mempool */
3260 for (i
= 0; i
< ginst
->type_argc
; ++i
)
3261 mono_metadata_free_type (ginst
->type_argv
[i
]);
3265 free_generic_class (MonoGenericClass
*gclass
)
3267 /* The gclass itself is allocated from the image set mempool */
3268 if (gclass
->cached_class
&& m_class_get_interface_id (gclass
->cached_class
))
3269 mono_unload_interface_id (gclass
->cached_class
);
3273 free_inflated_signature (MonoInflatedMethodSignature
*sig
)
3275 mono_metadata_free_inflated_signature (sig
->sig
);
3280 free_aggregate_modifiers (MonoAggregateModContainer
*amods
)
3282 for (int i
= 0; i
< amods
->count
; i
++)
3283 mono_metadata_free_type (amods
->modifiers
[i
].type
);
3284 /* the container itself is allocated in the image set mempool */
3288 * mono_metadata_get_inflated_signature:
3290 * Given an inflated signature and a generic context, return a canonical copy of the
3291 * signature. The returned signature might be equal to SIG or it might be a cached copy.
3293 MonoMethodSignature
*
3294 mono_metadata_get_inflated_signature (MonoMethodSignature
*sig
, MonoGenericContext
*context
)
3296 MonoInflatedMethodSignature helper
;
3297 MonoInflatedMethodSignature
*res
;
3302 helper
.context
.class_inst
= context
->class_inst
;
3303 helper
.context
.method_inst
= context
->method_inst
;
3305 collect_data_init (&data
);
3307 collect_inflated_signature_images (&helper
, &data
);
3309 set
= get_image_set (data
.images
, data
.nimages
);
3311 collect_data_free (&data
);
3313 mono_image_set_lock (set
);
3315 res
= (MonoInflatedMethodSignature
*)g_hash_table_lookup (set
->gsignature_cache
, &helper
);
3317 res
= g_new0 (MonoInflatedMethodSignature
, 1);
3319 res
->context
.class_inst
= context
->class_inst
;
3320 res
->context
.method_inst
= context
->method_inst
;
3321 g_hash_table_insert (set
->gsignature_cache
, res
, res
);
3324 mono_image_set_unlock (set
);
3330 mono_metadata_get_image_set_for_type (MonoType
*type
)
3333 CollectData image_set_data
;
3335 collect_data_init (&image_set_data
);
3336 collect_type_images (type
, &image_set_data
);
3337 set
= get_image_set (image_set_data
.images
, image_set_data
.nimages
);
3338 collect_data_free (&image_set_data
);
3344 mono_metadata_get_image_set_for_class (MonoClass
*klass
)
3346 return mono_metadata_get_image_set_for_type (m_class_get_byval_arg (klass
));
3350 mono_metadata_get_image_set_for_method (MonoMethodInflated
*method
)
3353 CollectData image_set_data
;
3355 collect_data_init (&image_set_data
);
3356 collect_method_images (method
, &image_set_data
);
3357 set
= get_image_set (image_set_data
.images
, image_set_data
.nimages
);
3358 collect_data_free (&image_set_data
);
3364 mono_metadata_get_image_set_for_aggregate_modifiers (MonoAggregateModContainer
*amods
)
3367 CollectData image_set_data
;
3368 collect_data_init (&image_set_data
);
3369 collect_aggregate_modifiers_images (amods
, &image_set_data
);
3370 set
= get_image_set (image_set_data
.images
, image_set_data
.nimages
);
3371 collect_data_free (&image_set_data
);
3377 mono_metadata_merge_image_sets (MonoImageSet
*set1
, MonoImageSet
*set2
)
3379 MonoImage
**images
= g_newa (MonoImage
*, set1
->nimages
+ set2
->nimages
);
3381 /* Add images from set1 */
3382 memcpy (images
, set1
->images
, sizeof (MonoImage
*) * set1
->nimages
);
3384 int nimages
= set1
->nimages
;
3386 /* Add images from set2 */
3387 for (int i
= 0; i
< set2
->nimages
; ++i
) {
3389 for (j
= 0; j
< set1
->nimages
; ++j
) {
3390 if (set2
->images
[i
] == set1
->images
[j
])
3393 if (j
== set1
->nimages
)
3394 images
[nimages
++] = set2
->images
[i
];
3396 return get_image_set (images
, nimages
);
3400 type_is_gtd (MonoType
*type
)
3402 switch (type
->type
) {
3403 case MONO_TYPE_CLASS
:
3404 case MONO_TYPE_VALUETYPE
:
3405 return mono_class_is_gtd (type
->data
.klass
);
3412 * mono_metadata_get_generic_inst:
3414 * Given a list of types, return a MonoGenericInst that represents that list.
3415 * The returned MonoGenericInst has its own copy of the list of types. The list
3416 * passed in the argument can be freed, modified or disposed of.
3420 mono_metadata_get_generic_inst (int type_argc
, MonoType
**type_argv
)
3422 MonoGenericInst
*ginst
;
3425 int size
= MONO_SIZEOF_GENERIC_INST
+ type_argc
* sizeof (MonoType
*);
3427 for (i
= 0; i
< type_argc
; ++i
)
3428 if (mono_class_is_open_constructed_type (type_argv
[i
]))
3430 is_open
= (i
< type_argc
);
3432 ginst
= (MonoGenericInst
*)g_alloca (size
);
3433 memset (ginst
, 0, sizeof (MonoGenericInst
));
3434 ginst
->is_open
= is_open
;
3435 ginst
->type_argc
= type_argc
;
3436 memcpy (ginst
->type_argv
, type_argv
, type_argc
* sizeof (MonoType
*));
3438 for (i
= 0; i
< type_argc
; ++i
) {
3439 MonoType
*t
= ginst
->type_argv
[i
];
3440 if (type_is_gtd (t
)) {
3441 ginst
->type_argv
[i
] = mono_class_gtd_get_canonical_inst (t
->data
.klass
);
3445 return mono_metadata_get_canonical_generic_inst (ginst
);
3449 * mono_metadata_get_canonical_generic_inst:
3450 * \param candidate an arbitrary generic instantiation
3452 * \returns the canonical generic instantiation that represents the given
3453 * candidate by identifying the image set for the candidate instantiation and
3454 * finding the instance in the image set or adding a copy of the given instance
3457 * The returned MonoGenericInst has its own copy of the list of types. The list
3458 * passed in the argument can be freed, modified or disposed of.
3462 mono_metadata_get_canonical_generic_inst (MonoGenericInst
*candidate
)
3465 int type_argc
= candidate
->type_argc
;
3466 gboolean is_open
= candidate
->is_open
;
3469 collect_data_init (&data
);
3471 collect_ginst_images (candidate
, &data
);
3473 set
= get_image_set (data
.images
, data
.nimages
);
3475 collect_data_free (&data
);
3477 mono_image_set_lock (set
);
3479 MonoGenericInst
*ginst
= (MonoGenericInst
*)g_hash_table_lookup (set
->ginst_cache
, candidate
);
3481 int size
= MONO_SIZEOF_GENERIC_INST
+ type_argc
* sizeof (MonoType
*);
3482 ginst
= (MonoGenericInst
*)mono_image_set_alloc0 (set
, size
);
3483 #ifndef MONO_SMALL_CONFIG
3484 ginst
->id
= mono_atomic_inc_i32 (&next_generic_inst_id
);
3486 ginst
->is_open
= is_open
;
3487 ginst
->type_argc
= type_argc
;
3489 for (int i
= 0; i
< type_argc
; ++i
)
3490 ginst
->type_argv
[i
] = mono_metadata_type_dup (NULL
, candidate
->type_argv
[i
]);
3492 g_hash_table_insert (set
->ginst_cache
, ginst
, ginst
);
3495 mono_image_set_unlock (set
);
3499 MonoAggregateModContainer
*
3500 mono_metadata_get_canonical_aggregate_modifiers (MonoAggregateModContainer
*candidate
)
3502 g_assert (candidate
->count
> 0);
3503 MonoImageSet
*set
= mono_metadata_get_image_set_for_aggregate_modifiers (candidate
);
3505 mono_image_set_lock (set
);
3507 MonoAggregateModContainer
*amods
= (MonoAggregateModContainer
*)g_hash_table_lookup (set
->aggregate_modifiers_cache
, candidate
);
3509 size_t size
= mono_sizeof_aggregate_modifiers (candidate
->count
);
3510 amods
= (MonoAggregateModContainer
*)mono_image_set_alloc0 (set
, size
);
3511 amods
->count
= candidate
->count
;
3512 for (int i
= 0; i
< candidate
->count
; ++i
) {
3513 amods
->modifiers
[i
].required
= candidate
->modifiers
[i
].required
;
3514 amods
->modifiers
[i
].type
= mono_metadata_type_dup (NULL
, candidate
->modifiers
[i
].type
);
3517 g_hash_table_insert (set
->aggregate_modifiers_cache
, amods
, amods
);
3519 mono_image_set_unlock (set
);
3524 mono_metadata_is_type_builder_generic_type_definition (MonoClass
*container_class
, MonoGenericInst
*inst
, gboolean is_dynamic
)
3526 MonoGenericContainer
*container
= mono_class_get_generic_container (container_class
);
3528 if (!is_dynamic
|| m_class_was_typebuilder (container_class
) || container
->type_argc
!= inst
->type_argc
)
3530 return inst
== container
->context
.class_inst
;
3534 * mono_metadata_lookup_generic_class:
3536 * Returns a MonoGenericClass with the given properties.
3540 mono_metadata_lookup_generic_class (MonoClass
*container_class
, MonoGenericInst
*inst
, gboolean is_dynamic
)
3542 MonoGenericClass
*gclass
;
3543 MonoGenericClass helper
;
3544 gboolean is_tb_open
= mono_metadata_is_type_builder_generic_type_definition (container_class
, inst
, is_dynamic
);
3548 g_assert (mono_class_get_generic_container (container_class
)->type_argc
== inst
->type_argc
);
3550 memset (&helper
, 0, sizeof(helper
)); // act like g_new0
3551 helper
.container_class
= container_class
;
3552 helper
.context
.class_inst
= inst
;
3553 helper
.is_dynamic
= is_dynamic
; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
3554 helper
.is_tb_open
= is_tb_open
;
3556 collect_data_init (&data
);
3558 collect_gclass_images (&helper
, &data
);
3560 set
= get_image_set (data
.images
, data
.nimages
);
3562 collect_data_free (&data
);
3564 gclass
= (MonoGenericClass
*)mono_conc_hashtable_lookup (set
->gclass_cache
, &helper
);
3566 /* A tripwire just to keep us honest */
3567 g_assert (!helper
.cached_class
);
3572 gclass
= mono_image_set_new0 (set
, MonoGenericClass
, 1);
3574 gclass
->is_dynamic
= 1;
3576 gclass
->is_tb_open
= is_tb_open
;
3577 gclass
->container_class
= container_class
;
3578 gclass
->context
.class_inst
= inst
;
3579 gclass
->context
.method_inst
= NULL
;
3580 gclass
->owner
= set
;
3581 if (inst
== mono_class_get_generic_container (container_class
)->context
.class_inst
&& !is_tb_open
)
3582 gclass
->cached_class
= container_class
;
3584 mono_image_set_lock (set
);
3586 MonoGenericClass
*gclass2
= (MonoGenericClass
*)mono_conc_hashtable_insert (set
->gclass_cache
, gclass
, gclass
);
3590 // g_hash_table_insert (set->gclass_cache, gclass, gclass);
3592 mono_image_set_unlock (set
);
3598 * mono_metadata_inflate_generic_inst:
3600 * Instantiate the generic instance @ginst with the context @context.
3601 * Check @error for success.
3605 mono_metadata_inflate_generic_inst (MonoGenericInst
*ginst
, MonoGenericContext
*context
, MonoError
*error
)
3607 MonoType
**type_argv
;
3608 MonoGenericInst
*nginst
= NULL
;
3613 if (!ginst
->is_open
)
3616 type_argv
= g_new0 (MonoType
*, ginst
->type_argc
);
3618 for (i
= 0; i
< ginst
->type_argc
; i
++) {
3619 type_argv
[i
] = mono_class_inflate_generic_type_checked (ginst
->type_argv
[i
], context
, error
);
3625 nginst
= mono_metadata_get_generic_inst (ginst
->type_argc
, type_argv
);
3628 for (i
= 0; i
< count
; i
++)
3629 mono_metadata_free_type (type_argv
[i
]);
3636 mono_metadata_parse_generic_inst (MonoImage
*m
, MonoGenericContainer
*container
,
3637 int count
, const char *ptr
, const char **rptr
, MonoError
*error
)
3639 MonoType
**type_argv
;
3640 MonoGenericInst
*ginst
= NULL
;
3641 int i
, parse_count
= 0;
3644 type_argv
= g_new0 (MonoType
*, count
);
3646 for (i
= 0; i
< count
; i
++) {
3647 /* this can be a transient type, mono_metadata_get_generic_inst will allocate
3648 * a canonical one, if needed.
3650 MonoType
*t
= mono_metadata_parse_type_checked (m
, container
, 0, TRUE
, ptr
, &ptr
, error
);
3660 g_assert (parse_count
== count
);
3661 ginst
= mono_metadata_get_generic_inst (count
, type_argv
);
3664 for (i
= 0; i
< parse_count
; i
++)
3665 mono_metadata_free_type (type_argv
[i
]);
3672 do_mono_metadata_parse_generic_class (MonoType
*type
, MonoImage
*m
, MonoGenericContainer
*container
,
3673 const char *ptr
, const char **rptr
, MonoError
*error
)
3675 MonoGenericInst
*inst
;
3682 // XXX how about transient?
3683 gtype
= mono_metadata_parse_type_checked (m
, NULL
, 0, FALSE
, ptr
, &ptr
, error
);
3687 gklass
= mono_class_from_mono_type_internal (gtype
);
3688 if (!mono_class_is_gtd (gklass
)) {
3689 mono_error_set_bad_image (error
, m
, "Generic instance with non-generic definition");
3693 count
= mono_metadata_decode_value (ptr
, &ptr
);
3694 inst
= mono_metadata_parse_generic_inst (m
, container
, count
, ptr
, &ptr
, error
);
3701 type
->data
.generic_class
= mono_metadata_lookup_generic_class (gklass
, inst
, FALSE
);
3707 * @gc: The generic container to normalize
3708 * @type: The kind of generic parameters the resulting generic-container should contain
3711 static MonoGenericContainer
*
3712 select_container (MonoGenericContainer
*gc
, MonoTypeEnum type
)
3714 gboolean is_var
= (type
== MONO_TYPE_VAR
);
3718 g_assert (is_var
|| type
== MONO_TYPE_MVAR
);
3721 if (gc
->is_method
|| gc
->parent
)
3723 * The current MonoGenericContainer is a generic method -> its `parent'
3724 * points to the containing class'es container.
3732 MonoGenericContainer
*
3733 mono_get_anonymous_container_for_image (MonoImage
*image
, gboolean is_mvar
)
3735 MonoGenericContainer
**container_pointer
;
3737 container_pointer
= &image
->anonymous_generic_method_container
;
3739 container_pointer
= &image
->anonymous_generic_class_container
;
3740 MonoGenericContainer
*result
= *container_pointer
;
3742 // This container has never been created; make it now.
3745 // Note this is never deallocated anywhere-- it exists for the lifetime of the image it's allocated from
3746 result
= (MonoGenericContainer
*)mono_image_alloc0 (image
, sizeof (MonoGenericContainer
));
3747 result
->owner
.image
= image
;
3748 result
->is_anonymous
= TRUE
;
3749 result
->is_method
= is_mvar
;
3751 // If another thread already made a container, use that and leak this new one.
3752 // (Technically it would currently be safe to just assign instead of CASing.)
3753 MonoGenericContainer
*exchange
= (MonoGenericContainer
*)mono_atomic_cas_ptr ((volatile gpointer
*)container_pointer
, result
, NULL
);
3760 #define FAST_GPARAM_CACHE_SIZE 16
3762 static MonoGenericParam
*
3763 lookup_anon_gparam (MonoImage
*image
, MonoGenericContainer
*container
, gint32 param_num
, gboolean is_mvar
)
3765 if (param_num
>= 0 && param_num
< FAST_GPARAM_CACHE_SIZE
) {
3766 MonoGenericParam
*cache
= is_mvar
? image
->mvar_gparam_cache_fast
: image
->var_gparam_cache_fast
;
3769 return &cache
[param_num
];
3771 MonoGenericParam key
;
3772 memset (&key
, 0, sizeof (key
));
3773 key
.owner
= container
;
3774 key
.num
= param_num
;
3775 key
.gshared_constraint
= NULL
;
3776 MonoConcurrentHashTable
*cache
= is_mvar
? image
->mvar_gparam_cache
: image
->var_gparam_cache
;
3779 return (MonoGenericParam
*)mono_conc_hashtable_lookup (cache
, &key
);
3783 static MonoGenericParam
*
3784 publish_anon_gparam_fast (MonoImage
*image
, MonoGenericContainer
*container
, gint32 param_num
)
3786 g_assert (param_num
>= 0 && param_num
< FAST_GPARAM_CACHE_SIZE
);
3787 MonoGenericParam
**cache
= container
->is_method
? &image
->mvar_gparam_cache_fast
: &image
->var_gparam_cache_fast
;
3789 mono_image_lock (image
);
3791 *cache
= (MonoGenericParam
*)mono_image_alloc0 (image
, sizeof (MonoGenericParam
) * FAST_GPARAM_CACHE_SIZE
);
3792 for (gint32 i
= 0; i
< FAST_GPARAM_CACHE_SIZE
; ++i
) {
3793 MonoGenericParam
*param
= &(*cache
)[i
];
3794 param
->owner
= container
;
3798 mono_image_unlock (image
);
3800 return &(*cache
)[param_num
];
3804 * publish_anon_gparam_slow:
3806 * Publish \p gparam anonymous generic parameter to the anon gparam cache for \p image.
3808 * LOCKING: takes the image lock.
3810 static MonoGenericParam
*
3811 publish_anon_gparam_slow (MonoImage
*image
, MonoGenericParam
*gparam
)
3813 MonoConcurrentHashTable
**cache
= gparam
->owner
->is_method
? &image
->mvar_gparam_cache
: &image
->var_gparam_cache
;
3815 mono_image_lock (image
);
3817 MonoConcurrentHashTable
*ht
= mono_conc_hashtable_new ((GHashFunc
)mono_metadata_generic_param_hash
,
3818 (GEqualFunc
) mono_metadata_generic_param_equal
);
3819 mono_atomic_store_release (cache
, ht
);
3821 mono_image_unlock (image
);
3823 MonoGenericParam
*other
= (MonoGenericParam
*)mono_conc_hashtable_insert (*cache
, gparam
, gparam
);
3824 // If another thread published first return their param, otherwise return ours.
3825 return other
? other
: gparam
;
3829 * mono_metadata_create_anon_gparam:
3830 * \param image the MonoImage that owns the anonymous generic parameter
3831 * \param param_num the parameter number
3832 * \param is_mvar TRUE if this is a method generic parameter, FALSE if it's a class generic parameter.
3834 * Returns: a new, or exisisting \c MonoGenericParam for an anonymous generic parameter with the given properties.
3836 * LOCKING: takes the image lock.
3839 mono_metadata_create_anon_gparam (MonoImage
*image
, gint32 param_num
, gboolean is_mvar
)
3841 MonoGenericContainer
*container
= mono_get_anonymous_container_for_image (image
, is_mvar
);
3842 MonoGenericParam
*gparam
= lookup_anon_gparam (image
, container
, param_num
, is_mvar
);
3845 if (param_num
>= 0 && param_num
< FAST_GPARAM_CACHE_SIZE
) {
3846 return publish_anon_gparam_fast (image
, container
, param_num
);
3848 // Create a candidate generic param and try to insert it in the cache.
3849 // If multiple threads both try to publish the same param, all but one
3850 // will leak, but that's okay.
3851 gparam
= (MonoGenericParam
*)mono_image_alloc0 (image
, sizeof (MonoGenericParam
));
3852 gparam
->owner
= container
;
3853 gparam
->num
= param_num
;
3855 return publish_anon_gparam_slow (image
, gparam
);
3860 * mono_metadata_parse_generic_param:
3861 * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
3862 * see mono_metadata_parse_type_checked() for details.
3863 * Internal routine to parse a generic type parameter.
3864 * LOCKING: Acquires the loader lock
3866 static MonoGenericParam
*
3867 mono_metadata_parse_generic_param (MonoImage
*m
, MonoGenericContainer
*generic_container
,
3868 MonoTypeEnum type
, const char *ptr
, const char **rptr
, MonoError
*error
)
3870 int index
= mono_metadata_decode_value (ptr
, &ptr
);
3876 generic_container
= select_container (generic_container
, type
);
3877 if (!generic_container
) {
3878 gboolean is_mvar
= FALSE
;
3883 case MONO_TYPE_MVAR
:
3887 g_error ("Cerating generic param object with invalid MonoType"); // This is not a generic param
3890 return mono_metadata_create_anon_gparam (m
, index
, is_mvar
);
3893 if (index
>= generic_container
->type_argc
) {
3894 mono_error_set_bad_image (error
, m
, "Invalid generic %s parameter index %d, max index is %d",
3895 generic_container
->is_method
? "method" : "type",
3896 index
, generic_container
->type_argc
);
3900 //This can't return NULL
3901 return mono_generic_container_get_param (generic_container
, index
);
3905 * mono_metadata_get_shared_type:
3907 * Return a shared instance of TYPE, if available, NULL otherwise.
3908 * Shared MonoType instances help save memory. Their contents should not be modified
3909 * by the caller. They do not need to be freed as their lifetime is bound by either
3910 * the lifetime of the runtime (builtin types), or the lifetime of the MonoClass
3911 * instance they are embedded in. If they are freed, they should be freed using
3912 * mono_metadata_free_type () instead of g_free ().
3915 mono_metadata_get_shared_type (MonoType
*type
)
3919 /* No need to use locking since nobody is modifying the hash table */
3920 if ((cached
= (MonoType
*)g_hash_table_lookup (type_cache
, type
)))
3923 switch (type
->type
){
3924 case MONO_TYPE_CLASS
:
3925 case MONO_TYPE_VALUETYPE
:
3926 if (type
== m_class_get_byval_arg (type
->data
.klass
))
3928 if (type
== m_class_get_this_arg (type
->data
.klass
))
3939 compare_type_literals (MonoImage
*image
, int class_type
, int type_type
, MonoError
*error
)
3943 /* _byval_arg.type can be zero if we're decoding a type that references a class been loading.
3944 * See mcs/test/gtest-440. and #650936.
3945 * FIXME This better be moved to the metadata verifier as it can catch more cases.
3949 /* NET 1.1 assemblies might encode string and object in a denormalized way.
3952 if (class_type
== type_type
)
3955 if (type_type
== MONO_TYPE_CLASS
) {
3956 if (class_type
== MONO_TYPE_STRING
|| class_type
== MONO_TYPE_OBJECT
)
3958 //XXX stringify this argument
3959 mono_error_set_bad_image (error
, image
, "Expected reference type but got type kind %d", class_type
);
3963 g_assert (type_type
== MONO_TYPE_VALUETYPE
);
3964 switch (class_type
) {
3965 case MONO_TYPE_BOOLEAN
:
3966 case MONO_TYPE_CHAR
:
3979 case MONO_TYPE_CLASS
:
3982 //XXX stringify this argument
3983 mono_error_set_bad_image (error
, image
, "Expected value type but got type kind %d", class_type
);
3989 verify_var_type_and_container (MonoImage
*image
, int var_type
, MonoGenericContainer
*container
, MonoError
*error
)
3992 if (var_type
== MONO_TYPE_MVAR
) {
3993 if (!container
->is_method
) { //MVAR and a method container
3994 mono_error_set_bad_image (error
, image
, "MVAR parsed in a context without a method container");
3998 if (!(!container
->is_method
|| //VAR and class container
3999 (container
->is_method
&& container
->parent
))) { //VAR and method container with parent
4000 mono_error_set_bad_image (error
, image
, "VAR parsed in a context without a class container");
4008 * do_mono_metadata_parse_type:
4009 * @type: MonoType to be filled in with the return value
4011 * @generic_context: generics_context
4012 * @transient: whenever to allocate data from the heap
4013 * @ptr: pointer to the encoded type
4014 * @rptr: pointer where the end of the encoded type is saved
4016 * Internal routine used to "fill" the contents of @type from an
4017 * allocated pointer. This is done this way to avoid doing too
4018 * many mini-allocations (particularly for the MonoFieldType which
4019 * most of the time is just a MonoType, but sometimes might be augmented).
4021 * This routine is used by mono_metadata_parse_type and
4022 * mono_metadata_parse_field_type
4024 * This extracts a Type as specified in Partition II (22.2.12)
4026 * Returns: FALSE if the type could not be loaded
4029 do_mono_metadata_parse_type (MonoType
*type
, MonoImage
*m
, MonoGenericContainer
*container
,
4030 gboolean transient
, const char *ptr
, const char **rptr
, MonoError
*error
)
4034 type
->type
= (MonoTypeEnum
)mono_metadata_decode_value (ptr
, &ptr
);
4036 switch (type
->type
){
4037 case MONO_TYPE_VOID
:
4038 case MONO_TYPE_BOOLEAN
:
4039 case MONO_TYPE_CHAR
:
4052 case MONO_TYPE_STRING
:
4053 case MONO_TYPE_OBJECT
:
4054 case MONO_TYPE_TYPEDBYREF
:
4056 case MONO_TYPE_VALUETYPE
:
4057 case MONO_TYPE_CLASS
: {
4060 token
= mono_metadata_parse_typedef_or_ref (m
, ptr
, &ptr
);
4061 klass
= mono_class_get_checked (m
, token
, error
);
4062 type
->data
.klass
= klass
;
4066 if (!compare_type_literals (m
, m_class_get_byval_arg (klass
)->type
, type
->type
, error
))
4071 case MONO_TYPE_SZARRAY
: {
4072 MonoType
*etype
= mono_metadata_parse_type_checked (m
, container
, 0, transient
, ptr
, &ptr
, error
);
4076 type
->data
.klass
= mono_class_from_mono_type_internal (etype
);
4079 mono_metadata_free_type (etype
);
4081 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.
4084 case MONO_TYPE_PTR
: {
4085 type
->data
.type
= mono_metadata_parse_type_checked (m
, container
, 0, transient
, ptr
, &ptr
, error
);
4086 if (!type
->data
.type
)
4090 case MONO_TYPE_FNPTR
: {
4091 type
->data
.method
= mono_metadata_parse_method_signature_full (m
, container
, 0, ptr
, &ptr
, error
);
4092 if (!type
->data
.method
)
4096 case MONO_TYPE_ARRAY
: {
4097 type
->data
.array
= mono_metadata_parse_array_internal (m
, container
, transient
, ptr
, &ptr
, error
);
4098 if (!type
->data
.array
)
4102 case MONO_TYPE_MVAR
:
4103 case MONO_TYPE_VAR
: {
4104 if (container
&& !verify_var_type_and_container (m
, type
->type
, container
, error
))
4107 type
->data
.generic_param
= mono_metadata_parse_generic_param (m
, container
, type
->type
, ptr
, &ptr
, error
);
4108 if (!type
->data
.generic_param
)
4113 case MONO_TYPE_GENERICINST
: {
4114 if (!do_mono_metadata_parse_generic_class (type
, m
, container
, ptr
, &ptr
, error
))
4119 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
);
4129 * mono_metadata_free_type:
4130 * \param type type to free
4132 * Free the memory allocated for type \p type which is allocated on the heap.
4135 mono_metadata_free_type (MonoType
*type
)
4137 if (type
>= builtin_types
&& type
< builtin_types
+ NBUILTIN_TYPES ())
4140 switch (type
->type
){
4141 case MONO_TYPE_OBJECT
:
4142 case MONO_TYPE_STRING
:
4143 if (!type
->data
.klass
)
4146 case MONO_TYPE_CLASS
:
4147 case MONO_TYPE_VALUETYPE
:
4148 if (type
== m_class_get_byval_arg (type
->data
.klass
) || type
== m_class_get_this_arg (type
->data
.klass
))
4152 mono_metadata_free_type (type
->data
.type
);
4154 case MONO_TYPE_FNPTR
:
4155 mono_metadata_free_method_signature (type
->data
.method
);
4157 case MONO_TYPE_ARRAY
:
4158 mono_metadata_free_array (type
->data
.array
);
4169 hex_dump (const char *buffer
, int base
, int count
)
4171 int show_header
= 1;
4179 for (i
= 0; i
< count
; i
++){
4182 printf ("\n0x%08x: ", (unsigned char) base
+ i
);
4184 printf ("%02x ", (unsigned char) (buffer
[i
]));
4191 * @ptr: Points to the beginning of the Section Data (25.3)
4193 static MonoExceptionClause
*
4194 parse_section_data (MonoImage
*m
, int *num_clauses
, const unsigned char *ptr
, MonoError
*error
)
4196 unsigned char sect_data_flags
;
4198 guint32 sect_data_len
;
4199 MonoExceptionClause
* clauses
= NULL
;
4204 /* align on 32-bit boundary */
4205 ptr
= dword_align (ptr
);
4206 sect_data_flags
= *ptr
;
4209 is_fat
= sect_data_flags
& METHOD_HEADER_SECTION_FAT_FORMAT
;
4211 sect_data_len
= (ptr
[2] << 16) | (ptr
[1] << 8) | ptr
[0];
4214 sect_data_len
= ptr
[0];
4218 if (sect_data_flags
& METHOD_HEADER_SECTION_EHTABLE
) {
4219 const unsigned char *p
= dword_align (ptr
);
4221 *num_clauses
= is_fat
? sect_data_len
/ 24: sect_data_len
/ 12;
4222 /* we could just store a pointer if we don't need to byteswap */
4223 clauses
= (MonoExceptionClause
*)g_malloc0 (sizeof (MonoExceptionClause
) * (*num_clauses
));
4224 for (i
= 0; i
< *num_clauses
; ++i
) {
4225 MonoExceptionClause
*ec
= &clauses
[i
];
4228 ec
->flags
= read32 (p
);
4229 ec
->try_offset
= read32 (p
+ 4);
4230 ec
->try_len
= read32 (p
+ 8);
4231 ec
->handler_offset
= read32 (p
+ 12);
4232 ec
->handler_len
= read32 (p
+ 16);
4233 tof_value
= read32 (p
+ 20);
4236 ec
->flags
= read16 (p
);
4237 ec
->try_offset
= read16 (p
+ 2);
4238 ec
->try_len
= *(p
+ 4);
4239 ec
->handler_offset
= read16 (p
+ 5);
4240 ec
->handler_len
= *(p
+ 7);
4241 tof_value
= read32 (p
+ 8);
4244 if (ec
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
4245 ec
->data
.filter_offset
= tof_value
;
4246 } else if (ec
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) {
4247 ec
->data
.catch_class
= NULL
;
4249 ec
->data
.catch_class
= mono_class_get_checked (m
, tof_value
, error
);
4250 if (!is_ok (error
)) {
4256 ec
->data
.catch_class
= NULL
;
4258 /* g_print ("try %d: %x %04x-%04x %04x\n", i, ec->flags, ec->try_offset, ec->try_offset+ec->try_len, ec->try_len); */
4262 if (sect_data_flags
& METHOD_HEADER_SECTION_MORE_SECTS
)
4263 ptr
+= sect_data_len
- 4; /* LAMESPEC: it seems the size includes the header */
4270 * mono_method_get_header_summary:
4271 * @method: The method to get the header.
4272 * @summary: Where to store the header
4275 * Returns: TRUE if the header was properly decoded.
4278 mono_method_get_header_summary (MonoMethod
*method
, MonoMethodHeaderSummary
*summary
)
4284 unsigned char flags
, format
;
4288 /*Only the GMD has a pointer to the metadata.*/
4289 while (method
->is_inflated
)
4290 method
= ((MonoMethodInflated
*)method
)->declaring
;
4292 summary
->code
= NULL
;
4293 summary
->code_size
= 0;
4294 summary
->max_stack
= 0;
4295 summary
->has_clauses
= FALSE
;
4296 summary
->has_locals
= FALSE
;
4298 /*FIXME extract this into a MACRO and share it with mono_method_get_header*/
4299 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
))
4302 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
|| method
->sre_method
) {
4303 MonoMethodHeader
*header
= ((MonoMethodWrapper
*)method
)->header
;
4306 summary
->code
= header
->code
;
4307 summary
->code_size
= header
->code_size
;
4308 summary
->max_stack
= header
->max_stack
;
4309 summary
->has_clauses
= header
->num_clauses
> 0;
4310 summary
->has_locals
= header
->num_locals
> 0;
4315 idx
= mono_metadata_token_index (method
->token
);
4316 img
= m_class_get_image (method
->klass
);
4317 rva
= mono_metadata_decode_row_col (&img
->tables
[MONO_TABLE_METHOD
], idx
- 1, MONO_METHOD_RVA
);
4319 /*We must run the verifier since we'll be decoding it.*/
4320 if (!mono_verifier_verify_method_header (img
, rva
, error
)) {
4321 mono_error_cleanup (error
);
4325 ptr
= mono_image_rva_map (img
, rva
);
4329 flags
= *(const unsigned char *)ptr
;
4330 format
= flags
& METHOD_HEADER_FORMAT_MASK
;
4333 case METHOD_HEADER_TINY_FORMAT
:
4335 summary
->max_stack
= 8;
4336 summary
->code
= (unsigned char *) ptr
;
4337 summary
->code_size
= flags
>> 2;
4339 case METHOD_HEADER_FAT_FORMAT
:
4340 fat_flags
= read16 (ptr
);
4342 summary
->max_stack
= read16 (ptr
);
4344 summary
->code_size
= read32 (ptr
);
4346 summary
->has_locals
= !!read32 (ptr
);
4348 if (fat_flags
& METHOD_HEADER_MORE_SECTS
)
4349 summary
->has_clauses
= TRUE
;
4350 summary
->code
= (unsigned char *) ptr
;
4359 * mono_metadata_parse_mh_full:
4360 * @m: metadata context
4361 * @generic_context: generics context
4362 * @ptr: pointer to the method header.
4364 * Decode the method header at @ptr, including pointer to the IL code,
4365 * info about local variables and optional exception tables.
4366 * This is a Mono runtime internal function.
4368 * LOCKING: Acquires the loader lock.
4370 * Returns: a transient MonoMethodHeader allocated from the heap.
4373 mono_metadata_parse_mh_full (MonoImage
*m
, MonoGenericContainer
*container
, const char *ptr
, MonoError
*error
)
4375 MonoMethodHeader
*mh
= NULL
;
4376 unsigned char flags
= *(const unsigned char *) ptr
;
4377 unsigned char format
= flags
& METHOD_HEADER_FORMAT_MASK
;
4379 guint32 local_var_sig_tok
, max_stack
, code_size
, init_locals
;
4380 const unsigned char *code
;
4381 MonoExceptionClause
* clauses
= NULL
;
4382 int num_clauses
= 0;
4383 MonoTableInfo
*t
= &m
->tables
[MONO_TABLE_STANDALONESIG
];
4384 guint32 cols
[MONO_STAND_ALONE_SIGNATURE_SIZE
];
4389 mono_error_set_bad_image (error
, m
, "Method header with null pointer");
4394 case METHOD_HEADER_TINY_FORMAT
:
4395 mh
= (MonoMethodHeader
*)g_malloc0 (MONO_SIZEOF_METHOD_HEADER
);
4398 mh
->is_transient
= TRUE
;
4399 local_var_sig_tok
= 0;
4400 mh
->code_size
= flags
>> 2;
4401 mh
->code
= (unsigned char*)ptr
;
4403 case METHOD_HEADER_FAT_FORMAT
:
4404 fat_flags
= read16 (ptr
);
4406 max_stack
= read16 (ptr
);
4408 code_size
= read32 (ptr
);
4410 local_var_sig_tok
= read32 (ptr
);
4413 if (fat_flags
& METHOD_HEADER_INIT_LOCALS
)
4418 code
= (unsigned char*)ptr
;
4420 if (!(fat_flags
& METHOD_HEADER_MORE_SECTS
))
4424 * There are more sections
4426 ptr
= (char*)code
+ code_size
;
4429 mono_error_set_bad_image (error
, m
, "Invalid method header format %d", format
);
4433 if (local_var_sig_tok
) {
4434 int idx
= (local_var_sig_tok
& 0xffffff)-1;
4435 if (idx
>= t
->rows
|| idx
< 0) {
4436 mono_error_set_bad_image (error
, m
, "Invalid method header local vars signature token 0x%8x", idx
);
4439 mono_metadata_decode_row (t
, idx
, cols
, 1);
4441 if (!mono_verifier_verify_standalone_signature (m
, cols
[MONO_STAND_ALONE_SIGNATURE
], error
))
4444 if (fat_flags
& METHOD_HEADER_MORE_SECTS
) {
4445 clauses
= parse_section_data (m
, &num_clauses
, (const unsigned char*)ptr
, error
);
4446 goto_if_nok (error
, fail
);
4448 if (local_var_sig_tok
) {
4449 const char *locals_ptr
;
4452 locals_ptr
= mono_metadata_blob_heap (m
, cols
[MONO_STAND_ALONE_SIGNATURE
]);
4453 mono_metadata_decode_blob_size (locals_ptr
, &locals_ptr
);
4454 if (*locals_ptr
!= 0x07)
4455 g_warning ("wrong signature for locals blob");
4457 len
= mono_metadata_decode_value (locals_ptr
, &locals_ptr
);
4458 mh
= (MonoMethodHeader
*)g_malloc0 (MONO_SIZEOF_METHOD_HEADER
+ len
* sizeof (MonoType
*) + num_clauses
* sizeof (MonoExceptionClause
));
4459 mh
->num_locals
= len
;
4460 for (i
= 0; i
< len
; ++i
) {
4461 mh
->locals
[i
] = mono_metadata_parse_type_internal (m
, container
, 0, TRUE
, locals_ptr
, &locals_ptr
, error
);
4462 goto_if_nok (error
, fail
);
4465 mh
= (MonoMethodHeader
*)g_malloc0 (MONO_SIZEOF_METHOD_HEADER
+ num_clauses
* sizeof (MonoExceptionClause
));
4468 mh
->code_size
= code_size
;
4469 mh
->max_stack
= max_stack
;
4470 mh
->is_transient
= TRUE
;
4471 mh
->init_locals
= init_locals
;
4473 MonoExceptionClause
* clausesp
= (MonoExceptionClause
*)&mh
->locals
[mh
->num_locals
];
4474 memcpy (clausesp
, clauses
, num_clauses
* sizeof (MonoExceptionClause
));
4476 mh
->clauses
= clausesp
;
4477 mh
->num_clauses
= num_clauses
;
4488 * mono_metadata_parse_mh:
4489 * \param generic_context generics context
4490 * \param ptr pointer to the method header.
4492 * Decode the method header at \p ptr, including pointer to the IL code,
4493 * info about local variables and optional exception tables.
4495 * \returns a transient \c MonoMethodHeader allocated from the heap.
4498 mono_metadata_parse_mh (MonoImage
*m
, const char *ptr
)
4501 MonoMethodHeader
*header
= mono_metadata_parse_mh_full (m
, NULL
, ptr
, error
);
4502 mono_error_cleanup (error
);
4507 * mono_metadata_free_mh:
4508 * \param mh a method header
4510 * Free the memory allocated for the method header.
4513 mono_metadata_free_mh (MonoMethodHeader
*mh
)
4517 /* If it is not transient it means it's part of a wrapper method,
4518 * or a SRE-generated method, so the lifetime in that case is
4519 * dictated by the method's own lifetime
4521 if (mh
&& mh
->is_transient
) {
4522 for (i
= 0; i
< mh
->num_locals
; ++i
)
4523 mono_metadata_free_type (mh
->locals
[i
]);
4529 * mono_method_header_get_code:
4530 * \param header a \c MonoMethodHeader pointer
4531 * \param code_size memory location for returning the code size
4532 * \param max_stack memory location for returning the max stack
4534 * Method header accessor to retreive info about the IL code properties:
4535 * a pointer to the IL code itself, the size of the code and the max number
4536 * of stack slots used by the code.
4538 * \returns pointer to the IL code represented by the method header.
4540 const unsigned char*
4541 mono_method_header_get_code (MonoMethodHeader
*header
, guint32
* code_size
, guint32
* max_stack
)
4544 *code_size
= header
->code_size
;
4546 *max_stack
= header
->max_stack
;
4547 return header
->code
;
4551 * mono_method_header_get_locals:
4552 * \param header a \c MonoMethodHeader pointer
4553 * \param num_locals memory location for returning the number of local variables
4554 * \param init_locals memory location for returning the init_locals flag
4556 * Method header accessor to retreive info about the local variables:
4557 * an array of local types, the number of locals and whether the locals
4558 * are supposed to be initialized to 0 on method entry
4560 * \returns pointer to an array of types of the local variables
4563 mono_method_header_get_locals (MonoMethodHeader
*header
, guint32
* num_locals
, gboolean
*init_locals
)
4566 *num_locals
= header
->num_locals
;
4568 *init_locals
= header
->init_locals
;
4569 return header
->locals
;
4573 * mono_method_header_get_num_clauses:
4574 * @header: a MonoMethodHeader pointer
4576 * Method header accessor to retreive the number of exception clauses.
4578 * Returns: the number of exception clauses present
4581 mono_method_header_get_num_clauses (MonoMethodHeader
*header
)
4583 return header
->num_clauses
;
4587 * mono_method_header_get_clauses:
4588 * \param header a \c MonoMethodHeader pointer
4589 * \param method \c MonoMethod the header belongs to
4590 * \param iter pointer to a iterator
4591 * \param clause pointer to a \c MonoExceptionClause structure which will be filled with the info
4593 * Get the info about the exception clauses in the method. Set \c *iter to NULL to
4594 * initiate the iteration, then call the method repeatedly until it returns FALSE.
4595 * At each iteration, the structure pointed to by clause if filled with the
4596 * exception clause information.
4598 * \returns TRUE if clause was filled with info, FALSE if there are no more exception
4602 mono_method_header_get_clauses (MonoMethodHeader
*header
, MonoMethod
*method
, gpointer
*iter
, MonoExceptionClause
*clause
)
4604 MonoExceptionClause
*sc
;
4605 /* later we'll be able to use this interface to parse the clause info on demand,
4606 * without allocating anything.
4608 if (!iter
|| !header
->num_clauses
)
4611 *iter
= sc
= header
->clauses
;
4615 sc
= (MonoExceptionClause
*)*iter
;
4617 if (sc
< header
->clauses
+ header
->num_clauses
) {
4626 * mono_metadata_parse_field_type:
4627 * \param m metadata context to extract information from
4628 * \param ptr pointer to the field signature
4629 * \param rptr pointer updated to match the end of the decoded stream
4631 * Parses the field signature, and returns the type information for it.
4633 * \returns The \c MonoType that was extracted from \p ptr .
4636 mono_metadata_parse_field_type (MonoImage
*m
, short field_flags
, const char *ptr
, const char **rptr
)
4639 MonoType
* type
= mono_metadata_parse_type_internal (m
, NULL
, field_flags
, FALSE
, ptr
, rptr
, error
);
4640 mono_error_cleanup (error
);
4645 * mono_metadata_parse_param:
4646 * \param m metadata context to extract information from
4647 * \param ptr pointer to the param signature
4648 * \param rptr pointer updated to match the end of the decoded stream
4650 * Parses the param signature, and returns the type information for it.
4652 * \returns The \c MonoType that was extracted from \p ptr .
4655 mono_metadata_parse_param (MonoImage
*m
, const char *ptr
, const char **rptr
)
4658 MonoType
* type
= mono_metadata_parse_type_internal (m
, NULL
, 0, FALSE
, ptr
, rptr
, error
);
4659 mono_error_cleanup (error
);
4664 * mono_metadata_token_from_dor:
4665 * \param dor_token A \c TypeDefOrRef coded index
4667 * \p dor_token is a \c TypeDefOrRef coded index: it contains either
4668 * a \c TypeDef, \c TypeRef or \c TypeSpec in the lower bits, and the upper
4669 * bits contain an index into the table.
4671 * \returns an expanded token
4674 mono_metadata_token_from_dor (guint32 dor_index
)
4678 table
= dor_index
& 0x03;
4679 idx
= dor_index
>> 2;
4682 case 0: /* TypeDef */
4683 return MONO_TOKEN_TYPE_DEF
| idx
;
4684 case 1: /* TypeRef */
4685 return MONO_TOKEN_TYPE_REF
| idx
;
4686 case 2: /* TypeSpec */
4687 return MONO_TOKEN_TYPE_SPEC
| idx
;
4689 g_assert_not_reached ();
4696 * We use this to pass context information to the row locator
4699 int idx
; /* The index that we are trying to locate */
4700 int col_idx
; /* The index in the row where idx may be stored */
4701 MonoTableInfo
*t
; /* pointer to the table */
4706 * How the row locator works.
4711 * ___|___------> _______
4714 * A column in the rows of table A references an index in table B.
4715 * For example A may be the TYPEDEF table and B the METHODDEF table.
4717 * Given an index in table B we want to get the row in table A
4718 * where the column n references our index in B.
4720 * In the locator_t structure:
4722 * col_idx is the column number
4723 * index is the index in table B
4724 * result will be the index in table A
4727 * Table A Table B column (in table A)
4728 * TYPEDEF METHODDEF MONO_TYPEDEF_METHOD_LIST
4729 * TYPEDEF FIELD MONO_TYPEDEF_FIELD_LIST
4730 * PROPERTYMAP PROPERTY MONO_PROPERTY_MAP_PROPERTY_LIST
4731 * INTERFIMPL TYPEDEF MONO_INTERFACEIMPL_CLASS
4732 * METHODSEM PROPERTY ASSOCIATION (encoded index)
4734 * Note that we still don't support encoded indexes.
4738 typedef_locator (const void *a
, const void *b
)
4740 locator_t
*loc
= (locator_t
*) a
;
4741 const char *bb
= (const char *) b
;
4742 int typedef_index
= (bb
- loc
->t
->base
) / loc
->t
->row_size
;
4743 guint32 col
, col_next
;
4745 col
= mono_metadata_decode_row_col (loc
->t
, typedef_index
, loc
->col_idx
);
4751 * Need to check that the next row is valid.
4753 if (typedef_index
+ 1 < loc
->t
->rows
) {
4754 col_next
= mono_metadata_decode_row_col (loc
->t
, typedef_index
+ 1, loc
->col_idx
);
4755 if (loc
->idx
>= col_next
)
4758 if (col
== col_next
)
4762 loc
->result
= typedef_index
;
4768 table_locator (const void *a
, const void *b
)
4770 locator_t
*loc
= (locator_t
*) a
;
4771 const char *bb
= (const char *) b
;
4772 guint32 table_index
= (bb
- loc
->t
->base
) / loc
->t
->row_size
;
4775 col
= mono_metadata_decode_row_col (loc
->t
, table_index
, loc
->col_idx
);
4777 if (loc
->idx
== col
) {
4778 loc
->result
= table_index
;
4788 declsec_locator (const void *a
, const void *b
)
4790 locator_t
*loc
= (locator_t
*) a
;
4791 const char *bb
= (const char *) b
;
4792 guint32 table_index
= (bb
- loc
->t
->base
) / loc
->t
->row_size
;
4795 col
= mono_metadata_decode_row_col (loc
->t
, table_index
, loc
->col_idx
);
4797 if (loc
->idx
== col
) {
4798 loc
->result
= table_index
;
4810 * Return the 1-based row index in TABLE, which must be one of the *Ptr tables,
4811 * which contains IDX.
4814 search_ptr_table (MonoImage
*image
, int table
, int idx
)
4816 MonoTableInfo
*ptrdef
= &image
->tables
[table
];
4819 /* Use a linear search to find our index in the table */
4820 for (i
= 0; i
< ptrdef
->rows
; i
++)
4821 /* All the Ptr tables have the same structure */
4822 if (mono_metadata_decode_row_col (ptrdef
, i
, 0) == idx
)
4825 if (i
< ptrdef
->rows
)
4832 * mono_metadata_typedef_from_field:
4833 * \param meta metadata context
4834 * \param index FieldDef token
4836 * \returns the 1-based index into the \c TypeDef table of the type that
4837 * declared the field described by \p index, or 0 if not found.
4840 mono_metadata_typedef_from_field (MonoImage
*meta
, guint32 index
)
4842 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_TYPEDEF
];
4848 loc
.idx
= mono_metadata_token_index (index
);
4849 loc
.col_idx
= MONO_TYPEDEF_FIELD_LIST
;
4852 if (meta
->uncompressed_metadata
)
4853 loc
.idx
= search_ptr_table (meta
, MONO_TABLE_FIELD_POINTER
, loc
.idx
);
4855 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, typedef_locator
))
4858 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4859 return loc
.result
+ 1;
4863 * mono_metadata_typedef_from_method:
4864 * \param meta metadata context
4865 * \param index \c MethodDef token
4866 * \returns the 1-based index into the \c TypeDef table of the type that
4867 * declared the method described by \p index. 0 if not found.
4870 mono_metadata_typedef_from_method (MonoImage
*meta
, guint32 index
)
4872 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_TYPEDEF
];
4878 loc
.idx
= mono_metadata_token_index (index
);
4879 loc
.col_idx
= MONO_TYPEDEF_METHOD_LIST
;
4882 if (meta
->uncompressed_metadata
)
4883 loc
.idx
= search_ptr_table (meta
, MONO_TABLE_METHOD_POINTER
, loc
.idx
);
4885 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, typedef_locator
))
4888 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4889 return loc
.result
+ 1;
4893 * mono_metadata_interfaces_from_typedef_full:
4894 * \param meta metadata context
4895 * \param index typedef token
4896 * \param interfaces Out parameter used to store the interface array
4897 * \param count Out parameter used to store the number of interfaces
4898 * \param heap_alloc_result if TRUE the result array will be \c g_malloc'd
4899 * \param context The generic context
4900 * \param error set on error
4902 * The array of interfaces that the \p index typedef token implements is returned in
4903 * \p interfaces. The number of elements in the array is returned in \p count.
4905 * \returns \c TRUE on success, \c FALSE on failure and sets \p error.
4908 mono_metadata_interfaces_from_typedef_full (MonoImage
*meta
, guint32 index
, MonoClass
***interfaces
, guint
*count
, gboolean heap_alloc_result
, MonoGenericContext
*context
, MonoError
*error
)
4910 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_INTERFACEIMPL
];
4913 guint32 cols
[MONO_INTERFACEIMPL_SIZE
];
4924 loc
.idx
= mono_metadata_token_index (index
);
4925 loc
.col_idx
= MONO_INTERFACEIMPL_CLASS
;
4928 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
4933 * We may end up in the middle of the rows...
4936 if (loc
.idx
== mono_metadata_decode_row_col (tdef
, start
- 1, MONO_INTERFACEIMPL_CLASS
))
4942 while (pos
< tdef
->rows
) {
4943 mono_metadata_decode_row (tdef
, pos
, cols
, MONO_INTERFACEIMPL_SIZE
);
4944 if (cols
[MONO_INTERFACEIMPL_CLASS
] != loc
.idx
)
4949 if (heap_alloc_result
)
4950 result
= g_new0 (MonoClass
*, pos
- start
);
4952 result
= (MonoClass
**)mono_image_alloc0 (meta
, sizeof (MonoClass
*) * (pos
- start
));
4955 while (pos
< tdef
->rows
) {
4958 mono_metadata_decode_row (tdef
, pos
, cols
, MONO_INTERFACEIMPL_SIZE
);
4959 if (cols
[MONO_INTERFACEIMPL_CLASS
] != loc
.idx
)
4961 iface
= mono_class_get_and_inflate_typespec_checked (
4962 meta
, mono_metadata_token_from_dor (cols
[MONO_INTERFACEIMPL_INTERFACE
]), context
, error
);
4965 result
[pos
- start
] = iface
;
4968 *count
= pos
- start
;
4969 *interfaces
= result
;
4974 * mono_metadata_interfaces_from_typedef:
4975 * \param meta metadata context
4976 * \param index typedef token
4977 * \param count Out parameter used to store the number of interfaces
4979 * The array of interfaces that the \p index typedef token implements is returned in
4980 * \p interfaces. The number of elements in the array is returned in \p count. The returned
4981 * array is allocated with \c g_malloc and the caller must free it.
4983 * LOCKING: Acquires the loader lock .
4985 * \returns the interface array on success, NULL on failure.
4988 mono_metadata_interfaces_from_typedef (MonoImage
*meta
, guint32 index
, guint
*count
)
4991 MonoClass
**interfaces
= NULL
;
4994 rv
= mono_metadata_interfaces_from_typedef_full (meta
, index
, &interfaces
, count
, TRUE
, NULL
, error
);
4995 mono_error_assert_ok (error
);
5003 * mono_metadata_nested_in_typedef:
5004 * \param meta metadata context
5005 * \param index typedef token
5006 * \returns the 1-based index into the TypeDef table of the type
5007 * where the type described by \p index is nested.
5008 * Returns 0 if \p index describes a non-nested type.
5011 mono_metadata_nested_in_typedef (MonoImage
*meta
, guint32 index
)
5013 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_NESTEDCLASS
];
5019 loc
.idx
= mono_metadata_token_index (index
);
5020 loc
.col_idx
= MONO_NESTED_CLASS_NESTED
;
5023 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
5026 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5027 return mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_NESTED_CLASS_ENCLOSING
) | MONO_TOKEN_TYPE_DEF
;
5031 * mono_metadata_nesting_typedef:
5032 * \param meta metadata context
5033 * \param index typedef token
5034 * \returns the 1-based index into the \c TypeDef table of the first type
5035 * that is nested inside the type described by \p index. The search starts at
5036 * \p start_index. Returns 0 if no such type is found.
5039 mono_metadata_nesting_typedef (MonoImage
*meta
, guint32 index
, guint32 start_index
)
5041 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_NESTEDCLASS
];
5043 guint32 class_index
= mono_metadata_token_index (index
);
5048 start
= start_index
;
5050 while (start
<= tdef
->rows
) {
5051 if (class_index
== mono_metadata_decode_row_col (tdef
, start
- 1, MONO_NESTED_CLASS_ENCLOSING
))
5057 if (start
> tdef
->rows
)
5064 * mono_metadata_packing_from_typedef:
5065 * \param meta metadata context
5066 * \param index token representing a type
5067 * \returns the info stored in the \c ClassLayout table for the given typedef token
5068 * into the \p packing and \p size pointers.
5069 * Returns 0 if the info is not found.
5072 mono_metadata_packing_from_typedef (MonoImage
*meta
, guint32 index
, guint32
*packing
, guint32
*size
)
5074 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_CLASSLAYOUT
];
5076 guint32 cols
[MONO_CLASS_LAYOUT_SIZE
];
5081 loc
.idx
= mono_metadata_token_index (index
);
5082 loc
.col_idx
= MONO_CLASS_LAYOUT_PARENT
;
5085 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
5088 mono_metadata_decode_row (tdef
, loc
.result
, cols
, MONO_CLASS_LAYOUT_SIZE
);
5090 *packing
= cols
[MONO_CLASS_LAYOUT_PACKING_SIZE
];
5092 *size
= cols
[MONO_CLASS_LAYOUT_CLASS_SIZE
];
5094 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5095 return loc
.result
+ 1;
5099 * mono_metadata_custom_attrs_from_index:
5100 * \param meta metadata context
5101 * \param index token representing the parent
5102 * \returns: the 1-based index into the \c CustomAttribute table of the first
5103 * attribute which belongs to the metadata object described by \p index.
5104 * Returns 0 if no such attribute is found.
5107 mono_metadata_custom_attrs_from_index (MonoImage
*meta
, guint32 index
)
5109 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_CUSTOMATTRIBUTE
];
5116 loc
.col_idx
= MONO_CUSTOM_ATTR_PARENT
;
5119 /* FIXME: Index translation */
5121 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
5124 /* Find the first entry by searching backwards */
5125 while ((loc
.result
> 0) && (mono_metadata_decode_row_col (tdef
, loc
.result
- 1, MONO_CUSTOM_ATTR_PARENT
) == index
))
5128 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5129 return loc
.result
+ 1;
5133 * mono_metadata_declsec_from_index:
5134 * \param meta metadata context
5135 * \param index token representing the parent
5136 * \returns the 0-based index into the \c DeclarativeSecurity table of the first
5137 * attribute which belongs to the metadata object described by \p index.
5138 * Returns \c -1 if no such attribute is found.
5141 mono_metadata_declsec_from_index (MonoImage
*meta
, guint32 index
)
5143 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_DECLSECURITY
];
5150 loc
.col_idx
= MONO_DECL_SECURITY_PARENT
;
5153 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, declsec_locator
))
5156 /* Find the first entry by searching backwards */
5157 while ((loc
.result
> 0) && (mono_metadata_decode_row_col (tdef
, loc
.result
- 1, MONO_DECL_SECURITY_PARENT
) == index
))
5164 * mono_metadata_localscope_from_methoddef:
5165 * @meta: metadata context
5166 * @index: methoddef index
5168 * Returns: the 1-based index into the LocalScope table of the first
5169 * scope which belongs to the method described by @index.
5170 * Returns 0 if no such row is found.
5173 mono_metadata_localscope_from_methoddef (MonoImage
*meta
, guint32 index
)
5175 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_LOCALSCOPE
];
5182 loc
.col_idx
= MONO_LOCALSCOPE_METHOD
;
5185 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
5188 /* Find the first entry by searching backwards */
5189 while ((loc
.result
> 0) && (mono_metadata_decode_row_col (tdef
, loc
.result
- 1, MONO_LOCALSCOPE_METHOD
) == index
))
5192 return loc
.result
+ 1;
5197 mono_backtrace (int limit
)
5202 backtrace (array
, limit
);
5203 names
= backtrace_symbols (array
, limit
);
5204 for (i
=0; i
< limit
; ++i
) {
5205 g_print ("\t%s\n", names
[i
]);
5211 static int i8_align
;
5214 * mono_type_set_alignment:
5216 * Set the alignment used by runtime to layout fields etc. of type TYPE to ALIGN.
5217 * This should only be used in AOT mode since the resulting layout will not match the
5221 mono_type_set_alignment (MonoTypeEnum type
, int align
)
5223 /* Support only a few types whose alignment is abi dependent */
5229 g_assert_not_reached ();
5236 * \param t the type to return the size of
5237 * \returns The number of bytes required to hold an instance of this
5241 mono_type_size (MonoType
*t
, int *align
)
5243 MonoTypeEnum simple_type
;
5250 *align
= MONO_ABI_ALIGNOF (gpointer
);
5251 return MONO_ABI_SIZEOF (gpointer
);
5254 simple_type
= t
->type
;
5256 switch (simple_type
) {
5257 case MONO_TYPE_VOID
:
5260 case MONO_TYPE_BOOLEAN
:
5261 *align
= MONO_ABI_ALIGNOF (gint8
);
5265 *align
= MONO_ABI_ALIGNOF (gint8
);
5267 case MONO_TYPE_CHAR
:
5270 *align
= MONO_ABI_ALIGNOF (gint16
);
5274 *align
= MONO_ABI_ALIGNOF (gint32
);
5277 *align
= MONO_ABI_ALIGNOF (float);
5281 *align
= MONO_ABI_ALIGNOF (gint64
);
5284 *align
= MONO_ABI_ALIGNOF (double);
5288 *align
= MONO_ABI_ALIGNOF (gpointer
);
5289 return MONO_ABI_SIZEOF (gpointer
);
5290 case MONO_TYPE_VALUETYPE
: {
5291 if (m_class_is_enumtype (t
->data
.klass
))
5292 return mono_type_size (mono_class_enum_basetype_internal (t
->data
.klass
), align
);
5294 return mono_class_value_size (t
->data
.klass
, (guint32
*)align
);
5296 case MONO_TYPE_STRING
:
5297 case MONO_TYPE_OBJECT
:
5298 case MONO_TYPE_CLASS
:
5299 case MONO_TYPE_SZARRAY
:
5301 case MONO_TYPE_FNPTR
:
5302 case MONO_TYPE_ARRAY
:
5303 *align
= MONO_ABI_ALIGNOF (gpointer
);
5304 return MONO_ABI_SIZEOF (gpointer
);
5305 case MONO_TYPE_TYPEDBYREF
:
5306 return mono_class_value_size (mono_defaults
.typed_reference_class
, (guint32
*)align
);
5307 case MONO_TYPE_GENERICINST
: {
5308 MonoGenericClass
*gclass
= t
->data
.generic_class
;
5309 MonoClass
*container_class
= gclass
->container_class
;
5311 // g_assert (!gclass->inst->is_open);
5313 if (m_class_is_valuetype (container_class
)) {
5314 if (m_class_is_enumtype (container_class
))
5315 return mono_type_size (mono_class_enum_basetype_internal (container_class
), align
);
5317 return mono_class_value_size (mono_class_from_mono_type_internal (t
), (guint32
*)align
);
5319 *align
= MONO_ABI_ALIGNOF (gpointer
);
5320 return MONO_ABI_SIZEOF (gpointer
);
5324 case MONO_TYPE_MVAR
:
5325 if (!t
->data
.generic_param
->gshared_constraint
|| t
->data
.generic_param
->gshared_constraint
->type
== MONO_TYPE_VALUETYPE
) {
5326 *align
= MONO_ABI_ALIGNOF (gpointer
);
5327 return MONO_ABI_SIZEOF (gpointer
);
5329 /* The gparam can only match types given by gshared_constraint */
5330 return mono_type_size (t
->data
.generic_param
->gshared_constraint
, align
);
5334 g_error ("mono_type_size: type 0x%02x unknown", t
->type
);
5340 * mono_type_stack_size:
5341 * \param t the type to return the size it uses on the stack
5342 * \returns The number of bytes required to hold an instance of this
5343 * type on the runtime stack
5346 mono_type_stack_size (MonoType
*t
, int *align
)
5348 return mono_type_stack_size_internal (t
, align
, FALSE
);
5352 mono_type_stack_size_internal (MonoType
*t
, int *align
, gboolean allow_open
)
5355 MonoTypeEnum simple_type
;
5356 int stack_slot_size
= TARGET_SIZEOF_VOID_P
;
5357 int stack_slot_align
= TARGET_SIZEOF_VOID_P
;
5359 g_assert (t
!= NULL
);
5365 *align
= stack_slot_align
;
5366 return stack_slot_size
;
5369 simple_type
= t
->type
;
5370 switch (simple_type
) {
5371 case MONO_TYPE_BOOLEAN
:
5372 case MONO_TYPE_CHAR
:
5381 case MONO_TYPE_STRING
:
5382 case MONO_TYPE_OBJECT
:
5383 case MONO_TYPE_CLASS
:
5384 case MONO_TYPE_SZARRAY
:
5386 case MONO_TYPE_FNPTR
:
5387 case MONO_TYPE_ARRAY
:
5388 *align
= stack_slot_align
;
5389 return stack_slot_size
;
5391 case MONO_TYPE_MVAR
:
5392 g_assert (allow_open
);
5393 if (!t
->data
.generic_param
->gshared_constraint
|| t
->data
.generic_param
->gshared_constraint
->type
== MONO_TYPE_VALUETYPE
) {
5394 *align
= stack_slot_align
;
5395 return stack_slot_size
;
5397 /* The gparam can only match types given by gshared_constraint */
5398 return mono_type_stack_size_internal (t
->data
.generic_param
->gshared_constraint
, align
, allow_open
);
5400 case MONO_TYPE_TYPEDBYREF
:
5401 *align
= stack_slot_align
;
5402 return stack_slot_size
* 3;
5404 *align
= MONO_ABI_ALIGNOF (float);
5405 return sizeof (float);
5408 *align
= MONO_ABI_ALIGNOF (gint64
);
5409 return sizeof (gint64
);
5411 *align
= MONO_ABI_ALIGNOF (double);
5412 return sizeof (double);
5413 case MONO_TYPE_VALUETYPE
: {
5416 if (m_class_is_enumtype (t
->data
.klass
))
5417 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (t
->data
.klass
), align
, allow_open
);
5419 size
= mono_class_value_size (t
->data
.klass
, (guint32
*)align
);
5421 *align
= *align
+ stack_slot_align
- 1;
5422 *align
&= ~(stack_slot_align
- 1);
5424 size
+= stack_slot_size
- 1;
5425 size
&= ~(stack_slot_size
- 1);
5430 case MONO_TYPE_GENERICINST
: {
5431 MonoGenericClass
*gclass
= t
->data
.generic_class
;
5432 MonoClass
*container_class
= gclass
->container_class
;
5435 g_assert (!gclass
->context
.class_inst
->is_open
);
5437 if (m_class_is_valuetype (container_class
)) {
5438 if (m_class_is_enumtype (container_class
))
5439 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (container_class
), align
, allow_open
);
5441 guint32 size
= mono_class_value_size (mono_class_from_mono_type_internal (t
), (guint32
*)align
);
5443 *align
= *align
+ stack_slot_align
- 1;
5444 *align
&= ~(stack_slot_align
- 1);
5446 size
+= stack_slot_size
- 1;
5447 size
&= ~(stack_slot_size
- 1);
5452 *align
= stack_slot_align
;
5453 return stack_slot_size
;
5457 g_error ("type 0x%02x unknown", t
->type
);
5463 mono_type_generic_inst_is_valuetype (MonoType
*type
)
5465 g_assert (type
->type
== MONO_TYPE_GENERICINST
);
5466 return m_class_is_valuetype (type
->data
.generic_class
->container_class
);
5470 * mono_metadata_generic_class_is_valuetype:
5473 mono_metadata_generic_class_is_valuetype (MonoGenericClass
*gclass
)
5475 return m_class_is_valuetype (gclass
->container_class
);
5479 _mono_metadata_generic_class_equal (const MonoGenericClass
*g1
, const MonoGenericClass
*g2
, gboolean signature_only
)
5481 MonoGenericInst
*i1
= g1
->context
.class_inst
;
5482 MonoGenericInst
*i2
= g2
->context
.class_inst
;
5484 if (g1
->is_dynamic
!= g2
->is_dynamic
)
5486 if (!mono_metadata_class_equal (g1
->container_class
, g2
->container_class
, signature_only
))
5488 if (!mono_generic_inst_equal_full (i1
, i2
, signature_only
))
5490 return g1
->is_tb_open
== g2
->is_tb_open
;
5494 _mono_metadata_generic_class_container_equal (const MonoGenericClass
*g1
, MonoClass
*c2
, gboolean signature_only
)
5496 MonoGenericInst
*i1
= g1
->context
.class_inst
;
5497 MonoGenericInst
*i2
= mono_class_get_generic_container (c2
)->context
.class_inst
;
5499 if (!mono_metadata_class_equal (g1
->container_class
, c2
, signature_only
))
5501 if (!mono_generic_inst_equal_full (i1
, i2
, signature_only
))
5503 return !g1
->is_tb_open
;
5507 mono_metadata_generic_context_hash (const MonoGenericContext
*context
)
5509 /* FIXME: check if this seed is good enough */
5510 guint hash
= 0xc01dfee7;
5511 if (context
->class_inst
)
5512 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_generic_inst_hash (context
->class_inst
);
5513 if (context
->method_inst
)
5514 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_generic_inst_hash (context
->method_inst
);
5519 mono_metadata_generic_context_equal (const MonoGenericContext
*g1
, const MonoGenericContext
*g2
)
5521 return g1
->class_inst
== g2
->class_inst
&& g1
->method_inst
== g2
->method_inst
;
5525 * mono_metadata_str_hash:
5527 * This should be used instead of g_str_hash for computing hash codes visible
5528 * outside this module, since g_str_hash () is not guaranteed to be stable
5529 * (its not the same in eglib for example).
5532 mono_metadata_str_hash (gconstpointer v1
)
5534 /* Same as g_str_hash () in glib */
5535 /* note: signed/unsigned char matters - we feed UTF-8 to this function, so the high bit will give diferent results if we don't match. */
5536 unsigned char *p
= (unsigned char *) v1
;
5541 hash
= (hash
<< 5) - hash
+ *p
;
5548 * mono_metadata_type_hash:
5550 * Computes a hash value for \p t1 to be used in \c GHashTable.
5551 * The returned hash is guaranteed to be the same across executions.
5554 mono_metadata_type_hash (MonoType
*t1
)
5556 guint hash
= t1
->type
;
5558 hash
|= t1
->byref
<< 6; /* do not collide with t1->type values */
5560 case MONO_TYPE_VALUETYPE
:
5561 case MONO_TYPE_CLASS
:
5562 case MONO_TYPE_SZARRAY
: {
5563 MonoClass
*klass
= t1
->data
.klass
;
5565 * Dynamic classes must not be hashed on their type since it can change
5566 * during runtime. For example, if we hash a reference type that is
5567 * later made into a valuetype.
5569 * This is specially problematic with generic instances since they are
5570 * inserted in a bunch of hash tables before been finished.
5572 if (image_is_dynamic (m_class_get_image (klass
)))
5573 return (t1
->byref
<< 6) | mono_metadata_str_hash (m_class_get_name (klass
));
5574 return ((hash
<< 5) - hash
) ^ mono_metadata_str_hash (m_class_get_name (klass
));
5577 return ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (t1
->data
.type
);
5578 case MONO_TYPE_ARRAY
:
5579 return ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (m_class_get_byval_arg (t1
->data
.array
->eklass
));
5580 case MONO_TYPE_GENERICINST
:
5581 return ((hash
<< 5) - hash
) ^ mono_generic_class_hash (t1
->data
.generic_class
);
5583 case MONO_TYPE_MVAR
:
5584 return ((hash
<< 5) - hash
) ^ mono_metadata_generic_param_hash (t1
->data
.generic_param
);
5591 mono_metadata_generic_param_hash (MonoGenericParam
*p
)
5594 MonoGenericParamInfo
*info
;
5596 hash
= (mono_generic_param_num (p
) << 2);
5597 if (p
->gshared_constraint
)
5598 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (p
->gshared_constraint
);
5599 info
= mono_generic_param_info (p
);
5600 /* Can't hash on the owner klass/method, since those might not be set when this is called */
5601 if (!p
->owner
->is_anonymous
)
5602 hash
= ((hash
<< 5) - hash
) ^ info
->token
;
5607 mono_metadata_generic_param_equal_internal (MonoGenericParam
*p1
, MonoGenericParam
*p2
, gboolean signature_only
)
5611 if (mono_generic_param_num (p1
) != mono_generic_param_num (p2
))
5613 if (p1
->gshared_constraint
&& p2
->gshared_constraint
) {
5614 if (!mono_metadata_type_equal (p1
->gshared_constraint
, p2
->gshared_constraint
))
5617 if (p1
->gshared_constraint
!= p2
->gshared_constraint
)
5622 * We have to compare the image as well because if we didn't,
5623 * the generic_inst_cache lookup wouldn't care about the image
5624 * of generic params, so what could happen is that a generic
5625 * inst with params from image A is put into the cache, then
5626 * image B gets that generic inst from the cache, image A is
5627 * unloaded, so the inst is deleted, but image B still retains
5630 if (mono_generic_param_owner (p1
) == mono_generic_param_owner (p2
))
5634 * If `signature_only' is true, we're comparing two (method) signatures.
5635 * In this case, the owner of two type parameters doesn't need to match.
5638 return signature_only
;
5642 mono_metadata_generic_param_equal (MonoGenericParam
*p1
, MonoGenericParam
*p2
)
5644 return mono_metadata_generic_param_equal_internal (p1
, p2
, TRUE
);
5648 mono_metadata_class_equal (MonoClass
*c1
, MonoClass
*c2
, gboolean signature_only
)
5652 if (mono_class_is_ginst (c1
) && mono_class_is_ginst (c2
))
5653 return _mono_metadata_generic_class_equal (mono_class_get_generic_class (c1
), mono_class_get_generic_class (c2
), signature_only
);
5654 if (mono_class_is_ginst (c1
) && mono_class_is_gtd (c2
))
5655 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c1
), c2
, signature_only
);
5656 if (mono_class_is_gtd (c1
) && mono_class_is_ginst (c2
))
5657 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c2
), c1
, signature_only
);
5658 MonoType
*c1_type
= m_class_get_byval_arg (c1
);
5659 MonoType
*c2_type
= m_class_get_byval_arg (c2
);
5660 if ((c1_type
->type
== MONO_TYPE_VAR
) && (c2_type
->type
== MONO_TYPE_VAR
))
5661 return mono_metadata_generic_param_equal_internal (
5662 c1_type
->data
.generic_param
, c2_type
->data
.generic_param
, signature_only
);
5663 if ((c1_type
->type
== MONO_TYPE_MVAR
) && (c2_type
->type
== MONO_TYPE_MVAR
))
5664 return mono_metadata_generic_param_equal_internal (
5665 c1_type
->data
.generic_param
, c2_type
->data
.generic_param
, signature_only
);
5666 if (signature_only
&&
5667 (c1_type
->type
== MONO_TYPE_SZARRAY
) && (c2_type
->type
== MONO_TYPE_SZARRAY
))
5668 return mono_metadata_class_equal (c1_type
->data
.klass
, c2_type
->data
.klass
, signature_only
);
5669 if (signature_only
&&
5670 (c1_type
->type
== MONO_TYPE_ARRAY
) && (c2_type
->type
== MONO_TYPE_ARRAY
))
5671 return do_mono_metadata_type_equal (c1_type
, c2_type
, signature_only
);
5676 mono_metadata_fnptr_equal (MonoMethodSignature
*s1
, MonoMethodSignature
*s2
, gboolean signature_only
)
5678 gpointer iter1
= 0, iter2
= 0;
5682 if (s1
->call_convention
!= s2
->call_convention
)
5684 if (s1
->sentinelpos
!= s2
->sentinelpos
)
5686 if (s1
->hasthis
!= s2
->hasthis
)
5688 if (s1
->explicit_this
!= s2
->explicit_this
)
5690 if (! do_mono_metadata_type_equal (s1
->ret
, s2
->ret
, signature_only
))
5692 if (s1
->param_count
!= s2
->param_count
)
5696 MonoType
*t1
= mono_signature_get_params (s1
, &iter1
);
5697 MonoType
*t2
= mono_signature_get_params (s2
, &iter2
);
5699 if (t1
== NULL
|| t2
== NULL
)
5701 if (! do_mono_metadata_type_equal (t1
, t2
, signature_only
))
5707 mono_metadata_custom_modifiers_equal (MonoType
*t1
, MonoType
*t2
, gboolean signature_only
)
5710 // The CLI itself shall treat required and optional modifiers in the same manner.
5711 // Two signatures that differ only by the addition of a custom modifier
5712 // (required or optional) shall not be considered to match.
5713 int count
= mono_type_custom_modifier_count (t1
);
5714 if (count
!= mono_type_custom_modifier_count (t2
))
5717 for (int i
=0; i
< count
; i
++) {
5718 // FIXME: propagate error to caller
5720 gboolean cm1_required
, cm2_required
;
5722 MonoType
*cm1_type
= mono_type_get_custom_modifier (t1
, i
, &cm1_required
, error
);
5723 mono_error_assert_ok (error
);
5724 MonoType
*cm2_type
= mono_type_get_custom_modifier (t2
, i
, &cm2_required
, error
);
5725 mono_error_assert_ok (error
);
5727 if (cm1_required
!= cm2_required
)
5730 if (!do_mono_metadata_type_equal (cm1_type
, cm2_type
, signature_only
))
5737 * mono_metadata_type_equal:
5740 * @signature_only: If true, treat ginsts as equal which are instantiated separately but have equal positional value
5742 * Determine if @t1 and @t2 represent the same type.
5743 * Returns: #TRUE if @t1 and @t2 are equal.
5746 do_mono_metadata_type_equal (MonoType
*t1
, MonoType
*t2
, gboolean signature_only
)
5748 if (t1
->type
!= t2
->type
|| t1
->byref
!= t2
->byref
)
5751 gboolean cmod_reject
= FALSE
;
5753 if (t1
->has_cmods
!= t2
->has_cmods
)
5755 else if (t1
->has_cmods
&& t2
->has_cmods
) {
5756 cmod_reject
= !mono_metadata_custom_modifiers_equal (t1
, t2
, signature_only
);
5759 gboolean result
= FALSE
;
5762 case MONO_TYPE_VOID
:
5763 case MONO_TYPE_BOOLEAN
:
5764 case MONO_TYPE_CHAR
:
5775 case MONO_TYPE_STRING
:
5778 case MONO_TYPE_OBJECT
:
5779 case MONO_TYPE_TYPEDBYREF
:
5782 case MONO_TYPE_VALUETYPE
:
5783 case MONO_TYPE_CLASS
:
5784 case MONO_TYPE_SZARRAY
:
5785 result
= mono_metadata_class_equal (t1
->data
.klass
, t2
->data
.klass
, signature_only
);
5788 result
= do_mono_metadata_type_equal (t1
->data
.type
, t2
->data
.type
, signature_only
);
5790 case MONO_TYPE_ARRAY
:
5791 if (t1
->data
.array
->rank
!= t2
->data
.array
->rank
)
5794 result
= mono_metadata_class_equal (t1
->data
.array
->eklass
, t2
->data
.array
->eklass
, signature_only
);
5796 case MONO_TYPE_GENERICINST
:
5797 result
= _mono_metadata_generic_class_equal (
5798 t1
->data
.generic_class
, t2
->data
.generic_class
, signature_only
);
5801 result
= mono_metadata_generic_param_equal_internal (
5802 t1
->data
.generic_param
, t2
->data
.generic_param
, signature_only
);
5804 case MONO_TYPE_MVAR
:
5805 result
= mono_metadata_generic_param_equal_internal (
5806 t1
->data
.generic_param
, t2
->data
.generic_param
, signature_only
);
5808 case MONO_TYPE_FNPTR
:
5809 result
= mono_metadata_fnptr_equal (t1
->data
.method
, t2
->data
.method
, signature_only
);
5812 g_error ("implement type compare for %0x!", t1
->type
);
5816 return result
&& !cmod_reject
;
5820 * mono_metadata_type_equal:
5823 mono_metadata_type_equal (MonoType
*t1
, MonoType
*t2
)
5825 return do_mono_metadata_type_equal (t1
, t2
, FALSE
);
5829 * mono_metadata_type_equal_full:
5831 * \param t2 another type
5832 * \param signature_only if signature only comparison should be made
5834 * Determine if \p t1 and \p t2 are signature compatible if \p signature_only is TRUE, otherwise
5835 * behaves the same way as mono_metadata_type_equal.
5836 * The function mono_metadata_type_equal(a, b) is just a shortcut for mono_metadata_type_equal_full(a, b, FALSE).
5837 * \returns TRUE if \p t1 and \p t2 are equal taking \p signature_only into account.
5840 mono_metadata_type_equal_full (MonoType
*t1
, MonoType
*t2
, gboolean signature_only
)
5842 return do_mono_metadata_type_equal (t1
, t2
, signature_only
);
5846 * mono_metadata_signature_equal:
5847 * \param sig1 a signature
5848 * \param sig2 another signature
5850 * Determine if \p sig1 and \p sig2 represent the same signature, with the
5851 * same number of arguments and the same types.
5852 * \returns TRUE if \p sig1 and \p sig2 are equal.
5855 mono_metadata_signature_equal (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
5859 if (sig1
->hasthis
!= sig2
->hasthis
|| sig1
->param_count
!= sig2
->param_count
)
5862 if (sig1
->generic_param_count
!= sig2
->generic_param_count
)
5866 * We're just comparing the signatures of two methods here:
5868 * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
5869 * U and V are equal here.
5871 * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
5874 for (i
= 0; i
< sig1
->param_count
; i
++) {
5875 MonoType
*p1
= sig1
->params
[i
];
5876 MonoType
*p2
= sig2
->params
[i
];
5878 /* if (p1->attrs != p2->attrs)
5881 if (!do_mono_metadata_type_equal (p1
, p2
, TRUE
))
5885 if (!do_mono_metadata_type_equal (sig1
->ret
, sig2
->ret
, TRUE
))
5891 mono_type_get_custom_modifier (const MonoType
*ty
, uint8_t idx
, gboolean
*required
, MonoError
*error
)
5893 g_assert (ty
->has_cmods
);
5894 if (mono_type_is_aggregate_mods (ty
)) {
5895 MonoAggregateModContainer
*amods
= mono_type_get_amods (ty
);
5896 g_assert (idx
< amods
->count
);
5897 MonoSingleCustomMod
*cmod
= &amods
->modifiers
[idx
];
5899 *required
= !!cmod
->required
;
5902 MonoCustomModContainer
*cmods
= mono_type_get_cmods (ty
);
5903 g_assert (idx
< cmods
->count
);
5904 MonoCustomMod
*cmod
= &cmods
->modifiers
[idx
];
5906 *required
= !!cmod
->required
;
5907 MonoImage
*image
= cmods
->image
;
5908 uint32_t token
= cmod
->token
;
5909 return mono_type_get_checked (image
, token
, NULL
, error
);
5915 * mono_metadata_type_dup:
5916 * \param image image to alloc memory from
5917 * \param original type to duplicate
5918 * \returns copy of type allocated from the image's mempool (or from the heap, if \p image is null).
5921 mono_metadata_type_dup (MonoImage
*image
, const MonoType
*o
)
5923 return mono_metadata_type_dup_with_cmods (image
, o
, o
);
5927 deep_type_dup_fixup (MonoImage
*image
, MonoType
*r
, const MonoType
*o
);
5930 custom_modifier_copy (MonoAggregateModContainer
*dest
, uint8_t dest_offset
, const MonoType
*source
)
5932 if (mono_type_is_aggregate_mods (source
)) {
5933 MonoAggregateModContainer
*src_cmods
= mono_type_get_amods (source
);
5934 memcpy (&dest
->modifiers
[dest_offset
], &src_cmods
->modifiers
[0], src_cmods
->count
* sizeof (MonoSingleCustomMod
));
5935 dest_offset
+= src_cmods
->count
;
5937 MonoCustomModContainer
*src_cmods
= mono_type_get_cmods (source
);
5938 for (int i
= 0; i
< src_cmods
->count
; i
++) {
5939 ERROR_DECL (error
); // XXX FIXME: AK - propagate the error to the caller.
5940 MonoSingleCustomMod
*cmod
= &dest
->modifiers
[dest_offset
++];
5941 cmod
->type
= mono_type_get_checked (src_cmods
->image
, src_cmods
->modifiers
[i
].token
, NULL
, error
);
5942 mono_error_assert_ok (error
);
5943 cmod
->required
= src_cmods
->modifiers
[i
].required
;
5949 /* makes a dup of 'o' but also appends the custom modifiers from 'cmods_source' */
5951 do_metadata_type_dup_append_cmods (MonoImage
*image
, const MonoType
*o
, const MonoType
*cmods_source
)
5953 g_assert (o
!= cmods_source
);
5954 g_assert (o
->has_cmods
);
5955 g_assert (cmods_source
->has_cmods
);
5956 if (!mono_type_is_aggregate_mods (o
) &&
5957 !mono_type_is_aggregate_mods (cmods_source
) &&
5958 mono_type_get_cmods (o
)->image
== mono_type_get_cmods (cmods_source
)->image
) {
5959 /* the uniform case: all the cmods are from the same image. */
5960 MonoCustomModContainer
*o_cmods
= mono_type_get_cmods (o
);
5961 MonoCustomModContainer
*extra_cmods
= mono_type_get_cmods (cmods_source
);
5962 uint8_t total_cmods
= o_cmods
->count
+ extra_cmods
->count
;
5963 gboolean aggregate
= FALSE
;
5964 size_t sizeof_dup
= mono_sizeof_type_with_mods (total_cmods
, aggregate
);
5965 MonoType
*r
= image
? (MonoType
*)mono_image_alloc0 (image
, sizeof_dup
) : (MonoType
*)g_malloc0 (sizeof_dup
);
5967 mono_type_with_mods_init (r
, total_cmods
, aggregate
);
5969 /* copy the original type o, not including its modifiers */
5970 memcpy (r
, o
, mono_sizeof_type_with_mods (0, FALSE
));
5971 deep_type_dup_fixup (image
, r
, o
);
5973 /* The modifier order matters to Roslyn, they expect the extra cmods to come first:
5975 * Suppose we substitute 'int32 modopt(IsLong)' for 'T' in 'void Test
5976 * (T modopt(IsConst))'. Roslyn expects the result to be 'void Test
5977 * (int32 modopt(IsLong) modopt(IsConst))'.
5979 * but! cmods are encoded in IL in reverse order, so 'int32 modopt(IsConst) modopt(IsLong)' is
5980 * encoded as `cmod_opt [typeref IsLong] cmod_opt [typeref IsConst] I4`
5981 * so in our array, extra_cmods (IsLong) come first, followed by o_cmods (IsConst)
5983 * (Here 'o' is 'int32 modopt(IsLong)' and cmods_source is 'T modopt(IsConst)')
5985 /* append the modifiers from cmods_source and o */
5986 MonoCustomModContainer
*r_container
= mono_type_get_cmods (r
);
5987 uint8_t dest_offset
= 0;
5988 r_container
->image
= extra_cmods
->image
;
5990 memcpy (&r_container
->modifiers
[dest_offset
], &o_cmods
->modifiers
[0], o_cmods
->count
* sizeof (MonoCustomMod
));
5991 dest_offset
+= o_cmods
->count
;
5992 memcpy (&r_container
->modifiers
[dest_offset
], &extra_cmods
->modifiers
[0], extra_cmods
->count
* sizeof (MonoCustomMod
));
5993 dest_offset
+= extra_cmods
->count
;
5994 g_assert (dest_offset
== total_cmods
);
5998 /* The aggregate case: either o_cmods or extra_cmods has aggregate cmods, or they're both simple but from different images. */
5999 uint8_t total_cmods
= 0;
6000 total_cmods
+= mono_type_custom_modifier_count (o
);
6001 total_cmods
+= mono_type_custom_modifier_count (cmods_source
);
6003 gboolean aggregate
= TRUE
;
6004 size_t sizeof_dup
= mono_sizeof_type_with_mods (total_cmods
, aggregate
);
6006 /* FIXME: if image, and the images of the custom modifiers from
6007 * o and cmods_source are all different, we need an image
6009 MonoType
*r
= image
? (MonoType
*)mono_image_alloc0 (image
, sizeof_dup
) : (MonoType
*)g_malloc0 (sizeof_dup
);
6011 mono_type_with_mods_init (r
, total_cmods
, aggregate
);
6013 memcpy (r
, o
, mono_sizeof_type_with_mods (0, FALSE
));
6014 deep_type_dup_fixup (image
, r
, o
);
6016 /* Try not to blow up the stack. See comment on
6017 * MONO_MAX_EXPECTED_CMODS. Since here we're appending all the
6018 * mods together, it's possible we'll end up with more than the
6019 * maximum allowed. If that ever happens in practice, we
6020 * should redefine the bound and possibly make this function
6021 * fail dynamically instead of asserting.
6023 g_assert (total_cmods
< MONO_MAX_EXPECTED_CMODS
);
6024 size_t r_container_size
= mono_sizeof_aggregate_modifiers (total_cmods
);
6025 MonoAggregateModContainer
*r_container_candidate
= g_alloca (r_container_size
);
6026 memset (r_container_candidate
, 0, r_container_size
);
6027 uint8_t dest_offset
= 0;
6029 dest_offset
= custom_modifier_copy (r_container_candidate
, dest_offset
, o
);
6030 dest_offset
= custom_modifier_copy (r_container_candidate
, dest_offset
, cmods_source
);
6031 g_assert (dest_offset
== total_cmods
);
6032 r_container_candidate
->count
= total_cmods
;
6034 mono_type_set_amods (r
, mono_metadata_get_canonical_aggregate_modifiers (r_container_candidate
));
6041 * Works the same way as mono_metadata_type_dup but pick cmods from @cmods_source
6044 mono_metadata_type_dup_with_cmods (MonoImage
*image
, const MonoType
*o
, const MonoType
*cmods_source
)
6046 if (o
->has_cmods
&& o
!= cmods_source
&& cmods_source
->has_cmods
) {
6047 return do_metadata_type_dup_append_cmods (image
, o
, cmods_source
);
6052 /* if we get here, either o and cmods_source alias, or else exactly one of them has cmods. */
6054 uint8_t num_mods
= MAX (mono_type_custom_modifier_count (o
), mono_type_custom_modifier_count (cmods_source
));
6055 gboolean aggregate
= mono_type_is_aggregate_mods (o
) || mono_type_is_aggregate_mods (cmods_source
);
6056 size_t sizeof_r
= mono_sizeof_type_with_mods (num_mods
, aggregate
);
6058 r
= image
? (MonoType
*)mono_image_alloc0 (image
, sizeof_r
) : (MonoType
*)g_malloc0 (sizeof_r
);
6060 if (cmods_source
->has_cmods
) {
6061 /* FIXME: if it's aggregate what do we assert here? */
6062 g_assert (!image
|| (!aggregate
&& image
== mono_type_get_cmods (cmods_source
)->image
));
6063 memcpy (r
, cmods_source
, mono_sizeof_type (cmods_source
));
6066 memcpy (r
, o
, mono_sizeof_type (o
));
6068 /* reset custom mod count and aggregateness to be correct. */
6069 mono_type_with_mods_init (r
, num_mods
, aggregate
);
6071 mono_type_set_amods (r
, mono_type_is_aggregate_mods (o
) ? mono_type_get_amods (o
) : mono_type_get_amods (cmods_source
));
6072 deep_type_dup_fixup (image
, r
, o
);
6078 deep_type_dup_fixup (MonoImage
*image
, MonoType
*r
, const MonoType
*o
)
6080 if (o
->type
== MONO_TYPE_PTR
) {
6081 r
->data
.type
= mono_metadata_type_dup (image
, o
->data
.type
);
6082 } else if (o
->type
== MONO_TYPE_ARRAY
) {
6083 r
->data
.array
= mono_dup_array_type (image
, o
->data
.array
);
6084 } else if (o
->type
== MONO_TYPE_FNPTR
) {
6085 /*FIXME the dup'ed signature is leaked mono_metadata_free_type*/
6086 r
->data
.method
= mono_metadata_signature_deep_dup (image
, o
->data
.method
);
6091 * mono_signature_hash:
6094 mono_signature_hash (MonoMethodSignature
*sig
)
6096 guint i
, res
= sig
->ret
->type
;
6098 for (i
= 0; i
< sig
->param_count
; i
++)
6099 res
= (res
<< 5) - res
+ mono_type_hash (sig
->params
[i
]);
6105 * mono_metadata_encode_value:
6106 * @value: value to encode
6107 * @buf: buffer where to write the compressed representation
6108 * @endbuf: pointer updated to point at the end of the encoded output
6110 * Encodes the value @value in the compressed representation used
6111 * in metadata and stores the result in @buf. @buf needs to be big
6112 * enough to hold the data (4 bytes).
6115 mono_metadata_encode_value (guint32 value
, char *buf
, char **endbuf
)
6121 else if (value
< 0x4000) {
6122 p
[0] = 0x80 | (value
>> 8);
6123 p
[1] = value
& 0xff;
6126 p
[0] = (value
>> 24) | 0xc0;
6127 p
[1] = (value
>> 16) & 0xff;
6128 p
[2] = (value
>> 8) & 0xff;
6129 p
[3] = value
& 0xff;
6137 * mono_metadata_field_info:
6138 * \param meta the Image the field is defined in
6139 * \param index the index in the field table representing the field
6140 * \param offset a pointer to an integer where to store the offset that may have been specified for the field in a FieldLayout table
6141 * \param rva a pointer to the RVA of the field data in the image that may have been defined in a \c FieldRVA table
6142 * \param marshal_spec a pointer to the marshal spec that may have been defined for the field in a \c FieldMarshal table.
6144 * Gather info for field \p index that may have been defined in the \c FieldLayout,
6145 * \c FieldRVA and \c FieldMarshal tables.
6146 * Either of \p offset, \p rva and \p marshal_spec can be NULL if you're not interested
6150 mono_metadata_field_info (MonoImage
*meta
, guint32 index
, guint32
*offset
, guint32
*rva
,
6151 MonoMarshalSpec
**marshal_spec
)
6153 mono_metadata_field_info_full (meta
, index
, offset
, rva
, marshal_spec
, FALSE
);
6157 mono_metadata_field_info_with_mempool (MonoImage
*meta
, guint32 index
, guint32
*offset
, guint32
*rva
,
6158 MonoMarshalSpec
**marshal_spec
)
6160 mono_metadata_field_info_full (meta
, index
, offset
, rva
, marshal_spec
, TRUE
);
6164 mono_metadata_field_info_full (MonoImage
*meta
, guint32 index
, guint32
*offset
, guint32
*rva
,
6165 MonoMarshalSpec
**marshal_spec
, gboolean alloc_from_image
)
6167 MonoTableInfo
*tdef
;
6170 loc
.idx
= index
+ 1;
6171 if (meta
->uncompressed_metadata
)
6172 loc
.idx
= search_ptr_table (meta
, MONO_TABLE_FIELD_POINTER
, loc
.idx
);
6175 tdef
= &meta
->tables
[MONO_TABLE_FIELDLAYOUT
];
6177 loc
.col_idx
= MONO_FIELD_LAYOUT_FIELD
;
6180 if (tdef
->base
&& mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
)) {
6181 *offset
= mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_FIELD_LAYOUT_OFFSET
);
6183 *offset
= (guint32
)-1;
6187 tdef
= &meta
->tables
[MONO_TABLE_FIELDRVA
];
6189 loc
.col_idx
= MONO_FIELD_RVA_FIELD
;
6192 if (tdef
->base
&& mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
)) {
6194 * LAMESPEC: There is no signature, no nothing, just the raw data.
6196 *rva
= mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_FIELD_RVA_RVA
);
6204 if ((p
= mono_metadata_get_marshal_info (meta
, index
, TRUE
))) {
6205 *marshal_spec
= mono_metadata_parse_marshal_spec_full (alloc_from_image
? meta
: NULL
, meta
, p
);
6212 * mono_metadata_get_constant_index:
6213 * \param meta the Image the field is defined in
6214 * \param index the token that may have a row defined in the constants table
6215 * \param hint possible position for the row
6217 * \p token must be a \c FieldDef, \c ParamDef or \c PropertyDef token.
6219 * \returns the index into the \c Constants table or 0 if not found.
6222 mono_metadata_get_constant_index (MonoImage
*meta
, guint32 token
, guint32 hint
)
6224 MonoTableInfo
*tdef
;
6226 guint32 index
= mono_metadata_token_index (token
);
6228 tdef
= &meta
->tables
[MONO_TABLE_CONSTANT
];
6229 index
<<= MONO_HASCONSTANT_BITS
;
6230 switch (mono_metadata_token_table (token
)) {
6231 case MONO_TABLE_FIELD
:
6232 index
|= MONO_HASCONSTANT_FIEDDEF
;
6234 case MONO_TABLE_PARAM
:
6235 index
|= MONO_HASCONSTANT_PARAM
;
6237 case MONO_TABLE_PROPERTY
:
6238 index
|= MONO_HASCONSTANT_PROPERTY
;
6241 g_warning ("Not a valid token for the constant table: 0x%08x", token
);
6245 loc
.col_idx
= MONO_CONSTANT_PARENT
;
6248 /* FIXME: Index translation */
6250 if ((hint
> 0) && (hint
< tdef
->rows
) && (mono_metadata_decode_row_col (tdef
, hint
- 1, MONO_CONSTANT_PARENT
) == index
))
6253 if (tdef
->base
&& mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
)) {
6254 return loc
.result
+ 1;
6260 * mono_metadata_events_from_typedef:
6261 * \param meta metadata context
6262 * \param index 0-based index (in the \c TypeDef table) describing a type
6263 * \returns the 0-based index in the \c Event table for the events in the
6264 * type. The last event that belongs to the type (plus 1) is stored
6265 * in the \p end_idx pointer.
6268 mono_metadata_events_from_typedef (MonoImage
*meta
, guint32 index
, guint
*end_idx
)
6272 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_EVENTMAP
];
6280 loc
.col_idx
= MONO_EVENT_MAP_PARENT
;
6281 loc
.idx
= index
+ 1;
6283 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
6286 start
= mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_EVENT_MAP_EVENTLIST
);
6287 if (loc
.result
+ 1 < tdef
->rows
) {
6288 end
= mono_metadata_decode_row_col (tdef
, loc
.result
+ 1, MONO_EVENT_MAP_EVENTLIST
) - 1;
6290 end
= meta
->tables
[MONO_TABLE_EVENT
].rows
;
6298 * mono_metadata_methods_from_event:
6299 * \param meta metadata context
6300 * \param index 0-based index (in the \c Event table) describing a event
6301 * \returns the 0-based index in the \c MethodDef table for the methods in the
6302 * event. The last method that belongs to the event (plus 1) is stored
6303 * in the \p end_idx pointer.
6306 mono_metadata_methods_from_event (MonoImage
*meta
, guint32 index
, guint
*end_idx
)
6310 guint32 cols
[MONO_METHOD_SEMA_SIZE
];
6311 MonoTableInfo
*msemt
= &meta
->tables
[MONO_TABLE_METHODSEMANTICS
];
6317 if (meta
->uncompressed_metadata
)
6318 index
= search_ptr_table (meta
, MONO_TABLE_EVENT_POINTER
, index
+ 1) - 1;
6321 loc
.col_idx
= MONO_METHOD_SEMA_ASSOCIATION
;
6322 loc
.idx
= ((index
+ 1) << MONO_HAS_SEMANTICS_BITS
) | MONO_HAS_SEMANTICS_EVENT
; /* Method association coded index */
6324 if (!mono_binary_search (&loc
, msemt
->base
, msemt
->rows
, msemt
->row_size
, table_locator
))
6329 * We may end up in the middle of the rows...
6332 if (loc
.idx
== mono_metadata_decode_row_col (msemt
, start
- 1, MONO_METHOD_SEMA_ASSOCIATION
))
6338 while (end
< msemt
->rows
) {
6339 mono_metadata_decode_row (msemt
, end
, cols
, MONO_METHOD_SEMA_SIZE
);
6340 if (cols
[MONO_METHOD_SEMA_ASSOCIATION
] != loc
.idx
)
6349 * mono_metadata_properties_from_typedef:
6350 * \param meta metadata context
6351 * \param index 0-based index (in the \c TypeDef table) describing a type
6352 * \returns the 0-based index in the \c Property table for the properties in the
6353 * type. The last property that belongs to the type (plus 1) is stored
6354 * in the \p end_idx pointer.
6357 mono_metadata_properties_from_typedef (MonoImage
*meta
, guint32 index
, guint
*end_idx
)
6361 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_PROPERTYMAP
];
6369 loc
.col_idx
= MONO_PROPERTY_MAP_PARENT
;
6370 loc
.idx
= index
+ 1;
6372 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
6375 start
= mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_PROPERTY_MAP_PROPERTY_LIST
);
6376 if (loc
.result
+ 1 < tdef
->rows
) {
6377 end
= mono_metadata_decode_row_col (tdef
, loc
.result
+ 1, MONO_PROPERTY_MAP_PROPERTY_LIST
) - 1;
6379 end
= meta
->tables
[MONO_TABLE_PROPERTY
].rows
;
6387 * mono_metadata_methods_from_property:
6388 * \param meta metadata context
6389 * \param index 0-based index (in the \c PropertyDef table) describing a property
6390 * \returns the 0-based index in the \c MethodDef table for the methods in the
6391 * property. The last method that belongs to the property (plus 1) is stored
6392 * in the \p end_idx pointer.
6395 mono_metadata_methods_from_property (MonoImage
*meta
, guint32 index
, guint
*end_idx
)
6399 guint32 cols
[MONO_METHOD_SEMA_SIZE
];
6400 MonoTableInfo
*msemt
= &meta
->tables
[MONO_TABLE_METHODSEMANTICS
];
6406 if (meta
->uncompressed_metadata
)
6407 index
= search_ptr_table (meta
, MONO_TABLE_PROPERTY_POINTER
, index
+ 1) - 1;
6410 loc
.col_idx
= MONO_METHOD_SEMA_ASSOCIATION
;
6411 loc
.idx
= ((index
+ 1) << MONO_HAS_SEMANTICS_BITS
) | MONO_HAS_SEMANTICS_PROPERTY
; /* Method association coded index */
6413 if (!mono_binary_search (&loc
, msemt
->base
, msemt
->rows
, msemt
->row_size
, table_locator
))
6418 * We may end up in the middle of the rows...
6421 if (loc
.idx
== mono_metadata_decode_row_col (msemt
, start
- 1, MONO_METHOD_SEMA_ASSOCIATION
))
6427 while (end
< msemt
->rows
) {
6428 mono_metadata_decode_row (msemt
, end
, cols
, MONO_METHOD_SEMA_SIZE
);
6429 if (cols
[MONO_METHOD_SEMA_ASSOCIATION
] != loc
.idx
)
6438 * mono_metadata_implmap_from_method:
6441 mono_metadata_implmap_from_method (MonoImage
*meta
, guint32 method_idx
)
6444 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_IMPLMAP
];
6449 /* No index translation seems to be needed */
6452 loc
.col_idx
= MONO_IMPLMAP_MEMBER
;
6453 loc
.idx
= ((method_idx
+ 1) << MONO_MEMBERFORWD_BITS
) | MONO_MEMBERFORWD_METHODDEF
;
6455 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
6458 return loc
.result
+ 1;
6462 * mono_type_create_from_typespec:
6463 * \param image context where the image is created
6464 * \param type_spec typespec token
6465 * \deprecated use \c mono_type_create_from_typespec_checked that has proper error handling
6467 * Creates a \c MonoType representing the \c TypeSpec indexed by the \p type_spec
6471 mono_type_create_from_typespec (MonoImage
*image
, guint32 type_spec
)
6474 MonoType
*type
= mono_type_create_from_typespec_checked (image
, type_spec
, error
);
6476 g_error ("Could not create typespec %x due to %s", type_spec
, mono_error_get_message (error
));
6481 mono_type_create_from_typespec_checked (MonoImage
*image
, guint32 type_spec
, MonoError
*error
)
6484 guint32 idx
= mono_metadata_token_index (type_spec
);
6486 guint32 cols
[MONO_TYPESPEC_SIZE
];
6488 MonoType
*type
, *type2
;
6492 type
= (MonoType
*)mono_conc_hashtable_lookup (image
->typespec_cache
, GUINT_TO_POINTER (type_spec
));
6496 t
= &image
->tables
[MONO_TABLE_TYPESPEC
];
6498 mono_metadata_decode_row (t
, idx
-1, cols
, MONO_TYPESPEC_SIZE
);
6499 ptr
= mono_metadata_blob_heap (image
, cols
[MONO_TYPESPEC_SIGNATURE
]);
6501 if (!mono_verifier_verify_typespec_signature (image
, cols
[MONO_TYPESPEC_SIGNATURE
], type_spec
, error
))
6504 mono_metadata_decode_value (ptr
, &ptr
);
6506 type
= mono_metadata_parse_type_checked (image
, NULL
, 0, TRUE
, ptr
, &ptr
, error
);
6510 type2
= mono_metadata_type_dup (image
, type
);
6511 mono_metadata_free_type (type
);
6513 mono_image_lock (image
);
6515 /* We might leak some data in the image mempool if found */
6516 type
= (MonoType
*)mono_conc_hashtable_insert (image
->typespec_cache
, GUINT_TO_POINTER (type_spec
), type2
);
6520 mono_image_unlock (image
);
6527 mono_image_strndup (MonoImage
*image
, const char *data
, guint len
)
6531 return g_strndup (data
, len
);
6532 res
= (char *)mono_image_alloc (image
, len
+ 1);
6533 memcpy (res
, data
, len
);
6539 * mono_metadata_parse_marshal_spec:
6542 mono_metadata_parse_marshal_spec (MonoImage
*image
, const char *ptr
)
6544 return mono_metadata_parse_marshal_spec_full (NULL
, image
, ptr
);
6548 * If IMAGE is non-null, memory will be allocated from its mempool, otherwise it will be allocated using malloc.
6549 * PARENT_IMAGE is the image containing the marshal spec.
6552 mono_metadata_parse_marshal_spec_full (MonoImage
*image
, MonoImage
*parent_image
, const char *ptr
)
6554 MonoMarshalSpec
*res
;
6556 const char *start
= ptr
;
6558 /* fixme: this is incomplete, but I cant find more infos in the specs */
6561 res
= (MonoMarshalSpec
*)mono_image_alloc0 (image
, sizeof (MonoMarshalSpec
));
6563 res
= g_new0 (MonoMarshalSpec
, 1);
6565 len
= mono_metadata_decode_value (ptr
, &ptr
);
6566 res
->native
= (MonoMarshalNative
)*ptr
++;
6568 if (res
->native
== MONO_NATIVE_LPARRAY
) {
6569 res
->data
.array_data
.param_num
= -1;
6570 res
->data
.array_data
.num_elem
= -1;
6571 res
->data
.array_data
.elem_mult
= -1;
6573 if (ptr
- start
<= len
)
6574 res
->data
.array_data
.elem_type
= (MonoMarshalNative
)*ptr
++;
6575 if (ptr
- start
<= len
)
6576 res
->data
.array_data
.param_num
= mono_metadata_decode_value (ptr
, &ptr
);
6577 if (ptr
- start
<= len
)
6578 res
->data
.array_data
.num_elem
= mono_metadata_decode_value (ptr
, &ptr
);
6579 if (ptr
- start
<= len
) {
6581 * LAMESPEC: Older spec versions say this parameter comes before
6582 * num_elem. Never spec versions don't talk about elem_mult at
6583 * all, but csc still emits it, and it is used to distinguish
6584 * between param_num being 0, and param_num being omitted.
6585 * So if (param_num == 0) && (num_elem > 0), then
6586 * elem_mult == 0 -> the array size is num_elem
6587 * elem_mult == 1 -> the array size is @param_num + num_elem
6589 res
->data
.array_data
.elem_mult
= mono_metadata_decode_value (ptr
, &ptr
);
6593 if (res
->native
== MONO_NATIVE_BYVALTSTR
) {
6594 if (ptr
- start
<= len
)
6595 res
->data
.array_data
.num_elem
= mono_metadata_decode_value (ptr
, &ptr
);
6598 if (res
->native
== MONO_NATIVE_BYVALARRAY
) {
6599 if (ptr
- start
<= len
)
6600 res
->data
.array_data
.num_elem
= mono_metadata_decode_value (ptr
, &ptr
);
6603 if (res
->native
== MONO_NATIVE_CUSTOM
) {
6604 /* skip unused type guid */
6605 len
= mono_metadata_decode_value (ptr
, &ptr
);
6607 /* skip unused native type name */
6608 len
= mono_metadata_decode_value (ptr
, &ptr
);
6610 /* read custom marshaler type name */
6611 len
= mono_metadata_decode_value (ptr
, &ptr
);
6612 res
->data
.custom_data
.custom_name
= mono_image_strndup (image
, ptr
, len
);
6614 /* read cookie string */
6615 len
= mono_metadata_decode_value (ptr
, &ptr
);
6616 res
->data
.custom_data
.cookie
= mono_image_strndup (image
, ptr
, len
);
6617 res
->data
.custom_data
.image
= parent_image
;
6620 if (res
->native
== MONO_NATIVE_SAFEARRAY
) {
6621 res
->data
.safearray_data
.elem_type
= (MonoMarshalVariant
)0;
6622 res
->data
.safearray_data
.num_elem
= 0;
6623 if (ptr
- start
<= len
)
6624 res
->data
.safearray_data
.elem_type
= (MonoMarshalVariant
)*ptr
++;
6625 if (ptr
- start
<= len
)
6626 res
->data
.safearray_data
.num_elem
= *ptr
++;
6632 * mono_metadata_free_marshal_spec:
6635 mono_metadata_free_marshal_spec (MonoMarshalSpec
*spec
)
6640 if (spec
->native
== MONO_NATIVE_CUSTOM
) {
6641 g_free (spec
->data
.custom_data
.custom_name
);
6642 g_free (spec
->data
.custom_data
.cookie
);
6648 * mono_type_to_unmanaged:
6649 * The value pointed to by \p conv will contain the kind of marshalling required for this
6650 * particular type one of the \c MONO_MARSHAL_CONV_ enumeration values.
6651 * \returns A \c MonoMarshalNative enumeration value (<code>MONO_NATIVE_</code>) value
6652 * describing the underlying native reprensetation of the type.
6654 guint32
// FIXMEcxx MonoMarshalNative
6655 mono_type_to_unmanaged (MonoType
*type
, MonoMarshalSpec
*mspec
, gboolean as_field
,
6656 gboolean unicode
, MonoMarshalConv
*conv
)
6658 MonoMarshalConv dummy_conv
;
6664 *conv
= MONO_MARSHAL_CONV_NONE
;
6667 return MONO_NATIVE_UINT
;
6671 case MONO_TYPE_BOOLEAN
:
6673 switch (mspec
->native
) {
6674 case MONO_NATIVE_VARIANTBOOL
:
6675 *conv
= MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
;
6676 return MONO_NATIVE_VARIANTBOOL
;
6677 case MONO_NATIVE_BOOLEAN
:
6678 *conv
= MONO_MARSHAL_CONV_BOOL_I4
;
6679 return MONO_NATIVE_BOOLEAN
;
6680 case MONO_NATIVE_I1
:
6681 case MONO_NATIVE_U1
:
6682 return mspec
->native
;
6684 g_error ("cant marshal bool to native type %02x", mspec
->native
);
6687 *conv
= MONO_MARSHAL_CONV_BOOL_I4
;
6688 return MONO_NATIVE_BOOLEAN
;
6689 case MONO_TYPE_CHAR
:
6691 switch (mspec
->native
) {
6692 case MONO_NATIVE_U2
:
6693 case MONO_NATIVE_U1
:
6694 return mspec
->native
;
6696 g_error ("cant marshal char to native type %02x", mspec
->native
);
6699 return unicode
? MONO_NATIVE_U2
: MONO_NATIVE_U1
;
6700 case MONO_TYPE_I1
: return MONO_NATIVE_I1
;
6701 case MONO_TYPE_U1
: return MONO_NATIVE_U1
;
6702 case MONO_TYPE_I2
: return MONO_NATIVE_I2
;
6703 case MONO_TYPE_U2
: return MONO_NATIVE_U2
;
6704 case MONO_TYPE_I4
: return MONO_NATIVE_I4
;
6705 case MONO_TYPE_U4
: return MONO_NATIVE_U4
;
6706 case MONO_TYPE_I8
: return MONO_NATIVE_I8
;
6707 case MONO_TYPE_U8
: return MONO_NATIVE_U8
;
6708 case MONO_TYPE_R4
: return MONO_NATIVE_R4
;
6709 case MONO_TYPE_R8
: return MONO_NATIVE_R8
;
6710 case MONO_TYPE_STRING
:
6712 switch (mspec
->native
) {
6713 case MONO_NATIVE_BSTR
:
6714 *conv
= MONO_MARSHAL_CONV_STR_BSTR
;
6715 return MONO_NATIVE_BSTR
;
6716 case MONO_NATIVE_LPSTR
:
6717 *conv
= MONO_MARSHAL_CONV_STR_LPSTR
;
6718 return MONO_NATIVE_LPSTR
;
6719 case MONO_NATIVE_LPWSTR
:
6720 *conv
= MONO_MARSHAL_CONV_STR_LPWSTR
;
6721 return MONO_NATIVE_LPWSTR
;
6722 case MONO_NATIVE_LPTSTR
:
6723 *conv
= MONO_MARSHAL_CONV_STR_LPTSTR
;
6724 return MONO_NATIVE_LPTSTR
;
6725 case MONO_NATIVE_ANSIBSTR
:
6726 *conv
= MONO_MARSHAL_CONV_STR_ANSIBSTR
;
6727 return MONO_NATIVE_ANSIBSTR
;
6728 case MONO_NATIVE_TBSTR
:
6729 *conv
= MONO_MARSHAL_CONV_STR_TBSTR
;
6730 return MONO_NATIVE_TBSTR
;
6731 case MONO_NATIVE_UTF8STR
:
6732 *conv
= MONO_MARSHAL_CONV_STR_UTF8STR
;
6733 return MONO_NATIVE_UTF8STR
;
6734 case MONO_NATIVE_BYVALTSTR
:
6736 *conv
= MONO_MARSHAL_CONV_STR_BYVALWSTR
;
6738 *conv
= MONO_MARSHAL_CONV_STR_BYVALSTR
;
6739 return MONO_NATIVE_BYVALTSTR
;
6741 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
);
6745 *conv
= MONO_MARSHAL_CONV_STR_LPWSTR
;
6746 return MONO_NATIVE_LPWSTR
;
6749 *conv
= MONO_MARSHAL_CONV_STR_LPSTR
;
6750 return MONO_NATIVE_LPSTR
;
6752 case MONO_TYPE_PTR
: return MONO_NATIVE_UINT
;
6753 case MONO_TYPE_VALUETYPE
: /*FIXME*/
6754 if (m_class_is_enumtype (type
->data
.klass
)) {
6755 t
= mono_class_enum_basetype_internal (type
->data
.klass
)->type
;
6758 if (type
->data
.klass
== mono_class_try_get_handleref_class ()){
6759 *conv
= MONO_MARSHAL_CONV_HANDLEREF
;
6760 return MONO_NATIVE_INT
;
6762 return MONO_NATIVE_STRUCT
;
6763 case MONO_TYPE_SZARRAY
:
6764 case MONO_TYPE_ARRAY
:
6766 switch (mspec
->native
) {
6767 case MONO_NATIVE_BYVALARRAY
:
6768 if ((m_class_get_element_class (type
->data
.klass
) == mono_defaults
.char_class
) && !unicode
)
6769 *conv
= MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
;
6771 *conv
= MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
;
6772 return MONO_NATIVE_BYVALARRAY
;
6773 case MONO_NATIVE_SAFEARRAY
:
6774 *conv
= MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
;
6775 return MONO_NATIVE_SAFEARRAY
;
6776 case MONO_NATIVE_LPARRAY
:
6777 *conv
= MONO_MARSHAL_CONV_ARRAY_LPARRAY
;
6778 return MONO_NATIVE_LPARRAY
;
6780 g_error ("cant marshal array as native type %02x", mspec
->native
);
6784 *conv
= MONO_MARSHAL_CONV_ARRAY_LPARRAY
;
6785 return MONO_NATIVE_LPARRAY
;
6786 case MONO_TYPE_I
: return MONO_NATIVE_INT
;
6787 case MONO_TYPE_U
: return MONO_NATIVE_UINT
;
6788 case MONO_TYPE_CLASS
:
6789 case MONO_TYPE_OBJECT
: {
6790 /* FIXME : we need to handle ArrayList and StringBuilder here, probably */
6792 switch (mspec
->native
) {
6793 case MONO_NATIVE_STRUCT
:
6794 // [MarshalAs(UnmanagedType.Struct)]
6797 // becomes a VARIANT
6799 // [MarshalAs(UnmangedType.Struct)]
6802 // becomes uses the CONV_OBJECT_STRUCT conversion
6803 if (t
!= MONO_TYPE_OBJECT
)
6804 *conv
= MONO_MARSHAL_CONV_OBJECT_STRUCT
;
6805 return MONO_NATIVE_STRUCT
;
6806 case MONO_NATIVE_CUSTOM
:
6807 return MONO_NATIVE_CUSTOM
;
6808 case MONO_NATIVE_INTERFACE
:
6809 *conv
= MONO_MARSHAL_CONV_OBJECT_INTERFACE
;
6810 return MONO_NATIVE_INTERFACE
;
6811 case MONO_NATIVE_IDISPATCH
:
6812 *conv
= MONO_MARSHAL_CONV_OBJECT_IDISPATCH
;
6813 return MONO_NATIVE_IDISPATCH
;
6814 case MONO_NATIVE_IUNKNOWN
:
6815 *conv
= MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
;
6816 return MONO_NATIVE_IUNKNOWN
;
6817 case MONO_NATIVE_FUNC
:
6818 if (t
== MONO_TYPE_CLASS
&& (type
->data
.klass
== mono_defaults
.multicastdelegate_class
||
6819 type
->data
.klass
== mono_defaults
.delegate_class
||
6820 m_class_get_parent (type
->data
.klass
) == mono_defaults
.multicastdelegate_class
)) {
6821 *conv
= MONO_MARSHAL_CONV_DEL_FTN
;
6822 return MONO_NATIVE_FUNC
;
6826 g_error ("cant marshal object as native type %02x", mspec
->native
);
6829 if (t
== MONO_TYPE_CLASS
&& (type
->data
.klass
== mono_defaults
.multicastdelegate_class
||
6830 type
->data
.klass
== mono_defaults
.delegate_class
||
6831 m_class_get_parent (type
->data
.klass
) == mono_defaults
.multicastdelegate_class
)) {
6832 *conv
= MONO_MARSHAL_CONV_DEL_FTN
;
6833 return MONO_NATIVE_FUNC
;
6835 if (mono_class_try_get_safehandle_class () && type
->data
.klass
!= NULL
&&
6836 mono_class_is_subclass_of_internal (type
->data
.klass
, mono_class_try_get_safehandle_class (), FALSE
)){
6837 *conv
= MONO_MARSHAL_CONV_SAFEHANDLE
;
6838 return MONO_NATIVE_INT
;
6841 if (t
== MONO_TYPE_CLASS
&& mono_cominterop_is_interface (type
->data
.klass
)){
6842 *conv
= MONO_MARSHAL_CONV_OBJECT_INTERFACE
;
6843 return MONO_NATIVE_INTERFACE
;
6846 *conv
= MONO_MARSHAL_CONV_OBJECT_STRUCT
;
6847 return MONO_NATIVE_STRUCT
;
6849 case MONO_TYPE_FNPTR
: return MONO_NATIVE_FUNC
;
6850 case MONO_TYPE_GENERICINST
:
6851 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
6854 case MONO_TYPE_TYPEDBYREF
:
6856 g_error ("type 0x%02x not handled in marshal", t
);
6858 return MONO_NATIVE_MAX
;
6862 * mono_metadata_get_marshal_info:
6865 mono_metadata_get_marshal_info (MonoImage
*meta
, guint32 idx
, gboolean is_field
)
6868 MonoTableInfo
*tdef
= &meta
->tables
[MONO_TABLE_FIELDMARSHAL
];
6874 loc
.col_idx
= MONO_FIELD_MARSHAL_PARENT
;
6875 loc
.idx
= ((idx
+ 1) << MONO_HAS_FIELD_MARSHAL_BITS
) | (is_field
? MONO_HAS_FIELD_MARSHAL_FIELDSREF
: MONO_HAS_FIELD_MARSHAL_PARAMDEF
);
6877 /* FIXME: Index translation */
6879 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
6882 return mono_metadata_blob_heap (meta
, mono_metadata_decode_row_col (tdef
, loc
.result
, MONO_FIELD_MARSHAL_NATIVE_TYPE
));
6886 mono_method_from_method_def_or_ref (MonoImage
*m
, guint32 tok
, MonoGenericContext
*context
, MonoError
*error
)
6888 MonoMethod
*result
= NULL
;
6889 guint32 idx
= tok
>> MONO_METHODDEFORREF_BITS
;
6893 switch (tok
& MONO_METHODDEFORREF_MASK
) {
6894 case MONO_METHODDEFORREF_METHODDEF
:
6895 result
= mono_get_method_checked (m
, MONO_TOKEN_METHOD_DEF
| idx
, NULL
, context
, error
);
6897 case MONO_METHODDEFORREF_METHODREF
:
6898 result
= mono_get_method_checked (m
, MONO_TOKEN_MEMBER_REF
| idx
, NULL
, context
, error
);
6901 mono_error_set_bad_image (error
, m
, "Invalid MethodDefOfRef token %x", tok
);
6908 * mono_class_get_overrides_full:
6910 * Compute the method overrides belonging to class @type_token in @overrides, and the number of overrides in @num_overrides.
6914 mono_class_get_overrides_full (MonoImage
*image
, guint32 type_token
, MonoMethod
***overrides
, gint32
*num_overrides
, MonoGenericContext
*generic_context
, MonoError
*error
)
6917 MonoTableInfo
*tdef
= &image
->tables
[MONO_TABLE_METHODIMPL
];
6920 guint32 cols
[MONO_METHODIMPL_SIZE
];
6921 MonoMethod
**result
;
6933 loc
.col_idx
= MONO_METHODIMPL_CLASS
;
6934 loc
.idx
= mono_metadata_token_index (type_token
);
6936 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
6942 * We may end up in the middle of the rows...
6945 if (loc
.idx
== mono_metadata_decode_row_col (tdef
, start
- 1, MONO_METHODIMPL_CLASS
))
6950 while (end
< tdef
->rows
) {
6951 if (loc
.idx
== mono_metadata_decode_row_col (tdef
, end
, MONO_METHODIMPL_CLASS
))
6957 result
= g_new (MonoMethod
*, num
* 2);
6958 for (i
= 0; i
< num
; ++i
) {
6961 if (!mono_verifier_verify_methodimpl_row (image
, start
+ i
, error
))
6964 mono_metadata_decode_row (tdef
, start
+ i
, cols
, MONO_METHODIMPL_SIZE
);
6965 method
= mono_method_from_method_def_or_ref (image
, cols
[MONO_METHODIMPL_DECLARATION
], generic_context
, error
);
6969 result
[i
* 2] = method
;
6970 method
= mono_method_from_method_def_or_ref (image
, cols
[MONO_METHODIMPL_BODY
], generic_context
, error
);
6974 result
[i
* 2 + 1] = method
;
6977 if (!is_ok (error
)) {
6983 *overrides
= result
;
6985 *num_overrides
= num
;
6990 * mono_guid_to_string:
6992 * Converts a 16 byte Microsoft GUID to the standard string representation.
6995 mono_guid_to_string (const guint8
*guid
)
6997 return g_strdup_printf ("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
6998 guid
[3], guid
[2], guid
[1], guid
[0],
7002 guid
[10], guid
[11], guid
[12], guid
[13], guid
[14], guid
[15]);
7006 * mono_guid_to_string_minimal:
7008 * Converts a 16 byte Microsoft GUID to lower case no '-' representation..
7011 mono_guid_to_string_minimal (const guint8
*guid
)
7013 return g_strdup_printf ("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
7014 guid
[3], guid
[2], guid
[1], guid
[0],
7018 guid
[10], guid
[11], guid
[12], guid
[13], guid
[14], guid
[15]);
7021 get_constraints (MonoImage
*image
, int owner
, MonoClass
***constraints
, MonoGenericContainer
*container
, MonoError
*error
)
7023 MonoTableInfo
*tdef
= &image
->tables
[MONO_TABLE_GENERICPARAMCONSTRAINT
];
7024 guint32 cols
[MONO_GENPARCONSTRAINT_SIZE
];
7025 guint32 i
, token
, found
;
7026 MonoClass
*klass
, **res
;
7027 GSList
*cons
= NULL
, *tmp
;
7028 MonoGenericContext
*context
= &container
->context
;
7032 *constraints
= NULL
;
7034 for (i
= 0; i
< tdef
->rows
; ++i
) {
7035 mono_metadata_decode_row (tdef
, i
, cols
, MONO_GENPARCONSTRAINT_SIZE
);
7036 if (cols
[MONO_GENPARCONSTRAINT_GENERICPAR
] == owner
) {
7037 token
= mono_metadata_token_from_dor (cols
[MONO_GENPARCONSTRAINT_CONSTRAINT
]);
7038 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, context
, error
);
7040 g_slist_free (cons
);
7043 cons
= g_slist_append (cons
, klass
);
7046 /* contiguous list finished */
7053 res
= (MonoClass
**)mono_image_alloc0 (image
, sizeof (MonoClass
*) * (found
+ 1));
7054 for (i
= 0, tmp
= cons
; i
< found
; ++i
, tmp
= tmp
->next
) {
7055 res
[i
] = (MonoClass
*)tmp
->data
;
7057 g_slist_free (cons
);
7063 * mono_metadata_get_generic_param_row:
7066 * @token: TypeOrMethodDef token, owner for GenericParam
7067 * @owner: coded token, set on return
7069 * Returns: 1-based row-id in the GenericParam table whose
7070 * owner is @token. 0 if not found.
7073 mono_metadata_get_generic_param_row (MonoImage
*image
, guint32 token
, guint32
*owner
)
7075 MonoTableInfo
*tdef
= &image
->tables
[MONO_TABLE_GENERICPARAM
];
7082 if (mono_metadata_token_table (token
) == MONO_TABLE_TYPEDEF
)
7083 *owner
= MONO_TYPEORMETHOD_TYPE
;
7084 else if (mono_metadata_token_table (token
) == MONO_TABLE_METHOD
)
7085 *owner
= MONO_TYPEORMETHOD_METHOD
;
7087 g_error ("wrong token %x to get_generic_param_row", token
);
7090 *owner
|= mono_metadata_token_index (token
) << MONO_TYPEORMETHOD_BITS
;
7093 loc
.col_idx
= MONO_GENERICPARAM_OWNER
;
7096 if (!mono_binary_search (&loc
, tdef
->base
, tdef
->rows
, tdef
->row_size
, table_locator
))
7099 /* Find the first entry by searching backwards */
7100 while ((loc
.result
> 0) && (mono_metadata_decode_row_col (tdef
, loc
.result
- 1, MONO_GENERICPARAM_OWNER
) == loc
.idx
))
7103 return loc
.result
+ 1;
7107 mono_metadata_has_generic_params (MonoImage
*image
, guint32 token
)
7110 return mono_metadata_get_generic_param_row (image
, token
, &owner
);
7114 * Memory is allocated from IMAGE's mempool.
7117 mono_metadata_load_generic_param_constraints_checked (MonoImage
*image
, guint32 token
,
7118 MonoGenericContainer
*container
, MonoError
*error
)
7121 guint32 start_row
, i
, owner
;
7124 if (! (start_row
= mono_metadata_get_generic_param_row (image
, token
, &owner
)))
7126 for (i
= 0; i
< container
->type_argc
; i
++) {
7127 if (!get_constraints (image
, start_row
+ i
, &mono_generic_container_get_param_info (container
, i
)->constraints
, container
, error
)) {
7135 * mono_metadata_load_generic_params:
7137 * Load the type parameters from the type or method definition @token.
7139 * Use this method after parsing a type or method definition to figure out whether it's a generic
7140 * type / method. When parsing a method definition, @parent_container points to the generic container
7141 * of the current class, if any.
7143 * Note: This method does not load the constraints: for typedefs, this has to be done after fully
7144 * creating the type.
7146 * Returns: NULL if @token is not a generic type or method definition or the new generic container.
7148 * LOCKING: Acquires the loader lock
7151 MonoGenericContainer
*
7152 mono_metadata_load_generic_params (MonoImage
*image
, guint32 token
, MonoGenericContainer
*parent_container
, gpointer real_owner
)
7154 MonoTableInfo
*tdef
= &image
->tables
[MONO_TABLE_GENERICPARAM
];
7155 guint32 cols
[MONO_GENERICPARAM_SIZE
];
7156 guint32 i
, owner
= 0, n
;
7157 MonoGenericContainer
*container
;
7158 MonoGenericParamFull
*params
;
7159 MonoGenericContext
*context
;
7160 gboolean is_method
= mono_metadata_token_table (token
) == MONO_TABLE_METHOD
;
7161 gboolean is_anonymous
= real_owner
== NULL
;
7163 if (!(i
= mono_metadata_get_generic_param_row (image
, token
, &owner
)))
7165 mono_metadata_decode_row (tdef
, i
- 1, cols
, MONO_GENERICPARAM_SIZE
);
7168 container
= (MonoGenericContainer
*)mono_image_alloc0 (image
, sizeof (MonoGenericContainer
));
7169 container
->is_anonymous
= is_anonymous
;
7171 container
->owner
.image
= image
;
7174 container
->owner
.method
= (MonoMethod
*)real_owner
;
7176 container
->owner
.klass
= (MonoClass
*)real_owner
;
7180 params
= (MonoGenericParamFull
*)g_realloc (params
, sizeof (MonoGenericParamFull
) * n
);
7181 memset (¶ms
[n
- 1], 0, sizeof (MonoGenericParamFull
));
7182 params
[n
- 1].owner
= container
;
7183 params
[n
- 1].num
= cols
[MONO_GENERICPARAM_NUMBER
];
7184 params
[n
- 1].info
.token
= i
| MONO_TOKEN_GENERIC_PARAM
;
7185 params
[n
- 1].info
.flags
= cols
[MONO_GENERICPARAM_FLAGS
];
7186 params
[n
- 1].info
.name
= mono_metadata_string_heap (image
, cols
[MONO_GENERICPARAM_NAME
]);
7187 if (params
[n
- 1].num
!= n
- 1)
7188 g_warning ("GenericParam table unsorted or hole in generic param sequence: token %d", i
);
7189 if (++i
> tdef
->rows
)
7191 mono_metadata_decode_row (tdef
, i
- 1, cols
, MONO_GENERICPARAM_SIZE
);
7192 } while (cols
[MONO_GENERICPARAM_OWNER
] == owner
);
7194 container
->type_argc
= n
;
7195 container
->type_params
= (MonoGenericParamFull
*)mono_image_alloc0 (image
, sizeof (MonoGenericParamFull
) * n
);
7196 memcpy (container
->type_params
, params
, sizeof (MonoGenericParamFull
) * n
);
7198 container
->parent
= parent_container
;
7201 container
->is_method
= 1;
7203 g_assert (container
->parent
== NULL
|| container
->is_method
);
7205 context
= &container
->context
;
7206 if (container
->is_method
) {
7207 context
->class_inst
= container
->parent
? container
->parent
->context
.class_inst
: NULL
;
7208 context
->method_inst
= mono_get_shared_generic_inst (container
);
7210 context
->class_inst
= mono_get_shared_generic_inst (container
);
7217 mono_get_shared_generic_inst (MonoGenericContainer
*container
)
7219 MonoType
**type_argv
;
7221 MonoGenericInst
*nginst
;
7224 type_argv
= g_new0 (MonoType
*, container
->type_argc
);
7225 helper
= g_new0 (MonoType
, container
->type_argc
);
7227 for (i
= 0; i
< container
->type_argc
; i
++) {
7228 MonoType
*t
= &helper
[i
];
7230 t
->type
= container
->is_method
? MONO_TYPE_MVAR
: MONO_TYPE_VAR
;
7231 t
->data
.generic_param
= mono_generic_container_get_param (container
, i
);
7236 nginst
= mono_metadata_get_generic_inst (container
->type_argc
, type_argv
);
7245 * mono_type_is_byref:
7246 * \param type the \c MonoType operated on
7247 * \returns TRUE if \p type represents a type passed by reference,
7251 mono_type_is_byref (MonoType
*type
)
7254 MONO_ENTER_GC_UNSAFE
; // FIXME slow
7255 result
= mono_type_is_byref_internal (type
);
7256 MONO_EXIT_GC_UNSAFE
;
7261 * mono_type_get_type:
7262 * \param type the \c MonoType operated on
7263 * \returns the IL type value for \p type. This is one of the \c MonoTypeEnum
7264 * enum members like \c MONO_TYPE_I4 or \c MONO_TYPE_STRING.
7267 mono_type_get_type (MonoType
*type
)
7269 return mono_type_get_type_internal (type
);
7273 * mono_type_get_signature:
7274 * \param type the \c MonoType operated on
7275 * It is only valid to call this function if \p type is a \c MONO_TYPE_FNPTR .
7276 * \returns the \c MonoMethodSignature pointer that describes the signature
7277 * of the function pointer \p type represents.
7279 MonoMethodSignature
*
7280 mono_type_get_signature (MonoType
*type
)
7282 return mono_type_get_signature_internal (type
);
7286 * mono_type_get_class:
7287 * \param type the \c MonoType operated on
7288 * It is only valid to call this function if \p type is a \c MONO_TYPE_CLASS or a
7289 * \c MONO_TYPE_VALUETYPE . For more general functionality, use \c mono_class_from_mono_type_internal,
7291 * \returns the \c MonoClass pointer that describes the class that \p type represents.
7294 mono_type_get_class (MonoType
*type
)
7296 /* FIXME: review the runtime users before adding the assert here */
7297 return mono_type_get_class_internal (type
);
7301 * mono_type_get_array_type:
7302 * \param type the \c MonoType operated on
7303 * It is only valid to call this function if \p type is a \c MONO_TYPE_ARRAY .
7304 * \returns a \c MonoArrayType struct describing the array type that \p type
7305 * represents. The info includes details such as rank, array element type
7306 * and the sizes and bounds of multidimensional arrays.
7309 mono_type_get_array_type (MonoType
*type
)
7311 return mono_type_get_array_type_internal (type
);
7315 * mono_type_get_ptr_type:
7316 * \pararm type the \c MonoType operated on
7317 * It is only valid to call this function if \p type is a \c MONO_TYPE_PTR .
7318 * \returns the \c MonoType pointer that describes the type that \p type
7319 * represents a pointer to.
7322 mono_type_get_ptr_type (MonoType
*type
)
7324 g_assert (type
->type
== MONO_TYPE_PTR
);
7325 return type
->data
.type
;
7329 * mono_type_get_modifiers:
7332 mono_type_get_modifiers (MonoType
*type
, gboolean
*is_required
, gpointer
*iter
)
7334 /* FIXME: implement */
7339 * mono_type_is_struct:
7340 * \param type the \c MonoType operated on
7341 * \returns TRUE if \p type is a struct, that is a \c ValueType but not an enum
7342 * or a basic type like \c System.Int32 . FALSE otherwise.
7345 mono_type_is_struct (MonoType
*type
)
7347 return (!type
->byref
&& ((type
->type
== MONO_TYPE_VALUETYPE
&&
7348 !m_class_is_enumtype (type
->data
.klass
)) || (type
->type
== MONO_TYPE_TYPEDBYREF
) ||
7349 ((type
->type
== MONO_TYPE_GENERICINST
) &&
7350 mono_metadata_generic_class_is_valuetype (type
->data
.generic_class
) &&
7351 !m_class_is_enumtype (type
->data
.generic_class
->container_class
))));
7355 * mono_type_is_void:
7356 * \param type the \c MonoType operated on
7357 * \returns TRUE if \p type is \c System.Void . FALSE otherwise.
7360 mono_type_is_void (MonoType
*type
)
7362 return (type
&& (type
->type
== MONO_TYPE_VOID
) && !type
->byref
);
7366 * mono_type_is_pointer:
7367 * \param type the \c MonoType operated on
7368 * \returns TRUE if \p type is a managed or unmanaged pointer type. FALSE otherwise.
7371 mono_type_is_pointer (MonoType
*type
)
7373 return (type
&& ((type
->byref
|| (type
->type
== MONO_TYPE_I
) || type
->type
== MONO_TYPE_STRING
)
7374 || (type
->type
== MONO_TYPE_SZARRAY
) || (type
->type
== MONO_TYPE_CLASS
) ||
7375 (type
->type
== MONO_TYPE_U
) || (type
->type
== MONO_TYPE_OBJECT
) ||
7376 (type
->type
== MONO_TYPE_ARRAY
) || (type
->type
== MONO_TYPE_PTR
) ||
7377 (type
->type
== MONO_TYPE_FNPTR
)));
7381 * mono_type_is_reference:
7382 * \param type the \c MonoType operated on
7383 * \returns TRUE if \p type represents an object reference. FALSE otherwise.
7386 mono_type_is_reference (MonoType
*type
)
7388 /* NOTE: changing this function to return TRUE more often may have
7389 * consequences for generic sharing in the AOT compiler. In
7390 * particular, returning TRUE for generic parameters with a 'class'
7391 * constraint may cause crashes.
7393 return (type
&& (((type
->type
== MONO_TYPE_STRING
) ||
7394 (type
->type
== MONO_TYPE_SZARRAY
) || (type
->type
== MONO_TYPE_CLASS
) ||
7395 (type
->type
== MONO_TYPE_OBJECT
) || (type
->type
== MONO_TYPE_ARRAY
)) ||
7396 ((type
->type
== MONO_TYPE_GENERICINST
) &&
7397 !mono_metadata_generic_class_is_valuetype (type
->data
.generic_class
))));
7401 mono_type_is_generic_parameter (MonoType
*type
)
7403 return !type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
);
7407 * mono_signature_get_return_type:
7408 * \param sig the method signature inspected
7409 * \returns the return type of the method signature \p sig
7412 mono_signature_get_return_type (MonoMethodSignature
*sig
)
7415 MONO_ENTER_GC_UNSAFE
;
7417 MONO_EXIT_GC_UNSAFE
;
7422 * mono_signature_get_params:
7423 * \param sig the method signature inspected
7424 * \param iter pointer to an iterator
7425 * Iterates over the parameters for the method signature \p sig.
7426 * A \c void* pointer must be initialized to NULL to start the iteration
7427 * and its address is passed to this function repeteadly until it returns
7429 * \returns the next parameter type of the method signature \p sig,
7430 * NULL when finished.
7433 mono_signature_get_params (MonoMethodSignature
*sig
, gpointer
*iter
)
7436 MONO_ENTER_GC_UNSAFE
;
7437 result
= mono_signature_get_params_internal (sig
, iter
);
7438 MONO_EXIT_GC_UNSAFE
;
7443 mono_signature_get_params_internal (MonoMethodSignature
*sig
, gpointer
*iter
)
7449 /* start from the first */
7450 if (sig
->param_count
) {
7451 *iter
= &sig
->params
[0];
7452 return sig
->params
[0];
7458 type
= (MonoType
**)*iter
;
7460 if (type
< &sig
->params
[sig
->param_count
]) {
7468 * mono_signature_get_param_count:
7469 * \param sig the method signature inspected
7470 * \returns the number of parameters in the method signature \p sig.
7473 mono_signature_get_param_count (MonoMethodSignature
*sig
)
7475 return sig
->param_count
;
7479 * mono_signature_get_call_conv:
7480 * \param sig the method signature inspected
7481 * \returns the call convention of the method signature \p sig.
7484 mono_signature_get_call_conv (MonoMethodSignature
*sig
)
7486 return sig
->call_convention
;
7490 * mono_signature_vararg_start:
7491 * \param sig the method signature inspected
7492 * \returns the number of the first vararg parameter in the
7493 * method signature \param sig. \c -1 if this is not a vararg signature.
7496 mono_signature_vararg_start (MonoMethodSignature
*sig
)
7498 return sig
->sentinelpos
;
7502 * mono_signature_is_instance:
7503 * \param sig the method signature inspected
7504 * \returns TRUE if this the method signature \p sig has an implicit
7505 * first instance argument. FALSE otherwise.
7508 mono_signature_is_instance (MonoMethodSignature
*sig
)
7510 return sig
->hasthis
;
7514 * mono_signature_param_is_out
7515 * \param sig the method signature inspected
7516 * \param param_num the 0-based index of the inspected parameter
7517 * \returns TRUE if the parameter is an out parameter, FALSE
7521 mono_signature_param_is_out (MonoMethodSignature
*sig
, int param_num
)
7523 g_assert (param_num
>= 0 && param_num
< sig
->param_count
);
7524 return (sig
->params
[param_num
]->attrs
& PARAM_ATTRIBUTE_OUT
) != 0;
7528 * mono_signature_explicit_this:
7529 * \param sig the method signature inspected
7530 * \returns TRUE if this the method signature \p sig has an explicit
7531 * instance argument. FALSE otherwise.
7534 mono_signature_explicit_this (MonoMethodSignature
*sig
)
7536 return sig
->explicit_this
;
7539 /* for use with allocated memory blocks (assumes alignment is to 8 bytes) */
7541 mono_aligned_addr_hash (gconstpointer ptr
)
7543 /* Same hashing we use for objects */
7544 return (GPOINTER_TO_UINT (ptr
) >> 3) * 2654435761u;
7548 * If @field belongs to an inflated generic class, return the corresponding field of the
7549 * generic type definition class.
7552 mono_metadata_get_corresponding_field_from_generic_type_definition (MonoClassField
*field
)
7557 if (!mono_class_is_ginst (field
->parent
))
7560 gtd
= mono_class_get_generic_class (field
->parent
)->container_class
;
7561 offset
= field
- m_class_get_fields (field
->parent
);
7562 return m_class_get_fields (gtd
) + offset
;
7566 * If @event belongs to an inflated generic class, return the corresponding event of the
7567 * generic type definition class.
7570 mono_metadata_get_corresponding_event_from_generic_type_definition (MonoEvent
*event
)
7575 if (!mono_class_is_ginst (event
->parent
))
7578 gtd
= mono_class_get_generic_class (event
->parent
)->container_class
;
7579 offset
= event
- mono_class_get_event_info (event
->parent
)->events
;
7580 return mono_class_get_event_info (gtd
)->events
+ offset
;
7584 * If @property belongs to an inflated generic class, return the corresponding property of the
7585 * generic type definition class.
7588 mono_metadata_get_corresponding_property_from_generic_type_definition (MonoProperty
*property
)
7590 MonoClassPropertyInfo
*info
;
7594 if (!mono_class_is_ginst (property
->parent
))
7597 info
= mono_class_get_property_info (property
->parent
);
7598 gtd
= mono_class_get_generic_class (property
->parent
)->container_class
;
7599 offset
= property
- info
->properties
;
7600 return mono_class_get_property_info (gtd
)->properties
+ offset
;
7604 mono_method_get_wrapper_cache (MonoMethod
*method
)
7606 if (method
->is_inflated
) {
7607 MonoMethodInflated
*imethod
= (MonoMethodInflated
*)method
;
7608 return &imethod
->owner
->wrapper_caches
;
7610 return &m_class_get_image (method
->klass
)->wrapper_caches
;
7614 // 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.
7617 * mono_find_image_set_owner:
7619 * Find the imageset, if any, which a given pointer is located in the memory of.
7622 mono_find_image_set_owner (void *ptr
)
7624 MonoImageSet
*owner
= NULL
;
7631 for (i
= 0; !owner
&& i
< image_sets
->len
; ++i
) {
7632 MonoImageSet
*set
= (MonoImageSet
*)g_ptr_array_index (image_sets
, i
);
7633 if (mono_mempool_contains_addr (set
->mempool
, ptr
))
7638 image_sets_unlock ();
7644 mono_loader_set_strict_assembly_name_check (gboolean enabled
)
7646 check_assembly_names_strictly
= enabled
;
7650 mono_loader_get_strict_assembly_name_check (void)
7652 #if !defined(DISABLE_DESKTOP_LOADER) || defined(ENABLE_NETCORE)
7653 return check_assembly_names_strictly
;
7661 mono_type_is_aggregate_mods (const MonoType
*t
)
7666 MonoTypeWithModifiers
*full
= (MonoTypeWithModifiers
*)t
;
7668 return full
->is_aggregate
;
7671 MonoCustomModContainer
*
7672 mono_type_get_cmods (const MonoType
*t
)
7677 MonoTypeWithModifiers
*full
= (MonoTypeWithModifiers
*)t
;
7679 g_assert (!full
->is_aggregate
);
7680 return &full
->mods
.cmods
;
7683 MonoAggregateModContainer
*
7684 mono_type_get_amods (const MonoType
*t
)
7689 MonoTypeWithModifiers
*full
= (MonoTypeWithModifiers
*)t
;
7691 g_assert (full
->is_aggregate
);
7692 return full
->mods
.amods
;
7696 mono_sizeof_aggregate_modifiers (uint8_t num_mods
)
7699 accum
+= offsetof (MonoAggregateModContainer
, modifiers
);
7700 accum
+= sizeof (MonoSingleCustomMod
) * num_mods
;
7705 mono_sizeof_type_with_mods (uint8_t num_mods
, gboolean is_aggregate
)
7708 return sizeof (MonoType
);
7710 accum
+= offsetof (MonoTypeWithModifiers
, mods
);
7712 if (!is_aggregate
) {
7713 accum
+= offsetof (struct _MonoCustomModContainer
, modifiers
);
7714 accum
+= sizeof (MonoCustomMod
) * num_mods
;
7716 accum
+= offsetof (MonoAggregateModContainer
, modifiers
);
7717 accum
+= sizeof (MonoAggregateModContainer
*);
7723 mono_sizeof_type (const MonoType
*ty
)
7725 if (ty
->has_cmods
) {
7726 if (!mono_type_is_aggregate_mods (ty
)) {
7727 MonoCustomModContainer
*cmods
= mono_type_get_cmods (ty
);
7728 return mono_sizeof_type_with_mods (cmods
->count
, FALSE
);
7730 MonoAggregateModContainer
*amods
= mono_type_get_amods (ty
);
7731 return mono_sizeof_type_with_mods (amods
->count
, TRUE
);
7734 return sizeof (MonoType
);
7738 mono_type_set_amods (MonoType
*t
, MonoAggregateModContainer
*amods
)
7740 g_assert (t
->has_cmods
);
7741 MonoTypeWithModifiers
*t_full
= (MonoTypeWithModifiers
*)t
;
7742 g_assert (t_full
->is_aggregate
);
7743 g_assert (t_full
->mods
.amods
== NULL
);
7744 t_full
->mods
.amods
= amods
;