[runtime] Fix a problem with PR #19361. (#19374)
[mono-project.git] / mono / metadata / metadata.c
blob9ce5150bdbee877817cc698141835f92473241a0
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 ENCLOG_SCHEMA_OFFSET FIELD_RVA_SCHEMA_OFFSET + 3
247 MONO_MT_UINT32, /* "Token" }, */
248 MONO_MT_UINT32, /* "FuncCode" }, */
249 MONO_MT_END,
251 #define ENCMAP_SCHEMA_OFFSET ENCLOG_SCHEMA_OFFSET + 3
252 MONO_MT_UINT32, /* "Token" }, */
253 MONO_MT_END,
255 #define FIELD_POINTER_SCHEMA_OFFSET ENCMAP_SCHEMA_OFFSET + 2
256 MONO_MT_TABLE_IDX, /* "Field" }, */
257 MONO_MT_END,
259 #define FILE_SCHEMA_OFFSET FIELD_POINTER_SCHEMA_OFFSET + 2
260 MONO_MT_UINT32, /* "Flags" }, */
261 MONO_MT_STRING_IDX, /* "Name" }, */
262 MONO_MT_BLOB_IDX, /* "Value" }, */
263 MONO_MT_END,
265 #define IMPLMAP_SCHEMA_OFFSET FILE_SCHEMA_OFFSET + 4
266 MONO_MT_UINT16, /* "MappingFlag" }, */
267 MONO_MT_MF_IDX, /* "MemberForwarded" }, */
268 MONO_MT_STRING_IDX, /* "ImportName" }, */
269 MONO_MT_TABLE_IDX, /* "ImportScope:ModuleRef" }, */
270 MONO_MT_END,
272 #define IFACEMAP_SCHEMA_OFFSET IMPLMAP_SCHEMA_OFFSET + 5
273 MONO_MT_TABLE_IDX, /* "Class:TypeDef" }, */
274 MONO_MT_TDOR_IDX, /* "Interface=TypeDefOrRef" }, */
275 MONO_MT_END,
277 #define MANIFEST_SCHEMA_OFFSET IFACEMAP_SCHEMA_OFFSET + 3
278 MONO_MT_UINT32, /* "Offset" }, */
279 MONO_MT_UINT32, /* "Flags" }, */
280 MONO_MT_STRING_IDX, /* "Name" }, */
281 MONO_MT_IMPL_IDX, /* "Implementation" }, */
282 MONO_MT_END,
284 #define MEMBERREF_SCHEMA_OFFSET MANIFEST_SCHEMA_OFFSET + 5
285 MONO_MT_MRP_IDX, /* "Class" }, */
286 MONO_MT_STRING_IDX, /* "Name" }, */
287 MONO_MT_BLOB_IDX, /* "Signature" }, */
288 MONO_MT_END,
290 #define METHOD_SCHEMA_OFFSET MEMBERREF_SCHEMA_OFFSET + 4
291 MONO_MT_UINT32, /* "RVA" }, */
292 MONO_MT_UINT16, /* "ImplFlags#MethodImplAttributes" }, */
293 MONO_MT_UINT16, /* "Flags#MethodAttribute" }, */
294 MONO_MT_STRING_IDX, /* "Name" }, */
295 MONO_MT_BLOB_IDX, /* "Signature" }, */
296 MONO_MT_TABLE_IDX, /* "ParamList:Param" }, */
297 MONO_MT_END,
299 #define METHOD_IMPL_SCHEMA_OFFSET METHOD_SCHEMA_OFFSET + 7
300 MONO_MT_TABLE_IDX, /* "Class:TypeDef" }, */
301 MONO_MT_MDOR_IDX, /* "MethodBody" }, */
302 MONO_MT_MDOR_IDX, /* "MethodDeclaration" }, */
303 MONO_MT_END,
305 #define METHOD_SEMA_SCHEMA_OFFSET METHOD_IMPL_SCHEMA_OFFSET + 4
306 MONO_MT_UINT16, /* "MethodSemantic" }, */
307 MONO_MT_TABLE_IDX, /* "Method:Method" }, */
308 MONO_MT_HS_IDX, /* "Association" }, */
309 MONO_MT_END,
311 #define METHOD_POINTER_SCHEMA_OFFSET METHOD_SEMA_SCHEMA_OFFSET + 4
312 MONO_MT_TABLE_IDX, /* "Method" }, */
313 MONO_MT_END,
315 #define MODULE_SCHEMA_OFFSET METHOD_POINTER_SCHEMA_OFFSET + 2
316 MONO_MT_UINT16, /* "Generation" }, */
317 MONO_MT_STRING_IDX, /* "Name" }, */
318 MONO_MT_GUID_IDX, /* "MVID" }, */
319 MONO_MT_GUID_IDX, /* "EncID" }, */
320 MONO_MT_GUID_IDX, /* "EncBaseID" }, */
321 MONO_MT_END,
323 #define MODULEREF_SCHEMA_OFFSET MODULE_SCHEMA_OFFSET + 6
324 MONO_MT_STRING_IDX, /* "Name" }, */
325 MONO_MT_END,
327 #define NESTED_CLASS_SCHEMA_OFFSET MODULEREF_SCHEMA_OFFSET + 2
328 MONO_MT_TABLE_IDX, /* "NestedClass:TypeDef" }, */
329 MONO_MT_TABLE_IDX, /* "EnclosingClass:TypeDef" }, */
330 MONO_MT_END,
332 #define PARAM_SCHEMA_OFFSET NESTED_CLASS_SCHEMA_OFFSET + 3
333 MONO_MT_UINT16, /* "Flags" }, */
334 MONO_MT_UINT16, /* "Sequence" }, */
335 MONO_MT_STRING_IDX, /* "Name" }, */
336 MONO_MT_END,
338 #define PARAM_POINTER_SCHEMA_OFFSET PARAM_SCHEMA_OFFSET + 4
339 MONO_MT_TABLE_IDX, /* "Param" }, */
340 MONO_MT_END,
342 #define PROPERTY_SCHEMA_OFFSET PARAM_POINTER_SCHEMA_OFFSET + 2
343 MONO_MT_UINT16, /* "Flags" }, */
344 MONO_MT_STRING_IDX, /* "Name" }, */
345 MONO_MT_BLOB_IDX, /* "Type" }, */
346 MONO_MT_END,
348 #define PROPERTY_POINTER_SCHEMA_OFFSET PROPERTY_SCHEMA_OFFSET + 4
349 MONO_MT_TABLE_IDX, /* "Property" }, */
350 MONO_MT_END,
352 #define PROPERTY_MAP_SCHEMA_OFFSET PROPERTY_POINTER_SCHEMA_OFFSET + 2
353 MONO_MT_TABLE_IDX, /* "Parent:TypeDef" }, */
354 MONO_MT_TABLE_IDX, /* "PropertyList:Property" }, */
355 MONO_MT_END,
357 #define STDALON_SIG_SCHEMA_OFFSET PROPERTY_MAP_SCHEMA_OFFSET + 3
358 MONO_MT_BLOB_IDX, /* "Signature" }, */
359 MONO_MT_END,
361 #define TYPEDEF_SCHEMA_OFFSET STDALON_SIG_SCHEMA_OFFSET + 2
362 MONO_MT_UINT32, /* "Flags" }, */
363 MONO_MT_STRING_IDX, /* "Name" }, */
364 MONO_MT_STRING_IDX, /* "Namespace" }, */
365 MONO_MT_TDOR_IDX, /* "Extends" }, */
366 MONO_MT_TABLE_IDX, /* "FieldList:Field" }, */
367 MONO_MT_TABLE_IDX, /* "MethodList:Method" }, */
368 MONO_MT_END,
370 #define TYPEREF_SCHEMA_OFFSET TYPEDEF_SCHEMA_OFFSET + 7
371 MONO_MT_RS_IDX, /* "ResolutionScope=ResolutionScope" }, */
372 MONO_MT_STRING_IDX, /* "Name" }, */
373 MONO_MT_STRING_IDX, /* "Namespace" }, */
374 MONO_MT_END,
376 #define TYPESPEC_SCHEMA_OFFSET TYPEREF_SCHEMA_OFFSET + 4
377 MONO_MT_BLOB_IDX, /* "Signature" }, */
378 MONO_MT_END,
380 #define GENPARAM_SCHEMA_OFFSET TYPESPEC_SCHEMA_OFFSET + 2
381 MONO_MT_UINT16, /* "Number" }, */
382 MONO_MT_UINT16, /* "Flags" }, */
383 MONO_MT_TABLE_IDX, /* "Owner" }, TypeDef or MethodDef */
384 MONO_MT_STRING_IDX, /* "Name" }, */
385 MONO_MT_END,
387 #define METHOD_SPEC_SCHEMA_OFFSET GENPARAM_SCHEMA_OFFSET + 5
388 MONO_MT_MDOR_IDX, /* "Method" }, */
389 MONO_MT_BLOB_IDX, /* "Signature" }, */
390 MONO_MT_END,
392 #define GEN_CONSTRAINT_SCHEMA_OFFSET METHOD_SPEC_SCHEMA_OFFSET + 3
393 MONO_MT_TABLE_IDX, /* "GenericParam" }, */
394 MONO_MT_TDOR_IDX, /* "Constraint" }, */
395 MONO_MT_END,
397 #define DOCUMENT_SCHEMA_OFFSET GEN_CONSTRAINT_SCHEMA_OFFSET + 3
398 MONO_MT_BLOB_IDX, /* Name */
399 MONO_MT_GUID_IDX, /* HashAlgorithm */
400 MONO_MT_BLOB_IDX, /* Hash */
401 MONO_MT_GUID_IDX, /* Language */
402 MONO_MT_END,
404 #define METHODBODY_SCHEMA_OFFSET DOCUMENT_SCHEMA_OFFSET + 5
405 MONO_MT_TABLE_IDX, /* Document */
406 MONO_MT_BLOB_IDX, /* SequencePoints */
407 MONO_MT_END,
409 #define LOCALSCOPE_SCHEMA_OFFSET METHODBODY_SCHEMA_OFFSET + 3
410 MONO_MT_TABLE_IDX, /* Method */
411 MONO_MT_TABLE_IDX, /* ImportScope */
412 MONO_MT_TABLE_IDX, /* VariableList */
413 MONO_MT_TABLE_IDX, /* ConstantList */
414 MONO_MT_UINT32, /* StartOffset */
415 MONO_MT_UINT32, /* Length */
416 MONO_MT_END,
418 #define LOCALVARIABLE_SCHEMA_OFFSET LOCALSCOPE_SCHEMA_OFFSET + 7
419 MONO_MT_UINT16, /* Attributes */
420 MONO_MT_UINT16, /* Index */
421 MONO_MT_STRING_IDX, /* Name */
422 MONO_MT_END,
424 #define LOCALCONSTANT_SCHEMA_OFFSET LOCALVARIABLE_SCHEMA_OFFSET + 4
425 MONO_MT_STRING_IDX, /* Name (String heap index) */
426 MONO_MT_BLOB_IDX, /* Signature (Blob heap index, LocalConstantSig blob) */
427 MONO_MT_END,
429 #define IMPORTSCOPE_SCHEMA_OFFSET LOCALCONSTANT_SCHEMA_OFFSET + 3
430 MONO_MT_TABLE_IDX, /* Parent (ImportScope row id or nil) */
431 MONO_MT_BLOB_IDX, /* Imports (Blob index, encoding: Imports blob) */
432 MONO_MT_END,
434 #define ASYNCMETHOD_SCHEMA_OFFSET IMPORTSCOPE_SCHEMA_OFFSET + 3
435 MONO_MT_TABLE_IDX, /* MoveNextMethod (MethodDef row id) */
436 MONO_MT_TABLE_IDX, /* KickoffMethod (MethodDef row id) */
437 MONO_MT_END,
439 #define CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET ASYNCMETHOD_SCHEMA_OFFSET + 3
440 MONO_MT_HASCUSTDEBUG_IDX, /* Parent (HasCustomDebugInformation coded index) */
441 MONO_MT_GUID_IDX, /* Kind (Guid heap index) */
442 MONO_MT_BLOB_IDX, /* Value (Blob heap index) */
443 MONO_MT_END,
445 #define NULL_SCHEMA_OFFSET CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET + 4
446 MONO_MT_END
449 /* Must be the same order as MONO_TABLE_* */
450 const static unsigned char
451 table_description [] = {
452 MODULE_SCHEMA_OFFSET,
453 TYPEREF_SCHEMA_OFFSET,
454 TYPEDEF_SCHEMA_OFFSET,
455 FIELD_POINTER_SCHEMA_OFFSET,
456 FIELD_SCHEMA_OFFSET,
457 METHOD_POINTER_SCHEMA_OFFSET,
458 METHOD_SCHEMA_OFFSET,
459 PARAM_POINTER_SCHEMA_OFFSET,
460 PARAM_SCHEMA_OFFSET,
461 IFACEMAP_SCHEMA_OFFSET,
462 MEMBERREF_SCHEMA_OFFSET, /* 0xa */
463 CONSTANT_SCHEMA_OFFSET,
464 CUSTOM_ATTR_SCHEMA_OFFSET,
465 FIELD_MARSHAL_SCHEMA_OFFSET,
466 DECL_SEC_SCHEMA_OFFSET,
467 CLASS_LAYOUT_SCHEMA_OFFSET,
468 FIELD_LAYOUT_SCHEMA_OFFSET, /* 0x10 */
469 STDALON_SIG_SCHEMA_OFFSET,
470 EVENTMAP_SCHEMA_OFFSET,
471 EVENT_POINTER_SCHEMA_OFFSET,
472 EVENT_SCHEMA_OFFSET,
473 PROPERTY_MAP_SCHEMA_OFFSET,
474 PROPERTY_POINTER_SCHEMA_OFFSET,
475 PROPERTY_SCHEMA_OFFSET,
476 METHOD_SEMA_SCHEMA_OFFSET,
477 METHOD_IMPL_SCHEMA_OFFSET,
478 MODULEREF_SCHEMA_OFFSET, /* 0x1a */
479 TYPESPEC_SCHEMA_OFFSET,
480 IMPLMAP_SCHEMA_OFFSET,
481 FIELD_RVA_SCHEMA_OFFSET,
482 ENCLOG_SCHEMA_OFFSET,
483 ENCMAP_SCHEMA_OFFSET,
484 ASSEMBLY_SCHEMA_OFFSET, /* 0x20 */
485 ASSEMBLYPROC_SCHEMA_OFFSET,
486 ASSEMBLYOS_SCHEMA_OFFSET,
487 ASSEMBLYREF_SCHEMA_OFFSET,
488 ASSEMBLYREFPROC_SCHEMA_OFFSET,
489 ASSEMBLYREFOS_SCHEMA_OFFSET,
490 FILE_SCHEMA_OFFSET,
491 EXPORTED_TYPE_SCHEMA_OFFSET,
492 MANIFEST_SCHEMA_OFFSET,
493 NESTED_CLASS_SCHEMA_OFFSET,
494 GENPARAM_SCHEMA_OFFSET, /* 0x2a */
495 METHOD_SPEC_SCHEMA_OFFSET,
496 GEN_CONSTRAINT_SCHEMA_OFFSET,
497 NULL_SCHEMA_OFFSET,
498 NULL_SCHEMA_OFFSET,
499 NULL_SCHEMA_OFFSET,
500 DOCUMENT_SCHEMA_OFFSET, /* 0x30 */
501 METHODBODY_SCHEMA_OFFSET,
502 LOCALSCOPE_SCHEMA_OFFSET,
503 LOCALVARIABLE_SCHEMA_OFFSET,
504 LOCALCONSTANT_SCHEMA_OFFSET,
505 IMPORTSCOPE_SCHEMA_OFFSET,
506 ASYNCMETHOD_SCHEMA_OFFSET,
507 CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET
510 // This, instead of an array of pointers, to optimize away a pointer and a relocation per string.
511 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
512 #define MSGSTRFIELD1(line) str##line
513 static const struct msgstr_t {
514 #define TABLEDEF(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
515 #include "mono/cil/tables.def"
516 #undef TABLEDEF
517 } tablestr = {
518 #define TABLEDEF(a,b) b,
519 #include "mono/cil/tables.def"
520 #undef TABLEDEF
522 static const gint16 tableidx [] = {
523 #define TABLEDEF(a,b) offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
524 #include "mono/cil/tables.def"
525 #undef TABLEDEF
528 /* On legacy, if TRUE (but also see DISABLE_DESKTOP_LOADER #define), Mono will check
529 * that the public key token, culture and version of a candidate assembly matches
530 * the requested strong name. On netcore, it will check the culture and version.
531 * If FALSE, as long as the name matches, the candidate will be allowed.
533 static gboolean check_assembly_names_strictly = FALSE;
535 // Amount initially reserved in each imageset's mempool.
536 // FIXME: This number is arbitrary, a more practical number should be found
537 #define INITIAL_IMAGE_SET_SIZE 1024
540 * mono_meta_table_name:
541 * \param table table index
543 * Returns the name of the given ECMA metadata logical format table
544 * as described in ECMA 335, Partition II, Section 22.
546 * \returns the name for the \p table index
548 const char *
549 mono_meta_table_name (int table)
551 if ((table < 0) || (table > MONO_TABLE_LAST))
552 return "";
554 return (const char*)&tablestr + tableidx [table];
557 /* The guy who wrote the spec for this should not be allowed near a
558 * computer again.
560 If e is a coded token(see clause 23.1.7) that points into table ti out of n possible tables t0, .. tn-1,
561 then it is stored as e << (log n) & tag{ t0, .. tn-1}[ ti] using 2 bytes if the maximum number of
562 rows of tables t0, ..tn-1, is less than 2^16 - (log n), and using 4 bytes otherwise. The family of
563 finite maps tag{ t0, ..tn-1} is defined below. Note that to decode a physical row, you need the
564 inverse of this mapping.
567 #define rtsize(meta,s,b) (((s) < (1 << (b)) ? 2 : 4))
569 static int
570 idx_size (MonoImage *meta, int idx)
572 if (meta->referenced_tables && (meta->referenced_tables & ((guint64)1 << idx)))
573 return meta->referenced_table_rows [idx] < 65536 ? 2 : 4;
574 else
575 return meta->tables [idx].rows < 65536 ? 2 : 4;
578 static int
579 get_nrows (MonoImage *meta, int idx)
581 if (meta->referenced_tables && (meta->referenced_tables & ((guint64)1 << idx)))
582 return meta->referenced_table_rows [idx];
583 else
584 return meta->tables [idx].rows;
587 /* Reference: Partition II - 23.2.6 */
589 * mono_metadata_compute_size:
590 * \param meta metadata context
591 * \param tableindex metadata table number
592 * \param result_bitfield pointer to \c guint32 where to store additional info
594 * \c mono_metadata_compute_size computes the length in bytes of a single
595 * row in a metadata table. The size of each column is encoded in the
596 * \p result_bitfield return value along with the number of columns in the table.
597 * the resulting bitfield should be handed to the \c mono_metadata_table_size
598 * and \c mono_metadata_table_count macros.
599 * This is a Mono runtime internal only function.
602 mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bitfield)
604 guint32 bitfield = 0;
605 int size = 0, field_size = 0;
606 int i, n, code;
607 int shift = 0;
608 const unsigned char *description = TableSchemas + table_description [tableindex];
610 for (i = 0; (code = description [i]) != MONO_MT_END; i++){
611 switch (code){
612 case MONO_MT_UINT32:
613 field_size = 4; break;
615 case MONO_MT_UINT16:
616 field_size = 2; break;
618 case MONO_MT_UINT8:
619 field_size = 1; break;
621 case MONO_MT_BLOB_IDX:
622 field_size = meta->idx_blob_wide ? 4 : 2; break;
624 case MONO_MT_STRING_IDX:
625 field_size = meta->idx_string_wide ? 4 : 2; break;
627 case MONO_MT_GUID_IDX:
628 field_size = meta->idx_guid_wide ? 4 : 2; break;
630 case MONO_MT_TABLE_IDX:
631 /* Uhm, a table index can point to other tables besides the current one
632 * so, it's not correct to use the rowcount of the current table to
633 * get the size for this column - lupus
635 switch (tableindex) {
636 case MONO_TABLE_ASSEMBLYREFOS:
637 g_assert (i == 3);
638 field_size = idx_size (meta, MONO_TABLE_ASSEMBLYREF); break;
639 case MONO_TABLE_ASSEMBLYREFPROCESSOR:
640 g_assert (i == 1);
641 field_size = idx_size (meta, MONO_TABLE_ASSEMBLYREF); break;
642 case MONO_TABLE_CLASSLAYOUT:
643 g_assert (i == 2);
644 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
645 case MONO_TABLE_EVENTMAP:
646 g_assert (i == 0 || i == 1);
647 field_size = i ? idx_size (meta, MONO_TABLE_EVENT):
648 idx_size (meta, MONO_TABLE_TYPEDEF);
649 break;
650 case MONO_TABLE_EVENT_POINTER:
651 g_assert (i == 0);
652 field_size = idx_size (meta, MONO_TABLE_EVENT); break;
653 case MONO_TABLE_EXPORTEDTYPE:
654 g_assert (i == 1);
655 /* the index is in another metadata file, so it must be 4 */
656 field_size = 4; break;
657 case MONO_TABLE_FIELDLAYOUT:
658 g_assert (i == 1);
659 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
660 case MONO_TABLE_FIELDRVA:
661 g_assert (i == 1);
662 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
663 case MONO_TABLE_FIELD_POINTER:
664 g_assert (i == 0);
665 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
666 case MONO_TABLE_IMPLMAP:
667 g_assert (i == 3);
668 field_size = idx_size (meta, MONO_TABLE_MODULEREF); break;
669 case MONO_TABLE_INTERFACEIMPL:
670 g_assert (i == 0);
671 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
672 case MONO_TABLE_METHOD:
673 g_assert (i == 5);
674 field_size = idx_size (meta, MONO_TABLE_PARAM); break;
675 case MONO_TABLE_METHODIMPL:
676 g_assert (i == 0);
677 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
678 case MONO_TABLE_METHODSEMANTICS:
679 g_assert (i == 1);
680 field_size = idx_size (meta, MONO_TABLE_METHOD); break;
681 case MONO_TABLE_METHOD_POINTER:
682 g_assert (i == 0);
683 field_size = idx_size (meta, MONO_TABLE_METHOD); break;
684 case MONO_TABLE_NESTEDCLASS:
685 g_assert (i == 0 || i == 1);
686 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
687 case MONO_TABLE_PARAM_POINTER:
688 g_assert (i == 0);
689 field_size = idx_size (meta, MONO_TABLE_PARAM); break;
690 case MONO_TABLE_PROPERTYMAP:
691 g_assert (i == 0 || i == 1);
692 field_size = i ? idx_size (meta, MONO_TABLE_PROPERTY):
693 idx_size (meta, MONO_TABLE_TYPEDEF);
694 break;
695 case MONO_TABLE_PROPERTY_POINTER:
696 g_assert (i == 0);
697 field_size = idx_size (meta, MONO_TABLE_PROPERTY); break;
698 case MONO_TABLE_TYPEDEF:
699 g_assert (i == 4 || i == 5);
700 field_size = i == 4 ? idx_size (meta, MONO_TABLE_FIELD):
701 idx_size (meta, MONO_TABLE_METHOD);
702 break;
703 case MONO_TABLE_GENERICPARAM:
704 g_assert (i == 2);
705 n = MAX (get_nrows (meta, MONO_TABLE_METHOD), get_nrows (meta, MONO_TABLE_TYPEDEF));
706 /*This is a coded token for 2 tables, so takes 1 bit */
707 field_size = rtsize (meta, n, 16 - MONO_TYPEORMETHOD_BITS);
708 break;
709 case MONO_TABLE_GENERICPARAMCONSTRAINT:
710 g_assert (i == 0);
711 field_size = idx_size (meta, MONO_TABLE_GENERICPARAM);
712 break;
713 case MONO_TABLE_LOCALSCOPE:
714 switch (i) {
715 case 0:
716 // FIXME: This table is in another file
717 field_size = idx_size (meta, MONO_TABLE_METHOD);
718 break;
719 case 1:
720 field_size = idx_size (meta, MONO_TABLE_IMPORTSCOPE);
721 break;
722 case 2:
723 field_size = idx_size (meta, MONO_TABLE_LOCALVARIABLE);
724 break;
725 case 3:
726 field_size = idx_size (meta, MONO_TABLE_LOCALCONSTANT);
727 break;
728 default:
729 g_assert_not_reached ();
730 break;
732 break;
733 case MONO_TABLE_METHODBODY:
734 g_assert (i == 0);
735 field_size = idx_size (meta, MONO_TABLE_DOCUMENT); break;
736 case MONO_TABLE_IMPORTSCOPE:
737 g_assert(i == 0);
738 field_size = idx_size (meta, MONO_TABLE_IMPORTSCOPE); break;
739 case MONO_TABLE_STATEMACHINEMETHOD:
740 g_assert(i == 0 || i == 1);
741 field_size = idx_size(meta, MONO_TABLE_METHOD); break;
742 default:
743 g_error ("Can't handle MONO_MT_TABLE_IDX for table %d element %d", tableindex, i);
745 break;
748 * HasConstant: ParamDef, FieldDef, Property
750 case MONO_MT_CONST_IDX:
751 n = MAX (get_nrows (meta, MONO_TABLE_PARAM),
752 get_nrows (meta, MONO_TABLE_FIELD));
753 n = MAX (n, get_nrows (meta, MONO_TABLE_PROPERTY));
755 /* 2 bits to encode tag */
756 field_size = rtsize (meta, n, 16-2);
757 break;
760 * HasCustomAttribute: points to any table but
761 * itself.
763 case MONO_MT_HASCAT_IDX:
765 * We believe that since the signature and
766 * permission are indexing the Blob heap,
767 * we should consider the blob size first
769 /* I'm not a believer - lupus
770 if (meta->idx_blob_wide){
771 field_size = 4;
772 break;
775 n = MAX (get_nrows (meta, MONO_TABLE_METHOD),
776 get_nrows (meta, MONO_TABLE_FIELD));
777 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPEREF));
778 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPEDEF));
779 n = MAX (n, get_nrows (meta, MONO_TABLE_PARAM));
780 n = MAX (n, get_nrows (meta, MONO_TABLE_INTERFACEIMPL));
781 n = MAX (n, get_nrows (meta, MONO_TABLE_MEMBERREF));
782 n = MAX (n, get_nrows (meta, MONO_TABLE_MODULE));
783 n = MAX (n, get_nrows (meta, MONO_TABLE_DECLSECURITY));
784 n = MAX (n, get_nrows (meta, MONO_TABLE_PROPERTY));
785 n = MAX (n, get_nrows (meta, MONO_TABLE_EVENT));
786 n = MAX (n, get_nrows (meta, MONO_TABLE_STANDALONESIG));
787 n = MAX (n, get_nrows (meta, MONO_TABLE_MODULEREF));
788 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPESPEC));
789 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLY));
790 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
791 n = MAX (n, get_nrows (meta, MONO_TABLE_FILE));
792 n = MAX (n, get_nrows (meta, MONO_TABLE_EXPORTEDTYPE));
793 n = MAX (n, get_nrows (meta, MONO_TABLE_MANIFESTRESOURCE));
794 n = MAX (n, get_nrows (meta, MONO_TABLE_GENERICPARAM));
795 n = MAX (n, get_nrows (meta, MONO_TABLE_GENERICPARAMCONSTRAINT));
796 n = MAX (n, get_nrows (meta, MONO_TABLE_METHODSPEC));
798 /* 5 bits to encode */
799 field_size = rtsize (meta, n, 16-5);
800 break;
803 * HasCustomAttribute: points to any table but
804 * itself.
807 case MONO_MT_HASCUSTDEBUG_IDX:
808 n = MAX(get_nrows (meta, MONO_TABLE_METHOD),
809 get_nrows (meta, MONO_TABLE_FIELD));
810 n = MAX(n, get_nrows (meta, MONO_TABLE_TYPEREF));
811 n = MAX(n, get_nrows (meta, MONO_TABLE_TYPEDEF));
812 n = MAX(n, get_nrows (meta, MONO_TABLE_PARAM));
813 n = MAX(n, get_nrows (meta, MONO_TABLE_INTERFACEIMPL));
814 n = MAX(n, get_nrows (meta, MONO_TABLE_MEMBERREF));
815 n = MAX(n, get_nrows (meta, MONO_TABLE_MODULE));
816 n = MAX(n, get_nrows (meta, MONO_TABLE_DECLSECURITY));
817 n = MAX(n, get_nrows (meta, MONO_TABLE_PROPERTY));
818 n = MAX(n, get_nrows (meta, MONO_TABLE_EVENT));
819 n = MAX(n, get_nrows (meta, MONO_TABLE_STANDALONESIG));
820 n = MAX(n, get_nrows (meta, MONO_TABLE_MODULEREF));
821 n = MAX(n, get_nrows (meta, MONO_TABLE_TYPESPEC));
822 n = MAX(n, get_nrows (meta, MONO_TABLE_ASSEMBLY));
823 n = MAX(n, get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
824 n = MAX(n, get_nrows (meta, MONO_TABLE_FILE));
825 n = MAX(n, get_nrows (meta, MONO_TABLE_EXPORTEDTYPE));
826 n = MAX(n, get_nrows (meta, MONO_TABLE_MANIFESTRESOURCE));
827 n = MAX(n, get_nrows (meta, MONO_TABLE_GENERICPARAM));
828 n = MAX(n, get_nrows (meta, MONO_TABLE_GENERICPARAMCONSTRAINT));
829 n = MAX(n, get_nrows (meta, MONO_TABLE_METHODSPEC));
830 n = MAX(n, get_nrows (meta, MONO_TABLE_DOCUMENT));
831 n = MAX(n, get_nrows (meta, MONO_TABLE_LOCALSCOPE));
832 n = MAX(n, get_nrows (meta, MONO_TABLE_LOCALVARIABLE));
833 n = MAX(n, get_nrows (meta, MONO_TABLE_LOCALCONSTANT));
834 n = MAX(n, get_nrows (meta, MONO_TABLE_IMPORTSCOPE));
836 /* 5 bits to encode */
837 field_size = rtsize(meta, n, 16 - 5);
838 break;
841 * CustomAttributeType: MethodDef, MemberRef.
843 case MONO_MT_CAT_IDX:
844 n = MAX (get_nrows (meta, MONO_TABLE_METHOD),
845 get_nrows (meta, MONO_TABLE_MEMBERREF));
847 /* 3 bits to encode */
848 field_size = rtsize (meta, n, 16-3);
849 break;
852 * HasDeclSecurity: Typedef, MethodDef, Assembly
854 case MONO_MT_HASDEC_IDX:
855 n = MAX (get_nrows (meta, MONO_TABLE_TYPEDEF),
856 get_nrows (meta, MONO_TABLE_METHOD));
857 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLY));
859 /* 2 bits to encode */
860 field_size = rtsize (meta, n, 16-2);
861 break;
864 * Implementation: File, AssemblyRef, ExportedType
866 case MONO_MT_IMPL_IDX:
867 n = MAX (get_nrows (meta, MONO_TABLE_FILE),
868 get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
869 n = MAX (n, get_nrows (meta, MONO_TABLE_EXPORTEDTYPE));
871 /* 2 bits to encode tag */
872 field_size = rtsize (meta, n, 16-2);
873 break;
876 * HasFieldMarshall: FieldDef, ParamDef
878 case MONO_MT_HFM_IDX:
879 n = MAX (get_nrows (meta, MONO_TABLE_FIELD),
880 get_nrows (meta, MONO_TABLE_PARAM));
882 /* 1 bit used to encode tag */
883 field_size = rtsize (meta, n, 16-1);
884 break;
887 * MemberForwarded: FieldDef, MethodDef
889 case MONO_MT_MF_IDX:
890 n = MAX (get_nrows (meta, MONO_TABLE_FIELD),
891 get_nrows (meta, MONO_TABLE_METHOD));
893 /* 1 bit used to encode tag */
894 field_size = rtsize (meta, n, 16-1);
895 break;
898 * TypeDefOrRef: TypeDef, ParamDef, TypeSpec
899 * LAMESPEC
900 * It is TypeDef, _TypeRef_, TypeSpec, instead.
902 case MONO_MT_TDOR_IDX:
903 n = MAX (get_nrows (meta, MONO_TABLE_TYPEDEF),
904 get_nrows (meta, MONO_TABLE_TYPEREF));
905 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPESPEC));
907 /* 2 bits to encode */
908 field_size = rtsize (meta, n, 16-2);
909 break;
912 * MemberRefParent: TypeDef, TypeRef, MethodDef, ModuleRef, TypeSpec, MemberRef
914 case MONO_MT_MRP_IDX:
915 n = MAX (get_nrows (meta, MONO_TABLE_TYPEDEF),
916 get_nrows (meta, MONO_TABLE_TYPEREF));
917 n = MAX (n, get_nrows (meta, MONO_TABLE_METHOD));
918 n = MAX (n, get_nrows (meta, MONO_TABLE_MODULEREF));
919 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPESPEC));
921 /* 3 bits to encode */
922 field_size = rtsize (meta, n, 16 - 3);
923 break;
926 * MethodDefOrRef: MethodDef, MemberRef
928 case MONO_MT_MDOR_IDX:
929 n = MAX (get_nrows (meta, MONO_TABLE_METHOD),
930 get_nrows (meta, MONO_TABLE_MEMBERREF));
932 /* 1 bit used to encode tag */
933 field_size = rtsize (meta, n, 16-1);
934 break;
937 * HasSemantics: Property, Event
939 case MONO_MT_HS_IDX:
940 n = MAX (get_nrows (meta, MONO_TABLE_PROPERTY),
941 get_nrows (meta, MONO_TABLE_EVENT));
943 /* 1 bit used to encode tag */
944 field_size = rtsize (meta, n, 16-1);
945 break;
948 * ResolutionScope: Module, ModuleRef, AssemblyRef, TypeRef
950 case MONO_MT_RS_IDX:
951 n = MAX (get_nrows (meta, MONO_TABLE_MODULE),
952 get_nrows (meta, MONO_TABLE_MODULEREF));
953 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
954 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPEREF));
956 /* 2 bits used to encode tag (ECMA spec claims 3) */
957 field_size = rtsize (meta, n, 16 - 2);
958 break;
962 * encode field size as follows (we just need to
963 * distinguish them).
965 * 4 -> 3
966 * 2 -> 1
967 * 1 -> 0
969 bitfield |= (field_size-1) << shift;
970 shift += 2;
971 size += field_size;
972 /*g_print ("table %02x field %d size %d\n", tableindex, i, field_size);*/
975 *result_bitfield = (i << 24) | bitfield;
976 return size;
980 * mono_metadata_compute_table_bases:
981 * \param meta metadata context to compute table values
983 * Computes the table bases for the metadata structure.
984 * This is an internal function used by the image loader code.
986 void
987 mono_metadata_compute_table_bases (MonoImage *meta)
989 int i;
990 const char *base = meta->tables_base;
992 for (i = 0; i < MONO_TABLE_NUM; i++) {
993 MonoTableInfo *table = &meta->tables [i];
994 if (table->rows == 0)
995 continue;
997 table->row_size = mono_metadata_compute_size (meta, i, &table->size_bitfield);
998 table->base = base;
999 base += table->rows * table->row_size;
1004 * mono_metadata_locate:
1005 * \param meta metadata context
1006 * \param table table code.
1007 * \param idx index of element to retrieve from \p table.
1009 * \returns a pointer to the \p idx element in the metadata table
1010 * whose code is \p table.
1012 const char *
1013 mono_metadata_locate (MonoImage *meta, int table, int idx)
1015 /* idx == 0 refers always to NULL */
1016 g_return_val_if_fail (idx > 0 && idx <= meta->tables [table].rows, ""); /*FIXME shouldn't we return NULL here?*/
1018 return meta->tables [table].base + (meta->tables [table].row_size * (idx - 1));
1022 * mono_metadata_locate_token:
1023 * \param meta metadata context
1024 * \param token metadata token
1026 * \returns a pointer to the data in the metadata represented by the
1027 * token \p token .
1029 const char *
1030 mono_metadata_locate_token (MonoImage *meta, guint32 token)
1032 return mono_metadata_locate (meta, token >> 24, token & 0xffffff);
1036 * mono_metadata_string_heap:
1037 * \param meta metadata context
1038 * \param index index into the string heap.
1039 * \returns an in-memory pointer to the \p index in the string heap.
1041 const char *
1042 mono_metadata_string_heap (MonoImage *meta, guint32 index)
1044 g_assert (index < meta->heap_strings.size);
1045 g_return_val_if_fail (index < meta->heap_strings.size, "");
1046 return meta->heap_strings.data + index;
1050 * mono_metadata_string_heap_checked:
1051 * \param meta metadata context
1052 * \param index index into the string heap.
1053 * \param error set on error
1054 * \returns an in-memory pointer to the \p index in the string heap.
1055 * On failure returns NULL and sets \p error.
1057 const char *
1058 mono_metadata_string_heap_checked (MonoImage *meta, guint32 index, MonoError *error)
1060 if (G_UNLIKELY (!(index < meta->heap_strings.size))) {
1061 const char *image_name = meta && meta->name ? meta->name : "unknown image";
1062 mono_error_set_bad_image_by_name (error, image_name, "string heap index %ud out bounds %u: %s", index, meta->heap_strings.size, image_name);
1063 return NULL;
1065 return meta->heap_strings.data + index;
1069 * mono_metadata_user_string:
1070 * \param meta metadata context
1071 * \param index index into the user string heap.
1072 * \returns an in-memory pointer to the \p index in the user string heap (<code>#US</code>).
1074 const char *
1075 mono_metadata_user_string (MonoImage *meta, guint32 index)
1077 g_assert (index < meta->heap_us.size);
1078 g_return_val_if_fail (index < meta->heap_us.size, "");
1079 return meta->heap_us.data + index;
1083 * mono_metadata_blob_heap:
1084 * \param meta metadata context
1085 * \param index index into the blob.
1086 * \returns an in-memory pointer to the \p index in the Blob heap.
1088 const char *
1089 mono_metadata_blob_heap (MonoImage *meta, guint32 index)
1091 /* Some tools can produce assemblies with a size 0 Blob stream. If a
1092 * blob value is optional, if the index == 0 and heap_blob.size == 0
1093 * assertion is hit, consider updating caller to use
1094 * mono_metadata_blob_heap_null_ok and handling a null return value. */
1095 g_assert (!(index == 0 && meta->heap_blob.size == 0));
1096 g_assert (index < meta->heap_blob.size);
1097 return meta->heap_blob.data + index;
1101 * mono_metadata_blob_heap_null_ok:
1102 * \param meta metadata context
1103 * \param index index into the blob.
1104 * \return an in-memory pointer to the \p index in the Blob heap.
1105 * If the Blob heap is empty or missing and index is 0 returns NULL, instead of asserting.
1107 const char *
1108 mono_metadata_blob_heap_null_ok (MonoImage *meta, guint32 index)
1110 if (G_UNLIKELY (index == 0 && meta->heap_blob.size == 0))
1111 return NULL;
1112 else
1113 return mono_metadata_blob_heap (meta, index);
1117 * mono_metadata_blob_heap_checked:
1118 * \param meta metadata context
1119 * \param index index into the blob.
1120 * \param error set on error
1121 * \returns an in-memory pointer to the \p index in the Blob heap. On failure sets \p error and returns NULL;
1122 * If the Blob heap is empty or missing and \p index is 0 returns NULL, without setting error.
1125 const char *
1126 mono_metadata_blob_heap_checked (MonoImage *meta, guint32 index, MonoError *error)
1128 if (G_UNLIKELY (index == 0 && meta->heap_blob.size == 0))
1129 return NULL;
1130 if (G_UNLIKELY (!(index < meta->heap_blob.size))) {
1131 const char *image_name = meta && meta->name ? meta->name : "unknown image";
1132 mono_error_set_bad_image_by_name (error, image_name, "blob heap index %u out of bounds %u: %s", index, meta->heap_blob.size, image_name);
1133 return NULL;
1135 return meta->heap_blob.data + index;
1139 * mono_metadata_guid_heap:
1140 * \param meta metadata context
1141 * \param index index into the guid heap.
1142 * \returns an in-memory pointer to the \p index in the guid heap.
1144 const char *
1145 mono_metadata_guid_heap (MonoImage *meta, guint32 index)
1147 --index;
1148 index *= 16; /* adjust for guid size and 1-based index */
1149 g_return_val_if_fail (index < meta->heap_guid.size, "");
1150 return meta->heap_guid.data + index;
1153 static const unsigned char *
1154 dword_align (const unsigned char *ptr)
1156 return (const unsigned char *) (((gsize) (ptr + 3)) & ~3);
1160 * mono_metadata_decode_row:
1161 * \param t table to extract information from.
1162 * \param idx index in table.
1163 * \param res array of \p res_size cols to store the results in
1165 * This decompresses the metadata element \p idx in table \p t
1166 * into the \c guint32 \p res array that has \p res_size elements
1168 void
1169 mono_metadata_decode_row (const MonoTableInfo *t, int idx, guint32 *res, int res_size)
1171 guint32 bitfield = t->size_bitfield;
1172 int i, count = mono_metadata_table_count (bitfield);
1173 const char *data;
1175 g_assert (idx < t->rows);
1176 g_assert (idx >= 0);
1177 data = t->base + idx * t->row_size;
1179 g_assert (res_size == count);
1181 for (i = 0; i < count; i++) {
1182 int n = mono_metadata_table_size (bitfield, i);
1184 switch (n){
1185 case 1:
1186 res [i] = *data; break;
1187 case 2:
1188 res [i] = read16 (data); break;
1189 case 4:
1190 res [i] = read32 (data); break;
1191 default:
1192 g_assert_not_reached ();
1194 data += n;
1199 * mono_metadata_decode_row_checked:
1200 * \param image the \c MonoImage the table belongs to
1201 * \param t table to extract information from.
1202 * \param idx index in the table.
1203 * \param res array of \p res_size cols to store the results in
1204 * \param error set on bounds error
1207 * This decompresses the metadata element \p idx in the table \p t
1208 * into the \c guint32 \p res array that has \p res_size elements.
1210 * \returns TRUE if the read succeeded. Otherwise sets \p error and returns FALSE.
1212 gboolean
1213 mono_metadata_decode_row_checked (const MonoImage *image, const MonoTableInfo *t, int idx, guint32 *res, int res_size, MonoError *error)
1215 guint32 bitfield = t->size_bitfield;
1216 int i, count = mono_metadata_table_count (bitfield);
1218 const char *image_name = image && image->name ? image->name : "unknown image";
1220 if (G_UNLIKELY (! (idx < t->rows && idx >= 0))) {
1221 mono_error_set_bad_image_by_name (error, image_name, "row index %d out of bounds: %d rows: %s", idx, t->rows, image_name);
1222 return FALSE;
1224 const char *data = t->base + idx * t->row_size;
1226 if (G_UNLIKELY (res_size != count)) {
1227 mono_error_set_bad_image_by_name (error, image_name, "res_size %d != count %d: %s", res_size, count, image_name);
1228 return FALSE;
1231 for (i = 0; i < count; i++) {
1232 int n = mono_metadata_table_size (bitfield, i);
1234 switch (n) {
1235 case 1:
1236 res [i] = *data; break;
1237 case 2:
1238 res [i] = read16 (data); break;
1239 case 4:
1240 res [i] = read32 (data); break;
1241 default:
1242 mono_error_set_bad_image_by_name (error, image_name, "unexpected table [%d] size %d: %s", i, n, image_name);
1243 return FALSE;
1245 data += n;
1248 return TRUE;
1252 * mono_metadata_decode_row_col:
1253 * \param t table to extract information from.
1254 * \param idx index for row in table.
1255 * \param col column in the row.
1257 * This function returns the value of column \p col from the \p idx
1258 * row in the table \p t .
1260 guint32
1261 mono_metadata_decode_row_col (const MonoTableInfo *t, int idx, guint col)
1263 guint32 bitfield = t->size_bitfield;
1264 int i;
1265 const char *data;
1266 int n;
1268 g_assert (idx < t->rows);
1269 g_assert (col < mono_metadata_table_count (bitfield));
1270 data = t->base + idx * t->row_size;
1272 n = mono_metadata_table_size (bitfield, 0);
1273 for (i = 0; i < col; ++i) {
1274 data += n;
1275 n = mono_metadata_table_size (bitfield, i + 1);
1277 switch (n) {
1278 case 1:
1279 return *data;
1280 case 2:
1281 return read16 (data);
1282 case 4:
1283 return read32 (data);
1284 default:
1285 g_assert_not_reached ();
1287 return 0;
1291 * mono_metadata_decode_blob_size:
1292 * \param ptr pointer to a blob object
1293 * \param rptr the new position of the pointer
1295 * This decodes a compressed size as described by 24.2.4 (#US and #Blob a blob or user string object)
1297 * \returns the size of the blob object
1299 guint32
1300 mono_metadata_decode_blob_size (const char *xptr, const char **rptr)
1302 const unsigned char *ptr = (const unsigned char *)xptr;
1303 guint32 size;
1305 if ((*ptr & 0x80) == 0){
1306 size = ptr [0] & 0x7f;
1307 ptr++;
1308 } else if ((*ptr & 0x40) == 0){
1309 size = ((ptr [0] & 0x3f) << 8) + ptr [1];
1310 ptr += 2;
1311 } else {
1312 size = ((ptr [0] & 0x1f) << 24) +
1313 (ptr [1] << 16) +
1314 (ptr [2] << 8) +
1315 ptr [3];
1316 ptr += 4;
1318 if (rptr)
1319 *rptr = (char*)ptr;
1320 return size;
1324 * mono_metadata_decode_value:
1325 * \param ptr pointer to decode from
1326 * \param rptr the new position of the pointer
1328 * This routine decompresses 32-bit values as specified in the "Blob and
1329 * Signature" section (23.2)
1331 * \returns the decoded value
1333 guint32
1334 mono_metadata_decode_value (const char *_ptr, const char **rptr)
1336 const unsigned char *ptr = (const unsigned char *) _ptr;
1337 unsigned char b = *ptr;
1338 guint32 len;
1340 if ((b & 0x80) == 0){
1341 len = b;
1342 ++ptr;
1343 } else if ((b & 0x40) == 0){
1344 len = ((b & 0x3f) << 8 | ptr [1]);
1345 ptr += 2;
1346 } else {
1347 len = ((b & 0x1f) << 24) |
1348 (ptr [1] << 16) |
1349 (ptr [2] << 8) |
1350 ptr [3];
1351 ptr += 4;
1353 if (rptr)
1354 *rptr = (char*)ptr;
1356 return len;
1360 * mono_metadata_decode_signed_value:
1361 * \param ptr pointer to decode from
1362 * \param rptr the new position of the pointer
1364 * This routine decompresses 32-bit signed values
1365 * (not specified in the spec)
1367 * \returns the decoded value
1369 gint32
1370 mono_metadata_decode_signed_value (const char *ptr, const char **rptr)
1372 guint32 uval = mono_metadata_decode_value (ptr, rptr);
1373 gint32 ival = uval >> 1;
1374 if (!(uval & 1))
1375 return ival;
1376 /* ival is a truncated 2's complement negative number. */
1377 if (ival < 0x40)
1378 /* 6 bits = 7 bits for compressed representation (top bit is '0') - 1 sign bit */
1379 return ival - 0x40;
1380 if (ival < 0x2000)
1381 /* 13 bits = 14 bits for compressed representation (top bits are '10') - 1 sign bit */
1382 return ival - 0x2000;
1383 if (ival < 0x10000000)
1384 /* 28 bits = 29 bits for compressed representation (top bits are '110') - 1 sign bit */
1385 return ival - 0x10000000;
1386 g_assert (ival < 0x20000000);
1387 g_warning ("compressed signed value appears to use 29 bits for compressed representation: %x (raw: %8x)", ival, uval);
1388 return ival - 0x20000000;
1392 * mono_metadata_translate_token_index:
1393 * Translates the given 1-based index into the \c Method, \c Field, \c Event, or \c Param tables
1394 * using the \c *Ptr tables in uncompressed metadata, if they are available.
1396 * FIXME: The caller is not forced to call this function, which is error-prone, since
1397 * forgetting to call it would only show up as a bug on uncompressed metadata.
1399 guint32
1400 mono_metadata_translate_token_index (MonoImage *image, int table, guint32 idx)
1402 if (!image->uncompressed_metadata)
1403 return idx;
1405 switch (table) {
1406 case MONO_TABLE_METHOD:
1407 if (image->tables [MONO_TABLE_METHOD_POINTER].rows)
1408 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_METHOD_POINTER], idx - 1, MONO_METHOD_POINTER_METHOD);
1409 else
1410 return idx;
1411 case MONO_TABLE_FIELD:
1412 if (image->tables [MONO_TABLE_FIELD_POINTER].rows)
1413 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_FIELD_POINTER], idx - 1, MONO_FIELD_POINTER_FIELD);
1414 else
1415 return idx;
1416 case MONO_TABLE_EVENT:
1417 if (image->tables [MONO_TABLE_EVENT_POINTER].rows)
1418 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_EVENT_POINTER], idx - 1, MONO_EVENT_POINTER_EVENT);
1419 else
1420 return idx;
1421 case MONO_TABLE_PROPERTY:
1422 if (image->tables [MONO_TABLE_PROPERTY_POINTER].rows)
1423 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_PROPERTY_POINTER], idx - 1, MONO_PROPERTY_POINTER_PROPERTY);
1424 else
1425 return idx;
1426 case MONO_TABLE_PARAM:
1427 if (image->tables [MONO_TABLE_PARAM_POINTER].rows)
1428 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_PARAM_POINTER], idx - 1, MONO_PARAM_POINTER_PARAM);
1429 else
1430 return idx;
1431 default:
1432 return idx;
1437 * mono_metadata_decode_table_row:
1439 * Same as \c mono_metadata_decode_row, but takes an \p image + \p table ID pair, and takes
1440 * uncompressed metadata into account, so it should be used to access the
1441 * \c Method, \c Field, \c Param and \c Event tables when the access is made from metadata, i.e.
1442 * \p idx is retrieved from a metadata table, like \c MONO_TYPEDEF_FIELD_LIST.
1444 void
1445 mono_metadata_decode_table_row (MonoImage *image, int table, int idx, guint32 *res, int res_size)
1447 if (image->uncompressed_metadata)
1448 idx = mono_metadata_translate_token_index (image, table, idx + 1) - 1;
1450 mono_metadata_decode_row (&image->tables [table], idx, res, res_size);
1454 * mono_metadata_decode_table_row_col:
1456 * Same as \c mono_metadata_decode_row_col, but takes an \p image + \p table ID pair, and takes
1457 * uncompressed metadata into account, so it should be used to access the
1458 * \c Method, \c Field, \c Param and \c Event tables.
1460 guint32 mono_metadata_decode_table_row_col (MonoImage *image, int table, int idx, guint col)
1462 if (image->uncompressed_metadata)
1463 idx = mono_metadata_translate_token_index (image, table, idx + 1) - 1;
1465 return mono_metadata_decode_row_col (&image->tables [table], idx, col);
1469 * mono_metadata_parse_typedef_or_ref:
1470 * \param m a metadata context.
1471 * \param ptr a pointer to an encoded TypedefOrRef in \p m
1472 * \param rptr pointer updated to match the end of the decoded stream
1473 * \returns a token valid in the \p m metadata decoded from
1474 * the compressed representation.
1476 guint32
1477 mono_metadata_parse_typedef_or_ref (MonoImage *m, const char *ptr, const char **rptr)
1479 guint32 token;
1480 token = mono_metadata_decode_value (ptr, &ptr);
1481 if (rptr)
1482 *rptr = ptr;
1483 return mono_metadata_token_from_dor (token);
1487 * mono_metadata_parse_custom_mod:
1488 * \param m a metadata context.
1489 * \param dest storage where the info about the custom modifier is stored (may be NULL)
1490 * \param ptr a pointer to (possibly) the start of a custom modifier list
1491 * \param rptr pointer updated to match the end of the decoded stream
1493 * Checks if \p ptr points to a type custom modifier compressed representation.
1495 * \returns TRUE if a custom modifier was found, FALSE if not.
1498 mono_metadata_parse_custom_mod (MonoImage *m, MonoCustomMod *dest, const char *ptr, const char **rptr)
1500 MonoCustomMod local;
1501 if ((*ptr == MONO_TYPE_CMOD_OPT) || (*ptr == MONO_TYPE_CMOD_REQD)) {
1502 if (!dest)
1503 dest = &local;
1504 dest->required = *ptr == MONO_TYPE_CMOD_REQD ? 1 : 0;
1505 dest->token = mono_metadata_parse_typedef_or_ref (m, ptr + 1, rptr);
1506 return TRUE;
1508 return FALSE;
1512 * mono_metadata_parse_array_internal:
1513 * @m: a metadata context.
1514 * @transient: whenever to allocate data from the heap
1515 * @ptr: a pointer to an encoded array description.
1516 * @rptr: pointer updated to match the end of the decoded stream
1518 * Decodes the compressed array description found in the metadata @m at @ptr.
1520 * Returns: a #MonoArrayType structure describing the array type
1521 * and dimensions. Memory is allocated from the heap or from the image mempool, depending
1522 * on the value of @transient.
1524 * LOCKING: Acquires the loader lock
1526 static MonoArrayType *
1527 mono_metadata_parse_array_internal (MonoImage *m, MonoGenericContainer *container,
1528 gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1530 int i;
1531 MonoArrayType *array;
1532 MonoType *etype;
1534 etype = mono_metadata_parse_type_checked (m, container, 0, FALSE, ptr, &ptr, error); //FIXME this doesn't respect @transient
1535 if (!etype)
1536 return NULL;
1538 array = transient ? (MonoArrayType *)g_malloc0 (sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (m, sizeof (MonoArrayType));
1539 array->eklass = mono_class_from_mono_type_internal (etype);
1540 array->rank = mono_metadata_decode_value (ptr, &ptr);
1542 array->numsizes = mono_metadata_decode_value (ptr, &ptr);
1543 if (array->numsizes)
1544 array->sizes = transient ? (int *)g_malloc0 (sizeof (int) * array->numsizes) : (int *)mono_image_alloc0 (m, sizeof (int) * array->numsizes);
1545 for (i = 0; i < array->numsizes; ++i)
1546 array->sizes [i] = mono_metadata_decode_value (ptr, &ptr);
1548 array->numlobounds = mono_metadata_decode_value (ptr, &ptr);
1549 if (array->numlobounds)
1550 array->lobounds = transient ? (int *)g_malloc0 (sizeof (int) * array->numlobounds) : (int *)mono_image_alloc0 (m, sizeof (int) * array->numlobounds);
1551 for (i = 0; i < array->numlobounds; ++i)
1552 array->lobounds [i] = mono_metadata_decode_signed_value (ptr, &ptr);
1554 if (rptr)
1555 *rptr = ptr;
1556 return array;
1560 * mono_metadata_parse_array:
1562 MonoArrayType *
1563 mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
1565 ERROR_DECL (error);
1566 MonoArrayType *ret = mono_metadata_parse_array_internal (m, NULL, FALSE, ptr, rptr, error);
1567 mono_error_cleanup (error);
1569 return ret;
1573 * mono_metadata_free_array:
1574 * \param array array description
1576 * Frees the array description returned from \c mono_metadata_parse_array.
1578 void
1579 mono_metadata_free_array (MonoArrayType *array)
1581 g_free (array->sizes);
1582 g_free (array->lobounds);
1583 g_free (array);
1587 * need to add common field and param attributes combinations:
1588 * [out] param
1589 * public static
1590 * public static literal
1591 * private
1592 * private static
1593 * private static literal
1595 static const MonoType
1596 builtin_types[] = {
1597 /* data, attrs, type, nmods, byref, pinned */
1598 {{NULL}, 0, MONO_TYPE_VOID, 0, 0, 0},
1599 {{NULL}, 0, MONO_TYPE_BOOLEAN, 0, 0, 0},
1600 {{NULL}, 0, MONO_TYPE_BOOLEAN, 0, 1, 0},
1601 {{NULL}, 0, MONO_TYPE_CHAR, 0, 0, 0},
1602 {{NULL}, 0, MONO_TYPE_CHAR, 0, 1, 0},
1603 {{NULL}, 0, MONO_TYPE_I1, 0, 0, 0},
1604 {{NULL}, 0, MONO_TYPE_I1, 0, 1, 0},
1605 {{NULL}, 0, MONO_TYPE_U1, 0, 0, 0},
1606 {{NULL}, 0, MONO_TYPE_U1, 0, 1, 0},
1607 {{NULL}, 0, MONO_TYPE_I2, 0, 0, 0},
1608 {{NULL}, 0, MONO_TYPE_I2, 0, 1, 0},
1609 {{NULL}, 0, MONO_TYPE_U2, 0, 0, 0},
1610 {{NULL}, 0, MONO_TYPE_U2, 0, 1, 0},
1611 {{NULL}, 0, MONO_TYPE_I4, 0, 0, 0},
1612 {{NULL}, 0, MONO_TYPE_I4, 0, 1, 0},
1613 {{NULL}, 0, MONO_TYPE_U4, 0, 0, 0},
1614 {{NULL}, 0, MONO_TYPE_U4, 0, 1, 0},
1615 {{NULL}, 0, MONO_TYPE_I8, 0, 0, 0},
1616 {{NULL}, 0, MONO_TYPE_I8, 0, 1, 0},
1617 {{NULL}, 0, MONO_TYPE_U8, 0, 0, 0},
1618 {{NULL}, 0, MONO_TYPE_U8, 0, 1, 0},
1619 {{NULL}, 0, MONO_TYPE_R4, 0, 0, 0},
1620 {{NULL}, 0, MONO_TYPE_R4, 0, 1, 0},
1621 {{NULL}, 0, MONO_TYPE_R8, 0, 0, 0},
1622 {{NULL}, 0, MONO_TYPE_R8, 0, 1, 0},
1623 {{NULL}, 0, MONO_TYPE_STRING, 0, 0, 0},
1624 {{NULL}, 0, MONO_TYPE_STRING, 0, 1, 0},
1625 {{NULL}, 0, MONO_TYPE_OBJECT, 0, 0, 0},
1626 {{NULL}, 0, MONO_TYPE_OBJECT, 0, 1, 0},
1627 {{NULL}, 0, MONO_TYPE_TYPEDBYREF, 0, 0, 0},
1628 {{NULL}, 0, MONO_TYPE_I, 0, 0, 0},
1629 {{NULL}, 0, MONO_TYPE_I, 0, 1, 0},
1630 {{NULL}, 0, MONO_TYPE_U, 0, 0, 0},
1631 {{NULL}, 0, MONO_TYPE_U, 0, 1, 0},
1634 #define NBUILTIN_TYPES() (sizeof (builtin_types) / sizeof (builtin_types [0]))
1636 static GHashTable *type_cache = NULL;
1637 static gint32 next_generic_inst_id = 0;
1639 /* Protected by image_sets_mutex */
1640 static MonoImageSet *mscorlib_image_set;
1641 /* Protected by image_sets_mutex */
1642 static GPtrArray *image_sets;
1643 static mono_mutex_t image_sets_mutex;
1645 static guint mono_generic_class_hash (gconstpointer data);
1648 * MonoTypes with modifies are never cached, so we never check or use that field.
1650 static guint
1651 mono_type_hash (gconstpointer data)
1653 const MonoType *type = (const MonoType *) data;
1654 if (type->type == MONO_TYPE_GENERICINST)
1655 return mono_generic_class_hash (type->data.generic_class);
1656 else
1657 return type->type | (type->byref << 8) | (type->attrs << 9);
1660 static gint
1661 mono_type_equal (gconstpointer ka, gconstpointer kb)
1663 const MonoType *a = (const MonoType *) ka;
1664 const MonoType *b = (const MonoType *) kb;
1666 if (a->type != b->type || a->byref != b->byref || a->attrs != b->attrs || a->pinned != b->pinned)
1667 return 0;
1668 /* need other checks */
1669 return 1;
1672 guint
1673 mono_metadata_generic_inst_hash (gconstpointer data)
1675 const MonoGenericInst *ginst = (const MonoGenericInst *) data;
1676 guint hash = 0;
1677 int i;
1678 g_assert (ginst);
1679 g_assert (ginst->type_argv);
1681 for (i = 0; i < ginst->type_argc; ++i) {
1682 hash *= 13;
1683 g_assert (ginst->type_argv [i]);
1684 hash += mono_metadata_type_hash (ginst->type_argv [i]);
1687 return hash ^ (ginst->is_open << 8);
1690 static gboolean
1691 mono_generic_inst_equal_full (const MonoGenericInst *a, const MonoGenericInst *b, gboolean signature_only)
1693 int i;
1695 // An optimization: if the ids of two insts are the same, we know they are the same inst and don't check contents.
1696 // Furthermore, because we perform early de-duping, if the ids differ, we know the contents differ.
1697 #ifndef MONO_SMALL_CONFIG // Optimization does not work in MONO_SMALL_CONFIG: There are no IDs
1698 if (a->id && b->id) { // "id 0" means "object has no id"-- de-duping hasn't been performed yet, must check contents.
1699 if (a->id == b->id)
1700 return TRUE;
1701 // In signature-comparison mode id equality implies object equality, but this is not true for inequality.
1702 // Two separate objects could have signature-equavalent contents.
1703 if (!signature_only)
1704 return FALSE;
1706 #endif
1708 if (a->is_open != b->is_open || a->type_argc != b->type_argc)
1709 return FALSE;
1710 for (i = 0; i < a->type_argc; ++i) {
1711 if (!do_mono_metadata_type_equal (a->type_argv [i], b->type_argv [i], signature_only))
1712 return FALSE;
1714 return TRUE;
1717 gboolean
1718 mono_metadata_generic_inst_equal (gconstpointer ka, gconstpointer kb)
1720 const MonoGenericInst *a = (const MonoGenericInst *) ka;
1721 const MonoGenericInst *b = (const MonoGenericInst *) kb;
1723 return mono_generic_inst_equal_full (a, b, FALSE);
1726 static guint
1727 mono_generic_class_hash (gconstpointer data)
1729 const MonoGenericClass *gclass = (const MonoGenericClass *) data;
1730 guint hash = mono_metadata_type_hash (m_class_get_byval_arg (gclass->container_class));
1732 hash *= 13;
1733 hash += gclass->is_tb_open;
1734 hash += mono_metadata_generic_context_hash (&gclass->context);
1736 return hash;
1739 static gboolean
1740 mono_generic_class_equal (gconstpointer ka, gconstpointer kb)
1742 const MonoGenericClass *a = (const MonoGenericClass *) ka;
1743 const MonoGenericClass *b = (const MonoGenericClass *) kb;
1745 return _mono_metadata_generic_class_equal (a, b, FALSE);
1749 * mono_metadata_init:
1751 * Initialize the global variables of this module.
1752 * This is a Mono runtime internal function.
1754 void
1755 mono_metadata_init (void)
1757 int i;
1759 /* We guard against double initialization due to how pedump in verification mode works.
1760 Until runtime initialization is properly factored to work with what it needs we need workarounds like this.
1761 FIXME: https://bugzilla.xamarin.com/show_bug.cgi?id=58793
1763 static gboolean inited;
1765 if (inited)
1766 return;
1767 inited = TRUE;
1769 type_cache = g_hash_table_new (mono_type_hash, mono_type_equal);
1771 for (i = 0; i < NBUILTIN_TYPES (); ++i)
1772 g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]);
1774 mono_os_mutex_init_recursive (&image_sets_mutex);
1776 mono_counters_register ("ImgSet Cache Hit", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_hit);
1777 mono_counters_register ("ImgSet Cache Miss", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_miss);
1778 mono_counters_register ("ImgSet Count", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_count);
1782 * mono_metadata_cleanup:
1784 * Free all resources used by this module.
1785 * This is a Mono runtime internal function.
1787 void
1788 mono_metadata_cleanup (void)
1790 g_hash_table_destroy (type_cache);
1791 type_cache = NULL;
1792 g_ptr_array_free (image_sets, TRUE);
1793 image_sets = NULL;
1794 mono_os_mutex_destroy (&image_sets_mutex);
1798 * mono_metadata_parse_type:
1799 * \param m metadata context
1800 * \param mode kind of type that may be found at \p ptr
1801 * \param opt_attrs optional attributes to store in the returned type
1802 * \param ptr pointer to the type representation
1803 * \param rptr pointer updated to match the end of the decoded stream
1804 * \param transient whenever to allocate the result from the heap or from a mempool
1806 * Decode a compressed type description found at \p ptr in \p m .
1807 * \p mode can be one of \c MONO_PARSE_MOD_TYPE, \c MONO_PARSE_PARAM, \c MONO_PARSE_RET,
1808 * \c MONO_PARSE_FIELD, \c MONO_PARSE_LOCAL, \c MONO_PARSE_TYPE.
1809 * This function can be used to decode type descriptions in method signatures,
1810 * field signatures, locals signatures etc.
1812 * To parse a generic type, \c generic_container points to the current class'es
1813 * (the \c generic_container field in the <code>MonoClass</code>) or the current generic method's
1814 * (stored in <code>image->property_hash</code>) generic container.
1815 * When we encounter a \c MONO_TYPE_VAR or \c MONO_TYPE_MVAR, it's looked up in
1816 * this \c MonoGenericContainer.
1818 * LOCKING: Acquires the loader lock.
1820 * \returns a \c MonoType structure representing the decoded type.
1822 static MonoType*
1823 mono_metadata_parse_type_internal (MonoImage *m, MonoGenericContainer *container,
1824 short opt_attrs, gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1826 MonoType *type, *cached;
1827 MonoType stype;
1828 gboolean byref = FALSE;
1829 gboolean pinned = FALSE;
1830 const char *tmp_ptr;
1831 int count = 0; // Number of mod arguments
1832 gboolean found;
1834 error_init (error);
1837 * According to the spec, custom modifiers should come before the byref
1838 * flag, but the IL produced by ilasm from the following signature:
1839 * object modopt(...) &
1840 * starts with a byref flag, followed by the modifiers. (bug #49802)
1841 * Also, this type seems to be different from 'object & modopt(...)'. Maybe
1842 * it would be better to treat byref as real type constructor instead of
1843 * a modifier...
1844 * Also, pinned should come before anything else, but some MSV++ produced
1845 * assemblies violate this (#bug 61990).
1848 /* Count the modifiers first */
1849 tmp_ptr = ptr;
1850 found = TRUE;
1851 while (found) {
1852 switch (*tmp_ptr) {
1853 case MONO_TYPE_PINNED:
1854 case MONO_TYPE_BYREF:
1855 ++tmp_ptr;
1856 break;
1857 case MONO_TYPE_CMOD_REQD:
1858 case MONO_TYPE_CMOD_OPT:
1859 count ++;
1860 mono_metadata_parse_custom_mod (m, NULL, tmp_ptr, &tmp_ptr);
1861 break;
1862 default:
1863 found = FALSE;
1867 MonoCustomModContainer *cmods = NULL;
1869 if (count) { // There are mods, so the MonoType will be of nonstandard size.
1870 if (count > 64) {
1871 mono_error_set_bad_image (error, m, "Invalid type with more than 64 modifiers");
1872 return NULL;
1875 size_t size = mono_sizeof_type_with_mods (count, FALSE);
1876 type = transient ? (MonoType *)g_malloc0 (size) : (MonoType *)mono_image_alloc0 (m, size);
1877 type->has_cmods = TRUE;
1879 cmods = mono_type_get_cmods (type);
1880 cmods->count = count;
1881 cmods->image = m;
1882 } else { // The type is of standard size, so we can allocate it on the stack.
1883 type = &stype;
1884 memset (type, 0, MONO_SIZEOF_TYPE);
1887 /* Iterate again, but now parse pinned, byref and custom modifiers */
1888 found = TRUE;
1889 /* cmods are encoded in reverse order from how we normally see them.
1890 * "int32 modopt (Foo) modopt (Bar)" is encoded as "cmod_opt [typedef_or_ref "Bar"] cmod_opt [typedef_or_ref "Foo"] I4"
1892 while (found) {
1893 switch (*ptr) {
1894 case MONO_TYPE_PINNED:
1895 pinned = TRUE;
1896 ++ptr;
1897 break;
1898 case MONO_TYPE_BYREF:
1899 byref = TRUE;
1900 ++ptr;
1901 break;
1902 case MONO_TYPE_CMOD_REQD:
1903 case MONO_TYPE_CMOD_OPT:
1904 mono_metadata_parse_custom_mod (m, &(cmods->modifiers [--count]), ptr, &ptr);
1905 break;
1906 default:
1907 found = FALSE;
1911 // either there were no cmods, or else we iterated through all of cmods backwards to populate it.
1912 g_assert (count == 0);
1914 type->attrs = opt_attrs;
1915 type->byref = byref;
1916 type->pinned = pinned ? 1 : 0;
1918 if (!do_mono_metadata_parse_type (type, m, container, transient, ptr, &ptr, error))
1919 return NULL;
1921 if (rptr)
1922 *rptr = ptr;
1924 // Possibly we can return an already-allocated type instead of the one we decoded
1925 if (!type->has_cmods && !transient) {
1926 /* no need to free type here, because it is on the stack */
1927 if ((type->type == MONO_TYPE_CLASS || type->type == MONO_TYPE_VALUETYPE) && !type->pinned && !type->attrs) {
1928 MonoType *ret = type->byref ? m_class_get_this_arg (type->data.klass) : m_class_get_byval_arg (type->data.klass);
1930 /* Consider the case:
1932 class Foo<T> { class Bar {} }
1933 class Test : Foo<Test>.Bar {}
1935 When Foo<Test> is being expanded, 'Test' isn't yet initialized. It's actually in
1936 a really pristine state: it doesn't even know whether 'Test' is a reference or a value type.
1938 We ensure that the MonoClass is in a state that we can canonicalize to:
1940 klass->_byval_arg.data.klass == klass
1941 klass->this_arg.data.klass == klass
1943 If we can't canonicalize 'type', it doesn't matter, since later users of 'type' will do it.
1945 LOCKING: even though we don't explicitly hold a lock, in the problematic case 'ret' is a field
1946 of a MonoClass which currently holds the loader lock. 'type' is local.
1948 if (ret->data.klass == type->data.klass) {
1949 return ret;
1952 /* No need to use locking since nobody is modifying the hash table */
1953 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type))) {
1954 return cached;
1958 /* printf ("%x %x %c %s\n", type->attrs, type->num_mods, type->pinned ? 'p' : ' ', mono_type_full_name (type)); */
1960 if (type == &stype) { // Type was allocated on the stack, so we need to copy it to safety
1961 type = transient ? (MonoType *)g_malloc (MONO_SIZEOF_TYPE) : (MonoType *)mono_image_alloc (m, MONO_SIZEOF_TYPE);
1962 memcpy (type, &stype, MONO_SIZEOF_TYPE);
1964 return type;
1968 MonoType*
1969 mono_metadata_parse_type_checked (MonoImage *m, MonoGenericContainer *container,
1970 short opt_attrs, gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1972 return mono_metadata_parse_type_internal (m, container, opt_attrs, transient, ptr, rptr, error);
1976 * LOCKING: Acquires the loader lock.
1978 MonoType*
1979 mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
1980 const char *ptr, const char **rptr)
1982 ERROR_DECL (error);
1983 MonoType * type = mono_metadata_parse_type_internal (m, NULL, opt_attrs, FALSE, ptr, rptr, error);
1984 mono_error_cleanup (error);
1985 return type;
1988 gboolean
1989 mono_metadata_method_has_param_attrs (MonoImage *m, int def)
1991 MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM];
1992 MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD];
1993 guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST);
1995 if (def < methodt->rows)
1996 lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
1997 else
1998 lastp = m->tables [MONO_TABLE_PARAM].rows + 1;
2000 for (i = param_index; i < lastp; ++i) {
2001 guint32 flags = mono_metadata_decode_row_col (paramt, i - 1, MONO_PARAM_FLAGS);
2002 if (flags)
2003 return TRUE;
2006 return FALSE;
2010 * mono_metadata_get_param_attrs:
2012 * @m The image to loader parameter attributes from
2013 * @def method def token (one based)
2014 * @param_count number of params to decode including the return value
2016 * Return the parameter attributes for the method whose MethodDef index is DEF. The
2017 * returned memory needs to be freed by the caller. If all the param attributes are
2018 * 0, then NULL is returned.
2020 int*
2021 mono_metadata_get_param_attrs (MonoImage *m, int def, int param_count)
2023 MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM];
2024 MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD];
2025 guint32 cols [MONO_PARAM_SIZE];
2026 guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST);
2027 int *pattrs = NULL;
2029 if (def < methodt->rows)
2030 lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
2031 else
2032 lastp = paramt->rows + 1;
2034 for (i = param_index; i < lastp; ++i) {
2035 mono_metadata_decode_row (paramt, i - 1, cols, MONO_PARAM_SIZE);
2036 if (cols [MONO_PARAM_FLAGS]) {
2037 if (!pattrs)
2038 pattrs = g_new0 (int, param_count);
2039 /* at runtime we just ignore this kind of malformed file:
2040 * the verifier can signal the error to the user
2042 if (cols [MONO_PARAM_SEQUENCE] >= param_count)
2043 continue;
2044 pattrs [cols [MONO_PARAM_SEQUENCE]] = cols [MONO_PARAM_FLAGS];
2048 return pattrs;
2053 * mono_metadata_parse_signature:
2054 * \param image metadata context
2055 * \param token metadata token
2057 * Decode a method signature stored in the \c StandAloneSig table
2059 * \returns a \c MonoMethodSignature describing the signature.
2061 MonoMethodSignature*
2062 mono_metadata_parse_signature (MonoImage *image, guint32 token)
2064 ERROR_DECL (error);
2065 MonoMethodSignature *ret;
2066 ret = mono_metadata_parse_signature_checked (image, token, error);
2067 mono_error_cleanup (error);
2068 return ret;
2072 * mono_metadata_parse_signature_checked:
2073 * @image: metadata context
2074 * @token: metadata token
2075 * @error: set on error
2077 * Decode a method signature stored in the STANDALONESIG table
2079 * Returns: a MonoMethodSignature describing the signature. On failure
2080 * returns NULL and sets @error.
2082 MonoMethodSignature*
2083 mono_metadata_parse_signature_checked (MonoImage *image, guint32 token, MonoError *error)
2086 error_init (error);
2087 MonoTableInfo *tables = image->tables;
2088 guint32 idx = mono_metadata_token_index (token);
2089 guint32 sig;
2090 const char *ptr;
2092 if (image_is_dynamic (image)) {
2093 return (MonoMethodSignature *)mono_lookup_dynamic_token (image, token, NULL, error);
2096 g_assert (mono_metadata_token_table(token) == MONO_TABLE_STANDALONESIG);
2098 sig = mono_metadata_decode_row_col (&tables [MONO_TABLE_STANDALONESIG], idx - 1, 0);
2100 ptr = mono_metadata_blob_heap (image, sig);
2101 mono_metadata_decode_blob_size (ptr, &ptr);
2103 return mono_metadata_parse_method_signature_full (image, NULL, 0, ptr, NULL, error);
2107 * mono_metadata_signature_alloc:
2108 * \param image metadata context
2109 * \param nparams number of parameters in the signature
2111 * Allocate a \c MonoMethodSignature structure with the specified number of params.
2112 * The return type and the params types need to be filled later.
2113 * This is a Mono runtime internal function.
2115 * LOCKING: Assumes the loader lock is held.
2117 * \returns the new \c MonoMethodSignature structure.
2119 MonoMethodSignature*
2120 mono_metadata_signature_alloc (MonoImage *m, guint32 nparams)
2122 MonoMethodSignature *sig;
2124 sig = (MonoMethodSignature *)mono_image_alloc0 (m, MONO_SIZEOF_METHOD_SIGNATURE + ((gint32)nparams) * sizeof (MonoType*));
2125 sig->param_count = nparams;
2126 sig->sentinelpos = -1;
2128 return sig;
2131 static MonoMethodSignature*
2132 mono_metadata_signature_dup_internal_with_padding (MonoImage *image, MonoMemPool *mp, MonoMethodSignature *sig, size_t padding)
2134 int sigsize, sig_header_size;
2135 MonoMethodSignature *ret;
2136 sigsize = sig_header_size = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *) + padding;
2137 if (sig->ret)
2138 sigsize += mono_sizeof_type (sig->ret);
2140 if (image) {
2141 ret = (MonoMethodSignature *)mono_image_alloc (image, sigsize);
2142 } else if (mp) {
2143 ret = (MonoMethodSignature *)mono_mempool_alloc (mp, sigsize);
2144 } else {
2145 ret = (MonoMethodSignature *)g_malloc (sigsize);
2148 memcpy (ret, sig, sig_header_size - padding);
2150 // Copy return value because of ownership semantics.
2151 if (sig->ret) {
2152 // Danger! Do not alter padding use without changing the dup_add_this below
2153 intptr_t end_of_header = (intptr_t)( (char*)(ret) + sig_header_size);
2154 ret->ret = (MonoType *)end_of_header;
2155 memcpy (ret->ret, sig->ret, mono_sizeof_type (sig->ret));
2158 return ret;
2161 static MonoMethodSignature*
2162 mono_metadata_signature_dup_internal (MonoImage *image, MonoMemPool *mp, MonoMethodSignature *sig)
2164 return mono_metadata_signature_dup_internal_with_padding (image, mp, sig, 0);
2167 * signature_dup_add_this:
2169 * Make a copy of @sig, adding an explicit this argument.
2171 MonoMethodSignature*
2172 mono_metadata_signature_dup_add_this (MonoImage *image, MonoMethodSignature *sig, MonoClass *klass)
2174 MonoMethodSignature *ret;
2175 ret = mono_metadata_signature_dup_internal_with_padding (image, NULL, sig, sizeof (MonoType *));
2177 ret->param_count = sig->param_count + 1;
2178 ret->hasthis = FALSE;
2180 for (int i = sig->param_count - 1; i >= 0; i --)
2181 ret->params [i + 1] = sig->params [i];
2182 ret->params [0] = m_class_is_valuetype (klass) ? m_class_get_this_arg (klass) : m_class_get_byval_arg (klass);
2184 for (int i = sig->param_count - 1; i >= 0; i --)
2185 g_assert(ret->params [i + 1]->type == sig->params [i]->type && ret->params [i+1]->type != MONO_TYPE_END);
2186 g_assert (ret->ret->type == sig->ret->type && ret->ret->type != MONO_TYPE_END);
2188 return ret;
2193 MonoMethodSignature*
2194 mono_metadata_signature_dup_full (MonoImage *image, MonoMethodSignature *sig)
2196 MonoMethodSignature *ret = mono_metadata_signature_dup_internal (image, NULL, sig);
2198 for (int i = 0 ; i < sig->param_count; i ++)
2199 g_assert(ret->params [i]->type == sig->params [i]->type);
2200 g_assert (ret->ret->type == sig->ret->type);
2202 return ret;
2205 /*The mempool is accessed without synchronization*/
2206 MonoMethodSignature*
2207 mono_metadata_signature_dup_mempool (MonoMemPool *mp, MonoMethodSignature *sig)
2209 return mono_metadata_signature_dup_internal (NULL, mp, sig);
2213 * mono_metadata_signature_dup:
2214 * \param sig method signature
2216 * Duplicate an existing \c MonoMethodSignature so it can be modified.
2217 * This is a Mono runtime internal function.
2219 * \returns the new \c MonoMethodSignature structure.
2221 MonoMethodSignature*
2222 mono_metadata_signature_dup (MonoMethodSignature *sig)
2224 return mono_metadata_signature_dup_full (NULL, sig);
2228 * mono_metadata_signature_size:
2230 * Return the amount of memory allocated to SIG.
2232 guint32
2233 mono_metadata_signature_size (MonoMethodSignature *sig)
2235 return MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
2239 * mono_metadata_parse_method_signature_full:
2240 * \param m metadata context
2241 * \param generic_container: generics container
2242 * \param def the \c MethodDef index or 0 for \c Ref signatures.
2243 * \param ptr pointer to the signature metadata representation
2244 * \param rptr pointer updated to match the end of the decoded stream
2245 * \param error set on error
2248 * Decode a method signature stored at \p ptr.
2249 * This is a Mono runtime internal function.
2251 * LOCKING: Assumes the loader lock is held.
2253 * \returns a \c MonoMethodSignature describing the signature. On error sets
2254 * \p error and returns \c NULL.
2256 MonoMethodSignature *
2257 mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *container,
2258 int def, const char *ptr, const char **rptr, MonoError *error)
2260 MonoMethodSignature *method;
2261 int i, *pattrs = NULL;
2262 guint32 hasthis = 0, explicit_this = 0, call_convention, param_count;
2263 guint32 gen_param_count = 0;
2264 gboolean is_open = FALSE;
2266 error_init (error);
2268 if (*ptr & 0x10)
2269 gen_param_count = 1;
2270 if (*ptr & 0x20)
2271 hasthis = 1;
2272 if (*ptr & 0x40)
2273 explicit_this = 1;
2274 call_convention = *ptr & 0x0F;
2275 ptr++;
2276 if (gen_param_count)
2277 gen_param_count = mono_metadata_decode_value (ptr, &ptr);
2278 param_count = mono_metadata_decode_value (ptr, &ptr);
2280 if (def)
2281 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 */
2283 method = mono_metadata_signature_alloc (m, param_count);
2284 method->hasthis = hasthis;
2285 method->explicit_this = explicit_this;
2286 method->call_convention = call_convention;
2287 method->generic_param_count = gen_param_count;
2289 switch (method->call_convention) {
2290 case MONO_CALL_DEFAULT:
2291 case MONO_CALL_VARARG:
2292 method->pinvoke = 0;
2293 break;
2294 case MONO_CALL_C:
2295 case MONO_CALL_STDCALL:
2296 case MONO_CALL_THISCALL:
2297 case MONO_CALL_FASTCALL:
2298 method->pinvoke = 1;
2299 break;
2302 if (call_convention != 0xa) {
2303 method->ret = mono_metadata_parse_type_checked (m, container, pattrs ? pattrs [0] : 0, FALSE, ptr, &ptr, error);
2304 if (!method->ret) {
2305 mono_metadata_free_method_signature (method);
2306 g_free (pattrs);
2307 return NULL;
2309 is_open = mono_class_is_open_constructed_type (method->ret);
2312 for (i = 0; i < method->param_count; ++i) {
2313 if (*ptr == MONO_TYPE_SENTINEL) {
2314 if (method->call_convention != MONO_CALL_VARARG || def) {
2315 mono_error_set_bad_image (error, m, "Found sentinel for methoddef or no vararg");
2316 g_free (pattrs);
2317 return NULL;
2319 if (method->sentinelpos >= 0) {
2320 mono_error_set_bad_image (error, m, "Found sentinel twice in the same signature.");
2321 g_free (pattrs);
2322 return NULL;
2324 method->sentinelpos = i;
2325 ptr++;
2327 method->params [i] = mono_metadata_parse_type_checked (m, container, pattrs ? pattrs [i+1] : 0, FALSE, ptr, &ptr, error);
2328 if (!method->params [i]) {
2329 mono_metadata_free_method_signature (method);
2330 g_free (pattrs);
2331 return NULL;
2333 if (!is_open)
2334 is_open = mono_class_is_open_constructed_type (method->params [i]);
2337 /* The sentinel could be missing if the caller does not pass any additional arguments */
2338 if (!def && method->call_convention == MONO_CALL_VARARG && method->sentinelpos < 0)
2339 method->sentinelpos = method->param_count;
2341 method->has_type_parameters = is_open;
2343 if (def && (method->call_convention == MONO_CALL_VARARG))
2344 method->sentinelpos = method->param_count;
2346 g_free (pattrs);
2348 if (rptr)
2349 *rptr = ptr;
2351 * Add signature to a cache and increase ref count...
2354 return method;
2358 * mono_metadata_parse_method_signature:
2359 * \param m metadata context
2360 * \param def the \c MethodDef index or 0 for \c Ref signatures.
2361 * \param ptr pointer to the signature metadata representation
2362 * \param rptr pointer updated to match the end of the decoded stream
2364 * Decode a method signature stored at \p ptr.
2365 * This is a Mono runtime internal function.
2367 * LOCKING: Assumes the loader lock is held.
2369 * \returns a \c MonoMethodSignature describing the signature.
2371 MonoMethodSignature *
2372 mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, const char **rptr)
2375 * This function MUST NOT be called by runtime code as it does error handling incorrectly.
2376 * Use mono_metadata_parse_method_signature_full instead.
2377 * It's ok to asser on failure as we no longer use it.
2379 ERROR_DECL (error);
2380 MonoMethodSignature *ret;
2381 ret = mono_metadata_parse_method_signature_full (m, NULL, def, ptr, rptr, error);
2382 mono_error_assert_ok (error);
2384 return ret;
2388 * mono_metadata_free_method_signature:
2389 * \param sig signature to destroy
2391 * Free the memory allocated in the signature \p sig.
2392 * This method needs to be robust and work also on partially-built
2393 * signatures, so it does extra checks.
2395 void
2396 mono_metadata_free_method_signature (MonoMethodSignature *sig)
2398 /* Everything is allocated from mempools */
2400 int i;
2401 if (sig->ret)
2402 mono_metadata_free_type (sig->ret);
2403 for (i = 0; i < sig->param_count; ++i) {
2404 if (sig->params [i])
2405 mono_metadata_free_type (sig->params [i]);
2410 void
2411 mono_metadata_free_inflated_signature (MonoMethodSignature *sig)
2413 int i;
2415 /* Allocated in inflate_generic_signature () */
2416 if (sig->ret)
2417 mono_metadata_free_type (sig->ret);
2418 for (i = 0; i < sig->param_count; ++i) {
2419 if (sig->params [i])
2420 mono_metadata_free_type (sig->params [i]);
2422 g_free (sig);
2425 static gboolean
2426 inflated_method_equal (gconstpointer a, gconstpointer b)
2428 const MonoMethodInflated *ma = (const MonoMethodInflated *)a;
2429 const MonoMethodInflated *mb = (const MonoMethodInflated *)b;
2430 if (ma->declaring != mb->declaring)
2431 return FALSE;
2432 return mono_metadata_generic_context_equal (&ma->context, &mb->context);
2435 static guint
2436 inflated_method_hash (gconstpointer a)
2438 const MonoMethodInflated *ma = (const MonoMethodInflated *)a;
2439 return (mono_metadata_generic_context_hash (&ma->context) ^ mono_aligned_addr_hash (ma->declaring));
2442 static gboolean
2443 inflated_signature_equal (gconstpointer a, gconstpointer b)
2445 const MonoInflatedMethodSignature *sig1 = (const MonoInflatedMethodSignature *)a;
2446 const MonoInflatedMethodSignature *sig2 = (const MonoInflatedMethodSignature *)b;
2448 /* sig->sig is assumed to be canonized */
2449 if (sig1->sig != sig2->sig)
2450 return FALSE;
2451 /* The generic instances are canonized */
2452 return mono_metadata_generic_context_equal (&sig1->context, &sig2->context);
2455 static guint
2456 inflated_signature_hash (gconstpointer a)
2458 const MonoInflatedMethodSignature *sig = (const MonoInflatedMethodSignature *)a;
2460 /* sig->sig is assumed to be canonized */
2461 return mono_metadata_generic_context_hash (&sig->context) ^ mono_aligned_addr_hash (sig->sig);
2464 /*static void
2465 dump_ginst (MonoGenericInst *ginst)
2467 int i;
2468 char *name;
2470 g_print ("Ginst: <");
2471 for (i = 0; i < ginst->type_argc; ++i) {
2472 if (i != 0)
2473 g_print (", ");
2474 name = mono_type_get_name (ginst->type_argv [i]);
2475 g_print ("%s", name);
2476 g_free (name);
2478 g_print (">");
2481 static gboolean
2482 aggregate_modifiers_equal (gconstpointer ka, gconstpointer kb)
2484 MonoAggregateModContainer *amods1 = (MonoAggregateModContainer *)ka;
2485 MonoAggregateModContainer *amods2 = (MonoAggregateModContainer *)kb;
2486 if (amods1->count != amods2->count)
2487 return FALSE;
2488 for (int i = 0; i < amods1->count; ++i) {
2489 if (amods1->modifiers [i].required != amods2->modifiers [i].required)
2490 return FALSE;
2491 if (!mono_metadata_type_equal_full (amods1->modifiers [i].type, amods2->modifiers [i].type, TRUE))
2492 return FALSE;
2494 return TRUE;
2497 static guint
2498 aggregate_modifiers_hash (gconstpointer a)
2500 const MonoAggregateModContainer *amods = (const MonoAggregateModContainer *)a;
2501 guint hash = 0;
2502 for (int i = 0; i < amods->count; ++i)
2504 // hash details borrowed from mono_metadata_generic_inst_hash
2505 hash *= 13;
2506 hash ^= (amods->modifiers [i].required << 8);
2507 hash += mono_metadata_type_hash (amods->modifiers [i].type);
2510 return hash;
2513 static gboolean type_in_image (MonoType *type, MonoImage *image);
2514 static gboolean aggregate_modifiers_in_image (MonoAggregateModContainer *amods, MonoImage *image);
2516 static gboolean
2517 signature_in_image (MonoMethodSignature *sig, MonoImage *image)
2519 gpointer iter = NULL;
2520 MonoType *p;
2522 while ((p = mono_signature_get_params_internal (sig, &iter)) != NULL)
2523 if (type_in_image (p, image))
2524 return TRUE;
2526 return type_in_image (mono_signature_get_return_type_internal (sig), image);
2529 static gboolean
2530 ginst_in_image (MonoGenericInst *ginst, MonoImage *image)
2532 int i;
2534 for (i = 0; i < ginst->type_argc; ++i) {
2535 if (type_in_image (ginst->type_argv [i], image))
2536 return TRUE;
2539 return FALSE;
2542 static gboolean
2543 gclass_in_image (MonoGenericClass *gclass, MonoImage *image)
2545 return m_class_get_image (gclass->container_class) == image ||
2546 ginst_in_image (gclass->context.class_inst, image);
2549 static gboolean
2550 type_in_image (MonoType *type, MonoImage *image)
2552 retry:
2553 if (type->has_cmods && mono_type_is_aggregate_mods (type))
2554 if (aggregate_modifiers_in_image (mono_type_get_amods (type), image))
2555 return TRUE;
2557 switch (type->type) {
2558 case MONO_TYPE_GENERICINST:
2559 return gclass_in_image (type->data.generic_class, image);
2560 case MONO_TYPE_PTR:
2561 type = type->data.type;
2562 goto retry;
2563 case MONO_TYPE_SZARRAY:
2564 type = m_class_get_byval_arg (type->data.klass);
2565 goto retry;
2566 case MONO_TYPE_ARRAY:
2567 type = m_class_get_byval_arg (type->data.array->eklass);
2568 goto retry;
2569 case MONO_TYPE_FNPTR:
2570 return signature_in_image (type->data.method, image);
2571 case MONO_TYPE_VAR:
2572 case MONO_TYPE_MVAR:
2573 return image == mono_get_image_for_generic_param (type->data.generic_param);
2574 default:
2575 /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type_internal () */
2576 return image == m_class_get_image (mono_class_from_mono_type_internal (type));
2580 gboolean
2581 mono_type_in_image (MonoType *type, MonoImage *image)
2583 return type_in_image (type, image);
2586 gboolean
2587 aggregate_modifiers_in_image (MonoAggregateModContainer *amods, MonoImage *image)
2589 for (int i = 0; i < amods->count; i++)
2590 if (type_in_image (amods->modifiers [i].type, image))
2591 return TRUE;
2592 return FALSE;
2595 static void
2596 image_sets_lock (void)
2598 mono_os_mutex_lock (&image_sets_mutex);
2601 static void
2602 image_sets_unlock (void)
2604 mono_os_mutex_unlock (&image_sets_mutex);
2607 //1103, 1327, 1597
2608 #define HASH_TABLE_SIZE 1103
2609 static MonoImageSet *img_set_cache [HASH_TABLE_SIZE];
2611 static guint32
2612 mix_hash (uintptr_t source)
2614 unsigned int hash = source;
2616 // Actual hash
2617 hash = (((hash * 215497) >> 16) ^ ((hash * 1823231) + hash));
2619 // Mix in highest bits on 64-bit systems only
2620 if (sizeof (source) > 4)
2621 hash = hash ^ ((source >> 31) >> 1);
2623 return hash;
2626 static guint32
2627 hash_images (MonoImage **images, int nimages)
2629 guint32 res = 0;
2630 int i;
2631 for (i = 0; i < nimages; ++i)
2632 res += mix_hash ((size_t)images [i]);
2634 return res;
2637 static gboolean
2638 compare_img_set (MonoImageSet *set, MonoImage **images, int nimages)
2640 int j, k;
2642 if (set->nimages != nimages)
2643 return FALSE;
2645 for (j = 0; j < nimages; ++j) {
2646 for (k = 0; k < nimages; ++k)
2647 if (set->images [k] == images [j])
2648 break; // Break on match
2650 // If we iterated all the way through set->images, images[j] was *not* found.
2651 if (k == nimages)
2652 break; // Break on "image not found"
2655 // If we iterated all the way through images without breaking, all items in images were found in set->images
2656 return j == nimages;
2660 static MonoImageSet*
2661 img_set_cache_get (MonoImage **images, int nimages)
2663 guint32 hash_code = hash_images (images, nimages);
2664 int index = hash_code % HASH_TABLE_SIZE;
2665 MonoImageSet *img = img_set_cache [index];
2666 if (!img || !compare_img_set (img, images, nimages)) {
2667 UnlockedIncrement (&img_set_cache_miss);
2668 return NULL;
2670 UnlockedIncrement (&img_set_cache_hit);
2671 return img;
2674 static void
2675 img_set_cache_add (MonoImageSet *set)
2677 guint32 hash_code = hash_images (set->images, set->nimages);
2678 int index = hash_code % HASH_TABLE_SIZE;
2679 img_set_cache [index] = set;
2682 static void
2683 img_set_cache_remove (MonoImageSet *is)
2685 guint32 hash_code = hash_images (is->images, is->nimages);
2686 int index = hash_code % HASH_TABLE_SIZE;
2687 if (img_set_cache [index] == is)
2688 img_set_cache [index] = NULL;
2691 * get_image_set:
2693 * Return a MonoImageSet representing the set of images in IMAGES.
2695 static MonoImageSet*
2696 get_image_set (MonoImage **images, int nimages)
2698 int i, j, k;
2699 MonoImageSet *set;
2700 GSList *l;
2702 /* Common case: Image set contains corlib only. If we've seen that case before, we cached the set. */
2703 if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set)
2704 return mscorlib_image_set;
2706 /* Happens with empty generic instances */
2707 // 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.
2708 if (nimages == 0)
2709 return mscorlib_image_set;
2711 set = img_set_cache_get (images, nimages);
2712 if (set)
2713 return set;
2715 image_sets_lock ();
2717 if (!image_sets)
2718 image_sets = g_ptr_array_new ();
2720 // Before we go on, we should check to see whether a MonoImageSet with these images already exists.
2721 // We can search the referred-by imagesets of any one of our images to do this. Arbitrarily pick one here:
2722 if (images [0] == mono_defaults.corlib && nimages > 1)
2723 l = images [1]->image_sets; // Prefer not to search the imagesets of corlib-- that will be a long list.
2724 else
2725 l = images [0]->image_sets;
2727 set = NULL;
2728 while (l) // Iterate over selected list, looking for an imageset with members equal to our target one
2730 set = (MonoImageSet *)l->data;
2732 if (set->nimages == nimages) { // Member count differs, this can't be it
2733 // Compare all members to all members-- order might be different
2734 for (j = 0; j < nimages; ++j) {
2735 for (k = 0; k < nimages; ++k)
2736 if (set->images [k] == images [j])
2737 break; // Break on match
2739 // If we iterated all the way through set->images, images[j] was *not* found.
2740 if (k == nimages)
2741 break; // Break on "image not found"
2744 // If we iterated all the way through images without breaking, all items in images were found in set->images
2745 if (j == nimages) {
2746 // Break on "found a set with equal members".
2747 // This happens in case of a hash collision with a previously cached set.
2748 break;
2752 l = l->next;
2755 // If we iterated all the way through l without breaking, the imageset does not already exist and we should create it
2756 if (!l) {
2757 set = g_new0 (MonoImageSet, 1);
2758 set->nimages = nimages;
2759 set->images = g_new0 (MonoImage*, nimages);
2760 mono_os_mutex_init_recursive (&set->lock);
2761 for (i = 0; i < nimages; ++i)
2762 set->images [i] = images [i];
2763 set->gclass_cache = mono_conc_hashtable_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
2764 set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
2765 set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
2766 set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
2768 set->szarray_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2769 set->array_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2771 set->aggregate_modifiers_cache = g_hash_table_new_full (aggregate_modifiers_hash, aggregate_modifiers_equal, NULL, (GDestroyNotify)free_aggregate_modifiers);
2773 for (i = 0; i < nimages; ++i)
2774 set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set);
2776 g_ptr_array_add (image_sets, set);
2777 UnlockedIncrement (&img_set_count); /* locked by image_sets_lock () */
2780 /* Cache the set. If there was a cache collision, the previously cached value will be replaced. */
2781 img_set_cache_add (set);
2783 if (nimages == 1 && images [0] == mono_defaults.corlib) {
2784 mono_memory_barrier ();
2785 mscorlib_image_set = set;
2788 image_sets_unlock ();
2790 return set;
2793 static void
2794 delete_image_set (MonoImageSet *set)
2796 int i;
2798 mono_conc_hashtable_destroy (set->gclass_cache);
2799 g_hash_table_destroy (set->ginst_cache);
2800 g_hash_table_destroy (set->gmethod_cache);
2801 g_hash_table_destroy (set->gsignature_cache);
2803 g_hash_table_destroy (set->szarray_cache);
2804 g_hash_table_destroy (set->array_cache);
2805 if (set->ptr_cache)
2806 g_hash_table_destroy (set->ptr_cache);
2808 g_hash_table_destroy (set->aggregate_modifiers_cache);
2810 for (i = 0; i < set->gshared_types_len; ++i) {
2811 if (set->gshared_types [i])
2812 g_hash_table_destroy (set->gshared_types [i]);
2814 g_free (set->gshared_types);
2816 mono_wrapper_caches_free (&set->wrapper_caches);
2818 image_sets_lock ();
2820 for (i = 0; i < set->nimages; ++i)
2821 set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set);
2823 g_ptr_array_remove (image_sets, set);
2825 image_sets_unlock ();
2827 img_set_cache_remove (set);
2829 if (set->mempool)
2830 mono_mempool_destroy (set->mempool);
2831 g_free (set->images);
2832 mono_os_mutex_destroy (&set->lock);
2833 g_free (set);
2836 void
2837 mono_image_set_lock (MonoImageSet *set)
2839 mono_os_mutex_lock (&set->lock);
2842 void
2843 mono_image_set_unlock (MonoImageSet *set)
2845 mono_os_mutex_unlock (&set->lock);
2848 gpointer
2849 mono_image_set_alloc (MonoImageSet *set, guint size)
2851 gpointer res;
2853 mono_image_set_lock (set);
2854 if (!set->mempool)
2855 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2856 res = mono_mempool_alloc (set->mempool, size);
2857 mono_image_set_unlock (set);
2859 return res;
2862 gpointer
2863 mono_image_set_alloc0 (MonoImageSet *set, guint size)
2865 gpointer res;
2867 mono_image_set_lock (set);
2868 if (!set->mempool)
2869 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2870 res = mono_mempool_alloc0 (set->mempool, size);
2871 mono_image_set_unlock (set);
2873 return res;
2876 char*
2877 mono_image_set_strdup (MonoImageSet *set, const char *s)
2879 char *res;
2881 mono_image_set_lock (set);
2882 if (!set->mempool)
2883 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2884 res = mono_mempool_strdup (set->mempool, s);
2885 mono_image_set_unlock (set);
2887 return res;
2890 // Get a descriptive string for a MonoImageSet
2891 // Callers are obligated to free buffer with g_free after use
2892 char *
2893 mono_image_set_description (MonoImageSet *set)
2895 GString *result = g_string_new (NULL);
2896 int img;
2897 g_string_append (result, "[");
2898 for (img = 0; img < set->nimages; img++)
2900 if (img > 0)
2901 g_string_append (result, ", ");
2902 g_string_append (result, set->images[img]->name);
2904 g_string_append (result, "]");
2905 return g_string_free (result, FALSE);
2909 * Structure used by the collect_..._images functions to store the image list.
2911 typedef struct {
2912 MonoImage *image_buf [64];
2913 MonoImage **images;
2914 int nimages, images_len;
2915 } CollectData;
2917 static void
2918 collect_data_init (CollectData *data)
2920 data->images = data->image_buf;
2921 data->images_len = 64;
2922 data->nimages = 0;
2925 static void
2926 collect_data_free (CollectData *data)
2928 if (data->images != data->image_buf)
2929 g_free (data->images);
2932 static void
2933 enlarge_data (CollectData *data)
2935 int new_len = data->images_len < 16 ? 16 : data->images_len * 2;
2936 MonoImage **d = g_new (MonoImage *, new_len);
2938 // FIXME: test this
2939 g_assert_not_reached ();
2940 memcpy (d, data->images, data->images_len);
2941 if (data->images != data->image_buf)
2942 g_free (data->images);
2943 data->images = d;
2944 data->images_len = new_len;
2947 static void
2948 add_image (MonoImage *image, CollectData *data)
2950 int i;
2952 /* The arrays are small, so use a linear search instead of a hash table */
2953 for (i = 0; i < data->nimages; ++i)
2954 if (data->images [i] == image)
2955 return;
2957 if (data->nimages == data->images_len)
2958 enlarge_data (data);
2960 data->images [data->nimages ++] = image;
2963 static void
2964 collect_type_images (MonoType *type, CollectData *data);
2966 static void
2967 collect_ginst_images (MonoGenericInst *ginst, CollectData *data)
2969 int i;
2971 for (i = 0; i < ginst->type_argc; ++i) {
2972 collect_type_images (ginst->type_argv [i], data);
2976 static void
2977 collect_gclass_images (MonoGenericClass *gclass, CollectData *data)
2979 add_image (m_class_get_image (gclass->container_class), data);
2980 if (gclass->context.class_inst)
2981 collect_ginst_images (gclass->context.class_inst, data);
2984 static void
2985 collect_signature_images (MonoMethodSignature *sig, CollectData *data)
2987 gpointer iter = NULL;
2988 MonoType *p;
2990 collect_type_images (mono_signature_get_return_type_internal (sig), data);
2991 while ((p = mono_signature_get_params_internal (sig, &iter)) != NULL)
2992 collect_type_images (p, data);
2995 static void
2996 collect_inflated_signature_images (MonoInflatedMethodSignature *sig, CollectData *data)
2998 collect_signature_images (sig->sig, data);
2999 if (sig->context.class_inst)
3000 collect_ginst_images (sig->context.class_inst, data);
3001 if (sig->context.method_inst)
3002 collect_ginst_images (sig->context.method_inst, data);
3005 static void
3006 collect_method_images (MonoMethodInflated *method, CollectData *data)
3008 MonoMethod *m = method->declaring;
3010 add_image (m_class_get_image (method->declaring->klass), data);
3011 if (method->context.class_inst)
3012 collect_ginst_images (method->context.class_inst, data);
3013 if (method->context.method_inst)
3014 collect_ginst_images (method->context.method_inst, data);
3016 * Dynamic assemblies have no references, so the images they depend on can be unloaded before them.
3018 if (image_is_dynamic (m_class_get_image (m->klass)))
3019 collect_signature_images (mono_method_signature_internal (m), data);
3022 static void
3023 collect_aggregate_modifiers_images (MonoAggregateModContainer *amods, CollectData *data)
3025 for (int i = 0; i < amods->count; ++i)
3026 collect_type_images (amods->modifiers [i].type, data);
3029 static void
3030 collect_type_images (MonoType *type, CollectData *data)
3032 retry:
3033 if (G_UNLIKELY (type->has_cmods && mono_type_is_aggregate_mods (type))) {
3034 collect_aggregate_modifiers_images (mono_type_get_amods (type), data);
3037 switch (type->type) {
3038 case MONO_TYPE_GENERICINST:
3039 collect_gclass_images (type->data.generic_class, data);
3040 break;
3041 case MONO_TYPE_PTR:
3042 type = type->data.type;
3043 goto retry;
3044 case MONO_TYPE_SZARRAY:
3045 type = m_class_get_byval_arg (type->data.klass);
3046 goto retry;
3047 case MONO_TYPE_ARRAY:
3048 type = m_class_get_byval_arg (type->data.array->eklass);
3049 goto retry;
3050 case MONO_TYPE_FNPTR:
3051 //return signature_in_image (type->data.method, image);
3052 g_assert_not_reached ();
3053 case MONO_TYPE_VAR:
3054 case MONO_TYPE_MVAR:
3056 MonoImage *image = mono_get_image_for_generic_param (type->data.generic_param);
3057 add_image (image, data);
3058 break;
3060 case MONO_TYPE_CLASS:
3061 case MONO_TYPE_VALUETYPE:
3062 add_image (m_class_get_image (mono_class_from_mono_type_internal (type)), data);
3063 break;
3064 default:
3065 add_image (mono_defaults.corlib, data);
3069 typedef struct {
3070 MonoImage *image;
3071 GSList *list;
3072 } CleanForImageUserData;
3074 static gboolean
3075 steal_gclass_in_image (gpointer key, gpointer value, gpointer data)
3077 MonoGenericClass *gclass = (MonoGenericClass *)key;
3078 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
3080 g_assert (gclass_in_image (gclass, user_data->image));
3082 user_data->list = g_slist_prepend (user_data->list, gclass);
3083 return TRUE;
3086 static gboolean
3087 steal_ginst_in_image (gpointer key, gpointer value, gpointer data)
3089 MonoGenericInst *ginst = (MonoGenericInst *)key;
3090 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
3092 // This doesn't work during corlib compilation
3093 //g_assert (ginst_in_image (ginst, user_data->image));
3095 user_data->list = g_slist_prepend (user_data->list, ginst);
3096 return TRUE;
3099 static gboolean
3100 steal_aggregate_modifiers_in_image (gpointer key, gpointer value, gpointer data)
3102 MonoAggregateModContainer *amods = (MonoAggregateModContainer *)key;
3103 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
3105 g_assert (aggregate_modifiers_in_image (amods, user_data->image));
3107 user_data->list = g_slist_prepend (user_data->list, amods);
3108 return TRUE;
3111 static gboolean
3112 inflated_method_in_image (gpointer key, gpointer value, gpointer data)
3114 MonoImage *image = (MonoImage *)data;
3115 MonoMethodInflated *method = (MonoMethodInflated *)key;
3117 // FIXME:
3118 // https://bugzilla.novell.com/show_bug.cgi?id=458168
3119 g_assert (m_class_get_image (method->declaring->klass) == image ||
3120 (method->context.class_inst && ginst_in_image (method->context.class_inst, image)) ||
3121 (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)));
3123 return TRUE;
3126 static gboolean
3127 inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
3129 MonoImage *image = (MonoImage *)data;
3130 MonoInflatedMethodSignature *sig = (MonoInflatedMethodSignature *)key;
3132 return signature_in_image (sig->sig, image) ||
3133 (sig->context.class_inst && ginst_in_image (sig->context.class_inst, image)) ||
3134 (sig->context.method_inst && ginst_in_image (sig->context.method_inst, image));
3137 static gboolean
3138 class_in_image (gpointer key, gpointer value, gpointer data)
3140 MonoImage *image = (MonoImage *)data;
3141 MonoClass *klass = (MonoClass *)key;
3143 g_assert (type_in_image (m_class_get_byval_arg (klass), image));
3145 return TRUE;
3148 static void
3149 check_gmethod (gpointer key, gpointer value, gpointer data)
3151 MonoMethodInflated *method = (MonoMethodInflated *)key;
3152 MonoImage *image = (MonoImage *)data;
3154 if (method->context.class_inst)
3155 g_assert (!ginst_in_image (method->context.class_inst, image));
3156 if (method->context.method_inst)
3157 g_assert (!ginst_in_image (method->context.method_inst, image));
3158 if (((MonoMethod*)method)->signature)
3159 g_assert (!signature_in_image (mono_method_signature_internal ((MonoMethod*)method), image));
3163 * check_image_sets:
3165 * Run a consistency check on the image set data structures.
3167 static G_GNUC_UNUSED void
3168 check_image_sets (MonoImage *image)
3170 int i;
3171 GSList *l = image->image_sets;
3173 if (!image_sets)
3174 return;
3176 for (i = 0; i < image_sets->len; ++i) {
3177 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
3179 if (!g_slist_find (l, set)) {
3180 g_hash_table_foreach (set->gmethod_cache, check_gmethod, image);
3185 void
3186 mono_metadata_clean_for_image (MonoImage *image)
3188 CleanForImageUserData ginst_data, gclass_data, amods_data;
3189 GSList *l, *set_list;
3191 //check_image_sets (image);
3194 * The data structures could reference each other so we delete them in two phases.
3195 * This is required because of the hashing functions in gclass/ginst_cache.
3197 ginst_data.image = gclass_data.image = image;
3198 ginst_data.list = gclass_data.list = NULL;
3199 amods_data.image = image;
3200 amods_data.list = NULL;
3202 /* Collect the items to delete */
3203 /* delete_image_set () modifies the lists so make a copy */
3204 for (l = image->image_sets; l; l = l->next) {
3205 MonoImageSet *set = (MonoImageSet *)l->data;
3207 mono_image_set_lock (set);
3208 mono_conc_hashtable_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data);
3209 g_hash_table_foreach_steal (set->ginst_cache, steal_ginst_in_image, &ginst_data);
3210 g_hash_table_foreach_remove (set->gmethod_cache, inflated_method_in_image, image);
3211 g_hash_table_foreach_remove (set->gsignature_cache, inflated_signature_in_image, image);
3213 g_hash_table_foreach_steal (set->szarray_cache, class_in_image, image);
3214 g_hash_table_foreach_steal (set->array_cache, class_in_image, image);
3215 if (set->ptr_cache)
3216 g_hash_table_foreach_steal (set->ptr_cache, class_in_image, image);
3218 g_hash_table_foreach_steal (set->aggregate_modifiers_cache, steal_aggregate_modifiers_in_image, &amods_data);
3220 mono_image_set_unlock (set);
3223 /* Delete the removed items */
3224 for (l = ginst_data.list; l; l = l->next)
3225 free_generic_inst ((MonoGenericInst *)l->data);
3226 for (l = gclass_data.list; l; l = l->next)
3227 free_generic_class ((MonoGenericClass *)l->data);
3228 for (l = amods_data.list; l; l = l->next)
3229 free_aggregate_modifiers ((MonoAggregateModContainer *)l->data);
3230 g_slist_free (ginst_data.list);
3231 g_slist_free (gclass_data.list);
3232 /* delete_image_set () modifies the lists so make a copy */
3233 set_list = g_slist_copy (image->image_sets);
3234 for (l = set_list; l; l = l->next) {
3235 MonoImageSet *set = (MonoImageSet *)l->data;
3237 delete_image_set (set);
3239 g_slist_free (set_list);
3242 static void
3243 free_inflated_method (MonoMethodInflated *imethod)
3245 MonoMethod *method = (MonoMethod*)imethod;
3247 if (method->signature)
3248 mono_metadata_free_inflated_signature (method->signature);
3250 if (method->wrapper_type)
3251 g_free (((MonoMethodWrapper*)method)->method_data);
3253 g_free (method);
3256 static void
3257 free_generic_inst (MonoGenericInst *ginst)
3259 int i;
3261 /* The ginst itself is allocated from the image set mempool */
3262 for (i = 0; i < ginst->type_argc; ++i)
3263 mono_metadata_free_type (ginst->type_argv [i]);
3266 static void
3267 free_generic_class (MonoGenericClass *gclass)
3269 /* The gclass itself is allocated from the image set mempool */
3270 if (gclass->cached_class && m_class_get_interface_id (gclass->cached_class))
3271 mono_unload_interface_id (gclass->cached_class);
3274 static void
3275 free_inflated_signature (MonoInflatedMethodSignature *sig)
3277 mono_metadata_free_inflated_signature (sig->sig);
3278 g_free (sig);
3281 static void
3282 free_aggregate_modifiers (MonoAggregateModContainer *amods)
3284 for (int i = 0; i < amods->count; i++)
3285 mono_metadata_free_type (amods->modifiers [i].type);
3286 /* the container itself is allocated in the image set mempool */
3290 * mono_metadata_get_inflated_signature:
3292 * Given an inflated signature and a generic context, return a canonical copy of the
3293 * signature. The returned signature might be equal to SIG or it might be a cached copy.
3295 MonoMethodSignature *
3296 mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericContext *context)
3298 MonoInflatedMethodSignature helper;
3299 MonoInflatedMethodSignature *res;
3300 CollectData data;
3301 MonoImageSet *set;
3303 helper.sig = sig;
3304 helper.context.class_inst = context->class_inst;
3305 helper.context.method_inst = context->method_inst;
3307 collect_data_init (&data);
3309 collect_inflated_signature_images (&helper, &data);
3311 set = get_image_set (data.images, data.nimages);
3313 collect_data_free (&data);
3315 mono_image_set_lock (set);
3317 res = (MonoInflatedMethodSignature *)g_hash_table_lookup (set->gsignature_cache, &helper);
3318 if (!res) {
3319 res = g_new0 (MonoInflatedMethodSignature, 1);
3320 res->sig = sig;
3321 res->context.class_inst = context->class_inst;
3322 res->context.method_inst = context->method_inst;
3323 g_hash_table_insert (set->gsignature_cache, res, res);
3326 mono_image_set_unlock (set);
3328 return res->sig;
3331 MonoImageSet *
3332 mono_metadata_get_image_set_for_type (MonoType *type)
3334 MonoImageSet *set;
3335 CollectData image_set_data;
3337 collect_data_init (&image_set_data);
3338 collect_type_images (type, &image_set_data);
3339 set = get_image_set (image_set_data.images, image_set_data.nimages);
3340 collect_data_free (&image_set_data);
3342 return set;
3345 MonoImageSet *
3346 mono_metadata_get_image_set_for_class (MonoClass *klass)
3348 return mono_metadata_get_image_set_for_type (m_class_get_byval_arg (klass));
3351 MonoImageSet *
3352 mono_metadata_get_image_set_for_method (MonoMethodInflated *method)
3354 MonoImageSet *set;
3355 CollectData image_set_data;
3357 collect_data_init (&image_set_data);
3358 collect_method_images (method, &image_set_data);
3359 set = get_image_set (image_set_data.images, image_set_data.nimages);
3360 collect_data_free (&image_set_data);
3362 return set;
3365 MonoImageSet *
3366 mono_metadata_get_image_set_for_aggregate_modifiers (MonoAggregateModContainer *amods)
3368 MonoImageSet *set;
3369 CollectData image_set_data;
3370 collect_data_init (&image_set_data);
3371 collect_aggregate_modifiers_images (amods, &image_set_data);
3372 set = get_image_set (image_set_data.images, image_set_data.nimages);
3373 collect_data_free (&image_set_data);
3375 return set;
3378 MonoImageSet *
3379 mono_metadata_merge_image_sets (MonoImageSet *set1, MonoImageSet *set2)
3381 MonoImage **images = g_newa (MonoImage*, set1->nimages + set2->nimages);
3383 /* Add images from set1 */
3384 memcpy (images, set1->images, sizeof (MonoImage*) * set1->nimages);
3386 int nimages = set1->nimages;
3387 // FIXME: Quaratic
3388 /* Add images from set2 */
3389 for (int i = 0; i < set2->nimages; ++i) {
3390 int j;
3391 for (j = 0; j < set1->nimages; ++j) {
3392 if (set2->images [i] == set1->images [j])
3393 break;
3395 if (j == set1->nimages)
3396 images [nimages ++] = set2->images [i];
3398 return get_image_set (images, nimages);
3401 static gboolean
3402 type_is_gtd (MonoType *type)
3404 switch (type->type) {
3405 case MONO_TYPE_CLASS:
3406 case MONO_TYPE_VALUETYPE:
3407 return mono_class_is_gtd (type->data.klass);
3408 default:
3409 return FALSE;
3414 * mono_metadata_get_generic_inst:
3416 * Given a list of types, return a MonoGenericInst that represents that list.
3417 * The returned MonoGenericInst has its own copy of the list of types. The list
3418 * passed in the argument can be freed, modified or disposed of.
3421 MonoGenericInst *
3422 mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
3424 MonoGenericInst *ginst;
3425 gboolean is_open;
3426 int i;
3427 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3429 for (i = 0; i < type_argc; ++i)
3430 if (mono_class_is_open_constructed_type (type_argv [i]))
3431 break;
3432 is_open = (i < type_argc);
3434 ginst = (MonoGenericInst *)g_alloca (size);
3435 memset (ginst, 0, MONO_SIZEOF_GENERIC_INST);
3436 ginst->is_open = is_open;
3437 ginst->type_argc = type_argc;
3438 memcpy (ginst->type_argv, type_argv, type_argc * sizeof (MonoType *));
3440 for (i = 0; i < type_argc; ++i) {
3441 MonoType *t = ginst->type_argv [i];
3442 if (type_is_gtd (t)) {
3443 ginst->type_argv [i] = mono_class_gtd_get_canonical_inst (t->data.klass);
3447 return mono_metadata_get_canonical_generic_inst (ginst);
3451 * mono_metadata_get_canonical_generic_inst:
3452 * \param candidate an arbitrary generic instantiation
3454 * \returns the canonical generic instantiation that represents the given
3455 * candidate by identifying the image set for the candidate instantiation and
3456 * finding the instance in the image set or adding a copy of the given instance
3457 * to the image set.
3459 * The returned MonoGenericInst has its own copy of the list of types. The list
3460 * passed in the argument can be freed, modified or disposed of.
3463 MonoGenericInst *
3464 mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate)
3466 CollectData data;
3467 int type_argc = candidate->type_argc;
3468 gboolean is_open = candidate->is_open;
3469 MonoImageSet *set;
3471 collect_data_init (&data);
3473 collect_ginst_images (candidate, &data);
3475 set = get_image_set (data.images, data.nimages);
3477 collect_data_free (&data);
3479 mono_image_set_lock (set);
3481 MonoGenericInst *ginst = (MonoGenericInst *)g_hash_table_lookup (set->ginst_cache, candidate);
3482 if (!ginst) {
3483 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3484 ginst = (MonoGenericInst *)mono_image_set_alloc0 (set, size);
3485 #ifndef MONO_SMALL_CONFIG
3486 ginst->id = mono_atomic_inc_i32 (&next_generic_inst_id);
3487 #endif
3488 ginst->is_open = is_open;
3489 ginst->type_argc = type_argc;
3491 for (int i = 0; i < type_argc; ++i)
3492 ginst->type_argv [i] = mono_metadata_type_dup (NULL, candidate->type_argv [i]);
3494 g_hash_table_insert (set->ginst_cache, ginst, ginst);
3497 mono_image_set_unlock (set);
3498 return ginst;
3501 MonoAggregateModContainer *
3502 mono_metadata_get_canonical_aggregate_modifiers (MonoAggregateModContainer *candidate)
3504 g_assert (candidate->count > 0);
3505 MonoImageSet *set = mono_metadata_get_image_set_for_aggregate_modifiers (candidate);
3507 mono_image_set_lock (set);
3509 MonoAggregateModContainer *amods = (MonoAggregateModContainer *)g_hash_table_lookup (set->aggregate_modifiers_cache, candidate);
3510 if (!amods) {
3511 size_t size = mono_sizeof_aggregate_modifiers (candidate->count);
3512 amods = (MonoAggregateModContainer *)mono_image_set_alloc0 (set, size);
3513 amods->count = candidate->count;
3514 for (int i = 0; i < candidate->count; ++i) {
3515 amods->modifiers [i].required = candidate->modifiers [i].required;
3516 amods->modifiers [i].type = mono_metadata_type_dup (NULL, candidate->modifiers [i].type);
3519 g_hash_table_insert (set->aggregate_modifiers_cache, amods, amods);
3521 mono_image_set_unlock (set);
3522 return amods;
3525 static gboolean
3526 mono_metadata_is_type_builder_generic_type_definition (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3528 MonoGenericContainer *container = mono_class_get_generic_container (container_class);
3530 if (!is_dynamic || m_class_was_typebuilder (container_class) || container->type_argc != inst->type_argc)
3531 return FALSE;
3532 return inst == container->context.class_inst;
3536 * mono_metadata_lookup_generic_class:
3538 * Returns a MonoGenericClass with the given properties.
3541 MonoGenericClass *
3542 mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3544 MonoGenericClass *gclass;
3545 MonoGenericClass helper;
3546 gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic);
3547 MonoImageSet *set;
3548 CollectData data;
3550 g_assert (mono_class_get_generic_container (container_class)->type_argc == inst->type_argc);
3552 memset (&helper, 0, sizeof(helper)); // act like g_new0
3553 helper.container_class = container_class;
3554 helper.context.class_inst = inst;
3555 helper.is_dynamic = is_dynamic; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
3556 helper.is_tb_open = is_tb_open;
3558 collect_data_init (&data);
3560 collect_gclass_images (&helper, &data);
3562 set = get_image_set (data.images, data.nimages);
3564 collect_data_free (&data);
3566 gclass = (MonoGenericClass *)mono_conc_hashtable_lookup (set->gclass_cache, &helper);
3568 /* A tripwire just to keep us honest */
3569 g_assert (!helper.cached_class);
3571 if (gclass)
3572 return gclass;
3574 gclass = mono_image_set_new0 (set, MonoGenericClass, 1);
3575 if (is_dynamic)
3576 gclass->is_dynamic = 1;
3578 gclass->is_tb_open = is_tb_open;
3579 gclass->container_class = container_class;
3580 gclass->context.class_inst = inst;
3581 gclass->context.method_inst = NULL;
3582 gclass->owner = set;
3583 if (inst == mono_class_get_generic_container (container_class)->context.class_inst && !is_tb_open)
3584 gclass->cached_class = container_class;
3586 mono_image_set_lock (set);
3588 MonoGenericClass *gclass2 = (MonoGenericClass*)mono_conc_hashtable_insert (set->gclass_cache, gclass, gclass);
3589 if (!gclass2)
3590 gclass2 = gclass;
3592 // g_hash_table_insert (set->gclass_cache, gclass, gclass);
3594 mono_image_set_unlock (set);
3596 return gclass2;
3600 * mono_metadata_inflate_generic_inst:
3602 * Instantiate the generic instance @ginst with the context @context.
3603 * Check @error for success.
3606 MonoGenericInst *
3607 mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context, MonoError *error)
3609 MonoType **type_argv;
3610 MonoGenericInst *nginst = NULL;
3611 int i, count = 0;
3613 error_init (error);
3615 if (!ginst->is_open)
3616 return ginst;
3618 type_argv = g_new0 (MonoType*, ginst->type_argc);
3620 for (i = 0; i < ginst->type_argc; i++) {
3621 type_argv [i] = mono_class_inflate_generic_type_checked (ginst->type_argv [i], context, error);
3622 if (!is_ok (error))
3623 goto cleanup;
3624 ++count;
3627 nginst = mono_metadata_get_generic_inst (ginst->type_argc, type_argv);
3629 cleanup:
3630 for (i = 0; i < count; i++)
3631 mono_metadata_free_type (type_argv [i]);
3632 g_free (type_argv);
3634 return nginst;
3637 MonoGenericInst *
3638 mono_metadata_parse_generic_inst (MonoImage *m, MonoGenericContainer *container,
3639 int count, const char *ptr, const char **rptr, MonoError *error)
3641 MonoType **type_argv;
3642 MonoGenericInst *ginst = NULL;
3643 int i, parse_count = 0;
3645 error_init (error);
3646 type_argv = g_new0 (MonoType*, count);
3648 for (i = 0; i < count; i++) {
3649 /* this can be a transient type, mono_metadata_get_generic_inst will allocate
3650 * a canonical one, if needed.
3652 MonoType *t = mono_metadata_parse_type_checked (m, container, 0, TRUE, ptr, &ptr, error);
3653 if (!t)
3654 goto cleanup;
3655 type_argv [i] = t;
3656 parse_count++;
3659 if (rptr)
3660 *rptr = ptr;
3662 g_assert (parse_count == count);
3663 ginst = mono_metadata_get_generic_inst (count, type_argv);
3665 cleanup:
3666 for (i = 0; i < parse_count; i++)
3667 mono_metadata_free_type (type_argv [i]);
3668 g_free (type_argv);
3670 return ginst;
3673 static gboolean
3674 do_mono_metadata_parse_generic_class (MonoType *type, MonoImage *m, MonoGenericContainer *container,
3675 const char *ptr, const char **rptr, MonoError *error)
3677 MonoGenericInst *inst;
3678 MonoClass *gklass;
3679 MonoType *gtype;
3680 int count;
3682 error_init (error);
3684 // XXX how about transient?
3685 gtype = mono_metadata_parse_type_checked (m, NULL, 0, FALSE, ptr, &ptr, error);
3686 if (gtype == NULL)
3687 return FALSE;
3689 gklass = mono_class_from_mono_type_internal (gtype);
3690 if (!mono_class_is_gtd (gklass)) {
3691 mono_error_set_bad_image (error, m, "Generic instance with non-generic definition");
3692 return FALSE;
3695 count = mono_metadata_decode_value (ptr, &ptr);
3696 inst = mono_metadata_parse_generic_inst (m, container, count, ptr, &ptr, error);
3697 if (inst == NULL)
3698 return FALSE;
3700 if (rptr)
3701 *rptr = ptr;
3703 type->data.generic_class = mono_metadata_lookup_generic_class (gklass, inst, FALSE);
3704 return TRUE;
3708 * select_container:
3709 * @gc: The generic container to normalize
3710 * @type: The kind of generic parameters the resulting generic-container should contain
3713 static MonoGenericContainer *
3714 select_container (MonoGenericContainer *gc, MonoTypeEnum type)
3716 gboolean is_var = (type == MONO_TYPE_VAR);
3717 if (!gc)
3718 return NULL;
3720 g_assert (is_var || type == MONO_TYPE_MVAR);
3722 if (is_var) {
3723 if (gc->is_method || gc->parent)
3725 * The current MonoGenericContainer is a generic method -> its `parent'
3726 * points to the containing class'es container.
3728 return gc->parent;
3731 return gc;
3734 MonoGenericContainer *
3735 mono_get_anonymous_container_for_image (MonoImage *image, gboolean is_mvar)
3737 MonoGenericContainer **container_pointer;
3738 if (is_mvar)
3739 container_pointer = &image->anonymous_generic_method_container;
3740 else
3741 container_pointer = &image->anonymous_generic_class_container;
3742 MonoGenericContainer *result = *container_pointer;
3744 // This container has never been created; make it now.
3745 if (!result)
3747 // Note this is never deallocated anywhere-- it exists for the lifetime of the image it's allocated from
3748 result = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
3749 result->owner.image = image;
3750 result->is_anonymous = TRUE;
3751 result->is_method = is_mvar;
3753 // If another thread already made a container, use that and leak this new one.
3754 // (Technically it would currently be safe to just assign instead of CASing.)
3755 MonoGenericContainer *exchange = (MonoGenericContainer *)mono_atomic_cas_ptr ((volatile gpointer *)container_pointer, result, NULL);
3756 if (exchange)
3757 result = exchange;
3759 return result;
3762 #define FAST_GPARAM_CACHE_SIZE 16
3764 static MonoGenericParam*
3765 lookup_anon_gparam (MonoImage *image, MonoGenericContainer *container, gint32 param_num, gboolean is_mvar)
3767 if (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE) {
3768 MonoGenericParam *cache = is_mvar ? image->mvar_gparam_cache_fast : image->var_gparam_cache_fast;
3769 if (!cache)
3770 return NULL;
3771 return &cache[param_num];
3772 } else {
3773 MonoGenericParam key;
3774 memset (&key, 0, sizeof (key));
3775 key.owner = container;
3776 key.num = param_num;
3777 key.gshared_constraint = NULL;
3778 MonoConcurrentHashTable *cache = is_mvar ? image->mvar_gparam_cache : image->var_gparam_cache;
3779 if (!cache)
3780 return NULL;
3781 return (MonoGenericParam*)mono_conc_hashtable_lookup (cache, &key);
3785 static MonoGenericParam*
3786 publish_anon_gparam_fast (MonoImage *image, MonoGenericContainer *container, gint32 param_num)
3788 g_assert (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE);
3789 MonoGenericParam **cache = container->is_method ? &image->mvar_gparam_cache_fast : &image->var_gparam_cache_fast;
3790 if (!*cache) {
3791 mono_image_lock (image);
3792 if (!*cache) {
3793 *cache = (MonoGenericParam*)mono_image_alloc0 (image, sizeof (MonoGenericParam) * FAST_GPARAM_CACHE_SIZE);
3794 for (gint32 i = 0; i < FAST_GPARAM_CACHE_SIZE; ++i) {
3795 MonoGenericParam *param = &(*cache)[i];
3796 param->owner = container;
3797 param->num = i;
3800 mono_image_unlock (image);
3802 return &(*cache)[param_num];
3806 * publish_anon_gparam_slow:
3808 * Publish \p gparam anonymous generic parameter to the anon gparam cache for \p image.
3810 * LOCKING: takes the image lock.
3812 static MonoGenericParam*
3813 publish_anon_gparam_slow (MonoImage *image, MonoGenericParam *gparam)
3815 MonoConcurrentHashTable **cache = gparam->owner->is_method ? &image->mvar_gparam_cache : &image->var_gparam_cache;
3816 if (!*cache) {
3817 mono_image_lock (image);
3818 if (!*cache) {
3819 MonoConcurrentHashTable *ht = mono_conc_hashtable_new ((GHashFunc)mono_metadata_generic_param_hash,
3820 (GEqualFunc) mono_metadata_generic_param_equal);
3821 mono_atomic_store_release (cache, ht);
3823 mono_image_unlock (image);
3825 MonoGenericParam *other = (MonoGenericParam*)mono_conc_hashtable_insert (*cache, gparam, gparam);
3826 // If another thread published first return their param, otherwise return ours.
3827 return other ? other : gparam;
3831 * mono_metadata_create_anon_gparam:
3832 * \param image the MonoImage that owns the anonymous generic parameter
3833 * \param param_num the parameter number
3834 * \param is_mvar TRUE if this is a method generic parameter, FALSE if it's a class generic parameter.
3836 * Returns: a new, or exisisting \c MonoGenericParam for an anonymous generic parameter with the given properties.
3838 * LOCKING: takes the image lock.
3840 MonoGenericParam*
3841 mono_metadata_create_anon_gparam (MonoImage *image, gint32 param_num, gboolean is_mvar)
3843 MonoGenericContainer *container = mono_get_anonymous_container_for_image (image, is_mvar);
3844 MonoGenericParam *gparam = lookup_anon_gparam (image, container, param_num, is_mvar);
3845 if (gparam)
3846 return gparam;
3847 if (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE) {
3848 return publish_anon_gparam_fast (image, container, param_num);
3849 } else {
3850 // Create a candidate generic param and try to insert it in the cache.
3851 // If multiple threads both try to publish the same param, all but one
3852 // will leak, but that's okay.
3853 gparam = (MonoGenericParam*)mono_image_alloc0 (image, sizeof (MonoGenericParam));
3854 gparam->owner = container;
3855 gparam->num = param_num;
3857 return publish_anon_gparam_slow (image, gparam);
3862 * mono_metadata_parse_generic_param:
3863 * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
3864 * see mono_metadata_parse_type_checked() for details.
3865 * Internal routine to parse a generic type parameter.
3866 * LOCKING: Acquires the loader lock
3868 static MonoGenericParam *
3869 mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_container,
3870 MonoTypeEnum type, const char *ptr, const char **rptr, MonoError *error)
3872 int index = mono_metadata_decode_value (ptr, &ptr);
3873 if (rptr)
3874 *rptr = ptr;
3876 error_init (error);
3878 generic_container = select_container (generic_container, type);
3879 if (!generic_container) {
3880 gboolean is_mvar = FALSE;
3881 switch (type)
3883 case MONO_TYPE_VAR:
3884 break;
3885 case MONO_TYPE_MVAR:
3886 is_mvar = TRUE;
3887 break;
3888 default:
3889 g_error ("Cerating generic param object with invalid MonoType"); // This is not a generic param
3892 return mono_metadata_create_anon_gparam (m, index, is_mvar);
3895 if (index >= generic_container->type_argc) {
3896 mono_error_set_bad_image (error, m, "Invalid generic %s parameter index %d, max index is %d",
3897 generic_container->is_method ? "method" : "type",
3898 index, generic_container->type_argc);
3899 return NULL;
3902 //This can't return NULL
3903 return mono_generic_container_get_param (generic_container, index);
3907 * mono_metadata_get_shared_type:
3909 * Return a shared instance of TYPE, if available, NULL otherwise.
3910 * Shared MonoType instances help save memory. Their contents should not be modified
3911 * by the caller. They do not need to be freed as their lifetime is bound by either
3912 * the lifetime of the runtime (builtin types), or the lifetime of the MonoClass
3913 * instance they are embedded in. If they are freed, they should be freed using
3914 * mono_metadata_free_type () instead of g_free ().
3916 MonoType*
3917 mono_metadata_get_shared_type (MonoType *type)
3919 MonoType *cached;
3921 /* No need to use locking since nobody is modifying the hash table */
3922 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type)))
3923 return cached;
3925 switch (type->type){
3926 case MONO_TYPE_CLASS:
3927 case MONO_TYPE_VALUETYPE:
3928 if (type == m_class_get_byval_arg (type->data.klass))
3929 return type;
3930 if (type == m_class_get_this_arg (type->data.klass))
3931 return type;
3932 break;
3933 default:
3934 break;
3937 return NULL;
3940 static gboolean
3941 compare_type_literals (MonoImage *image, int class_type, int type_type, MonoError *error)
3943 error_init (error);
3945 /* _byval_arg.type can be zero if we're decoding a type that references a class been loading.
3946 * See mcs/test/gtest-440. and #650936.
3947 * FIXME This better be moved to the metadata verifier as it can catch more cases.
3949 if (!class_type)
3950 return TRUE;
3951 /* NET 1.1 assemblies might encode string and object in a denormalized way.
3952 * See #675464.
3954 if (class_type == type_type)
3955 return TRUE;
3957 if (type_type == MONO_TYPE_CLASS) {
3958 if (class_type == MONO_TYPE_STRING || class_type == MONO_TYPE_OBJECT)
3959 return TRUE;
3960 //XXX stringify this argument
3961 mono_error_set_bad_image (error, image, "Expected reference type but got type kind %d", class_type);
3962 return FALSE;
3965 g_assert (type_type == MONO_TYPE_VALUETYPE);
3966 switch (class_type) {
3967 case MONO_TYPE_BOOLEAN:
3968 case MONO_TYPE_CHAR:
3969 case MONO_TYPE_I1:
3970 case MONO_TYPE_U1:
3971 case MONO_TYPE_I2:
3972 case MONO_TYPE_U2:
3973 case MONO_TYPE_I4:
3974 case MONO_TYPE_U4:
3975 case MONO_TYPE_I8:
3976 case MONO_TYPE_U8:
3977 case MONO_TYPE_R4:
3978 case MONO_TYPE_R8:
3979 case MONO_TYPE_I:
3980 case MONO_TYPE_U:
3981 case MONO_TYPE_CLASS:
3982 return TRUE;
3983 default:
3984 //XXX stringify this argument
3985 mono_error_set_bad_image (error, image, "Expected value type but got type kind %d", class_type);
3986 return FALSE;
3990 static gboolean
3991 verify_var_type_and_container (MonoImage *image, int var_type, MonoGenericContainer *container, MonoError *error)
3993 error_init (error);
3994 if (var_type == MONO_TYPE_MVAR) {
3995 if (!container->is_method) { //MVAR and a method container
3996 mono_error_set_bad_image (error, image, "MVAR parsed in a context without a method container");
3997 return FALSE;
3999 } else {
4000 if (!(!container->is_method || //VAR and class container
4001 (container->is_method && container->parent))) { //VAR and method container with parent
4002 mono_error_set_bad_image (error, image, "VAR parsed in a context without a class container");
4003 return FALSE;
4006 return TRUE;
4010 * do_mono_metadata_parse_type:
4011 * @type: MonoType to be filled in with the return value
4012 * @m: image context
4013 * @generic_context: generics_context
4014 * @transient: whenever to allocate data from the heap
4015 * @ptr: pointer to the encoded type
4016 * @rptr: pointer where the end of the encoded type is saved
4018 * Internal routine used to "fill" the contents of @type from an
4019 * allocated pointer. This is done this way to avoid doing too
4020 * many mini-allocations (particularly for the MonoFieldType which
4021 * most of the time is just a MonoType, but sometimes might be augmented).
4023 * This routine is used by mono_metadata_parse_type and
4024 * mono_metadata_parse_field_type
4026 * This extracts a Type as specified in Partition II (22.2.12)
4028 * Returns: FALSE if the type could not be loaded
4030 static gboolean
4031 do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container,
4032 gboolean transient, const char *ptr, const char **rptr, MonoError *error)
4034 error_init (error);
4036 type->type = (MonoTypeEnum)mono_metadata_decode_value (ptr, &ptr);
4038 switch (type->type){
4039 case MONO_TYPE_VOID:
4040 case MONO_TYPE_BOOLEAN:
4041 case MONO_TYPE_CHAR:
4042 case MONO_TYPE_I1:
4043 case MONO_TYPE_U1:
4044 case MONO_TYPE_I2:
4045 case MONO_TYPE_U2:
4046 case MONO_TYPE_I4:
4047 case MONO_TYPE_U4:
4048 case MONO_TYPE_I8:
4049 case MONO_TYPE_U8:
4050 case MONO_TYPE_R4:
4051 case MONO_TYPE_R8:
4052 case MONO_TYPE_I:
4053 case MONO_TYPE_U:
4054 case MONO_TYPE_STRING:
4055 case MONO_TYPE_OBJECT:
4056 case MONO_TYPE_TYPEDBYREF:
4057 break;
4058 case MONO_TYPE_VALUETYPE:
4059 case MONO_TYPE_CLASS: {
4060 guint32 token;
4061 MonoClass *klass;
4062 token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr);
4063 klass = mono_class_get_checked (m, token, error);
4064 type->data.klass = klass;
4065 if (!klass)
4066 return FALSE;
4068 if (!compare_type_literals (m, m_class_get_byval_arg (klass)->type, type->type, error))
4069 return FALSE;
4071 break;
4073 case MONO_TYPE_SZARRAY: {
4074 MonoType *etype = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
4075 if (!etype)
4076 return FALSE;
4078 type->data.klass = mono_class_from_mono_type_internal (etype);
4080 if (transient)
4081 mono_metadata_free_type (etype);
4083 g_assert (type->data.klass); //This was previously a check for NULL, but mcfmt should never fail. It can return a borken MonoClass, but should return at least something.
4084 break;
4086 case MONO_TYPE_PTR: {
4087 type->data.type = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
4088 if (!type->data.type)
4089 return FALSE;
4090 break;
4092 case MONO_TYPE_FNPTR: {
4093 type->data.method = mono_metadata_parse_method_signature_full (m, container, 0, ptr, &ptr, error);
4094 if (!type->data.method)
4095 return FALSE;
4096 break;
4098 case MONO_TYPE_ARRAY: {
4099 type->data.array = mono_metadata_parse_array_internal (m, container, transient, ptr, &ptr, error);
4100 if (!type->data.array)
4101 return FALSE;
4102 break;
4104 case MONO_TYPE_MVAR:
4105 case MONO_TYPE_VAR: {
4106 if (container && !verify_var_type_and_container (m, type->type, container, error))
4107 return FALSE;
4109 type->data.generic_param = mono_metadata_parse_generic_param (m, container, type->type, ptr, &ptr, error);
4110 if (!type->data.generic_param)
4111 return FALSE;
4113 break;
4115 case MONO_TYPE_GENERICINST: {
4116 if (!do_mono_metadata_parse_generic_class (type, m, container, ptr, &ptr, error))
4117 return FALSE;
4118 break;
4120 default:
4121 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);
4122 return FALSE;
4125 if (rptr)
4126 *rptr = ptr;
4127 return TRUE;
4131 * mono_metadata_free_type:
4132 * \param type type to free
4134 * Free the memory allocated for type \p type which is allocated on the heap.
4136 void
4137 mono_metadata_free_type (MonoType *type)
4139 if (type >= builtin_types && type < builtin_types + NBUILTIN_TYPES ())
4140 return;
4142 switch (type->type){
4143 case MONO_TYPE_OBJECT:
4144 case MONO_TYPE_STRING:
4145 if (!type->data.klass)
4146 break;
4147 /* fall through */
4148 case MONO_TYPE_CLASS:
4149 case MONO_TYPE_VALUETYPE:
4150 if (type == m_class_get_byval_arg (type->data.klass) || type == m_class_get_this_arg (type->data.klass))
4151 return;
4152 break;
4153 case MONO_TYPE_PTR:
4154 mono_metadata_free_type (type->data.type);
4155 break;
4156 case MONO_TYPE_FNPTR:
4157 mono_metadata_free_method_signature (type->data.method);
4158 break;
4159 case MONO_TYPE_ARRAY:
4160 mono_metadata_free_array (type->data.array);
4161 break;
4162 default:
4163 break;
4166 g_free (type);
4169 #if 0
4170 static void
4171 hex_dump (const char *buffer, int base, int count)
4173 int show_header = 1;
4174 int i;
4176 if (count < 0){
4177 count = -count;
4178 show_header = 0;
4181 for (i = 0; i < count; i++){
4182 if (show_header)
4183 if ((i % 16) == 0)
4184 printf ("\n0x%08x: ", (unsigned char) base + i);
4186 printf ("%02x ", (unsigned char) (buffer [i]));
4188 fflush (stdout);
4190 #endif
4192 /**
4193 * @ptr: Points to the beginning of the Section Data (25.3)
4195 static MonoExceptionClause*
4196 parse_section_data (MonoImage *m, int *num_clauses, const unsigned char *ptr, MonoError *error)
4198 unsigned char sect_data_flags;
4199 int is_fat;
4200 guint32 sect_data_len;
4201 MonoExceptionClause* clauses = NULL;
4203 error_init (error);
4205 while (1) {
4206 /* align on 32-bit boundary */
4207 ptr = dword_align (ptr);
4208 sect_data_flags = *ptr;
4209 ptr++;
4211 is_fat = sect_data_flags & METHOD_HEADER_SECTION_FAT_FORMAT;
4212 if (is_fat) {
4213 sect_data_len = (ptr [2] << 16) | (ptr [1] << 8) | ptr [0];
4214 ptr += 3;
4215 } else {
4216 sect_data_len = ptr [0];
4217 ++ptr;
4220 if (sect_data_flags & METHOD_HEADER_SECTION_EHTABLE) {
4221 const unsigned char *p = dword_align (ptr);
4222 int i;
4223 *num_clauses = is_fat ? sect_data_len / 24: sect_data_len / 12;
4224 /* we could just store a pointer if we don't need to byteswap */
4225 clauses = (MonoExceptionClause *)g_malloc0 (sizeof (MonoExceptionClause) * (*num_clauses));
4226 for (i = 0; i < *num_clauses; ++i) {
4227 MonoExceptionClause *ec = &clauses [i];
4228 guint32 tof_value;
4229 if (is_fat) {
4230 ec->flags = read32 (p);
4231 ec->try_offset = read32 (p + 4);
4232 ec->try_len = read32 (p + 8);
4233 ec->handler_offset = read32 (p + 12);
4234 ec->handler_len = read32 (p + 16);
4235 tof_value = read32 (p + 20);
4236 p += 24;
4237 } else {
4238 ec->flags = read16 (p);
4239 ec->try_offset = read16 (p + 2);
4240 ec->try_len = *(p + 4);
4241 ec->handler_offset = read16 (p + 5);
4242 ec->handler_len = *(p + 7);
4243 tof_value = read32 (p + 8);
4244 p += 12;
4246 if (ec->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4247 ec->data.filter_offset = tof_value;
4248 } else if (ec->flags == MONO_EXCEPTION_CLAUSE_NONE) {
4249 ec->data.catch_class = NULL;
4250 if (tof_value) {
4251 ec->data.catch_class = mono_class_get_checked (m, tof_value, error);
4252 if (!is_ok (error)) {
4253 g_free (clauses);
4254 return NULL;
4257 } else {
4258 ec->data.catch_class = NULL;
4260 /* g_print ("try %d: %x %04x-%04x %04x\n", i, ec->flags, ec->try_offset, ec->try_offset+ec->try_len, ec->try_len); */
4264 if (sect_data_flags & METHOD_HEADER_SECTION_MORE_SECTS)
4265 ptr += sect_data_len - 4; /* LAMESPEC: it seems the size includes the header */
4266 else
4267 return clauses;
4272 * mono_method_get_header_summary:
4273 * @method: The method to get the header.
4274 * @summary: Where to store the header
4277 * Returns: TRUE if the header was properly decoded.
4279 gboolean
4280 mono_method_get_header_summary (MonoMethod *method, MonoMethodHeaderSummary *summary)
4282 int idx;
4283 guint32 rva;
4284 MonoImage* img;
4285 const char *ptr;
4286 unsigned char flags, format;
4287 guint16 fat_flags;
4288 ERROR_DECL (error);
4290 /*Only the GMD has a pointer to the metadata.*/
4291 while (method->is_inflated)
4292 method = ((MonoMethodInflated*)method)->declaring;
4294 summary->code = NULL;
4295 summary->code_size = 0;
4296 summary->max_stack = 0;
4297 summary->has_clauses = FALSE;
4298 summary->has_locals = FALSE;
4300 /*FIXME extract this into a MACRO and share it with mono_method_get_header*/
4301 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
4302 return FALSE;
4304 if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
4305 MonoMethodHeader *header = ((MonoMethodWrapper *)method)->header;
4306 if (!header)
4307 return FALSE;
4308 summary->code = header->code;
4309 summary->code_size = header->code_size;
4310 summary->max_stack = header->max_stack;
4311 summary->has_clauses = header->num_clauses > 0;
4312 summary->has_locals = header->num_locals > 0;
4313 return TRUE;
4317 idx = mono_metadata_token_index (method->token);
4318 img = m_class_get_image (method->klass);
4319 rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
4321 /*We must run the verifier since we'll be decoding it.*/
4322 if (!mono_verifier_verify_method_header (img, rva, error)) {
4323 mono_error_cleanup (error);
4324 return FALSE;
4327 ptr = mono_image_rva_map (img, rva);
4328 if (!ptr)
4329 return FALSE;
4331 flags = *(const unsigned char *)ptr;
4332 format = flags & METHOD_HEADER_FORMAT_MASK;
4334 switch (format) {
4335 case METHOD_HEADER_TINY_FORMAT:
4336 ptr++;
4337 summary->max_stack = 8;
4338 summary->code = (unsigned char *) ptr;
4339 summary->code_size = flags >> 2;
4340 break;
4341 case METHOD_HEADER_FAT_FORMAT:
4342 fat_flags = read16 (ptr);
4343 ptr += 2;
4344 summary->max_stack = read16 (ptr);
4345 ptr += 2;
4346 summary->code_size = read32 (ptr);
4347 ptr += 4;
4348 summary->has_locals = !!read32 (ptr);
4349 ptr += 4;
4350 if (fat_flags & METHOD_HEADER_MORE_SECTS)
4351 summary->has_clauses = TRUE;
4352 summary->code = (unsigned char *) ptr;
4353 break;
4354 default:
4355 return FALSE;
4357 return TRUE;
4361 * mono_metadata_parse_mh_full:
4362 * @m: metadata context
4363 * @generic_context: generics context
4364 * @ptr: pointer to the method header.
4366 * Decode the method header at @ptr, including pointer to the IL code,
4367 * info about local variables and optional exception tables.
4368 * This is a Mono runtime internal function.
4370 * LOCKING: Acquires the loader lock.
4372 * Returns: a transient MonoMethodHeader allocated from the heap.
4374 MonoMethodHeader *
4375 mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, const char *ptr, MonoError *error)
4377 MonoMethodHeader *mh = NULL;
4378 unsigned char flags = *(const unsigned char *) ptr;
4379 unsigned char format = flags & METHOD_HEADER_FORMAT_MASK;
4380 guint16 fat_flags;
4381 guint32 local_var_sig_tok, max_stack, code_size, init_locals;
4382 const unsigned char *code;
4383 MonoExceptionClause* clauses = NULL;
4384 int num_clauses = 0;
4385 MonoTableInfo *t = &m->tables [MONO_TABLE_STANDALONESIG];
4386 guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
4388 error_init (error);
4390 if (!ptr) {
4391 mono_error_set_bad_image (error, m, "Method header with null pointer");
4392 return NULL;
4395 switch (format) {
4396 case METHOD_HEADER_TINY_FORMAT:
4397 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER);
4398 ptr++;
4399 mh->max_stack = 8;
4400 mh->is_transient = TRUE;
4401 local_var_sig_tok = 0;
4402 mh->code_size = flags >> 2;
4403 mh->code = (unsigned char*)ptr;
4404 return mh;
4405 case METHOD_HEADER_FAT_FORMAT:
4406 fat_flags = read16 (ptr);
4407 ptr += 2;
4408 max_stack = read16 (ptr);
4409 ptr += 2;
4410 code_size = read32 (ptr);
4411 ptr += 4;
4412 local_var_sig_tok = read32 (ptr);
4413 ptr += 4;
4415 if (fat_flags & METHOD_HEADER_INIT_LOCALS)
4416 init_locals = 1;
4417 else
4418 init_locals = 0;
4420 code = (unsigned char*)ptr;
4422 if (!(fat_flags & METHOD_HEADER_MORE_SECTS))
4423 break;
4426 * There are more sections
4428 ptr = (char*)code + code_size;
4429 break;
4430 default:
4431 mono_error_set_bad_image (error, m, "Invalid method header format %d", format);
4432 return NULL;
4435 if (local_var_sig_tok) {
4436 int idx = (local_var_sig_tok & 0xffffff)-1;
4437 if (idx >= t->rows || idx < 0) {
4438 mono_error_set_bad_image (error, m, "Invalid method header local vars signature token 0x%8x", idx);
4439 goto fail;
4441 mono_metadata_decode_row (t, idx, cols, 1);
4443 if (!mono_verifier_verify_standalone_signature (m, cols [MONO_STAND_ALONE_SIGNATURE], error))
4444 goto fail;
4446 if (fat_flags & METHOD_HEADER_MORE_SECTS) {
4447 clauses = parse_section_data (m, &num_clauses, (const unsigned char*)ptr, error);
4448 goto_if_nok (error, fail);
4450 if (local_var_sig_tok) {
4451 const char *locals_ptr;
4452 int len=0, i;
4454 locals_ptr = mono_metadata_blob_heap (m, cols [MONO_STAND_ALONE_SIGNATURE]);
4455 mono_metadata_decode_blob_size (locals_ptr, &locals_ptr);
4456 if (*locals_ptr != 0x07)
4457 g_warning ("wrong signature for locals blob");
4458 locals_ptr++;
4459 len = mono_metadata_decode_value (locals_ptr, &locals_ptr);
4460 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + len * sizeof (MonoType*) + num_clauses * sizeof (MonoExceptionClause));
4461 mh->num_locals = len;
4462 for (i = 0; i < len; ++i) {
4463 mh->locals [i] = mono_metadata_parse_type_internal (m, container, 0, TRUE, locals_ptr, &locals_ptr, error);
4464 goto_if_nok (error, fail);
4466 } else {
4467 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + num_clauses * sizeof (MonoExceptionClause));
4469 mh->code = code;
4470 mh->code_size = code_size;
4471 mh->max_stack = max_stack;
4472 mh->is_transient = TRUE;
4473 mh->init_locals = init_locals;
4474 if (clauses) {
4475 MonoExceptionClause* clausesp = (MonoExceptionClause*)&mh->locals [mh->num_locals];
4476 memcpy (clausesp, clauses, num_clauses * sizeof (MonoExceptionClause));
4477 g_free (clauses);
4478 mh->clauses = clausesp;
4479 mh->num_clauses = num_clauses;
4481 return mh;
4482 fail:
4483 g_free (clauses);
4484 g_free (mh);
4485 return NULL;
4490 * mono_metadata_parse_mh:
4491 * \param generic_context generics context
4492 * \param ptr pointer to the method header.
4494 * Decode the method header at \p ptr, including pointer to the IL code,
4495 * info about local variables and optional exception tables.
4497 * \returns a transient \c MonoMethodHeader allocated from the heap.
4499 MonoMethodHeader *
4500 mono_metadata_parse_mh (MonoImage *m, const char *ptr)
4502 ERROR_DECL (error);
4503 MonoMethodHeader *header = mono_metadata_parse_mh_full (m, NULL, ptr, error);
4504 mono_error_cleanup (error);
4505 return header;
4509 * mono_metadata_free_mh:
4510 * \param mh a method header
4512 * Free the memory allocated for the method header.
4514 void
4515 mono_metadata_free_mh (MonoMethodHeader *mh)
4517 int i;
4519 /* If it is not transient it means it's part of a wrapper method,
4520 * or a SRE-generated method, so the lifetime in that case is
4521 * dictated by the method's own lifetime
4523 if (mh && mh->is_transient) {
4524 for (i = 0; i < mh->num_locals; ++i)
4525 mono_metadata_free_type (mh->locals [i]);
4526 g_free (mh);
4531 * mono_method_header_get_code:
4532 * \param header a \c MonoMethodHeader pointer
4533 * \param code_size memory location for returning the code size
4534 * \param max_stack memory location for returning the max stack
4536 * Method header accessor to retreive info about the IL code properties:
4537 * a pointer to the IL code itself, the size of the code and the max number
4538 * of stack slots used by the code.
4540 * \returns pointer to the IL code represented by the method header.
4542 const unsigned char*
4543 mono_method_header_get_code (MonoMethodHeader *header, guint32* code_size, guint32* max_stack)
4545 if (code_size)
4546 *code_size = header->code_size;
4547 if (max_stack)
4548 *max_stack = header->max_stack;
4549 return header->code;
4553 * mono_method_header_get_locals:
4554 * \param header a \c MonoMethodHeader pointer
4555 * \param num_locals memory location for returning the number of local variables
4556 * \param init_locals memory location for returning the init_locals flag
4558 * Method header accessor to retreive info about the local variables:
4559 * an array of local types, the number of locals and whether the locals
4560 * are supposed to be initialized to 0 on method entry
4562 * \returns pointer to an array of types of the local variables
4564 MonoType**
4565 mono_method_header_get_locals (MonoMethodHeader *header, guint32* num_locals, gboolean *init_locals)
4567 if (num_locals)
4568 *num_locals = header->num_locals;
4569 if (init_locals)
4570 *init_locals = header->init_locals;
4571 return header->locals;
4575 * mono_method_header_get_num_clauses:
4576 * @header: a MonoMethodHeader pointer
4578 * Method header accessor to retreive the number of exception clauses.
4580 * Returns: the number of exception clauses present
4583 mono_method_header_get_num_clauses (MonoMethodHeader *header)
4585 return header->num_clauses;
4589 * mono_method_header_get_clauses:
4590 * \param header a \c MonoMethodHeader pointer
4591 * \param method \c MonoMethod the header belongs to
4592 * \param iter pointer to a iterator
4593 * \param clause pointer to a \c MonoExceptionClause structure which will be filled with the info
4595 * Get the info about the exception clauses in the method. Set \c *iter to NULL to
4596 * initiate the iteration, then call the method repeatedly until it returns FALSE.
4597 * At each iteration, the structure pointed to by clause if filled with the
4598 * exception clause information.
4600 * \returns TRUE if clause was filled with info, FALSE if there are no more exception
4601 * clauses.
4604 mono_method_header_get_clauses (MonoMethodHeader *header, MonoMethod *method, gpointer *iter, MonoExceptionClause *clause)
4606 MonoExceptionClause *sc;
4607 /* later we'll be able to use this interface to parse the clause info on demand,
4608 * without allocating anything.
4610 if (!iter || !header->num_clauses)
4611 return FALSE;
4612 if (!*iter) {
4613 *iter = sc = header->clauses;
4614 *clause = *sc;
4615 return TRUE;
4617 sc = (MonoExceptionClause *)*iter;
4618 sc++;
4619 if (sc < header->clauses + header->num_clauses) {
4620 *iter = sc;
4621 *clause = *sc;
4622 return TRUE;
4624 return FALSE;
4628 * mono_metadata_parse_field_type:
4629 * \param m metadata context to extract information from
4630 * \param ptr pointer to the field signature
4631 * \param rptr pointer updated to match the end of the decoded stream
4633 * Parses the field signature, and returns the type information for it.
4635 * \returns The \c MonoType that was extracted from \p ptr .
4637 MonoType *
4638 mono_metadata_parse_field_type (MonoImage *m, short field_flags, const char *ptr, const char **rptr)
4640 ERROR_DECL (error);
4641 MonoType * type = mono_metadata_parse_type_internal (m, NULL, field_flags, FALSE, ptr, rptr, error);
4642 mono_error_cleanup (error);
4643 return type;
4647 * mono_metadata_parse_param:
4648 * \param m metadata context to extract information from
4649 * \param ptr pointer to the param signature
4650 * \param rptr pointer updated to match the end of the decoded stream
4652 * Parses the param signature, and returns the type information for it.
4654 * \returns The \c MonoType that was extracted from \p ptr .
4656 MonoType *
4657 mono_metadata_parse_param (MonoImage *m, const char *ptr, const char **rptr)
4659 ERROR_DECL (error);
4660 MonoType * type = mono_metadata_parse_type_internal (m, NULL, 0, FALSE, ptr, rptr, error);
4661 mono_error_cleanup (error);
4662 return type;
4666 * mono_metadata_token_from_dor:
4667 * \param dor_token A \c TypeDefOrRef coded index
4669 * \p dor_token is a \c TypeDefOrRef coded index: it contains either
4670 * a \c TypeDef, \c TypeRef or \c TypeSpec in the lower bits, and the upper
4671 * bits contain an index into the table.
4673 * \returns an expanded token
4675 guint32
4676 mono_metadata_token_from_dor (guint32 dor_index)
4678 guint32 table, idx;
4680 table = dor_index & 0x03;
4681 idx = dor_index >> 2;
4683 switch (table){
4684 case 0: /* TypeDef */
4685 return MONO_TOKEN_TYPE_DEF | idx;
4686 case 1: /* TypeRef */
4687 return MONO_TOKEN_TYPE_REF | idx;
4688 case 2: /* TypeSpec */
4689 return MONO_TOKEN_TYPE_SPEC | idx;
4690 default:
4691 g_assert_not_reached ();
4694 return 0;
4698 * We use this to pass context information to the row locator
4700 typedef struct {
4701 int idx; /* The index that we are trying to locate */
4702 int col_idx; /* The index in the row where idx may be stored */
4703 MonoTableInfo *t; /* pointer to the table */
4704 guint32 result;
4705 } locator_t;
4708 * How the row locator works.
4710 * Table A
4711 * ___|___
4712 * ___|___ Table B
4713 * ___|___------> _______
4714 * ___|___ _______
4716 * A column in the rows of table A references an index in table B.
4717 * For example A may be the TYPEDEF table and B the METHODDEF table.
4719 * Given an index in table B we want to get the row in table A
4720 * where the column n references our index in B.
4722 * In the locator_t structure:
4723 * t is table A
4724 * col_idx is the column number
4725 * index is the index in table B
4726 * result will be the index in table A
4728 * Examples:
4729 * Table A Table B column (in table A)
4730 * TYPEDEF METHODDEF MONO_TYPEDEF_METHOD_LIST
4731 * TYPEDEF FIELD MONO_TYPEDEF_FIELD_LIST
4732 * PROPERTYMAP PROPERTY MONO_PROPERTY_MAP_PROPERTY_LIST
4733 * INTERFIMPL TYPEDEF MONO_INTERFACEIMPL_CLASS
4734 * METHODSEM PROPERTY ASSOCIATION (encoded index)
4736 * Note that we still don't support encoded indexes.
4739 static int
4740 typedef_locator (const void *a, const void *b)
4742 locator_t *loc = (locator_t *) a;
4743 const char *bb = (const char *) b;
4744 int typedef_index = (bb - loc->t->base) / loc->t->row_size;
4745 guint32 col, col_next;
4747 col = mono_metadata_decode_row_col (loc->t, typedef_index, loc->col_idx);
4749 if (loc->idx < col)
4750 return -1;
4753 * Need to check that the next row is valid.
4755 if (typedef_index + 1 < loc->t->rows) {
4756 col_next = mono_metadata_decode_row_col (loc->t, typedef_index + 1, loc->col_idx);
4757 if (loc->idx >= col_next)
4758 return 1;
4760 if (col == col_next)
4761 return 1;
4764 loc->result = typedef_index;
4766 return 0;
4769 static int
4770 table_locator (const void *a, const void *b)
4772 locator_t *loc = (locator_t *) a;
4773 const char *bb = (const char *) b;
4774 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4775 guint32 col;
4777 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4779 if (loc->idx == col) {
4780 loc->result = table_index;
4781 return 0;
4783 if (loc->idx < col)
4784 return -1;
4785 else
4786 return 1;
4789 static int
4790 declsec_locator (const void *a, const void *b)
4792 locator_t *loc = (locator_t *) a;
4793 const char *bb = (const char *) b;
4794 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4795 guint32 col;
4797 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4799 if (loc->idx == col) {
4800 loc->result = table_index;
4801 return 0;
4803 if (loc->idx < col)
4804 return -1;
4805 else
4806 return 1;
4810 * search_ptr_table:
4812 * Return the 1-based row index in TABLE, which must be one of the *Ptr tables,
4813 * which contains IDX.
4815 static guint32
4816 search_ptr_table (MonoImage *image, int table, int idx)
4818 MonoTableInfo *ptrdef = &image->tables [table];
4819 int i;
4821 /* Use a linear search to find our index in the table */
4822 for (i = 0; i < ptrdef->rows; i ++)
4823 /* All the Ptr tables have the same structure */
4824 if (mono_metadata_decode_row_col (ptrdef, i, 0) == idx)
4825 break;
4827 if (i < ptrdef->rows)
4828 return i + 1;
4829 else
4830 return idx;
4834 * mono_metadata_typedef_from_field:
4835 * \param meta metadata context
4836 * \param index FieldDef token
4838 * \returns the 1-based index into the \c TypeDef table of the type that
4839 * declared the field described by \p index, or 0 if not found.
4841 guint32
4842 mono_metadata_typedef_from_field (MonoImage *meta, guint32 index)
4844 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4845 locator_t loc;
4847 if (!tdef->base)
4848 return 0;
4850 loc.idx = mono_metadata_token_index (index);
4851 loc.col_idx = MONO_TYPEDEF_FIELD_LIST;
4852 loc.t = tdef;
4854 if (meta->uncompressed_metadata)
4855 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
4857 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4858 return 0;
4860 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4861 return loc.result + 1;
4865 * mono_metadata_typedef_from_method:
4866 * \param meta metadata context
4867 * \param index \c MethodDef token
4868 * \returns the 1-based index into the \c TypeDef table of the type that
4869 * declared the method described by \p index. 0 if not found.
4871 guint32
4872 mono_metadata_typedef_from_method (MonoImage *meta, guint32 index)
4874 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4875 locator_t loc;
4877 if (!tdef->base)
4878 return 0;
4880 loc.idx = mono_metadata_token_index (index);
4881 loc.col_idx = MONO_TYPEDEF_METHOD_LIST;
4882 loc.t = tdef;
4884 if (meta->uncompressed_metadata)
4885 loc.idx = search_ptr_table (meta, MONO_TABLE_METHOD_POINTER, loc.idx);
4887 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4888 return 0;
4890 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4891 return loc.result + 1;
4895 * mono_metadata_interfaces_from_typedef_full:
4896 * \param meta metadata context
4897 * \param index typedef token
4898 * \param interfaces Out parameter used to store the interface array
4899 * \param count Out parameter used to store the number of interfaces
4900 * \param heap_alloc_result if TRUE the result array will be \c g_malloc'd
4901 * \param context The generic context
4902 * \param error set on error
4904 * The array of interfaces that the \p index typedef token implements is returned in
4905 * \p interfaces. The number of elements in the array is returned in \p count.
4907 * \returns \c TRUE on success, \c FALSE on failure and sets \p error.
4909 gboolean
4910 mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, MonoClass ***interfaces, guint *count, gboolean heap_alloc_result, MonoGenericContext *context, MonoError *error)
4912 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_INTERFACEIMPL];
4913 locator_t loc;
4914 guint32 start, pos;
4915 guint32 cols [MONO_INTERFACEIMPL_SIZE];
4916 MonoClass **result;
4918 *interfaces = NULL;
4919 *count = 0;
4921 error_init (error);
4923 if (!tdef->base)
4924 return TRUE;
4926 loc.idx = mono_metadata_token_index (index);
4927 loc.col_idx = MONO_INTERFACEIMPL_CLASS;
4928 loc.t = tdef;
4930 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4931 return TRUE;
4933 start = loc.result;
4935 * We may end up in the middle of the rows...
4937 while (start > 0) {
4938 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_INTERFACEIMPL_CLASS))
4939 start--;
4940 else
4941 break;
4943 pos = start;
4944 while (pos < tdef->rows) {
4945 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4946 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4947 break;
4948 ++pos;
4951 if (heap_alloc_result)
4952 result = g_new0 (MonoClass*, pos - start);
4953 else
4954 result = (MonoClass **)mono_image_alloc0 (meta, sizeof (MonoClass*) * (pos - start));
4956 pos = start;
4957 while (pos < tdef->rows) {
4958 MonoClass *iface;
4960 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4961 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4962 break;
4963 iface = mono_class_get_and_inflate_typespec_checked (
4964 meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context, error);
4965 if (iface == NULL)
4966 return FALSE;
4967 result [pos - start] = iface;
4968 ++pos;
4970 *count = pos - start;
4971 *interfaces = result;
4972 return TRUE;
4976 * mono_metadata_interfaces_from_typedef:
4977 * \param meta metadata context
4978 * \param index typedef token
4979 * \param count Out parameter used to store the number of interfaces
4981 * The array of interfaces that the \p index typedef token implements is returned in
4982 * \p interfaces. The number of elements in the array is returned in \p count. The returned
4983 * array is allocated with \c g_malloc and the caller must free it.
4985 * LOCKING: Acquires the loader lock .
4987 * \returns the interface array on success, NULL on failure.
4989 MonoClass**
4990 mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *count)
4992 ERROR_DECL (error);
4993 MonoClass **interfaces = NULL;
4994 gboolean rv;
4996 rv = mono_metadata_interfaces_from_typedef_full (meta, index, &interfaces, count, TRUE, NULL, error);
4997 mono_error_assert_ok (error);
4998 if (rv)
4999 return interfaces;
5000 else
5001 return NULL;
5005 * mono_metadata_nested_in_typedef:
5006 * \param meta metadata context
5007 * \param index typedef token
5008 * \returns the 1-based index into the TypeDef table of the type
5009 * where the type described by \p index is nested.
5010 * Returns 0 if \p index describes a non-nested type.
5012 guint32
5013 mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index)
5015 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
5016 locator_t loc;
5018 if (!tdef->base)
5019 return 0;
5021 loc.idx = mono_metadata_token_index (index);
5022 loc.col_idx = MONO_NESTED_CLASS_NESTED;
5023 loc.t = tdef;
5025 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5026 return 0;
5028 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5029 return mono_metadata_decode_row_col (tdef, loc.result, MONO_NESTED_CLASS_ENCLOSING) | MONO_TOKEN_TYPE_DEF;
5033 * mono_metadata_nesting_typedef:
5034 * \param meta metadata context
5035 * \param index typedef token
5036 * \returns the 1-based index into the \c TypeDef table of the first type
5037 * that is nested inside the type described by \p index. The search starts at
5038 * \p start_index. Returns 0 if no such type is found.
5040 guint32
5041 mono_metadata_nesting_typedef (MonoImage *meta, guint32 index, guint32 start_index)
5043 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
5044 guint32 start;
5045 guint32 class_index = mono_metadata_token_index (index);
5047 if (!tdef->base)
5048 return 0;
5050 start = start_index;
5052 while (start <= tdef->rows) {
5053 if (class_index == mono_metadata_decode_row_col (tdef, start - 1, MONO_NESTED_CLASS_ENCLOSING))
5054 break;
5055 else
5056 start++;
5059 if (start > tdef->rows)
5060 return 0;
5061 else
5062 return start;
5066 * mono_metadata_packing_from_typedef:
5067 * \param meta metadata context
5068 * \param index token representing a type
5069 * \returns the info stored in the \c ClassLayout table for the given typedef token
5070 * into the \p packing and \p size pointers.
5071 * Returns 0 if the info is not found.
5073 guint32
5074 mono_metadata_packing_from_typedef (MonoImage *meta, guint32 index, guint32 *packing, guint32 *size)
5076 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CLASSLAYOUT];
5077 locator_t loc;
5078 guint32 cols [MONO_CLASS_LAYOUT_SIZE];
5080 if (!tdef->base)
5081 return 0;
5083 loc.idx = mono_metadata_token_index (index);
5084 loc.col_idx = MONO_CLASS_LAYOUT_PARENT;
5085 loc.t = tdef;
5087 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5088 return 0;
5090 mono_metadata_decode_row (tdef, loc.result, cols, MONO_CLASS_LAYOUT_SIZE);
5091 if (packing)
5092 *packing = cols [MONO_CLASS_LAYOUT_PACKING_SIZE];
5093 if (size)
5094 *size = cols [MONO_CLASS_LAYOUT_CLASS_SIZE];
5096 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5097 return loc.result + 1;
5101 * mono_metadata_custom_attrs_from_index:
5102 * \param meta metadata context
5103 * \param index token representing the parent
5104 * \returns: the 1-based index into the \c CustomAttribute table of the first
5105 * attribute which belongs to the metadata object described by \p index.
5106 * Returns 0 if no such attribute is found.
5108 guint32
5109 mono_metadata_custom_attrs_from_index (MonoImage *meta, guint32 index)
5111 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CUSTOMATTRIBUTE];
5112 locator_t loc;
5114 if (!tdef->base)
5115 return 0;
5117 loc.idx = index;
5118 loc.col_idx = MONO_CUSTOM_ATTR_PARENT;
5119 loc.t = tdef;
5121 /* FIXME: Index translation */
5123 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5124 return 0;
5126 /* Find the first entry by searching backwards */
5127 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_CUSTOM_ATTR_PARENT) == index))
5128 loc.result --;
5130 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
5131 return loc.result + 1;
5135 * mono_metadata_declsec_from_index:
5136 * \param meta metadata context
5137 * \param index token representing the parent
5138 * \returns the 0-based index into the \c DeclarativeSecurity table of the first
5139 * attribute which belongs to the metadata object described by \p index.
5140 * Returns \c -1 if no such attribute is found.
5142 guint32
5143 mono_metadata_declsec_from_index (MonoImage *meta, guint32 index)
5145 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_DECLSECURITY];
5146 locator_t loc;
5148 if (!tdef->base)
5149 return -1;
5151 loc.idx = index;
5152 loc.col_idx = MONO_DECL_SECURITY_PARENT;
5153 loc.t = tdef;
5155 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, declsec_locator))
5156 return -1;
5158 /* Find the first entry by searching backwards */
5159 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_DECL_SECURITY_PARENT) == index))
5160 loc.result --;
5162 return loc.result;
5166 * mono_metadata_localscope_from_methoddef:
5167 * @meta: metadata context
5168 * @index: methoddef index
5170 * Returns: the 1-based index into the LocalScope table of the first
5171 * scope which belongs to the method described by @index.
5172 * Returns 0 if no such row is found.
5174 guint32
5175 mono_metadata_localscope_from_methoddef (MonoImage *meta, guint32 index)
5177 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_LOCALSCOPE];
5178 locator_t loc;
5180 if (!tdef->base)
5181 return 0;
5183 loc.idx = index;
5184 loc.col_idx = MONO_LOCALSCOPE_METHOD;
5185 loc.t = tdef;
5187 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5188 return 0;
5190 /* Find the first entry by searching backwards */
5191 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_LOCALSCOPE_METHOD) == index))
5192 loc.result --;
5194 return loc.result + 1;
5197 #ifdef DEBUG
5198 static void
5199 mono_backtrace (int limit)
5201 void *array[limit];
5202 char **names;
5203 int i;
5204 backtrace (array, limit);
5205 names = backtrace_symbols (array, limit);
5206 for (i =0; i < limit; ++i) {
5207 g_print ("\t%s\n", names [i]);
5209 g_free (names);
5211 #endif
5213 static int i8_align;
5216 * mono_type_set_alignment:
5218 * Set the alignment used by runtime to layout fields etc. of type TYPE to ALIGN.
5219 * This should only be used in AOT mode since the resulting layout will not match the
5220 * host abi layout.
5222 void
5223 mono_type_set_alignment (MonoTypeEnum type, int align)
5225 /* Support only a few types whose alignment is abi dependent */
5226 switch (type) {
5227 case MONO_TYPE_I8:
5228 i8_align = align;
5229 break;
5230 default:
5231 g_assert_not_reached ();
5232 break;
5237 * mono_type_size:
5238 * \param t the type to return the size of
5239 * \returns The number of bytes required to hold an instance of this
5240 * type in memory
5243 mono_type_size (MonoType *t, int *align)
5245 MonoTypeEnum simple_type;
5247 if (!t) {
5248 *align = 1;
5249 return 0;
5251 if (t->byref) {
5252 *align = MONO_ABI_ALIGNOF (gpointer);
5253 return MONO_ABI_SIZEOF (gpointer);
5256 simple_type = t->type;
5257 again:
5258 switch (simple_type) {
5259 case MONO_TYPE_VOID:
5260 *align = 1;
5261 return 0;
5262 case MONO_TYPE_BOOLEAN:
5263 *align = MONO_ABI_ALIGNOF (gint8);
5264 return 1;
5265 case MONO_TYPE_I1:
5266 case MONO_TYPE_U1:
5267 *align = MONO_ABI_ALIGNOF (gint8);
5268 return 1;
5269 case MONO_TYPE_CHAR:
5270 case MONO_TYPE_I2:
5271 case MONO_TYPE_U2:
5272 *align = MONO_ABI_ALIGNOF (gint16);
5273 return 2;
5274 case MONO_TYPE_I4:
5275 case MONO_TYPE_U4:
5276 *align = MONO_ABI_ALIGNOF (gint32);
5277 return 4;
5278 case MONO_TYPE_R4:
5279 *align = MONO_ABI_ALIGNOF (float);
5280 return 4;
5281 case MONO_TYPE_I8:
5282 case MONO_TYPE_U8:
5283 *align = MONO_ABI_ALIGNOF (gint64);
5284 return 8;
5285 case MONO_TYPE_R8:
5286 *align = MONO_ABI_ALIGNOF (double);
5287 return 8;
5288 case MONO_TYPE_I:
5289 case MONO_TYPE_U:
5290 *align = MONO_ABI_ALIGNOF (gpointer);
5291 return MONO_ABI_SIZEOF (gpointer);
5292 case MONO_TYPE_VALUETYPE: {
5293 if (m_class_is_enumtype (t->data.klass))
5294 return mono_type_size (mono_class_enum_basetype_internal (t->data.klass), align);
5295 else
5296 return mono_class_value_size (t->data.klass, (guint32*)align);
5298 case MONO_TYPE_STRING:
5299 case MONO_TYPE_OBJECT:
5300 case MONO_TYPE_CLASS:
5301 case MONO_TYPE_SZARRAY:
5302 case MONO_TYPE_PTR:
5303 case MONO_TYPE_FNPTR:
5304 case MONO_TYPE_ARRAY:
5305 *align = MONO_ABI_ALIGNOF (gpointer);
5306 return MONO_ABI_SIZEOF (gpointer);
5307 case MONO_TYPE_TYPEDBYREF:
5308 return mono_class_value_size (mono_defaults.typed_reference_class, (guint32*)align);
5309 case MONO_TYPE_GENERICINST: {
5310 MonoGenericClass *gclass = t->data.generic_class;
5311 MonoClass *container_class = gclass->container_class;
5313 // g_assert (!gclass->inst->is_open);
5315 if (m_class_is_valuetype (container_class)) {
5316 if (m_class_is_enumtype (container_class))
5317 return mono_type_size (mono_class_enum_basetype_internal (container_class), align);
5318 else
5319 return mono_class_value_size (mono_class_from_mono_type_internal (t), (guint32*)align);
5320 } else {
5321 *align = MONO_ABI_ALIGNOF (gpointer);
5322 return MONO_ABI_SIZEOF (gpointer);
5325 case MONO_TYPE_VAR:
5326 case MONO_TYPE_MVAR:
5327 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
5328 *align = MONO_ABI_ALIGNOF (gpointer);
5329 return MONO_ABI_SIZEOF (gpointer);
5330 } else {
5331 /* The gparam can only match types given by gshared_constraint */
5332 return mono_type_size (t->data.generic_param->gshared_constraint, align);
5333 goto again;
5335 default:
5336 g_error ("mono_type_size: type 0x%02x unknown", t->type);
5338 return 0;
5342 * mono_type_stack_size:
5343 * \param t the type to return the size it uses on the stack
5344 * \returns The number of bytes required to hold an instance of this
5345 * type on the runtime stack
5348 mono_type_stack_size (MonoType *t, int *align)
5350 return mono_type_stack_size_internal (t, align, FALSE);
5354 mono_type_stack_size_internal (MonoType *t, int *align, gboolean allow_open)
5356 int tmp;
5357 MonoTypeEnum simple_type;
5358 int stack_slot_size = TARGET_SIZEOF_VOID_P;
5359 int stack_slot_align = TARGET_SIZEOF_VOID_P;
5361 g_assert (t != NULL);
5363 if (!align)
5364 align = &tmp;
5366 if (t->byref) {
5367 *align = stack_slot_align;
5368 return stack_slot_size;
5371 simple_type = t->type;
5372 switch (simple_type) {
5373 case MONO_TYPE_BOOLEAN:
5374 case MONO_TYPE_CHAR:
5375 case MONO_TYPE_I1:
5376 case MONO_TYPE_U1:
5377 case MONO_TYPE_I2:
5378 case MONO_TYPE_U2:
5379 case MONO_TYPE_I4:
5380 case MONO_TYPE_U4:
5381 case MONO_TYPE_I:
5382 case MONO_TYPE_U:
5383 case MONO_TYPE_STRING:
5384 case MONO_TYPE_OBJECT:
5385 case MONO_TYPE_CLASS:
5386 case MONO_TYPE_SZARRAY:
5387 case MONO_TYPE_PTR:
5388 case MONO_TYPE_FNPTR:
5389 case MONO_TYPE_ARRAY:
5390 *align = stack_slot_align;
5391 return stack_slot_size;
5392 case MONO_TYPE_VAR:
5393 case MONO_TYPE_MVAR:
5394 g_assert (allow_open);
5395 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
5396 *align = stack_slot_align;
5397 return stack_slot_size;
5398 } else {
5399 /* The gparam can only match types given by gshared_constraint */
5400 return mono_type_stack_size_internal (t->data.generic_param->gshared_constraint, align, allow_open);
5402 case MONO_TYPE_TYPEDBYREF:
5403 *align = stack_slot_align;
5404 return stack_slot_size * 3;
5405 case MONO_TYPE_R4:
5406 *align = MONO_ABI_ALIGNOF (float);
5407 return sizeof (float);
5408 case MONO_TYPE_I8:
5409 case MONO_TYPE_U8:
5410 *align = MONO_ABI_ALIGNOF (gint64);
5411 return sizeof (gint64);
5412 case MONO_TYPE_R8:
5413 *align = MONO_ABI_ALIGNOF (double);
5414 return sizeof (double);
5415 case MONO_TYPE_VALUETYPE: {
5416 guint32 size;
5418 if (m_class_is_enumtype (t->data.klass))
5419 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (t->data.klass), align, allow_open);
5420 else {
5421 size = mono_class_value_size (t->data.klass, (guint32*)align);
5423 *align = *align + stack_slot_align - 1;
5424 *align &= ~(stack_slot_align - 1);
5426 size += stack_slot_size - 1;
5427 size &= ~(stack_slot_size - 1);
5429 return size;
5432 case MONO_TYPE_GENERICINST: {
5433 MonoGenericClass *gclass = t->data.generic_class;
5434 MonoClass *container_class = gclass->container_class;
5436 if (!allow_open)
5437 g_assert (!gclass->context.class_inst->is_open);
5439 if (m_class_is_valuetype (container_class)) {
5440 if (m_class_is_enumtype (container_class))
5441 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (container_class), align, allow_open);
5442 else {
5443 guint32 size = mono_class_value_size (mono_class_from_mono_type_internal (t), (guint32*)align);
5445 *align = *align + stack_slot_align - 1;
5446 *align &= ~(stack_slot_align - 1);
5448 size += stack_slot_size - 1;
5449 size &= ~(stack_slot_size - 1);
5451 return size;
5453 } else {
5454 *align = stack_slot_align;
5455 return stack_slot_size;
5458 default:
5459 g_error ("type 0x%02x unknown", t->type);
5461 return 0;
5464 gboolean
5465 mono_type_generic_inst_is_valuetype (MonoType *type)
5467 g_assert (type->type == MONO_TYPE_GENERICINST);
5468 return m_class_is_valuetype (type->data.generic_class->container_class);
5472 * mono_metadata_generic_class_is_valuetype:
5474 gboolean
5475 mono_metadata_generic_class_is_valuetype (MonoGenericClass *gclass)
5477 return m_class_is_valuetype (gclass->container_class);
5480 static gboolean
5481 _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only)
5483 MonoGenericInst *i1 = g1->context.class_inst;
5484 MonoGenericInst *i2 = g2->context.class_inst;
5486 if (g1->is_dynamic != g2->is_dynamic)
5487 return FALSE;
5488 if (!mono_metadata_class_equal (g1->container_class, g2->container_class, signature_only))
5489 return FALSE;
5490 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5491 return FALSE;
5492 return g1->is_tb_open == g2->is_tb_open;
5495 static gboolean
5496 _mono_metadata_generic_class_container_equal (const MonoGenericClass *g1, MonoClass *c2, gboolean signature_only)
5498 MonoGenericInst *i1 = g1->context.class_inst;
5499 MonoGenericInst *i2 = mono_class_get_generic_container (c2)->context.class_inst;
5501 if (!mono_metadata_class_equal (g1->container_class, c2, signature_only))
5502 return FALSE;
5503 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5504 return FALSE;
5505 return !g1->is_tb_open;
5508 guint
5509 mono_metadata_generic_context_hash (const MonoGenericContext *context)
5511 /* FIXME: check if this seed is good enough */
5512 guint hash = 0xc01dfee7;
5513 if (context->class_inst)
5514 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->class_inst);
5515 if (context->method_inst)
5516 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->method_inst);
5517 return hash;
5520 gboolean
5521 mono_metadata_generic_context_equal (const MonoGenericContext *g1, const MonoGenericContext *g2)
5523 return g1->class_inst == g2->class_inst && g1->method_inst == g2->method_inst;
5527 * mono_metadata_str_hash:
5529 * This should be used instead of g_str_hash for computing hash codes visible
5530 * outside this module, since g_str_hash () is not guaranteed to be stable
5531 * (its not the same in eglib for example).
5533 guint
5534 mono_metadata_str_hash (gconstpointer v1)
5536 /* Same as g_str_hash () in glib */
5537 char *p = (char *) v1;
5538 guint hash = *p;
5540 while (*p++) {
5541 if (*p)
5542 hash = (hash << 5) - hash + *p;
5545 return hash;
5549 * mono_metadata_type_hash:
5550 * \param t1 a type
5551 * Computes a hash value for \p t1 to be used in \c GHashTable.
5552 * The returned hash is guaranteed to be the same across executions.
5554 guint
5555 mono_metadata_type_hash (MonoType *t1)
5557 guint hash = t1->type;
5559 hash |= t1->byref << 6; /* do not collide with t1->type values */
5560 switch (t1->type) {
5561 case MONO_TYPE_VALUETYPE:
5562 case MONO_TYPE_CLASS:
5563 case MONO_TYPE_SZARRAY: {
5564 MonoClass *klass = t1->data.klass;
5566 * Dynamic classes must not be hashed on their type since it can change
5567 * during runtime. For example, if we hash a reference type that is
5568 * later made into a valuetype.
5570 * This is specially problematic with generic instances since they are
5571 * inserted in a bunch of hash tables before been finished.
5573 if (image_is_dynamic (m_class_get_image (klass)))
5574 return (t1->byref << 6) | mono_metadata_str_hash (m_class_get_name (klass));
5575 return ((hash << 5) - hash) ^ mono_metadata_str_hash (m_class_get_name (klass));
5577 case MONO_TYPE_PTR:
5578 return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
5579 case MONO_TYPE_ARRAY:
5580 return ((hash << 5) - hash) ^ mono_metadata_type_hash (m_class_get_byval_arg (t1->data.array->eklass));
5581 case MONO_TYPE_GENERICINST:
5582 return ((hash << 5) - hash) ^ mono_generic_class_hash (t1->data.generic_class);
5583 case MONO_TYPE_VAR:
5584 case MONO_TYPE_MVAR:
5585 return ((hash << 5) - hash) ^ mono_metadata_generic_param_hash (t1->data.generic_param);
5586 default:
5587 return hash;
5591 guint
5592 mono_metadata_generic_param_hash (MonoGenericParam *p)
5594 guint hash;
5595 MonoGenericParamInfo *info;
5597 hash = (mono_generic_param_num (p) << 2);
5598 if (p->gshared_constraint)
5599 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->gshared_constraint);
5600 info = mono_generic_param_info (p);
5601 /* Can't hash on the owner klass/method, since those might not be set when this is called */
5602 if (!p->owner->is_anonymous)
5603 hash = ((hash << 5) - hash) ^ info->token;
5604 return hash;
5607 static gboolean
5608 mono_metadata_generic_param_equal_internal (MonoGenericParam *p1, MonoGenericParam *p2, gboolean signature_only)
5610 if (p1 == p2)
5611 return TRUE;
5612 if (mono_generic_param_num (p1) != mono_generic_param_num (p2))
5613 return FALSE;
5614 if (p1->gshared_constraint && p2->gshared_constraint) {
5615 if (!mono_metadata_type_equal (p1->gshared_constraint, p2->gshared_constraint))
5616 return FALSE;
5617 } else {
5618 if (p1->gshared_constraint != p2->gshared_constraint)
5619 return FALSE;
5623 * We have to compare the image as well because if we didn't,
5624 * the generic_inst_cache lookup wouldn't care about the image
5625 * of generic params, so what could happen is that a generic
5626 * inst with params from image A is put into the cache, then
5627 * image B gets that generic inst from the cache, image A is
5628 * unloaded, so the inst is deleted, but image B still retains
5629 * a pointer to it.
5631 if (mono_generic_param_owner (p1) == mono_generic_param_owner (p2))
5632 return TRUE;
5635 * If `signature_only' is true, we're comparing two (method) signatures.
5636 * In this case, the owner of two type parameters doesn't need to match.
5639 return signature_only;
5642 gboolean
5643 mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2)
5645 return mono_metadata_generic_param_equal_internal (p1, p2, TRUE);
5648 static gboolean
5649 mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only)
5651 if (c1 == c2)
5652 return TRUE;
5653 if (mono_class_is_ginst (c1) && mono_class_is_ginst (c2))
5654 return _mono_metadata_generic_class_equal (mono_class_get_generic_class (c1), mono_class_get_generic_class (c2), signature_only);
5655 if (mono_class_is_ginst (c1) && mono_class_is_gtd (c2))
5656 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c1), c2, signature_only);
5657 if (mono_class_is_gtd (c1) && mono_class_is_ginst (c2))
5658 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c2), c1, signature_only);
5659 MonoType *c1_type = m_class_get_byval_arg (c1);
5660 MonoType *c2_type = m_class_get_byval_arg (c2);
5661 if ((c1_type->type == MONO_TYPE_VAR) && (c2_type->type == MONO_TYPE_VAR))
5662 return mono_metadata_generic_param_equal_internal (
5663 c1_type->data.generic_param, c2_type->data.generic_param, signature_only);
5664 if ((c1_type->type == MONO_TYPE_MVAR) && (c2_type->type == MONO_TYPE_MVAR))
5665 return mono_metadata_generic_param_equal_internal (
5666 c1_type->data.generic_param, c2_type->data.generic_param, signature_only);
5667 if (signature_only &&
5668 (c1_type->type == MONO_TYPE_SZARRAY) && (c2_type->type == MONO_TYPE_SZARRAY))
5669 return mono_metadata_class_equal (c1_type->data.klass, c2_type->data.klass, signature_only);
5670 if (signature_only &&
5671 (c1_type->type == MONO_TYPE_ARRAY) && (c2_type->type == MONO_TYPE_ARRAY))
5672 return do_mono_metadata_type_equal (c1_type, c2_type, signature_only);
5673 return FALSE;
5676 static gboolean
5677 mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only)
5679 gpointer iter1 = 0, iter2 = 0;
5681 if (s1 == s2)
5682 return TRUE;
5683 if (s1->call_convention != s2->call_convention)
5684 return FALSE;
5685 if (s1->sentinelpos != s2->sentinelpos)
5686 return FALSE;
5687 if (s1->hasthis != s2->hasthis)
5688 return FALSE;
5689 if (s1->explicit_this != s2->explicit_this)
5690 return FALSE;
5691 if (! do_mono_metadata_type_equal (s1->ret, s2->ret, signature_only))
5692 return FALSE;
5693 if (s1->param_count != s2->param_count)
5694 return FALSE;
5696 while (TRUE) {
5697 MonoType *t1 = mono_signature_get_params_internal (s1, &iter1);
5698 MonoType *t2 = mono_signature_get_params_internal (s2, &iter2);
5700 if (t1 == NULL || t2 == NULL)
5701 return (t1 == t2);
5702 if (! do_mono_metadata_type_equal (t1, t2, signature_only))
5703 return FALSE;
5707 static gboolean
5708 mono_metadata_custom_modifiers_equal (MonoType *t1, MonoType *t2, gboolean signature_only)
5710 // ECMA 335, 7.1.1:
5711 // The CLI itself shall treat required and optional modifiers in the same manner.
5712 // Two signatures that differ only by the addition of a custom modifier
5713 // (required or optional) shall not be considered to match.
5714 int count = mono_type_custom_modifier_count (t1);
5715 if (count != mono_type_custom_modifier_count (t2))
5716 return FALSE;
5718 for (int i=0; i < count; i++) {
5719 // FIXME: propagate error to caller
5720 ERROR_DECL (error);
5721 gboolean cm1_required, cm2_required;
5723 MonoType *cm1_type = mono_type_get_custom_modifier (t1, i, &cm1_required, error);
5724 mono_error_assert_ok (error);
5725 MonoType *cm2_type = mono_type_get_custom_modifier (t2, i, &cm2_required, error);
5726 mono_error_assert_ok (error);
5728 if (cm1_required != cm2_required)
5729 return FALSE;
5731 if (!do_mono_metadata_type_equal (cm1_type, cm2_type, signature_only))
5732 return FALSE;
5734 return TRUE;
5738 * mono_metadata_type_equal:
5739 * @t1: a type
5740 * @t2: another type
5741 * @signature_only: If true, treat ginsts as equal which are instantiated separately but have equal positional value
5743 * Determine if @t1 and @t2 represent the same type.
5744 * Returns: #TRUE if @t1 and @t2 are equal.
5746 static gboolean
5747 do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only)
5749 if (t1->type != t2->type || t1->byref != t2->byref)
5750 return FALSE;
5752 gboolean cmod_reject = FALSE;
5754 if (t1->has_cmods != t2->has_cmods)
5755 cmod_reject = TRUE;
5756 else if (t1->has_cmods && t2->has_cmods) {
5757 cmod_reject = !mono_metadata_custom_modifiers_equal (t1, t2, signature_only);
5760 gboolean result = FALSE;
5762 switch (t1->type) {
5763 case MONO_TYPE_VOID:
5764 case MONO_TYPE_BOOLEAN:
5765 case MONO_TYPE_CHAR:
5766 case MONO_TYPE_I1:
5767 case MONO_TYPE_U1:
5768 case MONO_TYPE_I2:
5769 case MONO_TYPE_U2:
5770 case MONO_TYPE_I4:
5771 case MONO_TYPE_U4:
5772 case MONO_TYPE_I8:
5773 case MONO_TYPE_U8:
5774 case MONO_TYPE_R4:
5775 case MONO_TYPE_R8:
5776 case MONO_TYPE_STRING:
5777 case MONO_TYPE_I:
5778 case MONO_TYPE_U:
5779 case MONO_TYPE_OBJECT:
5780 case MONO_TYPE_TYPEDBYREF:
5781 result = TRUE;
5782 break;
5783 case MONO_TYPE_VALUETYPE:
5784 case MONO_TYPE_CLASS:
5785 case MONO_TYPE_SZARRAY:
5786 result = mono_metadata_class_equal (t1->data.klass, t2->data.klass, signature_only);
5787 break;
5788 case MONO_TYPE_PTR:
5789 result = do_mono_metadata_type_equal (t1->data.type, t2->data.type, signature_only);
5790 break;
5791 case MONO_TYPE_ARRAY:
5792 if (t1->data.array->rank != t2->data.array->rank)
5793 result = FALSE;
5794 else
5795 result = mono_metadata_class_equal (t1->data.array->eklass, t2->data.array->eklass, signature_only);
5796 break;
5797 case MONO_TYPE_GENERICINST:
5798 result = _mono_metadata_generic_class_equal (
5799 t1->data.generic_class, t2->data.generic_class, signature_only);
5800 break;
5801 case MONO_TYPE_VAR:
5802 result = mono_metadata_generic_param_equal_internal (
5803 t1->data.generic_param, t2->data.generic_param, signature_only);
5804 break;
5805 case MONO_TYPE_MVAR:
5806 result = mono_metadata_generic_param_equal_internal (
5807 t1->data.generic_param, t2->data.generic_param, signature_only);
5808 break;
5809 case MONO_TYPE_FNPTR:
5810 result = mono_metadata_fnptr_equal (t1->data.method, t2->data.method, signature_only);
5811 break;
5812 default:
5813 g_error ("implement type compare for %0x!", t1->type);
5814 return FALSE;
5817 return result && !cmod_reject;
5821 * mono_metadata_type_equal:
5823 gboolean
5824 mono_metadata_type_equal (MonoType *t1, MonoType *t2)
5826 return do_mono_metadata_type_equal (t1, t2, FALSE);
5830 * mono_metadata_type_equal_full:
5831 * \param t1 a type
5832 * \param t2 another type
5833 * \param signature_only if signature only comparison should be made
5835 * Determine if \p t1 and \p t2 are signature compatible if \p signature_only is TRUE, otherwise
5836 * behaves the same way as mono_metadata_type_equal.
5837 * The function mono_metadata_type_equal(a, b) is just a shortcut for mono_metadata_type_equal_full(a, b, FALSE).
5838 * \returns TRUE if \p t1 and \p t2 are equal taking \p signature_only into account.
5840 gboolean
5841 mono_metadata_type_equal_full (MonoType *t1, MonoType *t2, gboolean signature_only)
5843 return do_mono_metadata_type_equal (t1, t2, signature_only);
5847 * mono_metadata_signature_equal:
5848 * \param sig1 a signature
5849 * \param sig2 another signature
5851 * Determine if \p sig1 and \p sig2 represent the same signature, with the
5852 * same number of arguments and the same types.
5853 * \returns TRUE if \p sig1 and \p sig2 are equal.
5855 gboolean
5856 mono_metadata_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
5858 int i;
5860 if (sig1->hasthis != sig2->hasthis || sig1->param_count != sig2->param_count)
5861 return FALSE;
5863 if (sig1->generic_param_count != sig2->generic_param_count)
5864 return FALSE;
5867 * We're just comparing the signatures of two methods here:
5869 * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
5870 * U and V are equal here.
5872 * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
5875 for (i = 0; i < sig1->param_count; i++) {
5876 MonoType *p1 = sig1->params[i];
5877 MonoType *p2 = sig2->params[i];
5879 /* if (p1->attrs != p2->attrs)
5880 return FALSE;
5882 if (!do_mono_metadata_type_equal (p1, p2, TRUE))
5883 return FALSE;
5886 if (!do_mono_metadata_type_equal (sig1->ret, sig2->ret, TRUE))
5887 return FALSE;
5888 return TRUE;
5891 MonoType *
5892 mono_type_get_custom_modifier (const MonoType *ty, uint8_t idx, gboolean *required, MonoError *error)
5894 g_assert (ty->has_cmods);
5895 if (mono_type_is_aggregate_mods (ty)) {
5896 MonoAggregateModContainer *amods = mono_type_get_amods (ty);
5897 g_assert (idx < amods->count);
5898 MonoSingleCustomMod *cmod = &amods->modifiers [idx];
5899 if (required)
5900 *required = !!cmod->required;
5901 return cmod->type;
5902 } else {
5903 MonoCustomModContainer *cmods = mono_type_get_cmods (ty);
5904 g_assert (idx < cmods->count);
5905 MonoCustomMod *cmod = &cmods->modifiers [idx];
5906 if (required)
5907 *required = !!cmod->required;
5908 MonoImage *image = cmods->image;
5909 uint32_t token = cmod->token;
5910 return mono_type_get_checked (image, token, NULL, error);
5916 * mono_metadata_type_dup:
5917 * \param image image to alloc memory from
5918 * \param original type to duplicate
5919 * \returns copy of type allocated from the image's mempool (or from the heap, if \p image is null).
5921 MonoType *
5922 mono_metadata_type_dup (MonoImage *image, const MonoType *o)
5924 return mono_metadata_type_dup_with_cmods (image, o, o);
5927 static void
5928 deep_type_dup_fixup (MonoImage *image, MonoType *r, const MonoType *o);
5930 static uint8_t
5931 custom_modifier_copy (MonoAggregateModContainer *dest, uint8_t dest_offset, const MonoType *source)
5933 if (mono_type_is_aggregate_mods (source)) {
5934 MonoAggregateModContainer *src_cmods = mono_type_get_amods (source);
5935 memcpy (&dest->modifiers [dest_offset], &src_cmods->modifiers[0], src_cmods->count * sizeof (MonoSingleCustomMod));
5936 dest_offset += src_cmods->count;
5937 } else {
5938 MonoCustomModContainer *src_cmods = mono_type_get_cmods (source);
5939 for (int i = 0; i < src_cmods->count; i++) {
5940 ERROR_DECL (error); // XXX FIXME: AK - propagate the error to the caller.
5941 MonoSingleCustomMod *cmod = &dest->modifiers [dest_offset++];
5942 cmod->type = mono_type_get_checked (src_cmods->image, src_cmods->modifiers [i].token, NULL, error);
5943 mono_error_assert_ok (error);
5944 cmod->required = src_cmods->modifiers [i].required;
5947 return dest_offset;
5950 /* makes a dup of 'o' but also appends the custom modifiers from 'cmods_source' */
5951 static MonoType *
5952 do_metadata_type_dup_append_cmods (MonoImage *image, const MonoType *o, const MonoType *cmods_source)
5954 g_assert (o != cmods_source);
5955 g_assert (o->has_cmods);
5956 g_assert (cmods_source->has_cmods);
5957 if (!mono_type_is_aggregate_mods (o) &&
5958 !mono_type_is_aggregate_mods (cmods_source) &&
5959 mono_type_get_cmods (o)->image == mono_type_get_cmods (cmods_source)->image) {
5960 /* the uniform case: all the cmods are from the same image. */
5961 MonoCustomModContainer *o_cmods = mono_type_get_cmods (o);
5962 MonoCustomModContainer *extra_cmods = mono_type_get_cmods (cmods_source);
5963 uint8_t total_cmods = o_cmods->count + extra_cmods->count;
5964 gboolean aggregate = FALSE;
5965 size_t sizeof_dup = mono_sizeof_type_with_mods (total_cmods, aggregate);
5966 MonoType *r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_dup) : (MonoType *)g_malloc0 (sizeof_dup);
5968 mono_type_with_mods_init (r, total_cmods, aggregate);
5970 /* copy the original type o, not including its modifiers */
5971 memcpy (r, o, mono_sizeof_type_with_mods (0, FALSE));
5972 deep_type_dup_fixup (image, r, o);
5974 /* The modifier order matters to Roslyn, they expect the extra cmods to come first:
5976 * Suppose we substitute 'int32 modopt(IsLong)' for 'T' in 'void Test
5977 * (T modopt(IsConst))'. Roslyn expects the result to be 'void Test
5978 * (int32 modopt(IsLong) modopt(IsConst))'.
5980 * but! cmods are encoded in IL in reverse order, so 'int32 modopt(IsConst) modopt(IsLong)' is
5981 * encoded as `cmod_opt [typeref IsLong] cmod_opt [typeref IsConst] I4`
5982 * so in our array, extra_cmods (IsLong) come first, followed by o_cmods (IsConst)
5984 * (Here 'o' is 'int32 modopt(IsLong)' and cmods_source is 'T modopt(IsConst)')
5986 /* append the modifiers from cmods_source and o */
5987 MonoCustomModContainer *r_container = mono_type_get_cmods (r);
5988 uint8_t dest_offset = 0;
5989 r_container->image = extra_cmods->image;
5991 memcpy (&r_container->modifiers [dest_offset], &o_cmods->modifiers [0], o_cmods->count * sizeof (MonoCustomMod));
5992 dest_offset += o_cmods->count;
5993 memcpy (&r_container->modifiers [dest_offset], &extra_cmods->modifiers [0], extra_cmods->count * sizeof (MonoCustomMod));
5994 dest_offset += extra_cmods->count;
5995 g_assert (dest_offset == total_cmods);
5997 return r;
5998 } else {
5999 /* The aggregate case: either o_cmods or extra_cmods has aggregate cmods, or they're both simple but from different images. */
6000 uint8_t total_cmods = 0;
6001 total_cmods += mono_type_custom_modifier_count (o);
6002 total_cmods += mono_type_custom_modifier_count (cmods_source);
6004 gboolean aggregate = TRUE;
6005 size_t sizeof_dup = mono_sizeof_type_with_mods (total_cmods, aggregate);
6007 /* FIXME: if image, and the images of the custom modifiers from
6008 * o and cmods_source are all different, we need an image
6009 * set... */
6010 MonoType *r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_dup) : (MonoType*)g_malloc0 (sizeof_dup);
6012 mono_type_with_mods_init (r, total_cmods, aggregate);
6014 memcpy (r, o, mono_sizeof_type_with_mods (0, FALSE));
6015 deep_type_dup_fixup (image, r, o);
6017 /* Try not to blow up the stack. See comment on
6018 * MONO_MAX_EXPECTED_CMODS. Since here we're appending all the
6019 * mods together, it's possible we'll end up with more than the
6020 * maximum allowed. If that ever happens in practice, we
6021 * should redefine the bound and possibly make this function
6022 * fail dynamically instead of asserting.
6024 g_assert (total_cmods < MONO_MAX_EXPECTED_CMODS);
6025 size_t r_container_size = mono_sizeof_aggregate_modifiers (total_cmods);
6026 MonoAggregateModContainer *r_container_candidate = g_alloca (r_container_size);
6027 memset (r_container_candidate, 0, r_container_size);
6028 uint8_t dest_offset = 0;
6030 dest_offset = custom_modifier_copy (r_container_candidate, dest_offset, o);
6031 dest_offset = custom_modifier_copy (r_container_candidate, dest_offset, cmods_source);
6032 g_assert (dest_offset == total_cmods);
6033 r_container_candidate->count = total_cmods;
6035 mono_type_set_amods (r, mono_metadata_get_canonical_aggregate_modifiers (r_container_candidate));
6037 return r;
6042 * Works the same way as mono_metadata_type_dup but pick cmods from @cmods_source
6044 MonoType *
6045 mono_metadata_type_dup_with_cmods (MonoImage *image, const MonoType *o, const MonoType *cmods_source)
6047 if (o->has_cmods && o != cmods_source && cmods_source->has_cmods) {
6048 return do_metadata_type_dup_append_cmods (image, o, cmods_source);
6051 MonoType *r = NULL;
6053 /* if we get here, either o and cmods_source alias, or else exactly one of them has cmods. */
6055 uint8_t num_mods = MAX (mono_type_custom_modifier_count (o), mono_type_custom_modifier_count (cmods_source));
6056 gboolean aggregate = mono_type_is_aggregate_mods (o) || mono_type_is_aggregate_mods (cmods_source);
6057 size_t sizeof_r = mono_sizeof_type_with_mods (num_mods, aggregate);
6059 r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_r) : (MonoType *)g_malloc0 (sizeof_r);
6061 if (cmods_source->has_cmods) {
6062 /* FIXME: if it's aggregate what do we assert here? */
6063 g_assert (!image || (!aggregate && image == mono_type_get_cmods (cmods_source)->image));
6064 memcpy (r, cmods_source, mono_sizeof_type (cmods_source));
6067 memcpy (r, o, mono_sizeof_type (o));
6069 /* reset custom mod count and aggregateness to be correct. */
6070 mono_type_with_mods_init (r, num_mods, aggregate);
6071 if (aggregate)
6072 mono_type_set_amods (r, mono_type_is_aggregate_mods (o) ? mono_type_get_amods (o) : mono_type_get_amods (cmods_source));
6073 deep_type_dup_fixup (image, r, o);
6074 return r;
6078 static void
6079 deep_type_dup_fixup (MonoImage *image, MonoType *r, const MonoType *o)
6081 if (o->type == MONO_TYPE_PTR) {
6082 r->data.type = mono_metadata_type_dup (image, o->data.type);
6083 } else if (o->type == MONO_TYPE_ARRAY) {
6084 r->data.array = mono_dup_array_type (image, o->data.array);
6085 } else if (o->type == MONO_TYPE_FNPTR) {
6086 /*FIXME the dup'ed signature is leaked mono_metadata_free_type*/
6087 r->data.method = mono_metadata_signature_deep_dup (image, o->data.method);
6092 * mono_signature_hash:
6094 guint
6095 mono_signature_hash (MonoMethodSignature *sig)
6097 guint i, res = sig->ret->type;
6099 for (i = 0; i < sig->param_count; i++)
6100 res = (res << 5) - res + mono_type_hash (sig->params[i]);
6102 return res;
6106 * mono_metadata_encode_value:
6107 * @value: value to encode
6108 * @buf: buffer where to write the compressed representation
6109 * @endbuf: pointer updated to point at the end of the encoded output
6111 * Encodes the value @value in the compressed representation used
6112 * in metadata and stores the result in @buf. @buf needs to be big
6113 * enough to hold the data (4 bytes).
6115 void
6116 mono_metadata_encode_value (guint32 value, char *buf, char **endbuf)
6118 char *p = buf;
6120 if (value < 0x80)
6121 *p++ = value;
6122 else if (value < 0x4000) {
6123 p [0] = 0x80 | (value >> 8);
6124 p [1] = value & 0xff;
6125 p += 2;
6126 } else {
6127 p [0] = (value >> 24) | 0xc0;
6128 p [1] = (value >> 16) & 0xff;
6129 p [2] = (value >> 8) & 0xff;
6130 p [3] = value & 0xff;
6131 p += 4;
6133 if (endbuf)
6134 *endbuf = p;
6138 * mono_metadata_field_info:
6139 * \param meta the Image the field is defined in
6140 * \param index the index in the field table representing the field
6141 * \param offset a pointer to an integer where to store the offset that may have been specified for the field in a FieldLayout table
6142 * \param rva a pointer to the RVA of the field data in the image that may have been defined in a \c FieldRVA table
6143 * \param marshal_spec a pointer to the marshal spec that may have been defined for the field in a \c FieldMarshal table.
6145 * Gather info for field \p index that may have been defined in the \c FieldLayout,
6146 * \c FieldRVA and \c FieldMarshal tables.
6147 * Either of \p offset, \p rva and \p marshal_spec can be NULL if you're not interested
6148 * in the data.
6150 void
6151 mono_metadata_field_info (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
6152 MonoMarshalSpec **marshal_spec)
6154 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, FALSE);
6157 void
6158 mono_metadata_field_info_with_mempool (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
6159 MonoMarshalSpec **marshal_spec)
6161 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, TRUE);
6164 static void
6165 mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
6166 MonoMarshalSpec **marshal_spec, gboolean alloc_from_image)
6168 MonoTableInfo *tdef;
6169 locator_t loc;
6171 loc.idx = index + 1;
6172 if (meta->uncompressed_metadata)
6173 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
6175 if (offset) {
6176 tdef = &meta->tables [MONO_TABLE_FIELDLAYOUT];
6178 loc.col_idx = MONO_FIELD_LAYOUT_FIELD;
6179 loc.t = tdef;
6181 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
6182 *offset = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_LAYOUT_OFFSET);
6183 } else {
6184 *offset = (guint32)-1;
6187 if (rva) {
6188 tdef = &meta->tables [MONO_TABLE_FIELDRVA];
6190 loc.col_idx = MONO_FIELD_RVA_FIELD;
6191 loc.t = tdef;
6193 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
6195 * LAMESPEC: There is no signature, no nothing, just the raw data.
6197 *rva = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_RVA_RVA);
6198 } else {
6199 *rva = 0;
6202 if (marshal_spec) {
6203 const char *p;
6205 if ((p = mono_metadata_get_marshal_info (meta, index, TRUE))) {
6206 *marshal_spec = mono_metadata_parse_marshal_spec_full (alloc_from_image ? meta : NULL, meta, p);
6213 * mono_metadata_get_constant_index:
6214 * \param meta the Image the field is defined in
6215 * \param index the token that may have a row defined in the constants table
6216 * \param hint possible position for the row
6218 * \p token must be a \c FieldDef, \c ParamDef or \c PropertyDef token.
6220 * \returns the index into the \c Constants table or 0 if not found.
6222 guint32
6223 mono_metadata_get_constant_index (MonoImage *meta, guint32 token, guint32 hint)
6225 MonoTableInfo *tdef;
6226 locator_t loc;
6227 guint32 index = mono_metadata_token_index (token);
6229 tdef = &meta->tables [MONO_TABLE_CONSTANT];
6230 index <<= MONO_HASCONSTANT_BITS;
6231 switch (mono_metadata_token_table (token)) {
6232 case MONO_TABLE_FIELD:
6233 index |= MONO_HASCONSTANT_FIEDDEF;
6234 break;
6235 case MONO_TABLE_PARAM:
6236 index |= MONO_HASCONSTANT_PARAM;
6237 break;
6238 case MONO_TABLE_PROPERTY:
6239 index |= MONO_HASCONSTANT_PROPERTY;
6240 break;
6241 default:
6242 g_warning ("Not a valid token for the constant table: 0x%08x", token);
6243 return 0;
6245 loc.idx = index;
6246 loc.col_idx = MONO_CONSTANT_PARENT;
6247 loc.t = tdef;
6249 /* FIXME: Index translation */
6251 if ((hint > 0) && (hint < tdef->rows) && (mono_metadata_decode_row_col (tdef, hint - 1, MONO_CONSTANT_PARENT) == index))
6252 return hint;
6254 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
6255 return loc.result + 1;
6257 return 0;
6261 * mono_metadata_events_from_typedef:
6262 * \param meta metadata context
6263 * \param index 0-based index (in the \c TypeDef table) describing a type
6264 * \returns the 0-based index in the \c Event table for the events in the
6265 * type. The last event that belongs to the type (plus 1) is stored
6266 * in the \p end_idx pointer.
6268 guint32
6269 mono_metadata_events_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
6271 locator_t loc;
6272 guint32 start, end;
6273 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_EVENTMAP];
6275 *end_idx = 0;
6277 if (!tdef->base)
6278 return 0;
6280 loc.t = tdef;
6281 loc.col_idx = MONO_EVENT_MAP_PARENT;
6282 loc.idx = index + 1;
6284 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6285 return 0;
6287 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_EVENT_MAP_EVENTLIST);
6288 if (loc.result + 1 < tdef->rows) {
6289 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_EVENT_MAP_EVENTLIST) - 1;
6290 } else {
6291 end = meta->tables [MONO_TABLE_EVENT].rows;
6294 *end_idx = end;
6295 return start - 1;
6299 * mono_metadata_methods_from_event:
6300 * \param meta metadata context
6301 * \param index 0-based index (in the \c Event table) describing a event
6302 * \returns the 0-based index in the \c MethodDef table for the methods in the
6303 * event. The last method that belongs to the event (plus 1) is stored
6304 * in the \p end_idx pointer.
6306 guint32
6307 mono_metadata_methods_from_event (MonoImage *meta, guint32 index, guint *end_idx)
6309 locator_t loc;
6310 guint start, end;
6311 guint32 cols [MONO_METHOD_SEMA_SIZE];
6312 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
6314 *end_idx = 0;
6315 if (!msemt->base)
6316 return 0;
6318 if (meta->uncompressed_metadata)
6319 index = search_ptr_table (meta, MONO_TABLE_EVENT_POINTER, index + 1) - 1;
6321 loc.t = msemt;
6322 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
6323 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT; /* Method association coded index */
6325 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
6326 return 0;
6328 start = loc.result;
6330 * We may end up in the middle of the rows...
6332 while (start > 0) {
6333 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
6334 start--;
6335 else
6336 break;
6338 end = start + 1;
6339 while (end < msemt->rows) {
6340 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
6341 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
6342 break;
6343 ++end;
6345 *end_idx = end;
6346 return start;
6350 * mono_metadata_properties_from_typedef:
6351 * \param meta metadata context
6352 * \param index 0-based index (in the \c TypeDef table) describing a type
6353 * \returns the 0-based index in the \c Property table for the properties in the
6354 * type. The last property that belongs to the type (plus 1) is stored
6355 * in the \p end_idx pointer.
6357 guint32
6358 mono_metadata_properties_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
6360 locator_t loc;
6361 guint32 start, end;
6362 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_PROPERTYMAP];
6364 *end_idx = 0;
6366 if (!tdef->base)
6367 return 0;
6369 loc.t = tdef;
6370 loc.col_idx = MONO_PROPERTY_MAP_PARENT;
6371 loc.idx = index + 1;
6373 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6374 return 0;
6376 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_PROPERTY_MAP_PROPERTY_LIST);
6377 if (loc.result + 1 < tdef->rows) {
6378 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_PROPERTY_MAP_PROPERTY_LIST) - 1;
6379 } else {
6380 end = meta->tables [MONO_TABLE_PROPERTY].rows;
6383 *end_idx = end;
6384 return start - 1;
6388 * mono_metadata_methods_from_property:
6389 * \param meta metadata context
6390 * \param index 0-based index (in the \c PropertyDef table) describing a property
6391 * \returns the 0-based index in the \c MethodDef table for the methods in the
6392 * property. The last method that belongs to the property (plus 1) is stored
6393 * in the \p end_idx pointer.
6395 guint32
6396 mono_metadata_methods_from_property (MonoImage *meta, guint32 index, guint *end_idx)
6398 locator_t loc;
6399 guint start, end;
6400 guint32 cols [MONO_METHOD_SEMA_SIZE];
6401 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
6403 *end_idx = 0;
6404 if (!msemt->base)
6405 return 0;
6407 if (meta->uncompressed_metadata)
6408 index = search_ptr_table (meta, MONO_TABLE_PROPERTY_POINTER, index + 1) - 1;
6410 loc.t = msemt;
6411 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
6412 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY; /* Method association coded index */
6414 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
6415 return 0;
6417 start = loc.result;
6419 * We may end up in the middle of the rows...
6421 while (start > 0) {
6422 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
6423 start--;
6424 else
6425 break;
6427 end = start + 1;
6428 while (end < msemt->rows) {
6429 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
6430 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
6431 break;
6432 ++end;
6434 *end_idx = end;
6435 return start;
6439 * mono_metadata_implmap_from_method:
6441 guint32
6442 mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx)
6444 locator_t loc;
6445 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_IMPLMAP];
6447 if (!tdef->base)
6448 return 0;
6450 /* No index translation seems to be needed */
6452 loc.t = tdef;
6453 loc.col_idx = MONO_IMPLMAP_MEMBER;
6454 loc.idx = ((method_idx + 1) << MONO_MEMBERFORWD_BITS) | MONO_MEMBERFORWD_METHODDEF;
6456 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6457 return 0;
6459 return loc.result + 1;
6463 * mono_type_create_from_typespec:
6464 * \param image context where the image is created
6465 * \param type_spec typespec token
6466 * \deprecated use \c mono_type_create_from_typespec_checked that has proper error handling
6468 * Creates a \c MonoType representing the \c TypeSpec indexed by the \p type_spec
6469 * token.
6471 MonoType *
6472 mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
6474 ERROR_DECL (error);
6475 MonoType *type = mono_type_create_from_typespec_checked (image, type_spec, error);
6476 if (!type)
6477 g_error ("Could not create typespec %x due to %s", type_spec, mono_error_get_message (error));
6478 return type;
6481 MonoType *
6482 mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, MonoError *error)
6485 guint32 idx = mono_metadata_token_index (type_spec);
6486 MonoTableInfo *t;
6487 guint32 cols [MONO_TYPESPEC_SIZE];
6488 const char *ptr;
6489 MonoType *type, *type2;
6491 error_init (error);
6493 type = (MonoType *)mono_conc_hashtable_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
6494 if (type)
6495 return type;
6497 t = &image->tables [MONO_TABLE_TYPESPEC];
6499 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
6500 ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
6502 if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, error))
6503 return NULL;
6505 mono_metadata_decode_value (ptr, &ptr);
6507 type = mono_metadata_parse_type_checked (image, NULL, 0, TRUE, ptr, &ptr, error);
6508 if (!type)
6509 return NULL;
6511 type2 = mono_metadata_type_dup (image, type);
6512 mono_metadata_free_type (type);
6514 mono_image_lock (image);
6516 /* We might leak some data in the image mempool if found */
6517 type = (MonoType*)mono_conc_hashtable_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
6518 if (!type)
6519 type = type2;
6521 mono_image_unlock (image);
6523 return type;
6527 static char*
6528 mono_image_strndup (MonoImage *image, const char *data, guint len)
6530 char *res;
6531 if (!image)
6532 return g_strndup (data, len);
6533 res = (char *)mono_image_alloc (image, len + 1);
6534 memcpy (res, data, len);
6535 res [len] = 0;
6536 return res;
6540 * mono_metadata_parse_marshal_spec:
6542 MonoMarshalSpec *
6543 mono_metadata_parse_marshal_spec (MonoImage *image, const char *ptr)
6545 return mono_metadata_parse_marshal_spec_full (NULL, image, ptr);
6549 * If IMAGE is non-null, memory will be allocated from its mempool, otherwise it will be allocated using malloc.
6550 * PARENT_IMAGE is the image containing the marshal spec.
6552 MonoMarshalSpec *
6553 mono_metadata_parse_marshal_spec_full (MonoImage *image, MonoImage *parent_image, const char *ptr)
6555 MonoMarshalSpec *res;
6556 int len;
6557 const char *start = ptr;
6559 /* fixme: this is incomplete, but I cant find more infos in the specs */
6561 if (image)
6562 res = (MonoMarshalSpec *)mono_image_alloc0 (image, sizeof (MonoMarshalSpec));
6563 else
6564 res = g_new0 (MonoMarshalSpec, 1);
6566 len = mono_metadata_decode_value (ptr, &ptr);
6567 res->native = (MonoMarshalNative)*ptr++;
6569 if (res->native == MONO_NATIVE_LPARRAY) {
6570 res->data.array_data.param_num = -1;
6571 res->data.array_data.num_elem = -1;
6572 res->data.array_data.elem_mult = -1;
6574 if (ptr - start <= len)
6575 res->data.array_data.elem_type = (MonoMarshalNative)*ptr++;
6576 if (ptr - start <= len)
6577 res->data.array_data.param_num = mono_metadata_decode_value (ptr, &ptr);
6578 if (ptr - start <= len)
6579 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6580 if (ptr - start <= len) {
6582 * LAMESPEC: Older spec versions say this parameter comes before
6583 * num_elem. Never spec versions don't talk about elem_mult at
6584 * all, but csc still emits it, and it is used to distinguish
6585 * between param_num being 0, and param_num being omitted.
6586 * So if (param_num == 0) && (num_elem > 0), then
6587 * elem_mult == 0 -> the array size is num_elem
6588 * elem_mult == 1 -> the array size is @param_num + num_elem
6590 res->data.array_data.elem_mult = mono_metadata_decode_value (ptr, &ptr);
6594 if (res->native == MONO_NATIVE_BYVALTSTR) {
6595 if (ptr - start <= len)
6596 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6599 if (res->native == MONO_NATIVE_BYVALARRAY) {
6600 if (ptr - start <= len)
6601 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6604 if (res->native == MONO_NATIVE_CUSTOM) {
6605 /* skip unused type guid */
6606 len = mono_metadata_decode_value (ptr, &ptr);
6607 ptr += len;
6608 /* skip unused native type name */
6609 len = mono_metadata_decode_value (ptr, &ptr);
6610 ptr += len;
6611 /* read custom marshaler type name */
6612 len = mono_metadata_decode_value (ptr, &ptr);
6613 res->data.custom_data.custom_name = mono_image_strndup (image, ptr, len);
6614 ptr += len;
6615 /* read cookie string */
6616 len = mono_metadata_decode_value (ptr, &ptr);
6617 res->data.custom_data.cookie = mono_image_strndup (image, ptr, len);
6618 res->data.custom_data.image = parent_image;
6621 if (res->native == MONO_NATIVE_SAFEARRAY) {
6622 res->data.safearray_data.elem_type = (MonoMarshalVariant)0;
6623 res->data.safearray_data.num_elem = 0;
6624 if (ptr - start <= len)
6625 res->data.safearray_data.elem_type = (MonoMarshalVariant)*ptr++;
6626 if (ptr - start <= len)
6627 res->data.safearray_data.num_elem = *ptr++;
6629 return res;
6633 * mono_metadata_free_marshal_spec:
6635 void
6636 mono_metadata_free_marshal_spec (MonoMarshalSpec *spec)
6638 if (!spec)
6639 return;
6641 if (spec->native == MONO_NATIVE_CUSTOM) {
6642 g_free (spec->data.custom_data.custom_name);
6643 g_free (spec->data.custom_data.cookie);
6645 g_free (spec);
6649 * mono_type_to_unmanaged:
6650 * The value pointed to by \p conv will contain the kind of marshalling required for this
6651 * particular type one of the \c MONO_MARSHAL_CONV_ enumeration values.
6652 * \returns A \c MonoMarshalNative enumeration value (<code>MONO_NATIVE_</code>) value
6653 * describing the underlying native reprensetation of the type.
6655 guint32 // FIXMEcxx MonoMarshalNative
6656 mono_type_to_unmanaged (MonoType *type, MonoMarshalSpec *mspec, gboolean as_field,
6657 gboolean unicode, MonoMarshalConv *conv)
6659 MonoMarshalConv dummy_conv;
6660 int t = type->type;
6662 if (!conv)
6663 conv = &dummy_conv;
6665 *conv = MONO_MARSHAL_CONV_NONE;
6667 if (type->byref)
6668 return MONO_NATIVE_UINT;
6670 handle_enum:
6671 switch (t) {
6672 case MONO_TYPE_BOOLEAN:
6673 if (mspec) {
6674 switch (mspec->native) {
6675 case MONO_NATIVE_VARIANTBOOL:
6676 *conv = MONO_MARSHAL_CONV_BOOL_VARIANTBOOL;
6677 return MONO_NATIVE_VARIANTBOOL;
6678 case MONO_NATIVE_BOOLEAN:
6679 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6680 return MONO_NATIVE_BOOLEAN;
6681 case MONO_NATIVE_I1:
6682 case MONO_NATIVE_U1:
6683 return mspec->native;
6684 default:
6685 g_error ("cant marshal bool to native type %02x", mspec->native);
6688 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6689 return MONO_NATIVE_BOOLEAN;
6690 case MONO_TYPE_CHAR:
6691 if (mspec) {
6692 switch (mspec->native) {
6693 case MONO_NATIVE_U2:
6694 case MONO_NATIVE_U1:
6695 return mspec->native;
6696 default:
6697 g_error ("cant marshal char to native type %02x", mspec->native);
6700 return unicode ? MONO_NATIVE_U2 : MONO_NATIVE_U1;
6701 case MONO_TYPE_I1: return MONO_NATIVE_I1;
6702 case MONO_TYPE_U1: return MONO_NATIVE_U1;
6703 case MONO_TYPE_I2: return MONO_NATIVE_I2;
6704 case MONO_TYPE_U2: return MONO_NATIVE_U2;
6705 case MONO_TYPE_I4: return MONO_NATIVE_I4;
6706 case MONO_TYPE_U4: return MONO_NATIVE_U4;
6707 case MONO_TYPE_I8: return MONO_NATIVE_I8;
6708 case MONO_TYPE_U8: return MONO_NATIVE_U8;
6709 case MONO_TYPE_R4: return MONO_NATIVE_R4;
6710 case MONO_TYPE_R8: return MONO_NATIVE_R8;
6711 case MONO_TYPE_STRING:
6712 if (mspec) {
6713 switch (mspec->native) {
6714 case MONO_NATIVE_BSTR:
6715 *conv = MONO_MARSHAL_CONV_STR_BSTR;
6716 return MONO_NATIVE_BSTR;
6717 case MONO_NATIVE_LPSTR:
6718 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6719 return MONO_NATIVE_LPSTR;
6720 case MONO_NATIVE_LPWSTR:
6721 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6722 return MONO_NATIVE_LPWSTR;
6723 case MONO_NATIVE_LPTSTR:
6724 *conv = MONO_MARSHAL_CONV_STR_LPTSTR;
6725 return MONO_NATIVE_LPTSTR;
6726 case MONO_NATIVE_ANSIBSTR:
6727 *conv = MONO_MARSHAL_CONV_STR_ANSIBSTR;
6728 return MONO_NATIVE_ANSIBSTR;
6729 case MONO_NATIVE_TBSTR:
6730 *conv = MONO_MARSHAL_CONV_STR_TBSTR;
6731 return MONO_NATIVE_TBSTR;
6732 case MONO_NATIVE_UTF8STR:
6733 *conv = MONO_MARSHAL_CONV_STR_UTF8STR;
6734 return MONO_NATIVE_UTF8STR;
6735 case MONO_NATIVE_BYVALTSTR:
6736 if (unicode)
6737 *conv = MONO_MARSHAL_CONV_STR_BYVALWSTR;
6738 else
6739 *conv = MONO_MARSHAL_CONV_STR_BYVALSTR;
6740 return MONO_NATIVE_BYVALTSTR;
6741 default:
6742 g_error ("Can not marshal string to native type '%02x': Invalid managed/unmanaged type combination (String fields must be paired with LPStr, LPWStr, BStr or ByValTStr).", mspec->native);
6745 if (unicode) {
6746 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6747 return MONO_NATIVE_LPWSTR;
6749 else {
6750 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6751 return MONO_NATIVE_LPSTR;
6753 case MONO_TYPE_PTR: return MONO_NATIVE_UINT;
6754 case MONO_TYPE_VALUETYPE: /*FIXME*/
6755 if (m_class_is_enumtype (type->data.klass)) {
6756 t = mono_class_enum_basetype_internal (type->data.klass)->type;
6757 goto handle_enum;
6759 if (type->data.klass == mono_class_try_get_handleref_class ()){
6760 *conv = MONO_MARSHAL_CONV_HANDLEREF;
6761 return MONO_NATIVE_INT;
6763 return MONO_NATIVE_STRUCT;
6764 case MONO_TYPE_SZARRAY:
6765 case MONO_TYPE_ARRAY:
6766 if (mspec) {
6767 switch (mspec->native) {
6768 case MONO_NATIVE_BYVALARRAY:
6769 if ((m_class_get_element_class (type->data.klass) == mono_defaults.char_class) && !unicode)
6770 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY;
6771 else
6772 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALARRAY;
6773 return MONO_NATIVE_BYVALARRAY;
6774 case MONO_NATIVE_SAFEARRAY:
6775 *conv = MONO_MARSHAL_CONV_ARRAY_SAVEARRAY;
6776 return MONO_NATIVE_SAFEARRAY;
6777 case MONO_NATIVE_LPARRAY:
6778 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6779 return MONO_NATIVE_LPARRAY;
6780 default:
6781 g_error ("cant marshal array as native type %02x", mspec->native);
6785 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6786 return MONO_NATIVE_LPARRAY;
6787 case MONO_TYPE_I: return MONO_NATIVE_INT;
6788 case MONO_TYPE_U: return MONO_NATIVE_UINT;
6789 case MONO_TYPE_CLASS:
6790 case MONO_TYPE_OBJECT: {
6791 /* FIXME : we need to handle ArrayList and StringBuilder here, probably */
6792 if (mspec) {
6793 switch (mspec->native) {
6794 case MONO_NATIVE_STRUCT:
6795 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6796 return MONO_NATIVE_STRUCT;
6797 case MONO_NATIVE_CUSTOM:
6798 return MONO_NATIVE_CUSTOM;
6799 case MONO_NATIVE_INTERFACE:
6800 *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
6801 return MONO_NATIVE_INTERFACE;
6802 case MONO_NATIVE_IDISPATCH:
6803 *conv = MONO_MARSHAL_CONV_OBJECT_IDISPATCH;
6804 return MONO_NATIVE_IDISPATCH;
6805 case MONO_NATIVE_IUNKNOWN:
6806 *conv = MONO_MARSHAL_CONV_OBJECT_IUNKNOWN;
6807 return MONO_NATIVE_IUNKNOWN;
6808 case MONO_NATIVE_FUNC:
6809 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6810 type->data.klass == mono_defaults.delegate_class ||
6811 m_class_get_parent (type->data.klass) == mono_defaults.multicastdelegate_class)) {
6812 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6813 return MONO_NATIVE_FUNC;
6815 /* Fall through */
6816 default:
6817 g_error ("cant marshal object as native type %02x", mspec->native);
6820 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6821 type->data.klass == mono_defaults.delegate_class ||
6822 m_class_get_parent (type->data.klass) == mono_defaults.multicastdelegate_class)) {
6823 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6824 return MONO_NATIVE_FUNC;
6826 if (mono_class_try_get_safehandle_class () && type->data.klass != NULL &&
6827 mono_class_is_subclass_of_internal (type->data.klass, mono_class_try_get_safehandle_class (), FALSE)){
6828 *conv = MONO_MARSHAL_CONV_SAFEHANDLE;
6829 return MONO_NATIVE_INT;
6831 #ifndef DISABLE_COM
6832 if (t == MONO_TYPE_CLASS && mono_cominterop_is_interface (type->data.klass)){
6833 *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
6834 return MONO_NATIVE_INTERFACE;
6836 #endif
6837 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6838 return MONO_NATIVE_STRUCT;
6840 case MONO_TYPE_FNPTR: return MONO_NATIVE_FUNC;
6841 case MONO_TYPE_GENERICINST:
6842 type = m_class_get_byval_arg (type->data.generic_class->container_class);
6843 t = type->type;
6844 goto handle_enum;
6845 case MONO_TYPE_TYPEDBYREF:
6846 default:
6847 g_error ("type 0x%02x not handled in marshal", t);
6849 return MONO_NATIVE_MAX;
6853 * mono_metadata_get_marshal_info:
6855 const char*
6856 mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field)
6858 locator_t loc;
6859 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_FIELDMARSHAL];
6861 if (!tdef->base)
6862 return NULL;
6864 loc.t = tdef;
6865 loc.col_idx = MONO_FIELD_MARSHAL_PARENT;
6866 loc.idx = ((idx + 1) << MONO_HAS_FIELD_MARSHAL_BITS) | (is_field? MONO_HAS_FIELD_MARSHAL_FIELDSREF: MONO_HAS_FIELD_MARSHAL_PARAMDEF);
6868 /* FIXME: Index translation */
6870 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6871 return NULL;
6873 return mono_metadata_blob_heap (meta, mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_MARSHAL_NATIVE_TYPE));
6876 MonoMethod*
6877 mono_method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context, MonoError *error)
6879 MonoMethod *result = NULL;
6880 guint32 idx = tok >> MONO_METHODDEFORREF_BITS;
6882 error_init (error);
6884 switch (tok & MONO_METHODDEFORREF_MASK) {
6885 case MONO_METHODDEFORREF_METHODDEF:
6886 result = mono_get_method_checked (m, MONO_TOKEN_METHOD_DEF | idx, NULL, context, error);
6887 break;
6888 case MONO_METHODDEFORREF_METHODREF:
6889 result = mono_get_method_checked (m, MONO_TOKEN_MEMBER_REF | idx, NULL, context, error);
6890 break;
6891 default:
6892 mono_error_set_bad_image (error, m, "Invalid MethodDefOfRef token %x", tok);
6895 return result;
6899 * mono_class_get_overrides_full:
6901 * Compute the method overrides belonging to class @type_token in @overrides, and the number of overrides in @num_overrides.
6904 void
6905 mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides, MonoGenericContext *generic_context, MonoError *error)
6907 locator_t loc;
6908 MonoTableInfo *tdef = &image->tables [MONO_TABLE_METHODIMPL];
6909 guint32 start, end;
6910 gint32 i, num;
6911 guint32 cols [MONO_METHODIMPL_SIZE];
6912 MonoMethod **result;
6914 error_init (error);
6916 *overrides = NULL;
6917 if (num_overrides)
6918 *num_overrides = 0;
6920 if (!tdef->base)
6921 return;
6923 loc.t = tdef;
6924 loc.col_idx = MONO_METHODIMPL_CLASS;
6925 loc.idx = mono_metadata_token_index (type_token);
6927 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6928 return;
6930 start = loc.result;
6931 end = start + 1;
6933 * We may end up in the middle of the rows...
6935 while (start > 0) {
6936 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_METHODIMPL_CLASS))
6937 start--;
6938 else
6939 break;
6941 while (end < tdef->rows) {
6942 if (loc.idx == mono_metadata_decode_row_col (tdef, end, MONO_METHODIMPL_CLASS))
6943 end++;
6944 else
6945 break;
6947 num = end - start;
6948 result = g_new (MonoMethod*, num * 2);
6949 for (i = 0; i < num; ++i) {
6950 MonoMethod *method;
6952 if (!mono_verifier_verify_methodimpl_row (image, start + i, error))
6953 break;
6955 mono_metadata_decode_row (tdef, start + i, cols, MONO_METHODIMPL_SIZE);
6956 method = mono_method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_DECLARATION], generic_context, error);
6957 if (!method)
6958 break;
6960 result [i * 2] = method;
6961 method = mono_method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_BODY], generic_context, error);
6962 if (!method)
6963 break;
6965 result [i * 2 + 1] = method;
6968 if (!is_ok (error)) {
6969 g_free (result);
6970 *overrides = NULL;
6971 if (num_overrides)
6972 *num_overrides = 0;
6973 } else {
6974 *overrides = result;
6975 if (num_overrides)
6976 *num_overrides = num;
6981 * mono_guid_to_string:
6983 * Converts a 16 byte Microsoft GUID to the standard string representation.
6985 char *
6986 mono_guid_to_string (const guint8 *guid)
6988 return g_strdup_printf ("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
6989 guid[3], guid[2], guid[1], guid[0],
6990 guid[5], guid[4],
6991 guid[7], guid[6],
6992 guid[8], guid[9],
6993 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
6997 * mono_guid_to_string_minimal:
6999 * Converts a 16 byte Microsoft GUID to lower case no '-' representation..
7001 char *
7002 mono_guid_to_string_minimal (const guint8 *guid)
7004 return g_strdup_printf ("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
7005 guid[3], guid[2], guid[1], guid[0],
7006 guid[5], guid[4],
7007 guid[7], guid[6],
7008 guid[8], guid[9],
7009 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
7011 static gboolean
7012 get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGenericContainer *container, MonoError *error)
7014 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
7015 guint32 cols [MONO_GENPARCONSTRAINT_SIZE];
7016 guint32 i, token, found;
7017 MonoClass *klass, **res;
7018 GSList *cons = NULL, *tmp;
7019 MonoGenericContext *context = &container->context;
7021 error_init (error);
7023 *constraints = NULL;
7024 found = 0;
7025 for (i = 0; i < tdef->rows; ++i) {
7026 mono_metadata_decode_row (tdef, i, cols, MONO_GENPARCONSTRAINT_SIZE);
7027 if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) {
7028 token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]);
7029 klass = mono_class_get_and_inflate_typespec_checked (image, token, context, error);
7030 if (!klass) {
7031 g_slist_free (cons);
7032 return FALSE;
7034 cons = g_slist_append (cons, klass);
7035 ++found;
7036 } else {
7037 /* contiguous list finished */
7038 if (found)
7039 break;
7042 if (!found)
7043 return TRUE;
7044 res = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * (found + 1));
7045 for (i = 0, tmp = cons; i < found; ++i, tmp = tmp->next) {
7046 res [i] = (MonoClass *)tmp->data;
7048 g_slist_free (cons);
7049 *constraints = res;
7050 return TRUE;
7054 * mono_metadata_get_generic_param_row:
7056 * @image:
7057 * @token: TypeOrMethodDef token, owner for GenericParam
7058 * @owner: coded token, set on return
7060 * Returns: 1-based row-id in the GenericParam table whose
7061 * owner is @token. 0 if not found.
7063 guint32
7064 mono_metadata_get_generic_param_row (MonoImage *image, guint32 token, guint32 *owner)
7066 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
7067 locator_t loc;
7069 g_assert (owner);
7070 if (!tdef->base)
7071 return 0;
7073 if (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
7074 *owner = MONO_TYPEORMETHOD_TYPE;
7075 else if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
7076 *owner = MONO_TYPEORMETHOD_METHOD;
7077 else {
7078 g_error ("wrong token %x to get_generic_param_row", token);
7079 return 0;
7081 *owner |= mono_metadata_token_index (token) << MONO_TYPEORMETHOD_BITS;
7083 loc.idx = *owner;
7084 loc.col_idx = MONO_GENERICPARAM_OWNER;
7085 loc.t = tdef;
7087 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
7088 return 0;
7090 /* Find the first entry by searching backwards */
7091 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_GENERICPARAM_OWNER) == loc.idx))
7092 loc.result --;
7094 return loc.result + 1;
7097 gboolean
7098 mono_metadata_has_generic_params (MonoImage *image, guint32 token)
7100 guint32 owner;
7101 return mono_metadata_get_generic_param_row (image, token, &owner);
7105 * Memory is allocated from IMAGE's mempool.
7107 gboolean
7108 mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token,
7109 MonoGenericContainer *container, MonoError *error)
7112 guint32 start_row, i, owner;
7113 error_init (error);
7115 if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner)))
7116 return TRUE;
7117 for (i = 0; i < container->type_argc; i++) {
7118 if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container, error)) {
7119 return FALSE;
7122 return TRUE;
7126 * mono_metadata_load_generic_params:
7128 * Load the type parameters from the type or method definition @token.
7130 * Use this method after parsing a type or method definition to figure out whether it's a generic
7131 * type / method. When parsing a method definition, @parent_container points to the generic container
7132 * of the current class, if any.
7134 * Note: This method does not load the constraints: for typedefs, this has to be done after fully
7135 * creating the type.
7137 * Returns: NULL if @token is not a generic type or method definition or the new generic container.
7139 * LOCKING: Acquires the loader lock
7142 MonoGenericContainer *
7143 mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericContainer *parent_container, gpointer real_owner)
7145 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
7146 guint32 cols [MONO_GENERICPARAM_SIZE];
7147 guint32 i, owner = 0, n;
7148 MonoGenericContainer *container;
7149 MonoGenericParamFull *params;
7150 MonoGenericContext *context;
7151 gboolean is_method = mono_metadata_token_table (token) == MONO_TABLE_METHOD;
7152 gboolean is_anonymous = real_owner == NULL;
7154 if (!(i = mono_metadata_get_generic_param_row (image, token, &owner)))
7155 return NULL;
7156 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
7157 params = NULL;
7158 n = 0;
7159 container = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
7160 container->is_anonymous = is_anonymous;
7161 if (is_anonymous) {
7162 container->owner.image = image;
7163 } else {
7164 if (is_method)
7165 container->owner.method = (MonoMethod*)real_owner;
7166 else
7167 container->owner.klass = (MonoClass*)real_owner;
7169 do {
7170 n++;
7171 params = (MonoGenericParamFull *)g_realloc (params, sizeof (MonoGenericParamFull) * n);
7172 memset (&params [n - 1], 0, sizeof (MonoGenericParamFull));
7173 params [n - 1].owner = container;
7174 params [n - 1].num = cols [MONO_GENERICPARAM_NUMBER];
7175 params [n - 1].info.token = i | MONO_TOKEN_GENERIC_PARAM;
7176 params [n - 1].info.flags = cols [MONO_GENERICPARAM_FLAGS];
7177 params [n - 1].info.name = mono_metadata_string_heap (image, cols [MONO_GENERICPARAM_NAME]);
7178 if (params [n - 1].num != n - 1)
7179 g_warning ("GenericParam table unsorted or hole in generic param sequence: token %d", i);
7180 if (++i > tdef->rows)
7181 break;
7182 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
7183 } while (cols [MONO_GENERICPARAM_OWNER] == owner);
7185 container->type_argc = n;
7186 container->type_params = (MonoGenericParamFull *)mono_image_alloc0 (image, sizeof (MonoGenericParamFull) * n);
7187 memcpy (container->type_params, params, sizeof (MonoGenericParamFull) * n);
7188 g_free (params);
7189 container->parent = parent_container;
7191 if (is_method)
7192 container->is_method = 1;
7194 g_assert (container->parent == NULL || container->is_method);
7196 context = &container->context;
7197 if (container->is_method) {
7198 context->class_inst = container->parent ? container->parent->context.class_inst : NULL;
7199 context->method_inst = mono_get_shared_generic_inst (container);
7200 } else {
7201 context->class_inst = mono_get_shared_generic_inst (container);
7204 return container;
7207 MonoGenericInst *
7208 mono_get_shared_generic_inst (MonoGenericContainer *container)
7210 MonoType **type_argv;
7211 MonoType *helper;
7212 MonoGenericInst *nginst;
7213 int i;
7215 type_argv = g_new0 (MonoType *, container->type_argc);
7216 helper = g_new0 (MonoType, container->type_argc);
7218 for (i = 0; i < container->type_argc; i++) {
7219 MonoType *t = &helper [i];
7221 t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
7222 t->data.generic_param = mono_generic_container_get_param (container, i);
7224 type_argv [i] = t;
7227 nginst = mono_metadata_get_generic_inst (container->type_argc, type_argv);
7229 g_free (type_argv);
7230 g_free (helper);
7232 return nginst;
7236 * mono_type_is_byref:
7237 * \param type the \c MonoType operated on
7238 * \returns TRUE if \p type represents a type passed by reference,
7239 * FALSE otherwise.
7241 mono_bool
7242 mono_type_is_byref (MonoType *type)
7244 mono_bool result;
7245 MONO_ENTER_GC_UNSAFE; // FIXME slow
7246 result = mono_type_is_byref_internal (type);
7247 MONO_EXIT_GC_UNSAFE;
7248 return result;
7252 * mono_type_get_type:
7253 * \param type the \c MonoType operated on
7254 * \returns the IL type value for \p type. This is one of the \c MonoTypeEnum
7255 * enum members like \c MONO_TYPE_I4 or \c MONO_TYPE_STRING.
7258 mono_type_get_type (MonoType *type)
7260 return mono_type_get_type_internal (type);
7264 * mono_type_get_signature:
7265 * \param type the \c MonoType operated on
7266 * It is only valid to call this function if \p type is a \c MONO_TYPE_FNPTR .
7267 * \returns the \c MonoMethodSignature pointer that describes the signature
7268 * of the function pointer \p type represents.
7270 MonoMethodSignature*
7271 mono_type_get_signature (MonoType *type)
7273 return mono_type_get_signature_internal (type);
7277 * mono_type_get_class:
7278 * \param type the \c MonoType operated on
7279 * It is only valid to call this function if \p type is a \c MONO_TYPE_CLASS or a
7280 * \c MONO_TYPE_VALUETYPE . For more general functionality, use \c mono_class_from_mono_type_internal,
7281 * instead.
7282 * \returns the \c MonoClass pointer that describes the class that \p type represents.
7284 MonoClass*
7285 mono_type_get_class (MonoType *type)
7287 /* FIXME: review the runtime users before adding the assert here */
7288 return mono_type_get_class_internal (type);
7292 * mono_type_get_array_type:
7293 * \param type the \c MonoType operated on
7294 * It is only valid to call this function if \p type is a \c MONO_TYPE_ARRAY .
7295 * \returns a \c MonoArrayType struct describing the array type that \p type
7296 * represents. The info includes details such as rank, array element type
7297 * and the sizes and bounds of multidimensional arrays.
7299 MonoArrayType*
7300 mono_type_get_array_type (MonoType *type)
7302 return mono_type_get_array_type_internal (type);
7306 * mono_type_get_ptr_type:
7307 * \pararm type the \c MonoType operated on
7308 * It is only valid to call this function if \p type is a \c MONO_TYPE_PTR .
7309 * \returns the \c MonoType pointer that describes the type that \p type
7310 * represents a pointer to.
7312 MonoType*
7313 mono_type_get_ptr_type (MonoType *type)
7315 g_assert (type->type == MONO_TYPE_PTR);
7316 return type->data.type;
7320 * mono_type_get_modifiers:
7322 MonoClass*
7323 mono_type_get_modifiers (MonoType *type, gboolean *is_required, gpointer *iter)
7325 /* FIXME: implement */
7326 return NULL;
7330 * mono_type_is_struct:
7331 * \param type the \c MonoType operated on
7332 * \returns TRUE if \p type is a struct, that is a \c ValueType but not an enum
7333 * or a basic type like \c System.Int32 . FALSE otherwise.
7335 mono_bool
7336 mono_type_is_struct (MonoType *type)
7338 return (!type->byref && ((type->type == MONO_TYPE_VALUETYPE &&
7339 !m_class_is_enumtype (type->data.klass)) || (type->type == MONO_TYPE_TYPEDBYREF) ||
7340 ((type->type == MONO_TYPE_GENERICINST) &&
7341 mono_metadata_generic_class_is_valuetype (type->data.generic_class) &&
7342 !m_class_is_enumtype (type->data.generic_class->container_class))));
7346 * mono_type_is_void:
7347 * \param type the \c MonoType operated on
7348 * \returns TRUE if \p type is \c System.Void . FALSE otherwise.
7350 mono_bool
7351 mono_type_is_void (MonoType *type)
7353 return (type && (type->type == MONO_TYPE_VOID) && !type->byref);
7357 * mono_type_is_pointer:
7358 * \param type the \c MonoType operated on
7359 * \returns TRUE if \p type is a managed or unmanaged pointer type. FALSE otherwise.
7361 mono_bool
7362 mono_type_is_pointer (MonoType *type)
7364 return (type && ((type->byref || (type->type == MONO_TYPE_I) || type->type == MONO_TYPE_STRING)
7365 || (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
7366 (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_OBJECT) ||
7367 (type->type == MONO_TYPE_ARRAY) || (type->type == MONO_TYPE_PTR) ||
7368 (type->type == MONO_TYPE_FNPTR)));
7372 * mono_type_is_reference:
7373 * \param type the \c MonoType operated on
7374 * \returns TRUE if \p type represents an object reference. FALSE otherwise.
7376 mono_bool
7377 mono_type_is_reference (MonoType *type)
7379 /* NOTE: changing this function to return TRUE more often may have
7380 * consequences for generic sharing in the AOT compiler. In
7381 * particular, returning TRUE for generic parameters with a 'class'
7382 * constraint may cause crashes.
7384 return (type && (((type->type == MONO_TYPE_STRING) ||
7385 (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
7386 (type->type == MONO_TYPE_OBJECT) || (type->type == MONO_TYPE_ARRAY)) ||
7387 ((type->type == MONO_TYPE_GENERICINST) &&
7388 !mono_metadata_generic_class_is_valuetype (type->data.generic_class))));
7391 mono_bool
7392 mono_type_is_generic_parameter (MonoType *type)
7394 return !type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR);
7398 * mono_signature_get_return_type:
7399 * \param sig the method signature inspected
7400 * \returns the return type of the method signature \p sig
7402 MonoType*
7403 mono_signature_get_return_type (MonoMethodSignature *sig)
7405 MonoType *result;
7406 MONO_ENTER_GC_UNSAFE;
7407 result = sig->ret;
7408 MONO_EXIT_GC_UNSAFE;
7409 return result;
7413 * mono_signature_get_params:
7414 * \param sig the method signature inspected
7415 * \param iter pointer to an iterator
7416 * Iterates over the parameters for the method signature \p sig.
7417 * A \c void* pointer must be initialized to NULL to start the iteration
7418 * and its address is passed to this function repeteadly until it returns
7419 * NULL.
7420 * \returns the next parameter type of the method signature \p sig,
7421 * NULL when finished.
7423 MonoType*
7424 mono_signature_get_params (MonoMethodSignature *sig, gpointer *iter)
7426 MonoType *result;
7427 MONO_ENTER_GC_UNSAFE;
7428 result = mono_signature_get_params_internal (sig, iter);
7429 MONO_EXIT_GC_UNSAFE;
7430 return result;
7433 MonoType*
7434 mono_signature_get_params_internal (MonoMethodSignature *sig, gpointer *iter)
7436 MonoType** type;
7437 if (!iter)
7438 return NULL;
7439 if (!*iter) {
7440 /* start from the first */
7441 if (sig->param_count) {
7442 *iter = &sig->params [0];
7443 return sig->params [0];
7444 } else {
7445 /* no method */
7446 return NULL;
7449 type = (MonoType **)*iter;
7450 type++;
7451 if (type < &sig->params [sig->param_count]) {
7452 *iter = type;
7453 return *type;
7455 return NULL;
7459 * mono_signature_get_param_count:
7460 * \param sig the method signature inspected
7461 * \returns the number of parameters in the method signature \p sig.
7463 guint32
7464 mono_signature_get_param_count (MonoMethodSignature *sig)
7466 return sig->param_count;
7470 * mono_signature_get_call_conv:
7471 * \param sig the method signature inspected
7472 * \returns the call convention of the method signature \p sig.
7474 guint32
7475 mono_signature_get_call_conv (MonoMethodSignature *sig)
7477 return sig->call_convention;
7481 * mono_signature_vararg_start:
7482 * \param sig the method signature inspected
7483 * \returns the number of the first vararg parameter in the
7484 * method signature \param sig. \c -1 if this is not a vararg signature.
7487 mono_signature_vararg_start (MonoMethodSignature *sig)
7489 return sig->sentinelpos;
7493 * mono_signature_is_instance:
7494 * \param sig the method signature inspected
7495 * \returns TRUE if this the method signature \p sig has an implicit
7496 * first instance argument. FALSE otherwise.
7498 gboolean
7499 mono_signature_is_instance (MonoMethodSignature *sig)
7501 return sig->hasthis;
7505 * mono_signature_param_is_out
7506 * \param sig the method signature inspected
7507 * \param param_num the 0-based index of the inspected parameter
7508 * \returns TRUE if the parameter is an out parameter, FALSE
7509 * otherwise.
7511 mono_bool
7512 mono_signature_param_is_out (MonoMethodSignature *sig, int param_num)
7514 g_assert (param_num >= 0 && param_num < sig->param_count);
7515 return (sig->params [param_num]->attrs & PARAM_ATTRIBUTE_OUT) != 0;
7519 * mono_signature_explicit_this:
7520 * \param sig the method signature inspected
7521 * \returns TRUE if this the method signature \p sig has an explicit
7522 * instance argument. FALSE otherwise.
7524 gboolean
7525 mono_signature_explicit_this (MonoMethodSignature *sig)
7527 return sig->explicit_this;
7530 /* for use with allocated memory blocks (assumes alignment is to 8 bytes) */
7531 guint
7532 mono_aligned_addr_hash (gconstpointer ptr)
7534 /* Same hashing we use for objects */
7535 return (GPOINTER_TO_UINT (ptr) >> 3) * 2654435761u;
7539 * If @field belongs to an inflated generic class, return the corresponding field of the
7540 * generic type definition class.
7542 MonoClassField*
7543 mono_metadata_get_corresponding_field_from_generic_type_definition (MonoClassField *field)
7545 MonoClass *gtd;
7546 int offset;
7548 if (!mono_class_is_ginst (field->parent))
7549 return field;
7551 gtd = mono_class_get_generic_class (field->parent)->container_class;
7552 offset = field - m_class_get_fields (field->parent);
7553 return m_class_get_fields (gtd) + offset;
7557 * If @event belongs to an inflated generic class, return the corresponding event of the
7558 * generic type definition class.
7560 MonoEvent*
7561 mono_metadata_get_corresponding_event_from_generic_type_definition (MonoEvent *event)
7563 MonoClass *gtd;
7564 int offset;
7566 if (!mono_class_is_ginst (event->parent))
7567 return event;
7569 gtd = mono_class_get_generic_class (event->parent)->container_class;
7570 offset = event - mono_class_get_event_info (event->parent)->events;
7571 return mono_class_get_event_info (gtd)->events + offset;
7575 * If @property belongs to an inflated generic class, return the corresponding property of the
7576 * generic type definition class.
7578 MonoProperty*
7579 mono_metadata_get_corresponding_property_from_generic_type_definition (MonoProperty *property)
7581 MonoClassPropertyInfo *info;
7582 MonoClass *gtd;
7583 int offset;
7585 if (!mono_class_is_ginst (property->parent))
7586 return property;
7588 info = mono_class_get_property_info (property->parent);
7589 gtd = mono_class_get_generic_class (property->parent)->container_class;
7590 offset = property - info->properties;
7591 return mono_class_get_property_info (gtd)->properties + offset;
7594 MonoWrapperCaches*
7595 mono_method_get_wrapper_cache (MonoMethod *method)
7597 if (method->is_inflated) {
7598 MonoMethodInflated *imethod = (MonoMethodInflated *)method;
7599 return &imethod->owner->wrapper_caches;
7600 } else {
7601 return &m_class_get_image (method->klass)->wrapper_caches;
7605 // 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.
7608 * mono_find_image_set_owner:
7610 * Find the imageset, if any, which a given pointer is located in the memory of.
7612 MonoImageSet *
7613 mono_find_image_set_owner (void *ptr)
7615 MonoImageSet *owner = NULL;
7616 int i;
7618 image_sets_lock ();
7620 if (image_sets)
7622 for (i = 0; !owner && i < image_sets->len; ++i) {
7623 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
7624 if (mono_mempool_contains_addr (set->mempool, ptr))
7625 owner = set;
7629 image_sets_unlock ();
7631 return owner;
7634 void
7635 mono_loader_set_strict_assembly_name_check (gboolean enabled)
7637 check_assembly_names_strictly = enabled;
7640 gboolean
7641 mono_loader_get_strict_assembly_name_check (void)
7643 #if !defined(DISABLE_DESKTOP_LOADER) || defined(ENABLE_NETCORE)
7644 return check_assembly_names_strictly;
7645 #else
7646 return FALSE;
7647 #endif
7651 gboolean
7652 mono_type_is_aggregate_mods (const MonoType *t)
7654 if (!t->has_cmods)
7655 return FALSE;
7657 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7659 return full->is_aggregate;
7662 MonoCustomModContainer *
7663 mono_type_get_cmods (const MonoType *t)
7665 if (!t->has_cmods)
7666 return NULL;
7668 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7670 g_assert (!full->is_aggregate);
7671 return &full->mods.cmods;
7674 MonoAggregateModContainer *
7675 mono_type_get_amods (const MonoType *t)
7677 if (!t->has_cmods)
7678 return NULL;
7680 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7682 g_assert (full->is_aggregate);
7683 return full->mods.amods;
7686 size_t
7687 mono_sizeof_aggregate_modifiers (uint8_t num_mods)
7689 size_t accum = 0;
7690 accum += offsetof (MonoAggregateModContainer, modifiers);
7691 accum += sizeof (MonoSingleCustomMod) * num_mods;
7692 return accum;
7695 size_t
7696 mono_sizeof_type_with_mods (uint8_t num_mods, gboolean is_aggregate)
7698 if (num_mods == 0)
7699 return sizeof (MonoType);
7700 size_t accum = 0;
7701 accum += offsetof (MonoTypeWithModifiers, mods);
7703 if (!is_aggregate) {
7704 accum += offsetof (struct _MonoCustomModContainer, modifiers);
7705 accum += sizeof (MonoCustomMod) * num_mods;
7706 } else {
7707 accum += offsetof (MonoAggregateModContainer, modifiers);
7708 accum += sizeof (MonoAggregateModContainer *);
7710 return accum;
7713 size_t
7714 mono_sizeof_type (const MonoType *ty)
7716 if (ty->has_cmods) {
7717 if (!mono_type_is_aggregate_mods (ty)) {
7718 MonoCustomModContainer *cmods = mono_type_get_cmods (ty);
7719 return mono_sizeof_type_with_mods (cmods->count, FALSE);
7720 } else {
7721 MonoAggregateModContainer *amods = mono_type_get_amods (ty);
7722 return mono_sizeof_type_with_mods (amods->count, TRUE);
7724 } else
7725 return sizeof (MonoType);
7728 void
7729 mono_type_set_amods (MonoType *t, MonoAggregateModContainer *amods)
7731 g_assert (t->has_cmods);
7732 MonoTypeWithModifiers *t_full = (MonoTypeWithModifiers*)t;
7733 g_assert (t_full->is_aggregate);
7734 g_assert (t_full->mods.amods == NULL);
7735 t_full->mods.amods = amods;