[merp] Remove dead code (#20043)
[mono-project.git] / mono / metadata / metadata.c
blob5f6568da9b0c38080ea24398018ba9e87fe85acf
1 /**
2 * \file
3 * Routines for accessing the metadata
5 * Authors:
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.
14 #include <config.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <glib.h>
19 #include "metadata.h"
20 #include "tabledefs.h"
21 #include "mono-endian.h"
22 #include "cil-coff.h"
23 #include "tokentype.h"
24 #include "class-internals.h"
25 #include "metadata-internals.h"
26 #include "verify-internals.h"
27 #include "class.h"
28 #include "marshal.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 */
44 typedef struct {
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
68 * tables
70 enum {
71 MONO_MT_END,
73 /* Sized elements */
74 MONO_MT_UINT32,
75 MONO_MT_UINT16,
76 MONO_MT_UINT8,
78 /* Index into Blob heap */
79 MONO_MT_BLOB_IDX,
81 /* Index into String heap */
82 MONO_MT_STRING_IDX,
84 /* GUID index */
85 MONO_MT_GUID_IDX,
87 /* Pointer into a table */
88 MONO_MT_TABLE_IDX,
90 /* HasConstant:Parent pointer (Param, Field or Property) */
91 MONO_MT_CONST_IDX,
93 /* HasCustomAttribute index. Indexes any table except CustomAttribute */
94 MONO_MT_HASCAT_IDX,
96 /* CustomAttributeType encoded index */
97 MONO_MT_CAT_IDX,
99 /* HasDeclSecurity index: TypeDef Method or Assembly */
100 MONO_MT_HASDEC_IDX,
102 /* Implementation coded index: File, Export AssemblyRef */
103 MONO_MT_IMPL_IDX,
105 /* HasFieldMarshal coded index: Field or Param table */
106 MONO_MT_HFM_IDX,
108 /* MemberForwardedIndex: Field or Method */
109 MONO_MT_MF_IDX,
111 /* TypeDefOrRef coded index: typedef, typeref, typespec */
112 MONO_MT_TDOR_IDX,
114 /* MemberRefParent coded index: typeref, moduleref, method, memberref, typesepc, typedef */
115 MONO_MT_MRP_IDX,
117 /* MethodDefOrRef coded index: Method or Member Ref table */
118 MONO_MT_MDOR_IDX,
120 /* HasSemantic coded index: Event or Property */
121 MONO_MT_HS_IDX,
123 /* ResolutionScope coded index: Module, ModuleRef, AssemblytRef, TypeRef */
124 MONO_MT_RS_IDX,
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" }, */
141 MONO_MT_END,
143 #define ASSEMBLYOS_SCHEMA_OFFSET ASSEMBLY_SCHEMA_OFFSET + 10
144 MONO_MT_UINT32, /* "OSPlatformID" }, */
145 MONO_MT_UINT32, /* "OSMajor" }, */
146 MONO_MT_UINT32, /* "OSMinor" }, */
147 MONO_MT_END,
149 #define ASSEMBLYPROC_SCHEMA_OFFSET ASSEMBLYOS_SCHEMA_OFFSET + 4
150 MONO_MT_UINT32, /* "Processor" }, */
151 MONO_MT_END,
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" }, */
163 MONO_MT_END,
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" }, */
170 MONO_MT_END,
172 #define ASSEMBLYREFPROC_SCHEMA_OFFSET ASSEMBLYREFOS_SCHEMA_OFFSET + 5
173 MONO_MT_UINT32, /* "Processor" }, */
174 MONO_MT_TABLE_IDX, /* "AssemblyRef:AssemblyRef" }, */
175 MONO_MT_END,
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" }, */
181 MONO_MT_END,
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" }, */
188 MONO_MT_END,
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" }, */
194 MONO_MT_END,
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" }, */
200 MONO_MT_END,
202 #define EVENTMAP_SCHEMA_OFFSET DECL_SEC_SCHEMA_OFFSET + 4
203 MONO_MT_TABLE_IDX, /* "Parent:TypeDef" }, */
204 MONO_MT_TABLE_IDX, /* "EventList:Event" }, */
205 MONO_MT_END,
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 */
211 MONO_MT_END,
213 #define EVENT_POINTER_SCHEMA_OFFSET EVENT_SCHEMA_OFFSET + 4
214 MONO_MT_TABLE_IDX, /* "Event" }, */
215 MONO_MT_END,
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" }, */
223 MONO_MT_END,
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" }, */
229 MONO_MT_END,
231 #define FIELD_LAYOUT_SCHEMA_OFFSET FIELD_SCHEMA_OFFSET + 4
232 MONO_MT_UINT32, /* "Offset" }, */
233 MONO_MT_TABLE_IDX, /* "Field:Field" }, */
234 MONO_MT_END,
236 #define FIELD_MARSHAL_SCHEMA_OFFSET FIELD_LAYOUT_SCHEMA_OFFSET + 3
237 MONO_MT_HFM_IDX, /* "Parent" }, */
238 MONO_MT_BLOB_IDX, /* "NativeType" }, */
239 MONO_MT_END,
241 #define FIELD_RVA_SCHEMA_OFFSET FIELD_MARSHAL_SCHEMA_OFFSET + 3
242 MONO_MT_UINT32, /* "RVA" }, */
243 MONO_MT_TABLE_IDX, /* "Field:Field" }, */
244 MONO_MT_END,
246 #define FIELD_POINTER_SCHEMA_OFFSET FIELD_RVA_SCHEMA_OFFSET + 3
247 MONO_MT_TABLE_IDX, /* "Field" }, */
248 MONO_MT_END,
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" }, */
254 MONO_MT_END,
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" }, */
261 MONO_MT_END,
263 #define IFACEMAP_SCHEMA_OFFSET IMPLMAP_SCHEMA_OFFSET + 5
264 MONO_MT_TABLE_IDX, /* "Class:TypeDef" }, */
265 MONO_MT_TDOR_IDX, /* "Interface=TypeDefOrRef" }, */
266 MONO_MT_END,
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" }, */
273 MONO_MT_END,
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" }, */
279 MONO_MT_END,
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" }, */
288 MONO_MT_END,
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" }, */
294 MONO_MT_END,
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" }, */
300 MONO_MT_END,
302 #define METHOD_POINTER_SCHEMA_OFFSET METHOD_SEMA_SCHEMA_OFFSET + 4
303 MONO_MT_TABLE_IDX, /* "Method" }, */
304 MONO_MT_END,
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" }, */
312 MONO_MT_END,
314 #define MODULEREF_SCHEMA_OFFSET MODULE_SCHEMA_OFFSET + 6
315 MONO_MT_STRING_IDX, /* "Name" }, */
316 MONO_MT_END,
318 #define NESTED_CLASS_SCHEMA_OFFSET MODULEREF_SCHEMA_OFFSET + 2
319 MONO_MT_TABLE_IDX, /* "NestedClass:TypeDef" }, */
320 MONO_MT_TABLE_IDX, /* "EnclosingClass:TypeDef" }, */
321 MONO_MT_END,
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" }, */
327 MONO_MT_END,
329 #define PARAM_POINTER_SCHEMA_OFFSET PARAM_SCHEMA_OFFSET + 4
330 MONO_MT_TABLE_IDX, /* "Param" }, */
331 MONO_MT_END,
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" }, */
337 MONO_MT_END,
339 #define PROPERTY_POINTER_SCHEMA_OFFSET PROPERTY_SCHEMA_OFFSET + 4
340 MONO_MT_TABLE_IDX, /* "Property" }, */
341 MONO_MT_END,
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" }, */
346 MONO_MT_END,
348 #define STDALON_SIG_SCHEMA_OFFSET PROPERTY_MAP_SCHEMA_OFFSET + 3
349 MONO_MT_BLOB_IDX, /* "Signature" }, */
350 MONO_MT_END,
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" }, */
359 MONO_MT_END,
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" }, */
365 MONO_MT_END,
367 #define TYPESPEC_SCHEMA_OFFSET TYPEREF_SCHEMA_OFFSET + 4
368 MONO_MT_BLOB_IDX, /* "Signature" }, */
369 MONO_MT_END,
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" }, */
376 MONO_MT_END,
378 #define METHOD_SPEC_SCHEMA_OFFSET GENPARAM_SCHEMA_OFFSET + 5
379 MONO_MT_MDOR_IDX, /* "Method" }, */
380 MONO_MT_BLOB_IDX, /* "Signature" }, */
381 MONO_MT_END,
383 #define GEN_CONSTRAINT_SCHEMA_OFFSET METHOD_SPEC_SCHEMA_OFFSET + 3
384 MONO_MT_TABLE_IDX, /* "GenericParam" }, */
385 MONO_MT_TDOR_IDX, /* "Constraint" }, */
386 MONO_MT_END,
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 */
393 MONO_MT_END,
395 #define METHODBODY_SCHEMA_OFFSET DOCUMENT_SCHEMA_OFFSET + 5
396 MONO_MT_TABLE_IDX, /* Document */
397 MONO_MT_BLOB_IDX, /* SequencePoints */
398 MONO_MT_END,
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 */
407 MONO_MT_END,
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 */
413 MONO_MT_END,
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) */
418 MONO_MT_END,
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) */
423 MONO_MT_END,
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) */
428 MONO_MT_END,
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) */
434 MONO_MT_END,
436 #define NULL_SCHEMA_OFFSET CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET + 4
437 MONO_MT_END
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,
447 FIELD_SCHEMA_OFFSET,
448 METHOD_POINTER_SCHEMA_OFFSET,
449 METHOD_SCHEMA_OFFSET,
450 PARAM_POINTER_SCHEMA_OFFSET,
451 PARAM_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,
463 EVENT_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,
473 NULL_SCHEMA_OFFSET,
474 NULL_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,
481 FILE_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,
488 NULL_SCHEMA_OFFSET,
489 NULL_SCHEMA_OFFSET,
490 NULL_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"
507 #undef TABLEDEF
508 } tablestr = {
509 #define TABLEDEF(a,b) b,
510 #include "mono/cil/tables.def"
511 #undef TABLEDEF
513 static const gint16 tableidx [] = {
514 #define TABLEDEF(a,b) offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
515 #include "mono/cil/tables.def"
516 #undef TABLEDEF
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
539 const char *
540 mono_meta_table_name (int table)
542 if ((table < 0) || (table > MONO_TABLE_LAST))
543 return "";
545 return (const char*)&tablestr + tableidx [table];
548 /* The guy who wrote the spec for this should not be allowed near a
549 * computer again.
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))
560 static int
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;
565 else
566 return meta->tables [idx].rows < 65536 ? 2 : 4;
569 static int
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];
574 else
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;
597 int i, n, code;
598 int shift = 0;
599 const unsigned char *description = TableSchemas + table_description [tableindex];
601 for (i = 0; (code = description [i]) != MONO_MT_END; i++){
602 switch (code){
603 case MONO_MT_UINT32:
604 field_size = 4; break;
606 case MONO_MT_UINT16:
607 field_size = 2; break;
609 case MONO_MT_UINT8:
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:
628 g_assert (i == 3);
629 field_size = idx_size (meta, MONO_TABLE_ASSEMBLYREF); break;
630 case MONO_TABLE_ASSEMBLYREFPROCESSOR:
631 g_assert (i == 1);
632 field_size = idx_size (meta, MONO_TABLE_ASSEMBLYREF); break;
633 case MONO_TABLE_CLASSLAYOUT:
634 g_assert (i == 2);
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);
640 break;
641 case MONO_TABLE_EVENT_POINTER:
642 g_assert (i == 0);
643 field_size = idx_size (meta, MONO_TABLE_EVENT); break;
644 case MONO_TABLE_EXPORTEDTYPE:
645 g_assert (i == 1);
646 /* the index is in another metadata file, so it must be 4 */
647 field_size = 4; break;
648 case MONO_TABLE_FIELDLAYOUT:
649 g_assert (i == 1);
650 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
651 case MONO_TABLE_FIELDRVA:
652 g_assert (i == 1);
653 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
654 case MONO_TABLE_FIELD_POINTER:
655 g_assert (i == 0);
656 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
657 case MONO_TABLE_IMPLMAP:
658 g_assert (i == 3);
659 field_size = idx_size (meta, MONO_TABLE_MODULEREF); break;
660 case MONO_TABLE_INTERFACEIMPL:
661 g_assert (i == 0);
662 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
663 case MONO_TABLE_METHOD:
664 g_assert (i == 5);
665 field_size = idx_size (meta, MONO_TABLE_PARAM); break;
666 case MONO_TABLE_METHODIMPL:
667 g_assert (i == 0);
668 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
669 case MONO_TABLE_METHODSEMANTICS:
670 g_assert (i == 1);
671 field_size = idx_size (meta, MONO_TABLE_METHOD); break;
672 case MONO_TABLE_METHOD_POINTER:
673 g_assert (i == 0);
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:
679 g_assert (i == 0);
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);
685 break;
686 case MONO_TABLE_PROPERTY_POINTER:
687 g_assert (i == 0);
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);
693 break;
694 case MONO_TABLE_GENERICPARAM:
695 g_assert (i == 2);
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);
699 break;
700 case MONO_TABLE_GENERICPARAMCONSTRAINT:
701 g_assert (i == 0);
702 field_size = idx_size (meta, MONO_TABLE_GENERICPARAM);
703 break;
704 case MONO_TABLE_LOCALSCOPE:
705 switch (i) {
706 case 0:
707 // FIXME: This table is in another file
708 field_size = idx_size (meta, MONO_TABLE_METHOD);
709 break;
710 case 1:
711 field_size = idx_size (meta, MONO_TABLE_IMPORTSCOPE);
712 break;
713 case 2:
714 field_size = idx_size (meta, MONO_TABLE_LOCALVARIABLE);
715 break;
716 case 3:
717 field_size = idx_size (meta, MONO_TABLE_LOCALCONSTANT);
718 break;
719 default:
720 g_assert_not_reached ();
721 break;
723 break;
724 case MONO_TABLE_METHODBODY:
725 g_assert (i == 0);
726 field_size = idx_size (meta, MONO_TABLE_DOCUMENT); break;
727 case MONO_TABLE_IMPORTSCOPE:
728 g_assert(i == 0);
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;
733 default:
734 g_error ("Can't handle MONO_MT_TABLE_IDX for table %d element %d", tableindex, i);
736 break;
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);
748 break;
751 * HasCustomAttribute: points to any table but
752 * itself.
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){
762 field_size = 4;
763 break;
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);
791 break;
794 * HasCustomAttribute: points to any table but
795 * itself.
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);
829 break;
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);
840 break;
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);
852 break;
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);
864 break;
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);
875 break;
878 * MemberForwarded: FieldDef, MethodDef
880 case MONO_MT_MF_IDX:
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);
886 break;
889 * TypeDefOrRef: TypeDef, ParamDef, TypeSpec
890 * LAMESPEC
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);
900 break;
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);
914 break;
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);
925 break;
928 * HasSemantics: Property, Event
930 case MONO_MT_HS_IDX:
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);
936 break;
939 * ResolutionScope: Module, ModuleRef, AssemblyRef, TypeRef
941 case MONO_MT_RS_IDX:
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);
949 break;
953 * encode field size as follows (we just need to
954 * distinguish them).
956 * 4 -> 3
957 * 2 -> 1
958 * 1 -> 0
960 bitfield |= (field_size-1) << shift;
961 shift += 2;
962 size += field_size;
963 /*g_print ("table %02x field %d size %d\n", tableindex, i, field_size);*/
966 *result_bitfield = (i << 24) | bitfield;
967 return size;
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.
977 void
978 mono_metadata_compute_table_bases (MonoImage *meta)
980 int i;
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)
986 continue;
988 table->row_size = mono_metadata_compute_size (meta, i, &table->size_bitfield);
989 table->base = base;
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.
1003 const char *
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
1018 * token \p token .
1020 const char *
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.
1032 const char *
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.
1048 const char *
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);
1053 return NULL;
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>).
1064 const char *
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.
1078 const char *
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.
1097 const char *
1098 mono_metadata_blob_heap_null_ok (MonoImage *meta, guint32 index)
1100 if (G_UNLIKELY (index == 0 && meta->heap_blob.size == 0))
1101 return NULL;
1102 else
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.
1115 const char *
1116 mono_metadata_blob_heap_checked (MonoImage *meta, guint32 index, MonoError *error)
1118 if (G_UNLIKELY (index == 0 && meta->heap_blob.size == 0))
1119 return NULL;
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);
1122 return NULL;
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.
1133 const char *
1134 mono_metadata_guid_heap (MonoImage *meta, guint32 index)
1136 --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
1157 void
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);
1162 const char *data;
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);
1173 switch (n){
1174 case 1:
1175 res [i] = *data; break;
1176 case 2:
1177 res [i] = read16 (data); break;
1178 case 4:
1179 res [i] = read32 (data); break;
1180 default:
1181 g_assert_not_reached ();
1183 data += n;
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.
1201 gboolean
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);
1211 return FALSE;
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);
1217 return FALSE;
1220 for (i = 0; i < count; i++) {
1221 int n = mono_metadata_table_size (bitfield, i);
1223 switch (n) {
1224 case 1:
1225 res [i] = *data; break;
1226 case 2:
1227 res [i] = read16 (data); break;
1228 case 4:
1229 res [i] = read32 (data); break;
1230 default:
1231 mono_error_set_bad_image_by_name (error, image_name, "unexpected table [%d] size %d", i, n);
1232 return FALSE;
1234 data += n;
1237 return TRUE;
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 .
1249 guint32
1250 mono_metadata_decode_row_col (const MonoTableInfo *t, int idx, guint col)
1252 guint32 bitfield = t->size_bitfield;
1253 int i;
1254 const char *data;
1255 int n;
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) {
1263 data += n;
1264 n = mono_metadata_table_size (bitfield, i + 1);
1266 switch (n) {
1267 case 1:
1268 return *data;
1269 case 2:
1270 return read16 (data);
1271 case 4:
1272 return read32 (data);
1273 default:
1274 g_assert_not_reached ();
1276 return 0;
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
1288 guint32
1289 mono_metadata_decode_blob_size (const char *xptr, const char **rptr)
1291 const unsigned char *ptr = (const unsigned char *)xptr;
1292 guint32 size;
1294 if ((*ptr & 0x80) == 0){
1295 size = ptr [0] & 0x7f;
1296 ptr++;
1297 } else if ((*ptr & 0x40) == 0){
1298 size = ((ptr [0] & 0x3f) << 8) + ptr [1];
1299 ptr += 2;
1300 } else {
1301 size = ((ptr [0] & 0x1f) << 24) +
1302 (ptr [1] << 16) +
1303 (ptr [2] << 8) +
1304 ptr [3];
1305 ptr += 4;
1307 if (rptr)
1308 *rptr = (char*)ptr;
1309 return size;
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
1322 guint32
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;
1327 guint32 len;
1329 if ((b & 0x80) == 0){
1330 len = b;
1331 ++ptr;
1332 } else if ((b & 0x40) == 0){
1333 len = ((b & 0x3f) << 8 | ptr [1]);
1334 ptr += 2;
1335 } else {
1336 len = ((b & 0x1f) << 24) |
1337 (ptr [1] << 16) |
1338 (ptr [2] << 8) |
1339 ptr [3];
1340 ptr += 4;
1342 if (rptr)
1343 *rptr = (char*)ptr;
1345 return len;
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
1358 gint32
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;
1363 if (!(uval & 1))
1364 return ival;
1365 /* ival is a truncated 2's complement negative number. */
1366 if (ival < 0x40)
1367 /* 6 bits = 7 bits for compressed representation (top bit is '0') - 1 sign bit */
1368 return ival - 0x40;
1369 if (ival < 0x2000)
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.
1388 guint32
1389 mono_metadata_translate_token_index (MonoImage *image, int table, guint32 idx)
1391 if (!image->uncompressed_metadata)
1392 return idx;
1394 switch (table) {
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);
1398 else
1399 return idx;
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);
1403 else
1404 return idx;
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);
1408 else
1409 return idx;
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);
1413 else
1414 return idx;
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);
1418 else
1419 return idx;
1420 default:
1421 return idx;
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.
1433 void
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.
1465 guint32
1466 mono_metadata_parse_typedef_or_ref (MonoImage *m, const char *ptr, const char **rptr)
1468 guint32 token;
1469 token = mono_metadata_decode_value (ptr, &ptr);
1470 if (rptr)
1471 *rptr = 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)) {
1491 if (!dest)
1492 dest = &local;
1493 dest->required = *ptr == MONO_TYPE_CMOD_REQD ? 1 : 0;
1494 dest->token = mono_metadata_parse_typedef_or_ref (m, ptr + 1, rptr);
1495 return TRUE;
1497 return FALSE;
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)
1519 int i;
1520 MonoArrayType *array;
1521 MonoType *etype;
1523 etype = mono_metadata_parse_type_checked (m, container, 0, FALSE, ptr, &ptr, error); //FIXME this doesn't respect @transient
1524 if (!etype)
1525 return NULL;
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);
1543 if (rptr)
1544 *rptr = ptr;
1545 return array;
1549 * mono_metadata_parse_array:
1551 MonoArrayType *
1552 mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
1554 ERROR_DECL (error);
1555 MonoArrayType *ret = mono_metadata_parse_array_internal (m, NULL, FALSE, ptr, rptr, error);
1556 mono_error_cleanup (error);
1558 return ret;
1562 * mono_metadata_free_array:
1563 * \param array array description
1565 * Frees the array description returned from \c mono_metadata_parse_array.
1567 void
1568 mono_metadata_free_array (MonoArrayType *array)
1570 g_free (array->sizes);
1571 g_free (array->lobounds);
1572 g_free (array);
1576 * need to add common field and param attributes combinations:
1577 * [out] param
1578 * public static
1579 * public static literal
1580 * private
1581 * private static
1582 * private static literal
1584 static const MonoType
1585 builtin_types[] = {
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.
1639 static guint
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);
1645 else
1646 return type->type | (type->byref << 8) | (type->attrs << 9);
1649 static gint
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)
1656 return 0;
1657 /* need other checks */
1658 return 1;
1661 guint
1662 mono_metadata_generic_inst_hash (gconstpointer data)
1664 const MonoGenericInst *ginst = (const MonoGenericInst *) data;
1665 guint hash = 0;
1666 int i;
1667 g_assert (ginst);
1668 g_assert (ginst->type_argv);
1670 for (i = 0; i < ginst->type_argc; ++i) {
1671 hash *= 13;
1672 g_assert (ginst->type_argv [i]);
1673 hash += mono_metadata_type_hash (ginst->type_argv [i]);
1676 return hash ^ (ginst->is_open << 8);
1679 static gboolean
1680 mono_generic_inst_equal_full (const MonoGenericInst *a, const MonoGenericInst *b, gboolean signature_only)
1682 int i;
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.
1688 if (a->id == b->id)
1689 return TRUE;
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)
1693 return FALSE;
1695 #endif
1697 if (a->is_open != b->is_open || a->type_argc != b->type_argc)
1698 return FALSE;
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))
1701 return FALSE;
1703 return TRUE;
1706 gboolean
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);
1715 static guint
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));
1721 hash *= 13;
1722 hash += gclass->is_tb_open;
1723 hash += mono_metadata_generic_context_hash (&gclass->context);
1725 return hash;
1728 static gboolean
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.
1743 void
1744 mono_metadata_init (void)
1746 int i;
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;
1754 if (inited)
1755 return;
1756 inited = TRUE;
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.
1776 void
1777 mono_metadata_cleanup (void)
1779 g_hash_table_destroy (type_cache);
1780 type_cache = NULL;
1781 g_ptr_array_free (image_sets, TRUE);
1782 image_sets = NULL;
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.
1811 static MonoType*
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;
1816 MonoType stype;
1817 gboolean byref = FALSE;
1818 gboolean pinned = FALSE;
1819 const char *tmp_ptr;
1820 int count = 0; // Number of mod arguments
1821 gboolean found;
1823 error_init (error);
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
1832 * a modifier...
1833 * Also, pinned should come before anything else, but some MSV++ produced
1834 * assemblies violate this (#bug 61990).
1837 /* Count the modifiers first */
1838 tmp_ptr = ptr;
1839 found = TRUE;
1840 while (found) {
1841 switch (*tmp_ptr) {
1842 case MONO_TYPE_PINNED:
1843 case MONO_TYPE_BYREF:
1844 ++tmp_ptr;
1845 break;
1846 case MONO_TYPE_CMOD_REQD:
1847 case MONO_TYPE_CMOD_OPT:
1848 count ++;
1849 mono_metadata_parse_custom_mod (m, NULL, tmp_ptr, &tmp_ptr);
1850 break;
1851 default:
1852 found = FALSE;
1856 MonoCustomModContainer *cmods = NULL;
1858 if (count) { // There are mods, so the MonoType will be of nonstandard size.
1859 if (count > 64) {
1860 mono_error_set_bad_image (error, m, "Invalid type with more than 64 modifiers");
1861 return NULL;
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;
1870 cmods->image = m;
1871 } else { // The type is of standard size, so we can allocate it on the stack.
1872 type = &stype;
1873 memset (type, 0, MONO_SIZEOF_TYPE);
1876 /* Iterate again, but now parse pinned, byref and custom modifiers */
1877 found = TRUE;
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"
1881 while (found) {
1882 switch (*ptr) {
1883 case MONO_TYPE_PINNED:
1884 pinned = TRUE;
1885 ++ptr;
1886 break;
1887 case MONO_TYPE_BYREF:
1888 byref = TRUE;
1889 ++ptr;
1890 break;
1891 case MONO_TYPE_CMOD_REQD:
1892 case MONO_TYPE_CMOD_OPT:
1893 mono_metadata_parse_custom_mod (m, &(cmods->modifiers [--count]), ptr, &ptr);
1894 break;
1895 default:
1896 found = FALSE;
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))
1908 return NULL;
1910 if (rptr)
1911 *rptr = ptr;
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) {
1938 return ret;
1941 /* No need to use locking since nobody is modifying the hash table */
1942 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type))) {
1943 return cached;
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);
1953 return type;
1957 MonoType*
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.
1967 MonoType*
1968 mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
1969 const char *ptr, const char **rptr)
1971 ERROR_DECL (error);
1972 MonoType * type = mono_metadata_parse_type_internal (m, NULL, opt_attrs, FALSE, ptr, rptr, error);
1973 mono_error_cleanup (error);
1974 return type;
1977 gboolean
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);
1986 else
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);
1991 if (flags)
1992 return TRUE;
1995 return FALSE;
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.
2009 int*
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);
2016 int *pattrs = NULL;
2018 if (def < methodt->rows)
2019 lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
2020 else
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]) {
2026 if (!pattrs)
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)
2032 continue;
2033 pattrs [cols [MONO_PARAM_SEQUENCE]] = cols [MONO_PARAM_FLAGS];
2037 return pattrs;
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)
2053 ERROR_DECL (error);
2054 MonoMethodSignature *ret;
2055 ret = mono_metadata_parse_signature_checked (image, token, error);
2056 mono_error_cleanup (error);
2057 return ret;
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)
2075 error_init (error);
2076 MonoTableInfo *tables = image->tables;
2077 guint32 idx = mono_metadata_token_index (token);
2078 guint32 sig;
2079 const char *ptr;
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;
2117 return sig;
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;
2126 if (sig->ret)
2127 sigsize += mono_sizeof_type (sig->ret);
2129 if (image) {
2130 ret = (MonoMethodSignature *)mono_image_alloc (image, sigsize);
2131 } else if (mp) {
2132 ret = (MonoMethodSignature *)mono_mempool_alloc (mp, sigsize);
2133 } else {
2134 ret = (MonoMethodSignature *)g_malloc (sigsize);
2137 memcpy (ret, sig, sig_header_size - padding);
2139 // Copy return value because of ownership semantics.
2140 if (sig->ret) {
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));
2147 return 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);
2177 return ret;
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);
2191 return ret;
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.
2221 guint32
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;
2255 error_init (error);
2257 if (*ptr & 0x10)
2258 gen_param_count = 1;
2259 if (*ptr & 0x20)
2260 hasthis = 1;
2261 if (*ptr & 0x40)
2262 explicit_this = 1;
2263 call_convention = *ptr & 0x0F;
2264 ptr++;
2265 if (gen_param_count)
2266 gen_param_count = mono_metadata_decode_value (ptr, &ptr);
2267 param_count = mono_metadata_decode_value (ptr, &ptr);
2269 if (def)
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;
2282 break;
2283 case MONO_CALL_C:
2284 case MONO_CALL_STDCALL:
2285 case MONO_CALL_THISCALL:
2286 case MONO_CALL_FASTCALL:
2287 method->pinvoke = 1;
2288 break;
2291 if (call_convention != 0xa) {
2292 method->ret = mono_metadata_parse_type_checked (m, container, pattrs ? pattrs [0] : 0, FALSE, ptr, &ptr, error);
2293 if (!method->ret) {
2294 mono_metadata_free_method_signature (method);
2295 g_free (pattrs);
2296 return NULL;
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");
2305 g_free (pattrs);
2306 return NULL;
2308 if (method->sentinelpos >= 0) {
2309 mono_error_set_bad_image (error, m, "Found sentinel twice in the same signature.");
2310 g_free (pattrs);
2311 return NULL;
2313 method->sentinelpos = i;
2314 ptr++;
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);
2319 g_free (pattrs);
2320 return NULL;
2322 if (!is_open)
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;
2335 g_free (pattrs);
2337 if (rptr)
2338 *rptr = ptr;
2340 * Add signature to a cache and increase ref count...
2343 return method;
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.
2368 ERROR_DECL (error);
2369 MonoMethodSignature *ret;
2370 ret = mono_metadata_parse_method_signature_full (m, NULL, def, ptr, rptr, error);
2371 mono_error_assert_ok (error);
2373 return ret;
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.
2384 void
2385 mono_metadata_free_method_signature (MonoMethodSignature *sig)
2387 /* Everything is allocated from mempools */
2389 int i;
2390 if (sig->ret)
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]);
2399 void
2400 mono_metadata_free_inflated_signature (MonoMethodSignature *sig)
2402 int i;
2404 /* Allocated in inflate_generic_signature () */
2405 if (sig->ret)
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]);
2411 g_free (sig);
2414 static gboolean
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)
2420 return FALSE;
2421 return mono_metadata_generic_context_equal (&ma->context, &mb->context);
2424 static guint
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));
2431 static gboolean
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)
2439 return FALSE;
2440 /* The generic instances are canonized */
2441 return mono_metadata_generic_context_equal (&sig1->context, &sig2->context);
2444 static guint
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);
2453 /*static void
2454 dump_ginst (MonoGenericInst *ginst)
2456 int i;
2457 char *name;
2459 g_print ("Ginst: <");
2460 for (i = 0; i < ginst->type_argc; ++i) {
2461 if (i != 0)
2462 g_print (", ");
2463 name = mono_type_get_name (ginst->type_argv [i]);
2464 g_print ("%s", name);
2465 g_free (name);
2467 g_print (">");
2470 static gboolean
2471 aggregate_modifiers_equal (gconstpointer ka, gconstpointer kb)
2473 MonoAggregateModContainer *amods1 = (MonoAggregateModContainer *)ka;
2474 MonoAggregateModContainer *amods2 = (MonoAggregateModContainer *)kb;
2475 if (amods1->count != amods2->count)
2476 return FALSE;
2477 for (int i = 0; i < amods1->count; ++i) {
2478 if (amods1->modifiers [i].required != amods2->modifiers [i].required)
2479 return FALSE;
2480 if (!mono_metadata_type_equal_full (amods1->modifiers [i].type, amods2->modifiers [i].type, TRUE))
2481 return FALSE;
2483 return TRUE;
2486 static guint
2487 aggregate_modifiers_hash (gconstpointer a)
2489 const MonoAggregateModContainer *amods = (const MonoAggregateModContainer *)a;
2490 guint hash = 0;
2491 for (int i = 0; i < amods->count; ++i)
2493 // hash details borrowed from mono_metadata_generic_inst_hash
2494 hash *= 13;
2495 hash ^= (amods->modifiers [i].required << 8);
2496 hash += mono_metadata_type_hash (amods->modifiers [i].type);
2499 return hash;
2502 static gboolean type_in_image (MonoType *type, MonoImage *image);
2503 static gboolean aggregate_modifiers_in_image (MonoAggregateModContainer *amods, MonoImage *image);
2505 static gboolean
2506 signature_in_image (MonoMethodSignature *sig, MonoImage *image)
2508 gpointer iter = NULL;
2509 MonoType *p;
2511 while ((p = mono_signature_get_params (sig, &iter)) != NULL)
2512 if (type_in_image (p, image))
2513 return TRUE;
2515 return type_in_image (mono_signature_get_return_type (sig), image);
2518 static gboolean
2519 ginst_in_image (MonoGenericInst *ginst, MonoImage *image)
2521 int i;
2523 for (i = 0; i < ginst->type_argc; ++i) {
2524 if (type_in_image (ginst->type_argv [i], image))
2525 return TRUE;
2528 return FALSE;
2531 static gboolean
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);
2538 static gboolean
2539 type_in_image (MonoType *type, MonoImage *image)
2541 retry:
2542 if (type->has_cmods && mono_type_is_aggregate_mods (type))
2543 if (aggregate_modifiers_in_image (mono_type_get_amods (type), image))
2544 return TRUE;
2546 switch (type->type) {
2547 case MONO_TYPE_GENERICINST:
2548 return gclass_in_image (type->data.generic_class, image);
2549 case MONO_TYPE_PTR:
2550 type = type->data.type;
2551 goto retry;
2552 case MONO_TYPE_SZARRAY:
2553 type = m_class_get_byval_arg (type->data.klass);
2554 goto retry;
2555 case MONO_TYPE_ARRAY:
2556 type = m_class_get_byval_arg (type->data.array->eklass);
2557 goto retry;
2558 case MONO_TYPE_FNPTR:
2559 return signature_in_image (type->data.method, image);
2560 case MONO_TYPE_VAR:
2561 case MONO_TYPE_MVAR:
2562 return image == mono_get_image_for_generic_param (type->data.generic_param);
2563 default:
2564 /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type_internal () */
2565 return image == m_class_get_image (mono_class_from_mono_type_internal (type));
2569 gboolean
2570 mono_type_in_image (MonoType *type, MonoImage *image)
2572 return type_in_image (type, image);
2575 gboolean
2576 aggregate_modifiers_in_image (MonoAggregateModContainer *amods, MonoImage *image)
2578 for (int i = 0; i < amods->count; i++)
2579 if (type_in_image (amods->modifiers [i].type, image))
2580 return TRUE;
2581 return FALSE;
2584 static void
2585 image_sets_lock (void)
2587 mono_os_mutex_lock (&image_sets_mutex);
2590 static void
2591 image_sets_unlock (void)
2593 mono_os_mutex_unlock (&image_sets_mutex);
2596 //1103, 1327, 1597
2597 #define HASH_TABLE_SIZE 1103
2598 static MonoImageSet *img_set_cache [HASH_TABLE_SIZE];
2600 static guint32
2601 mix_hash (uintptr_t source)
2603 unsigned int hash = source;
2605 // Actual hash
2606 hash = (((hash * 215497) >> 16) ^ ((hash * 1823231) + hash));
2608 // Mix in highest bits on 64-bit systems only
2609 if (sizeof (source) > 4)
2610 hash = hash ^ ((source >> 31) >> 1);
2612 return hash;
2615 static guint32
2616 hash_images (MonoImage **images, int nimages)
2618 guint32 res = 0;
2619 int i;
2620 for (i = 0; i < nimages; ++i)
2621 res += mix_hash ((size_t)images [i]);
2623 return res;
2626 static gboolean
2627 compare_img_set (MonoImageSet *set, MonoImage **images, int nimages)
2629 int j, k;
2631 if (set->nimages != nimages)
2632 return FALSE;
2634 for (j = 0; j < nimages; ++j) {
2635 for (k = 0; k < nimages; ++k)
2636 if (set->images [k] == images [j])
2637 break; // Break on match
2639 // If we iterated all the way through set->images, images[j] was *not* found.
2640 if (k == nimages)
2641 break; // Break on "image not found"
2644 // If we iterated all the way through images without breaking, all items in images were found in set->images
2645 return j == nimages;
2649 static MonoImageSet*
2650 img_set_cache_get (MonoImage **images, int nimages)
2652 guint32 hash_code = hash_images (images, nimages);
2653 int index = hash_code % HASH_TABLE_SIZE;
2654 MonoImageSet *img = img_set_cache [index];
2655 if (!img || !compare_img_set (img, images, nimages)) {
2656 UnlockedIncrement (&img_set_cache_miss);
2657 return NULL;
2659 UnlockedIncrement (&img_set_cache_hit);
2660 return img;
2663 static void
2664 img_set_cache_add (MonoImageSet *set)
2666 guint32 hash_code = hash_images (set->images, set->nimages);
2667 int index = hash_code % HASH_TABLE_SIZE;
2668 img_set_cache [index] = set;
2671 static void
2672 img_set_cache_remove (MonoImageSet *is)
2674 guint32 hash_code = hash_images (is->images, is->nimages);
2675 int index = hash_code % HASH_TABLE_SIZE;
2676 if (img_set_cache [index] == is)
2677 img_set_cache [index] = NULL;
2680 * get_image_set:
2682 * Return a MonoImageSet representing the set of images in IMAGES.
2684 static MonoImageSet*
2685 get_image_set (MonoImage **images, int nimages)
2687 int i, j, k;
2688 MonoImageSet *set;
2689 GSList *l;
2691 /* Common case: Image set contains corlib only. If we've seen that case before, we cached the set. */
2692 if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set)
2693 return mscorlib_image_set;
2695 /* Happens with empty generic instances */
2696 // FIXME: Is corlib the correct thing to return here? If so, why? This may be an artifact of generic instances previously defaulting to allocating from corlib.
2697 if (nimages == 0)
2698 return mscorlib_image_set;
2700 set = img_set_cache_get (images, nimages);
2701 if (set)
2702 return set;
2704 image_sets_lock ();
2706 if (!image_sets)
2707 image_sets = g_ptr_array_new ();
2709 // Before we go on, we should check to see whether a MonoImageSet with these images already exists.
2710 // We can search the referred-by imagesets of any one of our images to do this. Arbitrarily pick one here:
2711 if (images [0] == mono_defaults.corlib && nimages > 1)
2712 l = images [1]->image_sets; // Prefer not to search the imagesets of corlib-- that will be a long list.
2713 else
2714 l = images [0]->image_sets;
2716 set = NULL;
2717 while (l) // Iterate over selected list, looking for an imageset with members equal to our target one
2719 set = (MonoImageSet *)l->data;
2721 if (set->nimages == nimages) { // Member count differs, this can't be it
2722 // Compare all members to all members-- order might be different
2723 for (j = 0; j < nimages; ++j) {
2724 for (k = 0; k < nimages; ++k)
2725 if (set->images [k] == images [j])
2726 break; // Break on match
2728 // If we iterated all the way through set->images, images[j] was *not* found.
2729 if (k == nimages)
2730 break; // Break on "image not found"
2733 // If we iterated all the way through images without breaking, all items in images were found in set->images
2734 if (j == nimages) {
2735 // Break on "found a set with equal members".
2736 // This happens in case of a hash collision with a previously cached set.
2737 break;
2741 l = l->next;
2744 // If we iterated all the way through l without breaking, the imageset does not already exist and we should create it
2745 if (!l) {
2746 set = g_new0 (MonoImageSet, 1);
2747 set->nimages = nimages;
2748 set->images = g_new0 (MonoImage*, nimages);
2749 mono_os_mutex_init_recursive (&set->lock);
2750 for (i = 0; i < nimages; ++i)
2751 set->images [i] = images [i];
2752 set->gclass_cache = mono_conc_hashtable_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
2753 set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
2754 set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
2755 set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
2757 set->szarray_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2758 set->array_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2760 set->aggregate_modifiers_cache = g_hash_table_new_full (aggregate_modifiers_hash, aggregate_modifiers_equal, NULL, (GDestroyNotify)free_aggregate_modifiers);
2762 for (i = 0; i < nimages; ++i)
2763 set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set);
2765 g_ptr_array_add (image_sets, set);
2766 UnlockedIncrement (&img_set_count); /* locked by image_sets_lock () */
2769 /* Cache the set. If there was a cache collision, the previously cached value will be replaced. */
2770 img_set_cache_add (set);
2772 if (nimages == 1 && images [0] == mono_defaults.corlib) {
2773 mono_memory_barrier ();
2774 mscorlib_image_set = set;
2777 image_sets_unlock ();
2779 return set;
2782 static void
2783 delete_image_set (MonoImageSet *set)
2785 int i;
2787 mono_conc_hashtable_destroy (set->gclass_cache);
2788 g_hash_table_destroy (set->ginst_cache);
2789 g_hash_table_destroy (set->gmethod_cache);
2790 g_hash_table_destroy (set->gsignature_cache);
2792 g_hash_table_destroy (set->szarray_cache);
2793 g_hash_table_destroy (set->array_cache);
2794 if (set->ptr_cache)
2795 g_hash_table_destroy (set->ptr_cache);
2797 g_hash_table_destroy (set->aggregate_modifiers_cache);
2799 for (i = 0; i < set->gshared_types_len; ++i) {
2800 if (set->gshared_types [i])
2801 g_hash_table_destroy (set->gshared_types [i]);
2803 g_free (set->gshared_types);
2805 mono_wrapper_caches_free (&set->wrapper_caches);
2807 image_sets_lock ();
2809 for (i = 0; i < set->nimages; ++i)
2810 set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set);
2812 g_ptr_array_remove (image_sets, set);
2814 image_sets_unlock ();
2816 img_set_cache_remove (set);
2818 if (set->mempool)
2819 mono_mempool_destroy (set->mempool);
2820 g_free (set->images);
2821 mono_os_mutex_destroy (&set->lock);
2822 g_free (set);
2825 void
2826 mono_image_set_lock (MonoImageSet *set)
2828 mono_os_mutex_lock (&set->lock);
2831 void
2832 mono_image_set_unlock (MonoImageSet *set)
2834 mono_os_mutex_unlock (&set->lock);
2837 gpointer
2838 mono_image_set_alloc (MonoImageSet *set, guint size)
2840 gpointer res;
2842 mono_image_set_lock (set);
2843 if (!set->mempool)
2844 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2845 res = mono_mempool_alloc (set->mempool, size);
2846 mono_image_set_unlock (set);
2848 return res;
2851 gpointer
2852 mono_image_set_alloc0 (MonoImageSet *set, guint size)
2854 gpointer res;
2856 mono_image_set_lock (set);
2857 if (!set->mempool)
2858 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2859 res = mono_mempool_alloc0 (set->mempool, size);
2860 mono_image_set_unlock (set);
2862 return res;
2865 char*
2866 mono_image_set_strdup (MonoImageSet *set, const char *s)
2868 char *res;
2870 mono_image_set_lock (set);
2871 if (!set->mempool)
2872 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2873 res = mono_mempool_strdup (set->mempool, s);
2874 mono_image_set_unlock (set);
2876 return res;
2879 // Get a descriptive string for a MonoImageSet
2880 // Callers are obligated to free buffer with g_free after use
2881 char *
2882 mono_image_set_description (MonoImageSet *set)
2884 GString *result = g_string_new (NULL);
2885 int img;
2886 g_string_append (result, "[");
2887 for (img = 0; img < set->nimages; img++)
2889 if (img > 0)
2890 g_string_append (result, ", ");
2891 g_string_append (result, set->images[img]->name);
2893 g_string_append (result, "]");
2894 return g_string_free (result, FALSE);
2898 * Structure used by the collect_..._images functions to store the image list.
2900 typedef struct {
2901 MonoImage *image_buf [64];
2902 MonoImage **images;
2903 int nimages, images_len;
2904 } CollectData;
2906 static void
2907 collect_data_init (CollectData *data)
2909 data->images = data->image_buf;
2910 data->images_len = 64;
2911 data->nimages = 0;
2914 static void
2915 collect_data_free (CollectData *data)
2917 if (data->images != data->image_buf)
2918 g_free (data->images);
2921 static void
2922 enlarge_data (CollectData *data)
2924 int new_len = data->images_len < 16 ? 16 : data->images_len * 2;
2925 MonoImage **d = g_new (MonoImage *, new_len);
2927 // FIXME: test this
2928 g_assert_not_reached ();
2929 memcpy (d, data->images, data->images_len);
2930 if (data->images != data->image_buf)
2931 g_free (data->images);
2932 data->images = d;
2933 data->images_len = new_len;
2936 static void
2937 add_image (MonoImage *image, CollectData *data)
2939 int i;
2941 /* The arrays are small, so use a linear search instead of a hash table */
2942 for (i = 0; i < data->nimages; ++i)
2943 if (data->images [i] == image)
2944 return;
2946 if (data->nimages == data->images_len)
2947 enlarge_data (data);
2949 data->images [data->nimages ++] = image;
2952 static void
2953 collect_type_images (MonoType *type, CollectData *data);
2955 static void
2956 collect_ginst_images (MonoGenericInst *ginst, CollectData *data)
2958 int i;
2960 for (i = 0; i < ginst->type_argc; ++i) {
2961 collect_type_images (ginst->type_argv [i], data);
2965 static void
2966 collect_gclass_images (MonoGenericClass *gclass, CollectData *data)
2968 add_image (m_class_get_image (gclass->container_class), data);
2969 if (gclass->context.class_inst)
2970 collect_ginst_images (gclass->context.class_inst, data);
2973 static void
2974 collect_signature_images (MonoMethodSignature *sig, CollectData *data)
2976 gpointer iter = NULL;
2977 MonoType *p;
2979 collect_type_images (mono_signature_get_return_type (sig), data);
2980 while ((p = mono_signature_get_params (sig, &iter)) != NULL)
2981 collect_type_images (p, data);
2984 static void
2985 collect_inflated_signature_images (MonoInflatedMethodSignature *sig, CollectData *data)
2987 collect_signature_images (sig->sig, data);
2988 if (sig->context.class_inst)
2989 collect_ginst_images (sig->context.class_inst, data);
2990 if (sig->context.method_inst)
2991 collect_ginst_images (sig->context.method_inst, data);
2994 static void
2995 collect_method_images (MonoMethodInflated *method, CollectData *data)
2997 MonoMethod *m = method->declaring;
2999 add_image (m_class_get_image (method->declaring->klass), data);
3000 if (method->context.class_inst)
3001 collect_ginst_images (method->context.class_inst, data);
3002 if (method->context.method_inst)
3003 collect_ginst_images (method->context.method_inst, data);
3005 * Dynamic assemblies have no references, so the images they depend on can be unloaded before them.
3007 if (image_is_dynamic (m_class_get_image (m->klass)))
3008 collect_signature_images (mono_method_signature_internal (m), data);
3011 static void
3012 collect_aggregate_modifiers_images (MonoAggregateModContainer *amods, CollectData *data)
3014 for (int i = 0; i < amods->count; ++i)
3015 collect_type_images (amods->modifiers [i].type, data);
3018 static void
3019 collect_type_images (MonoType *type, CollectData *data)
3021 retry:
3022 if (G_UNLIKELY (type->has_cmods && mono_type_is_aggregate_mods (type))) {
3023 collect_aggregate_modifiers_images (mono_type_get_amods (type), data);
3026 switch (type->type) {
3027 case MONO_TYPE_GENERICINST:
3028 collect_gclass_images (type->data.generic_class, data);
3029 break;
3030 case MONO_TYPE_PTR:
3031 type = type->data.type;
3032 goto retry;
3033 case MONO_TYPE_SZARRAY:
3034 type = m_class_get_byval_arg (type->data.klass);
3035 goto retry;
3036 case MONO_TYPE_ARRAY:
3037 type = m_class_get_byval_arg (type->data.array->eklass);
3038 goto retry;
3039 case MONO_TYPE_FNPTR:
3040 //return signature_in_image (type->data.method, image);
3041 g_assert_not_reached ();
3042 case MONO_TYPE_VAR:
3043 case MONO_TYPE_MVAR:
3045 MonoImage *image = mono_get_image_for_generic_param (type->data.generic_param);
3046 add_image (image, data);
3047 break;
3049 case MONO_TYPE_CLASS:
3050 case MONO_TYPE_VALUETYPE:
3051 add_image (m_class_get_image (mono_class_from_mono_type_internal (type)), data);
3052 break;
3053 default:
3054 add_image (mono_defaults.corlib, data);
3058 typedef struct {
3059 MonoImage *image;
3060 GSList *list;
3061 } CleanForImageUserData;
3063 static gboolean
3064 steal_gclass_in_image (gpointer key, gpointer value, gpointer data)
3066 MonoGenericClass *gclass = (MonoGenericClass *)key;
3067 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
3069 g_assert (gclass_in_image (gclass, user_data->image));
3071 user_data->list = g_slist_prepend (user_data->list, gclass);
3072 return TRUE;
3075 static gboolean
3076 steal_ginst_in_image (gpointer key, gpointer value, gpointer data)
3078 MonoGenericInst *ginst = (MonoGenericInst *)key;
3079 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
3081 // This doesn't work during corlib compilation
3082 //g_assert (ginst_in_image (ginst, user_data->image));
3084 user_data->list = g_slist_prepend (user_data->list, ginst);
3085 return TRUE;
3088 static gboolean
3089 steal_aggregate_modifiers_in_image (gpointer key, gpointer value, gpointer data)
3091 MonoAggregateModContainer *amods = (MonoAggregateModContainer *)key;
3092 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
3094 g_assert (aggregate_modifiers_in_image (amods, user_data->image));
3096 user_data->list = g_slist_prepend (user_data->list, amods);
3097 return TRUE;
3100 static gboolean
3101 inflated_method_in_image (gpointer key, gpointer value, gpointer data)
3103 MonoImage *image = (MonoImage *)data;
3104 MonoMethodInflated *method = (MonoMethodInflated *)key;
3106 // FIXME:
3107 // https://bugzilla.novell.com/show_bug.cgi?id=458168
3108 g_assert (m_class_get_image (method->declaring->klass) == image ||
3109 (method->context.class_inst && ginst_in_image (method->context.class_inst, image)) ||
3110 (method->context.method_inst && ginst_in_image (method->context.method_inst, image)) || (((MonoMethod*)method)->signature && signature_in_image (mono_method_signature_internal ((MonoMethod*)method), image)));
3112 return TRUE;
3115 static gboolean
3116 inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
3118 MonoImage *image = (MonoImage *)data;
3119 MonoInflatedMethodSignature *sig = (MonoInflatedMethodSignature *)key;
3121 return signature_in_image (sig->sig, image) ||
3122 (sig->context.class_inst && ginst_in_image (sig->context.class_inst, image)) ||
3123 (sig->context.method_inst && ginst_in_image (sig->context.method_inst, image));
3126 static gboolean
3127 class_in_image (gpointer key, gpointer value, gpointer data)
3129 MonoImage *image = (MonoImage *)data;
3130 MonoClass *klass = (MonoClass *)key;
3132 g_assert (type_in_image (m_class_get_byval_arg (klass), image));
3134 return TRUE;
3137 static void
3138 check_gmethod (gpointer key, gpointer value, gpointer data)
3140 MonoMethodInflated *method = (MonoMethodInflated *)key;
3141 MonoImage *image = (MonoImage *)data;
3143 if (method->context.class_inst)
3144 g_assert (!ginst_in_image (method->context.class_inst, image));
3145 if (method->context.method_inst)
3146 g_assert (!ginst_in_image (method->context.method_inst, image));
3147 if (((MonoMethod*)method)->signature)
3148 g_assert (!signature_in_image (mono_method_signature_internal ((MonoMethod*)method), image));
3152 * check_image_sets:
3154 * Run a consistency check on the image set data structures.
3156 static G_GNUC_UNUSED void
3157 check_image_sets (MonoImage *image)
3159 int i;
3160 GSList *l = image->image_sets;
3162 if (!image_sets)
3163 return;
3165 for (i = 0; i < image_sets->len; ++i) {
3166 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
3168 if (!g_slist_find (l, set)) {
3169 g_hash_table_foreach (set->gmethod_cache, check_gmethod, image);
3174 void
3175 mono_metadata_clean_for_image (MonoImage *image)
3177 CleanForImageUserData ginst_data, gclass_data, amods_data;
3178 GSList *l, *set_list;
3180 //check_image_sets (image);
3183 * The data structures could reference each other so we delete them in two phases.
3184 * This is required because of the hashing functions in gclass/ginst_cache.
3186 ginst_data.image = gclass_data.image = image;
3187 ginst_data.list = gclass_data.list = NULL;
3188 amods_data.image = image;
3189 amods_data.list = NULL;
3191 /* Collect the items to delete */
3192 /* delete_image_set () modifies the lists so make a copy */
3193 for (l = image->image_sets; l; l = l->next) {
3194 MonoImageSet *set = (MonoImageSet *)l->data;
3196 mono_image_set_lock (set);
3197 mono_conc_hashtable_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data);
3198 g_hash_table_foreach_steal (set->ginst_cache, steal_ginst_in_image, &ginst_data);
3199 g_hash_table_foreach_remove (set->gmethod_cache, inflated_method_in_image, image);
3200 g_hash_table_foreach_remove (set->gsignature_cache, inflated_signature_in_image, image);
3202 g_hash_table_foreach_steal (set->szarray_cache, class_in_image, image);
3203 g_hash_table_foreach_steal (set->array_cache, class_in_image, image);
3204 if (set->ptr_cache)
3205 g_hash_table_foreach_steal (set->ptr_cache, class_in_image, image);
3207 g_hash_table_foreach_steal (set->aggregate_modifiers_cache, steal_aggregate_modifiers_in_image, &amods_data);
3209 mono_image_set_unlock (set);
3212 /* Delete the removed items */
3213 for (l = ginst_data.list; l; l = l->next)
3214 free_generic_inst ((MonoGenericInst *)l->data);
3215 for (l = gclass_data.list; l; l = l->next)
3216 free_generic_class ((MonoGenericClass *)l->data);
3217 for (l = amods_data.list; l; l = l->next)
3218 free_aggregate_modifiers ((MonoAggregateModContainer *)l->data);
3219 g_slist_free (ginst_data.list);
3220 g_slist_free (gclass_data.list);
3221 /* delete_image_set () modifies the lists so make a copy */
3222 set_list = g_slist_copy (image->image_sets);
3223 for (l = set_list; l; l = l->next) {
3224 MonoImageSet *set = (MonoImageSet *)l->data;
3226 delete_image_set (set);
3228 g_slist_free (set_list);
3231 static void
3232 free_inflated_method (MonoMethodInflated *imethod)
3234 MonoMethod *method = (MonoMethod*)imethod;
3236 if (method->signature)
3237 mono_metadata_free_inflated_signature (method->signature);
3239 if (method->wrapper_type)
3240 g_free (((MonoMethodWrapper*)method)->method_data);
3242 g_free (method);
3245 static void
3246 free_generic_inst (MonoGenericInst *ginst)
3248 int i;
3250 /* The ginst itself is allocated from the image set mempool */
3251 for (i = 0; i < ginst->type_argc; ++i)
3252 mono_metadata_free_type (ginst->type_argv [i]);
3255 static void
3256 free_generic_class (MonoGenericClass *gclass)
3258 /* The gclass itself is allocated from the image set mempool */
3259 if (gclass->cached_class && m_class_get_interface_id (gclass->cached_class))
3260 mono_unload_interface_id (gclass->cached_class);
3263 static void
3264 free_inflated_signature (MonoInflatedMethodSignature *sig)
3266 mono_metadata_free_inflated_signature (sig->sig);
3267 g_free (sig);
3270 static void
3271 free_aggregate_modifiers (MonoAggregateModContainer *amods)
3273 for (int i = 0; i < amods->count; i++)
3274 mono_metadata_free_type (amods->modifiers [i].type);
3275 /* the container itself is allocated in the image set mempool */
3279 * mono_metadata_get_inflated_signature:
3281 * Given an inflated signature and a generic context, return a canonical copy of the
3282 * signature. The returned signature might be equal to SIG or it might be a cached copy.
3284 MonoMethodSignature *
3285 mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericContext *context)
3287 MonoInflatedMethodSignature helper;
3288 MonoInflatedMethodSignature *res;
3289 CollectData data;
3290 MonoImageSet *set;
3292 helper.sig = sig;
3293 helper.context.class_inst = context->class_inst;
3294 helper.context.method_inst = context->method_inst;
3296 collect_data_init (&data);
3298 collect_inflated_signature_images (&helper, &data);
3300 set = get_image_set (data.images, data.nimages);
3302 collect_data_free (&data);
3304 mono_image_set_lock (set);
3306 res = (MonoInflatedMethodSignature *)g_hash_table_lookup (set->gsignature_cache, &helper);
3307 if (!res) {
3308 res = g_new0 (MonoInflatedMethodSignature, 1);
3309 res->sig = sig;
3310 res->context.class_inst = context->class_inst;
3311 res->context.method_inst = context->method_inst;
3312 g_hash_table_insert (set->gsignature_cache, res, res);
3315 mono_image_set_unlock (set);
3317 return res->sig;
3320 MonoImageSet *
3321 mono_metadata_get_image_set_for_type (MonoType *type)
3323 MonoImageSet *set;
3324 CollectData image_set_data;
3326 collect_data_init (&image_set_data);
3327 collect_type_images (type, &image_set_data);
3328 set = get_image_set (image_set_data.images, image_set_data.nimages);
3329 collect_data_free (&image_set_data);
3331 return set;
3334 MonoImageSet *
3335 mono_metadata_get_image_set_for_class (MonoClass *klass)
3337 return mono_metadata_get_image_set_for_type (m_class_get_byval_arg (klass));
3340 MonoImageSet *
3341 mono_metadata_get_image_set_for_method (MonoMethodInflated *method)
3343 MonoImageSet *set;
3344 CollectData image_set_data;
3346 collect_data_init (&image_set_data);
3347 collect_method_images (method, &image_set_data);
3348 set = get_image_set (image_set_data.images, image_set_data.nimages);
3349 collect_data_free (&image_set_data);
3351 return set;
3354 MonoImageSet *
3355 mono_metadata_get_image_set_for_aggregate_modifiers (MonoAggregateModContainer *amods)
3357 MonoImageSet *set;
3358 CollectData image_set_data;
3359 collect_data_init (&image_set_data);
3360 collect_aggregate_modifiers_images (amods, &image_set_data);
3361 set = get_image_set (image_set_data.images, image_set_data.nimages);
3362 collect_data_free (&image_set_data);
3364 return set;
3367 MonoImageSet *
3368 mono_metadata_merge_image_sets (MonoImageSet *set1, MonoImageSet *set2)
3370 MonoImage **images = g_newa (MonoImage*, set1->nimages + set2->nimages);
3372 /* Add images from set1 */
3373 memcpy (images, set1->images, sizeof (MonoImage*) * set1->nimages);
3375 int nimages = set1->nimages;
3376 // FIXME: Quaratic
3377 /* Add images from set2 */
3378 for (int i = 0; i < set2->nimages; ++i) {
3379 int j;
3380 for (j = 0; j < set1->nimages; ++j) {
3381 if (set2->images [i] == set1->images [j])
3382 break;
3384 if (j == set1->nimages)
3385 images [nimages ++] = set2->images [i];
3387 return get_image_set (images, nimages);
3390 static gboolean
3391 type_is_gtd (MonoType *type)
3393 switch (type->type) {
3394 case MONO_TYPE_CLASS:
3395 case MONO_TYPE_VALUETYPE:
3396 return mono_class_is_gtd (type->data.klass);
3397 default:
3398 return FALSE;
3403 * mono_metadata_get_generic_inst:
3405 * Given a list of types, return a MonoGenericInst that represents that list.
3406 * The returned MonoGenericInst has its own copy of the list of types. The list
3407 * passed in the argument can be freed, modified or disposed of.
3410 MonoGenericInst *
3411 mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
3413 MonoGenericInst *ginst;
3414 gboolean is_open;
3415 int i;
3416 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3418 for (i = 0; i < type_argc; ++i)
3419 if (mono_class_is_open_constructed_type (type_argv [i]))
3420 break;
3421 is_open = (i < type_argc);
3423 ginst = (MonoGenericInst *)g_alloca (size);
3424 memset (ginst, 0, sizeof (MonoGenericInst));
3425 ginst->is_open = is_open;
3426 ginst->type_argc = type_argc;
3427 memcpy (ginst->type_argv, type_argv, type_argc * sizeof (MonoType *));
3429 for (i = 0; i < type_argc; ++i) {
3430 MonoType *t = ginst->type_argv [i];
3431 if (type_is_gtd (t)) {
3432 ginst->type_argv [i] = mono_class_gtd_get_canonical_inst (t->data.klass);
3436 return mono_metadata_get_canonical_generic_inst (ginst);
3440 * mono_metadata_get_canonical_generic_inst:
3441 * \param candidate an arbitrary generic instantiation
3443 * \returns the canonical generic instantiation that represents the given
3444 * candidate by identifying the image set for the candidate instantiation and
3445 * finding the instance in the image set or adding a copy of the given instance
3446 * to the image set.
3448 * The returned MonoGenericInst has its own copy of the list of types. The list
3449 * passed in the argument can be freed, modified or disposed of.
3452 MonoGenericInst *
3453 mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate)
3455 CollectData data;
3456 int type_argc = candidate->type_argc;
3457 gboolean is_open = candidate->is_open;
3458 MonoImageSet *set;
3460 collect_data_init (&data);
3462 collect_ginst_images (candidate, &data);
3464 set = get_image_set (data.images, data.nimages);
3466 collect_data_free (&data);
3468 mono_image_set_lock (set);
3470 MonoGenericInst *ginst = (MonoGenericInst *)g_hash_table_lookup (set->ginst_cache, candidate);
3471 if (!ginst) {
3472 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3473 ginst = (MonoGenericInst *)mono_image_set_alloc0 (set, size);
3474 #ifndef MONO_SMALL_CONFIG
3475 ginst->id = mono_atomic_inc_i32 (&next_generic_inst_id);
3476 #endif
3477 ginst->is_open = is_open;
3478 ginst->type_argc = type_argc;
3480 for (int i = 0; i < type_argc; ++i)
3481 ginst->type_argv [i] = mono_metadata_type_dup (NULL, candidate->type_argv [i]);
3483 g_hash_table_insert (set->ginst_cache, ginst, ginst);
3486 mono_image_set_unlock (set);
3487 return ginst;
3490 MonoAggregateModContainer *
3491 mono_metadata_get_canonical_aggregate_modifiers (MonoAggregateModContainer *candidate)
3493 g_assert (candidate->count > 0);
3494 MonoImageSet *set = mono_metadata_get_image_set_for_aggregate_modifiers (candidate);
3496 mono_image_set_lock (set);
3498 MonoAggregateModContainer *amods = (MonoAggregateModContainer *)g_hash_table_lookup (set->aggregate_modifiers_cache, candidate);
3499 if (!amods) {
3500 size_t size = mono_sizeof_aggregate_modifiers (candidate->count);
3501 amods = (MonoAggregateModContainer *)mono_image_set_alloc0 (set, size);
3502 amods->count = candidate->count;
3503 for (int i = 0; i < candidate->count; ++i) {
3504 amods->modifiers [i].required = candidate->modifiers [i].required;
3505 amods->modifiers [i].type = mono_metadata_type_dup (NULL, candidate->modifiers [i].type);
3508 g_hash_table_insert (set->aggregate_modifiers_cache, amods, amods);
3510 mono_image_set_unlock (set);
3511 return amods;
3514 static gboolean
3515 mono_metadata_is_type_builder_generic_type_definition (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3517 MonoGenericContainer *container = mono_class_get_generic_container (container_class);
3519 if (!is_dynamic || m_class_was_typebuilder (container_class) || container->type_argc != inst->type_argc)
3520 return FALSE;
3521 return inst == container->context.class_inst;
3525 * mono_metadata_lookup_generic_class:
3527 * Returns a MonoGenericClass with the given properties.
3530 MonoGenericClass *
3531 mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3533 MonoGenericClass *gclass;
3534 MonoGenericClass helper;
3535 gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic);
3536 MonoImageSet *set;
3537 CollectData data;
3539 g_assert (mono_class_get_generic_container (container_class)->type_argc == inst->type_argc);
3541 memset (&helper, 0, sizeof(helper)); // act like g_new0
3542 helper.container_class = container_class;
3543 helper.context.class_inst = inst;
3544 helper.is_dynamic = is_dynamic; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
3545 helper.is_tb_open = is_tb_open;
3547 collect_data_init (&data);
3549 collect_gclass_images (&helper, &data);
3551 set = get_image_set (data.images, data.nimages);
3553 collect_data_free (&data);
3555 gclass = (MonoGenericClass *)mono_conc_hashtable_lookup (set->gclass_cache, &helper);
3557 /* A tripwire just to keep us honest */
3558 g_assert (!helper.cached_class);
3560 if (gclass)
3561 return gclass;
3563 gclass = mono_image_set_new0 (set, MonoGenericClass, 1);
3564 if (is_dynamic)
3565 gclass->is_dynamic = 1;
3567 gclass->is_tb_open = is_tb_open;
3568 gclass->container_class = container_class;
3569 gclass->context.class_inst = inst;
3570 gclass->context.method_inst = NULL;
3571 gclass->owner = set;
3572 if (inst == mono_class_get_generic_container (container_class)->context.class_inst && !is_tb_open)
3573 gclass->cached_class = container_class;
3575 mono_image_set_lock (set);
3577 MonoGenericClass *gclass2 = (MonoGenericClass*)mono_conc_hashtable_insert (set->gclass_cache, gclass, gclass);
3578 if (!gclass2)
3579 gclass2 = gclass;
3581 // g_hash_table_insert (set->gclass_cache, gclass, gclass);
3583 mono_image_set_unlock (set);
3585 return gclass2;
3589 * mono_metadata_inflate_generic_inst:
3591 * Instantiate the generic instance @ginst with the context @context.
3592 * Check @error for success.
3595 MonoGenericInst *
3596 mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context, MonoError *error)
3598 MonoType **type_argv;
3599 MonoGenericInst *nginst = NULL;
3600 int i, count = 0;
3602 error_init (error);
3604 if (!ginst->is_open)
3605 return ginst;
3607 type_argv = g_new0 (MonoType*, ginst->type_argc);
3609 for (i = 0; i < ginst->type_argc; i++) {
3610 type_argv [i] = mono_class_inflate_generic_type_checked (ginst->type_argv [i], context, error);
3611 if (!is_ok (error))
3612 goto cleanup;
3613 ++count;
3616 nginst = mono_metadata_get_generic_inst (ginst->type_argc, type_argv);
3618 cleanup:
3619 for (i = 0; i < count; i++)
3620 mono_metadata_free_type (type_argv [i]);
3621 g_free (type_argv);
3623 return nginst;
3626 MonoGenericInst *
3627 mono_metadata_parse_generic_inst (MonoImage *m, MonoGenericContainer *container,
3628 int count, const char *ptr, const char **rptr, MonoError *error)
3630 MonoType **type_argv;
3631 MonoGenericInst *ginst = NULL;
3632 int i, parse_count = 0;
3634 error_init (error);
3635 type_argv = g_new0 (MonoType*, count);
3637 for (i = 0; i < count; i++) {
3638 /* this can be a transient type, mono_metadata_get_generic_inst will allocate
3639 * a canonical one, if needed.
3641 MonoType *t = mono_metadata_parse_type_checked (m, container, 0, TRUE, ptr, &ptr, error);
3642 if (!t)
3643 goto cleanup;
3644 type_argv [i] = t;
3645 parse_count++;
3648 if (rptr)
3649 *rptr = ptr;
3651 g_assert (parse_count == count);
3652 ginst = mono_metadata_get_generic_inst (count, type_argv);
3654 cleanup:
3655 for (i = 0; i < parse_count; i++)
3656 mono_metadata_free_type (type_argv [i]);
3657 g_free (type_argv);
3659 return ginst;
3662 static gboolean
3663 do_mono_metadata_parse_generic_class (MonoType *type, MonoImage *m, MonoGenericContainer *container,
3664 const char *ptr, const char **rptr, MonoError *error)
3666 MonoGenericInst *inst;
3667 MonoClass *gklass;
3668 MonoType *gtype;
3669 int count;
3671 error_init (error);
3673 // XXX how about transient?
3674 gtype = mono_metadata_parse_type_checked (m, NULL, 0, FALSE, ptr, &ptr, error);
3675 if (gtype == NULL)
3676 return FALSE;
3678 gklass = mono_class_from_mono_type_internal (gtype);
3679 if (!mono_class_is_gtd (gklass)) {
3680 mono_error_set_bad_image (error, m, "Generic instance with non-generic definition");
3681 return FALSE;
3684 count = mono_metadata_decode_value (ptr, &ptr);
3685 inst = mono_metadata_parse_generic_inst (m, container, count, ptr, &ptr, error);
3686 if (inst == NULL)
3687 return FALSE;
3689 if (rptr)
3690 *rptr = ptr;
3692 type->data.generic_class = mono_metadata_lookup_generic_class (gklass, inst, FALSE);
3693 return TRUE;
3697 * select_container:
3698 * @gc: The generic container to normalize
3699 * @type: The kind of generic parameters the resulting generic-container should contain
3702 static MonoGenericContainer *
3703 select_container (MonoGenericContainer *gc, MonoTypeEnum type)
3705 gboolean is_var = (type == MONO_TYPE_VAR);
3706 if (!gc)
3707 return NULL;
3709 g_assert (is_var || type == MONO_TYPE_MVAR);
3711 if (is_var) {
3712 if (gc->is_method || gc->parent)
3714 * The current MonoGenericContainer is a generic method -> its `parent'
3715 * points to the containing class'es container.
3717 return gc->parent;
3720 return gc;
3723 MonoGenericContainer *
3724 mono_get_anonymous_container_for_image (MonoImage *image, gboolean is_mvar)
3726 MonoGenericContainer **container_pointer;
3727 if (is_mvar)
3728 container_pointer = &image->anonymous_generic_method_container;
3729 else
3730 container_pointer = &image->anonymous_generic_class_container;
3731 MonoGenericContainer *result = *container_pointer;
3733 // This container has never been created; make it now.
3734 if (!result)
3736 // Note this is never deallocated anywhere-- it exists for the lifetime of the image it's allocated from
3737 result = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
3738 result->owner.image = image;
3739 result->is_anonymous = TRUE;
3740 result->is_method = is_mvar;
3742 // If another thread already made a container, use that and leak this new one.
3743 // (Technically it would currently be safe to just assign instead of CASing.)
3744 MonoGenericContainer *exchange = (MonoGenericContainer *)mono_atomic_cas_ptr ((volatile gpointer *)container_pointer, result, NULL);
3745 if (exchange)
3746 result = exchange;
3748 return result;
3751 #define FAST_GPARAM_CACHE_SIZE 16
3753 static MonoGenericParam*
3754 lookup_anon_gparam (MonoImage *image, MonoGenericContainer *container, gint32 param_num, gboolean is_mvar)
3756 if (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE) {
3757 MonoGenericParam *cache = is_mvar ? image->mvar_gparam_cache_fast : image->var_gparam_cache_fast;
3758 if (!cache)
3759 return NULL;
3760 return &cache[param_num];
3761 } else {
3762 MonoGenericParam key;
3763 memset (&key, 0, sizeof (key));
3764 key.owner = container;
3765 key.num = param_num;
3766 key.gshared_constraint = NULL;
3767 MonoConcurrentHashTable *cache = is_mvar ? image->mvar_gparam_cache : image->var_gparam_cache;
3768 if (!cache)
3769 return NULL;
3770 return (MonoGenericParam*)mono_conc_hashtable_lookup (cache, &key);
3774 static MonoGenericParam*
3775 publish_anon_gparam_fast (MonoImage *image, MonoGenericContainer *container, gint32 param_num)
3777 g_assert (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE);
3778 MonoGenericParam **cache = container->is_method ? &image->mvar_gparam_cache_fast : &image->var_gparam_cache_fast;
3779 if (!*cache) {
3780 mono_image_lock (image);
3781 if (!*cache) {
3782 *cache = (MonoGenericParam*)mono_image_alloc0 (image, sizeof (MonoGenericParam) * FAST_GPARAM_CACHE_SIZE);
3783 for (gint32 i = 0; i < FAST_GPARAM_CACHE_SIZE; ++i) {
3784 MonoGenericParam *param = &(*cache)[i];
3785 param->owner = container;
3786 param->num = i;
3789 mono_image_unlock (image);
3791 return &(*cache)[param_num];
3795 * publish_anon_gparam_slow:
3797 * Publish \p gparam anonymous generic parameter to the anon gparam cache for \p image.
3799 * LOCKING: takes the image lock.
3801 static MonoGenericParam*
3802 publish_anon_gparam_slow (MonoImage *image, MonoGenericParam *gparam)
3804 MonoConcurrentHashTable **cache = gparam->owner->is_method ? &image->mvar_gparam_cache : &image->var_gparam_cache;
3805 if (!*cache) {
3806 mono_image_lock (image);
3807 if (!*cache) {
3808 MonoConcurrentHashTable *ht = mono_conc_hashtable_new ((GHashFunc)mono_metadata_generic_param_hash,
3809 (GEqualFunc) mono_metadata_generic_param_equal);
3810 mono_atomic_store_release (cache, ht);
3812 mono_image_unlock (image);
3814 MonoGenericParam *other = (MonoGenericParam*)mono_conc_hashtable_insert (*cache, gparam, gparam);
3815 // If another thread published first return their param, otherwise return ours.
3816 return other ? other : gparam;
3820 * mono_metadata_create_anon_gparam:
3821 * \param image the MonoImage that owns the anonymous generic parameter
3822 * \param param_num the parameter number
3823 * \param is_mvar TRUE if this is a method generic parameter, FALSE if it's a class generic parameter.
3825 * Returns: a new, or exisisting \c MonoGenericParam for an anonymous generic parameter with the given properties.
3827 * LOCKING: takes the image lock.
3829 MonoGenericParam*
3830 mono_metadata_create_anon_gparam (MonoImage *image, gint32 param_num, gboolean is_mvar)
3832 MonoGenericContainer *container = mono_get_anonymous_container_for_image (image, is_mvar);
3833 MonoGenericParam *gparam = lookup_anon_gparam (image, container, param_num, is_mvar);
3834 if (gparam)
3835 return gparam;
3836 if (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE) {
3837 return publish_anon_gparam_fast (image, container, param_num);
3838 } else {
3839 // Create a candidate generic param and try to insert it in the cache.
3840 // If multiple threads both try to publish the same param, all but one
3841 // will leak, but that's okay.
3842 gparam = (MonoGenericParam*)mono_image_alloc0 (image, sizeof (MonoGenericParam));
3843 gparam->owner = container;
3844 gparam->num = param_num;
3846 return publish_anon_gparam_slow (image, gparam);
3851 * mono_metadata_parse_generic_param:
3852 * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
3853 * see mono_metadata_parse_type_checked() for details.
3854 * Internal routine to parse a generic type parameter.
3855 * LOCKING: Acquires the loader lock
3857 static MonoGenericParam *
3858 mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_container,
3859 MonoTypeEnum type, const char *ptr, const char **rptr, MonoError *error)
3861 int index = mono_metadata_decode_value (ptr, &ptr);
3862 if (rptr)
3863 *rptr = ptr;
3865 error_init (error);
3867 generic_container = select_container (generic_container, type);
3868 if (!generic_container) {
3869 gboolean is_mvar = FALSE;
3870 switch (type)
3872 case MONO_TYPE_VAR:
3873 break;
3874 case MONO_TYPE_MVAR:
3875 is_mvar = TRUE;
3876 break;
3877 default:
3878 g_error ("Cerating generic param object with invalid MonoType"); // This is not a generic param
3881 return mono_metadata_create_anon_gparam (m, index, is_mvar);
3884 if (index >= generic_container->type_argc) {
3885 mono_error_set_bad_image (error, m, "Invalid generic %s parameter index %d, max index is %d",
3886 generic_container->is_method ? "method" : "type",
3887 index, generic_container->type_argc);
3888 return NULL;
3891 //This can't return NULL
3892 return mono_generic_container_get_param (generic_container, index);
3896 * mono_metadata_get_shared_type:
3898 * Return a shared instance of TYPE, if available, NULL otherwise.
3899 * Shared MonoType instances help save memory. Their contents should not be modified
3900 * by the caller. They do not need to be freed as their lifetime is bound by either
3901 * the lifetime of the runtime (builtin types), or the lifetime of the MonoClass
3902 * instance they are embedded in. If they are freed, they should be freed using
3903 * mono_metadata_free_type () instead of g_free ().
3905 MonoType*
3906 mono_metadata_get_shared_type (MonoType *type)
3908 MonoType *cached;
3910 /* No need to use locking since nobody is modifying the hash table */
3911 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type)))
3912 return cached;
3914 switch (type->type){
3915 case MONO_TYPE_CLASS:
3916 case MONO_TYPE_VALUETYPE:
3917 if (type == m_class_get_byval_arg (type->data.klass))
3918 return type;
3919 if (type == m_class_get_this_arg (type->data.klass))
3920 return type;
3921 break;
3922 default:
3923 break;
3926 return NULL;
3929 static gboolean
3930 compare_type_literals (MonoImage *image, int class_type, int type_type, MonoError *error)
3932 error_init (error);
3934 /* _byval_arg.type can be zero if we're decoding a type that references a class been loading.
3935 * See mcs/test/gtest-440. and #650936.
3936 * FIXME This better be moved to the metadata verifier as it can catch more cases.
3938 if (!class_type)
3939 return TRUE;
3940 /* NET 1.1 assemblies might encode string and object in a denormalized way.
3941 * See #675464.
3943 if (class_type == type_type)
3944 return TRUE;
3946 if (type_type == MONO_TYPE_CLASS) {
3947 if (class_type == MONO_TYPE_STRING || class_type == MONO_TYPE_OBJECT)
3948 return TRUE;
3949 //XXX stringify this argument
3950 mono_error_set_bad_image (error, image, "Expected reference type but got type kind %d", class_type);
3951 return FALSE;
3954 g_assert (type_type == MONO_TYPE_VALUETYPE);
3955 switch (class_type) {
3956 case MONO_TYPE_BOOLEAN:
3957 case MONO_TYPE_CHAR:
3958 case MONO_TYPE_I1:
3959 case MONO_TYPE_U1:
3960 case MONO_TYPE_I2:
3961 case MONO_TYPE_U2:
3962 case MONO_TYPE_I4:
3963 case MONO_TYPE_U4:
3964 case MONO_TYPE_I8:
3965 case MONO_TYPE_U8:
3966 case MONO_TYPE_R4:
3967 case MONO_TYPE_R8:
3968 case MONO_TYPE_I:
3969 case MONO_TYPE_U:
3970 case MONO_TYPE_CLASS:
3971 return TRUE;
3972 default:
3973 //XXX stringify this argument
3974 mono_error_set_bad_image (error, image, "Expected value type but got type kind %d", class_type);
3975 return FALSE;
3979 static gboolean
3980 verify_var_type_and_container (MonoImage *image, int var_type, MonoGenericContainer *container, MonoError *error)
3982 error_init (error);
3983 if (var_type == MONO_TYPE_MVAR) {
3984 if (!container->is_method) { //MVAR and a method container
3985 mono_error_set_bad_image (error, image, "MVAR parsed in a context without a method container");
3986 return FALSE;
3988 } else {
3989 if (!(!container->is_method || //VAR and class container
3990 (container->is_method && container->parent))) { //VAR and method container with parent
3991 mono_error_set_bad_image (error, image, "VAR parsed in a context without a class container");
3992 return FALSE;
3995 return TRUE;
3999 * do_mono_metadata_parse_type:
4000 * @type: MonoType to be filled in with the return value
4001 * @m: image context
4002 * @generic_context: generics_context
4003 * @transient: whenever to allocate data from the heap
4004 * @ptr: pointer to the encoded type
4005 * @rptr: pointer where the end of the encoded type is saved
4007 * Internal routine used to "fill" the contents of @type from an
4008 * allocated pointer. This is done this way to avoid doing too
4009 * many mini-allocations (particularly for the MonoFieldType which
4010 * most of the time is just a MonoType, but sometimes might be augmented).
4012 * This routine is used by mono_metadata_parse_type and
4013 * mono_metadata_parse_field_type
4015 * This extracts a Type as specified in Partition II (22.2.12)
4017 * Returns: FALSE if the type could not be loaded
4019 static gboolean
4020 do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container,
4021 gboolean transient, const char *ptr, const char **rptr, MonoError *error)
4023 error_init (error);
4025 type->type = (MonoTypeEnum)mono_metadata_decode_value (ptr, &ptr);
4027 switch (type->type){
4028 case MONO_TYPE_VOID:
4029 case MONO_TYPE_BOOLEAN:
4030 case MONO_TYPE_CHAR:
4031 case MONO_TYPE_I1:
4032 case MONO_TYPE_U1:
4033 case MONO_TYPE_I2:
4034 case MONO_TYPE_U2:
4035 case MONO_TYPE_I4:
4036 case MONO_TYPE_U4:
4037 case MONO_TYPE_I8:
4038 case MONO_TYPE_U8:
4039 case MONO_TYPE_R4:
4040 case MONO_TYPE_R8:
4041 case MONO_TYPE_I:
4042 case MONO_TYPE_U:
4043 case MONO_TYPE_STRING:
4044 case MONO_TYPE_OBJECT:
4045 case MONO_TYPE_TYPEDBYREF:
4046 break;
4047 case MONO_TYPE_VALUETYPE:
4048 case MONO_TYPE_CLASS: {
4049 guint32 token;
4050 MonoClass *klass;
4051 token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr);
4052 klass = mono_class_get_checked (m, token, error);
4053 type->data.klass = klass;
4054 if (!klass)
4055 return FALSE;
4057 if (!compare_type_literals (m, m_class_get_byval_arg (klass)->type, type->type, error))
4058 return FALSE;
4060 break;
4062 case MONO_TYPE_SZARRAY: {
4063 MonoType *etype = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
4064 if (!etype)
4065 return FALSE;
4067 type->data.klass = mono_class_from_mono_type_internal (etype);
4069 if (transient)
4070 mono_metadata_free_type (etype);
4072 g_assert (type->data.klass); //This was previously a check for NULL, but mcfmt should never fail. It can return a borken MonoClass, but should return at least something.
4073 break;
4075 case MONO_TYPE_PTR: {
4076 type->data.type = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
4077 if (!type->data.type)
4078 return FALSE;
4079 break;
4081 case MONO_TYPE_FNPTR: {
4082 type->data.method = mono_metadata_parse_method_signature_full (m, container, 0, ptr, &ptr, error);
4083 if (!type->data.method)
4084 return FALSE;
4085 break;
4087 case MONO_TYPE_ARRAY: {
4088 type->data.array = mono_metadata_parse_array_internal (m, container, transient, ptr, &ptr, error);
4089 if (!type->data.array)
4090 return FALSE;
4091 break;
4093 case MONO_TYPE_MVAR:
4094 case MONO_TYPE_VAR: {
4095 if (container && !verify_var_type_and_container (m, type->type, container, error))
4096 return FALSE;
4098 type->data.generic_param = mono_metadata_parse_generic_param (m, container, type->type, ptr, &ptr, error);
4099 if (!type->data.generic_param)
4100 return FALSE;
4102 break;
4104 case MONO_TYPE_GENERICINST: {
4105 if (!do_mono_metadata_parse_generic_class (type, m, container, ptr, &ptr, error))
4106 return FALSE;
4107 break;
4109 default:
4110 mono_error_set_bad_image (error, m, "type 0x%02x not handled in do_mono_metadata_parse_type on image %s", type->type, m->name);
4111 return FALSE;
4114 if (rptr)
4115 *rptr = ptr;
4116 return TRUE;
4120 * mono_metadata_free_type:
4121 * \param type type to free
4123 * Free the memory allocated for type \p type which is allocated on the heap.
4125 void
4126 mono_metadata_free_type (MonoType *type)
4128 if (type >= builtin_types && type < builtin_types + NBUILTIN_TYPES ())
4129 return;
4131 switch (type->type){
4132 case MONO_TYPE_OBJECT:
4133 case MONO_TYPE_STRING:
4134 if (!type->data.klass)
4135 break;
4136 /* fall through */
4137 case MONO_TYPE_CLASS:
4138 case MONO_TYPE_VALUETYPE:
4139 if (type == m_class_get_byval_arg (type->data.klass) || type == m_class_get_this_arg (type->data.klass))
4140 return;
4141 break;
4142 case MONO_TYPE_PTR:
4143 mono_metadata_free_type (type->data.type);
4144 break;
4145 case MONO_TYPE_FNPTR:
4146 mono_metadata_free_method_signature (type->data.method);
4147 break;
4148 case MONO_TYPE_ARRAY:
4149 mono_metadata_free_array (type->data.array);
4150 break;
4151 default:
4152 break;
4155 g_free (type);
4158 #if 0
4159 static void
4160 hex_dump (const char *buffer, int base, int count)
4162 int show_header = 1;
4163 int i;
4165 if (count < 0){
4166 count = -count;
4167 show_header = 0;
4170 for (i = 0; i < count; i++){
4171 if (show_header)
4172 if ((i % 16) == 0)
4173 printf ("\n0x%08x: ", (unsigned char) base + i);
4175 printf ("%02x ", (unsigned char) (buffer [i]));
4177 fflush (stdout);
4179 #endif
4181 /**
4182 * @ptr: Points to the beginning of the Section Data (25.3)
4184 static MonoExceptionClause*
4185 parse_section_data (MonoImage *m, int *num_clauses, const unsigned char *ptr, MonoError *error)
4187 unsigned char sect_data_flags;
4188 int is_fat;
4189 guint32 sect_data_len;
4190 MonoExceptionClause* clauses = NULL;
4192 error_init (error);
4194 while (1) {
4195 /* align on 32-bit boundary */
4196 ptr = dword_align (ptr);
4197 sect_data_flags = *ptr;
4198 ptr++;
4200 is_fat = sect_data_flags & METHOD_HEADER_SECTION_FAT_FORMAT;
4201 if (is_fat) {
4202 sect_data_len = (ptr [2] << 16) | (ptr [1] << 8) | ptr [0];
4203 ptr += 3;
4204 } else {
4205 sect_data_len = ptr [0];
4206 ++ptr;
4209 if (sect_data_flags & METHOD_HEADER_SECTION_EHTABLE) {
4210 const unsigned char *p = dword_align (ptr);
4211 int i;
4212 *num_clauses = is_fat ? sect_data_len / 24: sect_data_len / 12;
4213 /* we could just store a pointer if we don't need to byteswap */
4214 clauses = (MonoExceptionClause *)g_malloc0 (sizeof (MonoExceptionClause) * (*num_clauses));
4215 for (i = 0; i < *num_clauses; ++i) {
4216 MonoExceptionClause *ec = &clauses [i];
4217 guint32 tof_value;
4218 if (is_fat) {
4219 ec->flags = read32 (p);
4220 ec->try_offset = read32 (p + 4);
4221 ec->try_len = read32 (p + 8);
4222 ec->handler_offset = read32 (p + 12);
4223 ec->handler_len = read32 (p + 16);
4224 tof_value = read32 (p + 20);
4225 p += 24;
4226 } else {
4227 ec->flags = read16 (p);
4228 ec->try_offset = read16 (p + 2);
4229 ec->try_len = *(p + 4);
4230 ec->handler_offset = read16 (p + 5);
4231 ec->handler_len = *(p + 7);
4232 tof_value = read32 (p + 8);
4233 p += 12;
4235 if (ec->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4236 ec->data.filter_offset = tof_value;
4237 } else if (ec->flags == MONO_EXCEPTION_CLAUSE_NONE) {
4238 ec->data.catch_class = NULL;
4239 if (tof_value) {
4240 ec->data.catch_class = mono_class_get_checked (m, tof_value, error);
4241 if (!is_ok (error)) {
4242 g_free (clauses);
4243 return NULL;
4246 } else {
4247 ec->data.catch_class = NULL;
4249 /* g_print ("try %d: %x %04x-%04x %04x\n", i, ec->flags, ec->try_offset, ec->try_offset+ec->try_len, ec->try_len); */
4253 if (sect_data_flags & METHOD_HEADER_SECTION_MORE_SECTS)
4254 ptr += sect_data_len - 4; /* LAMESPEC: it seems the size includes the header */
4255 else
4256 return clauses;
4261 * mono_method_get_header_summary:
4262 * @method: The method to get the header.
4263 * @summary: Where to store the header
4266 * Returns: TRUE if the header was properly decoded.
4268 gboolean
4269 mono_method_get_header_summary (MonoMethod *method, MonoMethodHeaderSummary *summary)
4271 int idx;
4272 guint32 rva;
4273 MonoImage* img;
4274 const char *ptr;
4275 unsigned char flags, format;
4276 guint16 fat_flags;
4277 ERROR_DECL (error);
4279 /*Only the GMD has a pointer to the metadata.*/
4280 while (method->is_inflated)
4281 method = ((MonoMethodInflated*)method)->declaring;
4283 summary->code = NULL;
4284 summary->code_size = 0;
4285 summary->max_stack = 0;
4286 summary->has_clauses = FALSE;
4287 summary->has_locals = FALSE;
4289 /*FIXME extract this into a MACRO and share it with mono_method_get_header*/
4290 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
4291 return FALSE;
4293 if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
4294 MonoMethodHeader *header = ((MonoMethodWrapper *)method)->header;
4295 if (!header)
4296 return FALSE;
4297 summary->code = header->code;
4298 summary->code_size = header->code_size;
4299 summary->max_stack = header->max_stack;
4300 summary->has_clauses = header->num_clauses > 0;
4301 summary->has_locals = header->num_locals > 0;
4302 return TRUE;
4306 idx = mono_metadata_token_index (method->token);
4307 img = m_class_get_image (method->klass);
4308 rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
4310 /*We must run the verifier since we'll be decoding it.*/
4311 if (!mono_verifier_verify_method_header (img, rva, error)) {
4312 mono_error_cleanup (error);
4313 return FALSE;
4316 ptr = mono_image_rva_map (img, rva);
4317 if (!ptr)
4318 return FALSE;
4320 flags = *(const unsigned char *)ptr;
4321 format = flags & METHOD_HEADER_FORMAT_MASK;
4323 switch (format) {
4324 case METHOD_HEADER_TINY_FORMAT:
4325 ptr++;
4326 summary->max_stack = 8;
4327 summary->code = (unsigned char *) ptr;
4328 summary->code_size = flags >> 2;
4329 break;
4330 case METHOD_HEADER_FAT_FORMAT:
4331 fat_flags = read16 (ptr);
4332 ptr += 2;
4333 summary->max_stack = read16 (ptr);
4334 ptr += 2;
4335 summary->code_size = read32 (ptr);
4336 ptr += 4;
4337 summary->has_locals = !!read32 (ptr);
4338 ptr += 4;
4339 if (fat_flags & METHOD_HEADER_MORE_SECTS)
4340 summary->has_clauses = TRUE;
4341 summary->code = (unsigned char *) ptr;
4342 break;
4343 default:
4344 return FALSE;
4346 return TRUE;
4350 * mono_metadata_parse_mh_full:
4351 * @m: metadata context
4352 * @generic_context: generics context
4353 * @ptr: pointer to the method header.
4355 * Decode the method header at @ptr, including pointer to the IL code,
4356 * info about local variables and optional exception tables.
4357 * This is a Mono runtime internal function.
4359 * LOCKING: Acquires the loader lock.
4361 * Returns: a transient MonoMethodHeader allocated from the heap.
4363 MonoMethodHeader *
4364 mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, const char *ptr, MonoError *error)
4366 MonoMethodHeader *mh = NULL;
4367 unsigned char flags = *(const unsigned char *) ptr;
4368 unsigned char format = flags & METHOD_HEADER_FORMAT_MASK;
4369 guint16 fat_flags;
4370 guint32 local_var_sig_tok, max_stack, code_size, init_locals;
4371 const unsigned char *code;
4372 MonoExceptionClause* clauses = NULL;
4373 int num_clauses = 0;
4374 MonoTableInfo *t = &m->tables [MONO_TABLE_STANDALONESIG];
4375 guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
4377 error_init (error);
4379 if (!ptr) {
4380 mono_error_set_bad_image (error, m, "Method header with null pointer");
4381 return NULL;
4384 switch (format) {
4385 case METHOD_HEADER_TINY_FORMAT:
4386 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER);
4387 ptr++;
4388 mh->max_stack = 8;
4389 mh->is_transient = TRUE;
4390 local_var_sig_tok = 0;
4391 mh->code_size = flags >> 2;
4392 mh->code = (unsigned char*)ptr;
4393 return mh;
4394 case METHOD_HEADER_FAT_FORMAT:
4395 fat_flags = read16 (ptr);
4396 ptr += 2;
4397 max_stack = read16 (ptr);
4398 ptr += 2;
4399 code_size = read32 (ptr);
4400 ptr += 4;
4401 local_var_sig_tok = read32 (ptr);
4402 ptr += 4;
4404 if (fat_flags & METHOD_HEADER_INIT_LOCALS)
4405 init_locals = 1;
4406 else
4407 init_locals = 0;
4409 code = (unsigned char*)ptr;
4411 if (!(fat_flags & METHOD_HEADER_MORE_SECTS))
4412 break;
4415 * There are more sections
4417 ptr = (char*)code + code_size;
4418 break;
4419 default:
4420 mono_error_set_bad_image (error, m, "Invalid method header format %d", format);
4421 return NULL;
4424 if (local_var_sig_tok) {
4425 int idx = (local_var_sig_tok & 0xffffff)-1;
4426 if (idx >= t->rows || idx < 0) {
4427 mono_error_set_bad_image (error, m, "Invalid method header local vars signature token 0x%8x", idx);
4428 goto fail;
4430 mono_metadata_decode_row (t, idx, cols, 1);
4432 if (!mono_verifier_verify_standalone_signature (m, cols [MONO_STAND_ALONE_SIGNATURE], error))
4433 goto fail;
4435 if (fat_flags & METHOD_HEADER_MORE_SECTS) {
4436 clauses = parse_section_data (m, &num_clauses, (const unsigned char*)ptr, error);
4437 goto_if_nok (error, fail);
4439 if (local_var_sig_tok) {
4440 const char *locals_ptr;
4441 int len=0, i;
4443 locals_ptr = mono_metadata_blob_heap (m, cols [MONO_STAND_ALONE_SIGNATURE]);
4444 mono_metadata_decode_blob_size (locals_ptr, &locals_ptr);
4445 if (*locals_ptr != 0x07)
4446 g_warning ("wrong signature for locals blob");
4447 locals_ptr++;
4448 len = mono_metadata_decode_value (locals_ptr, &locals_ptr);
4449 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + len * sizeof (MonoType*) + num_clauses * sizeof (MonoExceptionClause));
4450 mh->num_locals = len;
4451 for (i = 0; i < len; ++i) {
4452 mh->locals [i] = mono_metadata_parse_type_internal (m, container, 0, TRUE, locals_ptr, &locals_ptr, error);
4453 goto_if_nok (error, fail);
4455 } else {
4456 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + num_clauses * sizeof (MonoExceptionClause));
4458 mh->code = code;
4459 mh->code_size = code_size;
4460 mh->max_stack = max_stack;
4461 mh->is_transient = TRUE;
4462 mh->init_locals = init_locals;
4463 if (clauses) {
4464 MonoExceptionClause* clausesp = (MonoExceptionClause*)&mh->locals [mh->num_locals];
4465 memcpy (clausesp, clauses, num_clauses * sizeof (MonoExceptionClause));
4466 g_free (clauses);
4467 mh->clauses = clausesp;
4468 mh->num_clauses = num_clauses;
4470 return mh;
4471 fail:
4472 g_free (clauses);
4473 g_free (mh);
4474 return NULL;
4479 * mono_metadata_parse_mh:
4480 * \param generic_context generics context
4481 * \param ptr pointer to the method header.
4483 * Decode the method header at \p ptr, including pointer to the IL code,
4484 * info about local variables and optional exception tables.
4486 * \returns a transient \c MonoMethodHeader allocated from the heap.
4488 MonoMethodHeader *
4489 mono_metadata_parse_mh (MonoImage *m, const char *ptr)
4491 ERROR_DECL (error);
4492 MonoMethodHeader *header = mono_metadata_parse_mh_full (m, NULL, ptr, error);
4493 mono_error_cleanup (error);
4494 return header;
4498 * mono_metadata_free_mh:
4499 * \param mh a method header
4501 * Free the memory allocated for the method header.
4503 void
4504 mono_metadata_free_mh (MonoMethodHeader *mh)
4506 int i;
4508 /* If it is not transient it means it's part of a wrapper method,
4509 * or a SRE-generated method, so the lifetime in that case is
4510 * dictated by the method's own lifetime
4512 if (mh && mh->is_transient) {
4513 for (i = 0; i < mh->num_locals; ++i)
4514 mono_metadata_free_type (mh->locals [i]);
4515 g_free (mh);
4520 * mono_method_header_get_code:
4521 * \param header a \c MonoMethodHeader pointer
4522 * \param code_size memory location for returning the code size
4523 * \param max_stack memory location for returning the max stack
4525 * Method header accessor to retreive info about the IL code properties:
4526 * a pointer to the IL code itself, the size of the code and the max number
4527 * of stack slots used by the code.
4529 * \returns pointer to the IL code represented by the method header.
4531 const unsigned char*
4532 mono_method_header_get_code (MonoMethodHeader *header, guint32* code_size, guint32* max_stack)
4534 if (code_size)
4535 *code_size = header->code_size;
4536 if (max_stack)
4537 *max_stack = header->max_stack;
4538 return header->code;
4542 * mono_method_header_get_locals:
4543 * \param header a \c MonoMethodHeader pointer
4544 * \param num_locals memory location for returning the number of local variables
4545 * \param init_locals memory location for returning the init_locals flag
4547 * Method header accessor to retreive info about the local variables:
4548 * an array of local types, the number of locals and whether the locals
4549 * are supposed to be initialized to 0 on method entry
4551 * \returns pointer to an array of types of the local variables
4553 MonoType**
4554 mono_method_header_get_locals (MonoMethodHeader *header, guint32* num_locals, gboolean *init_locals)
4556 if (num_locals)
4557 *num_locals = header->num_locals;
4558 if (init_locals)
4559 *init_locals = header->init_locals;
4560 return header->locals;
4564 * mono_method_header_get_num_clauses:
4565 * @header: a MonoMethodHeader pointer
4567 * Method header accessor to retreive the number of exception clauses.
4569 * Returns: the number of exception clauses present
4572 mono_method_header_get_num_clauses (MonoMethodHeader *header)
4574 return header->num_clauses;
4578 * mono_method_header_get_clauses:
4579 * \param header a \c MonoMethodHeader pointer
4580 * \param method \c MonoMethod the header belongs to
4581 * \param iter pointer to a iterator
4582 * \param clause pointer to a \c MonoExceptionClause structure which will be filled with the info
4584 * Get the info about the exception clauses in the method. Set \c *iter to NULL to
4585 * initiate the iteration, then call the method repeatedly until it returns FALSE.
4586 * At each iteration, the structure pointed to by clause if filled with the
4587 * exception clause information.
4589 * \returns TRUE if clause was filled with info, FALSE if there are no more exception
4590 * clauses.
4593 mono_method_header_get_clauses (MonoMethodHeader *header, MonoMethod *method, gpointer *iter, MonoExceptionClause *clause)
4595 MonoExceptionClause *sc;
4596 /* later we'll be able to use this interface to parse the clause info on demand,
4597 * without allocating anything.
4599 if (!iter || !header->num_clauses)
4600 return FALSE;
4601 if (!*iter) {
4602 *iter = sc = header->clauses;
4603 *clause = *sc;
4604 return TRUE;
4606 sc = (MonoExceptionClause *)*iter;
4607 sc++;
4608 if (sc < header->clauses + header->num_clauses) {
4609 *iter = sc;
4610 *clause = *sc;
4611 return TRUE;
4613 return FALSE;
4617 * mono_metadata_parse_field_type:
4618 * \param m metadata context to extract information from
4619 * \param ptr pointer to the field signature
4620 * \param rptr pointer updated to match the end of the decoded stream
4622 * Parses the field signature, and returns the type information for it.
4624 * \returns The \c MonoType that was extracted from \p ptr .
4626 MonoType *
4627 mono_metadata_parse_field_type (MonoImage *m, short field_flags, const char *ptr, const char **rptr)
4629 ERROR_DECL (error);
4630 MonoType * type = mono_metadata_parse_type_internal (m, NULL, field_flags, FALSE, ptr, rptr, error);
4631 mono_error_cleanup (error);
4632 return type;
4636 * mono_metadata_parse_param:
4637 * \param m metadata context to extract information from
4638 * \param ptr pointer to the param signature
4639 * \param rptr pointer updated to match the end of the decoded stream
4641 * Parses the param signature, and returns the type information for it.
4643 * \returns The \c MonoType that was extracted from \p ptr .
4645 MonoType *
4646 mono_metadata_parse_param (MonoImage *m, const char *ptr, const char **rptr)
4648 ERROR_DECL (error);
4649 MonoType * type = mono_metadata_parse_type_internal (m, NULL, 0, FALSE, ptr, rptr, error);
4650 mono_error_cleanup (error);
4651 return type;
4655 * mono_metadata_token_from_dor:
4656 * \param dor_token A \c TypeDefOrRef coded index
4658 * \p dor_token is a \c TypeDefOrRef coded index: it contains either
4659 * a \c TypeDef, \c TypeRef or \c TypeSpec in the lower bits, and the upper
4660 * bits contain an index into the table.
4662 * \returns an expanded token
4664 guint32
4665 mono_metadata_token_from_dor (guint32 dor_index)
4667 guint32 table, idx;
4669 table = dor_index & 0x03;
4670 idx = dor_index >> 2;
4672 switch (table){
4673 case 0: /* TypeDef */
4674 return MONO_TOKEN_TYPE_DEF | idx;
4675 case 1: /* TypeRef */
4676 return MONO_TOKEN_TYPE_REF | idx;
4677 case 2: /* TypeSpec */
4678 return MONO_TOKEN_TYPE_SPEC | idx;
4679 default:
4680 g_assert_not_reached ();
4683 return 0;
4687 * We use this to pass context information to the row locator
4689 typedef struct {
4690 int idx; /* The index that we are trying to locate */
4691 int col_idx; /* The index in the row where idx may be stored */
4692 MonoTableInfo *t; /* pointer to the table */
4693 guint32 result;
4694 } locator_t;
4697 * How the row locator works.
4699 * Table A
4700 * ___|___
4701 * ___|___ Table B
4702 * ___|___------> _______
4703 * ___|___ _______
4705 * A column in the rows of table A references an index in table B.
4706 * For example A may be the TYPEDEF table and B the METHODDEF table.
4708 * Given an index in table B we want to get the row in table A
4709 * where the column n references our index in B.
4711 * In the locator_t structure:
4712 * t is table A
4713 * col_idx is the column number
4714 * index is the index in table B
4715 * result will be the index in table A
4717 * Examples:
4718 * Table A Table B column (in table A)
4719 * TYPEDEF METHODDEF MONO_TYPEDEF_METHOD_LIST
4720 * TYPEDEF FIELD MONO_TYPEDEF_FIELD_LIST
4721 * PROPERTYMAP PROPERTY MONO_PROPERTY_MAP_PROPERTY_LIST
4722 * INTERFIMPL TYPEDEF MONO_INTERFACEIMPL_CLASS
4723 * METHODSEM PROPERTY ASSOCIATION (encoded index)
4725 * Note that we still don't support encoded indexes.
4728 static int
4729 typedef_locator (const void *a, const void *b)
4731 locator_t *loc = (locator_t *) a;
4732 const char *bb = (const char *) b;
4733 int typedef_index = (bb - loc->t->base) / loc->t->row_size;
4734 guint32 col, col_next;
4736 col = mono_metadata_decode_row_col (loc->t, typedef_index, loc->col_idx);
4738 if (loc->idx < col)
4739 return -1;
4742 * Need to check that the next row is valid.
4744 if (typedef_index + 1 < loc->t->rows) {
4745 col_next = mono_metadata_decode_row_col (loc->t, typedef_index + 1, loc->col_idx);
4746 if (loc->idx >= col_next)
4747 return 1;
4749 if (col == col_next)
4750 return 1;
4753 loc->result = typedef_index;
4755 return 0;
4758 static int
4759 table_locator (const void *a, const void *b)
4761 locator_t *loc = (locator_t *) a;
4762 const char *bb = (const char *) b;
4763 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4764 guint32 col;
4766 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4768 if (loc->idx == col) {
4769 loc->result = table_index;
4770 return 0;
4772 if (loc->idx < col)
4773 return -1;
4774 else
4775 return 1;
4778 static int
4779 declsec_locator (const void *a, const void *b)
4781 locator_t *loc = (locator_t *) a;
4782 const char *bb = (const char *) b;
4783 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4784 guint32 col;
4786 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4788 if (loc->idx == col) {
4789 loc->result = table_index;
4790 return 0;
4792 if (loc->idx < col)
4793 return -1;
4794 else
4795 return 1;
4799 * search_ptr_table:
4801 * Return the 1-based row index in TABLE, which must be one of the *Ptr tables,
4802 * which contains IDX.
4804 static guint32
4805 search_ptr_table (MonoImage *image, int table, int idx)
4807 MonoTableInfo *ptrdef = &image->tables [table];
4808 int i;
4810 /* Use a linear search to find our index in the table */
4811 for (i = 0; i < ptrdef->rows; i ++)
4812 /* All the Ptr tables have the same structure */
4813 if (mono_metadata_decode_row_col (ptrdef, i, 0) == idx)
4814 break;
4816 if (i < ptrdef->rows)
4817 return i + 1;
4818 else
4819 return idx;
4823 * mono_metadata_typedef_from_field:
4824 * \param meta metadata context
4825 * \param index FieldDef token
4827 * \returns the 1-based index into the \c TypeDef table of the type that
4828 * declared the field described by \p index, or 0 if not found.
4830 guint32
4831 mono_metadata_typedef_from_field (MonoImage *meta, guint32 index)
4833 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4834 locator_t loc;
4836 if (!tdef->base)
4837 return 0;
4839 loc.idx = mono_metadata_token_index (index);
4840 loc.col_idx = MONO_TYPEDEF_FIELD_LIST;
4841 loc.t = tdef;
4843 if (meta->uncompressed_metadata)
4844 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
4846 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4847 return 0;
4849 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4850 return loc.result + 1;
4854 * mono_metadata_typedef_from_method:
4855 * \param meta metadata context
4856 * \param index \c MethodDef token
4857 * \returns the 1-based index into the \c TypeDef table of the type that
4858 * declared the method described by \p index. 0 if not found.
4860 guint32
4861 mono_metadata_typedef_from_method (MonoImage *meta, guint32 index)
4863 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4864 locator_t loc;
4866 if (!tdef->base)
4867 return 0;
4869 loc.idx = mono_metadata_token_index (index);
4870 loc.col_idx = MONO_TYPEDEF_METHOD_LIST;
4871 loc.t = tdef;
4873 if (meta->uncompressed_metadata)
4874 loc.idx = search_ptr_table (meta, MONO_TABLE_METHOD_POINTER, loc.idx);
4876 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4877 return 0;
4879 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4880 return loc.result + 1;
4884 * mono_metadata_interfaces_from_typedef_full:
4885 * \param meta metadata context
4886 * \param index typedef token
4887 * \param interfaces Out parameter used to store the interface array
4888 * \param count Out parameter used to store the number of interfaces
4889 * \param heap_alloc_result if TRUE the result array will be \c g_malloc'd
4890 * \param context The generic context
4891 * \param error set on error
4893 * The array of interfaces that the \p index typedef token implements is returned in
4894 * \p interfaces. The number of elements in the array is returned in \p count.
4896 * \returns \c TRUE on success, \c FALSE on failure and sets \p error.
4898 gboolean
4899 mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, MonoClass ***interfaces, guint *count, gboolean heap_alloc_result, MonoGenericContext *context, MonoError *error)
4901 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_INTERFACEIMPL];
4902 locator_t loc;
4903 guint32 start, pos;
4904 guint32 cols [MONO_INTERFACEIMPL_SIZE];
4905 MonoClass **result;
4907 *interfaces = NULL;
4908 *count = 0;
4910 error_init (error);
4912 if (!tdef->base)
4913 return TRUE;
4915 loc.idx = mono_metadata_token_index (index);
4916 loc.col_idx = MONO_INTERFACEIMPL_CLASS;
4917 loc.t = tdef;
4919 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4920 return TRUE;
4922 start = loc.result;
4924 * We may end up in the middle of the rows...
4926 while (start > 0) {
4927 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_INTERFACEIMPL_CLASS))
4928 start--;
4929 else
4930 break;
4932 pos = start;
4933 while (pos < tdef->rows) {
4934 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4935 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4936 break;
4937 ++pos;
4940 if (heap_alloc_result)
4941 result = g_new0 (MonoClass*, pos - start);
4942 else
4943 result = (MonoClass **)mono_image_alloc0 (meta, sizeof (MonoClass*) * (pos - start));
4945 pos = start;
4946 while (pos < tdef->rows) {
4947 MonoClass *iface;
4949 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4950 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4951 break;
4952 iface = mono_class_get_and_inflate_typespec_checked (
4953 meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context, error);
4954 if (iface == NULL)
4955 return FALSE;
4956 result [pos - start] = iface;
4957 ++pos;
4959 *count = pos - start;
4960 *interfaces = result;
4961 return TRUE;
4965 * mono_metadata_interfaces_from_typedef:
4966 * \param meta metadata context
4967 * \param index typedef token
4968 * \param count Out parameter used to store the number of interfaces
4970 * The array of interfaces that the \p index typedef token implements is returned in
4971 * \p interfaces. The number of elements in the array is returned in \p count. The returned
4972 * array is allocated with \c g_malloc and the caller must free it.
4974 * LOCKING: Acquires the loader lock .
4976 * \returns the interface array on success, NULL on failure.
4978 MonoClass**
4979 mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *count)
4981 ERROR_DECL (error);
4982 MonoClass **interfaces = NULL;
4983 gboolean rv;
4985 rv = mono_metadata_interfaces_from_typedef_full (meta, index, &interfaces, count, TRUE, NULL, error);
4986 mono_error_assert_ok (error);
4987 if (rv)
4988 return interfaces;
4989 else
4990 return NULL;
4994 * mono_metadata_nested_in_typedef:
4995 * \param meta metadata context
4996 * \param index typedef token
4997 * \returns the 1-based index into the TypeDef table of the type
4998 * where the type described by \p index is nested.
4999 * Returns 0 if \p index describes a non-nested type.
5001 guint32
5002 mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index)
5004 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
5005 locator_t loc;
5007 if (!tdef->base)
5008 return 0;
5010 loc.idx = mono_metadata_token_index (index);
5011 loc.col_idx = MONO_NESTED_CLASS_NESTED;
5012 loc.t = tdef;
5014 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5015 return 0;
5017 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5018 return mono_metadata_decode_row_col (tdef, loc.result, MONO_NESTED_CLASS_ENCLOSING) | MONO_TOKEN_TYPE_DEF;
5022 * mono_metadata_nesting_typedef:
5023 * \param meta metadata context
5024 * \param index typedef token
5025 * \returns the 1-based index into the \c TypeDef table of the first type
5026 * that is nested inside the type described by \p index. The search starts at
5027 * \p start_index. Returns 0 if no such type is found.
5029 guint32
5030 mono_metadata_nesting_typedef (MonoImage *meta, guint32 index, guint32 start_index)
5032 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
5033 guint32 start;
5034 guint32 class_index = mono_metadata_token_index (index);
5036 if (!tdef->base)
5037 return 0;
5039 start = start_index;
5041 while (start <= tdef->rows) {
5042 if (class_index == mono_metadata_decode_row_col (tdef, start - 1, MONO_NESTED_CLASS_ENCLOSING))
5043 break;
5044 else
5045 start++;
5048 if (start > tdef->rows)
5049 return 0;
5050 else
5051 return start;
5055 * mono_metadata_packing_from_typedef:
5056 * \param meta metadata context
5057 * \param index token representing a type
5058 * \returns the info stored in the \c ClassLayout table for the given typedef token
5059 * into the \p packing and \p size pointers.
5060 * Returns 0 if the info is not found.
5062 guint32
5063 mono_metadata_packing_from_typedef (MonoImage *meta, guint32 index, guint32 *packing, guint32 *size)
5065 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CLASSLAYOUT];
5066 locator_t loc;
5067 guint32 cols [MONO_CLASS_LAYOUT_SIZE];
5069 if (!tdef->base)
5070 return 0;
5072 loc.idx = mono_metadata_token_index (index);
5073 loc.col_idx = MONO_CLASS_LAYOUT_PARENT;
5074 loc.t = tdef;
5076 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5077 return 0;
5079 mono_metadata_decode_row (tdef, loc.result, cols, MONO_CLASS_LAYOUT_SIZE);
5080 if (packing)
5081 *packing = cols [MONO_CLASS_LAYOUT_PACKING_SIZE];
5082 if (size)
5083 *size = cols [MONO_CLASS_LAYOUT_CLASS_SIZE];
5085 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5086 return loc.result + 1;
5090 * mono_metadata_custom_attrs_from_index:
5091 * \param meta metadata context
5092 * \param index token representing the parent
5093 * \returns: the 1-based index into the \c CustomAttribute table of the first
5094 * attribute which belongs to the metadata object described by \p index.
5095 * Returns 0 if no such attribute is found.
5097 guint32
5098 mono_metadata_custom_attrs_from_index (MonoImage *meta, guint32 index)
5100 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CUSTOMATTRIBUTE];
5101 locator_t loc;
5103 if (!tdef->base)
5104 return 0;
5106 loc.idx = index;
5107 loc.col_idx = MONO_CUSTOM_ATTR_PARENT;
5108 loc.t = tdef;
5110 /* FIXME: Index translation */
5112 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5113 return 0;
5115 /* Find the first entry by searching backwards */
5116 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_CUSTOM_ATTR_PARENT) == index))
5117 loc.result --;
5119 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5120 return loc.result + 1;
5124 * mono_metadata_declsec_from_index:
5125 * \param meta metadata context
5126 * \param index token representing the parent
5127 * \returns the 0-based index into the \c DeclarativeSecurity table of the first
5128 * attribute which belongs to the metadata object described by \p index.
5129 * Returns \c -1 if no such attribute is found.
5131 guint32
5132 mono_metadata_declsec_from_index (MonoImage *meta, guint32 index)
5134 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_DECLSECURITY];
5135 locator_t loc;
5137 if (!tdef->base)
5138 return -1;
5140 loc.idx = index;
5141 loc.col_idx = MONO_DECL_SECURITY_PARENT;
5142 loc.t = tdef;
5144 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, declsec_locator))
5145 return -1;
5147 /* Find the first entry by searching backwards */
5148 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_DECL_SECURITY_PARENT) == index))
5149 loc.result --;
5151 return loc.result;
5155 * mono_metadata_localscope_from_methoddef:
5156 * @meta: metadata context
5157 * @index: methoddef index
5159 * Returns: the 1-based index into the LocalScope table of the first
5160 * scope which belongs to the method described by @index.
5161 * Returns 0 if no such row is found.
5163 guint32
5164 mono_metadata_localscope_from_methoddef (MonoImage *meta, guint32 index)
5166 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_LOCALSCOPE];
5167 locator_t loc;
5169 if (!tdef->base)
5170 return 0;
5172 loc.idx = index;
5173 loc.col_idx = MONO_LOCALSCOPE_METHOD;
5174 loc.t = tdef;
5176 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5177 return 0;
5179 /* Find the first entry by searching backwards */
5180 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_LOCALSCOPE_METHOD) == index))
5181 loc.result --;
5183 return loc.result + 1;
5186 #ifdef DEBUG
5187 static void
5188 mono_backtrace (int limit)
5190 void *array[limit];
5191 char **names;
5192 int i;
5193 backtrace (array, limit);
5194 names = backtrace_symbols (array, limit);
5195 for (i =0; i < limit; ++i) {
5196 g_print ("\t%s\n", names [i]);
5198 g_free (names);
5200 #endif
5202 static int i8_align;
5205 * mono_type_set_alignment:
5207 * Set the alignment used by runtime to layout fields etc. of type TYPE to ALIGN.
5208 * This should only be used in AOT mode since the resulting layout will not match the
5209 * host abi layout.
5211 void
5212 mono_type_set_alignment (MonoTypeEnum type, int align)
5214 /* Support only a few types whose alignment is abi dependent */
5215 switch (type) {
5216 case MONO_TYPE_I8:
5217 i8_align = align;
5218 break;
5219 default:
5220 g_assert_not_reached ();
5221 break;
5226 * mono_type_size:
5227 * \param t the type to return the size of
5228 * \returns The number of bytes required to hold an instance of this
5229 * type in memory
5232 mono_type_size (MonoType *t, int *align)
5234 MonoTypeEnum simple_type;
5236 if (!t) {
5237 *align = 1;
5238 return 0;
5240 if (t->byref) {
5241 *align = MONO_ABI_ALIGNOF (gpointer);
5242 return MONO_ABI_SIZEOF (gpointer);
5245 simple_type = t->type;
5246 again:
5247 switch (simple_type) {
5248 case MONO_TYPE_VOID:
5249 *align = 1;
5250 return 0;
5251 case MONO_TYPE_BOOLEAN:
5252 *align = MONO_ABI_ALIGNOF (gint8);
5253 return 1;
5254 case MONO_TYPE_I1:
5255 case MONO_TYPE_U1:
5256 *align = MONO_ABI_ALIGNOF (gint8);
5257 return 1;
5258 case MONO_TYPE_CHAR:
5259 case MONO_TYPE_I2:
5260 case MONO_TYPE_U2:
5261 *align = MONO_ABI_ALIGNOF (gint16);
5262 return 2;
5263 case MONO_TYPE_I4:
5264 case MONO_TYPE_U4:
5265 *align = MONO_ABI_ALIGNOF (gint32);
5266 return 4;
5267 case MONO_TYPE_R4:
5268 *align = MONO_ABI_ALIGNOF (float);
5269 return 4;
5270 case MONO_TYPE_I8:
5271 case MONO_TYPE_U8:
5272 *align = MONO_ABI_ALIGNOF (gint64);
5273 return 8;
5274 case MONO_TYPE_R8:
5275 *align = MONO_ABI_ALIGNOF (double);
5276 return 8;
5277 case MONO_TYPE_I:
5278 case MONO_TYPE_U:
5279 *align = MONO_ABI_ALIGNOF (gpointer);
5280 return MONO_ABI_SIZEOF (gpointer);
5281 case MONO_TYPE_VALUETYPE: {
5282 if (m_class_is_enumtype (t->data.klass))
5283 return mono_type_size (mono_class_enum_basetype_internal (t->data.klass), align);
5284 else
5285 return mono_class_value_size (t->data.klass, (guint32*)align);
5287 case MONO_TYPE_STRING:
5288 case MONO_TYPE_OBJECT:
5289 case MONO_TYPE_CLASS:
5290 case MONO_TYPE_SZARRAY:
5291 case MONO_TYPE_PTR:
5292 case MONO_TYPE_FNPTR:
5293 case MONO_TYPE_ARRAY:
5294 *align = MONO_ABI_ALIGNOF (gpointer);
5295 return MONO_ABI_SIZEOF (gpointer);
5296 case MONO_TYPE_TYPEDBYREF:
5297 return mono_class_value_size (mono_defaults.typed_reference_class, (guint32*)align);
5298 case MONO_TYPE_GENERICINST: {
5299 MonoGenericClass *gclass = t->data.generic_class;
5300 MonoClass *container_class = gclass->container_class;
5302 // g_assert (!gclass->inst->is_open);
5304 if (m_class_is_valuetype (container_class)) {
5305 if (m_class_is_enumtype (container_class))
5306 return mono_type_size (mono_class_enum_basetype_internal (container_class), align);
5307 else
5308 return mono_class_value_size (mono_class_from_mono_type_internal (t), (guint32*)align);
5309 } else {
5310 *align = MONO_ABI_ALIGNOF (gpointer);
5311 return MONO_ABI_SIZEOF (gpointer);
5314 case MONO_TYPE_VAR:
5315 case MONO_TYPE_MVAR:
5316 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
5317 *align = MONO_ABI_ALIGNOF (gpointer);
5318 return MONO_ABI_SIZEOF (gpointer);
5319 } else {
5320 /* The gparam can only match types given by gshared_constraint */
5321 return mono_type_size (t->data.generic_param->gshared_constraint, align);
5322 goto again;
5324 default:
5325 g_error ("mono_type_size: type 0x%02x unknown", t->type);
5327 return 0;
5331 * mono_type_stack_size:
5332 * \param t the type to return the size it uses on the stack
5333 * \returns The number of bytes required to hold an instance of this
5334 * type on the runtime stack
5337 mono_type_stack_size (MonoType *t, int *align)
5339 return mono_type_stack_size_internal (t, align, FALSE);
5343 mono_type_stack_size_internal (MonoType *t, int *align, gboolean allow_open)
5345 int tmp;
5346 MonoTypeEnum simple_type;
5347 int stack_slot_size = TARGET_SIZEOF_VOID_P;
5348 int stack_slot_align = TARGET_SIZEOF_VOID_P;
5350 g_assert (t != NULL);
5352 if (!align)
5353 align = &tmp;
5355 if (t->byref) {
5356 *align = stack_slot_align;
5357 return stack_slot_size;
5360 simple_type = t->type;
5361 switch (simple_type) {
5362 case MONO_TYPE_BOOLEAN:
5363 case MONO_TYPE_CHAR:
5364 case MONO_TYPE_I1:
5365 case MONO_TYPE_U1:
5366 case MONO_TYPE_I2:
5367 case MONO_TYPE_U2:
5368 case MONO_TYPE_I4:
5369 case MONO_TYPE_U4:
5370 case MONO_TYPE_I:
5371 case MONO_TYPE_U:
5372 case MONO_TYPE_STRING:
5373 case MONO_TYPE_OBJECT:
5374 case MONO_TYPE_CLASS:
5375 case MONO_TYPE_SZARRAY:
5376 case MONO_TYPE_PTR:
5377 case MONO_TYPE_FNPTR:
5378 case MONO_TYPE_ARRAY:
5379 *align = stack_slot_align;
5380 return stack_slot_size;
5381 case MONO_TYPE_VAR:
5382 case MONO_TYPE_MVAR:
5383 g_assert (allow_open);
5384 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
5385 *align = stack_slot_align;
5386 return stack_slot_size;
5387 } else {
5388 /* The gparam can only match types given by gshared_constraint */
5389 return mono_type_stack_size_internal (t->data.generic_param->gshared_constraint, align, allow_open);
5391 case MONO_TYPE_TYPEDBYREF:
5392 *align = stack_slot_align;
5393 return stack_slot_size * 3;
5394 case MONO_TYPE_R4:
5395 *align = MONO_ABI_ALIGNOF (float);
5396 return sizeof (float);
5397 case MONO_TYPE_I8:
5398 case MONO_TYPE_U8:
5399 *align = MONO_ABI_ALIGNOF (gint64);
5400 return sizeof (gint64);
5401 case MONO_TYPE_R8:
5402 *align = MONO_ABI_ALIGNOF (double);
5403 return sizeof (double);
5404 case MONO_TYPE_VALUETYPE: {
5405 guint32 size;
5407 if (m_class_is_enumtype (t->data.klass))
5408 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (t->data.klass), align, allow_open);
5409 else {
5410 size = mono_class_value_size (t->data.klass, (guint32*)align);
5412 *align = *align + stack_slot_align - 1;
5413 *align &= ~(stack_slot_align - 1);
5415 size += stack_slot_size - 1;
5416 size &= ~(stack_slot_size - 1);
5418 return size;
5421 case MONO_TYPE_GENERICINST: {
5422 MonoGenericClass *gclass = t->data.generic_class;
5423 MonoClass *container_class = gclass->container_class;
5425 if (!allow_open)
5426 g_assert (!gclass->context.class_inst->is_open);
5428 if (m_class_is_valuetype (container_class)) {
5429 if (m_class_is_enumtype (container_class))
5430 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (container_class), align, allow_open);
5431 else {
5432 guint32 size = mono_class_value_size (mono_class_from_mono_type_internal (t), (guint32*)align);
5434 *align = *align + stack_slot_align - 1;
5435 *align &= ~(stack_slot_align - 1);
5437 size += stack_slot_size - 1;
5438 size &= ~(stack_slot_size - 1);
5440 return size;
5442 } else {
5443 *align = stack_slot_align;
5444 return stack_slot_size;
5447 default:
5448 g_error ("type 0x%02x unknown", t->type);
5450 return 0;
5453 gboolean
5454 mono_type_generic_inst_is_valuetype (MonoType *type)
5456 g_assert (type->type == MONO_TYPE_GENERICINST);
5457 return m_class_is_valuetype (type->data.generic_class->container_class);
5461 * mono_metadata_generic_class_is_valuetype:
5463 gboolean
5464 mono_metadata_generic_class_is_valuetype (MonoGenericClass *gclass)
5466 return m_class_is_valuetype (gclass->container_class);
5469 static gboolean
5470 _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only)
5472 MonoGenericInst *i1 = g1->context.class_inst;
5473 MonoGenericInst *i2 = g2->context.class_inst;
5475 if (g1->is_dynamic != g2->is_dynamic)
5476 return FALSE;
5477 if (!mono_metadata_class_equal (g1->container_class, g2->container_class, signature_only))
5478 return FALSE;
5479 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5480 return FALSE;
5481 return g1->is_tb_open == g2->is_tb_open;
5484 static gboolean
5485 _mono_metadata_generic_class_container_equal (const MonoGenericClass *g1, MonoClass *c2, gboolean signature_only)
5487 MonoGenericInst *i1 = g1->context.class_inst;
5488 MonoGenericInst *i2 = mono_class_get_generic_container (c2)->context.class_inst;
5490 if (!mono_metadata_class_equal (g1->container_class, c2, signature_only))
5491 return FALSE;
5492 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5493 return FALSE;
5494 return !g1->is_tb_open;
5497 guint
5498 mono_metadata_generic_context_hash (const MonoGenericContext *context)
5500 /* FIXME: check if this seed is good enough */
5501 guint hash = 0xc01dfee7;
5502 if (context->class_inst)
5503 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->class_inst);
5504 if (context->method_inst)
5505 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->method_inst);
5506 return hash;
5509 gboolean
5510 mono_metadata_generic_context_equal (const MonoGenericContext *g1, const MonoGenericContext *g2)
5512 return g1->class_inst == g2->class_inst && g1->method_inst == g2->method_inst;
5516 * mono_metadata_str_hash:
5518 * This should be used instead of g_str_hash for computing hash codes visible
5519 * outside this module, since g_str_hash () is not guaranteed to be stable
5520 * (its not the same in eglib for example).
5522 guint
5523 mono_metadata_str_hash (gconstpointer v1)
5525 /* Same as g_str_hash () in glib */
5526 char *p = (char *) v1;
5527 guint hash = *p;
5529 while (*p++) {
5530 if (*p)
5531 hash = (hash << 5) - hash + *p;
5534 return hash;
5538 * mono_metadata_type_hash:
5539 * \param t1 a type
5540 * Computes a hash value for \p t1 to be used in \c GHashTable.
5541 * The returned hash is guaranteed to be the same across executions.
5543 guint
5544 mono_metadata_type_hash (MonoType *t1)
5546 guint hash = t1->type;
5548 hash |= t1->byref << 6; /* do not collide with t1->type values */
5549 switch (t1->type) {
5550 case MONO_TYPE_VALUETYPE:
5551 case MONO_TYPE_CLASS:
5552 case MONO_TYPE_SZARRAY: {
5553 MonoClass *klass = t1->data.klass;
5555 * Dynamic classes must not be hashed on their type since it can change
5556 * during runtime. For example, if we hash a reference type that is
5557 * later made into a valuetype.
5559 * This is specially problematic with generic instances since they are
5560 * inserted in a bunch of hash tables before been finished.
5562 if (image_is_dynamic (m_class_get_image (klass)))
5563 return (t1->byref << 6) | mono_metadata_str_hash (m_class_get_name (klass));
5564 return ((hash << 5) - hash) ^ mono_metadata_str_hash (m_class_get_name (klass));
5566 case MONO_TYPE_PTR:
5567 return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
5568 case MONO_TYPE_ARRAY:
5569 return ((hash << 5) - hash) ^ mono_metadata_type_hash (m_class_get_byval_arg (t1->data.array->eklass));
5570 case MONO_TYPE_GENERICINST:
5571 return ((hash << 5) - hash) ^ mono_generic_class_hash (t1->data.generic_class);
5572 case MONO_TYPE_VAR:
5573 case MONO_TYPE_MVAR:
5574 return ((hash << 5) - hash) ^ mono_metadata_generic_param_hash (t1->data.generic_param);
5575 default:
5576 return hash;
5580 guint
5581 mono_metadata_generic_param_hash (MonoGenericParam *p)
5583 guint hash;
5584 MonoGenericParamInfo *info;
5586 hash = (mono_generic_param_num (p) << 2);
5587 if (p->gshared_constraint)
5588 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->gshared_constraint);
5589 info = mono_generic_param_info (p);
5590 /* Can't hash on the owner klass/method, since those might not be set when this is called */
5591 if (!p->owner->is_anonymous)
5592 hash = ((hash << 5) - hash) ^ info->token;
5593 return hash;
5596 static gboolean
5597 mono_metadata_generic_param_equal_internal (MonoGenericParam *p1, MonoGenericParam *p2, gboolean signature_only)
5599 if (p1 == p2)
5600 return TRUE;
5601 if (mono_generic_param_num (p1) != mono_generic_param_num (p2))
5602 return FALSE;
5603 if (p1->gshared_constraint && p2->gshared_constraint) {
5604 if (!mono_metadata_type_equal (p1->gshared_constraint, p2->gshared_constraint))
5605 return FALSE;
5606 } else {
5607 if (p1->gshared_constraint != p2->gshared_constraint)
5608 return FALSE;
5612 * We have to compare the image as well because if we didn't,
5613 * the generic_inst_cache lookup wouldn't care about the image
5614 * of generic params, so what could happen is that a generic
5615 * inst with params from image A is put into the cache, then
5616 * image B gets that generic inst from the cache, image A is
5617 * unloaded, so the inst is deleted, but image B still retains
5618 * a pointer to it.
5620 if (mono_generic_param_owner (p1) == mono_generic_param_owner (p2))
5621 return TRUE;
5624 * If `signature_only' is true, we're comparing two (method) signatures.
5625 * In this case, the owner of two type parameters doesn't need to match.
5628 return signature_only;
5631 gboolean
5632 mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2)
5634 return mono_metadata_generic_param_equal_internal (p1, p2, TRUE);
5637 static gboolean
5638 mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only)
5640 if (c1 == c2)
5641 return TRUE;
5642 if (mono_class_is_ginst (c1) && mono_class_is_ginst (c2))
5643 return _mono_metadata_generic_class_equal (mono_class_get_generic_class (c1), mono_class_get_generic_class (c2), signature_only);
5644 if (mono_class_is_ginst (c1) && mono_class_is_gtd (c2))
5645 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c1), c2, signature_only);
5646 if (mono_class_is_gtd (c1) && mono_class_is_ginst (c2))
5647 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c2), c1, signature_only);
5648 MonoType *c1_type = m_class_get_byval_arg (c1);
5649 MonoType *c2_type = m_class_get_byval_arg (c2);
5650 if ((c1_type->type == MONO_TYPE_VAR) && (c2_type->type == MONO_TYPE_VAR))
5651 return mono_metadata_generic_param_equal_internal (
5652 c1_type->data.generic_param, c2_type->data.generic_param, signature_only);
5653 if ((c1_type->type == MONO_TYPE_MVAR) && (c2_type->type == MONO_TYPE_MVAR))
5654 return mono_metadata_generic_param_equal_internal (
5655 c1_type->data.generic_param, c2_type->data.generic_param, signature_only);
5656 if (signature_only &&
5657 (c1_type->type == MONO_TYPE_SZARRAY) && (c2_type->type == MONO_TYPE_SZARRAY))
5658 return mono_metadata_class_equal (c1_type->data.klass, c2_type->data.klass, signature_only);
5659 if (signature_only &&
5660 (c1_type->type == MONO_TYPE_ARRAY) && (c2_type->type == MONO_TYPE_ARRAY))
5661 return do_mono_metadata_type_equal (c1_type, c2_type, signature_only);
5662 return FALSE;
5665 static gboolean
5666 mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only)
5668 gpointer iter1 = 0, iter2 = 0;
5670 if (s1 == s2)
5671 return TRUE;
5672 if (s1->call_convention != s2->call_convention)
5673 return FALSE;
5674 if (s1->sentinelpos != s2->sentinelpos)
5675 return FALSE;
5676 if (s1->hasthis != s2->hasthis)
5677 return FALSE;
5678 if (s1->explicit_this != s2->explicit_this)
5679 return FALSE;
5680 if (! do_mono_metadata_type_equal (s1->ret, s2->ret, signature_only))
5681 return FALSE;
5682 if (s1->param_count != s2->param_count)
5683 return FALSE;
5685 while (TRUE) {
5686 MonoType *t1 = mono_signature_get_params (s1, &iter1);
5687 MonoType *t2 = mono_signature_get_params (s2, &iter2);
5689 if (t1 == NULL || t2 == NULL)
5690 return (t1 == t2);
5691 if (! do_mono_metadata_type_equal (t1, t2, signature_only))
5692 return FALSE;
5696 static gboolean
5697 mono_metadata_custom_modifiers_equal (MonoType *t1, MonoType *t2, gboolean signature_only)
5699 // ECMA 335, 7.1.1:
5700 // The CLI itself shall treat required and optional modifiers in the same manner.
5701 // Two signatures that differ only by the addition of a custom modifier
5702 // (required or optional) shall not be considered to match.
5703 int count = mono_type_custom_modifier_count (t1);
5704 if (count != mono_type_custom_modifier_count (t2))
5705 return FALSE;
5707 for (int i=0; i < count; i++) {
5708 // FIXME: propagate error to caller
5709 ERROR_DECL (error);
5710 gboolean cm1_required, cm2_required;
5712 MonoType *cm1_type = mono_type_get_custom_modifier (t1, i, &cm1_required, error);
5713 mono_error_assert_ok (error);
5714 MonoType *cm2_type = mono_type_get_custom_modifier (t2, i, &cm2_required, error);
5715 mono_error_assert_ok (error);
5717 if (cm1_required != cm2_required)
5718 return FALSE;
5720 if (!do_mono_metadata_type_equal (cm1_type, cm2_type, signature_only))
5721 return FALSE;
5723 return TRUE;
5727 * mono_metadata_type_equal:
5728 * @t1: a type
5729 * @t2: another type
5730 * @signature_only: If true, treat ginsts as equal which are instantiated separately but have equal positional value
5732 * Determine if @t1 and @t2 represent the same type.
5733 * Returns: #TRUE if @t1 and @t2 are equal.
5735 static gboolean
5736 do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only)
5738 if (t1->type != t2->type || t1->byref != t2->byref)
5739 return FALSE;
5741 gboolean cmod_reject = FALSE;
5743 if (t1->has_cmods != t2->has_cmods)
5744 cmod_reject = TRUE;
5745 else if (t1->has_cmods && t2->has_cmods) {
5746 cmod_reject = !mono_metadata_custom_modifiers_equal (t1, t2, signature_only);
5749 gboolean result = FALSE;
5751 switch (t1->type) {
5752 case MONO_TYPE_VOID:
5753 case MONO_TYPE_BOOLEAN:
5754 case MONO_TYPE_CHAR:
5755 case MONO_TYPE_I1:
5756 case MONO_TYPE_U1:
5757 case MONO_TYPE_I2:
5758 case MONO_TYPE_U2:
5759 case MONO_TYPE_I4:
5760 case MONO_TYPE_U4:
5761 case MONO_TYPE_I8:
5762 case MONO_TYPE_U8:
5763 case MONO_TYPE_R4:
5764 case MONO_TYPE_R8:
5765 case MONO_TYPE_STRING:
5766 case MONO_TYPE_I:
5767 case MONO_TYPE_U:
5768 case MONO_TYPE_OBJECT:
5769 case MONO_TYPE_TYPEDBYREF:
5770 result = TRUE;
5771 break;
5772 case MONO_TYPE_VALUETYPE:
5773 case MONO_TYPE_CLASS:
5774 case MONO_TYPE_SZARRAY:
5775 result = mono_metadata_class_equal (t1->data.klass, t2->data.klass, signature_only);
5776 break;
5777 case MONO_TYPE_PTR:
5778 result = do_mono_metadata_type_equal (t1->data.type, t2->data.type, signature_only);
5779 break;
5780 case MONO_TYPE_ARRAY:
5781 if (t1->data.array->rank != t2->data.array->rank)
5782 result = FALSE;
5783 else
5784 result = mono_metadata_class_equal (t1->data.array->eklass, t2->data.array->eklass, signature_only);
5785 break;
5786 case MONO_TYPE_GENERICINST:
5787 result = _mono_metadata_generic_class_equal (
5788 t1->data.generic_class, t2->data.generic_class, signature_only);
5789 break;
5790 case MONO_TYPE_VAR:
5791 result = mono_metadata_generic_param_equal_internal (
5792 t1->data.generic_param, t2->data.generic_param, signature_only);
5793 break;
5794 case MONO_TYPE_MVAR:
5795 result = mono_metadata_generic_param_equal_internal (
5796 t1->data.generic_param, t2->data.generic_param, signature_only);
5797 break;
5798 case MONO_TYPE_FNPTR:
5799 result = mono_metadata_fnptr_equal (t1->data.method, t2->data.method, signature_only);
5800 break;
5801 default:
5802 g_error ("implement type compare for %0x!", t1->type);
5803 return FALSE;
5806 return result && !cmod_reject;
5810 * mono_metadata_type_equal:
5812 gboolean
5813 mono_metadata_type_equal (MonoType *t1, MonoType *t2)
5815 return do_mono_metadata_type_equal (t1, t2, FALSE);
5819 * mono_metadata_type_equal_full:
5820 * \param t1 a type
5821 * \param t2 another type
5822 * \param signature_only if signature only comparison should be made
5824 * Determine if \p t1 and \p t2 are signature compatible if \p signature_only is TRUE, otherwise
5825 * behaves the same way as mono_metadata_type_equal.
5826 * The function mono_metadata_type_equal(a, b) is just a shortcut for mono_metadata_type_equal_full(a, b, FALSE).
5827 * \returns TRUE if \p t1 and \p t2 are equal taking \p signature_only into account.
5829 gboolean
5830 mono_metadata_type_equal_full (MonoType *t1, MonoType *t2, gboolean signature_only)
5832 return do_mono_metadata_type_equal (t1, t2, signature_only);
5836 * mono_metadata_signature_equal:
5837 * \param sig1 a signature
5838 * \param sig2 another signature
5840 * Determine if \p sig1 and \p sig2 represent the same signature, with the
5841 * same number of arguments and the same types.
5842 * \returns TRUE if \p sig1 and \p sig2 are equal.
5844 gboolean
5845 mono_metadata_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
5847 int i;
5849 if (sig1->hasthis != sig2->hasthis || sig1->param_count != sig2->param_count)
5850 return FALSE;
5852 if (sig1->generic_param_count != sig2->generic_param_count)
5853 return FALSE;
5856 * We're just comparing the signatures of two methods here:
5858 * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
5859 * U and V are equal here.
5861 * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
5864 for (i = 0; i < sig1->param_count; i++) {
5865 MonoType *p1 = sig1->params[i];
5866 MonoType *p2 = sig2->params[i];
5868 /* if (p1->attrs != p2->attrs)
5869 return FALSE;
5871 if (!do_mono_metadata_type_equal (p1, p2, TRUE))
5872 return FALSE;
5875 if (!do_mono_metadata_type_equal (sig1->ret, sig2->ret, TRUE))
5876 return FALSE;
5877 return TRUE;
5880 MonoType *
5881 mono_type_get_custom_modifier (const MonoType *ty, uint8_t idx, gboolean *required, MonoError *error)
5883 g_assert (ty->has_cmods);
5884 if (mono_type_is_aggregate_mods (ty)) {
5885 MonoAggregateModContainer *amods = mono_type_get_amods (ty);
5886 g_assert (idx < amods->count);
5887 MonoSingleCustomMod *cmod = &amods->modifiers [idx];
5888 if (required)
5889 *required = !!cmod->required;
5890 return cmod->type;
5891 } else {
5892 MonoCustomModContainer *cmods = mono_type_get_cmods (ty);
5893 g_assert (idx < cmods->count);
5894 MonoCustomMod *cmod = &cmods->modifiers [idx];
5895 if (required)
5896 *required = !!cmod->required;
5897 MonoImage *image = cmods->image;
5898 uint32_t token = cmod->token;
5899 return mono_type_get_checked (image, token, NULL, error);
5905 * mono_metadata_type_dup:
5906 * \param image image to alloc memory from
5907 * \param original type to duplicate
5908 * \returns copy of type allocated from the image's mempool (or from the heap, if \p image is null).
5910 MonoType *
5911 mono_metadata_type_dup (MonoImage *image, const MonoType *o)
5913 return mono_metadata_type_dup_with_cmods (image, o, o);
5916 static void
5917 deep_type_dup_fixup (MonoImage *image, MonoType *r, const MonoType *o);
5919 static uint8_t
5920 custom_modifier_copy (MonoAggregateModContainer *dest, uint8_t dest_offset, const MonoType *source)
5922 if (mono_type_is_aggregate_mods (source)) {
5923 MonoAggregateModContainer *src_cmods = mono_type_get_amods (source);
5924 memcpy (&dest->modifiers [dest_offset], &src_cmods->modifiers[0], src_cmods->count * sizeof (MonoSingleCustomMod));
5925 dest_offset += src_cmods->count;
5926 } else {
5927 MonoCustomModContainer *src_cmods = mono_type_get_cmods (source);
5928 for (int i = 0; i < src_cmods->count; i++) {
5929 ERROR_DECL (error); // XXX FIXME: AK - propagate the error to the caller.
5930 MonoSingleCustomMod *cmod = &dest->modifiers [dest_offset++];
5931 cmod->type = mono_type_get_checked (src_cmods->image, src_cmods->modifiers [i].token, NULL, error);
5932 mono_error_assert_ok (error);
5933 cmod->required = src_cmods->modifiers [i].required;
5936 return dest_offset;
5939 /* makes a dup of 'o' but also appends the custom modifiers from 'cmods_source' */
5940 static MonoType *
5941 do_metadata_type_dup_append_cmods (MonoImage *image, const MonoType *o, const MonoType *cmods_source)
5943 g_assert (o != cmods_source);
5944 g_assert (o->has_cmods);
5945 g_assert (cmods_source->has_cmods);
5946 if (!mono_type_is_aggregate_mods (o) &&
5947 !mono_type_is_aggregate_mods (cmods_source) &&
5948 mono_type_get_cmods (o)->image == mono_type_get_cmods (cmods_source)->image) {
5949 /* the uniform case: all the cmods are from the same image. */
5950 MonoCustomModContainer *o_cmods = mono_type_get_cmods (o);
5951 MonoCustomModContainer *extra_cmods = mono_type_get_cmods (cmods_source);
5952 uint8_t total_cmods = o_cmods->count + extra_cmods->count;
5953 gboolean aggregate = FALSE;
5954 size_t sizeof_dup = mono_sizeof_type_with_mods (total_cmods, aggregate);
5955 MonoType *r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_dup) : (MonoType *)g_malloc0 (sizeof_dup);
5957 mono_type_with_mods_init (r, total_cmods, aggregate);
5959 /* copy the original type o, not including its modifiers */
5960 memcpy (r, o, mono_sizeof_type_with_mods (0, FALSE));
5961 deep_type_dup_fixup (image, r, o);
5963 /* The modifier order matters to Roslyn, they expect the extra cmods to come first:
5965 * Suppose we substitute 'int32 modopt(IsLong)' for 'T' in 'void Test
5966 * (T modopt(IsConst))'. Roslyn expects the result to be 'void Test
5967 * (int32 modopt(IsLong) modopt(IsConst))'.
5969 * but! cmods are encoded in IL in reverse order, so 'int32 modopt(IsConst) modopt(IsLong)' is
5970 * encoded as `cmod_opt [typeref IsLong] cmod_opt [typeref IsConst] I4`
5971 * so in our array, extra_cmods (IsLong) come first, followed by o_cmods (IsConst)
5973 * (Here 'o' is 'int32 modopt(IsLong)' and cmods_source is 'T modopt(IsConst)')
5975 /* append the modifiers from cmods_source and o */
5976 MonoCustomModContainer *r_container = mono_type_get_cmods (r);
5977 uint8_t dest_offset = 0;
5978 r_container->image = extra_cmods->image;
5980 memcpy (&r_container->modifiers [dest_offset], &o_cmods->modifiers [0], o_cmods->count * sizeof (MonoCustomMod));
5981 dest_offset += o_cmods->count;
5982 memcpy (&r_container->modifiers [dest_offset], &extra_cmods->modifiers [0], extra_cmods->count * sizeof (MonoCustomMod));
5983 dest_offset += extra_cmods->count;
5984 g_assert (dest_offset == total_cmods);
5986 return r;
5987 } else {
5988 /* The aggregate case: either o_cmods or extra_cmods has aggregate cmods, or they're both simple but from different images. */
5989 uint8_t total_cmods = 0;
5990 total_cmods += mono_type_custom_modifier_count (o);
5991 total_cmods += mono_type_custom_modifier_count (cmods_source);
5993 gboolean aggregate = TRUE;
5994 size_t sizeof_dup = mono_sizeof_type_with_mods (total_cmods, aggregate);
5996 /* FIXME: if image, and the images of the custom modifiers from
5997 * o and cmods_source are all different, we need an image
5998 * set... */
5999 MonoType *r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_dup) : (MonoType*)g_malloc0 (sizeof_dup);
6001 mono_type_with_mods_init (r, total_cmods, aggregate);
6003 memcpy (r, o, mono_sizeof_type_with_mods (0, FALSE));
6004 deep_type_dup_fixup (image, r, o);
6006 /* Try not to blow up the stack. See comment on
6007 * MONO_MAX_EXPECTED_CMODS. Since here we're appending all the
6008 * mods together, it's possible we'll end up with more than the
6009 * maximum allowed. If that ever happens in practice, we
6010 * should redefine the bound and possibly make this function
6011 * fail dynamically instead of asserting.
6013 g_assert (total_cmods < MONO_MAX_EXPECTED_CMODS);
6014 size_t r_container_size = mono_sizeof_aggregate_modifiers (total_cmods);
6015 MonoAggregateModContainer *r_container_candidate = g_alloca (r_container_size);
6016 memset (r_container_candidate, 0, r_container_size);
6017 uint8_t dest_offset = 0;
6019 dest_offset = custom_modifier_copy (r_container_candidate, dest_offset, o);
6020 dest_offset = custom_modifier_copy (r_container_candidate, dest_offset, cmods_source);
6021 g_assert (dest_offset == total_cmods);
6022 r_container_candidate->count = total_cmods;
6024 mono_type_set_amods (r, mono_metadata_get_canonical_aggregate_modifiers (r_container_candidate));
6026 return r;
6031 * Works the same way as mono_metadata_type_dup but pick cmods from @cmods_source
6033 MonoType *
6034 mono_metadata_type_dup_with_cmods (MonoImage *image, const MonoType *o, const MonoType *cmods_source)
6036 if (o->has_cmods && o != cmods_source && cmods_source->has_cmods) {
6037 return do_metadata_type_dup_append_cmods (image, o, cmods_source);
6040 MonoType *r = NULL;
6042 /* if we get here, either o and cmods_source alias, or else exactly one of them has cmods. */
6044 uint8_t num_mods = MAX (mono_type_custom_modifier_count (o), mono_type_custom_modifier_count (cmods_source));
6045 gboolean aggregate = mono_type_is_aggregate_mods (o) || mono_type_is_aggregate_mods (cmods_source);
6046 size_t sizeof_r = mono_sizeof_type_with_mods (num_mods, aggregate);
6048 r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_r) : (MonoType *)g_malloc0 (sizeof_r);
6050 if (cmods_source->has_cmods) {
6051 /* FIXME: if it's aggregate what do we assert here? */
6052 g_assert (!image || (!aggregate && image == mono_type_get_cmods (cmods_source)->image));
6053 memcpy (r, cmods_source, mono_sizeof_type (cmods_source));
6056 memcpy (r, o, mono_sizeof_type (o));
6058 /* reset custom mod count and aggregateness to be correct. */
6059 mono_type_with_mods_init (r, num_mods, aggregate);
6060 if (aggregate)
6061 mono_type_set_amods (r, mono_type_is_aggregate_mods (o) ? mono_type_get_amods (o) : mono_type_get_amods (cmods_source));
6062 deep_type_dup_fixup (image, r, o);
6063 return r;
6067 static void
6068 deep_type_dup_fixup (MonoImage *image, MonoType *r, const MonoType *o)
6070 if (o->type == MONO_TYPE_PTR) {
6071 r->data.type = mono_metadata_type_dup (image, o->data.type);
6072 } else if (o->type == MONO_TYPE_ARRAY) {
6073 r->data.array = mono_dup_array_type (image, o->data.array);
6074 } else if (o->type == MONO_TYPE_FNPTR) {
6075 /*FIXME the dup'ed signature is leaked mono_metadata_free_type*/
6076 r->data.method = mono_metadata_signature_deep_dup (image, o->data.method);
6081 * mono_signature_hash:
6083 guint
6084 mono_signature_hash (MonoMethodSignature *sig)
6086 guint i, res = sig->ret->type;
6088 for (i = 0; i < sig->param_count; i++)
6089 res = (res << 5) - res + mono_type_hash (sig->params[i]);
6091 return res;
6095 * mono_metadata_encode_value:
6096 * @value: value to encode
6097 * @buf: buffer where to write the compressed representation
6098 * @endbuf: pointer updated to point at the end of the encoded output
6100 * Encodes the value @value in the compressed representation used
6101 * in metadata and stores the result in @buf. @buf needs to be big
6102 * enough to hold the data (4 bytes).
6104 void
6105 mono_metadata_encode_value (guint32 value, char *buf, char **endbuf)
6107 char *p = buf;
6109 if (value < 0x80)
6110 *p++ = value;
6111 else if (value < 0x4000) {
6112 p [0] = 0x80 | (value >> 8);
6113 p [1] = value & 0xff;
6114 p += 2;
6115 } else {
6116 p [0] = (value >> 24) | 0xc0;
6117 p [1] = (value >> 16) & 0xff;
6118 p [2] = (value >> 8) & 0xff;
6119 p [3] = value & 0xff;
6120 p += 4;
6122 if (endbuf)
6123 *endbuf = p;
6127 * mono_metadata_field_info:
6128 * \param meta the Image the field is defined in
6129 * \param index the index in the field table representing the field
6130 * \param offset a pointer to an integer where to store the offset that may have been specified for the field in a FieldLayout table
6131 * \param rva a pointer to the RVA of the field data in the image that may have been defined in a \c FieldRVA table
6132 * \param marshal_spec a pointer to the marshal spec that may have been defined for the field in a \c FieldMarshal table.
6134 * Gather info for field \p index that may have been defined in the \c FieldLayout,
6135 * \c FieldRVA and \c FieldMarshal tables.
6136 * Either of \p offset, \p rva and \p marshal_spec can be NULL if you're not interested
6137 * in the data.
6139 void
6140 mono_metadata_field_info (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
6141 MonoMarshalSpec **marshal_spec)
6143 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, FALSE);
6146 void
6147 mono_metadata_field_info_with_mempool (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
6148 MonoMarshalSpec **marshal_spec)
6150 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, TRUE);
6153 static void
6154 mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
6155 MonoMarshalSpec **marshal_spec, gboolean alloc_from_image)
6157 MonoTableInfo *tdef;
6158 locator_t loc;
6160 loc.idx = index + 1;
6161 if (meta->uncompressed_metadata)
6162 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
6164 if (offset) {
6165 tdef = &meta->tables [MONO_TABLE_FIELDLAYOUT];
6167 loc.col_idx = MONO_FIELD_LAYOUT_FIELD;
6168 loc.t = tdef;
6170 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
6171 *offset = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_LAYOUT_OFFSET);
6172 } else {
6173 *offset = (guint32)-1;
6176 if (rva) {
6177 tdef = &meta->tables [MONO_TABLE_FIELDRVA];
6179 loc.col_idx = MONO_FIELD_RVA_FIELD;
6180 loc.t = tdef;
6182 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
6184 * LAMESPEC: There is no signature, no nothing, just the raw data.
6186 *rva = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_RVA_RVA);
6187 } else {
6188 *rva = 0;
6191 if (marshal_spec) {
6192 const char *p;
6194 if ((p = mono_metadata_get_marshal_info (meta, index, TRUE))) {
6195 *marshal_spec = mono_metadata_parse_marshal_spec_full (alloc_from_image ? meta : NULL, meta, p);
6202 * mono_metadata_get_constant_index:
6203 * \param meta the Image the field is defined in
6204 * \param index the token that may have a row defined in the constants table
6205 * \param hint possible position for the row
6207 * \p token must be a \c FieldDef, \c ParamDef or \c PropertyDef token.
6209 * \returns the index into the \c Constants table or 0 if not found.
6211 guint32
6212 mono_metadata_get_constant_index (MonoImage *meta, guint32 token, guint32 hint)
6214 MonoTableInfo *tdef;
6215 locator_t loc;
6216 guint32 index = mono_metadata_token_index (token);
6218 tdef = &meta->tables [MONO_TABLE_CONSTANT];
6219 index <<= MONO_HASCONSTANT_BITS;
6220 switch (mono_metadata_token_table (token)) {
6221 case MONO_TABLE_FIELD:
6222 index |= MONO_HASCONSTANT_FIEDDEF;
6223 break;
6224 case MONO_TABLE_PARAM:
6225 index |= MONO_HASCONSTANT_PARAM;
6226 break;
6227 case MONO_TABLE_PROPERTY:
6228 index |= MONO_HASCONSTANT_PROPERTY;
6229 break;
6230 default:
6231 g_warning ("Not a valid token for the constant table: 0x%08x", token);
6232 return 0;
6234 loc.idx = index;
6235 loc.col_idx = MONO_CONSTANT_PARENT;
6236 loc.t = tdef;
6238 /* FIXME: Index translation */
6240 if ((hint > 0) && (hint < tdef->rows) && (mono_metadata_decode_row_col (tdef, hint - 1, MONO_CONSTANT_PARENT) == index))
6241 return hint;
6243 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
6244 return loc.result + 1;
6246 return 0;
6250 * mono_metadata_events_from_typedef:
6251 * \param meta metadata context
6252 * \param index 0-based index (in the \c TypeDef table) describing a type
6253 * \returns the 0-based index in the \c Event table for the events in the
6254 * type. The last event that belongs to the type (plus 1) is stored
6255 * in the \p end_idx pointer.
6257 guint32
6258 mono_metadata_events_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
6260 locator_t loc;
6261 guint32 start, end;
6262 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_EVENTMAP];
6264 *end_idx = 0;
6266 if (!tdef->base)
6267 return 0;
6269 loc.t = tdef;
6270 loc.col_idx = MONO_EVENT_MAP_PARENT;
6271 loc.idx = index + 1;
6273 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6274 return 0;
6276 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_EVENT_MAP_EVENTLIST);
6277 if (loc.result + 1 < tdef->rows) {
6278 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_EVENT_MAP_EVENTLIST) - 1;
6279 } else {
6280 end = meta->tables [MONO_TABLE_EVENT].rows;
6283 *end_idx = end;
6284 return start - 1;
6288 * mono_metadata_methods_from_event:
6289 * \param meta metadata context
6290 * \param index 0-based index (in the \c Event table) describing a event
6291 * \returns the 0-based index in the \c MethodDef table for the methods in the
6292 * event. The last method that belongs to the event (plus 1) is stored
6293 * in the \p end_idx pointer.
6295 guint32
6296 mono_metadata_methods_from_event (MonoImage *meta, guint32 index, guint *end_idx)
6298 locator_t loc;
6299 guint start, end;
6300 guint32 cols [MONO_METHOD_SEMA_SIZE];
6301 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
6303 *end_idx = 0;
6304 if (!msemt->base)
6305 return 0;
6307 if (meta->uncompressed_metadata)
6308 index = search_ptr_table (meta, MONO_TABLE_EVENT_POINTER, index + 1) - 1;
6310 loc.t = msemt;
6311 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
6312 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT; /* Method association coded index */
6314 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
6315 return 0;
6317 start = loc.result;
6319 * We may end up in the middle of the rows...
6321 while (start > 0) {
6322 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
6323 start--;
6324 else
6325 break;
6327 end = start + 1;
6328 while (end < msemt->rows) {
6329 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
6330 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
6331 break;
6332 ++end;
6334 *end_idx = end;
6335 return start;
6339 * mono_metadata_properties_from_typedef:
6340 * \param meta metadata context
6341 * \param index 0-based index (in the \c TypeDef table) describing a type
6342 * \returns the 0-based index in the \c Property table for the properties in the
6343 * type. The last property that belongs to the type (plus 1) is stored
6344 * in the \p end_idx pointer.
6346 guint32
6347 mono_metadata_properties_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
6349 locator_t loc;
6350 guint32 start, end;
6351 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_PROPERTYMAP];
6353 *end_idx = 0;
6355 if (!tdef->base)
6356 return 0;
6358 loc.t = tdef;
6359 loc.col_idx = MONO_PROPERTY_MAP_PARENT;
6360 loc.idx = index + 1;
6362 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6363 return 0;
6365 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_PROPERTY_MAP_PROPERTY_LIST);
6366 if (loc.result + 1 < tdef->rows) {
6367 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_PROPERTY_MAP_PROPERTY_LIST) - 1;
6368 } else {
6369 end = meta->tables [MONO_TABLE_PROPERTY].rows;
6372 *end_idx = end;
6373 return start - 1;
6377 * mono_metadata_methods_from_property:
6378 * \param meta metadata context
6379 * \param index 0-based index (in the \c PropertyDef table) describing a property
6380 * \returns the 0-based index in the \c MethodDef table for the methods in the
6381 * property. The last method that belongs to the property (plus 1) is stored
6382 * in the \p end_idx pointer.
6384 guint32
6385 mono_metadata_methods_from_property (MonoImage *meta, guint32 index, guint *end_idx)
6387 locator_t loc;
6388 guint start, end;
6389 guint32 cols [MONO_METHOD_SEMA_SIZE];
6390 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
6392 *end_idx = 0;
6393 if (!msemt->base)
6394 return 0;
6396 if (meta->uncompressed_metadata)
6397 index = search_ptr_table (meta, MONO_TABLE_PROPERTY_POINTER, index + 1) - 1;
6399 loc.t = msemt;
6400 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
6401 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY; /* Method association coded index */
6403 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
6404 return 0;
6406 start = loc.result;
6408 * We may end up in the middle of the rows...
6410 while (start > 0) {
6411 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
6412 start--;
6413 else
6414 break;
6416 end = start + 1;
6417 while (end < msemt->rows) {
6418 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
6419 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
6420 break;
6421 ++end;
6423 *end_idx = end;
6424 return start;
6428 * mono_metadata_implmap_from_method:
6430 guint32
6431 mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx)
6433 locator_t loc;
6434 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_IMPLMAP];
6436 if (!tdef->base)
6437 return 0;
6439 /* No index translation seems to be needed */
6441 loc.t = tdef;
6442 loc.col_idx = MONO_IMPLMAP_MEMBER;
6443 loc.idx = ((method_idx + 1) << MONO_MEMBERFORWD_BITS) | MONO_MEMBERFORWD_METHODDEF;
6445 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6446 return 0;
6448 return loc.result + 1;
6452 * mono_type_create_from_typespec:
6453 * \param image context where the image is created
6454 * \param type_spec typespec token
6455 * \deprecated use \c mono_type_create_from_typespec_checked that has proper error handling
6457 * Creates a \c MonoType representing the \c TypeSpec indexed by the \p type_spec
6458 * token.
6460 MonoType *
6461 mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
6463 ERROR_DECL (error);
6464 MonoType *type = mono_type_create_from_typespec_checked (image, type_spec, error);
6465 if (!type)
6466 g_error ("Could not create typespec %x due to %s", type_spec, mono_error_get_message (error));
6467 return type;
6470 MonoType *
6471 mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, MonoError *error)
6474 guint32 idx = mono_metadata_token_index (type_spec);
6475 MonoTableInfo *t;
6476 guint32 cols [MONO_TYPESPEC_SIZE];
6477 const char *ptr;
6478 MonoType *type, *type2;
6480 error_init (error);
6482 type = (MonoType *)mono_conc_hashtable_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
6483 if (type)
6484 return type;
6486 t = &image->tables [MONO_TABLE_TYPESPEC];
6488 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
6489 ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
6491 if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, error))
6492 return NULL;
6494 mono_metadata_decode_value (ptr, &ptr);
6496 type = mono_metadata_parse_type_checked (image, NULL, 0, TRUE, ptr, &ptr, error);
6497 if (!type)
6498 return NULL;
6500 type2 = mono_metadata_type_dup (image, type);
6501 mono_metadata_free_type (type);
6503 mono_image_lock (image);
6505 /* We might leak some data in the image mempool if found */
6506 type = (MonoType*)mono_conc_hashtable_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
6507 if (!type)
6508 type = type2;
6510 mono_image_unlock (image);
6512 return type;
6516 static char*
6517 mono_image_strndup (MonoImage *image, const char *data, guint len)
6519 char *res;
6520 if (!image)
6521 return g_strndup (data, len);
6522 res = (char *)mono_image_alloc (image, len + 1);
6523 memcpy (res, data, len);
6524 res [len] = 0;
6525 return res;
6529 * mono_metadata_parse_marshal_spec:
6531 MonoMarshalSpec *
6532 mono_metadata_parse_marshal_spec (MonoImage *image, const char *ptr)
6534 return mono_metadata_parse_marshal_spec_full (NULL, image, ptr);
6538 * If IMAGE is non-null, memory will be allocated from its mempool, otherwise it will be allocated using malloc.
6539 * PARENT_IMAGE is the image containing the marshal spec.
6541 MonoMarshalSpec *
6542 mono_metadata_parse_marshal_spec_full (MonoImage *image, MonoImage *parent_image, const char *ptr)
6544 MonoMarshalSpec *res;
6545 int len;
6546 const char *start = ptr;
6548 /* fixme: this is incomplete, but I cant find more infos in the specs */
6550 if (image)
6551 res = (MonoMarshalSpec *)mono_image_alloc0 (image, sizeof (MonoMarshalSpec));
6552 else
6553 res = g_new0 (MonoMarshalSpec, 1);
6555 len = mono_metadata_decode_value (ptr, &ptr);
6556 res->native = (MonoMarshalNative)*ptr++;
6558 if (res->native == MONO_NATIVE_LPARRAY) {
6559 res->data.array_data.param_num = -1;
6560 res->data.array_data.num_elem = -1;
6561 res->data.array_data.elem_mult = -1;
6563 if (ptr - start <= len)
6564 res->data.array_data.elem_type = (MonoMarshalNative)*ptr++;
6565 if (ptr - start <= len)
6566 res->data.array_data.param_num = mono_metadata_decode_value (ptr, &ptr);
6567 if (ptr - start <= len)
6568 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6569 if (ptr - start <= len) {
6571 * LAMESPEC: Older spec versions say this parameter comes before
6572 * num_elem. Never spec versions don't talk about elem_mult at
6573 * all, but csc still emits it, and it is used to distinguish
6574 * between param_num being 0, and param_num being omitted.
6575 * So if (param_num == 0) && (num_elem > 0), then
6576 * elem_mult == 0 -> the array size is num_elem
6577 * elem_mult == 1 -> the array size is @param_num + num_elem
6579 res->data.array_data.elem_mult = mono_metadata_decode_value (ptr, &ptr);
6583 if (res->native == MONO_NATIVE_BYVALTSTR) {
6584 if (ptr - start <= len)
6585 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6588 if (res->native == MONO_NATIVE_BYVALARRAY) {
6589 if (ptr - start <= len)
6590 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6593 if (res->native == MONO_NATIVE_CUSTOM) {
6594 /* skip unused type guid */
6595 len = mono_metadata_decode_value (ptr, &ptr);
6596 ptr += len;
6597 /* skip unused native type name */
6598 len = mono_metadata_decode_value (ptr, &ptr);
6599 ptr += len;
6600 /* read custom marshaler type name */
6601 len = mono_metadata_decode_value (ptr, &ptr);
6602 res->data.custom_data.custom_name = mono_image_strndup (image, ptr, len);
6603 ptr += len;
6604 /* read cookie string */
6605 len = mono_metadata_decode_value (ptr, &ptr);
6606 res->data.custom_data.cookie = mono_image_strndup (image, ptr, len);
6607 res->data.custom_data.image = parent_image;
6610 if (res->native == MONO_NATIVE_SAFEARRAY) {
6611 res->data.safearray_data.elem_type = (MonoMarshalVariant)0;
6612 res->data.safearray_data.num_elem = 0;
6613 if (ptr - start <= len)
6614 res->data.safearray_data.elem_type = (MonoMarshalVariant)*ptr++;
6615 if (ptr - start <= len)
6616 res->data.safearray_data.num_elem = *ptr++;
6618 return res;
6622 * mono_metadata_free_marshal_spec:
6624 void
6625 mono_metadata_free_marshal_spec (MonoMarshalSpec *spec)
6627 if (!spec)
6628 return;
6630 if (spec->native == MONO_NATIVE_CUSTOM) {
6631 g_free (spec->data.custom_data.custom_name);
6632 g_free (spec->data.custom_data.cookie);
6634 g_free (spec);
6638 * mono_type_to_unmanaged:
6639 * The value pointed to by \p conv will contain the kind of marshalling required for this
6640 * particular type one of the \c MONO_MARSHAL_CONV_ enumeration values.
6641 * \returns A \c MonoMarshalNative enumeration value (<code>MONO_NATIVE_</code>) value
6642 * describing the underlying native reprensetation of the type.
6644 guint32 // FIXMEcxx MonoMarshalNative
6645 mono_type_to_unmanaged (MonoType *type, MonoMarshalSpec *mspec, gboolean as_field,
6646 gboolean unicode, MonoMarshalConv *conv)
6648 MonoMarshalConv dummy_conv;
6649 int t = type->type;
6651 if (!conv)
6652 conv = &dummy_conv;
6654 *conv = MONO_MARSHAL_CONV_NONE;
6656 if (type->byref)
6657 return MONO_NATIVE_UINT;
6659 handle_enum:
6660 switch (t) {
6661 case MONO_TYPE_BOOLEAN:
6662 if (mspec) {
6663 switch (mspec->native) {
6664 case MONO_NATIVE_VARIANTBOOL:
6665 *conv = MONO_MARSHAL_CONV_BOOL_VARIANTBOOL;
6666 return MONO_NATIVE_VARIANTBOOL;
6667 case MONO_NATIVE_BOOLEAN:
6668 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6669 return MONO_NATIVE_BOOLEAN;
6670 case MONO_NATIVE_I1:
6671 case MONO_NATIVE_U1:
6672 return mspec->native;
6673 default:
6674 g_error ("cant marshal bool to native type %02x", mspec->native);
6677 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6678 return MONO_NATIVE_BOOLEAN;
6679 case MONO_TYPE_CHAR:
6680 if (mspec) {
6681 switch (mspec->native) {
6682 case MONO_NATIVE_U2:
6683 case MONO_NATIVE_U1:
6684 return mspec->native;
6685 default:
6686 g_error ("cant marshal char to native type %02x", mspec->native);
6689 return unicode ? MONO_NATIVE_U2 : MONO_NATIVE_U1;
6690 case MONO_TYPE_I1: return MONO_NATIVE_I1;
6691 case MONO_TYPE_U1: return MONO_NATIVE_U1;
6692 case MONO_TYPE_I2: return MONO_NATIVE_I2;
6693 case MONO_TYPE_U2: return MONO_NATIVE_U2;
6694 case MONO_TYPE_I4: return MONO_NATIVE_I4;
6695 case MONO_TYPE_U4: return MONO_NATIVE_U4;
6696 case MONO_TYPE_I8: return MONO_NATIVE_I8;
6697 case MONO_TYPE_U8: return MONO_NATIVE_U8;
6698 case MONO_TYPE_R4: return MONO_NATIVE_R4;
6699 case MONO_TYPE_R8: return MONO_NATIVE_R8;
6700 case MONO_TYPE_STRING:
6701 if (mspec) {
6702 switch (mspec->native) {
6703 case MONO_NATIVE_BSTR:
6704 *conv = MONO_MARSHAL_CONV_STR_BSTR;
6705 return MONO_NATIVE_BSTR;
6706 case MONO_NATIVE_LPSTR:
6707 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6708 return MONO_NATIVE_LPSTR;
6709 case MONO_NATIVE_LPWSTR:
6710 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6711 return MONO_NATIVE_LPWSTR;
6712 case MONO_NATIVE_LPTSTR:
6713 *conv = MONO_MARSHAL_CONV_STR_LPTSTR;
6714 return MONO_NATIVE_LPTSTR;
6715 case MONO_NATIVE_ANSIBSTR:
6716 *conv = MONO_MARSHAL_CONV_STR_ANSIBSTR;
6717 return MONO_NATIVE_ANSIBSTR;
6718 case MONO_NATIVE_TBSTR:
6719 *conv = MONO_MARSHAL_CONV_STR_TBSTR;
6720 return MONO_NATIVE_TBSTR;
6721 case MONO_NATIVE_UTF8STR:
6722 *conv = MONO_MARSHAL_CONV_STR_UTF8STR;
6723 return MONO_NATIVE_UTF8STR;
6724 case MONO_NATIVE_BYVALTSTR:
6725 if (unicode)
6726 *conv = MONO_MARSHAL_CONV_STR_BYVALWSTR;
6727 else
6728 *conv = MONO_MARSHAL_CONV_STR_BYVALSTR;
6729 return MONO_NATIVE_BYVALTSTR;
6730 default:
6731 g_error ("Can not marshal string to native type '%02x': Invalid managed/unmanaged type combination (String fields must be paired with LPStr, LPWStr, BStr or ByValTStr).", mspec->native);
6734 if (unicode) {
6735 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6736 return MONO_NATIVE_LPWSTR;
6738 else {
6739 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6740 return MONO_NATIVE_LPSTR;
6742 case MONO_TYPE_PTR: return MONO_NATIVE_UINT;
6743 case MONO_TYPE_VALUETYPE: /*FIXME*/
6744 if (m_class_is_enumtype (type->data.klass)) {
6745 t = mono_class_enum_basetype_internal (type->data.klass)->type;
6746 goto handle_enum;
6748 if (type->data.klass == mono_class_try_get_handleref_class ()){
6749 *conv = MONO_MARSHAL_CONV_HANDLEREF;
6750 return MONO_NATIVE_INT;
6752 return MONO_NATIVE_STRUCT;
6753 case MONO_TYPE_SZARRAY:
6754 case MONO_TYPE_ARRAY:
6755 if (mspec) {
6756 switch (mspec->native) {
6757 case MONO_NATIVE_BYVALARRAY:
6758 if ((m_class_get_element_class (type->data.klass) == mono_defaults.char_class) && !unicode)
6759 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY;
6760 else
6761 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALARRAY;
6762 return MONO_NATIVE_BYVALARRAY;
6763 case MONO_NATIVE_SAFEARRAY:
6764 *conv = MONO_MARSHAL_CONV_ARRAY_SAVEARRAY;
6765 return MONO_NATIVE_SAFEARRAY;
6766 case MONO_NATIVE_LPARRAY:
6767 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6768 return MONO_NATIVE_LPARRAY;
6769 default:
6770 g_error ("cant marshal array as native type %02x", mspec->native);
6774 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6775 return MONO_NATIVE_LPARRAY;
6776 case MONO_TYPE_I: return MONO_NATIVE_INT;
6777 case MONO_TYPE_U: return MONO_NATIVE_UINT;
6778 case MONO_TYPE_CLASS:
6779 case MONO_TYPE_OBJECT: {
6780 /* FIXME : we need to handle ArrayList and StringBuilder here, probably */
6781 if (mspec) {
6782 switch (mspec->native) {
6783 case MONO_NATIVE_STRUCT:
6784 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6785 return MONO_NATIVE_STRUCT;
6786 case MONO_NATIVE_CUSTOM:
6787 return MONO_NATIVE_CUSTOM;
6788 case MONO_NATIVE_INTERFACE:
6789 *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
6790 return MONO_NATIVE_INTERFACE;
6791 case MONO_NATIVE_IDISPATCH:
6792 *conv = MONO_MARSHAL_CONV_OBJECT_IDISPATCH;
6793 return MONO_NATIVE_IDISPATCH;
6794 case MONO_NATIVE_IUNKNOWN:
6795 *conv = MONO_MARSHAL_CONV_OBJECT_IUNKNOWN;
6796 return MONO_NATIVE_IUNKNOWN;
6797 case MONO_NATIVE_FUNC:
6798 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6799 type->data.klass == mono_defaults.delegate_class ||
6800 m_class_get_parent (type->data.klass) == mono_defaults.multicastdelegate_class)) {
6801 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6802 return MONO_NATIVE_FUNC;
6804 /* Fall through */
6805 default:
6806 g_error ("cant marshal object as native type %02x", mspec->native);
6809 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6810 type->data.klass == mono_defaults.delegate_class ||
6811 m_class_get_parent (type->data.klass) == mono_defaults.multicastdelegate_class)) {
6812 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6813 return MONO_NATIVE_FUNC;
6815 if (mono_class_try_get_safehandle_class () && type->data.klass != NULL &&
6816 mono_class_is_subclass_of_internal (type->data.klass, mono_class_try_get_safehandle_class (), FALSE)){
6817 *conv = MONO_MARSHAL_CONV_SAFEHANDLE;
6818 return MONO_NATIVE_INT;
6820 #ifndef DISABLE_COM
6821 if (t == MONO_TYPE_CLASS && mono_cominterop_is_interface (type->data.klass)){
6822 *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
6823 return MONO_NATIVE_INTERFACE;
6825 #endif
6826 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6827 return MONO_NATIVE_STRUCT;
6829 case MONO_TYPE_FNPTR: return MONO_NATIVE_FUNC;
6830 case MONO_TYPE_GENERICINST:
6831 type = m_class_get_byval_arg (type->data.generic_class->container_class);
6832 t = type->type;
6833 goto handle_enum;
6834 case MONO_TYPE_TYPEDBYREF:
6835 default:
6836 g_error ("type 0x%02x not handled in marshal", t);
6838 return MONO_NATIVE_MAX;
6842 * mono_metadata_get_marshal_info:
6844 const char*
6845 mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field)
6847 locator_t loc;
6848 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_FIELDMARSHAL];
6850 if (!tdef->base)
6851 return NULL;
6853 loc.t = tdef;
6854 loc.col_idx = MONO_FIELD_MARSHAL_PARENT;
6855 loc.idx = ((idx + 1) << MONO_HAS_FIELD_MARSHAL_BITS) | (is_field? MONO_HAS_FIELD_MARSHAL_FIELDSREF: MONO_HAS_FIELD_MARSHAL_PARAMDEF);
6857 /* FIXME: Index translation */
6859 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6860 return NULL;
6862 return mono_metadata_blob_heap (meta, mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_MARSHAL_NATIVE_TYPE));
6865 MonoMethod*
6866 mono_method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context, MonoError *error)
6868 MonoMethod *result = NULL;
6869 guint32 idx = tok >> MONO_METHODDEFORREF_BITS;
6871 error_init (error);
6873 switch (tok & MONO_METHODDEFORREF_MASK) {
6874 case MONO_METHODDEFORREF_METHODDEF:
6875 result = mono_get_method_checked (m, MONO_TOKEN_METHOD_DEF | idx, NULL, context, error);
6876 break;
6877 case MONO_METHODDEFORREF_METHODREF:
6878 result = mono_get_method_checked (m, MONO_TOKEN_MEMBER_REF | idx, NULL, context, error);
6879 break;
6880 default:
6881 mono_error_set_bad_image (error, m, "Invalid MethodDefOfRef token %x", tok);
6884 return result;
6888 * mono_class_get_overrides_full:
6890 * Compute the method overrides belonging to class @type_token in @overrides, and the number of overrides in @num_overrides.
6893 void
6894 mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides, MonoGenericContext *generic_context, MonoError *error)
6896 locator_t loc;
6897 MonoTableInfo *tdef = &image->tables [MONO_TABLE_METHODIMPL];
6898 guint32 start, end;
6899 gint32 i, num;
6900 guint32 cols [MONO_METHODIMPL_SIZE];
6901 MonoMethod **result;
6903 error_init (error);
6905 *overrides = NULL;
6906 if (num_overrides)
6907 *num_overrides = 0;
6909 if (!tdef->base)
6910 return;
6912 loc.t = tdef;
6913 loc.col_idx = MONO_METHODIMPL_CLASS;
6914 loc.idx = mono_metadata_token_index (type_token);
6916 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6917 return;
6919 start = loc.result;
6920 end = start + 1;
6922 * We may end up in the middle of the rows...
6924 while (start > 0) {
6925 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_METHODIMPL_CLASS))
6926 start--;
6927 else
6928 break;
6930 while (end < tdef->rows) {
6931 if (loc.idx == mono_metadata_decode_row_col (tdef, end, MONO_METHODIMPL_CLASS))
6932 end++;
6933 else
6934 break;
6936 num = end - start;
6937 result = g_new (MonoMethod*, num * 2);
6938 for (i = 0; i < num; ++i) {
6939 MonoMethod *method;
6941 if (!mono_verifier_verify_methodimpl_row (image, start + i, error))
6942 break;
6944 mono_metadata_decode_row (tdef, start + i, cols, MONO_METHODIMPL_SIZE);
6945 method = mono_method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_DECLARATION], generic_context, error);
6946 if (!method)
6947 break;
6949 result [i * 2] = method;
6950 method = mono_method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_BODY], generic_context, error);
6951 if (!method)
6952 break;
6954 result [i * 2 + 1] = method;
6957 if (!is_ok (error)) {
6958 g_free (result);
6959 *overrides = NULL;
6960 if (num_overrides)
6961 *num_overrides = 0;
6962 } else {
6963 *overrides = result;
6964 if (num_overrides)
6965 *num_overrides = num;
6970 * mono_guid_to_string:
6972 * Converts a 16 byte Microsoft GUID to the standard string representation.
6974 char *
6975 mono_guid_to_string (const guint8 *guid)
6977 return g_strdup_printf ("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
6978 guid[3], guid[2], guid[1], guid[0],
6979 guid[5], guid[4],
6980 guid[7], guid[6],
6981 guid[8], guid[9],
6982 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
6986 * mono_guid_to_string_minimal:
6988 * Converts a 16 byte Microsoft GUID to lower case no '-' representation..
6990 char *
6991 mono_guid_to_string_minimal (const guint8 *guid)
6993 return g_strdup_printf ("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
6994 guid[3], guid[2], guid[1], guid[0],
6995 guid[5], guid[4],
6996 guid[7], guid[6],
6997 guid[8], guid[9],
6998 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
7000 static gboolean
7001 get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGenericContainer *container, MonoError *error)
7003 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
7004 guint32 cols [MONO_GENPARCONSTRAINT_SIZE];
7005 guint32 i, token, found;
7006 MonoClass *klass, **res;
7007 GSList *cons = NULL, *tmp;
7008 MonoGenericContext *context = &container->context;
7010 error_init (error);
7012 *constraints = NULL;
7013 found = 0;
7014 for (i = 0; i < tdef->rows; ++i) {
7015 mono_metadata_decode_row (tdef, i, cols, MONO_GENPARCONSTRAINT_SIZE);
7016 if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) {
7017 token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]);
7018 klass = mono_class_get_and_inflate_typespec_checked (image, token, context, error);
7019 if (!klass) {
7020 g_slist_free (cons);
7021 return FALSE;
7023 cons = g_slist_append (cons, klass);
7024 ++found;
7025 } else {
7026 /* contiguous list finished */
7027 if (found)
7028 break;
7031 if (!found)
7032 return TRUE;
7033 res = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * (found + 1));
7034 for (i = 0, tmp = cons; i < found; ++i, tmp = tmp->next) {
7035 res [i] = (MonoClass *)tmp->data;
7037 g_slist_free (cons);
7038 *constraints = res;
7039 return TRUE;
7043 * mono_metadata_get_generic_param_row:
7045 * @image:
7046 * @token: TypeOrMethodDef token, owner for GenericParam
7047 * @owner: coded token, set on return
7049 * Returns: 1-based row-id in the GenericParam table whose
7050 * owner is @token. 0 if not found.
7052 guint32
7053 mono_metadata_get_generic_param_row (MonoImage *image, guint32 token, guint32 *owner)
7055 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
7056 locator_t loc;
7058 g_assert (owner);
7059 if (!tdef->base)
7060 return 0;
7062 if (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
7063 *owner = MONO_TYPEORMETHOD_TYPE;
7064 else if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
7065 *owner = MONO_TYPEORMETHOD_METHOD;
7066 else {
7067 g_error ("wrong token %x to get_generic_param_row", token);
7068 return 0;
7070 *owner |= mono_metadata_token_index (token) << MONO_TYPEORMETHOD_BITS;
7072 loc.idx = *owner;
7073 loc.col_idx = MONO_GENERICPARAM_OWNER;
7074 loc.t = tdef;
7076 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
7077 return 0;
7079 /* Find the first entry by searching backwards */
7080 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_GENERICPARAM_OWNER) == loc.idx))
7081 loc.result --;
7083 return loc.result + 1;
7086 gboolean
7087 mono_metadata_has_generic_params (MonoImage *image, guint32 token)
7089 guint32 owner;
7090 return mono_metadata_get_generic_param_row (image, token, &owner);
7094 * Memory is allocated from IMAGE's mempool.
7096 gboolean
7097 mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token,
7098 MonoGenericContainer *container, MonoError *error)
7101 guint32 start_row, i, owner;
7102 error_init (error);
7104 if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner)))
7105 return TRUE;
7106 for (i = 0; i < container->type_argc; i++) {
7107 if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container, error)) {
7108 return FALSE;
7111 return TRUE;
7115 * mono_metadata_load_generic_params:
7117 * Load the type parameters from the type or method definition @token.
7119 * Use this method after parsing a type or method definition to figure out whether it's a generic
7120 * type / method. When parsing a method definition, @parent_container points to the generic container
7121 * of the current class, if any.
7123 * Note: This method does not load the constraints: for typedefs, this has to be done after fully
7124 * creating the type.
7126 * Returns: NULL if @token is not a generic type or method definition or the new generic container.
7128 * LOCKING: Acquires the loader lock
7131 MonoGenericContainer *
7132 mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericContainer *parent_container, gpointer real_owner)
7134 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
7135 guint32 cols [MONO_GENERICPARAM_SIZE];
7136 guint32 i, owner = 0, n;
7137 MonoGenericContainer *container;
7138 MonoGenericParamFull *params;
7139 MonoGenericContext *context;
7140 gboolean is_method = mono_metadata_token_table (token) == MONO_TABLE_METHOD;
7141 gboolean is_anonymous = real_owner == NULL;
7143 if (!(i = mono_metadata_get_generic_param_row (image, token, &owner)))
7144 return NULL;
7145 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
7146 params = NULL;
7147 n = 0;
7148 container = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
7149 container->is_anonymous = is_anonymous;
7150 if (is_anonymous) {
7151 container->owner.image = image;
7152 } else {
7153 if (is_method)
7154 container->owner.method = (MonoMethod*)real_owner;
7155 else
7156 container->owner.klass = (MonoClass*)real_owner;
7158 do {
7159 n++;
7160 params = (MonoGenericParamFull *)g_realloc (params, sizeof (MonoGenericParamFull) * n);
7161 memset (&params [n - 1], 0, sizeof (MonoGenericParamFull));
7162 params [n - 1].owner = container;
7163 params [n - 1].num = cols [MONO_GENERICPARAM_NUMBER];
7164 params [n - 1].info.token = i | MONO_TOKEN_GENERIC_PARAM;
7165 params [n - 1].info.flags = cols [MONO_GENERICPARAM_FLAGS];
7166 params [n - 1].info.name = mono_metadata_string_heap (image, cols [MONO_GENERICPARAM_NAME]);
7167 if (params [n - 1].num != n - 1)
7168 g_warning ("GenericParam table unsorted or hole in generic param sequence: token %d", i);
7169 if (++i > tdef->rows)
7170 break;
7171 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
7172 } while (cols [MONO_GENERICPARAM_OWNER] == owner);
7174 container->type_argc = n;
7175 container->type_params = (MonoGenericParamFull *)mono_image_alloc0 (image, sizeof (MonoGenericParamFull) * n);
7176 memcpy (container->type_params, params, sizeof (MonoGenericParamFull) * n);
7177 g_free (params);
7178 container->parent = parent_container;
7180 if (is_method)
7181 container->is_method = 1;
7183 g_assert (container->parent == NULL || container->is_method);
7185 context = &container->context;
7186 if (container->is_method) {
7187 context->class_inst = container->parent ? container->parent->context.class_inst : NULL;
7188 context->method_inst = mono_get_shared_generic_inst (container);
7189 } else {
7190 context->class_inst = mono_get_shared_generic_inst (container);
7193 return container;
7196 MonoGenericInst *
7197 mono_get_shared_generic_inst (MonoGenericContainer *container)
7199 MonoType **type_argv;
7200 MonoType *helper;
7201 MonoGenericInst *nginst;
7202 int i;
7204 type_argv = g_new0 (MonoType *, container->type_argc);
7205 helper = g_new0 (MonoType, container->type_argc);
7207 for (i = 0; i < container->type_argc; i++) {
7208 MonoType *t = &helper [i];
7210 t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
7211 t->data.generic_param = mono_generic_container_get_param (container, i);
7213 type_argv [i] = t;
7216 nginst = mono_metadata_get_generic_inst (container->type_argc, type_argv);
7218 g_free (type_argv);
7219 g_free (helper);
7221 return nginst;
7225 * mono_type_is_byref:
7226 * \param type the \c MonoType operated on
7227 * \returns TRUE if \p type represents a type passed by reference,
7228 * FALSE otherwise.
7230 mono_bool
7231 mono_type_is_byref (MonoType *type)
7233 mono_bool result;
7234 MONO_ENTER_GC_UNSAFE; // FIXME slow
7235 result = mono_type_is_byref_internal (type);
7236 MONO_EXIT_GC_UNSAFE;
7237 return result;
7241 * mono_type_get_type:
7242 * \param type the \c MonoType operated on
7243 * \returns the IL type value for \p type. This is one of the \c MonoTypeEnum
7244 * enum members like \c MONO_TYPE_I4 or \c MONO_TYPE_STRING.
7247 mono_type_get_type (MonoType *type)
7249 return mono_type_get_type_internal (type);
7253 * mono_type_get_signature:
7254 * \param type the \c MonoType operated on
7255 * It is only valid to call this function if \p type is a \c MONO_TYPE_FNPTR .
7256 * \returns the \c MonoMethodSignature pointer that describes the signature
7257 * of the function pointer \p type represents.
7259 MonoMethodSignature*
7260 mono_type_get_signature (MonoType *type)
7262 return mono_type_get_signature_internal (type);
7266 * mono_type_get_class:
7267 * \param type the \c MonoType operated on
7268 * It is only valid to call this function if \p type is a \c MONO_TYPE_CLASS or a
7269 * \c MONO_TYPE_VALUETYPE . For more general functionality, use \c mono_class_from_mono_type_internal,
7270 * instead.
7271 * \returns the \c MonoClass pointer that describes the class that \p type represents.
7273 MonoClass*
7274 mono_type_get_class (MonoType *type)
7276 /* FIXME: review the runtime users before adding the assert here */
7277 return mono_type_get_class_internal (type);
7281 * mono_type_get_array_type:
7282 * \param type the \c MonoType operated on
7283 * It is only valid to call this function if \p type is a \c MONO_TYPE_ARRAY .
7284 * \returns a \c MonoArrayType struct describing the array type that \p type
7285 * represents. The info includes details such as rank, array element type
7286 * and the sizes and bounds of multidimensional arrays.
7288 MonoArrayType*
7289 mono_type_get_array_type (MonoType *type)
7291 return mono_type_get_array_type_internal (type);
7295 * mono_type_get_ptr_type:
7296 * \pararm type the \c MonoType operated on
7297 * It is only valid to call this function if \p type is a \c MONO_TYPE_PTR .
7298 * \returns the \c MonoType pointer that describes the type that \p type
7299 * represents a pointer to.
7301 MonoType*
7302 mono_type_get_ptr_type (MonoType *type)
7304 g_assert (type->type == MONO_TYPE_PTR);
7305 return type->data.type;
7309 * mono_type_get_modifiers:
7311 MonoClass*
7312 mono_type_get_modifiers (MonoType *type, gboolean *is_required, gpointer *iter)
7314 /* FIXME: implement */
7315 return NULL;
7319 * mono_type_is_struct:
7320 * \param type the \c MonoType operated on
7321 * \returns TRUE if \p type is a struct, that is a \c ValueType but not an enum
7322 * or a basic type like \c System.Int32 . FALSE otherwise.
7324 mono_bool
7325 mono_type_is_struct (MonoType *type)
7327 return (!type->byref && ((type->type == MONO_TYPE_VALUETYPE &&
7328 !m_class_is_enumtype (type->data.klass)) || (type->type == MONO_TYPE_TYPEDBYREF) ||
7329 ((type->type == MONO_TYPE_GENERICINST) &&
7330 mono_metadata_generic_class_is_valuetype (type->data.generic_class) &&
7331 !m_class_is_enumtype (type->data.generic_class->container_class))));
7335 * mono_type_is_void:
7336 * \param type the \c MonoType operated on
7337 * \returns TRUE if \p type is \c System.Void . FALSE otherwise.
7339 mono_bool
7340 mono_type_is_void (MonoType *type)
7342 return (type && (type->type == MONO_TYPE_VOID) && !type->byref);
7346 * mono_type_is_pointer:
7347 * \param type the \c MonoType operated on
7348 * \returns TRUE if \p type is a managed or unmanaged pointer type. FALSE otherwise.
7350 mono_bool
7351 mono_type_is_pointer (MonoType *type)
7353 return (type && ((type->byref || (type->type == MONO_TYPE_I) || type->type == MONO_TYPE_STRING)
7354 || (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
7355 (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_OBJECT) ||
7356 (type->type == MONO_TYPE_ARRAY) || (type->type == MONO_TYPE_PTR) ||
7357 (type->type == MONO_TYPE_FNPTR)));
7361 * mono_type_is_reference:
7362 * \param type the \c MonoType operated on
7363 * \returns TRUE if \p type represents an object reference. FALSE otherwise.
7365 mono_bool
7366 mono_type_is_reference (MonoType *type)
7368 /* NOTE: changing this function to return TRUE more often may have
7369 * consequences for generic sharing in the AOT compiler. In
7370 * particular, returning TRUE for generic parameters with a 'class'
7371 * constraint may cause crashes.
7373 return (type && (((type->type == MONO_TYPE_STRING) ||
7374 (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
7375 (type->type == MONO_TYPE_OBJECT) || (type->type == MONO_TYPE_ARRAY)) ||
7376 ((type->type == MONO_TYPE_GENERICINST) &&
7377 !mono_metadata_generic_class_is_valuetype (type->data.generic_class))));
7380 mono_bool
7381 mono_type_is_generic_parameter (MonoType *type)
7383 return !type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR);
7387 * mono_signature_get_return_type:
7388 * \param sig the method signature inspected
7389 * \returns the return type of the method signature \p sig
7391 MonoType*
7392 mono_signature_get_return_type (MonoMethodSignature *sig)
7394 MonoType *result;
7395 MONO_ENTER_GC_UNSAFE;
7396 result = sig->ret;
7397 MONO_EXIT_GC_UNSAFE;
7398 return result;
7402 * mono_signature_get_params:
7403 * \param sig the method signature inspected
7404 * \param iter pointer to an iterator
7405 * Iterates over the parameters for the method signature \p sig.
7406 * A \c void* pointer must be initialized to NULL to start the iteration
7407 * and its address is passed to this function repeteadly until it returns
7408 * NULL.
7409 * \returns the next parameter type of the method signature \p sig,
7410 * NULL when finished.
7412 MonoType*
7413 mono_signature_get_params (MonoMethodSignature *sig, gpointer *iter)
7415 MonoType *result;
7416 MONO_ENTER_GC_UNSAFE;
7417 result = mono_signature_get_params_internal (sig, iter);
7418 MONO_EXIT_GC_UNSAFE;
7419 return result;
7422 MonoType*
7423 mono_signature_get_params_internal (MonoMethodSignature *sig, gpointer *iter)
7425 MonoType** type;
7426 if (!iter)
7427 return NULL;
7428 if (!*iter) {
7429 /* start from the first */
7430 if (sig->param_count) {
7431 *iter = &sig->params [0];
7432 return sig->params [0];
7433 } else {
7434 /* no method */
7435 return NULL;
7438 type = (MonoType **)*iter;
7439 type++;
7440 if (type < &sig->params [sig->param_count]) {
7441 *iter = type;
7442 return *type;
7444 return NULL;
7448 * mono_signature_get_param_count:
7449 * \param sig the method signature inspected
7450 * \returns the number of parameters in the method signature \p sig.
7452 guint32
7453 mono_signature_get_param_count (MonoMethodSignature *sig)
7455 return sig->param_count;
7459 * mono_signature_get_call_conv:
7460 * \param sig the method signature inspected
7461 * \returns the call convention of the method signature \p sig.
7463 guint32
7464 mono_signature_get_call_conv (MonoMethodSignature *sig)
7466 return sig->call_convention;
7470 * mono_signature_vararg_start:
7471 * \param sig the method signature inspected
7472 * \returns the number of the first vararg parameter in the
7473 * method signature \param sig. \c -1 if this is not a vararg signature.
7476 mono_signature_vararg_start (MonoMethodSignature *sig)
7478 return sig->sentinelpos;
7482 * mono_signature_is_instance:
7483 * \param sig the method signature inspected
7484 * \returns TRUE if this the method signature \p sig has an implicit
7485 * first instance argument. FALSE otherwise.
7487 gboolean
7488 mono_signature_is_instance (MonoMethodSignature *sig)
7490 return sig->hasthis;
7494 * mono_signature_param_is_out
7495 * \param sig the method signature inspected
7496 * \param param_num the 0-based index of the inspected parameter
7497 * \returns TRUE if the parameter is an out parameter, FALSE
7498 * otherwise.
7500 mono_bool
7501 mono_signature_param_is_out (MonoMethodSignature *sig, int param_num)
7503 g_assert (param_num >= 0 && param_num < sig->param_count);
7504 return (sig->params [param_num]->attrs & PARAM_ATTRIBUTE_OUT) != 0;
7508 * mono_signature_explicit_this:
7509 * \param sig the method signature inspected
7510 * \returns TRUE if this the method signature \p sig has an explicit
7511 * instance argument. FALSE otherwise.
7513 gboolean
7514 mono_signature_explicit_this (MonoMethodSignature *sig)
7516 return sig->explicit_this;
7519 /* for use with allocated memory blocks (assumes alignment is to 8 bytes) */
7520 guint
7521 mono_aligned_addr_hash (gconstpointer ptr)
7523 /* Same hashing we use for objects */
7524 return (GPOINTER_TO_UINT (ptr) >> 3) * 2654435761u;
7528 * If @field belongs to an inflated generic class, return the corresponding field of the
7529 * generic type definition class.
7531 MonoClassField*
7532 mono_metadata_get_corresponding_field_from_generic_type_definition (MonoClassField *field)
7534 MonoClass *gtd;
7535 int offset;
7537 if (!mono_class_is_ginst (field->parent))
7538 return field;
7540 gtd = mono_class_get_generic_class (field->parent)->container_class;
7541 offset = field - m_class_get_fields (field->parent);
7542 return m_class_get_fields (gtd) + offset;
7546 * If @event belongs to an inflated generic class, return the corresponding event of the
7547 * generic type definition class.
7549 MonoEvent*
7550 mono_metadata_get_corresponding_event_from_generic_type_definition (MonoEvent *event)
7552 MonoClass *gtd;
7553 int offset;
7555 if (!mono_class_is_ginst (event->parent))
7556 return event;
7558 gtd = mono_class_get_generic_class (event->parent)->container_class;
7559 offset = event - mono_class_get_event_info (event->parent)->events;
7560 return mono_class_get_event_info (gtd)->events + offset;
7564 * If @property belongs to an inflated generic class, return the corresponding property of the
7565 * generic type definition class.
7567 MonoProperty*
7568 mono_metadata_get_corresponding_property_from_generic_type_definition (MonoProperty *property)
7570 MonoClassPropertyInfo *info;
7571 MonoClass *gtd;
7572 int offset;
7574 if (!mono_class_is_ginst (property->parent))
7575 return property;
7577 info = mono_class_get_property_info (property->parent);
7578 gtd = mono_class_get_generic_class (property->parent)->container_class;
7579 offset = property - info->properties;
7580 return mono_class_get_property_info (gtd)->properties + offset;
7583 MonoWrapperCaches*
7584 mono_method_get_wrapper_cache (MonoMethod *method)
7586 if (method->is_inflated) {
7587 MonoMethodInflated *imethod = (MonoMethodInflated *)method;
7588 return &imethod->owner->wrapper_caches;
7589 } else {
7590 return &m_class_get_image (method->klass)->wrapper_caches;
7594 // This is support for the mempool reference tracking feature in checked-build, but lives in metadata.c due to use of static variables of this file.
7597 * mono_find_image_set_owner:
7599 * Find the imageset, if any, which a given pointer is located in the memory of.
7601 MonoImageSet *
7602 mono_find_image_set_owner (void *ptr)
7604 MonoImageSet *owner = NULL;
7605 int i;
7607 image_sets_lock ();
7609 if (image_sets)
7611 for (i = 0; !owner && i < image_sets->len; ++i) {
7612 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
7613 if (mono_mempool_contains_addr (set->mempool, ptr))
7614 owner = set;
7618 image_sets_unlock ();
7620 return owner;
7623 void
7624 mono_loader_set_strict_assembly_name_check (gboolean enabled)
7626 check_assembly_names_strictly = enabled;
7629 gboolean
7630 mono_loader_get_strict_assembly_name_check (void)
7632 #if !defined(DISABLE_DESKTOP_LOADER) || defined(ENABLE_NETCORE)
7633 return check_assembly_names_strictly;
7634 #else
7635 return FALSE;
7636 #endif
7640 gboolean
7641 mono_type_is_aggregate_mods (const MonoType *t)
7643 if (!t->has_cmods)
7644 return FALSE;
7646 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7648 return full->is_aggregate;
7651 MonoCustomModContainer *
7652 mono_type_get_cmods (const MonoType *t)
7654 if (!t->has_cmods)
7655 return NULL;
7657 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7659 g_assert (!full->is_aggregate);
7660 return &full->mods.cmods;
7663 MonoAggregateModContainer *
7664 mono_type_get_amods (const MonoType *t)
7666 if (!t->has_cmods)
7667 return NULL;
7669 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7671 g_assert (full->is_aggregate);
7672 return full->mods.amods;
7675 size_t
7676 mono_sizeof_aggregate_modifiers (uint8_t num_mods)
7678 size_t accum = 0;
7679 accum += offsetof (MonoAggregateModContainer, modifiers);
7680 accum += sizeof (MonoSingleCustomMod) * num_mods;
7681 return accum;
7684 size_t
7685 mono_sizeof_type_with_mods (uint8_t num_mods, gboolean is_aggregate)
7687 if (num_mods == 0)
7688 return sizeof (MonoType);
7689 size_t accum = 0;
7690 accum += offsetof (MonoTypeWithModifiers, mods);
7692 if (!is_aggregate) {
7693 accum += offsetof (struct _MonoCustomModContainer, modifiers);
7694 accum += sizeof (MonoCustomMod) * num_mods;
7695 } else {
7696 accum += offsetof (MonoAggregateModContainer, modifiers);
7697 accum += sizeof (MonoAggregateModContainer *);
7699 return accum;
7702 size_t
7703 mono_sizeof_type (const MonoType *ty)
7705 if (ty->has_cmods) {
7706 if (!mono_type_is_aggregate_mods (ty)) {
7707 MonoCustomModContainer *cmods = mono_type_get_cmods (ty);
7708 return mono_sizeof_type_with_mods (cmods->count, FALSE);
7709 } else {
7710 MonoAggregateModContainer *amods = mono_type_get_amods (ty);
7711 return mono_sizeof_type_with_mods (amods->count, TRUE);
7713 } else
7714 return sizeof (MonoType);
7717 void
7718 mono_type_set_amods (MonoType *t, MonoAggregateModContainer *amods)
7720 g_assert (t->has_cmods);
7721 MonoTypeWithModifiers *t_full = (MonoTypeWithModifiers*)t;
7722 g_assert (t_full->is_aggregate);
7723 g_assert (t_full->mods.amods == NULL);
7724 t_full->mods.amods = amods;