[mono] Use `unsigned char` when computing UTF8 string hashes (#21633)
[mono-project.git] / mono / metadata / metadata.c
blob47d3273548e649fd95cf243feaec4375db28c104
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 if (image == mono_get_image_for_generic_param (type->data.generic_param))
2563 return TRUE;
2564 else if (type->data.generic_param->gshared_constraint) {
2565 type = type->data.generic_param->gshared_constraint;
2566 goto retry;
2568 return FALSE;
2569 default:
2570 /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type_internal () */
2571 return image == m_class_get_image (mono_class_from_mono_type_internal (type));
2575 gboolean
2576 mono_type_in_image (MonoType *type, MonoImage *image)
2578 return type_in_image (type, image);
2581 gboolean
2582 aggregate_modifiers_in_image (MonoAggregateModContainer *amods, MonoImage *image)
2584 for (int i = 0; i < amods->count; i++)
2585 if (type_in_image (amods->modifiers [i].type, image))
2586 return TRUE;
2587 return FALSE;
2590 static void
2591 image_sets_lock (void)
2593 mono_os_mutex_lock (&image_sets_mutex);
2596 static void
2597 image_sets_unlock (void)
2599 mono_os_mutex_unlock (&image_sets_mutex);
2602 //1103, 1327, 1597
2603 #define HASH_TABLE_SIZE 1103
2604 static MonoImageSet *img_set_cache [HASH_TABLE_SIZE];
2606 static guint32
2607 mix_hash (uintptr_t source)
2609 unsigned int hash = source;
2611 // Actual hash
2612 hash = (((hash * 215497) >> 16) ^ ((hash * 1823231) + hash));
2614 // Mix in highest bits on 64-bit systems only
2615 if (sizeof (source) > 4)
2616 hash = hash ^ ((source >> 31) >> 1);
2618 return hash;
2621 static guint32
2622 hash_images (MonoImage **images, int nimages)
2624 guint32 res = 0;
2625 int i;
2626 for (i = 0; i < nimages; ++i)
2627 res += mix_hash ((size_t)images [i]);
2629 return res;
2632 static gboolean
2633 compare_img_set (MonoImageSet *set, MonoImage **images, int nimages)
2635 int j, k;
2637 if (set->nimages != nimages)
2638 return FALSE;
2640 for (j = 0; j < nimages; ++j) {
2641 for (k = 0; k < nimages; ++k)
2642 if (set->images [k] == images [j])
2643 break; // Break on match
2645 // If we iterated all the way through set->images, images[j] was *not* found.
2646 if (k == nimages)
2647 break; // Break on "image not found"
2650 // If we iterated all the way through images without breaking, all items in images were found in set->images
2651 return j == nimages;
2655 static MonoImageSet*
2656 img_set_cache_get (MonoImage **images, int nimages)
2658 guint32 hash_code = hash_images (images, nimages);
2659 int index = hash_code % HASH_TABLE_SIZE;
2660 MonoImageSet *img = img_set_cache [index];
2661 if (!img || !compare_img_set (img, images, nimages)) {
2662 UnlockedIncrement (&img_set_cache_miss);
2663 return NULL;
2665 UnlockedIncrement (&img_set_cache_hit);
2666 return img;
2669 static void
2670 img_set_cache_add (MonoImageSet *set)
2672 guint32 hash_code = hash_images (set->images, set->nimages);
2673 int index = hash_code % HASH_TABLE_SIZE;
2674 img_set_cache [index] = set;
2677 static void
2678 img_set_cache_remove (MonoImageSet *is)
2680 guint32 hash_code = hash_images (is->images, is->nimages);
2681 int index = hash_code % HASH_TABLE_SIZE;
2682 if (img_set_cache [index] == is)
2683 img_set_cache [index] = NULL;
2686 * get_image_set:
2688 * Return a MonoImageSet representing the set of images in IMAGES.
2690 static MonoImageSet*
2691 get_image_set (MonoImage **images, int nimages)
2693 int i, j, k;
2694 MonoImageSet *set;
2695 GSList *l;
2697 /* Common case: Image set contains corlib only. If we've seen that case before, we cached the set. */
2698 if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set)
2699 return mscorlib_image_set;
2701 /* Happens with empty generic instances */
2702 // FIXME: Is corlib the correct thing to return here? If so, why? This may be an artifact of generic instances previously defaulting to allocating from corlib.
2703 if (nimages == 0)
2704 return mscorlib_image_set;
2706 set = img_set_cache_get (images, nimages);
2707 if (set)
2708 return set;
2710 image_sets_lock ();
2712 if (!image_sets)
2713 image_sets = g_ptr_array_new ();
2715 // Before we go on, we should check to see whether a MonoImageSet with these images already exists.
2716 // We can search the referred-by imagesets of any one of our images to do this. Arbitrarily pick one here:
2717 if (images [0] == mono_defaults.corlib && nimages > 1)
2718 l = images [1]->image_sets; // Prefer not to search the imagesets of corlib-- that will be a long list.
2719 else
2720 l = images [0]->image_sets;
2722 set = NULL;
2723 while (l) // Iterate over selected list, looking for an imageset with members equal to our target one
2725 set = (MonoImageSet *)l->data;
2727 if (set->nimages == nimages) { // Member count differs, this can't be it
2728 // Compare all members to all members-- order might be different
2729 for (j = 0; j < nimages; ++j) {
2730 for (k = 0; k < nimages; ++k)
2731 if (set->images [k] == images [j])
2732 break; // Break on match
2734 // If we iterated all the way through set->images, images[j] was *not* found.
2735 if (k == nimages)
2736 break; // Break on "image not found"
2739 // If we iterated all the way through images without breaking, all items in images were found in set->images
2740 if (j == nimages) {
2741 // Break on "found a set with equal members".
2742 // This happens in case of a hash collision with a previously cached set.
2743 break;
2747 l = l->next;
2750 // If we iterated all the way through l without breaking, the imageset does not already exist and we should create it
2751 if (!l) {
2752 set = g_new0 (MonoImageSet, 1);
2753 set->nimages = nimages;
2754 set->images = g_new0 (MonoImage*, nimages);
2755 mono_os_mutex_init_recursive (&set->lock);
2756 for (i = 0; i < nimages; ++i)
2757 set->images [i] = images [i];
2758 set->gclass_cache = mono_conc_hashtable_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
2759 set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
2760 set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
2761 set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
2763 set->szarray_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2764 set->array_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2766 set->aggregate_modifiers_cache = g_hash_table_new_full (aggregate_modifiers_hash, aggregate_modifiers_equal, NULL, (GDestroyNotify)free_aggregate_modifiers);
2768 for (i = 0; i < nimages; ++i)
2769 set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set);
2771 g_ptr_array_add (image_sets, set);
2772 UnlockedIncrement (&img_set_count); /* locked by image_sets_lock () */
2775 /* Cache the set. If there was a cache collision, the previously cached value will be replaced. */
2776 img_set_cache_add (set);
2778 if (nimages == 1 && images [0] == mono_defaults.corlib) {
2779 mono_memory_barrier ();
2780 mscorlib_image_set = set;
2783 image_sets_unlock ();
2785 return set;
2788 static void
2789 delete_image_set (MonoImageSet *set)
2791 int i;
2793 mono_conc_hashtable_destroy (set->gclass_cache);
2794 g_hash_table_destroy (set->ginst_cache);
2795 g_hash_table_destroy (set->gmethod_cache);
2796 g_hash_table_destroy (set->gsignature_cache);
2798 g_hash_table_destroy (set->szarray_cache);
2799 g_hash_table_destroy (set->array_cache);
2800 if (set->ptr_cache)
2801 g_hash_table_destroy (set->ptr_cache);
2803 g_hash_table_destroy (set->aggregate_modifiers_cache);
2805 for (i = 0; i < set->gshared_types_len; ++i) {
2806 if (set->gshared_types [i])
2807 g_hash_table_destroy (set->gshared_types [i]);
2809 g_free (set->gshared_types);
2811 mono_wrapper_caches_free (&set->wrapper_caches);
2813 image_sets_lock ();
2815 for (i = 0; i < set->nimages; ++i)
2816 set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set);
2818 g_ptr_array_remove (image_sets, set);
2820 image_sets_unlock ();
2822 img_set_cache_remove (set);
2824 if (set->mempool)
2825 mono_mempool_destroy (set->mempool);
2826 g_free (set->images);
2827 mono_os_mutex_destroy (&set->lock);
2828 g_free (set);
2831 void
2832 mono_image_set_lock (MonoImageSet *set)
2834 mono_os_mutex_lock (&set->lock);
2837 void
2838 mono_image_set_unlock (MonoImageSet *set)
2840 mono_os_mutex_unlock (&set->lock);
2843 gpointer
2844 mono_image_set_alloc (MonoImageSet *set, guint size)
2846 gpointer res;
2848 mono_image_set_lock (set);
2849 if (!set->mempool)
2850 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2851 res = mono_mempool_alloc (set->mempool, size);
2852 mono_image_set_unlock (set);
2854 return res;
2857 gpointer
2858 mono_image_set_alloc0 (MonoImageSet *set, guint size)
2860 gpointer res;
2862 mono_image_set_lock (set);
2863 if (!set->mempool)
2864 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2865 res = mono_mempool_alloc0 (set->mempool, size);
2866 mono_image_set_unlock (set);
2868 return res;
2871 char*
2872 mono_image_set_strdup (MonoImageSet *set, const char *s)
2874 char *res;
2876 mono_image_set_lock (set);
2877 if (!set->mempool)
2878 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2879 res = mono_mempool_strdup (set->mempool, s);
2880 mono_image_set_unlock (set);
2882 return res;
2885 // Get a descriptive string for a MonoImageSet
2886 // Callers are obligated to free buffer with g_free after use
2887 char *
2888 mono_image_set_description (MonoImageSet *set)
2890 GString *result = g_string_new (NULL);
2891 int img;
2892 g_string_append (result, "[");
2893 for (img = 0; img < set->nimages; img++)
2895 if (img > 0)
2896 g_string_append (result, ", ");
2897 g_string_append (result, set->images[img]->name);
2899 g_string_append (result, "]");
2900 return g_string_free (result, FALSE);
2904 * Structure used by the collect_..._images functions to store the image list.
2906 typedef struct {
2907 MonoImage *image_buf [64];
2908 MonoImage **images;
2909 int nimages, images_len;
2910 } CollectData;
2912 static void
2913 collect_data_init (CollectData *data)
2915 data->images = data->image_buf;
2916 data->images_len = 64;
2917 data->nimages = 0;
2920 static void
2921 collect_data_free (CollectData *data)
2923 if (data->images != data->image_buf)
2924 g_free (data->images);
2927 static void
2928 enlarge_data (CollectData *data)
2930 int new_len = data->images_len < 16 ? 16 : data->images_len * 2;
2931 MonoImage **d = g_new (MonoImage *, new_len);
2933 // FIXME: test this
2934 g_assert_not_reached ();
2935 memcpy (d, data->images, data->images_len);
2936 if (data->images != data->image_buf)
2937 g_free (data->images);
2938 data->images = d;
2939 data->images_len = new_len;
2942 static void
2943 add_image (MonoImage *image, CollectData *data)
2945 int i;
2947 /* The arrays are small, so use a linear search instead of a hash table */
2948 for (i = 0; i < data->nimages; ++i)
2949 if (data->images [i] == image)
2950 return;
2952 if (data->nimages == data->images_len)
2953 enlarge_data (data);
2955 data->images [data->nimages ++] = image;
2958 static void
2959 collect_type_images (MonoType *type, CollectData *data);
2961 static void
2962 collect_ginst_images (MonoGenericInst *ginst, CollectData *data)
2964 int i;
2966 for (i = 0; i < ginst->type_argc; ++i) {
2967 collect_type_images (ginst->type_argv [i], data);
2971 static void
2972 collect_gclass_images (MonoGenericClass *gclass, CollectData *data)
2974 add_image (m_class_get_image (gclass->container_class), data);
2975 if (gclass->context.class_inst)
2976 collect_ginst_images (gclass->context.class_inst, data);
2979 static void
2980 collect_signature_images (MonoMethodSignature *sig, CollectData *data)
2982 gpointer iter = NULL;
2983 MonoType *p;
2985 collect_type_images (mono_signature_get_return_type (sig), data);
2986 while ((p = mono_signature_get_params (sig, &iter)) != NULL)
2987 collect_type_images (p, data);
2990 static void
2991 collect_inflated_signature_images (MonoInflatedMethodSignature *sig, CollectData *data)
2993 collect_signature_images (sig->sig, data);
2994 if (sig->context.class_inst)
2995 collect_ginst_images (sig->context.class_inst, data);
2996 if (sig->context.method_inst)
2997 collect_ginst_images (sig->context.method_inst, data);
3000 static void
3001 collect_method_images (MonoMethodInflated *method, CollectData *data)
3003 MonoMethod *m = method->declaring;
3005 add_image (m_class_get_image (method->declaring->klass), data);
3006 if (method->context.class_inst)
3007 collect_ginst_images (method->context.class_inst, data);
3008 if (method->context.method_inst)
3009 collect_ginst_images (method->context.method_inst, data);
3011 * Dynamic assemblies have no references, so the images they depend on can be unloaded before them.
3013 if (image_is_dynamic (m_class_get_image (m->klass)))
3014 collect_signature_images (mono_method_signature_internal (m), data);
3017 static void
3018 collect_aggregate_modifiers_images (MonoAggregateModContainer *amods, CollectData *data)
3020 for (int i = 0; i < amods->count; ++i)
3021 collect_type_images (amods->modifiers [i].type, data);
3024 static void
3025 collect_type_images (MonoType *type, CollectData *data)
3027 retry:
3028 if (G_UNLIKELY (type->has_cmods && mono_type_is_aggregate_mods (type))) {
3029 collect_aggregate_modifiers_images (mono_type_get_amods (type), data);
3032 switch (type->type) {
3033 case MONO_TYPE_GENERICINST:
3034 collect_gclass_images (type->data.generic_class, data);
3035 break;
3036 case MONO_TYPE_PTR:
3037 type = type->data.type;
3038 goto retry;
3039 case MONO_TYPE_SZARRAY:
3040 type = m_class_get_byval_arg (type->data.klass);
3041 goto retry;
3042 case MONO_TYPE_ARRAY:
3043 type = m_class_get_byval_arg (type->data.array->eklass);
3044 goto retry;
3045 case MONO_TYPE_FNPTR:
3046 collect_signature_images (type->data.method, data);
3047 break;
3048 case MONO_TYPE_VAR:
3049 case MONO_TYPE_MVAR:
3051 MonoImage *image = mono_get_image_for_generic_param (type->data.generic_param);
3052 add_image (image, data);
3053 type = type->data.generic_param->gshared_constraint;
3054 if (type)
3055 goto retry;
3056 break;
3058 case MONO_TYPE_CLASS:
3059 case MONO_TYPE_VALUETYPE:
3060 add_image (m_class_get_image (mono_class_from_mono_type_internal (type)), data);
3061 break;
3062 default:
3063 add_image (mono_defaults.corlib, data);
3067 typedef struct {
3068 MonoImage *image;
3069 GSList *list;
3070 } CleanForImageUserData;
3072 static gboolean
3073 steal_gclass_in_image (gpointer key, gpointer value, gpointer data)
3075 MonoGenericClass *gclass = (MonoGenericClass *)key;
3076 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
3078 g_assert (gclass_in_image (gclass, user_data->image));
3080 user_data->list = g_slist_prepend (user_data->list, gclass);
3081 return TRUE;
3084 static gboolean
3085 steal_ginst_in_image (gpointer key, gpointer value, gpointer data)
3087 MonoGenericInst *ginst = (MonoGenericInst *)key;
3088 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
3090 // This doesn't work during corlib compilation
3091 //g_assert (ginst_in_image (ginst, user_data->image));
3093 user_data->list = g_slist_prepend (user_data->list, ginst);
3094 return TRUE;
3097 static gboolean
3098 steal_aggregate_modifiers_in_image (gpointer key, gpointer value, gpointer data)
3100 MonoAggregateModContainer *amods = (MonoAggregateModContainer *)key;
3101 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
3103 g_assert (aggregate_modifiers_in_image (amods, user_data->image));
3105 user_data->list = g_slist_prepend (user_data->list, amods);
3106 return TRUE;
3109 static gboolean
3110 inflated_method_in_image (gpointer key, gpointer value, gpointer data)
3112 MonoImage *image = (MonoImage *)data;
3113 MonoMethodInflated *method = (MonoMethodInflated *)key;
3115 // FIXME:
3116 // https://bugzilla.novell.com/show_bug.cgi?id=458168
3117 g_assert (m_class_get_image (method->declaring->klass) == image ||
3118 (method->context.class_inst && ginst_in_image (method->context.class_inst, image)) ||
3119 (method->context.method_inst && ginst_in_image (method->context.method_inst, image)) || (((MonoMethod*)method)->signature && signature_in_image (mono_method_signature_internal ((MonoMethod*)method), image)));
3121 return TRUE;
3124 static gboolean
3125 inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
3127 MonoImage *image = (MonoImage *)data;
3128 MonoInflatedMethodSignature *sig = (MonoInflatedMethodSignature *)key;
3130 return signature_in_image (sig->sig, image) ||
3131 (sig->context.class_inst && ginst_in_image (sig->context.class_inst, image)) ||
3132 (sig->context.method_inst && ginst_in_image (sig->context.method_inst, image));
3135 static gboolean
3136 class_in_image (gpointer key, gpointer value, gpointer data)
3138 MonoImage *image = (MonoImage *)data;
3139 MonoClass *klass = (MonoClass *)key;
3141 g_assert (type_in_image (m_class_get_byval_arg (klass), image));
3143 return TRUE;
3146 static void
3147 check_gmethod (gpointer key, gpointer value, gpointer data)
3149 MonoMethodInflated *method = (MonoMethodInflated *)key;
3150 MonoImage *image = (MonoImage *)data;
3152 if (method->context.class_inst)
3153 g_assert (!ginst_in_image (method->context.class_inst, image));
3154 if (method->context.method_inst)
3155 g_assert (!ginst_in_image (method->context.method_inst, image));
3156 if (((MonoMethod*)method)->signature)
3157 g_assert (!signature_in_image (mono_method_signature_internal ((MonoMethod*)method), image));
3161 * check_image_sets:
3163 * Run a consistency check on the image set data structures.
3165 static G_GNUC_UNUSED void
3166 check_image_sets (MonoImage *image)
3168 int i;
3169 GSList *l = image->image_sets;
3171 if (!image_sets)
3172 return;
3174 for (i = 0; i < image_sets->len; ++i) {
3175 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
3177 if (!g_slist_find (l, set)) {
3178 g_hash_table_foreach (set->gmethod_cache, check_gmethod, image);
3183 void
3184 mono_metadata_clean_for_image (MonoImage *image)
3186 CleanForImageUserData ginst_data, gclass_data, amods_data;
3187 GSList *l, *set_list;
3189 //check_image_sets (image);
3192 * The data structures could reference each other so we delete them in two phases.
3193 * This is required because of the hashing functions in gclass/ginst_cache.
3195 ginst_data.image = gclass_data.image = image;
3196 ginst_data.list = gclass_data.list = NULL;
3197 amods_data.image = image;
3198 amods_data.list = NULL;
3200 /* Collect the items to delete */
3201 /* delete_image_set () modifies the lists so make a copy */
3202 for (l = image->image_sets; l; l = l->next) {
3203 MonoImageSet *set = (MonoImageSet *)l->data;
3205 mono_image_set_lock (set);
3206 mono_conc_hashtable_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data);
3207 g_hash_table_foreach_steal (set->ginst_cache, steal_ginst_in_image, &ginst_data);
3208 g_hash_table_foreach_remove (set->gmethod_cache, inflated_method_in_image, image);
3209 g_hash_table_foreach_remove (set->gsignature_cache, inflated_signature_in_image, image);
3211 g_hash_table_foreach_steal (set->szarray_cache, class_in_image, image);
3212 g_hash_table_foreach_steal (set->array_cache, class_in_image, image);
3213 if (set->ptr_cache)
3214 g_hash_table_foreach_steal (set->ptr_cache, class_in_image, image);
3216 g_hash_table_foreach_steal (set->aggregate_modifiers_cache, steal_aggregate_modifiers_in_image, &amods_data);
3218 mono_image_set_unlock (set);
3221 /* Delete the removed items */
3222 for (l = ginst_data.list; l; l = l->next)
3223 free_generic_inst ((MonoGenericInst *)l->data);
3224 for (l = gclass_data.list; l; l = l->next)
3225 free_generic_class ((MonoGenericClass *)l->data);
3226 for (l = amods_data.list; l; l = l->next)
3227 free_aggregate_modifiers ((MonoAggregateModContainer *)l->data);
3228 g_slist_free (ginst_data.list);
3229 g_slist_free (gclass_data.list);
3230 /* delete_image_set () modifies the lists so make a copy */
3231 set_list = g_slist_copy (image->image_sets);
3232 for (l = set_list; l; l = l->next) {
3233 MonoImageSet *set = (MonoImageSet *)l->data;
3235 delete_image_set (set);
3237 g_slist_free (set_list);
3240 static void
3241 free_inflated_method (MonoMethodInflated *imethod)
3243 MonoMethod *method = (MonoMethod*)imethod;
3245 if (method->signature)
3246 mono_metadata_free_inflated_signature (method->signature);
3248 if (method->wrapper_type)
3249 g_free (((MonoMethodWrapper*)method)->method_data);
3251 g_free (method);
3254 static void
3255 free_generic_inst (MonoGenericInst *ginst)
3257 int i;
3259 /* The ginst itself is allocated from the image set mempool */
3260 for (i = 0; i < ginst->type_argc; ++i)
3261 mono_metadata_free_type (ginst->type_argv [i]);
3264 static void
3265 free_generic_class (MonoGenericClass *gclass)
3267 /* The gclass itself is allocated from the image set mempool */
3268 if (gclass->cached_class && m_class_get_interface_id (gclass->cached_class))
3269 mono_unload_interface_id (gclass->cached_class);
3272 static void
3273 free_inflated_signature (MonoInflatedMethodSignature *sig)
3275 mono_metadata_free_inflated_signature (sig->sig);
3276 g_free (sig);
3279 static void
3280 free_aggregate_modifiers (MonoAggregateModContainer *amods)
3282 for (int i = 0; i < amods->count; i++)
3283 mono_metadata_free_type (amods->modifiers [i].type);
3284 /* the container itself is allocated in the image set mempool */
3288 * mono_metadata_get_inflated_signature:
3290 * Given an inflated signature and a generic context, return a canonical copy of the
3291 * signature. The returned signature might be equal to SIG or it might be a cached copy.
3293 MonoMethodSignature *
3294 mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericContext *context)
3296 MonoInflatedMethodSignature helper;
3297 MonoInflatedMethodSignature *res;
3298 CollectData data;
3299 MonoImageSet *set;
3301 helper.sig = sig;
3302 helper.context.class_inst = context->class_inst;
3303 helper.context.method_inst = context->method_inst;
3305 collect_data_init (&data);
3307 collect_inflated_signature_images (&helper, &data);
3309 set = get_image_set (data.images, data.nimages);
3311 collect_data_free (&data);
3313 mono_image_set_lock (set);
3315 res = (MonoInflatedMethodSignature *)g_hash_table_lookup (set->gsignature_cache, &helper);
3316 if (!res) {
3317 res = g_new0 (MonoInflatedMethodSignature, 1);
3318 res->sig = sig;
3319 res->context.class_inst = context->class_inst;
3320 res->context.method_inst = context->method_inst;
3321 g_hash_table_insert (set->gsignature_cache, res, res);
3324 mono_image_set_unlock (set);
3326 return res->sig;
3329 MonoImageSet *
3330 mono_metadata_get_image_set_for_type (MonoType *type)
3332 MonoImageSet *set;
3333 CollectData image_set_data;
3335 collect_data_init (&image_set_data);
3336 collect_type_images (type, &image_set_data);
3337 set = get_image_set (image_set_data.images, image_set_data.nimages);
3338 collect_data_free (&image_set_data);
3340 return set;
3343 MonoImageSet *
3344 mono_metadata_get_image_set_for_class (MonoClass *klass)
3346 return mono_metadata_get_image_set_for_type (m_class_get_byval_arg (klass));
3349 MonoImageSet *
3350 mono_metadata_get_image_set_for_method (MonoMethodInflated *method)
3352 MonoImageSet *set;
3353 CollectData image_set_data;
3355 collect_data_init (&image_set_data);
3356 collect_method_images (method, &image_set_data);
3357 set = get_image_set (image_set_data.images, image_set_data.nimages);
3358 collect_data_free (&image_set_data);
3360 return set;
3363 MonoImageSet *
3364 mono_metadata_get_image_set_for_aggregate_modifiers (MonoAggregateModContainer *amods)
3366 MonoImageSet *set;
3367 CollectData image_set_data;
3368 collect_data_init (&image_set_data);
3369 collect_aggregate_modifiers_images (amods, &image_set_data);
3370 set = get_image_set (image_set_data.images, image_set_data.nimages);
3371 collect_data_free (&image_set_data);
3373 return set;
3376 MonoImageSet *
3377 mono_metadata_merge_image_sets (MonoImageSet *set1, MonoImageSet *set2)
3379 MonoImage **images = g_newa (MonoImage*, set1->nimages + set2->nimages);
3381 /* Add images from set1 */
3382 memcpy (images, set1->images, sizeof (MonoImage*) * set1->nimages);
3384 int nimages = set1->nimages;
3385 // FIXME: Quaratic
3386 /* Add images from set2 */
3387 for (int i = 0; i < set2->nimages; ++i) {
3388 int j;
3389 for (j = 0; j < set1->nimages; ++j) {
3390 if (set2->images [i] == set1->images [j])
3391 break;
3393 if (j == set1->nimages)
3394 images [nimages ++] = set2->images [i];
3396 return get_image_set (images, nimages);
3399 static gboolean
3400 type_is_gtd (MonoType *type)
3402 switch (type->type) {
3403 case MONO_TYPE_CLASS:
3404 case MONO_TYPE_VALUETYPE:
3405 return mono_class_is_gtd (type->data.klass);
3406 default:
3407 return FALSE;
3412 * mono_metadata_get_generic_inst:
3414 * Given a list of types, return a MonoGenericInst that represents that list.
3415 * The returned MonoGenericInst has its own copy of the list of types. The list
3416 * passed in the argument can be freed, modified or disposed of.
3419 MonoGenericInst *
3420 mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
3422 MonoGenericInst *ginst;
3423 gboolean is_open;
3424 int i;
3425 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3427 for (i = 0; i < type_argc; ++i)
3428 if (mono_class_is_open_constructed_type (type_argv [i]))
3429 break;
3430 is_open = (i < type_argc);
3432 ginst = (MonoGenericInst *)g_alloca (size);
3433 memset (ginst, 0, sizeof (MonoGenericInst));
3434 ginst->is_open = is_open;
3435 ginst->type_argc = type_argc;
3436 memcpy (ginst->type_argv, type_argv, type_argc * sizeof (MonoType *));
3438 for (i = 0; i < type_argc; ++i) {
3439 MonoType *t = ginst->type_argv [i];
3440 if (type_is_gtd (t)) {
3441 ginst->type_argv [i] = mono_class_gtd_get_canonical_inst (t->data.klass);
3445 return mono_metadata_get_canonical_generic_inst (ginst);
3449 * mono_metadata_get_canonical_generic_inst:
3450 * \param candidate an arbitrary generic instantiation
3452 * \returns the canonical generic instantiation that represents the given
3453 * candidate by identifying the image set for the candidate instantiation and
3454 * finding the instance in the image set or adding a copy of the given instance
3455 * to the image set.
3457 * The returned MonoGenericInst has its own copy of the list of types. The list
3458 * passed in the argument can be freed, modified or disposed of.
3461 MonoGenericInst *
3462 mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate)
3464 CollectData data;
3465 int type_argc = candidate->type_argc;
3466 gboolean is_open = candidate->is_open;
3467 MonoImageSet *set;
3469 collect_data_init (&data);
3471 collect_ginst_images (candidate, &data);
3473 set = get_image_set (data.images, data.nimages);
3475 collect_data_free (&data);
3477 mono_image_set_lock (set);
3479 MonoGenericInst *ginst = (MonoGenericInst *)g_hash_table_lookup (set->ginst_cache, candidate);
3480 if (!ginst) {
3481 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3482 ginst = (MonoGenericInst *)mono_image_set_alloc0 (set, size);
3483 #ifndef MONO_SMALL_CONFIG
3484 ginst->id = mono_atomic_inc_i32 (&next_generic_inst_id);
3485 #endif
3486 ginst->is_open = is_open;
3487 ginst->type_argc = type_argc;
3489 for (int i = 0; i < type_argc; ++i)
3490 ginst->type_argv [i] = mono_metadata_type_dup (NULL, candidate->type_argv [i]);
3492 g_hash_table_insert (set->ginst_cache, ginst, ginst);
3495 mono_image_set_unlock (set);
3496 return ginst;
3499 MonoAggregateModContainer *
3500 mono_metadata_get_canonical_aggregate_modifiers (MonoAggregateModContainer *candidate)
3502 g_assert (candidate->count > 0);
3503 MonoImageSet *set = mono_metadata_get_image_set_for_aggregate_modifiers (candidate);
3505 mono_image_set_lock (set);
3507 MonoAggregateModContainer *amods = (MonoAggregateModContainer *)g_hash_table_lookup (set->aggregate_modifiers_cache, candidate);
3508 if (!amods) {
3509 size_t size = mono_sizeof_aggregate_modifiers (candidate->count);
3510 amods = (MonoAggregateModContainer *)mono_image_set_alloc0 (set, size);
3511 amods->count = candidate->count;
3512 for (int i = 0; i < candidate->count; ++i) {
3513 amods->modifiers [i].required = candidate->modifiers [i].required;
3514 amods->modifiers [i].type = mono_metadata_type_dup (NULL, candidate->modifiers [i].type);
3517 g_hash_table_insert (set->aggregate_modifiers_cache, amods, amods);
3519 mono_image_set_unlock (set);
3520 return amods;
3523 static gboolean
3524 mono_metadata_is_type_builder_generic_type_definition (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3526 MonoGenericContainer *container = mono_class_get_generic_container (container_class);
3528 if (!is_dynamic || m_class_was_typebuilder (container_class) || container->type_argc != inst->type_argc)
3529 return FALSE;
3530 return inst == container->context.class_inst;
3534 * mono_metadata_lookup_generic_class:
3536 * Returns a MonoGenericClass with the given properties.
3539 MonoGenericClass *
3540 mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3542 MonoGenericClass *gclass;
3543 MonoGenericClass helper;
3544 gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic);
3545 MonoImageSet *set;
3546 CollectData data;
3548 g_assert (mono_class_get_generic_container (container_class)->type_argc == inst->type_argc);
3550 memset (&helper, 0, sizeof(helper)); // act like g_new0
3551 helper.container_class = container_class;
3552 helper.context.class_inst = inst;
3553 helper.is_dynamic = is_dynamic; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
3554 helper.is_tb_open = is_tb_open;
3556 collect_data_init (&data);
3558 collect_gclass_images (&helper, &data);
3560 set = get_image_set (data.images, data.nimages);
3562 collect_data_free (&data);
3564 gclass = (MonoGenericClass *)mono_conc_hashtable_lookup (set->gclass_cache, &helper);
3566 /* A tripwire just to keep us honest */
3567 g_assert (!helper.cached_class);
3569 if (gclass)
3570 return gclass;
3572 gclass = mono_image_set_new0 (set, MonoGenericClass, 1);
3573 if (is_dynamic)
3574 gclass->is_dynamic = 1;
3576 gclass->is_tb_open = is_tb_open;
3577 gclass->container_class = container_class;
3578 gclass->context.class_inst = inst;
3579 gclass->context.method_inst = NULL;
3580 gclass->owner = set;
3581 if (inst == mono_class_get_generic_container (container_class)->context.class_inst && !is_tb_open)
3582 gclass->cached_class = container_class;
3584 mono_image_set_lock (set);
3586 MonoGenericClass *gclass2 = (MonoGenericClass*)mono_conc_hashtable_insert (set->gclass_cache, gclass, gclass);
3587 if (!gclass2)
3588 gclass2 = gclass;
3590 // g_hash_table_insert (set->gclass_cache, gclass, gclass);
3592 mono_image_set_unlock (set);
3594 return gclass2;
3598 * mono_metadata_inflate_generic_inst:
3600 * Instantiate the generic instance @ginst with the context @context.
3601 * Check @error for success.
3604 MonoGenericInst *
3605 mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context, MonoError *error)
3607 MonoType **type_argv;
3608 MonoGenericInst *nginst = NULL;
3609 int i, count = 0;
3611 error_init (error);
3613 if (!ginst->is_open)
3614 return ginst;
3616 type_argv = g_new0 (MonoType*, ginst->type_argc);
3618 for (i = 0; i < ginst->type_argc; i++) {
3619 type_argv [i] = mono_class_inflate_generic_type_checked (ginst->type_argv [i], context, error);
3620 if (!is_ok (error))
3621 goto cleanup;
3622 ++count;
3625 nginst = mono_metadata_get_generic_inst (ginst->type_argc, type_argv);
3627 cleanup:
3628 for (i = 0; i < count; i++)
3629 mono_metadata_free_type (type_argv [i]);
3630 g_free (type_argv);
3632 return nginst;
3635 MonoGenericInst *
3636 mono_metadata_parse_generic_inst (MonoImage *m, MonoGenericContainer *container,
3637 int count, const char *ptr, const char **rptr, MonoError *error)
3639 MonoType **type_argv;
3640 MonoGenericInst *ginst = NULL;
3641 int i, parse_count = 0;
3643 error_init (error);
3644 type_argv = g_new0 (MonoType*, count);
3646 for (i = 0; i < count; i++) {
3647 /* this can be a transient type, mono_metadata_get_generic_inst will allocate
3648 * a canonical one, if needed.
3650 MonoType *t = mono_metadata_parse_type_checked (m, container, 0, TRUE, ptr, &ptr, error);
3651 if (!t)
3652 goto cleanup;
3653 type_argv [i] = t;
3654 parse_count++;
3657 if (rptr)
3658 *rptr = ptr;
3660 g_assert (parse_count == count);
3661 ginst = mono_metadata_get_generic_inst (count, type_argv);
3663 cleanup:
3664 for (i = 0; i < parse_count; i++)
3665 mono_metadata_free_type (type_argv [i]);
3666 g_free (type_argv);
3668 return ginst;
3671 static gboolean
3672 do_mono_metadata_parse_generic_class (MonoType *type, MonoImage *m, MonoGenericContainer *container,
3673 const char *ptr, const char **rptr, MonoError *error)
3675 MonoGenericInst *inst;
3676 MonoClass *gklass;
3677 MonoType *gtype;
3678 int count;
3680 error_init (error);
3682 // XXX how about transient?
3683 gtype = mono_metadata_parse_type_checked (m, NULL, 0, FALSE, ptr, &ptr, error);
3684 if (gtype == NULL)
3685 return FALSE;
3687 gklass = mono_class_from_mono_type_internal (gtype);
3688 if (!mono_class_is_gtd (gklass)) {
3689 mono_error_set_bad_image (error, m, "Generic instance with non-generic definition");
3690 return FALSE;
3693 count = mono_metadata_decode_value (ptr, &ptr);
3694 inst = mono_metadata_parse_generic_inst (m, container, count, ptr, &ptr, error);
3695 if (inst == NULL)
3696 return FALSE;
3698 if (rptr)
3699 *rptr = ptr;
3701 type->data.generic_class = mono_metadata_lookup_generic_class (gklass, inst, FALSE);
3702 return TRUE;
3706 * select_container:
3707 * @gc: The generic container to normalize
3708 * @type: The kind of generic parameters the resulting generic-container should contain
3711 static MonoGenericContainer *
3712 select_container (MonoGenericContainer *gc, MonoTypeEnum type)
3714 gboolean is_var = (type == MONO_TYPE_VAR);
3715 if (!gc)
3716 return NULL;
3718 g_assert (is_var || type == MONO_TYPE_MVAR);
3720 if (is_var) {
3721 if (gc->is_method || gc->parent)
3723 * The current MonoGenericContainer is a generic method -> its `parent'
3724 * points to the containing class'es container.
3726 return gc->parent;
3729 return gc;
3732 MonoGenericContainer *
3733 mono_get_anonymous_container_for_image (MonoImage *image, gboolean is_mvar)
3735 MonoGenericContainer **container_pointer;
3736 if (is_mvar)
3737 container_pointer = &image->anonymous_generic_method_container;
3738 else
3739 container_pointer = &image->anonymous_generic_class_container;
3740 MonoGenericContainer *result = *container_pointer;
3742 // This container has never been created; make it now.
3743 if (!result)
3745 // Note this is never deallocated anywhere-- it exists for the lifetime of the image it's allocated from
3746 result = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
3747 result->owner.image = image;
3748 result->is_anonymous = TRUE;
3749 result->is_method = is_mvar;
3751 // If another thread already made a container, use that and leak this new one.
3752 // (Technically it would currently be safe to just assign instead of CASing.)
3753 MonoGenericContainer *exchange = (MonoGenericContainer *)mono_atomic_cas_ptr ((volatile gpointer *)container_pointer, result, NULL);
3754 if (exchange)
3755 result = exchange;
3757 return result;
3760 #define FAST_GPARAM_CACHE_SIZE 16
3762 static MonoGenericParam*
3763 lookup_anon_gparam (MonoImage *image, MonoGenericContainer *container, gint32 param_num, gboolean is_mvar)
3765 if (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE) {
3766 MonoGenericParam *cache = is_mvar ? image->mvar_gparam_cache_fast : image->var_gparam_cache_fast;
3767 if (!cache)
3768 return NULL;
3769 return &cache[param_num];
3770 } else {
3771 MonoGenericParam key;
3772 memset (&key, 0, sizeof (key));
3773 key.owner = container;
3774 key.num = param_num;
3775 key.gshared_constraint = NULL;
3776 MonoConcurrentHashTable *cache = is_mvar ? image->mvar_gparam_cache : image->var_gparam_cache;
3777 if (!cache)
3778 return NULL;
3779 return (MonoGenericParam*)mono_conc_hashtable_lookup (cache, &key);
3783 static MonoGenericParam*
3784 publish_anon_gparam_fast (MonoImage *image, MonoGenericContainer *container, gint32 param_num)
3786 g_assert (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE);
3787 MonoGenericParam **cache = container->is_method ? &image->mvar_gparam_cache_fast : &image->var_gparam_cache_fast;
3788 if (!*cache) {
3789 mono_image_lock (image);
3790 if (!*cache) {
3791 *cache = (MonoGenericParam*)mono_image_alloc0 (image, sizeof (MonoGenericParam) * FAST_GPARAM_CACHE_SIZE);
3792 for (gint32 i = 0; i < FAST_GPARAM_CACHE_SIZE; ++i) {
3793 MonoGenericParam *param = &(*cache)[i];
3794 param->owner = container;
3795 param->num = i;
3798 mono_image_unlock (image);
3800 return &(*cache)[param_num];
3804 * publish_anon_gparam_slow:
3806 * Publish \p gparam anonymous generic parameter to the anon gparam cache for \p image.
3808 * LOCKING: takes the image lock.
3810 static MonoGenericParam*
3811 publish_anon_gparam_slow (MonoImage *image, MonoGenericParam *gparam)
3813 MonoConcurrentHashTable **cache = gparam->owner->is_method ? &image->mvar_gparam_cache : &image->var_gparam_cache;
3814 if (!*cache) {
3815 mono_image_lock (image);
3816 if (!*cache) {
3817 MonoConcurrentHashTable *ht = mono_conc_hashtable_new ((GHashFunc)mono_metadata_generic_param_hash,
3818 (GEqualFunc) mono_metadata_generic_param_equal);
3819 mono_atomic_store_release (cache, ht);
3821 mono_image_unlock (image);
3823 MonoGenericParam *other = (MonoGenericParam*)mono_conc_hashtable_insert (*cache, gparam, gparam);
3824 // If another thread published first return their param, otherwise return ours.
3825 return other ? other : gparam;
3829 * mono_metadata_create_anon_gparam:
3830 * \param image the MonoImage that owns the anonymous generic parameter
3831 * \param param_num the parameter number
3832 * \param is_mvar TRUE if this is a method generic parameter, FALSE if it's a class generic parameter.
3834 * Returns: a new, or exisisting \c MonoGenericParam for an anonymous generic parameter with the given properties.
3836 * LOCKING: takes the image lock.
3838 MonoGenericParam*
3839 mono_metadata_create_anon_gparam (MonoImage *image, gint32 param_num, gboolean is_mvar)
3841 MonoGenericContainer *container = mono_get_anonymous_container_for_image (image, is_mvar);
3842 MonoGenericParam *gparam = lookup_anon_gparam (image, container, param_num, is_mvar);
3843 if (gparam)
3844 return gparam;
3845 if (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE) {
3846 return publish_anon_gparam_fast (image, container, param_num);
3847 } else {
3848 // Create a candidate generic param and try to insert it in the cache.
3849 // If multiple threads both try to publish the same param, all but one
3850 // will leak, but that's okay.
3851 gparam = (MonoGenericParam*)mono_image_alloc0 (image, sizeof (MonoGenericParam));
3852 gparam->owner = container;
3853 gparam->num = param_num;
3855 return publish_anon_gparam_slow (image, gparam);
3860 * mono_metadata_parse_generic_param:
3861 * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
3862 * see mono_metadata_parse_type_checked() for details.
3863 * Internal routine to parse a generic type parameter.
3864 * LOCKING: Acquires the loader lock
3866 static MonoGenericParam *
3867 mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_container,
3868 MonoTypeEnum type, const char *ptr, const char **rptr, MonoError *error)
3870 int index = mono_metadata_decode_value (ptr, &ptr);
3871 if (rptr)
3872 *rptr = ptr;
3874 error_init (error);
3876 generic_container = select_container (generic_container, type);
3877 if (!generic_container) {
3878 gboolean is_mvar = FALSE;
3879 switch (type)
3881 case MONO_TYPE_VAR:
3882 break;
3883 case MONO_TYPE_MVAR:
3884 is_mvar = TRUE;
3885 break;
3886 default:
3887 g_error ("Cerating generic param object with invalid MonoType"); // This is not a generic param
3890 return mono_metadata_create_anon_gparam (m, index, is_mvar);
3893 if (index >= generic_container->type_argc) {
3894 mono_error_set_bad_image (error, m, "Invalid generic %s parameter index %d, max index is %d",
3895 generic_container->is_method ? "method" : "type",
3896 index, generic_container->type_argc);
3897 return NULL;
3900 //This can't return NULL
3901 return mono_generic_container_get_param (generic_container, index);
3905 * mono_metadata_get_shared_type:
3907 * Return a shared instance of TYPE, if available, NULL otherwise.
3908 * Shared MonoType instances help save memory. Their contents should not be modified
3909 * by the caller. They do not need to be freed as their lifetime is bound by either
3910 * the lifetime of the runtime (builtin types), or the lifetime of the MonoClass
3911 * instance they are embedded in. If they are freed, they should be freed using
3912 * mono_metadata_free_type () instead of g_free ().
3914 MonoType*
3915 mono_metadata_get_shared_type (MonoType *type)
3917 MonoType *cached;
3919 /* No need to use locking since nobody is modifying the hash table */
3920 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type)))
3921 return cached;
3923 switch (type->type){
3924 case MONO_TYPE_CLASS:
3925 case MONO_TYPE_VALUETYPE:
3926 if (type == m_class_get_byval_arg (type->data.klass))
3927 return type;
3928 if (type == m_class_get_this_arg (type->data.klass))
3929 return type;
3930 break;
3931 default:
3932 break;
3935 return NULL;
3938 static gboolean
3939 compare_type_literals (MonoImage *image, int class_type, int type_type, MonoError *error)
3941 error_init (error);
3943 /* _byval_arg.type can be zero if we're decoding a type that references a class been loading.
3944 * See mcs/test/gtest-440. and #650936.
3945 * FIXME This better be moved to the metadata verifier as it can catch more cases.
3947 if (!class_type)
3948 return TRUE;
3949 /* NET 1.1 assemblies might encode string and object in a denormalized way.
3950 * See #675464.
3952 if (class_type == type_type)
3953 return TRUE;
3955 if (type_type == MONO_TYPE_CLASS) {
3956 if (class_type == MONO_TYPE_STRING || class_type == MONO_TYPE_OBJECT)
3957 return TRUE;
3958 //XXX stringify this argument
3959 mono_error_set_bad_image (error, image, "Expected reference type but got type kind %d", class_type);
3960 return FALSE;
3963 g_assert (type_type == MONO_TYPE_VALUETYPE);
3964 switch (class_type) {
3965 case MONO_TYPE_BOOLEAN:
3966 case MONO_TYPE_CHAR:
3967 case MONO_TYPE_I1:
3968 case MONO_TYPE_U1:
3969 case MONO_TYPE_I2:
3970 case MONO_TYPE_U2:
3971 case MONO_TYPE_I4:
3972 case MONO_TYPE_U4:
3973 case MONO_TYPE_I8:
3974 case MONO_TYPE_U8:
3975 case MONO_TYPE_R4:
3976 case MONO_TYPE_R8:
3977 case MONO_TYPE_I:
3978 case MONO_TYPE_U:
3979 case MONO_TYPE_CLASS:
3980 return TRUE;
3981 default:
3982 //XXX stringify this argument
3983 mono_error_set_bad_image (error, image, "Expected value type but got type kind %d", class_type);
3984 return FALSE;
3988 static gboolean
3989 verify_var_type_and_container (MonoImage *image, int var_type, MonoGenericContainer *container, MonoError *error)
3991 error_init (error);
3992 if (var_type == MONO_TYPE_MVAR) {
3993 if (!container->is_method) { //MVAR and a method container
3994 mono_error_set_bad_image (error, image, "MVAR parsed in a context without a method container");
3995 return FALSE;
3997 } else {
3998 if (!(!container->is_method || //VAR and class container
3999 (container->is_method && container->parent))) { //VAR and method container with parent
4000 mono_error_set_bad_image (error, image, "VAR parsed in a context without a class container");
4001 return FALSE;
4004 return TRUE;
4008 * do_mono_metadata_parse_type:
4009 * @type: MonoType to be filled in with the return value
4010 * @m: image context
4011 * @generic_context: generics_context
4012 * @transient: whenever to allocate data from the heap
4013 * @ptr: pointer to the encoded type
4014 * @rptr: pointer where the end of the encoded type is saved
4016 * Internal routine used to "fill" the contents of @type from an
4017 * allocated pointer. This is done this way to avoid doing too
4018 * many mini-allocations (particularly for the MonoFieldType which
4019 * most of the time is just a MonoType, but sometimes might be augmented).
4021 * This routine is used by mono_metadata_parse_type and
4022 * mono_metadata_parse_field_type
4024 * This extracts a Type as specified in Partition II (22.2.12)
4026 * Returns: FALSE if the type could not be loaded
4028 static gboolean
4029 do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container,
4030 gboolean transient, const char *ptr, const char **rptr, MonoError *error)
4032 error_init (error);
4034 type->type = (MonoTypeEnum)mono_metadata_decode_value (ptr, &ptr);
4036 switch (type->type){
4037 case MONO_TYPE_VOID:
4038 case MONO_TYPE_BOOLEAN:
4039 case MONO_TYPE_CHAR:
4040 case MONO_TYPE_I1:
4041 case MONO_TYPE_U1:
4042 case MONO_TYPE_I2:
4043 case MONO_TYPE_U2:
4044 case MONO_TYPE_I4:
4045 case MONO_TYPE_U4:
4046 case MONO_TYPE_I8:
4047 case MONO_TYPE_U8:
4048 case MONO_TYPE_R4:
4049 case MONO_TYPE_R8:
4050 case MONO_TYPE_I:
4051 case MONO_TYPE_U:
4052 case MONO_TYPE_STRING:
4053 case MONO_TYPE_OBJECT:
4054 case MONO_TYPE_TYPEDBYREF:
4055 break;
4056 case MONO_TYPE_VALUETYPE:
4057 case MONO_TYPE_CLASS: {
4058 guint32 token;
4059 MonoClass *klass;
4060 token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr);
4061 klass = mono_class_get_checked (m, token, error);
4062 type->data.klass = klass;
4063 if (!klass)
4064 return FALSE;
4066 if (!compare_type_literals (m, m_class_get_byval_arg (klass)->type, type->type, error))
4067 return FALSE;
4069 break;
4071 case MONO_TYPE_SZARRAY: {
4072 MonoType *etype = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
4073 if (!etype)
4074 return FALSE;
4076 type->data.klass = mono_class_from_mono_type_internal (etype);
4078 if (transient)
4079 mono_metadata_free_type (etype);
4081 g_assert (type->data.klass); //This was previously a check for NULL, but mcfmt should never fail. It can return a borken MonoClass, but should return at least something.
4082 break;
4084 case MONO_TYPE_PTR: {
4085 type->data.type = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
4086 if (!type->data.type)
4087 return FALSE;
4088 break;
4090 case MONO_TYPE_FNPTR: {
4091 type->data.method = mono_metadata_parse_method_signature_full (m, container, 0, ptr, &ptr, error);
4092 if (!type->data.method)
4093 return FALSE;
4094 break;
4096 case MONO_TYPE_ARRAY: {
4097 type->data.array = mono_metadata_parse_array_internal (m, container, transient, ptr, &ptr, error);
4098 if (!type->data.array)
4099 return FALSE;
4100 break;
4102 case MONO_TYPE_MVAR:
4103 case MONO_TYPE_VAR: {
4104 if (container && !verify_var_type_and_container (m, type->type, container, error))
4105 return FALSE;
4107 type->data.generic_param = mono_metadata_parse_generic_param (m, container, type->type, ptr, &ptr, error);
4108 if (!type->data.generic_param)
4109 return FALSE;
4111 break;
4113 case MONO_TYPE_GENERICINST: {
4114 if (!do_mono_metadata_parse_generic_class (type, m, container, ptr, &ptr, error))
4115 return FALSE;
4116 break;
4118 default:
4119 mono_error_set_bad_image (error, m, "type 0x%02x not handled in do_mono_metadata_parse_type on image %s", type->type, m->name);
4120 return FALSE;
4123 if (rptr)
4124 *rptr = ptr;
4125 return TRUE;
4129 * mono_metadata_free_type:
4130 * \param type type to free
4132 * Free the memory allocated for type \p type which is allocated on the heap.
4134 void
4135 mono_metadata_free_type (MonoType *type)
4137 if (type >= builtin_types && type < builtin_types + NBUILTIN_TYPES ())
4138 return;
4140 switch (type->type){
4141 case MONO_TYPE_OBJECT:
4142 case MONO_TYPE_STRING:
4143 if (!type->data.klass)
4144 break;
4145 /* fall through */
4146 case MONO_TYPE_CLASS:
4147 case MONO_TYPE_VALUETYPE:
4148 if (type == m_class_get_byval_arg (type->data.klass) || type == m_class_get_this_arg (type->data.klass))
4149 return;
4150 break;
4151 case MONO_TYPE_PTR:
4152 mono_metadata_free_type (type->data.type);
4153 break;
4154 case MONO_TYPE_FNPTR:
4155 mono_metadata_free_method_signature (type->data.method);
4156 break;
4157 case MONO_TYPE_ARRAY:
4158 mono_metadata_free_array (type->data.array);
4159 break;
4160 default:
4161 break;
4164 g_free (type);
4167 #if 0
4168 static void
4169 hex_dump (const char *buffer, int base, int count)
4171 int show_header = 1;
4172 int i;
4174 if (count < 0){
4175 count = -count;
4176 show_header = 0;
4179 for (i = 0; i < count; i++){
4180 if (show_header)
4181 if ((i % 16) == 0)
4182 printf ("\n0x%08x: ", (unsigned char) base + i);
4184 printf ("%02x ", (unsigned char) (buffer [i]));
4186 fflush (stdout);
4188 #endif
4190 /**
4191 * @ptr: Points to the beginning of the Section Data (25.3)
4193 static MonoExceptionClause*
4194 parse_section_data (MonoImage *m, int *num_clauses, const unsigned char *ptr, MonoError *error)
4196 unsigned char sect_data_flags;
4197 int is_fat;
4198 guint32 sect_data_len;
4199 MonoExceptionClause* clauses = NULL;
4201 error_init (error);
4203 while (1) {
4204 /* align on 32-bit boundary */
4205 ptr = dword_align (ptr);
4206 sect_data_flags = *ptr;
4207 ptr++;
4209 is_fat = sect_data_flags & METHOD_HEADER_SECTION_FAT_FORMAT;
4210 if (is_fat) {
4211 sect_data_len = (ptr [2] << 16) | (ptr [1] << 8) | ptr [0];
4212 ptr += 3;
4213 } else {
4214 sect_data_len = ptr [0];
4215 ++ptr;
4218 if (sect_data_flags & METHOD_HEADER_SECTION_EHTABLE) {
4219 const unsigned char *p = dword_align (ptr);
4220 int i;
4221 *num_clauses = is_fat ? sect_data_len / 24: sect_data_len / 12;
4222 /* we could just store a pointer if we don't need to byteswap */
4223 clauses = (MonoExceptionClause *)g_malloc0 (sizeof (MonoExceptionClause) * (*num_clauses));
4224 for (i = 0; i < *num_clauses; ++i) {
4225 MonoExceptionClause *ec = &clauses [i];
4226 guint32 tof_value;
4227 if (is_fat) {
4228 ec->flags = read32 (p);
4229 ec->try_offset = read32 (p + 4);
4230 ec->try_len = read32 (p + 8);
4231 ec->handler_offset = read32 (p + 12);
4232 ec->handler_len = read32 (p + 16);
4233 tof_value = read32 (p + 20);
4234 p += 24;
4235 } else {
4236 ec->flags = read16 (p);
4237 ec->try_offset = read16 (p + 2);
4238 ec->try_len = *(p + 4);
4239 ec->handler_offset = read16 (p + 5);
4240 ec->handler_len = *(p + 7);
4241 tof_value = read32 (p + 8);
4242 p += 12;
4244 if (ec->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4245 ec->data.filter_offset = tof_value;
4246 } else if (ec->flags == MONO_EXCEPTION_CLAUSE_NONE) {
4247 ec->data.catch_class = NULL;
4248 if (tof_value) {
4249 ec->data.catch_class = mono_class_get_checked (m, tof_value, error);
4250 if (!is_ok (error)) {
4251 g_free (clauses);
4252 return NULL;
4255 } else {
4256 ec->data.catch_class = NULL;
4258 /* g_print ("try %d: %x %04x-%04x %04x\n", i, ec->flags, ec->try_offset, ec->try_offset+ec->try_len, ec->try_len); */
4262 if (sect_data_flags & METHOD_HEADER_SECTION_MORE_SECTS)
4263 ptr += sect_data_len - 4; /* LAMESPEC: it seems the size includes the header */
4264 else
4265 return clauses;
4270 * mono_method_get_header_summary:
4271 * @method: The method to get the header.
4272 * @summary: Where to store the header
4275 * Returns: TRUE if the header was properly decoded.
4277 gboolean
4278 mono_method_get_header_summary (MonoMethod *method, MonoMethodHeaderSummary *summary)
4280 int idx;
4281 guint32 rva;
4282 MonoImage* img;
4283 const char *ptr;
4284 unsigned char flags, format;
4285 guint16 fat_flags;
4286 ERROR_DECL (error);
4288 /*Only the GMD has a pointer to the metadata.*/
4289 while (method->is_inflated)
4290 method = ((MonoMethodInflated*)method)->declaring;
4292 summary->code = NULL;
4293 summary->code_size = 0;
4294 summary->max_stack = 0;
4295 summary->has_clauses = FALSE;
4296 summary->has_locals = FALSE;
4298 /*FIXME extract this into a MACRO and share it with mono_method_get_header*/
4299 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
4300 return FALSE;
4302 if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
4303 MonoMethodHeader *header = ((MonoMethodWrapper *)method)->header;
4304 if (!header)
4305 return FALSE;
4306 summary->code = header->code;
4307 summary->code_size = header->code_size;
4308 summary->max_stack = header->max_stack;
4309 summary->has_clauses = header->num_clauses > 0;
4310 summary->has_locals = header->num_locals > 0;
4311 return TRUE;
4315 idx = mono_metadata_token_index (method->token);
4316 img = m_class_get_image (method->klass);
4317 rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
4319 /*We must run the verifier since we'll be decoding it.*/
4320 if (!mono_verifier_verify_method_header (img, rva, error)) {
4321 mono_error_cleanup (error);
4322 return FALSE;
4325 ptr = mono_image_rva_map (img, rva);
4326 if (!ptr)
4327 return FALSE;
4329 flags = *(const unsigned char *)ptr;
4330 format = flags & METHOD_HEADER_FORMAT_MASK;
4332 switch (format) {
4333 case METHOD_HEADER_TINY_FORMAT:
4334 ptr++;
4335 summary->max_stack = 8;
4336 summary->code = (unsigned char *) ptr;
4337 summary->code_size = flags >> 2;
4338 break;
4339 case METHOD_HEADER_FAT_FORMAT:
4340 fat_flags = read16 (ptr);
4341 ptr += 2;
4342 summary->max_stack = read16 (ptr);
4343 ptr += 2;
4344 summary->code_size = read32 (ptr);
4345 ptr += 4;
4346 summary->has_locals = !!read32 (ptr);
4347 ptr += 4;
4348 if (fat_flags & METHOD_HEADER_MORE_SECTS)
4349 summary->has_clauses = TRUE;
4350 summary->code = (unsigned char *) ptr;
4351 break;
4352 default:
4353 return FALSE;
4355 return TRUE;
4359 * mono_metadata_parse_mh_full:
4360 * @m: metadata context
4361 * @generic_context: generics context
4362 * @ptr: pointer to the method header.
4364 * Decode the method header at @ptr, including pointer to the IL code,
4365 * info about local variables and optional exception tables.
4366 * This is a Mono runtime internal function.
4368 * LOCKING: Acquires the loader lock.
4370 * Returns: a transient MonoMethodHeader allocated from the heap.
4372 MonoMethodHeader *
4373 mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, const char *ptr, MonoError *error)
4375 MonoMethodHeader *mh = NULL;
4376 unsigned char flags = *(const unsigned char *) ptr;
4377 unsigned char format = flags & METHOD_HEADER_FORMAT_MASK;
4378 guint16 fat_flags;
4379 guint32 local_var_sig_tok, max_stack, code_size, init_locals;
4380 const unsigned char *code;
4381 MonoExceptionClause* clauses = NULL;
4382 int num_clauses = 0;
4383 MonoTableInfo *t = &m->tables [MONO_TABLE_STANDALONESIG];
4384 guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
4386 error_init (error);
4388 if (!ptr) {
4389 mono_error_set_bad_image (error, m, "Method header with null pointer");
4390 return NULL;
4393 switch (format) {
4394 case METHOD_HEADER_TINY_FORMAT:
4395 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER);
4396 ptr++;
4397 mh->max_stack = 8;
4398 mh->is_transient = TRUE;
4399 local_var_sig_tok = 0;
4400 mh->code_size = flags >> 2;
4401 mh->code = (unsigned char*)ptr;
4402 return mh;
4403 case METHOD_HEADER_FAT_FORMAT:
4404 fat_flags = read16 (ptr);
4405 ptr += 2;
4406 max_stack = read16 (ptr);
4407 ptr += 2;
4408 code_size = read32 (ptr);
4409 ptr += 4;
4410 local_var_sig_tok = read32 (ptr);
4411 ptr += 4;
4413 if (fat_flags & METHOD_HEADER_INIT_LOCALS)
4414 init_locals = 1;
4415 else
4416 init_locals = 0;
4418 code = (unsigned char*)ptr;
4420 if (!(fat_flags & METHOD_HEADER_MORE_SECTS))
4421 break;
4424 * There are more sections
4426 ptr = (char*)code + code_size;
4427 break;
4428 default:
4429 mono_error_set_bad_image (error, m, "Invalid method header format %d", format);
4430 return NULL;
4433 if (local_var_sig_tok) {
4434 int idx = (local_var_sig_tok & 0xffffff)-1;
4435 if (idx >= t->rows || idx < 0) {
4436 mono_error_set_bad_image (error, m, "Invalid method header local vars signature token 0x%8x", idx);
4437 goto fail;
4439 mono_metadata_decode_row (t, idx, cols, 1);
4441 if (!mono_verifier_verify_standalone_signature (m, cols [MONO_STAND_ALONE_SIGNATURE], error))
4442 goto fail;
4444 if (fat_flags & METHOD_HEADER_MORE_SECTS) {
4445 clauses = parse_section_data (m, &num_clauses, (const unsigned char*)ptr, error);
4446 goto_if_nok (error, fail);
4448 if (local_var_sig_tok) {
4449 const char *locals_ptr;
4450 int len=0, i;
4452 locals_ptr = mono_metadata_blob_heap (m, cols [MONO_STAND_ALONE_SIGNATURE]);
4453 mono_metadata_decode_blob_size (locals_ptr, &locals_ptr);
4454 if (*locals_ptr != 0x07)
4455 g_warning ("wrong signature for locals blob");
4456 locals_ptr++;
4457 len = mono_metadata_decode_value (locals_ptr, &locals_ptr);
4458 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + len * sizeof (MonoType*) + num_clauses * sizeof (MonoExceptionClause));
4459 mh->num_locals = len;
4460 for (i = 0; i < len; ++i) {
4461 mh->locals [i] = mono_metadata_parse_type_internal (m, container, 0, TRUE, locals_ptr, &locals_ptr, error);
4462 goto_if_nok (error, fail);
4464 } else {
4465 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + num_clauses * sizeof (MonoExceptionClause));
4467 mh->code = code;
4468 mh->code_size = code_size;
4469 mh->max_stack = max_stack;
4470 mh->is_transient = TRUE;
4471 mh->init_locals = init_locals;
4472 if (clauses) {
4473 MonoExceptionClause* clausesp = (MonoExceptionClause*)&mh->locals [mh->num_locals];
4474 memcpy (clausesp, clauses, num_clauses * sizeof (MonoExceptionClause));
4475 g_free (clauses);
4476 mh->clauses = clausesp;
4477 mh->num_clauses = num_clauses;
4479 return mh;
4480 fail:
4481 g_free (clauses);
4482 g_free (mh);
4483 return NULL;
4488 * mono_metadata_parse_mh:
4489 * \param generic_context generics context
4490 * \param ptr pointer to the method header.
4492 * Decode the method header at \p ptr, including pointer to the IL code,
4493 * info about local variables and optional exception tables.
4495 * \returns a transient \c MonoMethodHeader allocated from the heap.
4497 MonoMethodHeader *
4498 mono_metadata_parse_mh (MonoImage *m, const char *ptr)
4500 ERROR_DECL (error);
4501 MonoMethodHeader *header = mono_metadata_parse_mh_full (m, NULL, ptr, error);
4502 mono_error_cleanup (error);
4503 return header;
4507 * mono_metadata_free_mh:
4508 * \param mh a method header
4510 * Free the memory allocated for the method header.
4512 void
4513 mono_metadata_free_mh (MonoMethodHeader *mh)
4515 int i;
4517 /* If it is not transient it means it's part of a wrapper method,
4518 * or a SRE-generated method, so the lifetime in that case is
4519 * dictated by the method's own lifetime
4521 if (mh && mh->is_transient) {
4522 for (i = 0; i < mh->num_locals; ++i)
4523 mono_metadata_free_type (mh->locals [i]);
4524 g_free (mh);
4529 * mono_method_header_get_code:
4530 * \param header a \c MonoMethodHeader pointer
4531 * \param code_size memory location for returning the code size
4532 * \param max_stack memory location for returning the max stack
4534 * Method header accessor to retreive info about the IL code properties:
4535 * a pointer to the IL code itself, the size of the code and the max number
4536 * of stack slots used by the code.
4538 * \returns pointer to the IL code represented by the method header.
4540 const unsigned char*
4541 mono_method_header_get_code (MonoMethodHeader *header, guint32* code_size, guint32* max_stack)
4543 if (code_size)
4544 *code_size = header->code_size;
4545 if (max_stack)
4546 *max_stack = header->max_stack;
4547 return header->code;
4551 * mono_method_header_get_locals:
4552 * \param header a \c MonoMethodHeader pointer
4553 * \param num_locals memory location for returning the number of local variables
4554 * \param init_locals memory location for returning the init_locals flag
4556 * Method header accessor to retreive info about the local variables:
4557 * an array of local types, the number of locals and whether the locals
4558 * are supposed to be initialized to 0 on method entry
4560 * \returns pointer to an array of types of the local variables
4562 MonoType**
4563 mono_method_header_get_locals (MonoMethodHeader *header, guint32* num_locals, gboolean *init_locals)
4565 if (num_locals)
4566 *num_locals = header->num_locals;
4567 if (init_locals)
4568 *init_locals = header->init_locals;
4569 return header->locals;
4573 * mono_method_header_get_num_clauses:
4574 * @header: a MonoMethodHeader pointer
4576 * Method header accessor to retreive the number of exception clauses.
4578 * Returns: the number of exception clauses present
4581 mono_method_header_get_num_clauses (MonoMethodHeader *header)
4583 return header->num_clauses;
4587 * mono_method_header_get_clauses:
4588 * \param header a \c MonoMethodHeader pointer
4589 * \param method \c MonoMethod the header belongs to
4590 * \param iter pointer to a iterator
4591 * \param clause pointer to a \c MonoExceptionClause structure which will be filled with the info
4593 * Get the info about the exception clauses in the method. Set \c *iter to NULL to
4594 * initiate the iteration, then call the method repeatedly until it returns FALSE.
4595 * At each iteration, the structure pointed to by clause if filled with the
4596 * exception clause information.
4598 * \returns TRUE if clause was filled with info, FALSE if there are no more exception
4599 * clauses.
4602 mono_method_header_get_clauses (MonoMethodHeader *header, MonoMethod *method, gpointer *iter, MonoExceptionClause *clause)
4604 MonoExceptionClause *sc;
4605 /* later we'll be able to use this interface to parse the clause info on demand,
4606 * without allocating anything.
4608 if (!iter || !header->num_clauses)
4609 return FALSE;
4610 if (!*iter) {
4611 *iter = sc = header->clauses;
4612 *clause = *sc;
4613 return TRUE;
4615 sc = (MonoExceptionClause *)*iter;
4616 sc++;
4617 if (sc < header->clauses + header->num_clauses) {
4618 *iter = sc;
4619 *clause = *sc;
4620 return TRUE;
4622 return FALSE;
4626 * mono_metadata_parse_field_type:
4627 * \param m metadata context to extract information from
4628 * \param ptr pointer to the field signature
4629 * \param rptr pointer updated to match the end of the decoded stream
4631 * Parses the field signature, and returns the type information for it.
4633 * \returns The \c MonoType that was extracted from \p ptr .
4635 MonoType *
4636 mono_metadata_parse_field_type (MonoImage *m, short field_flags, const char *ptr, const char **rptr)
4638 ERROR_DECL (error);
4639 MonoType * type = mono_metadata_parse_type_internal (m, NULL, field_flags, FALSE, ptr, rptr, error);
4640 mono_error_cleanup (error);
4641 return type;
4645 * mono_metadata_parse_param:
4646 * \param m metadata context to extract information from
4647 * \param ptr pointer to the param signature
4648 * \param rptr pointer updated to match the end of the decoded stream
4650 * Parses the param signature, and returns the type information for it.
4652 * \returns The \c MonoType that was extracted from \p ptr .
4654 MonoType *
4655 mono_metadata_parse_param (MonoImage *m, const char *ptr, const char **rptr)
4657 ERROR_DECL (error);
4658 MonoType * type = mono_metadata_parse_type_internal (m, NULL, 0, FALSE, ptr, rptr, error);
4659 mono_error_cleanup (error);
4660 return type;
4664 * mono_metadata_token_from_dor:
4665 * \param dor_token A \c TypeDefOrRef coded index
4667 * \p dor_token is a \c TypeDefOrRef coded index: it contains either
4668 * a \c TypeDef, \c TypeRef or \c TypeSpec in the lower bits, and the upper
4669 * bits contain an index into the table.
4671 * \returns an expanded token
4673 guint32
4674 mono_metadata_token_from_dor (guint32 dor_index)
4676 guint32 table, idx;
4678 table = dor_index & 0x03;
4679 idx = dor_index >> 2;
4681 switch (table){
4682 case 0: /* TypeDef */
4683 return MONO_TOKEN_TYPE_DEF | idx;
4684 case 1: /* TypeRef */
4685 return MONO_TOKEN_TYPE_REF | idx;
4686 case 2: /* TypeSpec */
4687 return MONO_TOKEN_TYPE_SPEC | idx;
4688 default:
4689 g_assert_not_reached ();
4692 return 0;
4696 * We use this to pass context information to the row locator
4698 typedef struct {
4699 int idx; /* The index that we are trying to locate */
4700 int col_idx; /* The index in the row where idx may be stored */
4701 MonoTableInfo *t; /* pointer to the table */
4702 guint32 result;
4703 } locator_t;
4706 * How the row locator works.
4708 * Table A
4709 * ___|___
4710 * ___|___ Table B
4711 * ___|___------> _______
4712 * ___|___ _______
4714 * A column in the rows of table A references an index in table B.
4715 * For example A may be the TYPEDEF table and B the METHODDEF table.
4717 * Given an index in table B we want to get the row in table A
4718 * where the column n references our index in B.
4720 * In the locator_t structure:
4721 * t is table A
4722 * col_idx is the column number
4723 * index is the index in table B
4724 * result will be the index in table A
4726 * Examples:
4727 * Table A Table B column (in table A)
4728 * TYPEDEF METHODDEF MONO_TYPEDEF_METHOD_LIST
4729 * TYPEDEF FIELD MONO_TYPEDEF_FIELD_LIST
4730 * PROPERTYMAP PROPERTY MONO_PROPERTY_MAP_PROPERTY_LIST
4731 * INTERFIMPL TYPEDEF MONO_INTERFACEIMPL_CLASS
4732 * METHODSEM PROPERTY ASSOCIATION (encoded index)
4734 * Note that we still don't support encoded indexes.
4737 static int
4738 typedef_locator (const void *a, const void *b)
4740 locator_t *loc = (locator_t *) a;
4741 const char *bb = (const char *) b;
4742 int typedef_index = (bb - loc->t->base) / loc->t->row_size;
4743 guint32 col, col_next;
4745 col = mono_metadata_decode_row_col (loc->t, typedef_index, loc->col_idx);
4747 if (loc->idx < col)
4748 return -1;
4751 * Need to check that the next row is valid.
4753 if (typedef_index + 1 < loc->t->rows) {
4754 col_next = mono_metadata_decode_row_col (loc->t, typedef_index + 1, loc->col_idx);
4755 if (loc->idx >= col_next)
4756 return 1;
4758 if (col == col_next)
4759 return 1;
4762 loc->result = typedef_index;
4764 return 0;
4767 static int
4768 table_locator (const void *a, const void *b)
4770 locator_t *loc = (locator_t *) a;
4771 const char *bb = (const char *) b;
4772 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4773 guint32 col;
4775 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4777 if (loc->idx == col) {
4778 loc->result = table_index;
4779 return 0;
4781 if (loc->idx < col)
4782 return -1;
4783 else
4784 return 1;
4787 static int
4788 declsec_locator (const void *a, const void *b)
4790 locator_t *loc = (locator_t *) a;
4791 const char *bb = (const char *) b;
4792 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4793 guint32 col;
4795 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4797 if (loc->idx == col) {
4798 loc->result = table_index;
4799 return 0;
4801 if (loc->idx < col)
4802 return -1;
4803 else
4804 return 1;
4808 * search_ptr_table:
4810 * Return the 1-based row index in TABLE, which must be one of the *Ptr tables,
4811 * which contains IDX.
4813 static guint32
4814 search_ptr_table (MonoImage *image, int table, int idx)
4816 MonoTableInfo *ptrdef = &image->tables [table];
4817 int i;
4819 /* Use a linear search to find our index in the table */
4820 for (i = 0; i < ptrdef->rows; i ++)
4821 /* All the Ptr tables have the same structure */
4822 if (mono_metadata_decode_row_col (ptrdef, i, 0) == idx)
4823 break;
4825 if (i < ptrdef->rows)
4826 return i + 1;
4827 else
4828 return idx;
4832 * mono_metadata_typedef_from_field:
4833 * \param meta metadata context
4834 * \param index FieldDef token
4836 * \returns the 1-based index into the \c TypeDef table of the type that
4837 * declared the field described by \p index, or 0 if not found.
4839 guint32
4840 mono_metadata_typedef_from_field (MonoImage *meta, guint32 index)
4842 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4843 locator_t loc;
4845 if (!tdef->base)
4846 return 0;
4848 loc.idx = mono_metadata_token_index (index);
4849 loc.col_idx = MONO_TYPEDEF_FIELD_LIST;
4850 loc.t = tdef;
4852 if (meta->uncompressed_metadata)
4853 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
4855 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4856 return 0;
4858 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4859 return loc.result + 1;
4863 * mono_metadata_typedef_from_method:
4864 * \param meta metadata context
4865 * \param index \c MethodDef token
4866 * \returns the 1-based index into the \c TypeDef table of the type that
4867 * declared the method described by \p index. 0 if not found.
4869 guint32
4870 mono_metadata_typedef_from_method (MonoImage *meta, guint32 index)
4872 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4873 locator_t loc;
4875 if (!tdef->base)
4876 return 0;
4878 loc.idx = mono_metadata_token_index (index);
4879 loc.col_idx = MONO_TYPEDEF_METHOD_LIST;
4880 loc.t = tdef;
4882 if (meta->uncompressed_metadata)
4883 loc.idx = search_ptr_table (meta, MONO_TABLE_METHOD_POINTER, loc.idx);
4885 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4886 return 0;
4888 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4889 return loc.result + 1;
4893 * mono_metadata_interfaces_from_typedef_full:
4894 * \param meta metadata context
4895 * \param index typedef token
4896 * \param interfaces Out parameter used to store the interface array
4897 * \param count Out parameter used to store the number of interfaces
4898 * \param heap_alloc_result if TRUE the result array will be \c g_malloc'd
4899 * \param context The generic context
4900 * \param error set on error
4902 * The array of interfaces that the \p index typedef token implements is returned in
4903 * \p interfaces. The number of elements in the array is returned in \p count.
4905 * \returns \c TRUE on success, \c FALSE on failure and sets \p error.
4907 gboolean
4908 mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, MonoClass ***interfaces, guint *count, gboolean heap_alloc_result, MonoGenericContext *context, MonoError *error)
4910 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_INTERFACEIMPL];
4911 locator_t loc;
4912 guint32 start, pos;
4913 guint32 cols [MONO_INTERFACEIMPL_SIZE];
4914 MonoClass **result;
4916 *interfaces = NULL;
4917 *count = 0;
4919 error_init (error);
4921 if (!tdef->base)
4922 return TRUE;
4924 loc.idx = mono_metadata_token_index (index);
4925 loc.col_idx = MONO_INTERFACEIMPL_CLASS;
4926 loc.t = tdef;
4928 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4929 return TRUE;
4931 start = loc.result;
4933 * We may end up in the middle of the rows...
4935 while (start > 0) {
4936 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_INTERFACEIMPL_CLASS))
4937 start--;
4938 else
4939 break;
4941 pos = start;
4942 while (pos < tdef->rows) {
4943 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4944 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4945 break;
4946 ++pos;
4949 if (heap_alloc_result)
4950 result = g_new0 (MonoClass*, pos - start);
4951 else
4952 result = (MonoClass **)mono_image_alloc0 (meta, sizeof (MonoClass*) * (pos - start));
4954 pos = start;
4955 while (pos < tdef->rows) {
4956 MonoClass *iface;
4958 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4959 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4960 break;
4961 iface = mono_class_get_and_inflate_typespec_checked (
4962 meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context, error);
4963 if (iface == NULL)
4964 return FALSE;
4965 result [pos - start] = iface;
4966 ++pos;
4968 *count = pos - start;
4969 *interfaces = result;
4970 return TRUE;
4974 * mono_metadata_interfaces_from_typedef:
4975 * \param meta metadata context
4976 * \param index typedef token
4977 * \param count Out parameter used to store the number of interfaces
4979 * The array of interfaces that the \p index typedef token implements is returned in
4980 * \p interfaces. The number of elements in the array is returned in \p count. The returned
4981 * array is allocated with \c g_malloc and the caller must free it.
4983 * LOCKING: Acquires the loader lock .
4985 * \returns the interface array on success, NULL on failure.
4987 MonoClass**
4988 mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *count)
4990 ERROR_DECL (error);
4991 MonoClass **interfaces = NULL;
4992 gboolean rv;
4994 rv = mono_metadata_interfaces_from_typedef_full (meta, index, &interfaces, count, TRUE, NULL, error);
4995 mono_error_assert_ok (error);
4996 if (rv)
4997 return interfaces;
4998 else
4999 return NULL;
5003 * mono_metadata_nested_in_typedef:
5004 * \param meta metadata context
5005 * \param index typedef token
5006 * \returns the 1-based index into the TypeDef table of the type
5007 * where the type described by \p index is nested.
5008 * Returns 0 if \p index describes a non-nested type.
5010 guint32
5011 mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index)
5013 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
5014 locator_t loc;
5016 if (!tdef->base)
5017 return 0;
5019 loc.idx = mono_metadata_token_index (index);
5020 loc.col_idx = MONO_NESTED_CLASS_NESTED;
5021 loc.t = tdef;
5023 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5024 return 0;
5026 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5027 return mono_metadata_decode_row_col (tdef, loc.result, MONO_NESTED_CLASS_ENCLOSING) | MONO_TOKEN_TYPE_DEF;
5031 * mono_metadata_nesting_typedef:
5032 * \param meta metadata context
5033 * \param index typedef token
5034 * \returns the 1-based index into the \c TypeDef table of the first type
5035 * that is nested inside the type described by \p index. The search starts at
5036 * \p start_index. Returns 0 if no such type is found.
5038 guint32
5039 mono_metadata_nesting_typedef (MonoImage *meta, guint32 index, guint32 start_index)
5041 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
5042 guint32 start;
5043 guint32 class_index = mono_metadata_token_index (index);
5045 if (!tdef->base)
5046 return 0;
5048 start = start_index;
5050 while (start <= tdef->rows) {
5051 if (class_index == mono_metadata_decode_row_col (tdef, start - 1, MONO_NESTED_CLASS_ENCLOSING))
5052 break;
5053 else
5054 start++;
5057 if (start > tdef->rows)
5058 return 0;
5059 else
5060 return start;
5064 * mono_metadata_packing_from_typedef:
5065 * \param meta metadata context
5066 * \param index token representing a type
5067 * \returns the info stored in the \c ClassLayout table for the given typedef token
5068 * into the \p packing and \p size pointers.
5069 * Returns 0 if the info is not found.
5071 guint32
5072 mono_metadata_packing_from_typedef (MonoImage *meta, guint32 index, guint32 *packing, guint32 *size)
5074 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CLASSLAYOUT];
5075 locator_t loc;
5076 guint32 cols [MONO_CLASS_LAYOUT_SIZE];
5078 if (!tdef->base)
5079 return 0;
5081 loc.idx = mono_metadata_token_index (index);
5082 loc.col_idx = MONO_CLASS_LAYOUT_PARENT;
5083 loc.t = tdef;
5085 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5086 return 0;
5088 mono_metadata_decode_row (tdef, loc.result, cols, MONO_CLASS_LAYOUT_SIZE);
5089 if (packing)
5090 *packing = cols [MONO_CLASS_LAYOUT_PACKING_SIZE];
5091 if (size)
5092 *size = cols [MONO_CLASS_LAYOUT_CLASS_SIZE];
5094 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5095 return loc.result + 1;
5099 * mono_metadata_custom_attrs_from_index:
5100 * \param meta metadata context
5101 * \param index token representing the parent
5102 * \returns: the 1-based index into the \c CustomAttribute table of the first
5103 * attribute which belongs to the metadata object described by \p index.
5104 * Returns 0 if no such attribute is found.
5106 guint32
5107 mono_metadata_custom_attrs_from_index (MonoImage *meta, guint32 index)
5109 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CUSTOMATTRIBUTE];
5110 locator_t loc;
5112 if (!tdef->base)
5113 return 0;
5115 loc.idx = index;
5116 loc.col_idx = MONO_CUSTOM_ATTR_PARENT;
5117 loc.t = tdef;
5119 /* FIXME: Index translation */
5121 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5122 return 0;
5124 /* Find the first entry by searching backwards */
5125 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_CUSTOM_ATTR_PARENT) == index))
5126 loc.result --;
5128 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5129 return loc.result + 1;
5133 * mono_metadata_declsec_from_index:
5134 * \param meta metadata context
5135 * \param index token representing the parent
5136 * \returns the 0-based index into the \c DeclarativeSecurity table of the first
5137 * attribute which belongs to the metadata object described by \p index.
5138 * Returns \c -1 if no such attribute is found.
5140 guint32
5141 mono_metadata_declsec_from_index (MonoImage *meta, guint32 index)
5143 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_DECLSECURITY];
5144 locator_t loc;
5146 if (!tdef->base)
5147 return -1;
5149 loc.idx = index;
5150 loc.col_idx = MONO_DECL_SECURITY_PARENT;
5151 loc.t = tdef;
5153 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, declsec_locator))
5154 return -1;
5156 /* Find the first entry by searching backwards */
5157 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_DECL_SECURITY_PARENT) == index))
5158 loc.result --;
5160 return loc.result;
5164 * mono_metadata_localscope_from_methoddef:
5165 * @meta: metadata context
5166 * @index: methoddef index
5168 * Returns: the 1-based index into the LocalScope table of the first
5169 * scope which belongs to the method described by @index.
5170 * Returns 0 if no such row is found.
5172 guint32
5173 mono_metadata_localscope_from_methoddef (MonoImage *meta, guint32 index)
5175 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_LOCALSCOPE];
5176 locator_t loc;
5178 if (!tdef->base)
5179 return 0;
5181 loc.idx = index;
5182 loc.col_idx = MONO_LOCALSCOPE_METHOD;
5183 loc.t = tdef;
5185 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5186 return 0;
5188 /* Find the first entry by searching backwards */
5189 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_LOCALSCOPE_METHOD) == index))
5190 loc.result --;
5192 return loc.result + 1;
5195 #ifdef DEBUG
5196 static void
5197 mono_backtrace (int limit)
5199 void *array[limit];
5200 char **names;
5201 int i;
5202 backtrace (array, limit);
5203 names = backtrace_symbols (array, limit);
5204 for (i =0; i < limit; ++i) {
5205 g_print ("\t%s\n", names [i]);
5207 g_free (names);
5209 #endif
5211 static int i8_align;
5214 * mono_type_set_alignment:
5216 * Set the alignment used by runtime to layout fields etc. of type TYPE to ALIGN.
5217 * This should only be used in AOT mode since the resulting layout will not match the
5218 * host abi layout.
5220 void
5221 mono_type_set_alignment (MonoTypeEnum type, int align)
5223 /* Support only a few types whose alignment is abi dependent */
5224 switch (type) {
5225 case MONO_TYPE_I8:
5226 i8_align = align;
5227 break;
5228 default:
5229 g_assert_not_reached ();
5230 break;
5235 * mono_type_size:
5236 * \param t the type to return the size of
5237 * \returns The number of bytes required to hold an instance of this
5238 * type in memory
5241 mono_type_size (MonoType *t, int *align)
5243 MonoTypeEnum simple_type;
5245 if (!t) {
5246 *align = 1;
5247 return 0;
5249 if (t->byref) {
5250 *align = MONO_ABI_ALIGNOF (gpointer);
5251 return MONO_ABI_SIZEOF (gpointer);
5254 simple_type = t->type;
5255 again:
5256 switch (simple_type) {
5257 case MONO_TYPE_VOID:
5258 *align = 1;
5259 return 0;
5260 case MONO_TYPE_BOOLEAN:
5261 *align = MONO_ABI_ALIGNOF (gint8);
5262 return 1;
5263 case MONO_TYPE_I1:
5264 case MONO_TYPE_U1:
5265 *align = MONO_ABI_ALIGNOF (gint8);
5266 return 1;
5267 case MONO_TYPE_CHAR:
5268 case MONO_TYPE_I2:
5269 case MONO_TYPE_U2:
5270 *align = MONO_ABI_ALIGNOF (gint16);
5271 return 2;
5272 case MONO_TYPE_I4:
5273 case MONO_TYPE_U4:
5274 *align = MONO_ABI_ALIGNOF (gint32);
5275 return 4;
5276 case MONO_TYPE_R4:
5277 *align = MONO_ABI_ALIGNOF (float);
5278 return 4;
5279 case MONO_TYPE_I8:
5280 case MONO_TYPE_U8:
5281 *align = MONO_ABI_ALIGNOF (gint64);
5282 return 8;
5283 case MONO_TYPE_R8:
5284 *align = MONO_ABI_ALIGNOF (double);
5285 return 8;
5286 case MONO_TYPE_I:
5287 case MONO_TYPE_U:
5288 *align = MONO_ABI_ALIGNOF (gpointer);
5289 return MONO_ABI_SIZEOF (gpointer);
5290 case MONO_TYPE_VALUETYPE: {
5291 if (m_class_is_enumtype (t->data.klass))
5292 return mono_type_size (mono_class_enum_basetype_internal (t->data.klass), align);
5293 else
5294 return mono_class_value_size (t->data.klass, (guint32*)align);
5296 case MONO_TYPE_STRING:
5297 case MONO_TYPE_OBJECT:
5298 case MONO_TYPE_CLASS:
5299 case MONO_TYPE_SZARRAY:
5300 case MONO_TYPE_PTR:
5301 case MONO_TYPE_FNPTR:
5302 case MONO_TYPE_ARRAY:
5303 *align = MONO_ABI_ALIGNOF (gpointer);
5304 return MONO_ABI_SIZEOF (gpointer);
5305 case MONO_TYPE_TYPEDBYREF:
5306 return mono_class_value_size (mono_defaults.typed_reference_class, (guint32*)align);
5307 case MONO_TYPE_GENERICINST: {
5308 MonoGenericClass *gclass = t->data.generic_class;
5309 MonoClass *container_class = gclass->container_class;
5311 // g_assert (!gclass->inst->is_open);
5313 if (m_class_is_valuetype (container_class)) {
5314 if (m_class_is_enumtype (container_class))
5315 return mono_type_size (mono_class_enum_basetype_internal (container_class), align);
5316 else
5317 return mono_class_value_size (mono_class_from_mono_type_internal (t), (guint32*)align);
5318 } else {
5319 *align = MONO_ABI_ALIGNOF (gpointer);
5320 return MONO_ABI_SIZEOF (gpointer);
5323 case MONO_TYPE_VAR:
5324 case MONO_TYPE_MVAR:
5325 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
5326 *align = MONO_ABI_ALIGNOF (gpointer);
5327 return MONO_ABI_SIZEOF (gpointer);
5328 } else {
5329 /* The gparam can only match types given by gshared_constraint */
5330 return mono_type_size (t->data.generic_param->gshared_constraint, align);
5331 goto again;
5333 default:
5334 g_error ("mono_type_size: type 0x%02x unknown", t->type);
5336 return 0;
5340 * mono_type_stack_size:
5341 * \param t the type to return the size it uses on the stack
5342 * \returns The number of bytes required to hold an instance of this
5343 * type on the runtime stack
5346 mono_type_stack_size (MonoType *t, int *align)
5348 return mono_type_stack_size_internal (t, align, FALSE);
5352 mono_type_stack_size_internal (MonoType *t, int *align, gboolean allow_open)
5354 int tmp;
5355 MonoTypeEnum simple_type;
5356 int stack_slot_size = TARGET_SIZEOF_VOID_P;
5357 int stack_slot_align = TARGET_SIZEOF_VOID_P;
5359 g_assert (t != NULL);
5361 if (!align)
5362 align = &tmp;
5364 if (t->byref) {
5365 *align = stack_slot_align;
5366 return stack_slot_size;
5369 simple_type = t->type;
5370 switch (simple_type) {
5371 case MONO_TYPE_BOOLEAN:
5372 case MONO_TYPE_CHAR:
5373 case MONO_TYPE_I1:
5374 case MONO_TYPE_U1:
5375 case MONO_TYPE_I2:
5376 case MONO_TYPE_U2:
5377 case MONO_TYPE_I4:
5378 case MONO_TYPE_U4:
5379 case MONO_TYPE_I:
5380 case MONO_TYPE_U:
5381 case MONO_TYPE_STRING:
5382 case MONO_TYPE_OBJECT:
5383 case MONO_TYPE_CLASS:
5384 case MONO_TYPE_SZARRAY:
5385 case MONO_TYPE_PTR:
5386 case MONO_TYPE_FNPTR:
5387 case MONO_TYPE_ARRAY:
5388 *align = stack_slot_align;
5389 return stack_slot_size;
5390 case MONO_TYPE_VAR:
5391 case MONO_TYPE_MVAR:
5392 g_assert (allow_open);
5393 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
5394 *align = stack_slot_align;
5395 return stack_slot_size;
5396 } else {
5397 /* The gparam can only match types given by gshared_constraint */
5398 return mono_type_stack_size_internal (t->data.generic_param->gshared_constraint, align, allow_open);
5400 case MONO_TYPE_TYPEDBYREF:
5401 *align = stack_slot_align;
5402 return stack_slot_size * 3;
5403 case MONO_TYPE_R4:
5404 *align = MONO_ABI_ALIGNOF (float);
5405 return sizeof (float);
5406 case MONO_TYPE_I8:
5407 case MONO_TYPE_U8:
5408 *align = MONO_ABI_ALIGNOF (gint64);
5409 return sizeof (gint64);
5410 case MONO_TYPE_R8:
5411 *align = MONO_ABI_ALIGNOF (double);
5412 return sizeof (double);
5413 case MONO_TYPE_VALUETYPE: {
5414 guint32 size;
5416 if (m_class_is_enumtype (t->data.klass))
5417 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (t->data.klass), align, allow_open);
5418 else {
5419 size = mono_class_value_size (t->data.klass, (guint32*)align);
5421 *align = *align + stack_slot_align - 1;
5422 *align &= ~(stack_slot_align - 1);
5424 size += stack_slot_size - 1;
5425 size &= ~(stack_slot_size - 1);
5427 return size;
5430 case MONO_TYPE_GENERICINST: {
5431 MonoGenericClass *gclass = t->data.generic_class;
5432 MonoClass *container_class = gclass->container_class;
5434 if (!allow_open)
5435 g_assert (!gclass->context.class_inst->is_open);
5437 if (m_class_is_valuetype (container_class)) {
5438 if (m_class_is_enumtype (container_class))
5439 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (container_class), align, allow_open);
5440 else {
5441 guint32 size = mono_class_value_size (mono_class_from_mono_type_internal (t), (guint32*)align);
5443 *align = *align + stack_slot_align - 1;
5444 *align &= ~(stack_slot_align - 1);
5446 size += stack_slot_size - 1;
5447 size &= ~(stack_slot_size - 1);
5449 return size;
5451 } else {
5452 *align = stack_slot_align;
5453 return stack_slot_size;
5456 default:
5457 g_error ("type 0x%02x unknown", t->type);
5459 return 0;
5462 gboolean
5463 mono_type_generic_inst_is_valuetype (MonoType *type)
5465 g_assert (type->type == MONO_TYPE_GENERICINST);
5466 return m_class_is_valuetype (type->data.generic_class->container_class);
5470 * mono_metadata_generic_class_is_valuetype:
5472 gboolean
5473 mono_metadata_generic_class_is_valuetype (MonoGenericClass *gclass)
5475 return m_class_is_valuetype (gclass->container_class);
5478 static gboolean
5479 _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only)
5481 MonoGenericInst *i1 = g1->context.class_inst;
5482 MonoGenericInst *i2 = g2->context.class_inst;
5484 if (g1->is_dynamic != g2->is_dynamic)
5485 return FALSE;
5486 if (!mono_metadata_class_equal (g1->container_class, g2->container_class, signature_only))
5487 return FALSE;
5488 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5489 return FALSE;
5490 return g1->is_tb_open == g2->is_tb_open;
5493 static gboolean
5494 _mono_metadata_generic_class_container_equal (const MonoGenericClass *g1, MonoClass *c2, gboolean signature_only)
5496 MonoGenericInst *i1 = g1->context.class_inst;
5497 MonoGenericInst *i2 = mono_class_get_generic_container (c2)->context.class_inst;
5499 if (!mono_metadata_class_equal (g1->container_class, c2, signature_only))
5500 return FALSE;
5501 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5502 return FALSE;
5503 return !g1->is_tb_open;
5506 guint
5507 mono_metadata_generic_context_hash (const MonoGenericContext *context)
5509 /* FIXME: check if this seed is good enough */
5510 guint hash = 0xc01dfee7;
5511 if (context->class_inst)
5512 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->class_inst);
5513 if (context->method_inst)
5514 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->method_inst);
5515 return hash;
5518 gboolean
5519 mono_metadata_generic_context_equal (const MonoGenericContext *g1, const MonoGenericContext *g2)
5521 return g1->class_inst == g2->class_inst && g1->method_inst == g2->method_inst;
5525 * mono_metadata_str_hash:
5527 * This should be used instead of g_str_hash for computing hash codes visible
5528 * outside this module, since g_str_hash () is not guaranteed to be stable
5529 * (its not the same in eglib for example).
5531 guint
5532 mono_metadata_str_hash (gconstpointer v1)
5534 /* Same as g_str_hash () in glib */
5535 /* note: signed/unsigned char matters - we feed UTF-8 to this function, so the high bit will give diferent results if we don't match. */
5536 unsigned char *p = (unsigned char *) v1;
5537 guint hash = *p;
5539 while (*p++) {
5540 if (*p)
5541 hash = (hash << 5) - hash + *p;
5544 return hash;
5548 * mono_metadata_type_hash:
5549 * \param t1 a type
5550 * Computes a hash value for \p t1 to be used in \c GHashTable.
5551 * The returned hash is guaranteed to be the same across executions.
5553 guint
5554 mono_metadata_type_hash (MonoType *t1)
5556 guint hash = t1->type;
5558 hash |= t1->byref << 6; /* do not collide with t1->type values */
5559 switch (t1->type) {
5560 case MONO_TYPE_VALUETYPE:
5561 case MONO_TYPE_CLASS:
5562 case MONO_TYPE_SZARRAY: {
5563 MonoClass *klass = t1->data.klass;
5565 * Dynamic classes must not be hashed on their type since it can change
5566 * during runtime. For example, if we hash a reference type that is
5567 * later made into a valuetype.
5569 * This is specially problematic with generic instances since they are
5570 * inserted in a bunch of hash tables before been finished.
5572 if (image_is_dynamic (m_class_get_image (klass)))
5573 return (t1->byref << 6) | mono_metadata_str_hash (m_class_get_name (klass));
5574 return ((hash << 5) - hash) ^ mono_metadata_str_hash (m_class_get_name (klass));
5576 case MONO_TYPE_PTR:
5577 return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
5578 case MONO_TYPE_ARRAY:
5579 return ((hash << 5) - hash) ^ mono_metadata_type_hash (m_class_get_byval_arg (t1->data.array->eklass));
5580 case MONO_TYPE_GENERICINST:
5581 return ((hash << 5) - hash) ^ mono_generic_class_hash (t1->data.generic_class);
5582 case MONO_TYPE_VAR:
5583 case MONO_TYPE_MVAR:
5584 return ((hash << 5) - hash) ^ mono_metadata_generic_param_hash (t1->data.generic_param);
5585 default:
5586 return hash;
5590 guint
5591 mono_metadata_generic_param_hash (MonoGenericParam *p)
5593 guint hash;
5594 MonoGenericParamInfo *info;
5596 hash = (mono_generic_param_num (p) << 2);
5597 if (p->gshared_constraint)
5598 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->gshared_constraint);
5599 info = mono_generic_param_info (p);
5600 /* Can't hash on the owner klass/method, since those might not be set when this is called */
5601 if (!p->owner->is_anonymous)
5602 hash = ((hash << 5) - hash) ^ info->token;
5603 return hash;
5606 static gboolean
5607 mono_metadata_generic_param_equal_internal (MonoGenericParam *p1, MonoGenericParam *p2, gboolean signature_only)
5609 if (p1 == p2)
5610 return TRUE;
5611 if (mono_generic_param_num (p1) != mono_generic_param_num (p2))
5612 return FALSE;
5613 if (p1->gshared_constraint && p2->gshared_constraint) {
5614 if (!mono_metadata_type_equal (p1->gshared_constraint, p2->gshared_constraint))
5615 return FALSE;
5616 } else {
5617 if (p1->gshared_constraint != p2->gshared_constraint)
5618 return FALSE;
5622 * We have to compare the image as well because if we didn't,
5623 * the generic_inst_cache lookup wouldn't care about the image
5624 * of generic params, so what could happen is that a generic
5625 * inst with params from image A is put into the cache, then
5626 * image B gets that generic inst from the cache, image A is
5627 * unloaded, so the inst is deleted, but image B still retains
5628 * a pointer to it.
5630 if (mono_generic_param_owner (p1) == mono_generic_param_owner (p2))
5631 return TRUE;
5634 * If `signature_only' is true, we're comparing two (method) signatures.
5635 * In this case, the owner of two type parameters doesn't need to match.
5638 return signature_only;
5641 gboolean
5642 mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2)
5644 return mono_metadata_generic_param_equal_internal (p1, p2, TRUE);
5647 static gboolean
5648 mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only)
5650 if (c1 == c2)
5651 return TRUE;
5652 if (mono_class_is_ginst (c1) && mono_class_is_ginst (c2))
5653 return _mono_metadata_generic_class_equal (mono_class_get_generic_class (c1), mono_class_get_generic_class (c2), signature_only);
5654 if (mono_class_is_ginst (c1) && mono_class_is_gtd (c2))
5655 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c1), c2, signature_only);
5656 if (mono_class_is_gtd (c1) && mono_class_is_ginst (c2))
5657 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c2), c1, signature_only);
5658 MonoType *c1_type = m_class_get_byval_arg (c1);
5659 MonoType *c2_type = m_class_get_byval_arg (c2);
5660 if ((c1_type->type == MONO_TYPE_VAR) && (c2_type->type == MONO_TYPE_VAR))
5661 return mono_metadata_generic_param_equal_internal (
5662 c1_type->data.generic_param, c2_type->data.generic_param, signature_only);
5663 if ((c1_type->type == MONO_TYPE_MVAR) && (c2_type->type == MONO_TYPE_MVAR))
5664 return mono_metadata_generic_param_equal_internal (
5665 c1_type->data.generic_param, c2_type->data.generic_param, signature_only);
5666 if (signature_only &&
5667 (c1_type->type == MONO_TYPE_SZARRAY) && (c2_type->type == MONO_TYPE_SZARRAY))
5668 return mono_metadata_class_equal (c1_type->data.klass, c2_type->data.klass, signature_only);
5669 if (signature_only &&
5670 (c1_type->type == MONO_TYPE_ARRAY) && (c2_type->type == MONO_TYPE_ARRAY))
5671 return do_mono_metadata_type_equal (c1_type, c2_type, signature_only);
5672 return FALSE;
5675 static gboolean
5676 mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only)
5678 gpointer iter1 = 0, iter2 = 0;
5680 if (s1 == s2)
5681 return TRUE;
5682 if (s1->call_convention != s2->call_convention)
5683 return FALSE;
5684 if (s1->sentinelpos != s2->sentinelpos)
5685 return FALSE;
5686 if (s1->hasthis != s2->hasthis)
5687 return FALSE;
5688 if (s1->explicit_this != s2->explicit_this)
5689 return FALSE;
5690 if (! do_mono_metadata_type_equal (s1->ret, s2->ret, signature_only))
5691 return FALSE;
5692 if (s1->param_count != s2->param_count)
5693 return FALSE;
5695 while (TRUE) {
5696 MonoType *t1 = mono_signature_get_params (s1, &iter1);
5697 MonoType *t2 = mono_signature_get_params (s2, &iter2);
5699 if (t1 == NULL || t2 == NULL)
5700 return (t1 == t2);
5701 if (! do_mono_metadata_type_equal (t1, t2, signature_only))
5702 return FALSE;
5706 static gboolean
5707 mono_metadata_custom_modifiers_equal (MonoType *t1, MonoType *t2, gboolean signature_only)
5709 // ECMA 335, 7.1.1:
5710 // The CLI itself shall treat required and optional modifiers in the same manner.
5711 // Two signatures that differ only by the addition of a custom modifier
5712 // (required or optional) shall not be considered to match.
5713 int count = mono_type_custom_modifier_count (t1);
5714 if (count != mono_type_custom_modifier_count (t2))
5715 return FALSE;
5717 for (int i=0; i < count; i++) {
5718 // FIXME: propagate error to caller
5719 ERROR_DECL (error);
5720 gboolean cm1_required, cm2_required;
5722 MonoType *cm1_type = mono_type_get_custom_modifier (t1, i, &cm1_required, error);
5723 mono_error_assert_ok (error);
5724 MonoType *cm2_type = mono_type_get_custom_modifier (t2, i, &cm2_required, error);
5725 mono_error_assert_ok (error);
5727 if (cm1_required != cm2_required)
5728 return FALSE;
5730 if (!do_mono_metadata_type_equal (cm1_type, cm2_type, signature_only))
5731 return FALSE;
5733 return TRUE;
5737 * mono_metadata_type_equal:
5738 * @t1: a type
5739 * @t2: another type
5740 * @signature_only: If true, treat ginsts as equal which are instantiated separately but have equal positional value
5742 * Determine if @t1 and @t2 represent the same type.
5743 * Returns: #TRUE if @t1 and @t2 are equal.
5745 static gboolean
5746 do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only)
5748 if (t1->type != t2->type || t1->byref != t2->byref)
5749 return FALSE;
5751 gboolean cmod_reject = FALSE;
5753 if (t1->has_cmods != t2->has_cmods)
5754 cmod_reject = TRUE;
5755 else if (t1->has_cmods && t2->has_cmods) {
5756 cmod_reject = !mono_metadata_custom_modifiers_equal (t1, t2, signature_only);
5759 gboolean result = FALSE;
5761 switch (t1->type) {
5762 case MONO_TYPE_VOID:
5763 case MONO_TYPE_BOOLEAN:
5764 case MONO_TYPE_CHAR:
5765 case MONO_TYPE_I1:
5766 case MONO_TYPE_U1:
5767 case MONO_TYPE_I2:
5768 case MONO_TYPE_U2:
5769 case MONO_TYPE_I4:
5770 case MONO_TYPE_U4:
5771 case MONO_TYPE_I8:
5772 case MONO_TYPE_U8:
5773 case MONO_TYPE_R4:
5774 case MONO_TYPE_R8:
5775 case MONO_TYPE_STRING:
5776 case MONO_TYPE_I:
5777 case MONO_TYPE_U:
5778 case MONO_TYPE_OBJECT:
5779 case MONO_TYPE_TYPEDBYREF:
5780 result = TRUE;
5781 break;
5782 case MONO_TYPE_VALUETYPE:
5783 case MONO_TYPE_CLASS:
5784 case MONO_TYPE_SZARRAY:
5785 result = mono_metadata_class_equal (t1->data.klass, t2->data.klass, signature_only);
5786 break;
5787 case MONO_TYPE_PTR:
5788 result = do_mono_metadata_type_equal (t1->data.type, t2->data.type, signature_only);
5789 break;
5790 case MONO_TYPE_ARRAY:
5791 if (t1->data.array->rank != t2->data.array->rank)
5792 result = FALSE;
5793 else
5794 result = mono_metadata_class_equal (t1->data.array->eklass, t2->data.array->eklass, signature_only);
5795 break;
5796 case MONO_TYPE_GENERICINST:
5797 result = _mono_metadata_generic_class_equal (
5798 t1->data.generic_class, t2->data.generic_class, signature_only);
5799 break;
5800 case MONO_TYPE_VAR:
5801 result = mono_metadata_generic_param_equal_internal (
5802 t1->data.generic_param, t2->data.generic_param, signature_only);
5803 break;
5804 case MONO_TYPE_MVAR:
5805 result = mono_metadata_generic_param_equal_internal (
5806 t1->data.generic_param, t2->data.generic_param, signature_only);
5807 break;
5808 case MONO_TYPE_FNPTR:
5809 result = mono_metadata_fnptr_equal (t1->data.method, t2->data.method, signature_only);
5810 break;
5811 default:
5812 g_error ("implement type compare for %0x!", t1->type);
5813 return FALSE;
5816 return result && !cmod_reject;
5820 * mono_metadata_type_equal:
5822 gboolean
5823 mono_metadata_type_equal (MonoType *t1, MonoType *t2)
5825 return do_mono_metadata_type_equal (t1, t2, FALSE);
5829 * mono_metadata_type_equal_full:
5830 * \param t1 a type
5831 * \param t2 another type
5832 * \param signature_only if signature only comparison should be made
5834 * Determine if \p t1 and \p t2 are signature compatible if \p signature_only is TRUE, otherwise
5835 * behaves the same way as mono_metadata_type_equal.
5836 * The function mono_metadata_type_equal(a, b) is just a shortcut for mono_metadata_type_equal_full(a, b, FALSE).
5837 * \returns TRUE if \p t1 and \p t2 are equal taking \p signature_only into account.
5839 gboolean
5840 mono_metadata_type_equal_full (MonoType *t1, MonoType *t2, gboolean signature_only)
5842 return do_mono_metadata_type_equal (t1, t2, signature_only);
5846 * mono_metadata_signature_equal:
5847 * \param sig1 a signature
5848 * \param sig2 another signature
5850 * Determine if \p sig1 and \p sig2 represent the same signature, with the
5851 * same number of arguments and the same types.
5852 * \returns TRUE if \p sig1 and \p sig2 are equal.
5854 gboolean
5855 mono_metadata_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
5857 int i;
5859 if (sig1->hasthis != sig2->hasthis || sig1->param_count != sig2->param_count)
5860 return FALSE;
5862 if (sig1->generic_param_count != sig2->generic_param_count)
5863 return FALSE;
5866 * We're just comparing the signatures of two methods here:
5868 * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
5869 * U and V are equal here.
5871 * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
5874 for (i = 0; i < sig1->param_count; i++) {
5875 MonoType *p1 = sig1->params[i];
5876 MonoType *p2 = sig2->params[i];
5878 /* if (p1->attrs != p2->attrs)
5879 return FALSE;
5881 if (!do_mono_metadata_type_equal (p1, p2, TRUE))
5882 return FALSE;
5885 if (!do_mono_metadata_type_equal (sig1->ret, sig2->ret, TRUE))
5886 return FALSE;
5887 return TRUE;
5890 MonoType *
5891 mono_type_get_custom_modifier (const MonoType *ty, uint8_t idx, gboolean *required, MonoError *error)
5893 g_assert (ty->has_cmods);
5894 if (mono_type_is_aggregate_mods (ty)) {
5895 MonoAggregateModContainer *amods = mono_type_get_amods (ty);
5896 g_assert (idx < amods->count);
5897 MonoSingleCustomMod *cmod = &amods->modifiers [idx];
5898 if (required)
5899 *required = !!cmod->required;
5900 return cmod->type;
5901 } else {
5902 MonoCustomModContainer *cmods = mono_type_get_cmods (ty);
5903 g_assert (idx < cmods->count);
5904 MonoCustomMod *cmod = &cmods->modifiers [idx];
5905 if (required)
5906 *required = !!cmod->required;
5907 MonoImage *image = cmods->image;
5908 uint32_t token = cmod->token;
5909 return mono_type_get_checked (image, token, NULL, error);
5915 * mono_metadata_type_dup:
5916 * \param image image to alloc memory from
5917 * \param original type to duplicate
5918 * \returns copy of type allocated from the image's mempool (or from the heap, if \p image is null).
5920 MonoType *
5921 mono_metadata_type_dup (MonoImage *image, const MonoType *o)
5923 return mono_metadata_type_dup_with_cmods (image, o, o);
5926 static void
5927 deep_type_dup_fixup (MonoImage *image, MonoType *r, const MonoType *o);
5929 static uint8_t
5930 custom_modifier_copy (MonoAggregateModContainer *dest, uint8_t dest_offset, const MonoType *source)
5932 if (mono_type_is_aggregate_mods (source)) {
5933 MonoAggregateModContainer *src_cmods = mono_type_get_amods (source);
5934 memcpy (&dest->modifiers [dest_offset], &src_cmods->modifiers[0], src_cmods->count * sizeof (MonoSingleCustomMod));
5935 dest_offset += src_cmods->count;
5936 } else {
5937 MonoCustomModContainer *src_cmods = mono_type_get_cmods (source);
5938 for (int i = 0; i < src_cmods->count; i++) {
5939 ERROR_DECL (error); // XXX FIXME: AK - propagate the error to the caller.
5940 MonoSingleCustomMod *cmod = &dest->modifiers [dest_offset++];
5941 cmod->type = mono_type_get_checked (src_cmods->image, src_cmods->modifiers [i].token, NULL, error);
5942 mono_error_assert_ok (error);
5943 cmod->required = src_cmods->modifiers [i].required;
5946 return dest_offset;
5949 /* makes a dup of 'o' but also appends the custom modifiers from 'cmods_source' */
5950 static MonoType *
5951 do_metadata_type_dup_append_cmods (MonoImage *image, const MonoType *o, const MonoType *cmods_source)
5953 g_assert (o != cmods_source);
5954 g_assert (o->has_cmods);
5955 g_assert (cmods_source->has_cmods);
5956 if (!mono_type_is_aggregate_mods (o) &&
5957 !mono_type_is_aggregate_mods (cmods_source) &&
5958 mono_type_get_cmods (o)->image == mono_type_get_cmods (cmods_source)->image) {
5959 /* the uniform case: all the cmods are from the same image. */
5960 MonoCustomModContainer *o_cmods = mono_type_get_cmods (o);
5961 MonoCustomModContainer *extra_cmods = mono_type_get_cmods (cmods_source);
5962 uint8_t total_cmods = o_cmods->count + extra_cmods->count;
5963 gboolean aggregate = FALSE;
5964 size_t sizeof_dup = mono_sizeof_type_with_mods (total_cmods, aggregate);
5965 MonoType *r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_dup) : (MonoType *)g_malloc0 (sizeof_dup);
5967 mono_type_with_mods_init (r, total_cmods, aggregate);
5969 /* copy the original type o, not including its modifiers */
5970 memcpy (r, o, mono_sizeof_type_with_mods (0, FALSE));
5971 deep_type_dup_fixup (image, r, o);
5973 /* The modifier order matters to Roslyn, they expect the extra cmods to come first:
5975 * Suppose we substitute 'int32 modopt(IsLong)' for 'T' in 'void Test
5976 * (T modopt(IsConst))'. Roslyn expects the result to be 'void Test
5977 * (int32 modopt(IsLong) modopt(IsConst))'.
5979 * but! cmods are encoded in IL in reverse order, so 'int32 modopt(IsConst) modopt(IsLong)' is
5980 * encoded as `cmod_opt [typeref IsLong] cmod_opt [typeref IsConst] I4`
5981 * so in our array, extra_cmods (IsLong) come first, followed by o_cmods (IsConst)
5983 * (Here 'o' is 'int32 modopt(IsLong)' and cmods_source is 'T modopt(IsConst)')
5985 /* append the modifiers from cmods_source and o */
5986 MonoCustomModContainer *r_container = mono_type_get_cmods (r);
5987 uint8_t dest_offset = 0;
5988 r_container->image = extra_cmods->image;
5990 memcpy (&r_container->modifiers [dest_offset], &o_cmods->modifiers [0], o_cmods->count * sizeof (MonoCustomMod));
5991 dest_offset += o_cmods->count;
5992 memcpy (&r_container->modifiers [dest_offset], &extra_cmods->modifiers [0], extra_cmods->count * sizeof (MonoCustomMod));
5993 dest_offset += extra_cmods->count;
5994 g_assert (dest_offset == total_cmods);
5996 return r;
5997 } else {
5998 /* The aggregate case: either o_cmods or extra_cmods has aggregate cmods, or they're both simple but from different images. */
5999 uint8_t total_cmods = 0;
6000 total_cmods += mono_type_custom_modifier_count (o);
6001 total_cmods += mono_type_custom_modifier_count (cmods_source);
6003 gboolean aggregate = TRUE;
6004 size_t sizeof_dup = mono_sizeof_type_with_mods (total_cmods, aggregate);
6006 /* FIXME: if image, and the images of the custom modifiers from
6007 * o and cmods_source are all different, we need an image
6008 * set... */
6009 MonoType *r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_dup) : (MonoType*)g_malloc0 (sizeof_dup);
6011 mono_type_with_mods_init (r, total_cmods, aggregate);
6013 memcpy (r, o, mono_sizeof_type_with_mods (0, FALSE));
6014 deep_type_dup_fixup (image, r, o);
6016 /* Try not to blow up the stack. See comment on
6017 * MONO_MAX_EXPECTED_CMODS. Since here we're appending all the
6018 * mods together, it's possible we'll end up with more than the
6019 * maximum allowed. If that ever happens in practice, we
6020 * should redefine the bound and possibly make this function
6021 * fail dynamically instead of asserting.
6023 g_assert (total_cmods < MONO_MAX_EXPECTED_CMODS);
6024 size_t r_container_size = mono_sizeof_aggregate_modifiers (total_cmods);
6025 MonoAggregateModContainer *r_container_candidate = g_alloca (r_container_size);
6026 memset (r_container_candidate, 0, r_container_size);
6027 uint8_t dest_offset = 0;
6029 dest_offset = custom_modifier_copy (r_container_candidate, dest_offset, o);
6030 dest_offset = custom_modifier_copy (r_container_candidate, dest_offset, cmods_source);
6031 g_assert (dest_offset == total_cmods);
6032 r_container_candidate->count = total_cmods;
6034 mono_type_set_amods (r, mono_metadata_get_canonical_aggregate_modifiers (r_container_candidate));
6036 return r;
6041 * Works the same way as mono_metadata_type_dup but pick cmods from @cmods_source
6043 MonoType *
6044 mono_metadata_type_dup_with_cmods (MonoImage *image, const MonoType *o, const MonoType *cmods_source)
6046 if (o->has_cmods && o != cmods_source && cmods_source->has_cmods) {
6047 return do_metadata_type_dup_append_cmods (image, o, cmods_source);
6050 MonoType *r = NULL;
6052 /* if we get here, either o and cmods_source alias, or else exactly one of them has cmods. */
6054 uint8_t num_mods = MAX (mono_type_custom_modifier_count (o), mono_type_custom_modifier_count (cmods_source));
6055 gboolean aggregate = mono_type_is_aggregate_mods (o) || mono_type_is_aggregate_mods (cmods_source);
6056 size_t sizeof_r = mono_sizeof_type_with_mods (num_mods, aggregate);
6058 r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_r) : (MonoType *)g_malloc0 (sizeof_r);
6060 if (cmods_source->has_cmods) {
6061 /* FIXME: if it's aggregate what do we assert here? */
6062 g_assert (!image || (!aggregate && image == mono_type_get_cmods (cmods_source)->image));
6063 memcpy (r, cmods_source, mono_sizeof_type (cmods_source));
6066 memcpy (r, o, mono_sizeof_type (o));
6068 /* reset custom mod count and aggregateness to be correct. */
6069 mono_type_with_mods_init (r, num_mods, aggregate);
6070 if (aggregate)
6071 mono_type_set_amods (r, mono_type_is_aggregate_mods (o) ? mono_type_get_amods (o) : mono_type_get_amods (cmods_source));
6072 deep_type_dup_fixup (image, r, o);
6073 return r;
6077 static void
6078 deep_type_dup_fixup (MonoImage *image, MonoType *r, const MonoType *o)
6080 if (o->type == MONO_TYPE_PTR) {
6081 r->data.type = mono_metadata_type_dup (image, o->data.type);
6082 } else if (o->type == MONO_TYPE_ARRAY) {
6083 r->data.array = mono_dup_array_type (image, o->data.array);
6084 } else if (o->type == MONO_TYPE_FNPTR) {
6085 /*FIXME the dup'ed signature is leaked mono_metadata_free_type*/
6086 r->data.method = mono_metadata_signature_deep_dup (image, o->data.method);
6091 * mono_signature_hash:
6093 guint
6094 mono_signature_hash (MonoMethodSignature *sig)
6096 guint i, res = sig->ret->type;
6098 for (i = 0; i < sig->param_count; i++)
6099 res = (res << 5) - res + mono_type_hash (sig->params[i]);
6101 return res;
6105 * mono_metadata_encode_value:
6106 * @value: value to encode
6107 * @buf: buffer where to write the compressed representation
6108 * @endbuf: pointer updated to point at the end of the encoded output
6110 * Encodes the value @value in the compressed representation used
6111 * in metadata and stores the result in @buf. @buf needs to be big
6112 * enough to hold the data (4 bytes).
6114 void
6115 mono_metadata_encode_value (guint32 value, char *buf, char **endbuf)
6117 char *p = buf;
6119 if (value < 0x80)
6120 *p++ = value;
6121 else if (value < 0x4000) {
6122 p [0] = 0x80 | (value >> 8);
6123 p [1] = value & 0xff;
6124 p += 2;
6125 } else {
6126 p [0] = (value >> 24) | 0xc0;
6127 p [1] = (value >> 16) & 0xff;
6128 p [2] = (value >> 8) & 0xff;
6129 p [3] = value & 0xff;
6130 p += 4;
6132 if (endbuf)
6133 *endbuf = p;
6137 * mono_metadata_field_info:
6138 * \param meta the Image the field is defined in
6139 * \param index the index in the field table representing the field
6140 * \param offset a pointer to an integer where to store the offset that may have been specified for the field in a FieldLayout table
6141 * \param rva a pointer to the RVA of the field data in the image that may have been defined in a \c FieldRVA table
6142 * \param marshal_spec a pointer to the marshal spec that may have been defined for the field in a \c FieldMarshal table.
6144 * Gather info for field \p index that may have been defined in the \c FieldLayout,
6145 * \c FieldRVA and \c FieldMarshal tables.
6146 * Either of \p offset, \p rva and \p marshal_spec can be NULL if you're not interested
6147 * in the data.
6149 void
6150 mono_metadata_field_info (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
6151 MonoMarshalSpec **marshal_spec)
6153 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, FALSE);
6156 void
6157 mono_metadata_field_info_with_mempool (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
6158 MonoMarshalSpec **marshal_spec)
6160 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, TRUE);
6163 static void
6164 mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
6165 MonoMarshalSpec **marshal_spec, gboolean alloc_from_image)
6167 MonoTableInfo *tdef;
6168 locator_t loc;
6170 loc.idx = index + 1;
6171 if (meta->uncompressed_metadata)
6172 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
6174 if (offset) {
6175 tdef = &meta->tables [MONO_TABLE_FIELDLAYOUT];
6177 loc.col_idx = MONO_FIELD_LAYOUT_FIELD;
6178 loc.t = tdef;
6180 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
6181 *offset = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_LAYOUT_OFFSET);
6182 } else {
6183 *offset = (guint32)-1;
6186 if (rva) {
6187 tdef = &meta->tables [MONO_TABLE_FIELDRVA];
6189 loc.col_idx = MONO_FIELD_RVA_FIELD;
6190 loc.t = tdef;
6192 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
6194 * LAMESPEC: There is no signature, no nothing, just the raw data.
6196 *rva = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_RVA_RVA);
6197 } else {
6198 *rva = 0;
6201 if (marshal_spec) {
6202 const char *p;
6204 if ((p = mono_metadata_get_marshal_info (meta, index, TRUE))) {
6205 *marshal_spec = mono_metadata_parse_marshal_spec_full (alloc_from_image ? meta : NULL, meta, p);
6212 * mono_metadata_get_constant_index:
6213 * \param meta the Image the field is defined in
6214 * \param index the token that may have a row defined in the constants table
6215 * \param hint possible position for the row
6217 * \p token must be a \c FieldDef, \c ParamDef or \c PropertyDef token.
6219 * \returns the index into the \c Constants table or 0 if not found.
6221 guint32
6222 mono_metadata_get_constant_index (MonoImage *meta, guint32 token, guint32 hint)
6224 MonoTableInfo *tdef;
6225 locator_t loc;
6226 guint32 index = mono_metadata_token_index (token);
6228 tdef = &meta->tables [MONO_TABLE_CONSTANT];
6229 index <<= MONO_HASCONSTANT_BITS;
6230 switch (mono_metadata_token_table (token)) {
6231 case MONO_TABLE_FIELD:
6232 index |= MONO_HASCONSTANT_FIEDDEF;
6233 break;
6234 case MONO_TABLE_PARAM:
6235 index |= MONO_HASCONSTANT_PARAM;
6236 break;
6237 case MONO_TABLE_PROPERTY:
6238 index |= MONO_HASCONSTANT_PROPERTY;
6239 break;
6240 default:
6241 g_warning ("Not a valid token for the constant table: 0x%08x", token);
6242 return 0;
6244 loc.idx = index;
6245 loc.col_idx = MONO_CONSTANT_PARENT;
6246 loc.t = tdef;
6248 /* FIXME: Index translation */
6250 if ((hint > 0) && (hint < tdef->rows) && (mono_metadata_decode_row_col (tdef, hint - 1, MONO_CONSTANT_PARENT) == index))
6251 return hint;
6253 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
6254 return loc.result + 1;
6256 return 0;
6260 * mono_metadata_events_from_typedef:
6261 * \param meta metadata context
6262 * \param index 0-based index (in the \c TypeDef table) describing a type
6263 * \returns the 0-based index in the \c Event table for the events in the
6264 * type. The last event that belongs to the type (plus 1) is stored
6265 * in the \p end_idx pointer.
6267 guint32
6268 mono_metadata_events_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
6270 locator_t loc;
6271 guint32 start, end;
6272 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_EVENTMAP];
6274 *end_idx = 0;
6276 if (!tdef->base)
6277 return 0;
6279 loc.t = tdef;
6280 loc.col_idx = MONO_EVENT_MAP_PARENT;
6281 loc.idx = index + 1;
6283 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6284 return 0;
6286 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_EVENT_MAP_EVENTLIST);
6287 if (loc.result + 1 < tdef->rows) {
6288 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_EVENT_MAP_EVENTLIST) - 1;
6289 } else {
6290 end = meta->tables [MONO_TABLE_EVENT].rows;
6293 *end_idx = end;
6294 return start - 1;
6298 * mono_metadata_methods_from_event:
6299 * \param meta metadata context
6300 * \param index 0-based index (in the \c Event table) describing a event
6301 * \returns the 0-based index in the \c MethodDef table for the methods in the
6302 * event. The last method that belongs to the event (plus 1) is stored
6303 * in the \p end_idx pointer.
6305 guint32
6306 mono_metadata_methods_from_event (MonoImage *meta, guint32 index, guint *end_idx)
6308 locator_t loc;
6309 guint start, end;
6310 guint32 cols [MONO_METHOD_SEMA_SIZE];
6311 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
6313 *end_idx = 0;
6314 if (!msemt->base)
6315 return 0;
6317 if (meta->uncompressed_metadata)
6318 index = search_ptr_table (meta, MONO_TABLE_EVENT_POINTER, index + 1) - 1;
6320 loc.t = msemt;
6321 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
6322 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT; /* Method association coded index */
6324 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
6325 return 0;
6327 start = loc.result;
6329 * We may end up in the middle of the rows...
6331 while (start > 0) {
6332 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
6333 start--;
6334 else
6335 break;
6337 end = start + 1;
6338 while (end < msemt->rows) {
6339 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
6340 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
6341 break;
6342 ++end;
6344 *end_idx = end;
6345 return start;
6349 * mono_metadata_properties_from_typedef:
6350 * \param meta metadata context
6351 * \param index 0-based index (in the \c TypeDef table) describing a type
6352 * \returns the 0-based index in the \c Property table for the properties in the
6353 * type. The last property that belongs to the type (plus 1) is stored
6354 * in the \p end_idx pointer.
6356 guint32
6357 mono_metadata_properties_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
6359 locator_t loc;
6360 guint32 start, end;
6361 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_PROPERTYMAP];
6363 *end_idx = 0;
6365 if (!tdef->base)
6366 return 0;
6368 loc.t = tdef;
6369 loc.col_idx = MONO_PROPERTY_MAP_PARENT;
6370 loc.idx = index + 1;
6372 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6373 return 0;
6375 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_PROPERTY_MAP_PROPERTY_LIST);
6376 if (loc.result + 1 < tdef->rows) {
6377 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_PROPERTY_MAP_PROPERTY_LIST) - 1;
6378 } else {
6379 end = meta->tables [MONO_TABLE_PROPERTY].rows;
6382 *end_idx = end;
6383 return start - 1;
6387 * mono_metadata_methods_from_property:
6388 * \param meta metadata context
6389 * \param index 0-based index (in the \c PropertyDef table) describing a property
6390 * \returns the 0-based index in the \c MethodDef table for the methods in the
6391 * property. The last method that belongs to the property (plus 1) is stored
6392 * in the \p end_idx pointer.
6394 guint32
6395 mono_metadata_methods_from_property (MonoImage *meta, guint32 index, guint *end_idx)
6397 locator_t loc;
6398 guint start, end;
6399 guint32 cols [MONO_METHOD_SEMA_SIZE];
6400 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
6402 *end_idx = 0;
6403 if (!msemt->base)
6404 return 0;
6406 if (meta->uncompressed_metadata)
6407 index = search_ptr_table (meta, MONO_TABLE_PROPERTY_POINTER, index + 1) - 1;
6409 loc.t = msemt;
6410 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
6411 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY; /* Method association coded index */
6413 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
6414 return 0;
6416 start = loc.result;
6418 * We may end up in the middle of the rows...
6420 while (start > 0) {
6421 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
6422 start--;
6423 else
6424 break;
6426 end = start + 1;
6427 while (end < msemt->rows) {
6428 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
6429 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
6430 break;
6431 ++end;
6433 *end_idx = end;
6434 return start;
6438 * mono_metadata_implmap_from_method:
6440 guint32
6441 mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx)
6443 locator_t loc;
6444 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_IMPLMAP];
6446 if (!tdef->base)
6447 return 0;
6449 /* No index translation seems to be needed */
6451 loc.t = tdef;
6452 loc.col_idx = MONO_IMPLMAP_MEMBER;
6453 loc.idx = ((method_idx + 1) << MONO_MEMBERFORWD_BITS) | MONO_MEMBERFORWD_METHODDEF;
6455 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6456 return 0;
6458 return loc.result + 1;
6462 * mono_type_create_from_typespec:
6463 * \param image context where the image is created
6464 * \param type_spec typespec token
6465 * \deprecated use \c mono_type_create_from_typespec_checked that has proper error handling
6467 * Creates a \c MonoType representing the \c TypeSpec indexed by the \p type_spec
6468 * token.
6470 MonoType *
6471 mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
6473 ERROR_DECL (error);
6474 MonoType *type = mono_type_create_from_typespec_checked (image, type_spec, error);
6475 if (!type)
6476 g_error ("Could not create typespec %x due to %s", type_spec, mono_error_get_message (error));
6477 return type;
6480 MonoType *
6481 mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, MonoError *error)
6484 guint32 idx = mono_metadata_token_index (type_spec);
6485 MonoTableInfo *t;
6486 guint32 cols [MONO_TYPESPEC_SIZE];
6487 const char *ptr;
6488 MonoType *type, *type2;
6490 error_init (error);
6492 type = (MonoType *)mono_conc_hashtable_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
6493 if (type)
6494 return type;
6496 t = &image->tables [MONO_TABLE_TYPESPEC];
6498 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
6499 ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
6501 if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, error))
6502 return NULL;
6504 mono_metadata_decode_value (ptr, &ptr);
6506 type = mono_metadata_parse_type_checked (image, NULL, 0, TRUE, ptr, &ptr, error);
6507 if (!type)
6508 return NULL;
6510 type2 = mono_metadata_type_dup (image, type);
6511 mono_metadata_free_type (type);
6513 mono_image_lock (image);
6515 /* We might leak some data in the image mempool if found */
6516 type = (MonoType*)mono_conc_hashtable_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
6517 if (!type)
6518 type = type2;
6520 mono_image_unlock (image);
6522 return type;
6526 static char*
6527 mono_image_strndup (MonoImage *image, const char *data, guint len)
6529 char *res;
6530 if (!image)
6531 return g_strndup (data, len);
6532 res = (char *)mono_image_alloc (image, len + 1);
6533 memcpy (res, data, len);
6534 res [len] = 0;
6535 return res;
6539 * mono_metadata_parse_marshal_spec:
6541 MonoMarshalSpec *
6542 mono_metadata_parse_marshal_spec (MonoImage *image, const char *ptr)
6544 return mono_metadata_parse_marshal_spec_full (NULL, image, ptr);
6548 * If IMAGE is non-null, memory will be allocated from its mempool, otherwise it will be allocated using malloc.
6549 * PARENT_IMAGE is the image containing the marshal spec.
6551 MonoMarshalSpec *
6552 mono_metadata_parse_marshal_spec_full (MonoImage *image, MonoImage *parent_image, const char *ptr)
6554 MonoMarshalSpec *res;
6555 int len;
6556 const char *start = ptr;
6558 /* fixme: this is incomplete, but I cant find more infos in the specs */
6560 if (image)
6561 res = (MonoMarshalSpec *)mono_image_alloc0 (image, sizeof (MonoMarshalSpec));
6562 else
6563 res = g_new0 (MonoMarshalSpec, 1);
6565 len = mono_metadata_decode_value (ptr, &ptr);
6566 res->native = (MonoMarshalNative)*ptr++;
6568 if (res->native == MONO_NATIVE_LPARRAY) {
6569 res->data.array_data.param_num = -1;
6570 res->data.array_data.num_elem = -1;
6571 res->data.array_data.elem_mult = -1;
6573 if (ptr - start <= len)
6574 res->data.array_data.elem_type = (MonoMarshalNative)*ptr++;
6575 if (ptr - start <= len)
6576 res->data.array_data.param_num = mono_metadata_decode_value (ptr, &ptr);
6577 if (ptr - start <= len)
6578 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6579 if (ptr - start <= len) {
6581 * LAMESPEC: Older spec versions say this parameter comes before
6582 * num_elem. Never spec versions don't talk about elem_mult at
6583 * all, but csc still emits it, and it is used to distinguish
6584 * between param_num being 0, and param_num being omitted.
6585 * So if (param_num == 0) && (num_elem > 0), then
6586 * elem_mult == 0 -> the array size is num_elem
6587 * elem_mult == 1 -> the array size is @param_num + num_elem
6589 res->data.array_data.elem_mult = mono_metadata_decode_value (ptr, &ptr);
6593 if (res->native == MONO_NATIVE_BYVALTSTR) {
6594 if (ptr - start <= len)
6595 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6598 if (res->native == MONO_NATIVE_BYVALARRAY) {
6599 if (ptr - start <= len)
6600 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6603 if (res->native == MONO_NATIVE_CUSTOM) {
6604 /* skip unused type guid */
6605 len = mono_metadata_decode_value (ptr, &ptr);
6606 ptr += len;
6607 /* skip unused native type name */
6608 len = mono_metadata_decode_value (ptr, &ptr);
6609 ptr += len;
6610 /* read custom marshaler type name */
6611 len = mono_metadata_decode_value (ptr, &ptr);
6612 res->data.custom_data.custom_name = mono_image_strndup (image, ptr, len);
6613 ptr += len;
6614 /* read cookie string */
6615 len = mono_metadata_decode_value (ptr, &ptr);
6616 res->data.custom_data.cookie = mono_image_strndup (image, ptr, len);
6617 res->data.custom_data.image = parent_image;
6620 if (res->native == MONO_NATIVE_SAFEARRAY) {
6621 res->data.safearray_data.elem_type = (MonoMarshalVariant)0;
6622 res->data.safearray_data.num_elem = 0;
6623 if (ptr - start <= len)
6624 res->data.safearray_data.elem_type = (MonoMarshalVariant)*ptr++;
6625 if (ptr - start <= len)
6626 res->data.safearray_data.num_elem = *ptr++;
6628 return res;
6632 * mono_metadata_free_marshal_spec:
6634 void
6635 mono_metadata_free_marshal_spec (MonoMarshalSpec *spec)
6637 if (!spec)
6638 return;
6640 if (spec->native == MONO_NATIVE_CUSTOM) {
6641 g_free (spec->data.custom_data.custom_name);
6642 g_free (spec->data.custom_data.cookie);
6644 g_free (spec);
6648 * mono_type_to_unmanaged:
6649 * The value pointed to by \p conv will contain the kind of marshalling required for this
6650 * particular type one of the \c MONO_MARSHAL_CONV_ enumeration values.
6651 * \returns A \c MonoMarshalNative enumeration value (<code>MONO_NATIVE_</code>) value
6652 * describing the underlying native reprensetation of the type.
6654 guint32 // FIXMEcxx MonoMarshalNative
6655 mono_type_to_unmanaged (MonoType *type, MonoMarshalSpec *mspec, gboolean as_field,
6656 gboolean unicode, MonoMarshalConv *conv)
6658 MonoMarshalConv dummy_conv;
6659 int t = type->type;
6661 if (!conv)
6662 conv = &dummy_conv;
6664 *conv = MONO_MARSHAL_CONV_NONE;
6666 if (type->byref)
6667 return MONO_NATIVE_UINT;
6669 handle_enum:
6670 switch (t) {
6671 case MONO_TYPE_BOOLEAN:
6672 if (mspec) {
6673 switch (mspec->native) {
6674 case MONO_NATIVE_VARIANTBOOL:
6675 *conv = MONO_MARSHAL_CONV_BOOL_VARIANTBOOL;
6676 return MONO_NATIVE_VARIANTBOOL;
6677 case MONO_NATIVE_BOOLEAN:
6678 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6679 return MONO_NATIVE_BOOLEAN;
6680 case MONO_NATIVE_I1:
6681 case MONO_NATIVE_U1:
6682 return mspec->native;
6683 default:
6684 g_error ("cant marshal bool to native type %02x", mspec->native);
6687 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6688 return MONO_NATIVE_BOOLEAN;
6689 case MONO_TYPE_CHAR:
6690 if (mspec) {
6691 switch (mspec->native) {
6692 case MONO_NATIVE_U2:
6693 case MONO_NATIVE_U1:
6694 return mspec->native;
6695 default:
6696 g_error ("cant marshal char to native type %02x", mspec->native);
6699 return unicode ? MONO_NATIVE_U2 : MONO_NATIVE_U1;
6700 case MONO_TYPE_I1: return MONO_NATIVE_I1;
6701 case MONO_TYPE_U1: return MONO_NATIVE_U1;
6702 case MONO_TYPE_I2: return MONO_NATIVE_I2;
6703 case MONO_TYPE_U2: return MONO_NATIVE_U2;
6704 case MONO_TYPE_I4: return MONO_NATIVE_I4;
6705 case MONO_TYPE_U4: return MONO_NATIVE_U4;
6706 case MONO_TYPE_I8: return MONO_NATIVE_I8;
6707 case MONO_TYPE_U8: return MONO_NATIVE_U8;
6708 case MONO_TYPE_R4: return MONO_NATIVE_R4;
6709 case MONO_TYPE_R8: return MONO_NATIVE_R8;
6710 case MONO_TYPE_STRING:
6711 if (mspec) {
6712 switch (mspec->native) {
6713 case MONO_NATIVE_BSTR:
6714 *conv = MONO_MARSHAL_CONV_STR_BSTR;
6715 return MONO_NATIVE_BSTR;
6716 case MONO_NATIVE_LPSTR:
6717 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6718 return MONO_NATIVE_LPSTR;
6719 case MONO_NATIVE_LPWSTR:
6720 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6721 return MONO_NATIVE_LPWSTR;
6722 case MONO_NATIVE_LPTSTR:
6723 *conv = MONO_MARSHAL_CONV_STR_LPTSTR;
6724 return MONO_NATIVE_LPTSTR;
6725 case MONO_NATIVE_ANSIBSTR:
6726 *conv = MONO_MARSHAL_CONV_STR_ANSIBSTR;
6727 return MONO_NATIVE_ANSIBSTR;
6728 case MONO_NATIVE_TBSTR:
6729 *conv = MONO_MARSHAL_CONV_STR_TBSTR;
6730 return MONO_NATIVE_TBSTR;
6731 case MONO_NATIVE_UTF8STR:
6732 *conv = MONO_MARSHAL_CONV_STR_UTF8STR;
6733 return MONO_NATIVE_UTF8STR;
6734 case MONO_NATIVE_BYVALTSTR:
6735 if (unicode)
6736 *conv = MONO_MARSHAL_CONV_STR_BYVALWSTR;
6737 else
6738 *conv = MONO_MARSHAL_CONV_STR_BYVALSTR;
6739 return MONO_NATIVE_BYVALTSTR;
6740 default:
6741 g_error ("Can not marshal string to native type '%02x': Invalid managed/unmanaged type combination (String fields must be paired with LPStr, LPWStr, BStr or ByValTStr).", mspec->native);
6744 if (unicode) {
6745 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6746 return MONO_NATIVE_LPWSTR;
6748 else {
6749 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6750 return MONO_NATIVE_LPSTR;
6752 case MONO_TYPE_PTR: return MONO_NATIVE_UINT;
6753 case MONO_TYPE_VALUETYPE: /*FIXME*/
6754 if (m_class_is_enumtype (type->data.klass)) {
6755 t = mono_class_enum_basetype_internal (type->data.klass)->type;
6756 goto handle_enum;
6758 if (type->data.klass == mono_class_try_get_handleref_class ()){
6759 *conv = MONO_MARSHAL_CONV_HANDLEREF;
6760 return MONO_NATIVE_INT;
6762 return MONO_NATIVE_STRUCT;
6763 case MONO_TYPE_SZARRAY:
6764 case MONO_TYPE_ARRAY:
6765 if (mspec) {
6766 switch (mspec->native) {
6767 case MONO_NATIVE_BYVALARRAY:
6768 if ((m_class_get_element_class (type->data.klass) == mono_defaults.char_class) && !unicode)
6769 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY;
6770 else
6771 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALARRAY;
6772 return MONO_NATIVE_BYVALARRAY;
6773 case MONO_NATIVE_SAFEARRAY:
6774 *conv = MONO_MARSHAL_CONV_ARRAY_SAVEARRAY;
6775 return MONO_NATIVE_SAFEARRAY;
6776 case MONO_NATIVE_LPARRAY:
6777 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6778 return MONO_NATIVE_LPARRAY;
6779 default:
6780 g_error ("cant marshal array as native type %02x", mspec->native);
6784 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6785 return MONO_NATIVE_LPARRAY;
6786 case MONO_TYPE_I: return MONO_NATIVE_INT;
6787 case MONO_TYPE_U: return MONO_NATIVE_UINT;
6788 case MONO_TYPE_CLASS:
6789 case MONO_TYPE_OBJECT: {
6790 /* FIXME : we need to handle ArrayList and StringBuilder here, probably */
6791 if (mspec) {
6792 switch (mspec->native) {
6793 case MONO_NATIVE_STRUCT:
6794 // [MarshalAs(UnmanagedType.Struct)]
6795 // object field;
6797 // becomes a VARIANT
6799 // [MarshalAs(UnmangedType.Struct)]
6800 // SomeClass field;
6802 // becomes uses the CONV_OBJECT_STRUCT conversion
6803 if (t != MONO_TYPE_OBJECT)
6804 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6805 return MONO_NATIVE_STRUCT;
6806 case MONO_NATIVE_CUSTOM:
6807 return MONO_NATIVE_CUSTOM;
6808 case MONO_NATIVE_INTERFACE:
6809 *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
6810 return MONO_NATIVE_INTERFACE;
6811 case MONO_NATIVE_IDISPATCH:
6812 *conv = MONO_MARSHAL_CONV_OBJECT_IDISPATCH;
6813 return MONO_NATIVE_IDISPATCH;
6814 case MONO_NATIVE_IUNKNOWN:
6815 *conv = MONO_MARSHAL_CONV_OBJECT_IUNKNOWN;
6816 return MONO_NATIVE_IUNKNOWN;
6817 case MONO_NATIVE_FUNC:
6818 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6819 type->data.klass == mono_defaults.delegate_class ||
6820 m_class_get_parent (type->data.klass) == mono_defaults.multicastdelegate_class)) {
6821 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6822 return MONO_NATIVE_FUNC;
6824 /* Fall through */
6825 default:
6826 g_error ("cant marshal object as native type %02x", mspec->native);
6829 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6830 type->data.klass == mono_defaults.delegate_class ||
6831 m_class_get_parent (type->data.klass) == mono_defaults.multicastdelegate_class)) {
6832 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6833 return MONO_NATIVE_FUNC;
6835 if (mono_class_try_get_safehandle_class () && type->data.klass != NULL &&
6836 mono_class_is_subclass_of_internal (type->data.klass, mono_class_try_get_safehandle_class (), FALSE)){
6837 *conv = MONO_MARSHAL_CONV_SAFEHANDLE;
6838 return MONO_NATIVE_INT;
6840 #ifndef DISABLE_COM
6841 if (t == MONO_TYPE_CLASS && mono_cominterop_is_interface (type->data.klass)){
6842 *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
6843 return MONO_NATIVE_INTERFACE;
6845 #endif
6846 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6847 return MONO_NATIVE_STRUCT;
6849 case MONO_TYPE_FNPTR: return MONO_NATIVE_FUNC;
6850 case MONO_TYPE_GENERICINST:
6851 type = m_class_get_byval_arg (type->data.generic_class->container_class);
6852 t = type->type;
6853 goto handle_enum;
6854 case MONO_TYPE_TYPEDBYREF:
6855 default:
6856 g_error ("type 0x%02x not handled in marshal", t);
6858 return MONO_NATIVE_MAX;
6862 * mono_metadata_get_marshal_info:
6864 const char*
6865 mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field)
6867 locator_t loc;
6868 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_FIELDMARSHAL];
6870 if (!tdef->base)
6871 return NULL;
6873 loc.t = tdef;
6874 loc.col_idx = MONO_FIELD_MARSHAL_PARENT;
6875 loc.idx = ((idx + 1) << MONO_HAS_FIELD_MARSHAL_BITS) | (is_field? MONO_HAS_FIELD_MARSHAL_FIELDSREF: MONO_HAS_FIELD_MARSHAL_PARAMDEF);
6877 /* FIXME: Index translation */
6879 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6880 return NULL;
6882 return mono_metadata_blob_heap (meta, mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_MARSHAL_NATIVE_TYPE));
6885 MonoMethod*
6886 mono_method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context, MonoError *error)
6888 MonoMethod *result = NULL;
6889 guint32 idx = tok >> MONO_METHODDEFORREF_BITS;
6891 error_init (error);
6893 switch (tok & MONO_METHODDEFORREF_MASK) {
6894 case MONO_METHODDEFORREF_METHODDEF:
6895 result = mono_get_method_checked (m, MONO_TOKEN_METHOD_DEF | idx, NULL, context, error);
6896 break;
6897 case MONO_METHODDEFORREF_METHODREF:
6898 result = mono_get_method_checked (m, MONO_TOKEN_MEMBER_REF | idx, NULL, context, error);
6899 break;
6900 default:
6901 mono_error_set_bad_image (error, m, "Invalid MethodDefOfRef token %x", tok);
6904 return result;
6908 * mono_class_get_overrides_full:
6910 * Compute the method overrides belonging to class @type_token in @overrides, and the number of overrides in @num_overrides.
6913 void
6914 mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides, MonoGenericContext *generic_context, MonoError *error)
6916 locator_t loc;
6917 MonoTableInfo *tdef = &image->tables [MONO_TABLE_METHODIMPL];
6918 guint32 start, end;
6919 gint32 i, num;
6920 guint32 cols [MONO_METHODIMPL_SIZE];
6921 MonoMethod **result;
6923 error_init (error);
6925 *overrides = NULL;
6926 if (num_overrides)
6927 *num_overrides = 0;
6929 if (!tdef->base)
6930 return;
6932 loc.t = tdef;
6933 loc.col_idx = MONO_METHODIMPL_CLASS;
6934 loc.idx = mono_metadata_token_index (type_token);
6936 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6937 return;
6939 start = loc.result;
6940 end = start + 1;
6942 * We may end up in the middle of the rows...
6944 while (start > 0) {
6945 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_METHODIMPL_CLASS))
6946 start--;
6947 else
6948 break;
6950 while (end < tdef->rows) {
6951 if (loc.idx == mono_metadata_decode_row_col (tdef, end, MONO_METHODIMPL_CLASS))
6952 end++;
6953 else
6954 break;
6956 num = end - start;
6957 result = g_new (MonoMethod*, num * 2);
6958 for (i = 0; i < num; ++i) {
6959 MonoMethod *method;
6961 if (!mono_verifier_verify_methodimpl_row (image, start + i, error))
6962 break;
6964 mono_metadata_decode_row (tdef, start + i, cols, MONO_METHODIMPL_SIZE);
6965 method = mono_method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_DECLARATION], generic_context, error);
6966 if (!method)
6967 break;
6969 result [i * 2] = method;
6970 method = mono_method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_BODY], generic_context, error);
6971 if (!method)
6972 break;
6974 result [i * 2 + 1] = method;
6977 if (!is_ok (error)) {
6978 g_free (result);
6979 *overrides = NULL;
6980 if (num_overrides)
6981 *num_overrides = 0;
6982 } else {
6983 *overrides = result;
6984 if (num_overrides)
6985 *num_overrides = num;
6990 * mono_guid_to_string:
6992 * Converts a 16 byte Microsoft GUID to the standard string representation.
6994 char *
6995 mono_guid_to_string (const guint8 *guid)
6997 return g_strdup_printf ("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
6998 guid[3], guid[2], guid[1], guid[0],
6999 guid[5], guid[4],
7000 guid[7], guid[6],
7001 guid[8], guid[9],
7002 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
7006 * mono_guid_to_string_minimal:
7008 * Converts a 16 byte Microsoft GUID to lower case no '-' representation..
7010 char *
7011 mono_guid_to_string_minimal (const guint8 *guid)
7013 return g_strdup_printf ("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
7014 guid[3], guid[2], guid[1], guid[0],
7015 guid[5], guid[4],
7016 guid[7], guid[6],
7017 guid[8], guid[9],
7018 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
7020 static gboolean
7021 get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGenericContainer *container, MonoError *error)
7023 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
7024 guint32 cols [MONO_GENPARCONSTRAINT_SIZE];
7025 guint32 i, token, found;
7026 MonoClass *klass, **res;
7027 GSList *cons = NULL, *tmp;
7028 MonoGenericContext *context = &container->context;
7030 error_init (error);
7032 *constraints = NULL;
7033 found = 0;
7034 for (i = 0; i < tdef->rows; ++i) {
7035 mono_metadata_decode_row (tdef, i, cols, MONO_GENPARCONSTRAINT_SIZE);
7036 if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) {
7037 token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]);
7038 klass = mono_class_get_and_inflate_typespec_checked (image, token, context, error);
7039 if (!klass) {
7040 g_slist_free (cons);
7041 return FALSE;
7043 cons = g_slist_append (cons, klass);
7044 ++found;
7045 } else {
7046 /* contiguous list finished */
7047 if (found)
7048 break;
7051 if (!found)
7052 return TRUE;
7053 res = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * (found + 1));
7054 for (i = 0, tmp = cons; i < found; ++i, tmp = tmp->next) {
7055 res [i] = (MonoClass *)tmp->data;
7057 g_slist_free (cons);
7058 *constraints = res;
7059 return TRUE;
7063 * mono_metadata_get_generic_param_row:
7065 * @image:
7066 * @token: TypeOrMethodDef token, owner for GenericParam
7067 * @owner: coded token, set on return
7069 * Returns: 1-based row-id in the GenericParam table whose
7070 * owner is @token. 0 if not found.
7072 guint32
7073 mono_metadata_get_generic_param_row (MonoImage *image, guint32 token, guint32 *owner)
7075 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
7076 locator_t loc;
7078 g_assert (owner);
7079 if (!tdef->base)
7080 return 0;
7082 if (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
7083 *owner = MONO_TYPEORMETHOD_TYPE;
7084 else if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
7085 *owner = MONO_TYPEORMETHOD_METHOD;
7086 else {
7087 g_error ("wrong token %x to get_generic_param_row", token);
7088 return 0;
7090 *owner |= mono_metadata_token_index (token) << MONO_TYPEORMETHOD_BITS;
7092 loc.idx = *owner;
7093 loc.col_idx = MONO_GENERICPARAM_OWNER;
7094 loc.t = tdef;
7096 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
7097 return 0;
7099 /* Find the first entry by searching backwards */
7100 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_GENERICPARAM_OWNER) == loc.idx))
7101 loc.result --;
7103 return loc.result + 1;
7106 gboolean
7107 mono_metadata_has_generic_params (MonoImage *image, guint32 token)
7109 guint32 owner;
7110 return mono_metadata_get_generic_param_row (image, token, &owner);
7114 * Memory is allocated from IMAGE's mempool.
7116 gboolean
7117 mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token,
7118 MonoGenericContainer *container, MonoError *error)
7121 guint32 start_row, i, owner;
7122 error_init (error);
7124 if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner)))
7125 return TRUE;
7126 for (i = 0; i < container->type_argc; i++) {
7127 if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container, error)) {
7128 return FALSE;
7131 return TRUE;
7135 * mono_metadata_load_generic_params:
7137 * Load the type parameters from the type or method definition @token.
7139 * Use this method after parsing a type or method definition to figure out whether it's a generic
7140 * type / method. When parsing a method definition, @parent_container points to the generic container
7141 * of the current class, if any.
7143 * Note: This method does not load the constraints: for typedefs, this has to be done after fully
7144 * creating the type.
7146 * Returns: NULL if @token is not a generic type or method definition or the new generic container.
7148 * LOCKING: Acquires the loader lock
7151 MonoGenericContainer *
7152 mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericContainer *parent_container, gpointer real_owner)
7154 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
7155 guint32 cols [MONO_GENERICPARAM_SIZE];
7156 guint32 i, owner = 0, n;
7157 MonoGenericContainer *container;
7158 MonoGenericParamFull *params;
7159 MonoGenericContext *context;
7160 gboolean is_method = mono_metadata_token_table (token) == MONO_TABLE_METHOD;
7161 gboolean is_anonymous = real_owner == NULL;
7163 if (!(i = mono_metadata_get_generic_param_row (image, token, &owner)))
7164 return NULL;
7165 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
7166 params = NULL;
7167 n = 0;
7168 container = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
7169 container->is_anonymous = is_anonymous;
7170 if (is_anonymous) {
7171 container->owner.image = image;
7172 } else {
7173 if (is_method)
7174 container->owner.method = (MonoMethod*)real_owner;
7175 else
7176 container->owner.klass = (MonoClass*)real_owner;
7178 do {
7179 n++;
7180 params = (MonoGenericParamFull *)g_realloc (params, sizeof (MonoGenericParamFull) * n);
7181 memset (&params [n - 1], 0, sizeof (MonoGenericParamFull));
7182 params [n - 1].owner = container;
7183 params [n - 1].num = cols [MONO_GENERICPARAM_NUMBER];
7184 params [n - 1].info.token = i | MONO_TOKEN_GENERIC_PARAM;
7185 params [n - 1].info.flags = cols [MONO_GENERICPARAM_FLAGS];
7186 params [n - 1].info.name = mono_metadata_string_heap (image, cols [MONO_GENERICPARAM_NAME]);
7187 if (params [n - 1].num != n - 1)
7188 g_warning ("GenericParam table unsorted or hole in generic param sequence: token %d", i);
7189 if (++i > tdef->rows)
7190 break;
7191 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
7192 } while (cols [MONO_GENERICPARAM_OWNER] == owner);
7194 container->type_argc = n;
7195 container->type_params = (MonoGenericParamFull *)mono_image_alloc0 (image, sizeof (MonoGenericParamFull) * n);
7196 memcpy (container->type_params, params, sizeof (MonoGenericParamFull) * n);
7197 g_free (params);
7198 container->parent = parent_container;
7200 if (is_method)
7201 container->is_method = 1;
7203 g_assert (container->parent == NULL || container->is_method);
7205 context = &container->context;
7206 if (container->is_method) {
7207 context->class_inst = container->parent ? container->parent->context.class_inst : NULL;
7208 context->method_inst = mono_get_shared_generic_inst (container);
7209 } else {
7210 context->class_inst = mono_get_shared_generic_inst (container);
7213 return container;
7216 MonoGenericInst *
7217 mono_get_shared_generic_inst (MonoGenericContainer *container)
7219 MonoType **type_argv;
7220 MonoType *helper;
7221 MonoGenericInst *nginst;
7222 int i;
7224 type_argv = g_new0 (MonoType *, container->type_argc);
7225 helper = g_new0 (MonoType, container->type_argc);
7227 for (i = 0; i < container->type_argc; i++) {
7228 MonoType *t = &helper [i];
7230 t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
7231 t->data.generic_param = mono_generic_container_get_param (container, i);
7233 type_argv [i] = t;
7236 nginst = mono_metadata_get_generic_inst (container->type_argc, type_argv);
7238 g_free (type_argv);
7239 g_free (helper);
7241 return nginst;
7245 * mono_type_is_byref:
7246 * \param type the \c MonoType operated on
7247 * \returns TRUE if \p type represents a type passed by reference,
7248 * FALSE otherwise.
7250 mono_bool
7251 mono_type_is_byref (MonoType *type)
7253 mono_bool result;
7254 MONO_ENTER_GC_UNSAFE; // FIXME slow
7255 result = mono_type_is_byref_internal (type);
7256 MONO_EXIT_GC_UNSAFE;
7257 return result;
7261 * mono_type_get_type:
7262 * \param type the \c MonoType operated on
7263 * \returns the IL type value for \p type. This is one of the \c MonoTypeEnum
7264 * enum members like \c MONO_TYPE_I4 or \c MONO_TYPE_STRING.
7267 mono_type_get_type (MonoType *type)
7269 return mono_type_get_type_internal (type);
7273 * mono_type_get_signature:
7274 * \param type the \c MonoType operated on
7275 * It is only valid to call this function if \p type is a \c MONO_TYPE_FNPTR .
7276 * \returns the \c MonoMethodSignature pointer that describes the signature
7277 * of the function pointer \p type represents.
7279 MonoMethodSignature*
7280 mono_type_get_signature (MonoType *type)
7282 return mono_type_get_signature_internal (type);
7286 * mono_type_get_class:
7287 * \param type the \c MonoType operated on
7288 * It is only valid to call this function if \p type is a \c MONO_TYPE_CLASS or a
7289 * \c MONO_TYPE_VALUETYPE . For more general functionality, use \c mono_class_from_mono_type_internal,
7290 * instead.
7291 * \returns the \c MonoClass pointer that describes the class that \p type represents.
7293 MonoClass*
7294 mono_type_get_class (MonoType *type)
7296 /* FIXME: review the runtime users before adding the assert here */
7297 return mono_type_get_class_internal (type);
7301 * mono_type_get_array_type:
7302 * \param type the \c MonoType operated on
7303 * It is only valid to call this function if \p type is a \c MONO_TYPE_ARRAY .
7304 * \returns a \c MonoArrayType struct describing the array type that \p type
7305 * represents. The info includes details such as rank, array element type
7306 * and the sizes and bounds of multidimensional arrays.
7308 MonoArrayType*
7309 mono_type_get_array_type (MonoType *type)
7311 return mono_type_get_array_type_internal (type);
7315 * mono_type_get_ptr_type:
7316 * \pararm type the \c MonoType operated on
7317 * It is only valid to call this function if \p type is a \c MONO_TYPE_PTR .
7318 * \returns the \c MonoType pointer that describes the type that \p type
7319 * represents a pointer to.
7321 MonoType*
7322 mono_type_get_ptr_type (MonoType *type)
7324 g_assert (type->type == MONO_TYPE_PTR);
7325 return type->data.type;
7329 * mono_type_get_modifiers:
7331 MonoClass*
7332 mono_type_get_modifiers (MonoType *type, gboolean *is_required, gpointer *iter)
7334 /* FIXME: implement */
7335 return NULL;
7339 * mono_type_is_struct:
7340 * \param type the \c MonoType operated on
7341 * \returns TRUE if \p type is a struct, that is a \c ValueType but not an enum
7342 * or a basic type like \c System.Int32 . FALSE otherwise.
7344 mono_bool
7345 mono_type_is_struct (MonoType *type)
7347 return (!type->byref && ((type->type == MONO_TYPE_VALUETYPE &&
7348 !m_class_is_enumtype (type->data.klass)) || (type->type == MONO_TYPE_TYPEDBYREF) ||
7349 ((type->type == MONO_TYPE_GENERICINST) &&
7350 mono_metadata_generic_class_is_valuetype (type->data.generic_class) &&
7351 !m_class_is_enumtype (type->data.generic_class->container_class))));
7355 * mono_type_is_void:
7356 * \param type the \c MonoType operated on
7357 * \returns TRUE if \p type is \c System.Void . FALSE otherwise.
7359 mono_bool
7360 mono_type_is_void (MonoType *type)
7362 return (type && (type->type == MONO_TYPE_VOID) && !type->byref);
7366 * mono_type_is_pointer:
7367 * \param type the \c MonoType operated on
7368 * \returns TRUE if \p type is a managed or unmanaged pointer type. FALSE otherwise.
7370 mono_bool
7371 mono_type_is_pointer (MonoType *type)
7373 return (type && ((type->byref || (type->type == MONO_TYPE_I) || type->type == MONO_TYPE_STRING)
7374 || (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
7375 (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_OBJECT) ||
7376 (type->type == MONO_TYPE_ARRAY) || (type->type == MONO_TYPE_PTR) ||
7377 (type->type == MONO_TYPE_FNPTR)));
7381 * mono_type_is_reference:
7382 * \param type the \c MonoType operated on
7383 * \returns TRUE if \p type represents an object reference. FALSE otherwise.
7385 mono_bool
7386 mono_type_is_reference (MonoType *type)
7388 /* NOTE: changing this function to return TRUE more often may have
7389 * consequences for generic sharing in the AOT compiler. In
7390 * particular, returning TRUE for generic parameters with a 'class'
7391 * constraint may cause crashes.
7393 return (type && (((type->type == MONO_TYPE_STRING) ||
7394 (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
7395 (type->type == MONO_TYPE_OBJECT) || (type->type == MONO_TYPE_ARRAY)) ||
7396 ((type->type == MONO_TYPE_GENERICINST) &&
7397 !mono_metadata_generic_class_is_valuetype (type->data.generic_class))));
7400 mono_bool
7401 mono_type_is_generic_parameter (MonoType *type)
7403 return !type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR);
7407 * mono_signature_get_return_type:
7408 * \param sig the method signature inspected
7409 * \returns the return type of the method signature \p sig
7411 MonoType*
7412 mono_signature_get_return_type (MonoMethodSignature *sig)
7414 MonoType *result;
7415 MONO_ENTER_GC_UNSAFE;
7416 result = sig->ret;
7417 MONO_EXIT_GC_UNSAFE;
7418 return result;
7422 * mono_signature_get_params:
7423 * \param sig the method signature inspected
7424 * \param iter pointer to an iterator
7425 * Iterates over the parameters for the method signature \p sig.
7426 * A \c void* pointer must be initialized to NULL to start the iteration
7427 * and its address is passed to this function repeteadly until it returns
7428 * NULL.
7429 * \returns the next parameter type of the method signature \p sig,
7430 * NULL when finished.
7432 MonoType*
7433 mono_signature_get_params (MonoMethodSignature *sig, gpointer *iter)
7435 MonoType *result;
7436 MONO_ENTER_GC_UNSAFE;
7437 result = mono_signature_get_params_internal (sig, iter);
7438 MONO_EXIT_GC_UNSAFE;
7439 return result;
7442 MonoType*
7443 mono_signature_get_params_internal (MonoMethodSignature *sig, gpointer *iter)
7445 MonoType** type;
7446 if (!iter)
7447 return NULL;
7448 if (!*iter) {
7449 /* start from the first */
7450 if (sig->param_count) {
7451 *iter = &sig->params [0];
7452 return sig->params [0];
7453 } else {
7454 /* no method */
7455 return NULL;
7458 type = (MonoType **)*iter;
7459 type++;
7460 if (type < &sig->params [sig->param_count]) {
7461 *iter = type;
7462 return *type;
7464 return NULL;
7468 * mono_signature_get_param_count:
7469 * \param sig the method signature inspected
7470 * \returns the number of parameters in the method signature \p sig.
7472 guint32
7473 mono_signature_get_param_count (MonoMethodSignature *sig)
7475 return sig->param_count;
7479 * mono_signature_get_call_conv:
7480 * \param sig the method signature inspected
7481 * \returns the call convention of the method signature \p sig.
7483 guint32
7484 mono_signature_get_call_conv (MonoMethodSignature *sig)
7486 return sig->call_convention;
7490 * mono_signature_vararg_start:
7491 * \param sig the method signature inspected
7492 * \returns the number of the first vararg parameter in the
7493 * method signature \param sig. \c -1 if this is not a vararg signature.
7496 mono_signature_vararg_start (MonoMethodSignature *sig)
7498 return sig->sentinelpos;
7502 * mono_signature_is_instance:
7503 * \param sig the method signature inspected
7504 * \returns TRUE if this the method signature \p sig has an implicit
7505 * first instance argument. FALSE otherwise.
7507 gboolean
7508 mono_signature_is_instance (MonoMethodSignature *sig)
7510 return sig->hasthis;
7514 * mono_signature_param_is_out
7515 * \param sig the method signature inspected
7516 * \param param_num the 0-based index of the inspected parameter
7517 * \returns TRUE if the parameter is an out parameter, FALSE
7518 * otherwise.
7520 mono_bool
7521 mono_signature_param_is_out (MonoMethodSignature *sig, int param_num)
7523 g_assert (param_num >= 0 && param_num < sig->param_count);
7524 return (sig->params [param_num]->attrs & PARAM_ATTRIBUTE_OUT) != 0;
7528 * mono_signature_explicit_this:
7529 * \param sig the method signature inspected
7530 * \returns TRUE if this the method signature \p sig has an explicit
7531 * instance argument. FALSE otherwise.
7533 gboolean
7534 mono_signature_explicit_this (MonoMethodSignature *sig)
7536 return sig->explicit_this;
7539 /* for use with allocated memory blocks (assumes alignment is to 8 bytes) */
7540 guint
7541 mono_aligned_addr_hash (gconstpointer ptr)
7543 /* Same hashing we use for objects */
7544 return (GPOINTER_TO_UINT (ptr) >> 3) * 2654435761u;
7548 * If @field belongs to an inflated generic class, return the corresponding field of the
7549 * generic type definition class.
7551 MonoClassField*
7552 mono_metadata_get_corresponding_field_from_generic_type_definition (MonoClassField *field)
7554 MonoClass *gtd;
7555 int offset;
7557 if (!mono_class_is_ginst (field->parent))
7558 return field;
7560 gtd = mono_class_get_generic_class (field->parent)->container_class;
7561 offset = field - m_class_get_fields (field->parent);
7562 return m_class_get_fields (gtd) + offset;
7566 * If @event belongs to an inflated generic class, return the corresponding event of the
7567 * generic type definition class.
7569 MonoEvent*
7570 mono_metadata_get_corresponding_event_from_generic_type_definition (MonoEvent *event)
7572 MonoClass *gtd;
7573 int offset;
7575 if (!mono_class_is_ginst (event->parent))
7576 return event;
7578 gtd = mono_class_get_generic_class (event->parent)->container_class;
7579 offset = event - mono_class_get_event_info (event->parent)->events;
7580 return mono_class_get_event_info (gtd)->events + offset;
7584 * If @property belongs to an inflated generic class, return the corresponding property of the
7585 * generic type definition class.
7587 MonoProperty*
7588 mono_metadata_get_corresponding_property_from_generic_type_definition (MonoProperty *property)
7590 MonoClassPropertyInfo *info;
7591 MonoClass *gtd;
7592 int offset;
7594 if (!mono_class_is_ginst (property->parent))
7595 return property;
7597 info = mono_class_get_property_info (property->parent);
7598 gtd = mono_class_get_generic_class (property->parent)->container_class;
7599 offset = property - info->properties;
7600 return mono_class_get_property_info (gtd)->properties + offset;
7603 MonoWrapperCaches*
7604 mono_method_get_wrapper_cache (MonoMethod *method)
7606 if (method->is_inflated) {
7607 MonoMethodInflated *imethod = (MonoMethodInflated *)method;
7608 return &imethod->owner->wrapper_caches;
7609 } else {
7610 return &m_class_get_image (method->klass)->wrapper_caches;
7614 // This is support for the mempool reference tracking feature in checked-build, but lives in metadata.c due to use of static variables of this file.
7617 * mono_find_image_set_owner:
7619 * Find the imageset, if any, which a given pointer is located in the memory of.
7621 MonoImageSet *
7622 mono_find_image_set_owner (void *ptr)
7624 MonoImageSet *owner = NULL;
7625 int i;
7627 image_sets_lock ();
7629 if (image_sets)
7631 for (i = 0; !owner && i < image_sets->len; ++i) {
7632 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
7633 if (mono_mempool_contains_addr (set->mempool, ptr))
7634 owner = set;
7638 image_sets_unlock ();
7640 return owner;
7643 void
7644 mono_loader_set_strict_assembly_name_check (gboolean enabled)
7646 check_assembly_names_strictly = enabled;
7649 gboolean
7650 mono_loader_get_strict_assembly_name_check (void)
7652 #if !defined(DISABLE_DESKTOP_LOADER) || defined(ENABLE_NETCORE)
7653 return check_assembly_names_strictly;
7654 #else
7655 return FALSE;
7656 #endif
7660 gboolean
7661 mono_type_is_aggregate_mods (const MonoType *t)
7663 if (!t->has_cmods)
7664 return FALSE;
7666 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7668 return full->is_aggregate;
7671 MonoCustomModContainer *
7672 mono_type_get_cmods (const MonoType *t)
7674 if (!t->has_cmods)
7675 return NULL;
7677 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7679 g_assert (!full->is_aggregate);
7680 return &full->mods.cmods;
7683 MonoAggregateModContainer *
7684 mono_type_get_amods (const MonoType *t)
7686 if (!t->has_cmods)
7687 return NULL;
7689 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7691 g_assert (full->is_aggregate);
7692 return full->mods.amods;
7695 size_t
7696 mono_sizeof_aggregate_modifiers (uint8_t num_mods)
7698 size_t accum = 0;
7699 accum += offsetof (MonoAggregateModContainer, modifiers);
7700 accum += sizeof (MonoSingleCustomMod) * num_mods;
7701 return accum;
7704 size_t
7705 mono_sizeof_type_with_mods (uint8_t num_mods, gboolean is_aggregate)
7707 if (num_mods == 0)
7708 return sizeof (MonoType);
7709 size_t accum = 0;
7710 accum += offsetof (MonoTypeWithModifiers, mods);
7712 if (!is_aggregate) {
7713 accum += offsetof (struct _MonoCustomModContainer, modifiers);
7714 accum += sizeof (MonoCustomMod) * num_mods;
7715 } else {
7716 accum += offsetof (MonoAggregateModContainer, modifiers);
7717 accum += sizeof (MonoAggregateModContainer *);
7719 return accum;
7722 size_t
7723 mono_sizeof_type (const MonoType *ty)
7725 if (ty->has_cmods) {
7726 if (!mono_type_is_aggregate_mods (ty)) {
7727 MonoCustomModContainer *cmods = mono_type_get_cmods (ty);
7728 return mono_sizeof_type_with_mods (cmods->count, FALSE);
7729 } else {
7730 MonoAggregateModContainer *amods = mono_type_get_amods (ty);
7731 return mono_sizeof_type_with_mods (amods->count, TRUE);
7733 } else
7734 return sizeof (MonoType);
7737 void
7738 mono_type_set_amods (MonoType *t, MonoAggregateModContainer *amods)
7740 g_assert (t->has_cmods);
7741 MonoTypeWithModifiers *t_full = (MonoTypeWithModifiers*)t;
7742 g_assert (t_full->is_aggregate);
7743 g_assert (t_full->mods.amods == NULL);
7744 t_full->mods.amods = amods;