[Mono.Runtime.Tests] Exclude simd tests
[mono-project.git] / mono / metadata / metadata.c
blob53a88d9e78bb91e96ae38dd1cd2ee2210a7742c7
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 <mono/metadata/exception-internals.h>
32 #include <mono/utils/mono-error-internals.h>
33 #include <mono/utils/mono-memory-model.h>
34 #include <mono/utils/bsearch.h>
35 #include <mono/utils/atomic.h>
36 #include <mono/utils/unlocked.h>
37 #include <mono/utils/mono-counters.h>
39 static gint32 img_set_cache_hit, img_set_cache_miss, img_set_count;
42 /* Auxiliary structure used for caching inflated signatures */
43 typedef struct {
44 MonoMethodSignature *sig;
45 MonoGenericContext context;
46 } MonoInflatedMethodSignature;
48 static gboolean do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container, gboolean transient,
49 const char *ptr, const char **rptr, MonoError *error);
51 static gboolean do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only);
52 static gboolean mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only);
53 static gboolean mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only);
54 static gboolean _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2,
55 gboolean signature_only);
56 static void free_generic_inst (MonoGenericInst *ginst);
57 static void free_generic_class (MonoGenericClass *ginst);
58 static void free_inflated_method (MonoMethodInflated *method);
59 static void free_inflated_signature (MonoInflatedMethodSignature *sig);
60 static void mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva, MonoMarshalSpec **marshal_spec, gboolean alloc_from_image);
62 static MonoType* mono_signature_get_params_internal (MonoMethodSignature *sig, gpointer *iter);
66 * This enumeration is used to describe the data types in the metadata
67 * tables
69 enum {
70 MONO_MT_END,
72 /* Sized elements */
73 MONO_MT_UINT32,
74 MONO_MT_UINT16,
75 MONO_MT_UINT8,
77 /* Index into Blob heap */
78 MONO_MT_BLOB_IDX,
80 /* Index into String heap */
81 MONO_MT_STRING_IDX,
83 /* GUID index */
84 MONO_MT_GUID_IDX,
86 /* Pointer into a table */
87 MONO_MT_TABLE_IDX,
89 /* HasConstant:Parent pointer (Param, Field or Property) */
90 MONO_MT_CONST_IDX,
92 /* HasCustomAttribute index. Indexes any table except CustomAttribute */
93 MONO_MT_HASCAT_IDX,
95 /* CustomAttributeType encoded index */
96 MONO_MT_CAT_IDX,
98 /* HasDeclSecurity index: TypeDef Method or Assembly */
99 MONO_MT_HASDEC_IDX,
101 /* Implementation coded index: File, Export AssemblyRef */
102 MONO_MT_IMPL_IDX,
104 /* HasFieldMarshal coded index: Field or Param table */
105 MONO_MT_HFM_IDX,
107 /* MemberForwardedIndex: Field or Method */
108 MONO_MT_MF_IDX,
110 /* TypeDefOrRef coded index: typedef, typeref, typespec */
111 MONO_MT_TDOR_IDX,
113 /* MemberRefParent coded index: typeref, moduleref, method, memberref, typesepc, typedef */
114 MONO_MT_MRP_IDX,
116 /* MethodDefOrRef coded index: Method or Member Ref table */
117 MONO_MT_MDOR_IDX,
119 /* HasSemantic coded index: Event or Property */
120 MONO_MT_HS_IDX,
122 /* ResolutionScope coded index: Module, ModuleRef, AssemblytRef, TypeRef */
123 MONO_MT_RS_IDX,
125 /* CustomDebugInformation parent encoded index */
126 MONO_MT_HASCUSTDEBUG_IDX
129 const static unsigned char TableSchemas [] = {
130 #define ASSEMBLY_SCHEMA_OFFSET 0
131 MONO_MT_UINT32, /* "HashId" }, */
132 MONO_MT_UINT16, /* "Major" }, */
133 MONO_MT_UINT16, /* "Minor" }, */
134 MONO_MT_UINT16, /* "BuildNumber" }, */
135 MONO_MT_UINT16, /* "RevisionNumber" }, */
136 MONO_MT_UINT32, /* "Flags" }, */
137 MONO_MT_BLOB_IDX, /* "PublicKey" }, */
138 MONO_MT_STRING_IDX, /* "Name" }, */
139 MONO_MT_STRING_IDX, /* "Culture" }, */
140 MONO_MT_END,
142 #define ASSEMBLYOS_SCHEMA_OFFSET ASSEMBLY_SCHEMA_OFFSET + 10
143 MONO_MT_UINT32, /* "OSPlatformID" }, */
144 MONO_MT_UINT32, /* "OSMajor" }, */
145 MONO_MT_UINT32, /* "OSMinor" }, */
146 MONO_MT_END,
148 #define ASSEMBLYPROC_SCHEMA_OFFSET ASSEMBLYOS_SCHEMA_OFFSET + 4
149 MONO_MT_UINT32, /* "Processor" }, */
150 MONO_MT_END,
152 #define ASSEMBLYREF_SCHEMA_OFFSET ASSEMBLYPROC_SCHEMA_OFFSET + 2
153 MONO_MT_UINT16, /* "Major" }, */
154 MONO_MT_UINT16, /* "Minor" }, */
155 MONO_MT_UINT16, /* "Build" }, */
156 MONO_MT_UINT16, /* "Revision" }, */
157 MONO_MT_UINT32, /* "Flags" }, */
158 MONO_MT_BLOB_IDX, /* "PublicKeyOrToken" }, */
159 MONO_MT_STRING_IDX, /* "Name" }, */
160 MONO_MT_STRING_IDX, /* "Culture" }, */
161 MONO_MT_BLOB_IDX, /* "HashValue" }, */
162 MONO_MT_END,
164 #define ASSEMBLYREFOS_SCHEMA_OFFSET ASSEMBLYREF_SCHEMA_OFFSET + 10
165 MONO_MT_UINT32, /* "OSPlatformID" }, */
166 MONO_MT_UINT32, /* "OSMajorVersion" }, */
167 MONO_MT_UINT32, /* "OSMinorVersion" }, */
168 MONO_MT_TABLE_IDX, /* "AssemblyRef:AssemblyRef" }, */
169 MONO_MT_END,
171 #define ASSEMBLYREFPROC_SCHEMA_OFFSET ASSEMBLYREFOS_SCHEMA_OFFSET + 5
172 MONO_MT_UINT32, /* "Processor" }, */
173 MONO_MT_TABLE_IDX, /* "AssemblyRef:AssemblyRef" }, */
174 MONO_MT_END,
176 #define CLASS_LAYOUT_SCHEMA_OFFSET ASSEMBLYREFPROC_SCHEMA_OFFSET + 3
177 MONO_MT_UINT16, /* "PackingSize" }, */
178 MONO_MT_UINT32, /* "ClassSize" }, */
179 MONO_MT_TABLE_IDX, /* "Parent:TypeDef" }, */
180 MONO_MT_END,
182 #define CONSTANT_SCHEMA_OFFSET CLASS_LAYOUT_SCHEMA_OFFSET + 4
183 MONO_MT_UINT8, /* "Type" }, */
184 MONO_MT_UINT8, /* "PaddingZero" }, */
185 MONO_MT_CONST_IDX, /* "Parent" }, */
186 MONO_MT_BLOB_IDX, /* "Value" }, */
187 MONO_MT_END,
189 #define CUSTOM_ATTR_SCHEMA_OFFSET CONSTANT_SCHEMA_OFFSET + 5
190 MONO_MT_HASCAT_IDX, /* "Parent" }, */
191 MONO_MT_CAT_IDX, /* "Type" }, */
192 MONO_MT_BLOB_IDX, /* "Value" }, */
193 MONO_MT_END,
195 #define DECL_SEC_SCHEMA_OFFSET CUSTOM_ATTR_SCHEMA_OFFSET + 4
196 MONO_MT_UINT16, /* "Action" }, */
197 MONO_MT_HASDEC_IDX, /* "Parent" }, */
198 MONO_MT_BLOB_IDX, /* "PermissionSet" }, */
199 MONO_MT_END,
201 #define EVENTMAP_SCHEMA_OFFSET DECL_SEC_SCHEMA_OFFSET + 4
202 MONO_MT_TABLE_IDX, /* "Parent:TypeDef" }, */
203 MONO_MT_TABLE_IDX, /* "EventList:Event" }, */
204 MONO_MT_END,
206 #define EVENT_SCHEMA_OFFSET EVENTMAP_SCHEMA_OFFSET + 3
207 MONO_MT_UINT16, /* "EventFlags#EventAttribute" }, */
208 MONO_MT_STRING_IDX, /* "Name" }, */
209 MONO_MT_TDOR_IDX, /* "EventType" }, TypeDef or TypeRef or TypeSpec */
210 MONO_MT_END,
212 #define EVENT_POINTER_SCHEMA_OFFSET EVENT_SCHEMA_OFFSET + 4
213 MONO_MT_TABLE_IDX, /* "Event" }, */
214 MONO_MT_END,
216 #define EXPORTED_TYPE_SCHEMA_OFFSET EVENT_POINTER_SCHEMA_OFFSET + 2
217 MONO_MT_UINT32, /* "Flags" }, */
218 MONO_MT_TABLE_IDX, /* "TypeDefId" }, */
219 MONO_MT_STRING_IDX, /* "TypeName" }, */
220 MONO_MT_STRING_IDX, /* "TypeNameSpace" }, */
221 MONO_MT_IMPL_IDX, /* "Implementation" }, */
222 MONO_MT_END,
224 #define FIELD_SCHEMA_OFFSET EXPORTED_TYPE_SCHEMA_OFFSET + 6
225 MONO_MT_UINT16, /* "Flags" }, */
226 MONO_MT_STRING_IDX, /* "Name" }, */
227 MONO_MT_BLOB_IDX, /* "Signature" }, */
228 MONO_MT_END,
230 #define FIELD_LAYOUT_SCHEMA_OFFSET FIELD_SCHEMA_OFFSET + 4
231 MONO_MT_UINT32, /* "Offset" }, */
232 MONO_MT_TABLE_IDX, /* "Field:Field" }, */
233 MONO_MT_END,
235 #define FIELD_MARSHAL_SCHEMA_OFFSET FIELD_LAYOUT_SCHEMA_OFFSET + 3
236 MONO_MT_HFM_IDX, /* "Parent" }, */
237 MONO_MT_BLOB_IDX, /* "NativeType" }, */
238 MONO_MT_END,
240 #define FIELD_RVA_SCHEMA_OFFSET FIELD_MARSHAL_SCHEMA_OFFSET + 3
241 MONO_MT_UINT32, /* "RVA" }, */
242 MONO_MT_TABLE_IDX, /* "Field:Field" }, */
243 MONO_MT_END,
245 #define FIELD_POINTER_SCHEMA_OFFSET FIELD_RVA_SCHEMA_OFFSET + 3
246 MONO_MT_TABLE_IDX, /* "Field" }, */
247 MONO_MT_END,
249 #define FILE_SCHEMA_OFFSET FIELD_POINTER_SCHEMA_OFFSET + 2
250 MONO_MT_UINT32, /* "Flags" }, */
251 MONO_MT_STRING_IDX, /* "Name" }, */
252 MONO_MT_BLOB_IDX, /* "Value" }, */
253 MONO_MT_END,
255 #define IMPLMAP_SCHEMA_OFFSET FILE_SCHEMA_OFFSET + 4
256 MONO_MT_UINT16, /* "MappingFlag" }, */
257 MONO_MT_MF_IDX, /* "MemberForwarded" }, */
258 MONO_MT_STRING_IDX, /* "ImportName" }, */
259 MONO_MT_TABLE_IDX, /* "ImportScope:ModuleRef" }, */
260 MONO_MT_END,
262 #define IFACEMAP_SCHEMA_OFFSET IMPLMAP_SCHEMA_OFFSET + 5
263 MONO_MT_TABLE_IDX, /* "Class:TypeDef" }, */
264 MONO_MT_TDOR_IDX, /* "Interface=TypeDefOrRef" }, */
265 MONO_MT_END,
267 #define MANIFEST_SCHEMA_OFFSET IFACEMAP_SCHEMA_OFFSET + 3
268 MONO_MT_UINT32, /* "Offset" }, */
269 MONO_MT_UINT32, /* "Flags" }, */
270 MONO_MT_STRING_IDX, /* "Name" }, */
271 MONO_MT_IMPL_IDX, /* "Implementation" }, */
272 MONO_MT_END,
274 #define MEMBERREF_SCHEMA_OFFSET MANIFEST_SCHEMA_OFFSET + 5
275 MONO_MT_MRP_IDX, /* "Class" }, */
276 MONO_MT_STRING_IDX, /* "Name" }, */
277 MONO_MT_BLOB_IDX, /* "Signature" }, */
278 MONO_MT_END,
280 #define METHOD_SCHEMA_OFFSET MEMBERREF_SCHEMA_OFFSET + 4
281 MONO_MT_UINT32, /* "RVA" }, */
282 MONO_MT_UINT16, /* "ImplFlags#MethodImplAttributes" }, */
283 MONO_MT_UINT16, /* "Flags#MethodAttribute" }, */
284 MONO_MT_STRING_IDX, /* "Name" }, */
285 MONO_MT_BLOB_IDX, /* "Signature" }, */
286 MONO_MT_TABLE_IDX, /* "ParamList:Param" }, */
287 MONO_MT_END,
289 #define METHOD_IMPL_SCHEMA_OFFSET METHOD_SCHEMA_OFFSET + 7
290 MONO_MT_TABLE_IDX, /* "Class:TypeDef" }, */
291 MONO_MT_MDOR_IDX, /* "MethodBody" }, */
292 MONO_MT_MDOR_IDX, /* "MethodDeclaration" }, */
293 MONO_MT_END,
295 #define METHOD_SEMA_SCHEMA_OFFSET METHOD_IMPL_SCHEMA_OFFSET + 4
296 MONO_MT_UINT16, /* "MethodSemantic" }, */
297 MONO_MT_TABLE_IDX, /* "Method:Method" }, */
298 MONO_MT_HS_IDX, /* "Association" }, */
299 MONO_MT_END,
301 #define METHOD_POINTER_SCHEMA_OFFSET METHOD_SEMA_SCHEMA_OFFSET + 4
302 MONO_MT_TABLE_IDX, /* "Method" }, */
303 MONO_MT_END,
305 #define MODULE_SCHEMA_OFFSET METHOD_POINTER_SCHEMA_OFFSET + 2
306 MONO_MT_UINT16, /* "Generation" }, */
307 MONO_MT_STRING_IDX, /* "Name" }, */
308 MONO_MT_GUID_IDX, /* "MVID" }, */
309 MONO_MT_GUID_IDX, /* "EncID" }, */
310 MONO_MT_GUID_IDX, /* "EncBaseID" }, */
311 MONO_MT_END,
313 #define MODULEREF_SCHEMA_OFFSET MODULE_SCHEMA_OFFSET + 6
314 MONO_MT_STRING_IDX, /* "Name" }, */
315 MONO_MT_END,
317 #define NESTED_CLASS_SCHEMA_OFFSET MODULEREF_SCHEMA_OFFSET + 2
318 MONO_MT_TABLE_IDX, /* "NestedClass:TypeDef" }, */
319 MONO_MT_TABLE_IDX, /* "EnclosingClass:TypeDef" }, */
320 MONO_MT_END,
322 #define PARAM_SCHEMA_OFFSET NESTED_CLASS_SCHEMA_OFFSET + 3
323 MONO_MT_UINT16, /* "Flags" }, */
324 MONO_MT_UINT16, /* "Sequence" }, */
325 MONO_MT_STRING_IDX, /* "Name" }, */
326 MONO_MT_END,
328 #define PARAM_POINTER_SCHEMA_OFFSET PARAM_SCHEMA_OFFSET + 4
329 MONO_MT_TABLE_IDX, /* "Param" }, */
330 MONO_MT_END,
332 #define PROPERTY_SCHEMA_OFFSET PARAM_POINTER_SCHEMA_OFFSET + 2
333 MONO_MT_UINT16, /* "Flags" }, */
334 MONO_MT_STRING_IDX, /* "Name" }, */
335 MONO_MT_BLOB_IDX, /* "Type" }, */
336 MONO_MT_END,
338 #define PROPERTY_POINTER_SCHEMA_OFFSET PROPERTY_SCHEMA_OFFSET + 4
339 MONO_MT_TABLE_IDX, /* "Property" }, */
340 MONO_MT_END,
342 #define PROPERTY_MAP_SCHEMA_OFFSET PROPERTY_POINTER_SCHEMA_OFFSET + 2
343 MONO_MT_TABLE_IDX, /* "Parent:TypeDef" }, */
344 MONO_MT_TABLE_IDX, /* "PropertyList:Property" }, */
345 MONO_MT_END,
347 #define STDALON_SIG_SCHEMA_OFFSET PROPERTY_MAP_SCHEMA_OFFSET + 3
348 MONO_MT_BLOB_IDX, /* "Signature" }, */
349 MONO_MT_END,
351 #define TYPEDEF_SCHEMA_OFFSET STDALON_SIG_SCHEMA_OFFSET + 2
352 MONO_MT_UINT32, /* "Flags" }, */
353 MONO_MT_STRING_IDX, /* "Name" }, */
354 MONO_MT_STRING_IDX, /* "Namespace" }, */
355 MONO_MT_TDOR_IDX, /* "Extends" }, */
356 MONO_MT_TABLE_IDX, /* "FieldList:Field" }, */
357 MONO_MT_TABLE_IDX, /* "MethodList:Method" }, */
358 MONO_MT_END,
360 #define TYPEREF_SCHEMA_OFFSET TYPEDEF_SCHEMA_OFFSET + 7
361 MONO_MT_RS_IDX, /* "ResolutionScope=ResolutionScope" }, */
362 MONO_MT_STRING_IDX, /* "Name" }, */
363 MONO_MT_STRING_IDX, /* "Namespace" }, */
364 MONO_MT_END,
366 #define TYPESPEC_SCHEMA_OFFSET TYPEREF_SCHEMA_OFFSET + 4
367 MONO_MT_BLOB_IDX, /* "Signature" }, */
368 MONO_MT_END,
370 #define GENPARAM_SCHEMA_OFFSET TYPESPEC_SCHEMA_OFFSET + 2
371 MONO_MT_UINT16, /* "Number" }, */
372 MONO_MT_UINT16, /* "Flags" }, */
373 MONO_MT_TABLE_IDX, /* "Owner" }, TypeDef or MethodDef */
374 MONO_MT_STRING_IDX, /* "Name" }, */
375 MONO_MT_END,
377 #define METHOD_SPEC_SCHEMA_OFFSET GENPARAM_SCHEMA_OFFSET + 5
378 MONO_MT_MDOR_IDX, /* "Method" }, */
379 MONO_MT_BLOB_IDX, /* "Signature" }, */
380 MONO_MT_END,
382 #define GEN_CONSTRAINT_SCHEMA_OFFSET METHOD_SPEC_SCHEMA_OFFSET + 3
383 MONO_MT_TABLE_IDX, /* "GenericParam" }, */
384 MONO_MT_TDOR_IDX, /* "Constraint" }, */
385 MONO_MT_END,
387 #define DOCUMENT_SCHEMA_OFFSET GEN_CONSTRAINT_SCHEMA_OFFSET + 3
388 MONO_MT_BLOB_IDX, /* Name */
389 MONO_MT_GUID_IDX, /* HashAlgorithm */
390 MONO_MT_BLOB_IDX, /* Hash */
391 MONO_MT_GUID_IDX, /* Language */
392 MONO_MT_END,
394 #define METHODBODY_SCHEMA_OFFSET DOCUMENT_SCHEMA_OFFSET + 5
395 MONO_MT_TABLE_IDX, /* Document */
396 MONO_MT_BLOB_IDX, /* SequencePoints */
397 MONO_MT_END,
399 #define LOCALSCOPE_SCHEMA_OFFSET METHODBODY_SCHEMA_OFFSET + 3
400 MONO_MT_TABLE_IDX, /* Method */
401 MONO_MT_TABLE_IDX, /* ImportScope */
402 MONO_MT_TABLE_IDX, /* VariableList */
403 MONO_MT_TABLE_IDX, /* ConstantList */
404 MONO_MT_UINT32, /* StartOffset */
405 MONO_MT_UINT32, /* Length */
406 MONO_MT_END,
408 #define LOCALVARIABLE_SCHEMA_OFFSET LOCALSCOPE_SCHEMA_OFFSET + 7
409 MONO_MT_UINT16, /* Attributes */
410 MONO_MT_UINT16, /* Index */
411 MONO_MT_STRING_IDX, /* Name */
412 MONO_MT_END,
414 #define LOCALCONSTANT_SCHEMA_OFFSET LOCALVARIABLE_SCHEMA_OFFSET + 4
415 MONO_MT_STRING_IDX, /* Name (String heap index) */
416 MONO_MT_BLOB_IDX, /* Signature (Blob heap index, LocalConstantSig blob) */
417 MONO_MT_END,
419 #define IMPORTSCOPE_SCHEMA_OFFSET LOCALCONSTANT_SCHEMA_OFFSET + 3
420 MONO_MT_TABLE_IDX, /* Parent (ImportScope row id or nil) */
421 MONO_MT_BLOB_IDX, /* Imports (Blob index, encoding: Imports blob) */
422 MONO_MT_END,
424 #define ASYNCMETHOD_SCHEMA_OFFSET IMPORTSCOPE_SCHEMA_OFFSET + 3
425 MONO_MT_TABLE_IDX, /* MoveNextMethod (MethodDef row id) */
426 MONO_MT_TABLE_IDX, /* KickoffMethod (MethodDef row id) */
427 MONO_MT_END,
429 #define CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET ASYNCMETHOD_SCHEMA_OFFSET + 3
430 MONO_MT_HASCUSTDEBUG_IDX, /* Parent (HasCustomDebugInformation coded index) */
431 MONO_MT_GUID_IDX, /* Kind (Guid heap index) */
432 MONO_MT_BLOB_IDX, /* Value (Blob heap index) */
433 MONO_MT_END,
435 #define NULL_SCHEMA_OFFSET CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET + 4
436 MONO_MT_END
439 /* Must be the same order as MONO_TABLE_* */
440 const static unsigned char
441 table_description [] = {
442 MODULE_SCHEMA_OFFSET,
443 TYPEREF_SCHEMA_OFFSET,
444 TYPEDEF_SCHEMA_OFFSET,
445 FIELD_POINTER_SCHEMA_OFFSET,
446 FIELD_SCHEMA_OFFSET,
447 METHOD_POINTER_SCHEMA_OFFSET,
448 METHOD_SCHEMA_OFFSET,
449 PARAM_POINTER_SCHEMA_OFFSET,
450 PARAM_SCHEMA_OFFSET,
451 IFACEMAP_SCHEMA_OFFSET,
452 MEMBERREF_SCHEMA_OFFSET, /* 0xa */
453 CONSTANT_SCHEMA_OFFSET,
454 CUSTOM_ATTR_SCHEMA_OFFSET,
455 FIELD_MARSHAL_SCHEMA_OFFSET,
456 DECL_SEC_SCHEMA_OFFSET,
457 CLASS_LAYOUT_SCHEMA_OFFSET,
458 FIELD_LAYOUT_SCHEMA_OFFSET, /* 0x10 */
459 STDALON_SIG_SCHEMA_OFFSET,
460 EVENTMAP_SCHEMA_OFFSET,
461 EVENT_POINTER_SCHEMA_OFFSET,
462 EVENT_SCHEMA_OFFSET,
463 PROPERTY_MAP_SCHEMA_OFFSET,
464 PROPERTY_POINTER_SCHEMA_OFFSET,
465 PROPERTY_SCHEMA_OFFSET,
466 METHOD_SEMA_SCHEMA_OFFSET,
467 METHOD_IMPL_SCHEMA_OFFSET,
468 MODULEREF_SCHEMA_OFFSET, /* 0x1a */
469 TYPESPEC_SCHEMA_OFFSET,
470 IMPLMAP_SCHEMA_OFFSET,
471 FIELD_RVA_SCHEMA_OFFSET,
472 NULL_SCHEMA_OFFSET,
473 NULL_SCHEMA_OFFSET,
474 ASSEMBLY_SCHEMA_OFFSET, /* 0x20 */
475 ASSEMBLYPROC_SCHEMA_OFFSET,
476 ASSEMBLYOS_SCHEMA_OFFSET,
477 ASSEMBLYREF_SCHEMA_OFFSET,
478 ASSEMBLYREFPROC_SCHEMA_OFFSET,
479 ASSEMBLYREFOS_SCHEMA_OFFSET,
480 FILE_SCHEMA_OFFSET,
481 EXPORTED_TYPE_SCHEMA_OFFSET,
482 MANIFEST_SCHEMA_OFFSET,
483 NESTED_CLASS_SCHEMA_OFFSET,
484 GENPARAM_SCHEMA_OFFSET, /* 0x2a */
485 METHOD_SPEC_SCHEMA_OFFSET,
486 GEN_CONSTRAINT_SCHEMA_OFFSET,
487 NULL_SCHEMA_OFFSET,
488 NULL_SCHEMA_OFFSET,
489 NULL_SCHEMA_OFFSET,
490 DOCUMENT_SCHEMA_OFFSET, /* 0x30 */
491 METHODBODY_SCHEMA_OFFSET,
492 LOCALSCOPE_SCHEMA_OFFSET,
493 LOCALVARIABLE_SCHEMA_OFFSET,
494 LOCALCONSTANT_SCHEMA_OFFSET,
495 IMPORTSCOPE_SCHEMA_OFFSET,
496 ASYNCMETHOD_SCHEMA_OFFSET,
497 CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET
500 // This, instead of an array of pointers, to optimize away a pointer and a relocation per string.
501 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
502 #define MSGSTRFIELD1(line) str##line
503 static const struct msgstr_t {
504 #define TABLEDEF(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
505 #include "mono/cil/tables.def"
506 #undef TABLEDEF
507 } tablestr = {
508 #define TABLEDEF(a,b) b,
509 #include "mono/cil/tables.def"
510 #undef TABLEDEF
512 static const gint16 tableidx [] = {
513 #define TABLEDEF(a,b) offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
514 #include "mono/cil/tables.def"
515 #undef TABLEDEF
518 /* If TRUE (but also see DISABLE_STICT_STRONG_NAMES #define), Mono will check
519 * that the public key token, culture and version of a candidate assembly matches
520 * the requested strong name. If FALSE, as long as the name matches, the candidate
521 * will be allowed.
523 static gboolean check_strong_names_strictly = FALSE;
525 // Amount initially reserved in each imageset's mempool.
526 // FIXME: This number is arbitrary, a more practical number should be found
527 #define INITIAL_IMAGE_SET_SIZE 1024
530 * mono_meta_table_name:
531 * \param table table index
533 * Returns the name of the given ECMA metadata logical format table
534 * as described in ECMA 335, Partition II, Section 22.
536 * \returns the name for the \p table index
538 const char *
539 mono_meta_table_name (int table)
541 if ((table < 0) || (table > MONO_TABLE_LAST))
542 return "";
544 return (const char*)&tablestr + tableidx [table];
547 /* The guy who wrote the spec for this should not be allowed near a
548 * computer again.
550 If e is a coded token(see clause 23.1.7) that points into table ti out of n possible tables t0, .. tn-1,
551 then it is stored as e << (log n) & tag{ t0, .. tn-1}[ ti] using 2 bytes if the maximum number of
552 rows of tables t0, ..tn-1, is less than 2^16 - (log n), and using 4 bytes otherwise. The family of
553 finite maps tag{ t0, ..tn-1} is defined below. Note that to decode a physical row, you need the
554 inverse of this mapping.
557 #define rtsize(meta,s,b) (((s) < (1 << (b)) ? 2 : 4))
559 static inline int
560 idx_size (MonoImage *meta, int idx)
562 if (meta->referenced_tables && (meta->referenced_tables & ((guint64)1 << idx)))
563 return meta->referenced_table_rows [idx] < 65536 ? 2 : 4;
564 else
565 return meta->tables [idx].rows < 65536 ? 2 : 4;
568 static inline int
569 get_nrows (MonoImage *meta, int idx)
571 if (meta->referenced_tables && (meta->referenced_tables & ((guint64)1 << idx)))
572 return meta->referenced_table_rows [idx];
573 else
574 return meta->tables [idx].rows;
577 /* Reference: Partition II - 23.2.6 */
579 * mono_metadata_compute_size:
580 * \param meta metadata context
581 * \param tableindex metadata table number
582 * \param result_bitfield pointer to \c guint32 where to store additional info
584 * \c mono_metadata_compute_size computes the length in bytes of a single
585 * row in a metadata table. The size of each column is encoded in the
586 * \p result_bitfield return value along with the number of columns in the table.
587 * the resulting bitfield should be handed to the \c mono_metadata_table_size
588 * and \c mono_metadata_table_count macros.
589 * This is a Mono runtime internal only function.
592 mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bitfield)
594 guint32 bitfield = 0;
595 int size = 0, field_size = 0;
596 int i, n, code;
597 int shift = 0;
598 const unsigned char *description = TableSchemas + table_description [tableindex];
600 for (i = 0; (code = description [i]) != MONO_MT_END; i++){
601 switch (code){
602 case MONO_MT_UINT32:
603 field_size = 4; break;
605 case MONO_MT_UINT16:
606 field_size = 2; break;
608 case MONO_MT_UINT8:
609 field_size = 1; break;
611 case MONO_MT_BLOB_IDX:
612 field_size = meta->idx_blob_wide ? 4 : 2; break;
614 case MONO_MT_STRING_IDX:
615 field_size = meta->idx_string_wide ? 4 : 2; break;
617 case MONO_MT_GUID_IDX:
618 field_size = meta->idx_guid_wide ? 4 : 2; break;
620 case MONO_MT_TABLE_IDX:
621 /* Uhm, a table index can point to other tables besides the current one
622 * so, it's not correct to use the rowcount of the current table to
623 * get the size for this column - lupus
625 switch (tableindex) {
626 case MONO_TABLE_ASSEMBLYREFOS:
627 g_assert (i == 3);
628 field_size = idx_size (meta, MONO_TABLE_ASSEMBLYREF); break;
629 case MONO_TABLE_ASSEMBLYREFPROCESSOR:
630 g_assert (i == 1);
631 field_size = idx_size (meta, MONO_TABLE_ASSEMBLYREF); break;
632 case MONO_TABLE_CLASSLAYOUT:
633 g_assert (i == 2);
634 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
635 case MONO_TABLE_EVENTMAP:
636 g_assert (i == 0 || i == 1);
637 field_size = i ? idx_size (meta, MONO_TABLE_EVENT):
638 idx_size (meta, MONO_TABLE_TYPEDEF);
639 break;
640 case MONO_TABLE_EVENT_POINTER:
641 g_assert (i == 0);
642 field_size = idx_size (meta, MONO_TABLE_EVENT); break;
643 case MONO_TABLE_EXPORTEDTYPE:
644 g_assert (i == 1);
645 /* the index is in another metadata file, so it must be 4 */
646 field_size = 4; break;
647 case MONO_TABLE_FIELDLAYOUT:
648 g_assert (i == 1);
649 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
650 case MONO_TABLE_FIELDRVA:
651 g_assert (i == 1);
652 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
653 case MONO_TABLE_FIELD_POINTER:
654 g_assert (i == 0);
655 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
656 case MONO_TABLE_IMPLMAP:
657 g_assert (i == 3);
658 field_size = idx_size (meta, MONO_TABLE_MODULEREF); break;
659 case MONO_TABLE_INTERFACEIMPL:
660 g_assert (i == 0);
661 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
662 case MONO_TABLE_METHOD:
663 g_assert (i == 5);
664 field_size = idx_size (meta, MONO_TABLE_PARAM); break;
665 case MONO_TABLE_METHODIMPL:
666 g_assert (i == 0);
667 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
668 case MONO_TABLE_METHODSEMANTICS:
669 g_assert (i == 1);
670 field_size = idx_size (meta, MONO_TABLE_METHOD); break;
671 case MONO_TABLE_METHOD_POINTER:
672 g_assert (i == 0);
673 field_size = idx_size (meta, MONO_TABLE_METHOD); break;
674 case MONO_TABLE_NESTEDCLASS:
675 g_assert (i == 0 || i == 1);
676 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
677 case MONO_TABLE_PARAM_POINTER:
678 g_assert (i == 0);
679 field_size = idx_size (meta, MONO_TABLE_PARAM); break;
680 case MONO_TABLE_PROPERTYMAP:
681 g_assert (i == 0 || i == 1);
682 field_size = i ? idx_size (meta, MONO_TABLE_PROPERTY):
683 idx_size (meta, MONO_TABLE_TYPEDEF);
684 break;
685 case MONO_TABLE_PROPERTY_POINTER:
686 g_assert (i == 0);
687 field_size = idx_size (meta, MONO_TABLE_PROPERTY); break;
688 case MONO_TABLE_TYPEDEF:
689 g_assert (i == 4 || i == 5);
690 field_size = i == 4 ? idx_size (meta, MONO_TABLE_FIELD):
691 idx_size (meta, MONO_TABLE_METHOD);
692 break;
693 case MONO_TABLE_GENERICPARAM:
694 g_assert (i == 2);
695 n = MAX (get_nrows (meta, MONO_TABLE_METHOD), get_nrows (meta, MONO_TABLE_TYPEDEF));
696 /*This is a coded token for 2 tables, so takes 1 bit */
697 field_size = rtsize (meta, n, 16 - MONO_TYPEORMETHOD_BITS);
698 break;
699 case MONO_TABLE_GENERICPARAMCONSTRAINT:
700 g_assert (i == 0);
701 field_size = idx_size (meta, MONO_TABLE_GENERICPARAM);
702 break;
703 case MONO_TABLE_LOCALSCOPE:
704 switch (i) {
705 case 0:
706 // FIXME: This table is in another file
707 field_size = idx_size (meta, MONO_TABLE_METHOD);
708 break;
709 case 1:
710 field_size = idx_size (meta, MONO_TABLE_IMPORTSCOPE);
711 break;
712 case 2:
713 field_size = idx_size (meta, MONO_TABLE_LOCALVARIABLE);
714 break;
715 case 3:
716 field_size = idx_size (meta, MONO_TABLE_LOCALCONSTANT);
717 break;
718 default:
719 g_assert_not_reached ();
720 break;
722 break;
723 case MONO_TABLE_METHODBODY:
724 g_assert (i == 0);
725 field_size = idx_size (meta, MONO_TABLE_DOCUMENT); break;
726 case MONO_TABLE_IMPORTSCOPE:
727 g_assert(i == 0);
728 field_size = idx_size (meta, MONO_TABLE_IMPORTSCOPE); break;
729 case MONO_TABLE_STATEMACHINEMETHOD:
730 g_assert(i == 0 || i == 1);
731 field_size = idx_size(meta, MONO_TABLE_METHOD); break;
732 default:
733 g_error ("Can't handle MONO_MT_TABLE_IDX for table %d element %d", tableindex, i);
735 break;
738 * HasConstant: ParamDef, FieldDef, Property
740 case MONO_MT_CONST_IDX:
741 n = MAX (get_nrows (meta, MONO_TABLE_PARAM),
742 get_nrows (meta, MONO_TABLE_FIELD));
743 n = MAX (n, get_nrows (meta, MONO_TABLE_PROPERTY));
745 /* 2 bits to encode tag */
746 field_size = rtsize (meta, n, 16-2);
747 break;
750 * HasCustomAttribute: points to any table but
751 * itself.
753 case MONO_MT_HASCAT_IDX:
755 * We believe that since the signature and
756 * permission are indexing the Blob heap,
757 * we should consider the blob size first
759 /* I'm not a believer - lupus
760 if (meta->idx_blob_wide){
761 field_size = 4;
762 break;
765 n = MAX (get_nrows (meta, MONO_TABLE_METHOD),
766 get_nrows (meta, MONO_TABLE_FIELD));
767 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPEREF));
768 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPEDEF));
769 n = MAX (n, get_nrows (meta, MONO_TABLE_PARAM));
770 n = MAX (n, get_nrows (meta, MONO_TABLE_INTERFACEIMPL));
771 n = MAX (n, get_nrows (meta, MONO_TABLE_MEMBERREF));
772 n = MAX (n, get_nrows (meta, MONO_TABLE_MODULE));
773 n = MAX (n, get_nrows (meta, MONO_TABLE_DECLSECURITY));
774 n = MAX (n, get_nrows (meta, MONO_TABLE_PROPERTY));
775 n = MAX (n, get_nrows (meta, MONO_TABLE_EVENT));
776 n = MAX (n, get_nrows (meta, MONO_TABLE_STANDALONESIG));
777 n = MAX (n, get_nrows (meta, MONO_TABLE_MODULEREF));
778 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPESPEC));
779 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLY));
780 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
781 n = MAX (n, get_nrows (meta, MONO_TABLE_FILE));
782 n = MAX (n, get_nrows (meta, MONO_TABLE_EXPORTEDTYPE));
783 n = MAX (n, get_nrows (meta, MONO_TABLE_MANIFESTRESOURCE));
784 n = MAX (n, get_nrows (meta, MONO_TABLE_GENERICPARAM));
785 n = MAX (n, get_nrows (meta, MONO_TABLE_GENERICPARAMCONSTRAINT));
786 n = MAX (n, get_nrows (meta, MONO_TABLE_METHODSPEC));
788 /* 5 bits to encode */
789 field_size = rtsize (meta, n, 16-5);
790 break;
793 * HasCustomAttribute: points to any table but
794 * itself.
797 case MONO_MT_HASCUSTDEBUG_IDX:
798 n = MAX(get_nrows (meta, MONO_TABLE_METHOD),
799 get_nrows (meta, MONO_TABLE_FIELD));
800 n = MAX(n, get_nrows (meta, MONO_TABLE_TYPEREF));
801 n = MAX(n, get_nrows (meta, MONO_TABLE_TYPEDEF));
802 n = MAX(n, get_nrows (meta, MONO_TABLE_PARAM));
803 n = MAX(n, get_nrows (meta, MONO_TABLE_INTERFACEIMPL));
804 n = MAX(n, get_nrows (meta, MONO_TABLE_MEMBERREF));
805 n = MAX(n, get_nrows (meta, MONO_TABLE_MODULE));
806 n = MAX(n, get_nrows (meta, MONO_TABLE_DECLSECURITY));
807 n = MAX(n, get_nrows (meta, MONO_TABLE_PROPERTY));
808 n = MAX(n, get_nrows (meta, MONO_TABLE_EVENT));
809 n = MAX(n, get_nrows (meta, MONO_TABLE_STANDALONESIG));
810 n = MAX(n, get_nrows (meta, MONO_TABLE_MODULEREF));
811 n = MAX(n, get_nrows (meta, MONO_TABLE_TYPESPEC));
812 n = MAX(n, get_nrows (meta, MONO_TABLE_ASSEMBLY));
813 n = MAX(n, get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
814 n = MAX(n, get_nrows (meta, MONO_TABLE_FILE));
815 n = MAX(n, get_nrows (meta, MONO_TABLE_EXPORTEDTYPE));
816 n = MAX(n, get_nrows (meta, MONO_TABLE_MANIFESTRESOURCE));
817 n = MAX(n, get_nrows (meta, MONO_TABLE_GENERICPARAM));
818 n = MAX(n, get_nrows (meta, MONO_TABLE_GENERICPARAMCONSTRAINT));
819 n = MAX(n, get_nrows (meta, MONO_TABLE_METHODSPEC));
820 n = MAX(n, get_nrows (meta, MONO_TABLE_DOCUMENT));
821 n = MAX(n, get_nrows (meta, MONO_TABLE_LOCALSCOPE));
822 n = MAX(n, get_nrows (meta, MONO_TABLE_LOCALVARIABLE));
823 n = MAX(n, get_nrows (meta, MONO_TABLE_LOCALCONSTANT));
824 n = MAX(n, get_nrows (meta, MONO_TABLE_IMPORTSCOPE));
826 /* 5 bits to encode */
827 field_size = rtsize(meta, n, 16 - 5);
828 break;
831 * CustomAttributeType: MethodDef, MemberRef.
833 case MONO_MT_CAT_IDX:
834 n = MAX (get_nrows (meta, MONO_TABLE_METHOD),
835 get_nrows (meta, MONO_TABLE_MEMBERREF));
837 /* 3 bits to encode */
838 field_size = rtsize (meta, n, 16-3);
839 break;
842 * HasDeclSecurity: Typedef, MethodDef, Assembly
844 case MONO_MT_HASDEC_IDX:
845 n = MAX (get_nrows (meta, MONO_TABLE_TYPEDEF),
846 get_nrows (meta, MONO_TABLE_METHOD));
847 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLY));
849 /* 2 bits to encode */
850 field_size = rtsize (meta, n, 16-2);
851 break;
854 * Implementation: File, AssemblyRef, ExportedType
856 case MONO_MT_IMPL_IDX:
857 n = MAX (get_nrows (meta, MONO_TABLE_FILE),
858 get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
859 n = MAX (n, get_nrows (meta, MONO_TABLE_EXPORTEDTYPE));
861 /* 2 bits to encode tag */
862 field_size = rtsize (meta, n, 16-2);
863 break;
866 * HasFieldMarshall: FieldDef, ParamDef
868 case MONO_MT_HFM_IDX:
869 n = MAX (get_nrows (meta, MONO_TABLE_FIELD),
870 get_nrows (meta, MONO_TABLE_PARAM));
872 /* 1 bit used to encode tag */
873 field_size = rtsize (meta, n, 16-1);
874 break;
877 * MemberForwarded: FieldDef, MethodDef
879 case MONO_MT_MF_IDX:
880 n = MAX (get_nrows (meta, MONO_TABLE_FIELD),
881 get_nrows (meta, MONO_TABLE_METHOD));
883 /* 1 bit used to encode tag */
884 field_size = rtsize (meta, n, 16-1);
885 break;
888 * TypeDefOrRef: TypeDef, ParamDef, TypeSpec
889 * LAMESPEC
890 * It is TypeDef, _TypeRef_, TypeSpec, instead.
892 case MONO_MT_TDOR_IDX:
893 n = MAX (get_nrows (meta, MONO_TABLE_TYPEDEF),
894 get_nrows (meta, MONO_TABLE_TYPEREF));
895 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPESPEC));
897 /* 2 bits to encode */
898 field_size = rtsize (meta, n, 16-2);
899 break;
902 * MemberRefParent: TypeDef, TypeRef, MethodDef, ModuleRef, TypeSpec, MemberRef
904 case MONO_MT_MRP_IDX:
905 n = MAX (get_nrows (meta, MONO_TABLE_TYPEDEF),
906 get_nrows (meta, MONO_TABLE_TYPEREF));
907 n = MAX (n, get_nrows (meta, MONO_TABLE_METHOD));
908 n = MAX (n, get_nrows (meta, MONO_TABLE_MODULEREF));
909 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPESPEC));
911 /* 3 bits to encode */
912 field_size = rtsize (meta, n, 16 - 3);
913 break;
916 * MethodDefOrRef: MethodDef, MemberRef
918 case MONO_MT_MDOR_IDX:
919 n = MAX (get_nrows (meta, MONO_TABLE_METHOD),
920 get_nrows (meta, MONO_TABLE_MEMBERREF));
922 /* 1 bit used to encode tag */
923 field_size = rtsize (meta, n, 16-1);
924 break;
927 * HasSemantics: Property, Event
929 case MONO_MT_HS_IDX:
930 n = MAX (get_nrows (meta, MONO_TABLE_PROPERTY),
931 get_nrows (meta, MONO_TABLE_EVENT));
933 /* 1 bit used to encode tag */
934 field_size = rtsize (meta, n, 16-1);
935 break;
938 * ResolutionScope: Module, ModuleRef, AssemblyRef, TypeRef
940 case MONO_MT_RS_IDX:
941 n = MAX (get_nrows (meta, MONO_TABLE_MODULE),
942 get_nrows (meta, MONO_TABLE_MODULEREF));
943 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
944 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPEREF));
946 /* 2 bits used to encode tag (ECMA spec claims 3) */
947 field_size = rtsize (meta, n, 16 - 2);
948 break;
952 * encode field size as follows (we just need to
953 * distinguish them).
955 * 4 -> 3
956 * 2 -> 1
957 * 1 -> 0
959 bitfield |= (field_size-1) << shift;
960 shift += 2;
961 size += field_size;
962 /*g_print ("table %02x field %d size %d\n", tableindex, i, field_size);*/
965 *result_bitfield = (i << 24) | bitfield;
966 return size;
970 * mono_metadata_compute_table_bases:
971 * \param meta metadata context to compute table values
973 * Computes the table bases for the metadata structure.
974 * This is an internal function used by the image loader code.
976 void
977 mono_metadata_compute_table_bases (MonoImage *meta)
979 int i;
980 const char *base = meta->tables_base;
982 for (i = 0; i < MONO_TABLE_NUM; i++) {
983 MonoTableInfo *table = &meta->tables [i];
984 if (table->rows == 0)
985 continue;
987 table->row_size = mono_metadata_compute_size (meta, i, &table->size_bitfield);
988 table->base = base;
989 base += table->rows * table->row_size;
994 * mono_metadata_locate:
995 * \param meta metadata context
996 * \param table table code.
997 * \param idx index of element to retrieve from \p table.
999 * \returns a pointer to the \p idx element in the metadata table
1000 * whose code is \p table.
1002 const char *
1003 mono_metadata_locate (MonoImage *meta, int table, int idx)
1005 /* idx == 0 refers always to NULL */
1006 g_return_val_if_fail (idx > 0 && idx <= meta->tables [table].rows, ""); /*FIXME shouldn't we return NULL here?*/
1008 return meta->tables [table].base + (meta->tables [table].row_size * (idx - 1));
1012 * mono_metadata_locate_token:
1013 * \param meta metadata context
1014 * \param token metadata token
1016 * \returns a pointer to the data in the metadata represented by the
1017 * token \p token .
1019 const char *
1020 mono_metadata_locate_token (MonoImage *meta, guint32 token)
1022 return mono_metadata_locate (meta, token >> 24, token & 0xffffff);
1026 * mono_metadata_string_heap:
1027 * \param meta metadata context
1028 * \param index index into the string heap.
1029 * \returns an in-memory pointer to the \p index in the string heap.
1031 const char *
1032 mono_metadata_string_heap (MonoImage *meta, guint32 index)
1034 g_assert (index < meta->heap_strings.size);
1035 g_return_val_if_fail (index < meta->heap_strings.size, "");
1036 return meta->heap_strings.data + index;
1040 * mono_metadata_string_heap_checked:
1041 * \param meta metadata context
1042 * \param index index into the string heap.
1043 * \param error set on error
1044 * \returns an in-memory pointer to the \p index in the string heap.
1045 * On failure returns NULL and sets \p error.
1047 const char *
1048 mono_metadata_string_heap_checked (MonoImage *meta, guint32 index, MonoError *error)
1050 if (G_UNLIKELY (!(index < meta->heap_strings.size))) {
1051 mono_error_set_bad_image_by_name (error, meta->name ? meta->name : "unknown image", "string heap index %ud out bounds %u", index, meta->heap_strings.size);
1052 return NULL;
1054 return meta->heap_strings.data + index;
1058 * mono_metadata_user_string:
1059 * \param meta metadata context
1060 * \param index index into the user string heap.
1061 * \returns an in-memory pointer to the \p index in the user string heap (<code>#US</code>).
1063 const char *
1064 mono_metadata_user_string (MonoImage *meta, guint32 index)
1066 g_assert (index < meta->heap_us.size);
1067 g_return_val_if_fail (index < meta->heap_us.size, "");
1068 return meta->heap_us.data + index;
1072 * mono_metadata_blob_heap:
1073 * \param meta metadata context
1074 * \param index index into the blob.
1075 * \returns an in-memory pointer to the \p index in the Blob heap.
1077 const char *
1078 mono_metadata_blob_heap (MonoImage *meta, guint32 index)
1080 g_assert (index < meta->heap_blob.size);
1081 g_return_val_if_fail (index < meta->heap_blob.size, "");/*FIXME shouldn't we return NULL and check for index == 0?*/
1082 return meta->heap_blob.data + index;
1086 * mono_metadata_blob_heap_checked:
1087 * \param meta metadata context
1088 * \param index index into the blob.
1089 * \param error set on error
1090 * \returns an in-memory pointer to the \p index in the Blob heap. On failure sets \p error and returns NULL;
1093 const char *
1094 mono_metadata_blob_heap_checked (MonoImage *meta, guint32 index, MonoError *error)
1096 if (G_UNLIKELY (!(index < meta->heap_blob.size))) {
1097 mono_error_set_bad_image_by_name (error, meta->name ? meta->name : "unknown image", "blob heap index %u out of bounds %u", index, meta->heap_blob.size);
1098 return NULL;
1100 return meta->heap_blob.data + index;
1104 * mono_metadata_guid_heap:
1105 * \param meta metadata context
1106 * \param index index into the guid heap.
1107 * \returns an in-memory pointer to the \p index in the guid heap.
1109 const char *
1110 mono_metadata_guid_heap (MonoImage *meta, guint32 index)
1112 --index;
1113 index *= 16; /* adjust for guid size and 1-based index */
1114 g_return_val_if_fail (index < meta->heap_guid.size, "");
1115 return meta->heap_guid.data + index;
1118 static const unsigned char *
1119 dword_align (const unsigned char *ptr)
1121 return (const unsigned char *) (((gsize) (ptr + 3)) & ~3);
1125 * mono_metadata_decode_row:
1126 * \param t table to extract information from.
1127 * \param idx index in table.
1128 * \param res array of \p res_size cols to store the results in
1130 * This decompresses the metadata element \p idx in table \p t
1131 * into the \c guint32 \p res array that has \p res_size elements
1133 void
1134 mono_metadata_decode_row (const MonoTableInfo *t, int idx, guint32 *res, int res_size)
1136 guint32 bitfield = t->size_bitfield;
1137 int i, count = mono_metadata_table_count (bitfield);
1138 const char *data;
1140 g_assert (idx < t->rows);
1141 g_assert (idx >= 0);
1142 data = t->base + idx * t->row_size;
1144 g_assert (res_size == count);
1146 for (i = 0; i < count; i++) {
1147 int n = mono_metadata_table_size (bitfield, i);
1149 switch (n){
1150 case 1:
1151 res [i] = *data; break;
1152 case 2:
1153 res [i] = read16 (data); break;
1154 case 4:
1155 res [i] = read32 (data); break;
1156 default:
1157 g_assert_not_reached ();
1159 data += n;
1164 * mono_metadata_decode_row_checked:
1165 * \param image the \c MonoImage the table belongs to
1166 * \param t table to extract information from.
1167 * \param idx index in the table.
1168 * \param res array of \p res_size cols to store the results in
1169 * \param error set on bounds error
1172 * This decompresses the metadata element \p idx in the table \p t
1173 * into the \c guint32 \p res array that has \p res_size elements.
1175 * \returns TRUE if the read succeeded. Otherwise sets \p error and returns FALSE.
1177 gboolean
1178 mono_metadata_decode_row_checked (const MonoImage *image, const MonoTableInfo *t, int idx, guint32 *res, int res_size, MonoError *error)
1180 guint32 bitfield = t->size_bitfield;
1181 int i, count = mono_metadata_table_count (bitfield);
1183 const char *image_name = image && image->name ? image->name : "unknown image";
1185 if (G_UNLIKELY (! (idx < t->rows && idx >= 0))) {
1186 mono_error_set_bad_image_by_name (error, image_name, "row index %d out of bounds: %d rows", idx, t->rows);
1187 return FALSE;
1189 const char *data = t->base + idx * t->row_size;
1191 if (G_UNLIKELY (res_size != count)) {
1192 mono_error_set_bad_image_by_name (error, image_name, "res_size %d != count %d", res_size, count);
1193 return FALSE;
1196 for (i = 0; i < count; i++) {
1197 int n = mono_metadata_table_size (bitfield, i);
1199 switch (n) {
1200 case 1:
1201 res [i] = *data; break;
1202 case 2:
1203 res [i] = read16 (data); break;
1204 case 4:
1205 res [i] = read32 (data); break;
1206 default:
1207 mono_error_set_bad_image_by_name (error, image_name, "unexpected table [%d] size %d", i, n);
1208 return FALSE;
1210 data += n;
1213 return TRUE;
1217 * mono_metadata_decode_row_col:
1218 * \param t table to extract information from.
1219 * \param idx index for row in table.
1220 * \param col column in the row.
1222 * This function returns the value of column \p col from the \p idx
1223 * row in the table \p t .
1225 guint32
1226 mono_metadata_decode_row_col (const MonoTableInfo *t, int idx, guint col)
1228 guint32 bitfield = t->size_bitfield;
1229 int i;
1230 const char *data;
1231 int n;
1233 g_assert (idx < t->rows);
1234 g_assert (col < mono_metadata_table_count (bitfield));
1235 data = t->base + idx * t->row_size;
1237 n = mono_metadata_table_size (bitfield, 0);
1238 for (i = 0; i < col; ++i) {
1239 data += n;
1240 n = mono_metadata_table_size (bitfield, i + 1);
1242 switch (n) {
1243 case 1:
1244 return *data;
1245 case 2:
1246 return read16 (data);
1247 case 4:
1248 return read32 (data);
1249 default:
1250 g_assert_not_reached ();
1252 return 0;
1256 * mono_metadata_decode_blob_size:
1257 * \param ptr pointer to a blob object
1258 * \param rptr the new position of the pointer
1260 * This decodes a compressed size as described by 24.2.4 (#US and #Blob a blob or user string object)
1262 * \returns the size of the blob object
1264 guint32
1265 mono_metadata_decode_blob_size (const char *xptr, const char **rptr)
1267 const unsigned char *ptr = (const unsigned char *)xptr;
1268 guint32 size;
1270 if ((*ptr & 0x80) == 0){
1271 size = ptr [0] & 0x7f;
1272 ptr++;
1273 } else if ((*ptr & 0x40) == 0){
1274 size = ((ptr [0] & 0x3f) << 8) + ptr [1];
1275 ptr += 2;
1276 } else {
1277 size = ((ptr [0] & 0x1f) << 24) +
1278 (ptr [1] << 16) +
1279 (ptr [2] << 8) +
1280 ptr [3];
1281 ptr += 4;
1283 if (rptr)
1284 *rptr = (char*)ptr;
1285 return size;
1289 * mono_metadata_decode_value:
1290 * \param ptr pointer to decode from
1291 * \param rptr the new position of the pointer
1293 * This routine decompresses 32-bit values as specified in the "Blob and
1294 * Signature" section (23.2)
1296 * \returns the decoded value
1298 guint32
1299 mono_metadata_decode_value (const char *_ptr, const char **rptr)
1301 const unsigned char *ptr = (const unsigned char *) _ptr;
1302 unsigned char b = *ptr;
1303 guint32 len;
1305 if ((b & 0x80) == 0){
1306 len = b;
1307 ++ptr;
1308 } else if ((b & 0x40) == 0){
1309 len = ((b & 0x3f) << 8 | ptr [1]);
1310 ptr += 2;
1311 } else {
1312 len = ((b & 0x1f) << 24) |
1313 (ptr [1] << 16) |
1314 (ptr [2] << 8) |
1315 ptr [3];
1316 ptr += 4;
1318 if (rptr)
1319 *rptr = (char*)ptr;
1321 return len;
1325 * mono_metadata_decode_signed_value:
1326 * \param ptr pointer to decode from
1327 * \param rptr the new position of the pointer
1329 * This routine decompresses 32-bit signed values
1330 * (not specified in the spec)
1332 * \returns the decoded value
1334 gint32
1335 mono_metadata_decode_signed_value (const char *ptr, const char **rptr)
1337 guint32 uval = mono_metadata_decode_value (ptr, rptr);
1338 gint32 ival = uval >> 1;
1339 if (!(uval & 1))
1340 return ival;
1341 /* ival is a truncated 2's complement negative number. */
1342 if (ival < 0x40)
1343 /* 6 bits = 7 bits for compressed representation (top bit is '0') - 1 sign bit */
1344 return ival - 0x40;
1345 if (ival < 0x2000)
1346 /* 13 bits = 14 bits for compressed representation (top bits are '10') - 1 sign bit */
1347 return ival - 0x2000;
1348 if (ival < 0x10000000)
1349 /* 28 bits = 29 bits for compressed representation (top bits are '110') - 1 sign bit */
1350 return ival - 0x10000000;
1351 g_assert (ival < 0x20000000);
1352 g_warning ("compressed signed value appears to use 29 bits for compressed representation: %x (raw: %8x)", ival, uval);
1353 return ival - 0x20000000;
1357 * mono_metadata_translate_token_index:
1358 * Translates the given 1-based index into the \c Method, \c Field, \c Event, or \c Param tables
1359 * using the \c *Ptr tables in uncompressed metadata, if they are available.
1361 * FIXME: The caller is not forced to call this function, which is error-prone, since
1362 * forgetting to call it would only show up as a bug on uncompressed metadata.
1364 guint32
1365 mono_metadata_translate_token_index (MonoImage *image, int table, guint32 idx)
1367 if (!image->uncompressed_metadata)
1368 return idx;
1370 switch (table) {
1371 case MONO_TABLE_METHOD:
1372 if (image->tables [MONO_TABLE_METHOD_POINTER].rows)
1373 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_METHOD_POINTER], idx - 1, MONO_METHOD_POINTER_METHOD);
1374 else
1375 return idx;
1376 case MONO_TABLE_FIELD:
1377 if (image->tables [MONO_TABLE_FIELD_POINTER].rows)
1378 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_FIELD_POINTER], idx - 1, MONO_FIELD_POINTER_FIELD);
1379 else
1380 return idx;
1381 case MONO_TABLE_EVENT:
1382 if (image->tables [MONO_TABLE_EVENT_POINTER].rows)
1383 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_EVENT_POINTER], idx - 1, MONO_EVENT_POINTER_EVENT);
1384 else
1385 return idx;
1386 case MONO_TABLE_PROPERTY:
1387 if (image->tables [MONO_TABLE_PROPERTY_POINTER].rows)
1388 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_PROPERTY_POINTER], idx - 1, MONO_PROPERTY_POINTER_PROPERTY);
1389 else
1390 return idx;
1391 case MONO_TABLE_PARAM:
1392 if (image->tables [MONO_TABLE_PARAM_POINTER].rows)
1393 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_PARAM_POINTER], idx - 1, MONO_PARAM_POINTER_PARAM);
1394 else
1395 return idx;
1396 default:
1397 return idx;
1402 * mono_metadata_decode_table_row:
1404 * Same as \c mono_metadata_decode_row, but takes an \p image + \p table ID pair, and takes
1405 * uncompressed metadata into account, so it should be used to access the
1406 * \c Method, \c Field, \c Param and \c Event tables when the access is made from metadata, i.e.
1407 * \p idx is retrieved from a metadata table, like \c MONO_TYPEDEF_FIELD_LIST.
1409 void
1410 mono_metadata_decode_table_row (MonoImage *image, int table, int idx, guint32 *res, int res_size)
1412 if (image->uncompressed_metadata)
1413 idx = mono_metadata_translate_token_index (image, table, idx + 1) - 1;
1415 mono_metadata_decode_row (&image->tables [table], idx, res, res_size);
1419 * mono_metadata_decode_table_row_col:
1421 * Same as \c mono_metadata_decode_row_col, but takes an \p image + \p table ID pair, and takes
1422 * uncompressed metadata into account, so it should be used to access the
1423 * \c Method, \c Field, \c Param and \c Event tables.
1425 guint32 mono_metadata_decode_table_row_col (MonoImage *image, int table, int idx, guint col)
1427 if (image->uncompressed_metadata)
1428 idx = mono_metadata_translate_token_index (image, table, idx + 1) - 1;
1430 return mono_metadata_decode_row_col (&image->tables [table], idx, col);
1434 * mono_metadata_parse_typedef_or_ref:
1435 * \param m a metadata context.
1436 * \param ptr a pointer to an encoded TypedefOrRef in \p m
1437 * \param rptr pointer updated to match the end of the decoded stream
1438 * \returns a token valid in the \p m metadata decoded from
1439 * the compressed representation.
1441 guint32
1442 mono_metadata_parse_typedef_or_ref (MonoImage *m, const char *ptr, const char **rptr)
1444 guint32 token;
1445 token = mono_metadata_decode_value (ptr, &ptr);
1446 if (rptr)
1447 *rptr = ptr;
1448 return mono_metadata_token_from_dor (token);
1452 * mono_metadata_parse_custom_mod:
1453 * \param m a metadata context.
1454 * \param dest storage where the info about the custom modifier is stored (may be NULL)
1455 * \param ptr a pointer to (possibly) the start of a custom modifier list
1456 * \param rptr pointer updated to match the end of the decoded stream
1458 * Checks if \p ptr points to a type custom modifier compressed representation.
1460 * \returns TRUE if a custom modifier was found, FALSE if not.
1463 mono_metadata_parse_custom_mod (MonoImage *m, MonoCustomMod *dest, const char *ptr, const char **rptr)
1465 MonoCustomMod local;
1466 if ((*ptr == MONO_TYPE_CMOD_OPT) || (*ptr == MONO_TYPE_CMOD_REQD)) {
1467 if (!dest)
1468 dest = &local;
1469 dest->required = *ptr == MONO_TYPE_CMOD_REQD ? 1 : 0;
1470 dest->token = mono_metadata_parse_typedef_or_ref (m, ptr + 1, rptr);
1471 return TRUE;
1473 return FALSE;
1477 * mono_metadata_parse_array_internal:
1478 * @m: a metadata context.
1479 * @transient: whenever to allocate data from the heap
1480 * @ptr: a pointer to an encoded array description.
1481 * @rptr: pointer updated to match the end of the decoded stream
1483 * Decodes the compressed array description found in the metadata @m at @ptr.
1485 * Returns: a #MonoArrayType structure describing the array type
1486 * and dimensions. Memory is allocated from the heap or from the image mempool, depending
1487 * on the value of @transient.
1489 * LOCKING: Acquires the loader lock
1491 static MonoArrayType *
1492 mono_metadata_parse_array_internal (MonoImage *m, MonoGenericContainer *container,
1493 gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1495 int i;
1496 MonoArrayType *array;
1497 MonoType *etype;
1499 etype = mono_metadata_parse_type_checked (m, container, 0, FALSE, ptr, &ptr, error); //FIXME this doesn't respect @transient
1500 if (!etype)
1501 return NULL;
1503 array = transient ? (MonoArrayType *)g_malloc0 (sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (m, sizeof (MonoArrayType));
1504 array->eklass = mono_class_from_mono_type_internal (etype);
1505 array->rank = mono_metadata_decode_value (ptr, &ptr);
1507 array->numsizes = mono_metadata_decode_value (ptr, &ptr);
1508 if (array->numsizes)
1509 array->sizes = transient ? (int *)g_malloc0 (sizeof (int) * array->numsizes) : (int *)mono_image_alloc0 (m, sizeof (int) * array->numsizes);
1510 for (i = 0; i < array->numsizes; ++i)
1511 array->sizes [i] = mono_metadata_decode_value (ptr, &ptr);
1513 array->numlobounds = mono_metadata_decode_value (ptr, &ptr);
1514 if (array->numlobounds)
1515 array->lobounds = transient ? (int *)g_malloc0 (sizeof (int) * array->numlobounds) : (int *)mono_image_alloc0 (m, sizeof (int) * array->numlobounds);
1516 for (i = 0; i < array->numlobounds; ++i)
1517 array->lobounds [i] = mono_metadata_decode_signed_value (ptr, &ptr);
1519 if (rptr)
1520 *rptr = ptr;
1521 return array;
1525 * mono_metadata_parse_array:
1527 MonoArrayType *
1528 mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
1530 ERROR_DECL (error);
1531 MonoArrayType *ret = mono_metadata_parse_array_internal (m, NULL, FALSE, ptr, rptr, error);
1532 mono_error_cleanup (error);
1534 return ret;
1538 * mono_metadata_free_array:
1539 * \param array array description
1541 * Frees the array description returned from \c mono_metadata_parse_array.
1543 void
1544 mono_metadata_free_array (MonoArrayType *array)
1546 g_free (array->sizes);
1547 g_free (array->lobounds);
1548 g_free (array);
1552 * need to add common field and param attributes combinations:
1553 * [out] param
1554 * public static
1555 * public static literal
1556 * private
1557 * private static
1558 * private static literal
1560 static const MonoType
1561 builtin_types[] = {
1562 /* data, attrs, type, nmods, byref, pinned */
1563 {{NULL}, 0, MONO_TYPE_VOID, 0, 0, 0},
1564 {{NULL}, 0, MONO_TYPE_BOOLEAN, 0, 0, 0},
1565 {{NULL}, 0, MONO_TYPE_BOOLEAN, 0, 1, 0},
1566 {{NULL}, 0, MONO_TYPE_CHAR, 0, 0, 0},
1567 {{NULL}, 0, MONO_TYPE_CHAR, 0, 1, 0},
1568 {{NULL}, 0, MONO_TYPE_I1, 0, 0, 0},
1569 {{NULL}, 0, MONO_TYPE_I1, 0, 1, 0},
1570 {{NULL}, 0, MONO_TYPE_U1, 0, 0, 0},
1571 {{NULL}, 0, MONO_TYPE_U1, 0, 1, 0},
1572 {{NULL}, 0, MONO_TYPE_I2, 0, 0, 0},
1573 {{NULL}, 0, MONO_TYPE_I2, 0, 1, 0},
1574 {{NULL}, 0, MONO_TYPE_U2, 0, 0, 0},
1575 {{NULL}, 0, MONO_TYPE_U2, 0, 1, 0},
1576 {{NULL}, 0, MONO_TYPE_I4, 0, 0, 0},
1577 {{NULL}, 0, MONO_TYPE_I4, 0, 1, 0},
1578 {{NULL}, 0, MONO_TYPE_U4, 0, 0, 0},
1579 {{NULL}, 0, MONO_TYPE_U4, 0, 1, 0},
1580 {{NULL}, 0, MONO_TYPE_I8, 0, 0, 0},
1581 {{NULL}, 0, MONO_TYPE_I8, 0, 1, 0},
1582 {{NULL}, 0, MONO_TYPE_U8, 0, 0, 0},
1583 {{NULL}, 0, MONO_TYPE_U8, 0, 1, 0},
1584 {{NULL}, 0, MONO_TYPE_R4, 0, 0, 0},
1585 {{NULL}, 0, MONO_TYPE_R4, 0, 1, 0},
1586 {{NULL}, 0, MONO_TYPE_R8, 0, 0, 0},
1587 {{NULL}, 0, MONO_TYPE_R8, 0, 1, 0},
1588 {{NULL}, 0, MONO_TYPE_STRING, 0, 0, 0},
1589 {{NULL}, 0, MONO_TYPE_STRING, 0, 1, 0},
1590 {{NULL}, 0, MONO_TYPE_OBJECT, 0, 0, 0},
1591 {{NULL}, 0, MONO_TYPE_OBJECT, 0, 1, 0},
1592 {{NULL}, 0, MONO_TYPE_TYPEDBYREF, 0, 0, 0},
1593 {{NULL}, 0, MONO_TYPE_I, 0, 0, 0},
1594 {{NULL}, 0, MONO_TYPE_I, 0, 1, 0},
1595 {{NULL}, 0, MONO_TYPE_U, 0, 0, 0},
1596 {{NULL}, 0, MONO_TYPE_U, 0, 1, 0},
1599 #define NBUILTIN_TYPES() (sizeof (builtin_types) / sizeof (builtin_types [0]))
1601 static GHashTable *type_cache = NULL;
1602 static gint32 next_generic_inst_id = 0;
1604 /* Protected by image_sets_mutex */
1605 static MonoImageSet *mscorlib_image_set;
1606 /* Protected by image_sets_mutex */
1607 static GPtrArray *image_sets;
1608 static mono_mutex_t image_sets_mutex;
1610 static guint mono_generic_class_hash (gconstpointer data);
1613 * MonoTypes with modifies are never cached, so we never check or use that field.
1615 static guint
1616 mono_type_hash (gconstpointer data)
1618 const MonoType *type = (const MonoType *) data;
1619 if (type->type == MONO_TYPE_GENERICINST)
1620 return mono_generic_class_hash (type->data.generic_class);
1621 else
1622 return type->type | (type->byref << 8) | (type->attrs << 9);
1625 static gint
1626 mono_type_equal (gconstpointer ka, gconstpointer kb)
1628 const MonoType *a = (const MonoType *) ka;
1629 const MonoType *b = (const MonoType *) kb;
1631 if (a->type != b->type || a->byref != b->byref || a->attrs != b->attrs || a->pinned != b->pinned)
1632 return 0;
1633 /* need other checks */
1634 return 1;
1637 guint
1638 mono_metadata_generic_inst_hash (gconstpointer data)
1640 const MonoGenericInst *ginst = (const MonoGenericInst *) data;
1641 guint hash = 0;
1642 int i;
1643 g_assert (ginst);
1644 g_assert (ginst->type_argv);
1646 for (i = 0; i < ginst->type_argc; ++i) {
1647 hash *= 13;
1648 g_assert (ginst->type_argv [i]);
1649 hash += mono_metadata_type_hash (ginst->type_argv [i]);
1652 return hash ^ (ginst->is_open << 8);
1655 static gboolean
1656 mono_generic_inst_equal_full (const MonoGenericInst *a, const MonoGenericInst *b, gboolean signature_only)
1658 int i;
1660 // An optimization: if the ids of two insts are the same, we know they are the same inst and don't check contents.
1661 // Furthermore, because we perform early de-duping, if the ids differ, we know the contents differ.
1662 #ifndef MONO_SMALL_CONFIG // Optimization does not work in MONO_SMALL_CONFIG: There are no IDs
1663 if (a->id && b->id) { // "id 0" means "object has no id"-- de-duping hasn't been performed yet, must check contents.
1664 if (a->id == b->id)
1665 return TRUE;
1666 // In signature-comparison mode id equality implies object equality, but this is not true for inequality.
1667 // Two separate objects could have signature-equavalent contents.
1668 if (!signature_only)
1669 return FALSE;
1671 #endif
1673 if (a->is_open != b->is_open || a->type_argc != b->type_argc)
1674 return FALSE;
1675 for (i = 0; i < a->type_argc; ++i) {
1676 if (!do_mono_metadata_type_equal (a->type_argv [i], b->type_argv [i], signature_only))
1677 return FALSE;
1679 return TRUE;
1682 gboolean
1683 mono_metadata_generic_inst_equal (gconstpointer ka, gconstpointer kb)
1685 const MonoGenericInst *a = (const MonoGenericInst *) ka;
1686 const MonoGenericInst *b = (const MonoGenericInst *) kb;
1688 return mono_generic_inst_equal_full (a, b, FALSE);
1691 static guint
1692 mono_generic_class_hash (gconstpointer data)
1694 const MonoGenericClass *gclass = (const MonoGenericClass *) data;
1695 guint hash = mono_metadata_type_hash (m_class_get_byval_arg (gclass->container_class));
1697 hash *= 13;
1698 hash += gclass->is_tb_open;
1699 hash += mono_metadata_generic_context_hash (&gclass->context);
1701 return hash;
1704 static gboolean
1705 mono_generic_class_equal (gconstpointer ka, gconstpointer kb)
1707 const MonoGenericClass *a = (const MonoGenericClass *) ka;
1708 const MonoGenericClass *b = (const MonoGenericClass *) kb;
1710 return _mono_metadata_generic_class_equal (a, b, FALSE);
1714 * mono_metadata_init:
1716 * Initialize the global variables of this module.
1717 * This is a Mono runtime internal function.
1719 void
1720 mono_metadata_init (void)
1722 int i;
1724 /* We guard against double initialization due to how pedump in verification mode works.
1725 Until runtime initialization is properly factored to work with what it needs we need workarounds like this.
1726 FIXME: https://bugzilla.xamarin.com/show_bug.cgi?id=58793
1728 static gboolean inited;
1730 if (inited)
1731 return;
1732 inited = TRUE;
1734 type_cache = g_hash_table_new (mono_type_hash, mono_type_equal);
1736 for (i = 0; i < NBUILTIN_TYPES (); ++i)
1737 g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]);
1739 mono_os_mutex_init_recursive (&image_sets_mutex);
1741 mono_counters_register ("ImgSet Cache Hit", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_hit);
1742 mono_counters_register ("ImgSet Cache Miss", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_miss);
1743 mono_counters_register ("ImgSet Count", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_count);
1747 * mono_metadata_cleanup:
1749 * Free all resources used by this module.
1750 * This is a Mono runtime internal function.
1752 void
1753 mono_metadata_cleanup (void)
1755 g_hash_table_destroy (type_cache);
1756 type_cache = NULL;
1757 g_ptr_array_free (image_sets, TRUE);
1758 image_sets = NULL;
1759 mono_os_mutex_destroy (&image_sets_mutex);
1763 * mono_metadata_parse_type:
1764 * \param m metadata context
1765 * \param mode kind of type that may be found at \p ptr
1766 * \param opt_attrs optional attributes to store in the returned type
1767 * \param ptr pointer to the type representation
1768 * \param rptr pointer updated to match the end of the decoded stream
1769 * \param transient whenever to allocate the result from the heap or from a mempool
1771 * Decode a compressed type description found at \p ptr in \p m .
1772 * \p mode can be one of \c MONO_PARSE_MOD_TYPE, \c MONO_PARSE_PARAM, \c MONO_PARSE_RET,
1773 * \c MONO_PARSE_FIELD, \c MONO_PARSE_LOCAL, \c MONO_PARSE_TYPE.
1774 * This function can be used to decode type descriptions in method signatures,
1775 * field signatures, locals signatures etc.
1777 * To parse a generic type, \c generic_container points to the current class'es
1778 * (the \c generic_container field in the <code>MonoClass</code>) or the current generic method's
1779 * (stored in <code>image->property_hash</code>) generic container.
1780 * When we encounter a \c MONO_TYPE_VAR or \c MONO_TYPE_MVAR, it's looked up in
1781 * this \c MonoGenericContainer.
1783 * LOCKING: Acquires the loader lock.
1785 * \returns a \c MonoType structure representing the decoded type.
1787 static MonoType*
1788 mono_metadata_parse_type_internal (MonoImage *m, MonoGenericContainer *container,
1789 short opt_attrs, gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1791 MonoType *type, *cached;
1792 MonoType stype;
1793 gboolean byref = FALSE;
1794 gboolean pinned = FALSE;
1795 const char *tmp_ptr;
1796 int count = 0; // Number of mod arguments
1797 gboolean found;
1799 error_init (error);
1802 * According to the spec, custom modifiers should come before the byref
1803 * flag, but the IL produced by ilasm from the following signature:
1804 * object modopt(...) &
1805 * starts with a byref flag, followed by the modifiers. (bug #49802)
1806 * Also, this type seems to be different from 'object & modopt(...)'. Maybe
1807 * it would be better to treat byref as real type constructor instead of
1808 * a modifier...
1809 * Also, pinned should come before anything else, but some MSV++ produced
1810 * assemblies violate this (#bug 61990).
1813 /* Count the modifiers first */
1814 tmp_ptr = ptr;
1815 found = TRUE;
1816 while (found) {
1817 switch (*tmp_ptr) {
1818 case MONO_TYPE_PINNED:
1819 case MONO_TYPE_BYREF:
1820 ++tmp_ptr;
1821 break;
1822 case MONO_TYPE_CMOD_REQD:
1823 case MONO_TYPE_CMOD_OPT:
1824 count ++;
1825 mono_metadata_parse_custom_mod (m, NULL, tmp_ptr, &tmp_ptr);
1826 break;
1827 default:
1828 found = FALSE;
1832 MonoCustomModContainer *cmods = NULL;
1834 if (count) { // There are mods, so the MonoType will be of nonstandard size.
1835 if (count > 64) {
1836 mono_error_set_bad_image (error, m, "Invalid type with more than 64 modifiers");
1837 return NULL;
1840 size_t size = mono_sizeof_type_with_mods (count);
1841 type = transient ? (MonoType *)g_malloc0 (size) : (MonoType *)mono_image_alloc0 (m, size);
1842 type->has_cmods = TRUE;
1844 cmods = mono_type_get_cmods (type);
1845 cmods->count = count;
1846 cmods->image = m;
1847 } else { // The type is of standard size, so we can allocate it on the stack.
1848 type = &stype;
1849 memset (type, 0, MONO_SIZEOF_TYPE);
1852 /* Iterate again, but now parse pinned, byref and custom modifiers */
1853 found = TRUE;
1854 count = 0;
1855 while (found) {
1856 switch (*ptr) {
1857 case MONO_TYPE_PINNED:
1858 pinned = TRUE;
1859 ++ptr;
1860 break;
1861 case MONO_TYPE_BYREF:
1862 byref = TRUE;
1863 ++ptr;
1864 break;
1865 case MONO_TYPE_CMOD_REQD:
1866 case MONO_TYPE_CMOD_OPT:
1867 mono_metadata_parse_custom_mod (m, &(cmods->modifiers [count]), ptr, &ptr);
1868 count ++;
1869 break;
1870 default:
1871 found = FALSE;
1875 type->attrs = opt_attrs;
1876 type->byref = byref;
1877 type->pinned = pinned ? 1 : 0;
1879 if (!do_mono_metadata_parse_type (type, m, container, transient, ptr, &ptr, error))
1880 return NULL;
1882 if (rptr)
1883 *rptr = ptr;
1885 // Possibly we can return an already-allocated type instead of the one we decoded
1886 if (!type->has_cmods && !transient) {
1887 /* no need to free type here, because it is on the stack */
1888 if ((type->type == MONO_TYPE_CLASS || type->type == MONO_TYPE_VALUETYPE) && !type->pinned && !type->attrs) {
1889 MonoType *ret = type->byref ? m_class_get_this_arg (type->data.klass) : m_class_get_byval_arg (type->data.klass);
1891 /* Consider the case:
1893 class Foo<T> { class Bar {} }
1894 class Test : Foo<Test>.Bar {}
1896 When Foo<Test> is being expanded, 'Test' isn't yet initialized. It's actually in
1897 a really pristine state: it doesn't even know whether 'Test' is a reference or a value type.
1899 We ensure that the MonoClass is in a state that we can canonicalize to:
1901 klass->_byval_arg.data.klass == klass
1902 klass->this_arg.data.klass == klass
1904 If we can't canonicalize 'type', it doesn't matter, since later users of 'type' will do it.
1906 LOCKING: even though we don't explicitly hold a lock, in the problematic case 'ret' is a field
1907 of a MonoClass which currently holds the loader lock. 'type' is local.
1909 if (ret->data.klass == type->data.klass) {
1910 return ret;
1913 /* No need to use locking since nobody is modifying the hash table */
1914 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type))) {
1915 return cached;
1919 /* printf ("%x %x %c %s\n", type->attrs, type->num_mods, type->pinned ? 'p' : ' ', mono_type_full_name (type)); */
1921 if (type == &stype) { // Type was allocated on the stack, so we need to copy it to safety
1922 type = transient ? (MonoType *)g_malloc (MONO_SIZEOF_TYPE) : (MonoType *)mono_image_alloc (m, MONO_SIZEOF_TYPE);
1923 memcpy (type, &stype, MONO_SIZEOF_TYPE);
1925 return type;
1929 MonoType*
1930 mono_metadata_parse_type_checked (MonoImage *m, MonoGenericContainer *container,
1931 short opt_attrs, gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1933 return mono_metadata_parse_type_internal (m, container, opt_attrs, transient, ptr, rptr, error);
1937 * LOCKING: Acquires the loader lock.
1939 MonoType*
1940 mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
1941 const char *ptr, const char **rptr)
1943 ERROR_DECL (error);
1944 MonoType * type = mono_metadata_parse_type_internal (m, NULL, opt_attrs, FALSE, ptr, rptr, error);
1945 mono_error_cleanup (error);
1946 return type;
1949 gboolean
1950 mono_metadata_method_has_param_attrs (MonoImage *m, int def)
1952 MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM];
1953 MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD];
1954 guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST);
1956 if (def < methodt->rows)
1957 lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
1958 else
1959 lastp = m->tables [MONO_TABLE_PARAM].rows + 1;
1961 for (i = param_index; i < lastp; ++i) {
1962 guint32 flags = mono_metadata_decode_row_col (paramt, i - 1, MONO_PARAM_FLAGS);
1963 if (flags)
1964 return TRUE;
1967 return FALSE;
1971 * mono_metadata_get_param_attrs:
1973 * @m The image to loader parameter attributes from
1974 * @def method def token (one based)
1975 * @param_count number of params to decode including the return value
1977 * Return the parameter attributes for the method whose MethodDef index is DEF. The
1978 * returned memory needs to be freed by the caller. If all the param attributes are
1979 * 0, then NULL is returned.
1981 int*
1982 mono_metadata_get_param_attrs (MonoImage *m, int def, int param_count)
1984 MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM];
1985 MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD];
1986 guint32 cols [MONO_PARAM_SIZE];
1987 guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST);
1988 int *pattrs = NULL;
1990 if (def < methodt->rows)
1991 lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
1992 else
1993 lastp = paramt->rows + 1;
1995 for (i = param_index; i < lastp; ++i) {
1996 mono_metadata_decode_row (paramt, i - 1, cols, MONO_PARAM_SIZE);
1997 if (cols [MONO_PARAM_FLAGS]) {
1998 if (!pattrs)
1999 pattrs = g_new0 (int, param_count);
2000 /* at runtime we just ignore this kind of malformed file:
2001 * the verifier can signal the error to the user
2003 if (cols [MONO_PARAM_SEQUENCE] >= param_count)
2004 continue;
2005 pattrs [cols [MONO_PARAM_SEQUENCE]] = cols [MONO_PARAM_FLAGS];
2009 return pattrs;
2014 * mono_metadata_parse_signature:
2015 * \param image metadata context
2016 * \param token metadata token
2018 * Decode a method signature stored in the \c StandAloneSig table
2020 * \returns a \c MonoMethodSignature describing the signature.
2022 MonoMethodSignature*
2023 mono_metadata_parse_signature (MonoImage *image, guint32 token)
2025 ERROR_DECL (error);
2026 MonoMethodSignature *ret;
2027 ret = mono_metadata_parse_signature_checked (image, token, error);
2028 mono_error_cleanup (error);
2029 return ret;
2033 * mono_metadata_parse_signature_checked:
2034 * @image: metadata context
2035 * @token: metadata token
2036 * @error: set on error
2038 * Decode a method signature stored in the STANDALONESIG table
2040 * Returns: a MonoMethodSignature describing the signature. On failure
2041 * returns NULL and sets @error.
2043 MonoMethodSignature*
2044 mono_metadata_parse_signature_checked (MonoImage *image, guint32 token, MonoError *error)
2047 error_init (error);
2048 MonoTableInfo *tables = image->tables;
2049 guint32 idx = mono_metadata_token_index (token);
2050 guint32 sig;
2051 const char *ptr;
2053 if (image_is_dynamic (image)) {
2054 return (MonoMethodSignature *)mono_lookup_dynamic_token (image, token, NULL, error);
2057 g_assert (mono_metadata_token_table(token) == MONO_TABLE_STANDALONESIG);
2059 sig = mono_metadata_decode_row_col (&tables [MONO_TABLE_STANDALONESIG], idx - 1, 0);
2061 ptr = mono_metadata_blob_heap (image, sig);
2062 mono_metadata_decode_blob_size (ptr, &ptr);
2064 return mono_metadata_parse_method_signature_full (image, NULL, 0, ptr, NULL, error);
2068 * mono_metadata_signature_alloc:
2069 * \param image metadata context
2070 * \param nparams number of parameters in the signature
2072 * Allocate a \c MonoMethodSignature structure with the specified number of params.
2073 * The return type and the params types need to be filled later.
2074 * This is a Mono runtime internal function.
2076 * LOCKING: Assumes the loader lock is held.
2078 * \returns the new \c MonoMethodSignature structure.
2080 MonoMethodSignature*
2081 mono_metadata_signature_alloc (MonoImage *m, guint32 nparams)
2083 MonoMethodSignature *sig;
2085 sig = (MonoMethodSignature *)mono_image_alloc0 (m, MONO_SIZEOF_METHOD_SIGNATURE + ((gint32)nparams) * sizeof (MonoType*));
2086 sig->param_count = nparams;
2087 sig->sentinelpos = -1;
2089 return sig;
2092 static MonoMethodSignature*
2093 mono_metadata_signature_dup_internal_with_padding (MonoImage *image, MonoMemPool *mp, MonoMethodSignature *sig, size_t padding)
2095 int sigsize, sig_header_size;
2096 MonoMethodSignature *ret;
2097 sigsize = sig_header_size = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *) + padding;
2098 if (sig->ret)
2099 sigsize += mono_sizeof_type (sig->ret);
2101 if (image) {
2102 ret = (MonoMethodSignature *)mono_image_alloc (image, sigsize);
2103 } else if (mp) {
2104 ret = (MonoMethodSignature *)mono_mempool_alloc (mp, sigsize);
2105 } else {
2106 ret = (MonoMethodSignature *)g_malloc (sigsize);
2109 memcpy (ret, sig, sig_header_size - padding);
2111 // Copy return value because of ownership semantics.
2112 if (sig->ret) {
2113 // Danger! Do not alter padding use without changing the dup_add_this below
2114 intptr_t end_of_header = (intptr_t)( (char*)(ret) + sig_header_size);
2115 ret->ret = (MonoType *)end_of_header;
2116 memcpy (ret->ret, sig->ret, mono_sizeof_type (sig->ret));
2119 return ret;
2122 static MonoMethodSignature*
2123 mono_metadata_signature_dup_internal (MonoImage *image, MonoMemPool *mp, MonoMethodSignature *sig)
2125 return mono_metadata_signature_dup_internal_with_padding (image, mp, sig, 0);
2128 * signature_dup_add_this:
2130 * Make a copy of @sig, adding an explicit this argument.
2132 MonoMethodSignature*
2133 mono_metadata_signature_dup_add_this (MonoImage *image, MonoMethodSignature *sig, MonoClass *klass)
2135 MonoMethodSignature *ret;
2136 ret = mono_metadata_signature_dup_internal_with_padding (image, NULL, sig, sizeof (MonoType *));
2138 ret->param_count = sig->param_count + 1;
2139 ret->hasthis = FALSE;
2141 for (int i = sig->param_count - 1; i >= 0; i --)
2142 ret->params [i + 1] = sig->params [i];
2143 ret->params [0] = m_class_is_valuetype (klass) ? m_class_get_this_arg (klass) : m_class_get_byval_arg (klass);
2145 for (int i = sig->param_count - 1; i >= 0; i --)
2146 g_assert(ret->params [i + 1]->type == sig->params [i]->type && ret->params [i+1]->type != MONO_TYPE_END);
2147 g_assert (ret->ret->type == sig->ret->type && ret->ret->type != MONO_TYPE_END);
2149 return ret;
2154 MonoMethodSignature*
2155 mono_metadata_signature_dup_full (MonoImage *image, MonoMethodSignature *sig)
2157 MonoMethodSignature *ret = mono_metadata_signature_dup_internal (image, NULL, sig);
2159 for (int i = 0 ; i < sig->param_count; i ++)
2160 g_assert(ret->params [i]->type == sig->params [i]->type);
2161 g_assert (ret->ret->type == sig->ret->type);
2163 return ret;
2166 /*The mempool is accessed without synchronization*/
2167 MonoMethodSignature*
2168 mono_metadata_signature_dup_mempool (MonoMemPool *mp, MonoMethodSignature *sig)
2170 return mono_metadata_signature_dup_internal (NULL, mp, sig);
2174 * mono_metadata_signature_dup:
2175 * \param sig method signature
2177 * Duplicate an existing \c MonoMethodSignature so it can be modified.
2178 * This is a Mono runtime internal function.
2180 * \returns the new \c MonoMethodSignature structure.
2182 MonoMethodSignature*
2183 mono_metadata_signature_dup (MonoMethodSignature *sig)
2185 return mono_metadata_signature_dup_full (NULL, sig);
2189 * mono_metadata_signature_size:
2191 * Return the amount of memory allocated to SIG.
2193 guint32
2194 mono_metadata_signature_size (MonoMethodSignature *sig)
2196 return MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
2200 * mono_metadata_parse_method_signature_full:
2201 * \param m metadata context
2202 * \param generic_container: generics container
2203 * \param def the \c MethodDef index or 0 for \c Ref signatures.
2204 * \param ptr pointer to the signature metadata representation
2205 * \param rptr pointer updated to match the end of the decoded stream
2206 * \param error set on error
2209 * Decode a method signature stored at \p ptr.
2210 * This is a Mono runtime internal function.
2212 * LOCKING: Assumes the loader lock is held.
2214 * \returns a \c MonoMethodSignature describing the signature. On error sets
2215 * \p error and returns \c NULL.
2217 MonoMethodSignature *
2218 mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *container,
2219 int def, const char *ptr, const char **rptr, MonoError *error)
2221 MonoMethodSignature *method;
2222 int i, *pattrs = NULL;
2223 guint32 hasthis = 0, explicit_this = 0, call_convention, param_count;
2224 guint32 gen_param_count = 0;
2225 gboolean is_open = FALSE;
2227 error_init (error);
2229 if (*ptr & 0x10)
2230 gen_param_count = 1;
2231 if (*ptr & 0x20)
2232 hasthis = 1;
2233 if (*ptr & 0x40)
2234 explicit_this = 1;
2235 call_convention = *ptr & 0x0F;
2236 ptr++;
2237 if (gen_param_count)
2238 gen_param_count = mono_metadata_decode_value (ptr, &ptr);
2239 param_count = mono_metadata_decode_value (ptr, &ptr);
2241 if (def)
2242 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 */
2244 method = mono_metadata_signature_alloc (m, param_count);
2245 method->hasthis = hasthis;
2246 method->explicit_this = explicit_this;
2247 method->call_convention = call_convention;
2248 method->generic_param_count = gen_param_count;
2250 if (call_convention != 0xa) {
2251 method->ret = mono_metadata_parse_type_checked (m, container, pattrs ? pattrs [0] : 0, FALSE, ptr, &ptr, error);
2252 if (!method->ret) {
2253 mono_metadata_free_method_signature (method);
2254 g_free (pattrs);
2255 return NULL;
2257 is_open = mono_class_is_open_constructed_type (method->ret);
2260 for (i = 0; i < method->param_count; ++i) {
2261 if (*ptr == MONO_TYPE_SENTINEL) {
2262 if (method->call_convention != MONO_CALL_VARARG || def) {
2263 mono_error_set_bad_image (error, m, "Found sentinel for methoddef or no vararg");
2264 g_free (pattrs);
2265 return NULL;
2267 if (method->sentinelpos >= 0) {
2268 mono_error_set_bad_image (error, m, "Found sentinel twice in the same signature.");
2269 g_free (pattrs);
2270 return NULL;
2272 method->sentinelpos = i;
2273 ptr++;
2275 method->params [i] = mono_metadata_parse_type_checked (m, container, pattrs ? pattrs [i+1] : 0, FALSE, ptr, &ptr, error);
2276 if (!method->params [i]) {
2277 mono_metadata_free_method_signature (method);
2278 g_free (pattrs);
2279 return NULL;
2281 if (!is_open)
2282 is_open = mono_class_is_open_constructed_type (method->params [i]);
2285 /* The sentinel could be missing if the caller does not pass any additional arguments */
2286 if (!def && method->call_convention == MONO_CALL_VARARG && method->sentinelpos < 0)
2287 method->sentinelpos = method->param_count;
2289 method->has_type_parameters = is_open;
2291 if (def && (method->call_convention == MONO_CALL_VARARG))
2292 method->sentinelpos = method->param_count;
2294 g_free (pattrs);
2296 if (rptr)
2297 *rptr = ptr;
2299 * Add signature to a cache and increase ref count...
2302 return method;
2306 * mono_metadata_parse_method_signature:
2307 * \param m metadata context
2308 * \param def the \c MethodDef index or 0 for \c Ref signatures.
2309 * \param ptr pointer to the signature metadata representation
2310 * \param rptr pointer updated to match the end of the decoded stream
2312 * Decode a method signature stored at \p ptr.
2313 * This is a Mono runtime internal function.
2315 * LOCKING: Assumes the loader lock is held.
2317 * \returns a \c MonoMethodSignature describing the signature.
2319 MonoMethodSignature *
2320 mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, const char **rptr)
2323 * This function MUST NOT be called by runtime code as it does error handling incorrectly.
2324 * Use mono_metadata_parse_method_signature_full instead.
2325 * It's ok to asser on failure as we no longer use it.
2327 ERROR_DECL (error);
2328 MonoMethodSignature *ret;
2329 ret = mono_metadata_parse_method_signature_full (m, NULL, def, ptr, rptr, error);
2330 mono_error_assert_ok (error);
2332 return ret;
2336 * mono_metadata_free_method_signature:
2337 * \param sig signature to destroy
2339 * Free the memory allocated in the signature \p sig.
2340 * This method needs to be robust and work also on partially-built
2341 * signatures, so it does extra checks.
2343 void
2344 mono_metadata_free_method_signature (MonoMethodSignature *sig)
2346 /* Everything is allocated from mempools */
2348 int i;
2349 if (sig->ret)
2350 mono_metadata_free_type (sig->ret);
2351 for (i = 0; i < sig->param_count; ++i) {
2352 if (sig->params [i])
2353 mono_metadata_free_type (sig->params [i]);
2358 void
2359 mono_metadata_free_inflated_signature (MonoMethodSignature *sig)
2361 int i;
2363 /* Allocated in inflate_generic_signature () */
2364 if (sig->ret)
2365 mono_metadata_free_type (sig->ret);
2366 for (i = 0; i < sig->param_count; ++i) {
2367 if (sig->params [i])
2368 mono_metadata_free_type (sig->params [i]);
2370 g_free (sig);
2373 static gboolean
2374 inflated_method_equal (gconstpointer a, gconstpointer b)
2376 const MonoMethodInflated *ma = (const MonoMethodInflated *)a;
2377 const MonoMethodInflated *mb = (const MonoMethodInflated *)b;
2378 if (ma->declaring != mb->declaring)
2379 return FALSE;
2380 return mono_metadata_generic_context_equal (&ma->context, &mb->context);
2383 static guint
2384 inflated_method_hash (gconstpointer a)
2386 const MonoMethodInflated *ma = (const MonoMethodInflated *)a;
2387 return (mono_metadata_generic_context_hash (&ma->context) ^ mono_aligned_addr_hash (ma->declaring));
2390 static gboolean
2391 inflated_signature_equal (gconstpointer a, gconstpointer b)
2393 const MonoInflatedMethodSignature *sig1 = (const MonoInflatedMethodSignature *)a;
2394 const MonoInflatedMethodSignature *sig2 = (const MonoInflatedMethodSignature *)b;
2396 /* sig->sig is assumed to be canonized */
2397 if (sig1->sig != sig2->sig)
2398 return FALSE;
2399 /* The generic instances are canonized */
2400 return mono_metadata_generic_context_equal (&sig1->context, &sig2->context);
2403 static guint
2404 inflated_signature_hash (gconstpointer a)
2406 const MonoInflatedMethodSignature *sig = (const MonoInflatedMethodSignature *)a;
2408 /* sig->sig is assumed to be canonized */
2409 return mono_metadata_generic_context_hash (&sig->context) ^ mono_aligned_addr_hash (sig->sig);
2412 /*static void
2413 dump_ginst (MonoGenericInst *ginst)
2415 int i;
2416 char *name;
2418 g_print ("Ginst: <");
2419 for (i = 0; i < ginst->type_argc; ++i) {
2420 if (i != 0)
2421 g_print (", ");
2422 name = mono_type_get_name (ginst->type_argv [i]);
2423 g_print ("%s", name);
2424 g_free (name);
2426 g_print (">");
2429 static gboolean type_in_image (MonoType *type, MonoImage *image);
2431 static gboolean
2432 signature_in_image (MonoMethodSignature *sig, MonoImage *image)
2434 gpointer iter = NULL;
2435 MonoType *p;
2437 while ((p = mono_signature_get_params (sig, &iter)) != NULL)
2438 if (type_in_image (p, image))
2439 return TRUE;
2441 return type_in_image (mono_signature_get_return_type (sig), image);
2444 static gboolean
2445 ginst_in_image (MonoGenericInst *ginst, MonoImage *image)
2447 int i;
2449 for (i = 0; i < ginst->type_argc; ++i) {
2450 if (type_in_image (ginst->type_argv [i], image))
2451 return TRUE;
2454 return FALSE;
2457 static gboolean
2458 gclass_in_image (MonoGenericClass *gclass, MonoImage *image)
2460 return m_class_get_image (gclass->container_class) == image ||
2461 ginst_in_image (gclass->context.class_inst, image);
2464 static gboolean
2465 type_in_image (MonoType *type, MonoImage *image)
2467 retry:
2468 switch (type->type) {
2469 case MONO_TYPE_GENERICINST:
2470 return gclass_in_image (type->data.generic_class, image);
2471 case MONO_TYPE_PTR:
2472 type = type->data.type;
2473 goto retry;
2474 case MONO_TYPE_SZARRAY:
2475 type = m_class_get_byval_arg (type->data.klass);
2476 goto retry;
2477 case MONO_TYPE_ARRAY:
2478 type = m_class_get_byval_arg (type->data.array->eklass);
2479 goto retry;
2480 case MONO_TYPE_FNPTR:
2481 return signature_in_image (type->data.method, image);
2482 case MONO_TYPE_VAR:
2483 case MONO_TYPE_MVAR:
2484 return image == mono_get_image_for_generic_param (type->data.generic_param);
2485 default:
2486 /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type_internal () */
2487 return image == m_class_get_image (mono_class_from_mono_type_internal (type));
2491 gboolean
2492 mono_type_in_image (MonoType *type, MonoImage *image)
2494 return type_in_image (type, image);
2497 static inline void
2498 image_sets_lock (void)
2500 mono_os_mutex_lock (&image_sets_mutex);
2503 static inline void
2504 image_sets_unlock (void)
2506 mono_os_mutex_unlock (&image_sets_mutex);
2509 static int
2510 compare_pointers (const void *a, const void *b)
2512 return (size_t)a - (size_t)b;
2515 //1103, 1327, 1597
2516 #define HASH_TABLE_SIZE 1103
2517 static MonoImageSet *img_set_cache [HASH_TABLE_SIZE];
2519 static guint32
2520 mix_hash (uintptr_t source)
2522 unsigned int hash = source;
2524 // Actual hash
2525 hash = (((hash * 215497) >> 16) ^ ((hash * 1823231) + hash));
2527 // Mix in highest bits on 64-bit systems only
2528 if (sizeof (source) > 4)
2529 hash = hash ^ (source >> 32);
2531 return hash;
2534 static guint32
2535 hash_images (MonoImage **images, int nimages)
2537 guint32 res = 0;
2538 int i;
2539 for (i = 0; i < nimages; ++i)
2540 res += mix_hash ((size_t)images [i]);
2542 return res;
2545 static gboolean
2546 compare_img_set (MonoImageSet *set, MonoImage **images, int nimages)
2548 int j, k;
2550 if (set->nimages != nimages)
2551 return FALSE;
2553 for (j = 0; j < nimages; ++j) {
2554 for (k = 0; k < nimages; ++k)
2555 if (set->images [k] == images [j])
2556 break; // Break on match
2558 // If we iterated all the way through set->images, images[j] was *not* found.
2559 if (k == nimages)
2560 break; // Break on "image not found"
2563 // If we iterated all the way through images without breaking, all items in images were found in set->images
2564 return j == nimages;
2568 static MonoImageSet*
2569 img_set_cache_get (MonoImage **images, int nimages)
2571 guint32 hash_code = hash_images (images, nimages);
2572 int index = hash_code % HASH_TABLE_SIZE;
2573 MonoImageSet *img = img_set_cache [index];
2574 if (!img || !compare_img_set (img, images, nimages)) {
2575 UnlockedIncrement (&img_set_cache_miss);
2576 return NULL;
2578 UnlockedIncrement (&img_set_cache_hit);
2579 return img;
2582 static void
2583 img_set_cache_add (MonoImageSet *set)
2585 guint32 hash_code = hash_images (set->images, set->nimages);
2586 int index = hash_code % HASH_TABLE_SIZE;
2587 img_set_cache [index] = set;
2590 static void
2591 img_set_cache_remove (MonoImageSet *is)
2593 guint32 hash_code = hash_images (is->images, is->nimages);
2594 int index = hash_code % HASH_TABLE_SIZE;
2595 if (img_set_cache [index] == is)
2596 img_set_cache [index] = NULL;
2599 * get_image_set:
2601 * Return a MonoImageSet representing the set of images in IMAGES.
2603 static MonoImageSet*
2604 get_image_set (MonoImage **images, int nimages)
2606 int i, j, k;
2607 MonoImageSet *set;
2608 GSList *l;
2610 /* Common case: Image set contains corlib only. If we've seen that case before, we cached the set. */
2611 if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set)
2612 return mscorlib_image_set;
2614 /* Happens with empty generic instances */
2615 // 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.
2616 if (nimages == 0)
2617 return mscorlib_image_set;
2619 set = img_set_cache_get (images, nimages);
2620 if (set)
2621 return set;
2623 image_sets_lock ();
2625 if (!image_sets)
2626 image_sets = g_ptr_array_new ();
2628 // Before we go on, we should check to see whether a MonoImageSet with these images already exists.
2629 // We can search the referred-by imagesets of any one of our images to do this. Arbitrarily pick one here:
2630 if (images [0] == mono_defaults.corlib && nimages > 1)
2631 l = images [1]->image_sets; // Prefer not to search the imagesets of corlib-- that will be a long list.
2632 else
2633 l = images [0]->image_sets;
2635 set = NULL;
2636 while (l) // Iterate over selected list, looking for an imageset with members equal to our target one
2638 set = (MonoImageSet *)l->data;
2640 if (set->nimages == nimages) { // Member count differs, this can't be it
2641 // Compare all members to all members-- order might be different
2642 for (j = 0; j < nimages; ++j) {
2643 for (k = 0; k < nimages; ++k)
2644 if (set->images [k] == images [j])
2645 break; // Break on match
2647 // If we iterated all the way through set->images, images[j] was *not* found.
2648 if (k == nimages)
2649 break; // Break on "image not found"
2652 // If we iterated all the way through images without breaking, all items in images were found in set->images
2653 if (j == nimages) {
2654 // Break on "found a set with equal members".
2655 // This happens in case of a hash collision with a previously cached set.
2656 break;
2660 l = l->next;
2663 // If we iterated all the way through l without breaking, the imageset does not already exist and we should create it
2664 if (!l) {
2665 set = g_new0 (MonoImageSet, 1);
2666 set->nimages = nimages;
2667 set->images = g_new0 (MonoImage*, nimages);
2668 mono_os_mutex_init_recursive (&set->lock);
2669 for (i = 0; i < nimages; ++i)
2670 set->images [i] = images [i];
2671 set->gclass_cache = mono_conc_hashtable_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
2672 set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
2673 set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
2674 set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
2676 set->szarray_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2677 set->array_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2679 for (i = 0; i < nimages; ++i)
2680 set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set);
2682 g_ptr_array_add (image_sets, set);
2683 UnlockedIncrement (&img_set_count); /* locked by image_sets_lock () */
2686 /* Cache the set. If there was a cache collision, the previously cached value will be replaced. */
2687 img_set_cache_add (set);
2689 if (nimages == 1 && images [0] == mono_defaults.corlib) {
2690 mono_memory_barrier ();
2691 mscorlib_image_set = set;
2694 image_sets_unlock ();
2696 return set;
2699 static void
2700 delete_image_set (MonoImageSet *set)
2702 int i;
2704 mono_conc_hashtable_destroy (set->gclass_cache);
2705 g_hash_table_destroy (set->ginst_cache);
2706 g_hash_table_destroy (set->gmethod_cache);
2707 g_hash_table_destroy (set->gsignature_cache);
2709 g_hash_table_destroy (set->szarray_cache);
2710 g_hash_table_destroy (set->array_cache);
2711 if (set->ptr_cache)
2712 g_hash_table_destroy (set->ptr_cache);
2714 mono_wrapper_caches_free (&set->wrapper_caches);
2716 image_sets_lock ();
2718 for (i = 0; i < set->nimages; ++i)
2719 set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set);
2721 g_ptr_array_remove (image_sets, set);
2723 image_sets_unlock ();
2725 img_set_cache_remove (set);
2727 if (set->mempool)
2728 mono_mempool_destroy (set->mempool);
2729 g_free (set->images);
2730 mono_os_mutex_destroy (&set->lock);
2731 g_free (set);
2734 void
2735 mono_image_set_lock (MonoImageSet *set)
2737 mono_os_mutex_lock (&set->lock);
2740 void
2741 mono_image_set_unlock (MonoImageSet *set)
2743 mono_os_mutex_unlock (&set->lock);
2746 gpointer
2747 mono_image_set_alloc (MonoImageSet *set, guint size)
2749 gpointer res;
2751 mono_image_set_lock (set);
2752 if (!set->mempool)
2753 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2754 res = mono_mempool_alloc (set->mempool, size);
2755 mono_image_set_unlock (set);
2757 return res;
2760 gpointer
2761 mono_image_set_alloc0 (MonoImageSet *set, guint size)
2763 gpointer res;
2765 mono_image_set_lock (set);
2766 if (!set->mempool)
2767 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2768 res = mono_mempool_alloc0 (set->mempool, size);
2769 mono_image_set_unlock (set);
2771 return res;
2774 char*
2775 mono_image_set_strdup (MonoImageSet *set, const char *s)
2777 char *res;
2779 mono_image_set_lock (set);
2780 if (!set->mempool)
2781 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2782 res = mono_mempool_strdup (set->mempool, s);
2783 mono_image_set_unlock (set);
2785 return res;
2788 // Get a descriptive string for a MonoImageSet
2789 // Callers are obligated to free buffer with g_free after use
2790 char *
2791 mono_image_set_description (MonoImageSet *set)
2793 GString *result = g_string_new (NULL);
2794 int img;
2795 g_string_append (result, "[");
2796 for (img = 0; img < set->nimages; img++)
2798 if (img > 0)
2799 g_string_append (result, ", ");
2800 g_string_append (result, set->images[img]->name);
2802 g_string_append (result, "]");
2803 return g_string_free (result, FALSE);
2807 * Structure used by the collect_..._images functions to store the image list.
2809 typedef struct {
2810 MonoImage *image_buf [64];
2811 MonoImage **images;
2812 int nimages, images_len;
2813 } CollectData;
2815 static void
2816 collect_data_init (CollectData *data)
2818 data->images = data->image_buf;
2819 data->images_len = 64;
2820 data->nimages = 0;
2823 static void
2824 collect_data_free (CollectData *data)
2826 if (data->images != data->image_buf)
2827 g_free (data->images);
2830 static void
2831 enlarge_data (CollectData *data)
2833 int new_len = data->images_len < 16 ? 16 : data->images_len * 2;
2834 MonoImage **d = g_new (MonoImage *, new_len);
2836 // FIXME: test this
2837 g_assert_not_reached ();
2838 memcpy (d, data->images, data->images_len);
2839 if (data->images != data->image_buf)
2840 g_free (data->images);
2841 data->images = d;
2842 data->images_len = new_len;
2845 static inline void
2846 add_image (MonoImage *image, CollectData *data)
2848 int i;
2850 /* The arrays are small, so use a linear search instead of a hash table */
2851 for (i = 0; i < data->nimages; ++i)
2852 if (data->images [i] == image)
2853 return;
2855 if (data->nimages == data->images_len)
2856 enlarge_data (data);
2858 data->images [data->nimages ++] = image;
2861 static void
2862 collect_type_images (MonoType *type, CollectData *data);
2864 static void
2865 collect_ginst_images (MonoGenericInst *ginst, CollectData *data)
2867 int i;
2869 for (i = 0; i < ginst->type_argc; ++i) {
2870 collect_type_images (ginst->type_argv [i], data);
2874 static void
2875 collect_gclass_images (MonoGenericClass *gclass, CollectData *data)
2877 add_image (m_class_get_image (gclass->container_class), data);
2878 if (gclass->context.class_inst)
2879 collect_ginst_images (gclass->context.class_inst, data);
2882 static void
2883 collect_signature_images (MonoMethodSignature *sig, CollectData *data)
2885 gpointer iter = NULL;
2886 MonoType *p;
2888 collect_type_images (mono_signature_get_return_type (sig), data);
2889 while ((p = mono_signature_get_params (sig, &iter)) != NULL)
2890 collect_type_images (p, data);
2893 static void
2894 collect_inflated_signature_images (MonoInflatedMethodSignature *sig, CollectData *data)
2896 collect_signature_images (sig->sig, data);
2897 if (sig->context.class_inst)
2898 collect_ginst_images (sig->context.class_inst, data);
2899 if (sig->context.method_inst)
2900 collect_ginst_images (sig->context.method_inst, data);
2903 static void
2904 collect_method_images (MonoMethodInflated *method, CollectData *data)
2906 MonoMethod *m = method->declaring;
2908 add_image (m_class_get_image (method->declaring->klass), data);
2909 if (method->context.class_inst)
2910 collect_ginst_images (method->context.class_inst, data);
2911 if (method->context.method_inst)
2912 collect_ginst_images (method->context.method_inst, data);
2914 * Dynamic assemblies have no references, so the images they depend on can be unloaded before them.
2916 if (image_is_dynamic (m_class_get_image (m->klass)))
2917 collect_signature_images (mono_method_signature_internal (m), data);
2920 static void
2921 collect_type_images (MonoType *type, CollectData *data)
2923 retry:
2924 switch (type->type) {
2925 case MONO_TYPE_GENERICINST:
2926 collect_gclass_images (type->data.generic_class, data);
2927 break;
2928 case MONO_TYPE_PTR:
2929 type = type->data.type;
2930 goto retry;
2931 case MONO_TYPE_SZARRAY:
2932 type = m_class_get_byval_arg (type->data.klass);
2933 goto retry;
2934 case MONO_TYPE_ARRAY:
2935 type = m_class_get_byval_arg (type->data.array->eklass);
2936 goto retry;
2937 case MONO_TYPE_FNPTR:
2938 //return signature_in_image (type->data.method, image);
2939 g_assert_not_reached ();
2940 case MONO_TYPE_VAR:
2941 case MONO_TYPE_MVAR:
2943 MonoImage *image = mono_get_image_for_generic_param (type->data.generic_param);
2944 add_image (image, data);
2945 break;
2947 case MONO_TYPE_CLASS:
2948 case MONO_TYPE_VALUETYPE:
2949 add_image (m_class_get_image (mono_class_from_mono_type_internal (type)), data);
2950 break;
2951 default:
2952 add_image (mono_defaults.corlib, data);
2956 typedef struct {
2957 MonoImage *image;
2958 GSList *list;
2959 } CleanForImageUserData;
2961 static gboolean
2962 steal_gclass_in_image (gpointer key, gpointer value, gpointer data)
2964 MonoGenericClass *gclass = (MonoGenericClass *)key;
2965 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
2967 g_assert (gclass_in_image (gclass, user_data->image));
2969 user_data->list = g_slist_prepend (user_data->list, gclass);
2970 return TRUE;
2973 static gboolean
2974 steal_ginst_in_image (gpointer key, gpointer value, gpointer data)
2976 MonoGenericInst *ginst = (MonoGenericInst *)key;
2977 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
2979 // This doesn't work during corlib compilation
2980 //g_assert (ginst_in_image (ginst, user_data->image));
2982 user_data->list = g_slist_prepend (user_data->list, ginst);
2983 return TRUE;
2986 static gboolean
2987 inflated_method_in_image (gpointer key, gpointer value, gpointer data)
2989 MonoImage *image = (MonoImage *)data;
2990 MonoMethodInflated *method = (MonoMethodInflated *)key;
2992 // FIXME:
2993 // https://bugzilla.novell.com/show_bug.cgi?id=458168
2994 g_assert (m_class_get_image (method->declaring->klass) == image ||
2995 (method->context.class_inst && ginst_in_image (method->context.class_inst, image)) ||
2996 (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)));
2998 return TRUE;
3001 static gboolean
3002 inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
3004 MonoImage *image = (MonoImage *)data;
3005 MonoInflatedMethodSignature *sig = (MonoInflatedMethodSignature *)key;
3007 return signature_in_image (sig->sig, image) ||
3008 (sig->context.class_inst && ginst_in_image (sig->context.class_inst, image)) ||
3009 (sig->context.method_inst && ginst_in_image (sig->context.method_inst, image));
3012 static gboolean
3013 class_in_image (gpointer key, gpointer value, gpointer data)
3015 MonoImage *image = (MonoImage *)data;
3016 MonoClass *klass = (MonoClass *)key;
3018 g_assert (type_in_image (m_class_get_byval_arg (klass), image));
3020 return TRUE;
3023 static void
3024 check_gmethod (gpointer key, gpointer value, gpointer data)
3026 MonoMethodInflated *method = (MonoMethodInflated *)key;
3027 MonoImage *image = (MonoImage *)data;
3029 if (method->context.class_inst)
3030 g_assert (!ginst_in_image (method->context.class_inst, image));
3031 if (method->context.method_inst)
3032 g_assert (!ginst_in_image (method->context.method_inst, image));
3033 if (((MonoMethod*)method)->signature)
3034 g_assert (!signature_in_image (mono_method_signature_internal ((MonoMethod*)method), image));
3038 * check_image_sets:
3040 * Run a consistency check on the image set data structures.
3042 static G_GNUC_UNUSED void
3043 check_image_sets (MonoImage *image)
3045 int i;
3046 GSList *l = image->image_sets;
3048 if (!image_sets)
3049 return;
3051 for (i = 0; i < image_sets->len; ++i) {
3052 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
3054 if (!g_slist_find (l, set)) {
3055 g_hash_table_foreach (set->gmethod_cache, check_gmethod, image);
3060 void
3061 mono_metadata_clean_for_image (MonoImage *image)
3063 CleanForImageUserData ginst_data, gclass_data;
3064 GSList *l, *set_list;
3066 //check_image_sets (image);
3069 * The data structures could reference each other so we delete them in two phases.
3070 * This is required because of the hashing functions in gclass/ginst_cache.
3072 ginst_data.image = gclass_data.image = image;
3073 ginst_data.list = gclass_data.list = NULL;
3075 /* Collect the items to delete */
3076 /* delete_image_set () modifies the lists so make a copy */
3077 for (l = image->image_sets; l; l = l->next) {
3078 MonoImageSet *set = (MonoImageSet *)l->data;
3080 mono_image_set_lock (set);
3081 mono_conc_hashtable_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data);
3082 g_hash_table_foreach_steal (set->ginst_cache, steal_ginst_in_image, &ginst_data);
3083 g_hash_table_foreach_remove (set->gmethod_cache, inflated_method_in_image, image);
3084 g_hash_table_foreach_remove (set->gsignature_cache, inflated_signature_in_image, image);
3086 g_hash_table_foreach_steal (set->szarray_cache, class_in_image, image);
3087 g_hash_table_foreach_steal (set->array_cache, class_in_image, image);
3088 if (set->ptr_cache)
3089 g_hash_table_foreach_steal (set->ptr_cache, class_in_image, image);
3090 mono_image_set_unlock (set);
3093 /* Delete the removed items */
3094 for (l = ginst_data.list; l; l = l->next)
3095 free_generic_inst ((MonoGenericInst *)l->data);
3096 for (l = gclass_data.list; l; l = l->next)
3097 free_generic_class ((MonoGenericClass *)l->data);
3098 g_slist_free (ginst_data.list);
3099 g_slist_free (gclass_data.list);
3100 /* delete_image_set () modifies the lists so make a copy */
3101 set_list = g_slist_copy (image->image_sets);
3102 for (l = set_list; l; l = l->next) {
3103 MonoImageSet *set = (MonoImageSet *)l->data;
3105 delete_image_set (set);
3107 g_slist_free (set_list);
3110 static void
3111 free_inflated_method (MonoMethodInflated *imethod)
3113 MonoMethod *method = (MonoMethod*)imethod;
3115 if (method->signature)
3116 mono_metadata_free_inflated_signature (method->signature);
3118 if (method->wrapper_type)
3119 g_free (((MonoMethodWrapper*)method)->method_data);
3121 g_free (method);
3124 static void
3125 free_generic_inst (MonoGenericInst *ginst)
3127 int i;
3129 /* The ginst itself is allocated from the image set mempool */
3130 for (i = 0; i < ginst->type_argc; ++i)
3131 mono_metadata_free_type (ginst->type_argv [i]);
3134 static void
3135 free_generic_class (MonoGenericClass *gclass)
3137 /* The gclass itself is allocated from the image set mempool */
3138 if (gclass->cached_class && m_class_get_interface_id (gclass->cached_class))
3139 mono_unload_interface_id (gclass->cached_class);
3142 static void
3143 free_inflated_signature (MonoInflatedMethodSignature *sig)
3145 mono_metadata_free_inflated_signature (sig->sig);
3146 g_free (sig);
3150 * mono_metadata_get_inflated_signature:
3152 * Given an inflated signature and a generic context, return a canonical copy of the
3153 * signature. The returned signature might be equal to SIG or it might be a cached copy.
3155 MonoMethodSignature *
3156 mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericContext *context)
3158 MonoInflatedMethodSignature helper;
3159 MonoInflatedMethodSignature *res;
3160 CollectData data;
3161 MonoImageSet *set;
3163 helper.sig = sig;
3164 helper.context.class_inst = context->class_inst;
3165 helper.context.method_inst = context->method_inst;
3167 collect_data_init (&data);
3169 collect_inflated_signature_images (&helper, &data);
3171 set = get_image_set (data.images, data.nimages);
3173 collect_data_free (&data);
3175 mono_image_set_lock (set);
3177 res = (MonoInflatedMethodSignature *)g_hash_table_lookup (set->gsignature_cache, &helper);
3178 if (!res) {
3179 res = g_new0 (MonoInflatedMethodSignature, 1);
3180 res->sig = sig;
3181 res->context.class_inst = context->class_inst;
3182 res->context.method_inst = context->method_inst;
3183 g_hash_table_insert (set->gsignature_cache, res, res);
3186 mono_image_set_unlock (set);
3188 return res->sig;
3191 MonoImageSet *
3192 mono_metadata_get_image_set_for_class (MonoClass *klass)
3194 MonoImageSet *set;
3195 CollectData image_set_data;
3197 collect_data_init (&image_set_data);
3198 collect_type_images (m_class_get_byval_arg (klass), &image_set_data);
3199 set = get_image_set (image_set_data.images, image_set_data.nimages);
3200 collect_data_free (&image_set_data);
3202 return set;
3205 MonoImageSet *
3206 mono_metadata_get_image_set_for_method (MonoMethodInflated *method)
3208 MonoImageSet *set;
3209 CollectData image_set_data;
3211 collect_data_init (&image_set_data);
3212 collect_method_images (method, &image_set_data);
3213 set = get_image_set (image_set_data.images, image_set_data.nimages);
3214 collect_data_free (&image_set_data);
3216 return set;
3219 static gboolean
3220 type_is_gtd (MonoType *type)
3222 switch (type->type) {
3223 case MONO_TYPE_CLASS:
3224 case MONO_TYPE_VALUETYPE:
3225 return mono_class_is_gtd (type->data.klass);
3226 default:
3227 return FALSE;
3232 * mono_metadata_get_generic_inst:
3234 * Given a list of types, return a MonoGenericInst that represents that list.
3235 * The returned MonoGenericInst has its own copy of the list of types. The list
3236 * passed in the argument can be freed, modified or disposed of.
3239 MonoGenericInst *
3240 mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
3242 MonoGenericInst *ginst;
3243 gboolean is_open;
3244 int i;
3245 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3247 for (i = 0; i < type_argc; ++i)
3248 if (mono_class_is_open_constructed_type (type_argv [i]))
3249 break;
3250 is_open = (i < type_argc);
3252 ginst = (MonoGenericInst *)g_alloca (size);
3253 memset (ginst, 0, sizeof (MonoGenericInst));
3254 ginst->is_open = is_open;
3255 ginst->type_argc = type_argc;
3256 memcpy (ginst->type_argv, type_argv, type_argc * sizeof (MonoType *));
3258 for (i = 0; i < type_argc; ++i) {
3259 MonoType *t = ginst->type_argv [i];
3260 if (type_is_gtd (t)) {
3261 ginst->type_argv [i] = mono_class_gtd_get_canonical_inst (t->data.klass);
3265 return mono_metadata_get_canonical_generic_inst (ginst);
3270 * mono_metadata_get_canonical_generic_inst:
3271 * \param candidate an arbitrary generic instantiation
3273 * \returns the canonical generic instantiation that represents the given
3274 * candidate by identifying the image set for the candidate instantiation and
3275 * finding the instance in the image set or adding a copy of the given instance
3276 * to the image set.
3278 * The returned MonoGenericInst has its own copy of the list of types. The list
3279 * passed in the argument can be freed, modified or disposed of.
3282 MonoGenericInst *
3283 mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate)
3285 CollectData data;
3286 int type_argc = candidate->type_argc;
3287 gboolean is_open = candidate->is_open;
3288 MonoImageSet *set;
3290 collect_data_init (&data);
3292 collect_ginst_images (candidate, &data);
3294 set = get_image_set (data.images, data.nimages);
3296 collect_data_free (&data);
3298 mono_image_set_lock (set);
3300 MonoGenericInst *ginst = (MonoGenericInst *)g_hash_table_lookup (set->ginst_cache, candidate);
3301 if (!ginst) {
3302 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3303 ginst = (MonoGenericInst *)mono_image_set_alloc0 (set, size);
3304 #ifndef MONO_SMALL_CONFIG
3305 ginst->id = mono_atomic_inc_i32 (&next_generic_inst_id);
3306 #endif
3307 ginst->is_open = is_open;
3308 ginst->type_argc = type_argc;
3310 for (int i = 0; i < type_argc; ++i)
3311 ginst->type_argv [i] = mono_metadata_type_dup (NULL, candidate->type_argv [i]);
3313 g_hash_table_insert (set->ginst_cache, ginst, ginst);
3316 mono_image_set_unlock (set);
3317 return ginst;
3320 static gboolean
3321 mono_metadata_is_type_builder_generic_type_definition (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3323 MonoGenericContainer *container = mono_class_get_generic_container (container_class);
3325 if (!is_dynamic || m_class_was_typebuilder (container_class) || container->type_argc != inst->type_argc)
3326 return FALSE;
3327 return inst == container->context.class_inst;
3331 * mono_metadata_lookup_generic_class:
3333 * Returns a MonoGenericClass with the given properties.
3336 MonoGenericClass *
3337 mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3339 MonoGenericClass *gclass;
3340 MonoGenericClass helper;
3341 gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic);
3342 MonoImageSet *set;
3343 CollectData data;
3345 g_assert (mono_class_get_generic_container (container_class)->type_argc == inst->type_argc);
3347 memset (&helper, 0, sizeof(helper)); // act like g_new0
3348 helper.container_class = container_class;
3349 helper.context.class_inst = inst;
3350 helper.is_dynamic = is_dynamic; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
3351 helper.is_tb_open = is_tb_open;
3353 collect_data_init (&data);
3355 collect_gclass_images (&helper, &data);
3357 set = get_image_set (data.images, data.nimages);
3359 collect_data_free (&data);
3361 gclass = (MonoGenericClass *)mono_conc_hashtable_lookup (set->gclass_cache, &helper);
3363 /* A tripwire just to keep us honest */
3364 g_assert (!helper.cached_class);
3366 if (gclass)
3367 return gclass;
3369 gclass = mono_image_set_new0 (set, MonoGenericClass, 1);
3370 if (is_dynamic)
3371 gclass->is_dynamic = 1;
3373 gclass->is_tb_open = is_tb_open;
3374 gclass->container_class = container_class;
3375 gclass->context.class_inst = inst;
3376 gclass->context.method_inst = NULL;
3377 gclass->owner = set;
3378 if (inst == mono_class_get_generic_container (container_class)->context.class_inst && !is_tb_open)
3379 gclass->cached_class = container_class;
3381 mono_image_set_lock (set);
3383 MonoGenericClass *gclass2 = (MonoGenericClass*)mono_conc_hashtable_insert (set->gclass_cache, gclass, gclass);
3384 if (!gclass2)
3385 gclass2 = gclass;
3387 // g_hash_table_insert (set->gclass_cache, gclass, gclass);
3389 mono_image_set_unlock (set);
3391 return gclass2;
3395 * mono_metadata_inflate_generic_inst:
3397 * Instantiate the generic instance @ginst with the context @context.
3398 * Check @error for success.
3401 MonoGenericInst *
3402 mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context, MonoError *error)
3404 MonoType **type_argv;
3405 MonoGenericInst *nginst = NULL;
3406 int i, count = 0;
3408 error_init (error);
3410 if (!ginst->is_open)
3411 return ginst;
3413 type_argv = g_new0 (MonoType*, ginst->type_argc);
3415 for (i = 0; i < ginst->type_argc; i++) {
3416 type_argv [i] = mono_class_inflate_generic_type_checked (ginst->type_argv [i], context, error);
3417 if (!mono_error_ok (error))
3418 goto cleanup;
3419 ++count;
3422 nginst = mono_metadata_get_generic_inst (ginst->type_argc, type_argv);
3424 cleanup:
3425 for (i = 0; i < count; i++)
3426 mono_metadata_free_type (type_argv [i]);
3427 g_free (type_argv);
3429 return nginst;
3432 MonoGenericInst *
3433 mono_metadata_parse_generic_inst (MonoImage *m, MonoGenericContainer *container,
3434 int count, const char *ptr, const char **rptr, MonoError *error)
3436 MonoType **type_argv;
3437 MonoGenericInst *ginst = NULL;
3438 int i, parse_count = 0;
3440 error_init (error);
3441 type_argv = g_new0 (MonoType*, count);
3443 for (i = 0; i < count; i++) {
3444 /* this can be a transient type, mono_metadata_get_generic_inst will allocate
3445 * a canonical one, if needed.
3447 MonoType *t = mono_metadata_parse_type_checked (m, container, 0, TRUE, ptr, &ptr, error);
3448 if (!t)
3449 goto cleanup;
3450 type_argv [i] = t;
3451 parse_count++;
3454 if (rptr)
3455 *rptr = ptr;
3457 g_assert (parse_count == count);
3458 ginst = mono_metadata_get_generic_inst (count, type_argv);
3460 cleanup:
3461 for (i = 0; i < parse_count; i++)
3462 mono_metadata_free_type (type_argv [i]);
3463 g_free (type_argv);
3465 return ginst;
3468 static gboolean
3469 do_mono_metadata_parse_generic_class (MonoType *type, MonoImage *m, MonoGenericContainer *container,
3470 const char *ptr, const char **rptr, MonoError *error)
3472 MonoGenericInst *inst;
3473 MonoClass *gklass;
3474 MonoType *gtype;
3475 int count;
3477 error_init (error);
3479 // XXX how about transient?
3480 gtype = mono_metadata_parse_type_checked (m, NULL, 0, FALSE, ptr, &ptr, error);
3481 if (gtype == NULL)
3482 return FALSE;
3484 gklass = mono_class_from_mono_type_internal (gtype);
3485 if (!mono_class_is_gtd (gklass)) {
3486 mono_error_set_bad_image (error, m, "Generic instance with non-generic definition");
3487 return FALSE;
3490 count = mono_metadata_decode_value (ptr, &ptr);
3491 inst = mono_metadata_parse_generic_inst (m, container, count, ptr, &ptr, error);
3492 if (inst == NULL)
3493 return FALSE;
3495 if (rptr)
3496 *rptr = ptr;
3498 type->data.generic_class = mono_metadata_lookup_generic_class (gklass, inst, FALSE);
3499 return TRUE;
3503 * select_container:
3504 * @gc: The generic container to normalize
3505 * @type: The kind of generic parameters the resulting generic-container should contain
3508 static MonoGenericContainer *
3509 select_container (MonoGenericContainer *gc, MonoTypeEnum type)
3511 gboolean is_var = (type == MONO_TYPE_VAR);
3512 if (!gc)
3513 return NULL;
3515 g_assert (is_var || type == MONO_TYPE_MVAR);
3517 if (is_var) {
3518 if (gc->is_method || gc->parent)
3520 * The current MonoGenericContainer is a generic method -> its `parent'
3521 * points to the containing class'es container.
3523 return gc->parent;
3526 return gc;
3529 MonoGenericContainer *
3530 mono_get_anonymous_container_for_image (MonoImage *image, gboolean is_mvar)
3532 MonoGenericContainer **container_pointer;
3533 if (is_mvar)
3534 container_pointer = &image->anonymous_generic_method_container;
3535 else
3536 container_pointer = &image->anonymous_generic_class_container;
3537 MonoGenericContainer *result = *container_pointer;
3539 // This container has never been created; make it now.
3540 if (!result)
3542 // Note this is never deallocated anywhere-- it exists for the lifetime of the image it's allocated from
3543 result = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
3544 result->owner.image = image;
3545 result->is_anonymous = TRUE;
3546 result->is_method = is_mvar;
3548 // If another thread already made a container, use that and leak this new one.
3549 // (Technically it would currently be safe to just assign instead of CASing.)
3550 MonoGenericContainer *exchange = (MonoGenericContainer *)mono_atomic_cas_ptr ((volatile gpointer *)container_pointer, result, NULL);
3551 if (exchange)
3552 result = exchange;
3554 return result;
3557 #define FAST_GPARAM_CACHE_SIZE 16
3559 static MonoGenericParam*
3560 lookup_anon_gparam (MonoImage *image, MonoGenericContainer *container, gint32 param_num, gboolean is_mvar)
3562 if (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE) {
3563 MonoGenericParam *cache = is_mvar ? image->mvar_gparam_cache_fast : image->var_gparam_cache_fast;
3564 if (!cache)
3565 return NULL;
3566 return &cache[param_num];
3567 } else {
3568 MonoGenericParam key;
3569 memset (&key, 0, sizeof (key));
3570 key.owner = container;
3571 key.num = param_num;
3572 key.gshared_constraint = NULL;
3573 MonoConcurrentHashTable *cache = is_mvar ? image->mvar_gparam_cache : image->var_gparam_cache;
3574 if (!cache)
3575 return NULL;
3576 return (MonoGenericParam*)mono_conc_hashtable_lookup (cache, &key);
3580 static MonoGenericParam*
3581 publish_anon_gparam_fast (MonoImage *image, MonoGenericContainer *container, gint32 param_num)
3583 g_assert (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE);
3584 MonoGenericParam **cache = container->is_method ? &image->mvar_gparam_cache_fast : &image->var_gparam_cache_fast;
3585 if (!*cache) {
3586 mono_image_lock (image);
3587 if (!*cache) {
3588 *cache = (MonoGenericParam*)mono_image_alloc0 (image, sizeof (MonoGenericParam) * FAST_GPARAM_CACHE_SIZE);
3589 for (gint32 i = 0; i < FAST_GPARAM_CACHE_SIZE; ++i) {
3590 MonoGenericParam *param = &(*cache)[i];
3591 param->owner = container;
3592 param->num = i;
3595 mono_image_unlock (image);
3597 return &(*cache)[param_num];
3601 * publish_anon_gparam_slow:
3603 * Publish \p gparam anonymous generic parameter to the anon gparam cache for \p image.
3605 * LOCKING: takes the image lock.
3607 static MonoGenericParam*
3608 publish_anon_gparam_slow (MonoImage *image, MonoGenericParam *gparam)
3610 MonoConcurrentHashTable **cache = gparam->owner->is_method ? &image->mvar_gparam_cache : &image->var_gparam_cache;
3611 if (!*cache) {
3612 mono_image_lock (image);
3613 if (!*cache) {
3614 MonoConcurrentHashTable *ht = mono_conc_hashtable_new ((GHashFunc)mono_metadata_generic_param_hash,
3615 (GEqualFunc) mono_metadata_generic_param_equal);
3616 mono_atomic_store_release (cache, ht);
3618 mono_image_unlock (image);
3620 MonoGenericParam *other = (MonoGenericParam*)mono_conc_hashtable_insert (*cache, gparam, gparam);
3621 // If another thread published first return their param, otherwise return ours.
3622 return other ? other : gparam;
3626 * mono_metadata_create_anon_gparam:
3627 * \param image the MonoImage that owns the anonymous generic parameter
3628 * \param param_num the parameter number
3629 * \param is_mvar TRUE if this is a method generic parameter, FALSE if it's a class generic parameter.
3631 * Returns: a new, or exisisting \c MonoGenericParam for an anonymous generic parameter with the given properties.
3633 * LOCKING: takes the image lock.
3635 MonoGenericParam*
3636 mono_metadata_create_anon_gparam (MonoImage *image, gint32 param_num, gboolean is_mvar)
3638 MonoGenericContainer *container = mono_get_anonymous_container_for_image (image, is_mvar);
3639 MonoGenericParam *gparam = lookup_anon_gparam (image, container, param_num, is_mvar);
3640 if (gparam)
3641 return gparam;
3642 if (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE) {
3643 return publish_anon_gparam_fast (image, container, param_num);
3644 } else {
3645 // Create a candidate generic param and try to insert it in the cache.
3646 // If multiple threads both try to publish the same param, all but one
3647 // will leak, but that's okay.
3648 gparam = (MonoGenericParam*)mono_image_alloc0 (image, sizeof (MonoGenericParam));
3649 gparam->owner = container;
3650 gparam->num = param_num;
3652 return publish_anon_gparam_slow (image, gparam);
3657 * mono_metadata_parse_generic_param:
3658 * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
3659 * see mono_metadata_parse_type_checked() for details.
3660 * Internal routine to parse a generic type parameter.
3661 * LOCKING: Acquires the loader lock
3663 static MonoGenericParam *
3664 mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_container,
3665 MonoTypeEnum type, const char *ptr, const char **rptr, MonoError *error)
3667 int index = mono_metadata_decode_value (ptr, &ptr);
3668 if (rptr)
3669 *rptr = ptr;
3671 error_init (error);
3673 generic_container = select_container (generic_container, type);
3674 if (!generic_container) {
3675 gboolean is_mvar = FALSE;
3676 switch (type)
3678 case MONO_TYPE_VAR:
3679 break;
3680 case MONO_TYPE_MVAR:
3681 is_mvar = TRUE;
3682 break;
3683 default:
3684 g_error ("Cerating generic param object with invalid MonoType"); // This is not a generic param
3687 return mono_metadata_create_anon_gparam (m, index, is_mvar);
3690 if (index >= generic_container->type_argc) {
3691 mono_error_set_bad_image (error, m, "Invalid generic %s parameter index %d, max index is %d",
3692 generic_container->is_method ? "method" : "type",
3693 index, generic_container->type_argc);
3694 return NULL;
3697 //This can't return NULL
3698 return mono_generic_container_get_param (generic_container, index);
3702 * mono_metadata_get_shared_type:
3704 * Return a shared instance of TYPE, if available, NULL otherwise.
3705 * Shared MonoType instances help save memory. Their contents should not be modified
3706 * by the caller. They do not need to be freed as their lifetime is bound by either
3707 * the lifetime of the runtime (builtin types), or the lifetime of the MonoClass
3708 * instance they are embedded in. If they are freed, they should be freed using
3709 * mono_metadata_free_type () instead of g_free ().
3711 MonoType*
3712 mono_metadata_get_shared_type (MonoType *type)
3714 MonoType *cached;
3716 /* No need to use locking since nobody is modifying the hash table */
3717 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type)))
3718 return cached;
3720 switch (type->type){
3721 case MONO_TYPE_CLASS:
3722 case MONO_TYPE_VALUETYPE:
3723 if (type == m_class_get_byval_arg (type->data.klass))
3724 return type;
3725 if (type == m_class_get_this_arg (type->data.klass))
3726 return type;
3727 break;
3728 default:
3729 break;
3732 return NULL;
3735 static gboolean
3736 compare_type_literals (MonoImage *image, int class_type, int type_type, MonoError *error)
3738 error_init (error);
3740 /* _byval_arg.type can be zero if we're decoding a type that references a class been loading.
3741 * See mcs/test/gtest-440. and #650936.
3742 * FIXME This better be moved to the metadata verifier as it can catch more cases.
3744 if (!class_type)
3745 return TRUE;
3746 /* NET 1.1 assemblies might encode string and object in a denormalized way.
3747 * See #675464.
3749 if (class_type == type_type)
3750 return TRUE;
3752 if (type_type == MONO_TYPE_CLASS) {
3753 if (class_type == MONO_TYPE_STRING || class_type == MONO_TYPE_OBJECT)
3754 return TRUE;
3755 //XXX stringify this argument
3756 mono_error_set_bad_image (error, image, "Expected reference type but got type kind %d", class_type);
3757 return FALSE;
3760 g_assert (type_type == MONO_TYPE_VALUETYPE);
3761 switch (class_type) {
3762 case MONO_TYPE_BOOLEAN:
3763 case MONO_TYPE_CHAR:
3764 case MONO_TYPE_I1:
3765 case MONO_TYPE_U1:
3766 case MONO_TYPE_I2:
3767 case MONO_TYPE_U2:
3768 case MONO_TYPE_I4:
3769 case MONO_TYPE_U4:
3770 case MONO_TYPE_I8:
3771 case MONO_TYPE_U8:
3772 case MONO_TYPE_R4:
3773 case MONO_TYPE_R8:
3774 case MONO_TYPE_I:
3775 case MONO_TYPE_U:
3776 case MONO_TYPE_CLASS:
3777 return TRUE;
3778 default:
3779 //XXX stringify this argument
3780 mono_error_set_bad_image (error, image, "Expected value type but got type kind %d", class_type);
3781 return FALSE;
3785 static gboolean
3786 verify_var_type_and_container (MonoImage *image, int var_type, MonoGenericContainer *container, MonoError *error)
3788 error_init (error);
3789 if (var_type == MONO_TYPE_MVAR) {
3790 if (!container->is_method) { //MVAR and a method container
3791 mono_error_set_bad_image (error, image, "MVAR parsed in a context without a method container");
3792 return FALSE;
3794 } else {
3795 if (!(!container->is_method || //VAR and class container
3796 (container->is_method && container->parent))) { //VAR and method container with parent
3797 mono_error_set_bad_image (error, image, "VAR parsed in a context without a class container");
3798 return FALSE;
3801 return TRUE;
3805 * do_mono_metadata_parse_type:
3806 * @type: MonoType to be filled in with the return value
3807 * @m: image context
3808 * @generic_context: generics_context
3809 * @transient: whenever to allocate data from the heap
3810 * @ptr: pointer to the encoded type
3811 * @rptr: pointer where the end of the encoded type is saved
3813 * Internal routine used to "fill" the contents of @type from an
3814 * allocated pointer. This is done this way to avoid doing too
3815 * many mini-allocations (particularly for the MonoFieldType which
3816 * most of the time is just a MonoType, but sometimes might be augmented).
3818 * This routine is used by mono_metadata_parse_type and
3819 * mono_metadata_parse_field_type
3821 * This extracts a Type as specified in Partition II (22.2.12)
3823 * Returns: FALSE if the type could not be loaded
3825 static gboolean
3826 do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container,
3827 gboolean transient, const char *ptr, const char **rptr, MonoError *error)
3829 error_init (error);
3831 type->type = (MonoTypeEnum)mono_metadata_decode_value (ptr, &ptr);
3833 switch (type->type){
3834 case MONO_TYPE_VOID:
3835 case MONO_TYPE_BOOLEAN:
3836 case MONO_TYPE_CHAR:
3837 case MONO_TYPE_I1:
3838 case MONO_TYPE_U1:
3839 case MONO_TYPE_I2:
3840 case MONO_TYPE_U2:
3841 case MONO_TYPE_I4:
3842 case MONO_TYPE_U4:
3843 case MONO_TYPE_I8:
3844 case MONO_TYPE_U8:
3845 case MONO_TYPE_R4:
3846 case MONO_TYPE_R8:
3847 case MONO_TYPE_I:
3848 case MONO_TYPE_U:
3849 case MONO_TYPE_STRING:
3850 case MONO_TYPE_OBJECT:
3851 case MONO_TYPE_TYPEDBYREF:
3852 break;
3853 case MONO_TYPE_VALUETYPE:
3854 case MONO_TYPE_CLASS: {
3855 guint32 token;
3856 MonoClass *klass;
3857 token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr);
3858 klass = mono_class_get_checked (m, token, error);
3859 type->data.klass = klass;
3860 if (!klass)
3861 return FALSE;
3863 if (!compare_type_literals (m, m_class_get_byval_arg (klass)->type, type->type, error))
3864 return FALSE;
3866 break;
3868 case MONO_TYPE_SZARRAY: {
3869 MonoType *etype = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
3870 if (!etype)
3871 return FALSE;
3873 type->data.klass = mono_class_from_mono_type_internal (etype);
3875 if (transient)
3876 mono_metadata_free_type (etype);
3878 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.
3879 break;
3881 case MONO_TYPE_PTR: {
3882 type->data.type = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
3883 if (!type->data.type)
3884 return FALSE;
3885 break;
3887 case MONO_TYPE_FNPTR: {
3888 type->data.method = mono_metadata_parse_method_signature_full (m, container, 0, ptr, &ptr, error);
3889 if (!type->data.method)
3890 return FALSE;
3891 break;
3893 case MONO_TYPE_ARRAY: {
3894 type->data.array = mono_metadata_parse_array_internal (m, container, transient, ptr, &ptr, error);
3895 if (!type->data.array)
3896 return FALSE;
3897 break;
3899 case MONO_TYPE_MVAR:
3900 case MONO_TYPE_VAR: {
3901 if (container && !verify_var_type_and_container (m, type->type, container, error))
3902 return FALSE;
3904 type->data.generic_param = mono_metadata_parse_generic_param (m, container, type->type, ptr, &ptr, error);
3905 if (!type->data.generic_param)
3906 return FALSE;
3908 break;
3910 case MONO_TYPE_GENERICINST: {
3911 if (!do_mono_metadata_parse_generic_class (type, m, container, ptr, &ptr, error))
3912 return FALSE;
3913 break;
3915 default:
3916 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);
3917 return FALSE;
3920 if (rptr)
3921 *rptr = ptr;
3922 return TRUE;
3926 * mono_metadata_free_type:
3927 * \param type type to free
3929 * Free the memory allocated for type \p type which is allocated on the heap.
3931 void
3932 mono_metadata_free_type (MonoType *type)
3934 if (type >= builtin_types && type < builtin_types + NBUILTIN_TYPES ())
3935 return;
3937 switch (type->type){
3938 case MONO_TYPE_OBJECT:
3939 case MONO_TYPE_STRING:
3940 if (!type->data.klass)
3941 break;
3942 /* fall through */
3943 case MONO_TYPE_CLASS:
3944 case MONO_TYPE_VALUETYPE:
3945 if (type == m_class_get_byval_arg (type->data.klass) || type == m_class_get_this_arg (type->data.klass))
3946 return;
3947 break;
3948 case MONO_TYPE_PTR:
3949 mono_metadata_free_type (type->data.type);
3950 break;
3951 case MONO_TYPE_FNPTR:
3952 mono_metadata_free_method_signature (type->data.method);
3953 break;
3954 case MONO_TYPE_ARRAY:
3955 mono_metadata_free_array (type->data.array);
3956 break;
3957 default:
3958 break;
3961 g_free (type);
3964 #if 0
3965 static void
3966 hex_dump (const char *buffer, int base, int count)
3968 int show_header = 1;
3969 int i;
3971 if (count < 0){
3972 count = -count;
3973 show_header = 0;
3976 for (i = 0; i < count; i++){
3977 if (show_header)
3978 if ((i % 16) == 0)
3979 printf ("\n0x%08x: ", (unsigned char) base + i);
3981 printf ("%02x ", (unsigned char) (buffer [i]));
3983 fflush (stdout);
3985 #endif
3987 /**
3988 * @ptr: Points to the beginning of the Section Data (25.3)
3990 static MonoExceptionClause*
3991 parse_section_data (MonoImage *m, int *num_clauses, const unsigned char *ptr, MonoError *error)
3993 unsigned char sect_data_flags;
3994 int is_fat;
3995 guint32 sect_data_len;
3996 MonoExceptionClause* clauses = NULL;
3998 error_init (error);
4000 while (1) {
4001 /* align on 32-bit boundary */
4002 ptr = dword_align (ptr);
4003 sect_data_flags = *ptr;
4004 ptr++;
4006 is_fat = sect_data_flags & METHOD_HEADER_SECTION_FAT_FORMAT;
4007 if (is_fat) {
4008 sect_data_len = (ptr [2] << 16) | (ptr [1] << 8) | ptr [0];
4009 ptr += 3;
4010 } else {
4011 sect_data_len = ptr [0];
4012 ++ptr;
4015 if (sect_data_flags & METHOD_HEADER_SECTION_EHTABLE) {
4016 const unsigned char *p = dword_align (ptr);
4017 int i;
4018 *num_clauses = is_fat ? sect_data_len / 24: sect_data_len / 12;
4019 /* we could just store a pointer if we don't need to byteswap */
4020 clauses = (MonoExceptionClause *)g_malloc0 (sizeof (MonoExceptionClause) * (*num_clauses));
4021 for (i = 0; i < *num_clauses; ++i) {
4022 MonoExceptionClause *ec = &clauses [i];
4023 guint32 tof_value;
4024 if (is_fat) {
4025 ec->flags = read32 (p);
4026 ec->try_offset = read32 (p + 4);
4027 ec->try_len = read32 (p + 8);
4028 ec->handler_offset = read32 (p + 12);
4029 ec->handler_len = read32 (p + 16);
4030 tof_value = read32 (p + 20);
4031 p += 24;
4032 } else {
4033 ec->flags = read16 (p);
4034 ec->try_offset = read16 (p + 2);
4035 ec->try_len = *(p + 4);
4036 ec->handler_offset = read16 (p + 5);
4037 ec->handler_len = *(p + 7);
4038 tof_value = read32 (p + 8);
4039 p += 12;
4041 if (ec->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4042 ec->data.filter_offset = tof_value;
4043 } else if (ec->flags == MONO_EXCEPTION_CLAUSE_NONE) {
4044 ec->data.catch_class = NULL;
4045 if (tof_value) {
4046 ec->data.catch_class = mono_class_get_checked (m, tof_value, error);
4047 if (!is_ok (error)) {
4048 g_free (clauses);
4049 return NULL;
4052 } else {
4053 ec->data.catch_class = NULL;
4055 /* g_print ("try %d: %x %04x-%04x %04x\n", i, ec->flags, ec->try_offset, ec->try_offset+ec->try_len, ec->try_len); */
4059 if (sect_data_flags & METHOD_HEADER_SECTION_MORE_SECTS)
4060 ptr += sect_data_len - 4; /* LAMESPEC: it seems the size includes the header */
4061 else
4062 return clauses;
4067 * mono_method_get_header_summary:
4068 * @method: The method to get the header.
4069 * @summary: Where to store the header
4072 * Returns: TRUE if the header was properly decoded.
4074 gboolean
4075 mono_method_get_header_summary (MonoMethod *method, MonoMethodHeaderSummary *summary)
4077 int idx;
4078 guint32 rva;
4079 MonoImage* img;
4080 const char *ptr;
4081 unsigned char flags, format;
4082 guint16 fat_flags;
4083 ERROR_DECL (error);
4085 /*Only the GMD has a pointer to the metadata.*/
4086 while (method->is_inflated)
4087 method = ((MonoMethodInflated*)method)->declaring;
4089 summary->code = NULL;
4090 summary->code_size = 0;
4091 summary->max_stack = 0;
4092 summary->has_clauses = FALSE;
4093 summary->has_locals = FALSE;
4095 /*FIXME extract this into a MACRO and share it with mono_method_get_header*/
4096 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))
4097 return FALSE;
4099 if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
4100 MonoMethodHeader *header = ((MonoMethodWrapper *)method)->header;
4101 if (!header)
4102 return FALSE;
4103 summary->code = header->code;
4104 summary->code_size = header->code_size;
4105 summary->max_stack = header->max_stack;
4106 summary->has_clauses = header->num_clauses > 0;
4107 summary->has_locals = header->num_locals > 0;
4108 return TRUE;
4112 idx = mono_metadata_token_index (method->token);
4113 img = m_class_get_image (method->klass);
4114 rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
4116 /*We must run the verifier since we'll be decoding it.*/
4117 if (!mono_verifier_verify_method_header (img, rva, error)) {
4118 mono_error_cleanup (error);
4119 return FALSE;
4122 ptr = mono_image_rva_map (img, rva);
4123 if (!ptr)
4124 return FALSE;
4126 flags = *(const unsigned char *)ptr;
4127 format = flags & METHOD_HEADER_FORMAT_MASK;
4129 switch (format) {
4130 case METHOD_HEADER_TINY_FORMAT:
4131 ptr++;
4132 summary->max_stack = 8;
4133 summary->code = (unsigned char *) ptr;
4134 summary->code_size = flags >> 2;
4135 break;
4136 case METHOD_HEADER_FAT_FORMAT:
4137 fat_flags = read16 (ptr);
4138 ptr += 2;
4139 summary->max_stack = read16 (ptr);
4140 ptr += 2;
4141 summary->code_size = read32 (ptr);
4142 ptr += 4;
4143 summary->has_locals = !!read32 (ptr);
4144 ptr += 4;
4145 if (fat_flags & METHOD_HEADER_MORE_SECTS)
4146 summary->has_clauses = TRUE;
4147 summary->code = (unsigned char *) ptr;
4148 break;
4149 default:
4150 return FALSE;
4152 return TRUE;
4156 * mono_metadata_parse_mh_full:
4157 * @m: metadata context
4158 * @generic_context: generics context
4159 * @ptr: pointer to the method header.
4161 * Decode the method header at @ptr, including pointer to the IL code,
4162 * info about local variables and optional exception tables.
4163 * This is a Mono runtime internal function.
4165 * LOCKING: Acquires the loader lock.
4167 * Returns: a transient MonoMethodHeader allocated from the heap.
4169 MonoMethodHeader *
4170 mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, const char *ptr, MonoError *error)
4172 MonoMethodHeader *mh = NULL;
4173 unsigned char flags = *(const unsigned char *) ptr;
4174 unsigned char format = flags & METHOD_HEADER_FORMAT_MASK;
4175 guint16 fat_flags;
4176 guint32 local_var_sig_tok, max_stack, code_size, init_locals;
4177 const unsigned char *code;
4178 MonoExceptionClause* clauses = NULL;
4179 int num_clauses = 0;
4180 MonoTableInfo *t = &m->tables [MONO_TABLE_STANDALONESIG];
4181 guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
4183 error_init (error);
4185 if (!ptr) {
4186 mono_error_set_bad_image (error, m, "Method header with null pointer");
4187 return NULL;
4190 switch (format) {
4191 case METHOD_HEADER_TINY_FORMAT:
4192 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER);
4193 ptr++;
4194 mh->max_stack = 8;
4195 mh->is_transient = TRUE;
4196 local_var_sig_tok = 0;
4197 mh->code_size = flags >> 2;
4198 mh->code = (unsigned char*)ptr;
4199 return mh;
4200 case METHOD_HEADER_FAT_FORMAT:
4201 fat_flags = read16 (ptr);
4202 ptr += 2;
4203 max_stack = read16 (ptr);
4204 ptr += 2;
4205 code_size = read32 (ptr);
4206 ptr += 4;
4207 local_var_sig_tok = read32 (ptr);
4208 ptr += 4;
4210 if (fat_flags & METHOD_HEADER_INIT_LOCALS)
4211 init_locals = 1;
4212 else
4213 init_locals = 0;
4215 code = (unsigned char*)ptr;
4217 if (!(fat_flags & METHOD_HEADER_MORE_SECTS))
4218 break;
4221 * There are more sections
4223 ptr = (char*)code + code_size;
4224 break;
4225 default:
4226 mono_error_set_bad_image (error, m, "Invalid method header format %d", format);
4227 return NULL;
4230 if (local_var_sig_tok) {
4231 int idx = (local_var_sig_tok & 0xffffff)-1;
4232 if (idx >= t->rows || idx < 0) {
4233 mono_error_set_bad_image (error, m, "Invalid method header local vars signature token 0x%8x", idx);
4234 goto fail;
4236 mono_metadata_decode_row (t, idx, cols, 1);
4238 if (!mono_verifier_verify_standalone_signature (m, cols [MONO_STAND_ALONE_SIGNATURE], error))
4239 goto fail;
4241 if (fat_flags & METHOD_HEADER_MORE_SECTS) {
4242 clauses = parse_section_data (m, &num_clauses, (const unsigned char*)ptr, error);
4243 goto_if_nok (error, fail);
4245 if (local_var_sig_tok) {
4246 const char *locals_ptr;
4247 int len=0, i;
4249 locals_ptr = mono_metadata_blob_heap (m, cols [MONO_STAND_ALONE_SIGNATURE]);
4250 mono_metadata_decode_blob_size (locals_ptr, &locals_ptr);
4251 if (*locals_ptr != 0x07)
4252 g_warning ("wrong signature for locals blob");
4253 locals_ptr++;
4254 len = mono_metadata_decode_value (locals_ptr, &locals_ptr);
4255 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + len * sizeof (MonoType*) + num_clauses * sizeof (MonoExceptionClause));
4256 mh->num_locals = len;
4257 for (i = 0; i < len; ++i) {
4258 mh->locals [i] = mono_metadata_parse_type_internal (m, container, 0, TRUE, locals_ptr, &locals_ptr, error);
4259 goto_if_nok (error, fail);
4261 } else {
4262 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + num_clauses * sizeof (MonoExceptionClause));
4264 mh->code = code;
4265 mh->code_size = code_size;
4266 mh->max_stack = max_stack;
4267 mh->is_transient = TRUE;
4268 mh->init_locals = init_locals;
4269 if (clauses) {
4270 MonoExceptionClause* clausesp = (MonoExceptionClause*)&mh->locals [mh->num_locals];
4271 memcpy (clausesp, clauses, num_clauses * sizeof (MonoExceptionClause));
4272 g_free (clauses);
4273 mh->clauses = clausesp;
4274 mh->num_clauses = num_clauses;
4276 return mh;
4277 fail:
4278 g_free (clauses);
4279 g_free (mh);
4280 return NULL;
4285 * mono_metadata_parse_mh:
4286 * \param generic_context generics context
4287 * \param ptr pointer to the method header.
4289 * Decode the method header at \p ptr, including pointer to the IL code,
4290 * info about local variables and optional exception tables.
4292 * \returns a transient \c MonoMethodHeader allocated from the heap.
4294 MonoMethodHeader *
4295 mono_metadata_parse_mh (MonoImage *m, const char *ptr)
4297 ERROR_DECL (error);
4298 MonoMethodHeader *header = mono_metadata_parse_mh_full (m, NULL, ptr, error);
4299 mono_error_cleanup (error);
4300 return header;
4304 * mono_metadata_free_mh:
4305 * \param mh a method header
4307 * Free the memory allocated for the method header.
4309 void
4310 mono_metadata_free_mh (MonoMethodHeader *mh)
4312 int i;
4314 /* If it is not transient it means it's part of a wrapper method,
4315 * or a SRE-generated method, so the lifetime in that case is
4316 * dictated by the method's own lifetime
4318 if (mh && mh->is_transient) {
4319 for (i = 0; i < mh->num_locals; ++i)
4320 mono_metadata_free_type (mh->locals [i]);
4321 g_free (mh);
4326 * mono_method_header_get_code:
4327 * \param header a \c MonoMethodHeader pointer
4328 * \param code_size memory location for returning the code size
4329 * \param max_stack memory location for returning the max stack
4331 * Method header accessor to retreive info about the IL code properties:
4332 * a pointer to the IL code itself, the size of the code and the max number
4333 * of stack slots used by the code.
4335 * \returns pointer to the IL code represented by the method header.
4337 const unsigned char*
4338 mono_method_header_get_code (MonoMethodHeader *header, guint32* code_size, guint32* max_stack)
4340 if (code_size)
4341 *code_size = header->code_size;
4342 if (max_stack)
4343 *max_stack = header->max_stack;
4344 return header->code;
4348 * mono_method_header_get_locals:
4349 * \param header a \c MonoMethodHeader pointer
4350 * \param num_locals memory location for returning the number of local variables
4351 * \param init_locals memory location for returning the init_locals flag
4353 * Method header accessor to retreive info about the local variables:
4354 * an array of local types, the number of locals and whether the locals
4355 * are supposed to be initialized to 0 on method entry
4357 * \returns pointer to an array of types of the local variables
4359 MonoType**
4360 mono_method_header_get_locals (MonoMethodHeader *header, guint32* num_locals, gboolean *init_locals)
4362 if (num_locals)
4363 *num_locals = header->num_locals;
4364 if (init_locals)
4365 *init_locals = header->init_locals;
4366 return header->locals;
4370 * mono_method_header_get_num_clauses:
4371 * @header: a MonoMethodHeader pointer
4373 * Method header accessor to retreive the number of exception clauses.
4375 * Returns: the number of exception clauses present
4378 mono_method_header_get_num_clauses (MonoMethodHeader *header)
4380 return header->num_clauses;
4384 * mono_method_header_get_clauses:
4385 * \param header a \c MonoMethodHeader pointer
4386 * \param method \c MonoMethod the header belongs to
4387 * \param iter pointer to a iterator
4388 * \param clause pointer to a \c MonoExceptionClause structure which will be filled with the info
4390 * Get the info about the exception clauses in the method. Set \c *iter to NULL to
4391 * initiate the iteration, then call the method repeatedly until it returns FALSE.
4392 * At each iteration, the structure pointed to by clause if filled with the
4393 * exception clause information.
4395 * \returns TRUE if clause was filled with info, FALSE if there are no more exception
4396 * clauses.
4399 mono_method_header_get_clauses (MonoMethodHeader *header, MonoMethod *method, gpointer *iter, MonoExceptionClause *clause)
4401 MonoExceptionClause *sc;
4402 /* later we'll be able to use this interface to parse the clause info on demand,
4403 * without allocating anything.
4405 if (!iter || !header->num_clauses)
4406 return FALSE;
4407 if (!*iter) {
4408 *iter = sc = header->clauses;
4409 *clause = *sc;
4410 return TRUE;
4412 sc = (MonoExceptionClause *)*iter;
4413 sc++;
4414 if (sc < header->clauses + header->num_clauses) {
4415 *iter = sc;
4416 *clause = *sc;
4417 return TRUE;
4419 return FALSE;
4423 * mono_metadata_parse_field_type:
4424 * \param m metadata context to extract information from
4425 * \param ptr pointer to the field signature
4426 * \param rptr pointer updated to match the end of the decoded stream
4428 * Parses the field signature, and returns the type information for it.
4430 * \returns The \c MonoType that was extracted from \p ptr .
4432 MonoType *
4433 mono_metadata_parse_field_type (MonoImage *m, short field_flags, const char *ptr, const char **rptr)
4435 ERROR_DECL (error);
4436 MonoType * type = mono_metadata_parse_type_internal (m, NULL, field_flags, FALSE, ptr, rptr, error);
4437 mono_error_cleanup (error);
4438 return type;
4442 * mono_metadata_parse_param:
4443 * \param m metadata context to extract information from
4444 * \param ptr pointer to the param signature
4445 * \param rptr pointer updated to match the end of the decoded stream
4447 * Parses the param signature, and returns the type information for it.
4449 * \returns The \c MonoType that was extracted from \p ptr .
4451 MonoType *
4452 mono_metadata_parse_param (MonoImage *m, const char *ptr, const char **rptr)
4454 ERROR_DECL (error);
4455 MonoType * type = mono_metadata_parse_type_internal (m, NULL, 0, FALSE, ptr, rptr, error);
4456 mono_error_cleanup (error);
4457 return type;
4461 * mono_metadata_token_from_dor:
4462 * \param dor_token A \c TypeDefOrRef coded index
4464 * \p dor_token is a \c TypeDefOrRef coded index: it contains either
4465 * a \c TypeDef, \c TypeRef or \c TypeSpec in the lower bits, and the upper
4466 * bits contain an index into the table.
4468 * \returns an expanded token
4470 guint32
4471 mono_metadata_token_from_dor (guint32 dor_index)
4473 guint32 table, idx;
4475 table = dor_index & 0x03;
4476 idx = dor_index >> 2;
4478 switch (table){
4479 case 0: /* TypeDef */
4480 return MONO_TOKEN_TYPE_DEF | idx;
4481 case 1: /* TypeRef */
4482 return MONO_TOKEN_TYPE_REF | idx;
4483 case 2: /* TypeSpec */
4484 return MONO_TOKEN_TYPE_SPEC | idx;
4485 default:
4486 g_assert_not_reached ();
4489 return 0;
4493 * We use this to pass context information to the row locator
4495 typedef struct {
4496 int idx; /* The index that we are trying to locate */
4497 int col_idx; /* The index in the row where idx may be stored */
4498 MonoTableInfo *t; /* pointer to the table */
4499 guint32 result;
4500 } locator_t;
4503 * How the row locator works.
4505 * Table A
4506 * ___|___
4507 * ___|___ Table B
4508 * ___|___------> _______
4509 * ___|___ _______
4511 * A column in the rows of table A references an index in table B.
4512 * For example A may be the TYPEDEF table and B the METHODDEF table.
4514 * Given an index in table B we want to get the row in table A
4515 * where the column n references our index in B.
4517 * In the locator_t structure:
4518 * t is table A
4519 * col_idx is the column number
4520 * index is the index in table B
4521 * result will be the index in table A
4523 * Examples:
4524 * Table A Table B column (in table A)
4525 * TYPEDEF METHODDEF MONO_TYPEDEF_METHOD_LIST
4526 * TYPEDEF FIELD MONO_TYPEDEF_FIELD_LIST
4527 * PROPERTYMAP PROPERTY MONO_PROPERTY_MAP_PROPERTY_LIST
4528 * INTERFIMPL TYPEDEF MONO_INTERFACEIMPL_CLASS
4529 * METHODSEM PROPERTY ASSOCIATION (encoded index)
4531 * Note that we still don't support encoded indexes.
4534 static int
4535 typedef_locator (const void *a, const void *b)
4537 locator_t *loc = (locator_t *) a;
4538 const char *bb = (const char *) b;
4539 int typedef_index = (bb - loc->t->base) / loc->t->row_size;
4540 guint32 col, col_next;
4542 col = mono_metadata_decode_row_col (loc->t, typedef_index, loc->col_idx);
4544 if (loc->idx < col)
4545 return -1;
4548 * Need to check that the next row is valid.
4550 if (typedef_index + 1 < loc->t->rows) {
4551 col_next = mono_metadata_decode_row_col (loc->t, typedef_index + 1, loc->col_idx);
4552 if (loc->idx >= col_next)
4553 return 1;
4555 if (col == col_next)
4556 return 1;
4559 loc->result = typedef_index;
4561 return 0;
4564 static int
4565 table_locator (const void *a, const void *b)
4567 locator_t *loc = (locator_t *) a;
4568 const char *bb = (const char *) b;
4569 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4570 guint32 col;
4572 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4574 if (loc->idx == col) {
4575 loc->result = table_index;
4576 return 0;
4578 if (loc->idx < col)
4579 return -1;
4580 else
4581 return 1;
4584 static int
4585 declsec_locator (const void *a, const void *b)
4587 locator_t *loc = (locator_t *) a;
4588 const char *bb = (const char *) b;
4589 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4590 guint32 col;
4592 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4594 if (loc->idx == col) {
4595 loc->result = table_index;
4596 return 0;
4598 if (loc->idx < col)
4599 return -1;
4600 else
4601 return 1;
4605 * search_ptr_table:
4607 * Return the 1-based row index in TABLE, which must be one of the *Ptr tables,
4608 * which contains IDX.
4610 static guint32
4611 search_ptr_table (MonoImage *image, int table, int idx)
4613 MonoTableInfo *ptrdef = &image->tables [table];
4614 int i;
4616 /* Use a linear search to find our index in the table */
4617 for (i = 0; i < ptrdef->rows; i ++)
4618 /* All the Ptr tables have the same structure */
4619 if (mono_metadata_decode_row_col (ptrdef, i, 0) == idx)
4620 break;
4622 if (i < ptrdef->rows)
4623 return i + 1;
4624 else
4625 return idx;
4629 * mono_metadata_typedef_from_field:
4630 * \param meta metadata context
4631 * \param index FieldDef token
4633 * \returns the 1-based index into the \c TypeDef table of the type that
4634 * declared the field described by \p index, or 0 if not found.
4636 guint32
4637 mono_metadata_typedef_from_field (MonoImage *meta, guint32 index)
4639 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4640 locator_t loc;
4642 if (!tdef->base)
4643 return 0;
4645 loc.idx = mono_metadata_token_index (index);
4646 loc.col_idx = MONO_TYPEDEF_FIELD_LIST;
4647 loc.t = tdef;
4649 if (meta->uncompressed_metadata)
4650 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
4652 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4653 return 0;
4655 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4656 return loc.result + 1;
4660 * mono_metadata_typedef_from_method:
4661 * \param meta metadata context
4662 * \param index \c MethodDef token
4663 * \returns the 1-based index into the \c TypeDef table of the type that
4664 * declared the method described by \p index. 0 if not found.
4666 guint32
4667 mono_metadata_typedef_from_method (MonoImage *meta, guint32 index)
4669 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4670 locator_t loc;
4672 if (!tdef->base)
4673 return 0;
4675 loc.idx = mono_metadata_token_index (index);
4676 loc.col_idx = MONO_TYPEDEF_METHOD_LIST;
4677 loc.t = tdef;
4679 if (meta->uncompressed_metadata)
4680 loc.idx = search_ptr_table (meta, MONO_TABLE_METHOD_POINTER, loc.idx);
4682 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4683 return 0;
4685 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4686 return loc.result + 1;
4690 * mono_metadata_interfaces_from_typedef_full:
4691 * \param meta metadata context
4692 * \param index typedef token
4693 * \param interfaces Out parameter used to store the interface array
4694 * \param count Out parameter used to store the number of interfaces
4695 * \param heap_alloc_result if TRUE the result array will be \c g_malloc'd
4696 * \param context The generic context
4697 * \param error set on error
4699 * The array of interfaces that the \p index typedef token implements is returned in
4700 * \p interfaces. The number of elements in the array is returned in \p count.
4702 * \returns \c TRUE on success, \c FALSE on failure and sets \p error.
4704 gboolean
4705 mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, MonoClass ***interfaces, guint *count, gboolean heap_alloc_result, MonoGenericContext *context, MonoError *error)
4707 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_INTERFACEIMPL];
4708 locator_t loc;
4709 guint32 start, pos;
4710 guint32 cols [MONO_INTERFACEIMPL_SIZE];
4711 MonoClass **result;
4713 *interfaces = NULL;
4714 *count = 0;
4716 error_init (error);
4718 if (!tdef->base)
4719 return TRUE;
4721 loc.idx = mono_metadata_token_index (index);
4722 loc.col_idx = MONO_INTERFACEIMPL_CLASS;
4723 loc.t = tdef;
4725 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4726 return TRUE;
4728 start = loc.result;
4730 * We may end up in the middle of the rows...
4732 while (start > 0) {
4733 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_INTERFACEIMPL_CLASS))
4734 start--;
4735 else
4736 break;
4738 pos = start;
4739 while (pos < tdef->rows) {
4740 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4741 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4742 break;
4743 ++pos;
4746 if (heap_alloc_result)
4747 result = g_new0 (MonoClass*, pos - start);
4748 else
4749 result = (MonoClass **)mono_image_alloc0 (meta, sizeof (MonoClass*) * (pos - start));
4751 pos = start;
4752 while (pos < tdef->rows) {
4753 MonoClass *iface;
4755 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4756 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4757 break;
4758 iface = mono_class_get_and_inflate_typespec_checked (
4759 meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context, error);
4760 if (iface == NULL)
4761 return FALSE;
4762 result [pos - start] = iface;
4763 ++pos;
4765 *count = pos - start;
4766 *interfaces = result;
4767 return TRUE;
4771 * mono_metadata_interfaces_from_typedef:
4772 * \param meta metadata context
4773 * \param index typedef token
4774 * \param count Out parameter used to store the number of interfaces
4776 * The array of interfaces that the \p index typedef token implements is returned in
4777 * \p interfaces. The number of elements in the array is returned in \p count. The returned
4778 * array is allocated with \c g_malloc and the caller must free it.
4780 * LOCKING: Acquires the loader lock .
4782 * \returns the interface array on success, NULL on failure.
4784 MonoClass**
4785 mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *count)
4787 ERROR_DECL (error);
4788 MonoClass **interfaces = NULL;
4789 gboolean rv;
4791 rv = mono_metadata_interfaces_from_typedef_full (meta, index, &interfaces, count, TRUE, NULL, error);
4792 mono_error_assert_ok (error);
4793 if (rv)
4794 return interfaces;
4795 else
4796 return NULL;
4800 * mono_metadata_nested_in_typedef:
4801 * \param meta metadata context
4802 * \param index typedef token
4803 * \returns the 1-based index into the TypeDef table of the type
4804 * where the type described by \p index is nested.
4805 * Returns 0 if \p index describes a non-nested type.
4807 guint32
4808 mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index)
4810 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
4811 locator_t loc;
4813 if (!tdef->base)
4814 return 0;
4816 loc.idx = mono_metadata_token_index (index);
4817 loc.col_idx = MONO_NESTED_CLASS_NESTED;
4818 loc.t = tdef;
4820 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4821 return 0;
4823 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4824 return mono_metadata_decode_row_col (tdef, loc.result, MONO_NESTED_CLASS_ENCLOSING) | MONO_TOKEN_TYPE_DEF;
4828 * mono_metadata_nesting_typedef:
4829 * \param meta metadata context
4830 * \param index typedef token
4831 * \returns the 1-based index into the \c TypeDef table of the first type
4832 * that is nested inside the type described by \p index. The search starts at
4833 * \p start_index. Returns 0 if no such type is found.
4835 guint32
4836 mono_metadata_nesting_typedef (MonoImage *meta, guint32 index, guint32 start_index)
4838 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
4839 guint32 start;
4840 guint32 class_index = mono_metadata_token_index (index);
4842 if (!tdef->base)
4843 return 0;
4845 start = start_index;
4847 while (start <= tdef->rows) {
4848 if (class_index == mono_metadata_decode_row_col (tdef, start - 1, MONO_NESTED_CLASS_ENCLOSING))
4849 break;
4850 else
4851 start++;
4854 if (start > tdef->rows)
4855 return 0;
4856 else
4857 return start;
4861 * mono_metadata_packing_from_typedef:
4862 * \param meta metadata context
4863 * \param index token representing a type
4864 * \returns the info stored in the \c ClassLayout table for the given typedef token
4865 * into the \p packing and \p size pointers.
4866 * Returns 0 if the info is not found.
4868 guint32
4869 mono_metadata_packing_from_typedef (MonoImage *meta, guint32 index, guint32 *packing, guint32 *size)
4871 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CLASSLAYOUT];
4872 locator_t loc;
4873 guint32 cols [MONO_CLASS_LAYOUT_SIZE];
4875 if (!tdef->base)
4876 return 0;
4878 loc.idx = mono_metadata_token_index (index);
4879 loc.col_idx = MONO_CLASS_LAYOUT_PARENT;
4880 loc.t = tdef;
4882 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4883 return 0;
4885 mono_metadata_decode_row (tdef, loc.result, cols, MONO_CLASS_LAYOUT_SIZE);
4886 if (packing)
4887 *packing = cols [MONO_CLASS_LAYOUT_PACKING_SIZE];
4888 if (size)
4889 *size = cols [MONO_CLASS_LAYOUT_CLASS_SIZE];
4891 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4892 return loc.result + 1;
4896 * mono_metadata_custom_attrs_from_index:
4897 * \param meta metadata context
4898 * \param index token representing the parent
4899 * \returns: the 1-based index into the \c CustomAttribute table of the first
4900 * attribute which belongs to the metadata object described by \p index.
4901 * Returns 0 if no such attribute is found.
4903 guint32
4904 mono_metadata_custom_attrs_from_index (MonoImage *meta, guint32 index)
4906 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CUSTOMATTRIBUTE];
4907 locator_t loc;
4909 if (!tdef->base)
4910 return 0;
4912 loc.idx = index;
4913 loc.col_idx = MONO_CUSTOM_ATTR_PARENT;
4914 loc.t = tdef;
4916 /* FIXME: Index translation */
4918 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4919 return 0;
4921 /* Find the first entry by searching backwards */
4922 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_CUSTOM_ATTR_PARENT) == index))
4923 loc.result --;
4925 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4926 return loc.result + 1;
4930 * mono_metadata_declsec_from_index:
4931 * \param meta metadata context
4932 * \param index token representing the parent
4933 * \returns the 0-based index into the \c DeclarativeSecurity table of the first
4934 * attribute which belongs to the metadata object described by \p index.
4935 * Returns \c -1 if no such attribute is found.
4937 guint32
4938 mono_metadata_declsec_from_index (MonoImage *meta, guint32 index)
4940 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_DECLSECURITY];
4941 locator_t loc;
4943 if (!tdef->base)
4944 return -1;
4946 loc.idx = index;
4947 loc.col_idx = MONO_DECL_SECURITY_PARENT;
4948 loc.t = tdef;
4950 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, declsec_locator))
4951 return -1;
4953 /* Find the first entry by searching backwards */
4954 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_DECL_SECURITY_PARENT) == index))
4955 loc.result --;
4957 return loc.result;
4961 * mono_metadata_localscope_from_methoddef:
4962 * @meta: metadata context
4963 * @index: methoddef index
4965 * Returns: the 1-based index into the LocalScope table of the first
4966 * scope which belongs to the method described by @index.
4967 * Returns 0 if no such row is found.
4969 guint32
4970 mono_metadata_localscope_from_methoddef (MonoImage *meta, guint32 index)
4972 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_LOCALSCOPE];
4973 locator_t loc;
4975 if (!tdef->base)
4976 return 0;
4978 loc.idx = index;
4979 loc.col_idx = MONO_LOCALSCOPE_METHOD;
4980 loc.t = tdef;
4982 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4983 return 0;
4985 /* Find the first entry by searching backwards */
4986 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_LOCALSCOPE_METHOD) == index))
4987 loc.result --;
4989 return loc.result + 1;
4992 #ifdef DEBUG
4993 static void
4994 mono_backtrace (int limit)
4996 void *array[limit];
4997 char **names;
4998 int i;
4999 backtrace (array, limit);
5000 names = backtrace_symbols (array, limit);
5001 for (i =0; i < limit; ++i) {
5002 g_print ("\t%s\n", names [i]);
5004 g_free (names);
5006 #endif
5008 static int i8_align;
5011 * mono_type_set_alignment:
5013 * Set the alignment used by runtime to layout fields etc. of type TYPE to ALIGN.
5014 * This should only be used in AOT mode since the resulting layout will not match the
5015 * host abi layout.
5017 void
5018 mono_type_set_alignment (MonoTypeEnum type, int align)
5020 /* Support only a few types whose alignment is abi dependent */
5021 switch (type) {
5022 case MONO_TYPE_I8:
5023 i8_align = align;
5024 break;
5025 default:
5026 g_assert_not_reached ();
5027 break;
5032 * mono_type_size:
5033 * \param t the type to return the size of
5034 * \returns The number of bytes required to hold an instance of this
5035 * type in memory
5038 mono_type_size (MonoType *t, int *align)
5040 MonoTypeEnum simple_type;
5042 if (!t) {
5043 *align = 1;
5044 return 0;
5046 if (t->byref) {
5047 *align = MONO_ABI_ALIGNOF (gpointer);
5048 return MONO_ABI_SIZEOF (gpointer);
5051 simple_type = t->type;
5052 again:
5053 switch (simple_type) {
5054 case MONO_TYPE_VOID:
5055 *align = 1;
5056 return 0;
5057 case MONO_TYPE_BOOLEAN:
5058 *align = MONO_ABI_ALIGNOF (gint8);
5059 return 1;
5060 case MONO_TYPE_I1:
5061 case MONO_TYPE_U1:
5062 *align = MONO_ABI_ALIGNOF (gint8);
5063 return 1;
5064 case MONO_TYPE_CHAR:
5065 case MONO_TYPE_I2:
5066 case MONO_TYPE_U2:
5067 *align = MONO_ABI_ALIGNOF (gint16);
5068 return 2;
5069 case MONO_TYPE_I4:
5070 case MONO_TYPE_U4:
5071 *align = MONO_ABI_ALIGNOF (gint32);
5072 return 4;
5073 case MONO_TYPE_R4:
5074 *align = MONO_ABI_ALIGNOF (float);
5075 return 4;
5076 case MONO_TYPE_I8:
5077 case MONO_TYPE_U8:
5078 *align = MONO_ABI_ALIGNOF (gint64);
5079 return 8;
5080 case MONO_TYPE_R8:
5081 *align = MONO_ABI_ALIGNOF (double);
5082 return 8;
5083 case MONO_TYPE_I:
5084 case MONO_TYPE_U:
5085 *align = MONO_ABI_ALIGNOF (gpointer);
5086 return MONO_ABI_SIZEOF (gpointer);
5087 case MONO_TYPE_VALUETYPE: {
5088 if (m_class_is_enumtype (t->data.klass))
5089 return mono_type_size (mono_class_enum_basetype_internal (t->data.klass), align);
5090 else
5091 return mono_class_value_size (t->data.klass, (guint32*)align);
5093 case MONO_TYPE_STRING:
5094 case MONO_TYPE_OBJECT:
5095 case MONO_TYPE_CLASS:
5096 case MONO_TYPE_SZARRAY:
5097 case MONO_TYPE_PTR:
5098 case MONO_TYPE_FNPTR:
5099 case MONO_TYPE_ARRAY:
5100 *align = MONO_ABI_ALIGNOF (gpointer);
5101 return MONO_ABI_SIZEOF (gpointer);
5102 case MONO_TYPE_TYPEDBYREF:
5103 return mono_class_value_size (mono_defaults.typed_reference_class, (guint32*)align);
5104 case MONO_TYPE_GENERICINST: {
5105 MonoGenericClass *gclass = t->data.generic_class;
5106 MonoClass *container_class = gclass->container_class;
5108 // g_assert (!gclass->inst->is_open);
5110 if (m_class_is_valuetype (container_class)) {
5111 if (m_class_is_enumtype (container_class))
5112 return mono_type_size (mono_class_enum_basetype_internal (container_class), align);
5113 else
5114 return mono_class_value_size (mono_class_from_mono_type_internal (t), (guint32*)align);
5115 } else {
5116 *align = MONO_ABI_ALIGNOF (gpointer);
5117 return MONO_ABI_SIZEOF (gpointer);
5120 case MONO_TYPE_VAR:
5121 case MONO_TYPE_MVAR:
5122 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
5123 *align = MONO_ABI_ALIGNOF (gpointer);
5124 return MONO_ABI_SIZEOF (gpointer);
5125 } else {
5126 /* The gparam can only match types given by gshared_constraint */
5127 return mono_type_size (t->data.generic_param->gshared_constraint, align);
5128 goto again;
5130 default:
5131 g_error ("mono_type_size: type 0x%02x unknown", t->type);
5133 return 0;
5137 * mono_type_stack_size:
5138 * \param t the type to return the size it uses on the stack
5139 * \returns The number of bytes required to hold an instance of this
5140 * type on the runtime stack
5143 mono_type_stack_size (MonoType *t, int *align)
5145 return mono_type_stack_size_internal (t, align, FALSE);
5149 mono_type_stack_size_internal (MonoType *t, int *align, gboolean allow_open)
5151 int tmp;
5152 MonoTypeEnum simple_type;
5153 int stack_slot_size = TARGET_SIZEOF_VOID_P;
5154 int stack_slot_align = TARGET_SIZEOF_VOID_P;
5156 g_assert (t != NULL);
5158 if (!align)
5159 align = &tmp;
5161 if (t->byref) {
5162 *align = stack_slot_align;
5163 return stack_slot_size;
5166 simple_type = t->type;
5167 switch (simple_type) {
5168 case MONO_TYPE_BOOLEAN:
5169 case MONO_TYPE_CHAR:
5170 case MONO_TYPE_I1:
5171 case MONO_TYPE_U1:
5172 case MONO_TYPE_I2:
5173 case MONO_TYPE_U2:
5174 case MONO_TYPE_I4:
5175 case MONO_TYPE_U4:
5176 case MONO_TYPE_I:
5177 case MONO_TYPE_U:
5178 case MONO_TYPE_STRING:
5179 case MONO_TYPE_OBJECT:
5180 case MONO_TYPE_CLASS:
5181 case MONO_TYPE_SZARRAY:
5182 case MONO_TYPE_PTR:
5183 case MONO_TYPE_FNPTR:
5184 case MONO_TYPE_ARRAY:
5185 *align = stack_slot_align;
5186 return stack_slot_size;
5187 case MONO_TYPE_VAR:
5188 case MONO_TYPE_MVAR:
5189 g_assert (allow_open);
5190 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
5191 *align = stack_slot_align;
5192 return stack_slot_size;
5193 } else {
5194 /* The gparam can only match types given by gshared_constraint */
5195 return mono_type_stack_size_internal (t->data.generic_param->gshared_constraint, align, allow_open);
5197 case MONO_TYPE_TYPEDBYREF:
5198 *align = stack_slot_align;
5199 return stack_slot_size * 3;
5200 case MONO_TYPE_R4:
5201 *align = MONO_ABI_ALIGNOF (float);
5202 return sizeof (float);
5203 case MONO_TYPE_I8:
5204 case MONO_TYPE_U8:
5205 *align = MONO_ABI_ALIGNOF (gint64);
5206 return sizeof (gint64);
5207 case MONO_TYPE_R8:
5208 *align = MONO_ABI_ALIGNOF (double);
5209 return sizeof (double);
5210 case MONO_TYPE_VALUETYPE: {
5211 guint32 size;
5213 if (m_class_is_enumtype (t->data.klass))
5214 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (t->data.klass), align, allow_open);
5215 else {
5216 size = mono_class_value_size (t->data.klass, (guint32*)align);
5218 *align = *align + stack_slot_align - 1;
5219 *align &= ~(stack_slot_align - 1);
5221 size += stack_slot_size - 1;
5222 size &= ~(stack_slot_size - 1);
5224 return size;
5227 case MONO_TYPE_GENERICINST: {
5228 MonoGenericClass *gclass = t->data.generic_class;
5229 MonoClass *container_class = gclass->container_class;
5231 if (!allow_open)
5232 g_assert (!gclass->context.class_inst->is_open);
5234 if (m_class_is_valuetype (container_class)) {
5235 if (m_class_is_enumtype (container_class))
5236 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (container_class), align, allow_open);
5237 else {
5238 guint32 size = mono_class_value_size (mono_class_from_mono_type_internal (t), (guint32*)align);
5240 *align = *align + stack_slot_align - 1;
5241 *align &= ~(stack_slot_align - 1);
5243 size += stack_slot_size - 1;
5244 size &= ~(stack_slot_size - 1);
5246 return size;
5248 } else {
5249 *align = stack_slot_align;
5250 return stack_slot_size;
5253 default:
5254 g_error ("type 0x%02x unknown", t->type);
5256 return 0;
5259 gboolean
5260 mono_type_generic_inst_is_valuetype (MonoType *type)
5262 g_assert (type->type == MONO_TYPE_GENERICINST);
5263 return m_class_is_valuetype (type->data.generic_class->container_class);
5267 * mono_metadata_generic_class_is_valuetype:
5269 gboolean
5270 mono_metadata_generic_class_is_valuetype (MonoGenericClass *gclass)
5272 return m_class_is_valuetype (gclass->container_class);
5275 static gboolean
5276 _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only)
5278 MonoGenericInst *i1 = g1->context.class_inst;
5279 MonoGenericInst *i2 = g2->context.class_inst;
5281 if (g1->is_dynamic != g2->is_dynamic)
5282 return FALSE;
5283 if (!mono_metadata_class_equal (g1->container_class, g2->container_class, signature_only))
5284 return FALSE;
5285 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5286 return FALSE;
5287 return g1->is_tb_open == g2->is_tb_open;
5290 static gboolean
5291 _mono_metadata_generic_class_container_equal (const MonoGenericClass *g1, MonoClass *c2, gboolean signature_only)
5293 MonoGenericInst *i1 = g1->context.class_inst;
5294 MonoGenericInst *i2 = mono_class_get_generic_container (c2)->context.class_inst;
5296 if (!mono_metadata_class_equal (g1->container_class, c2, signature_only))
5297 return FALSE;
5298 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5299 return FALSE;
5300 return !g1->is_tb_open;
5303 guint
5304 mono_metadata_generic_context_hash (const MonoGenericContext *context)
5306 /* FIXME: check if this seed is good enough */
5307 guint hash = 0xc01dfee7;
5308 if (context->class_inst)
5309 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->class_inst);
5310 if (context->method_inst)
5311 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->method_inst);
5312 return hash;
5315 gboolean
5316 mono_metadata_generic_context_equal (const MonoGenericContext *g1, const MonoGenericContext *g2)
5318 return g1->class_inst == g2->class_inst && g1->method_inst == g2->method_inst;
5322 * mono_metadata_str_hash:
5324 * This should be used instead of g_str_hash for computing hash codes visible
5325 * outside this module, since g_str_hash () is not guaranteed to be stable
5326 * (its not the same in eglib for example).
5328 guint
5329 mono_metadata_str_hash (gconstpointer v1)
5331 /* Same as g_str_hash () in glib */
5332 char *p = (char *) v1;
5333 guint hash = *p;
5335 while (*p++) {
5336 if (*p)
5337 hash = (hash << 5) - hash + *p;
5340 return hash;
5344 * mono_metadata_type_hash:
5345 * \param t1 a type
5346 * Computes a hash value for \p t1 to be used in \c GHashTable.
5347 * The returned hash is guaranteed to be the same across executions.
5349 guint
5350 mono_metadata_type_hash (MonoType *t1)
5352 guint hash = t1->type;
5354 hash |= t1->byref << 6; /* do not collide with t1->type values */
5355 switch (t1->type) {
5356 case MONO_TYPE_VALUETYPE:
5357 case MONO_TYPE_CLASS:
5358 case MONO_TYPE_SZARRAY: {
5359 MonoClass *klass = t1->data.klass;
5361 * Dynamic classes must not be hashed on their type since it can change
5362 * during runtime. For example, if we hash a reference type that is
5363 * later made into a valuetype.
5365 * This is specially problematic with generic instances since they are
5366 * inserted in a bunch of hash tables before been finished.
5368 if (image_is_dynamic (m_class_get_image (klass)))
5369 return (t1->byref << 6) | mono_metadata_str_hash (m_class_get_name (klass));
5370 return ((hash << 5) - hash) ^ mono_metadata_str_hash (m_class_get_name (klass));
5372 case MONO_TYPE_PTR:
5373 return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
5374 case MONO_TYPE_ARRAY:
5375 return ((hash << 5) - hash) ^ mono_metadata_type_hash (m_class_get_byval_arg (t1->data.array->eklass));
5376 case MONO_TYPE_GENERICINST:
5377 return ((hash << 5) - hash) ^ mono_generic_class_hash (t1->data.generic_class);
5378 case MONO_TYPE_VAR:
5379 case MONO_TYPE_MVAR:
5380 return ((hash << 5) - hash) ^ mono_metadata_generic_param_hash (t1->data.generic_param);
5381 default:
5382 return hash;
5386 guint
5387 mono_metadata_generic_param_hash (MonoGenericParam *p)
5389 guint hash;
5390 MonoGenericParamInfo *info;
5392 hash = (mono_generic_param_num (p) << 2);
5393 if (p->gshared_constraint)
5394 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->gshared_constraint);
5395 info = mono_generic_param_info (p);
5396 /* Can't hash on the owner klass/method, since those might not be set when this is called */
5397 if (!p->owner->is_anonymous)
5398 hash = ((hash << 5) - hash) ^ info->token;
5399 return hash;
5402 static gboolean
5403 mono_metadata_generic_param_equal_internal (MonoGenericParam *p1, MonoGenericParam *p2, gboolean signature_only)
5405 if (p1 == p2)
5406 return TRUE;
5407 if (mono_generic_param_num (p1) != mono_generic_param_num (p2))
5408 return FALSE;
5409 if (p1->gshared_constraint && p2->gshared_constraint) {
5410 if (!mono_metadata_type_equal (p1->gshared_constraint, p2->gshared_constraint))
5411 return FALSE;
5412 } else {
5413 if (p1->gshared_constraint != p2->gshared_constraint)
5414 return FALSE;
5418 * We have to compare the image as well because if we didn't,
5419 * the generic_inst_cache lookup wouldn't care about the image
5420 * of generic params, so what could happen is that a generic
5421 * inst with params from image A is put into the cache, then
5422 * image B gets that generic inst from the cache, image A is
5423 * unloaded, so the inst is deleted, but image B still retains
5424 * a pointer to it.
5426 if (mono_generic_param_owner (p1) == mono_generic_param_owner (p2))
5427 return TRUE;
5430 * If `signature_only' is true, we're comparing two (method) signatures.
5431 * In this case, the owner of two type parameters doesn't need to match.
5434 return signature_only;
5437 gboolean
5438 mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2)
5440 return mono_metadata_generic_param_equal_internal (p1, p2, TRUE);
5443 static gboolean
5444 mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only)
5446 if (c1 == c2)
5447 return TRUE;
5448 if (mono_class_is_ginst (c1) && mono_class_is_ginst (c2))
5449 return _mono_metadata_generic_class_equal (mono_class_get_generic_class (c1), mono_class_get_generic_class (c2), signature_only);
5450 if (mono_class_is_ginst (c1) && mono_class_is_gtd (c2))
5451 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c1), c2, signature_only);
5452 if (mono_class_is_gtd (c1) && mono_class_is_ginst (c2))
5453 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c2), c1, signature_only);
5454 MonoType *c1_type = m_class_get_byval_arg (c1);
5455 MonoType *c2_type = m_class_get_byval_arg (c2);
5456 if ((c1_type->type == MONO_TYPE_VAR) && (c2_type->type == MONO_TYPE_VAR))
5457 return mono_metadata_generic_param_equal_internal (
5458 c1_type->data.generic_param, c2_type->data.generic_param, signature_only);
5459 if ((c1_type->type == MONO_TYPE_MVAR) && (c2_type->type == MONO_TYPE_MVAR))
5460 return mono_metadata_generic_param_equal_internal (
5461 c1_type->data.generic_param, c2_type->data.generic_param, signature_only);
5462 if (signature_only &&
5463 (c1_type->type == MONO_TYPE_SZARRAY) && (c2_type->type == MONO_TYPE_SZARRAY))
5464 return mono_metadata_class_equal (c1_type->data.klass, c2_type->data.klass, signature_only);
5465 if (signature_only &&
5466 (c1_type->type == MONO_TYPE_ARRAY) && (c2_type->type == MONO_TYPE_ARRAY))
5467 return do_mono_metadata_type_equal (c1_type, c2_type, signature_only);
5468 return FALSE;
5471 static gboolean
5472 mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only)
5474 gpointer iter1 = 0, iter2 = 0;
5476 if (s1 == s2)
5477 return TRUE;
5478 if (s1->call_convention != s2->call_convention)
5479 return FALSE;
5480 if (s1->sentinelpos != s2->sentinelpos)
5481 return FALSE;
5482 if (s1->hasthis != s2->hasthis)
5483 return FALSE;
5484 if (s1->explicit_this != s2->explicit_this)
5485 return FALSE;
5486 if (! do_mono_metadata_type_equal (s1->ret, s2->ret, signature_only))
5487 return FALSE;
5488 if (s1->param_count != s2->param_count)
5489 return FALSE;
5491 while (TRUE) {
5492 MonoType *t1 = mono_signature_get_params (s1, &iter1);
5493 MonoType *t2 = mono_signature_get_params (s2, &iter2);
5495 if (t1 == NULL || t2 == NULL)
5496 return (t1 == t2);
5497 if (! do_mono_metadata_type_equal (t1, t2, signature_only))
5498 return FALSE;
5503 * mono_metadata_type_equal:
5504 * @t1: a type
5505 * @t2: another type
5506 * @signature_only: If true, treat ginsts as equal which are instantiated separately but have equal positional value
5508 * Determine if @t1 and @t2 represent the same type.
5509 * Returns: #TRUE if @t1 and @t2 are equal.
5511 static gboolean
5512 do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only)
5514 if (t1->type != t2->type || t1->byref != t2->byref)
5515 return FALSE;
5517 gboolean cmod_reject = FALSE;
5519 gboolean is_pointer = (t1->type == MONO_TYPE_PTR);
5521 if (t1->has_cmods != t2->has_cmods)
5522 cmod_reject = TRUE;
5523 else if (t1->has_cmods && t2->has_cmods) {
5524 MonoCustomModContainer *cm1 = mono_type_get_cmods (t1);
5525 MonoCustomModContainer *cm2 = mono_type_get_cmods (t2);
5527 g_assert (cm1);
5528 g_assert (cm2);
5530 // ECMA 335, 7.1.1:
5531 // The CLI itself shall treat required and optional modifiers in the same manner.
5532 // Two signatures that differ only by the addition of a custom modifier
5533 // (required or optional) shall not be considered to match.
5534 if (cm1->count != cm2->count) {
5535 cmod_reject = TRUE;
5536 } else for (int i=0; i < cm1->count; i++) {
5537 if (cm1->modifiers[i].required != cm2->modifiers[i].required) {
5538 cmod_reject = TRUE;
5539 break;
5542 // FIXME: propagate error to caller
5543 ERROR_DECL (error);
5544 MonoClass *c1 = mono_class_get_checked (cm1->image, cm1->modifiers [i].token, error);
5545 mono_error_assert_ok (error);
5546 MonoClass *c2 = mono_class_get_checked (cm2->image, cm2->modifiers [i].token, error);
5547 mono_error_assert_ok (error);
5549 if (c1 != c2) {
5550 cmod_reject = TRUE;
5551 break;
5556 gboolean result = FALSE;
5558 switch (t1->type) {
5559 case MONO_TYPE_VOID:
5560 case MONO_TYPE_BOOLEAN:
5561 case MONO_TYPE_CHAR:
5562 case MONO_TYPE_I1:
5563 case MONO_TYPE_U1:
5564 case MONO_TYPE_I2:
5565 case MONO_TYPE_U2:
5566 case MONO_TYPE_I4:
5567 case MONO_TYPE_U4:
5568 case MONO_TYPE_I8:
5569 case MONO_TYPE_U8:
5570 case MONO_TYPE_R4:
5571 case MONO_TYPE_R8:
5572 case MONO_TYPE_STRING:
5573 case MONO_TYPE_I:
5574 case MONO_TYPE_U:
5575 case MONO_TYPE_OBJECT:
5576 case MONO_TYPE_TYPEDBYREF:
5577 result = TRUE;
5578 break;
5579 case MONO_TYPE_VALUETYPE:
5580 case MONO_TYPE_CLASS:
5581 case MONO_TYPE_SZARRAY:
5582 result = mono_metadata_class_equal (t1->data.klass, t2->data.klass, signature_only);
5583 break;
5584 case MONO_TYPE_PTR:
5585 result = do_mono_metadata_type_equal (t1->data.type, t2->data.type, signature_only);
5586 break;
5587 case MONO_TYPE_ARRAY:
5588 if (t1->data.array->rank != t2->data.array->rank)
5589 result = FALSE;
5590 else
5591 result = mono_metadata_class_equal (t1->data.array->eklass, t2->data.array->eklass, signature_only);
5592 break;
5593 case MONO_TYPE_GENERICINST:
5594 result = _mono_metadata_generic_class_equal (
5595 t1->data.generic_class, t2->data.generic_class, signature_only);
5596 break;
5597 case MONO_TYPE_VAR:
5598 result = mono_metadata_generic_param_equal_internal (
5599 t1->data.generic_param, t2->data.generic_param, signature_only);
5600 break;
5601 case MONO_TYPE_MVAR:
5602 result = mono_metadata_generic_param_equal_internal (
5603 t1->data.generic_param, t2->data.generic_param, signature_only);
5604 break;
5605 case MONO_TYPE_FNPTR:
5606 result = mono_metadata_fnptr_equal (t1->data.method, t2->data.method, signature_only);
5607 break;
5608 default:
5609 g_error ("implement type compare for %0x!", t1->type);
5610 return FALSE;
5613 if (cmod_reject && is_pointer)
5614 return FALSE;
5616 return result;
5620 * mono_metadata_type_equal:
5622 gboolean
5623 mono_metadata_type_equal (MonoType *t1, MonoType *t2)
5625 return do_mono_metadata_type_equal (t1, t2, FALSE);
5629 * mono_metadata_type_equal_full:
5630 * \param t1 a type
5631 * \param t2 another type
5632 * \param signature_only if signature only comparison should be made
5634 * Determine if \p t1 and \p t2 are signature compatible if \p signature_only is TRUE, otherwise
5635 * behaves the same way as mono_metadata_type_equal.
5636 * The function mono_metadata_type_equal(a, b) is just a shortcut for mono_metadata_type_equal_full(a, b, FALSE).
5637 * \returns TRUE if \p t1 and \p t2 are equal taking \p signature_only into account.
5639 gboolean
5640 mono_metadata_type_equal_full (MonoType *t1, MonoType *t2, gboolean signature_only)
5642 return do_mono_metadata_type_equal (t1, t2, signature_only);
5646 * mono_metadata_signature_equal:
5647 * \param sig1 a signature
5648 * \param sig2 another signature
5650 * Determine if \p sig1 and \p sig2 represent the same signature, with the
5651 * same number of arguments and the same types.
5652 * \returns TRUE if \p sig1 and \p sig2 are equal.
5654 gboolean
5655 mono_metadata_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
5657 int i;
5659 if (sig1->hasthis != sig2->hasthis || sig1->param_count != sig2->param_count)
5660 return FALSE;
5662 if (sig1->generic_param_count != sig2->generic_param_count)
5663 return FALSE;
5666 * We're just comparing the signatures of two methods here:
5668 * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
5669 * U and V are equal here.
5671 * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
5674 for (i = 0; i < sig1->param_count; i++) {
5675 MonoType *p1 = sig1->params[i];
5676 MonoType *p2 = sig2->params[i];
5678 /* if (p1->attrs != p2->attrs)
5679 return FALSE;
5681 if (!do_mono_metadata_type_equal (p1, p2, TRUE))
5682 return FALSE;
5685 if (!do_mono_metadata_type_equal (sig1->ret, sig2->ret, TRUE))
5686 return FALSE;
5687 return TRUE;
5691 * mono_metadata_type_dup:
5692 * \param image image to alloc memory from
5693 * \param original type to duplicate
5694 * \returns copy of type allocated from the image's mempool (or from the heap, if \p image is null).
5696 MonoType *
5697 mono_metadata_type_dup (MonoImage *image, const MonoType *o)
5699 return mono_metadata_type_dup_with_cmods (image, o, o);
5703 * Works the same way as mono_metadata_type_dup but pick cmods from @cmods_source
5705 MonoType *
5706 mono_metadata_type_dup_with_cmods (MonoImage *image, const MonoType *o, const MonoType *cmods_source)
5708 MonoType *r = NULL;
5709 size_t sizeof_o = mono_sizeof_type (cmods_source);
5711 r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_o) : (MonoType *)g_malloc (sizeof_o);
5713 if (cmods_source->has_cmods) {
5714 g_assert (!image || image == mono_type_get_cmods (cmods_source)->image);
5715 memcpy (r, cmods_source, sizeof_o);
5718 memcpy (r, o, sizeof (MonoType));
5719 r->has_cmods = cmods_source->has_cmods;
5721 if (o->type == MONO_TYPE_PTR) {
5722 r->data.type = mono_metadata_type_dup (image, o->data.type);
5723 } else if (o->type == MONO_TYPE_ARRAY) {
5724 r->data.array = mono_dup_array_type (image, o->data.array);
5725 } else if (o->type == MONO_TYPE_FNPTR) {
5726 /*FIXME the dup'ed signature is leaked mono_metadata_free_type*/
5727 r->data.method = mono_metadata_signature_deep_dup (image, o->data.method);
5729 return r;
5733 * mono_signature_hash:
5735 guint
5736 mono_signature_hash (MonoMethodSignature *sig)
5738 guint i, res = sig->ret->type;
5740 for (i = 0; i < sig->param_count; i++)
5741 res = (res << 5) - res + mono_type_hash (sig->params[i]);
5743 return res;
5747 * mono_metadata_encode_value:
5748 * @value: value to encode
5749 * @buf: buffer where to write the compressed representation
5750 * @endbuf: pointer updated to point at the end of the encoded output
5752 * Encodes the value @value in the compressed representation used
5753 * in metadata and stores the result in @buf. @buf needs to be big
5754 * enough to hold the data (4 bytes).
5756 void
5757 mono_metadata_encode_value (guint32 value, char *buf, char **endbuf)
5759 char *p = buf;
5761 if (value < 0x80)
5762 *p++ = value;
5763 else if (value < 0x4000) {
5764 p [0] = 0x80 | (value >> 8);
5765 p [1] = value & 0xff;
5766 p += 2;
5767 } else {
5768 p [0] = (value >> 24) | 0xc0;
5769 p [1] = (value >> 16) & 0xff;
5770 p [2] = (value >> 8) & 0xff;
5771 p [3] = value & 0xff;
5772 p += 4;
5774 if (endbuf)
5775 *endbuf = p;
5779 * mono_metadata_field_info:
5780 * \param meta the Image the field is defined in
5781 * \param index the index in the field table representing the field
5782 * \param offset a pointer to an integer where to store the offset that may have been specified for the field in a FieldLayout table
5783 * \param rva a pointer to the RVA of the field data in the image that may have been defined in a \c FieldRVA table
5784 * \param marshal_spec a pointer to the marshal spec that may have been defined for the field in a \c FieldMarshal table.
5786 * Gather info for field \p index that may have been defined in the \c FieldLayout,
5787 * \c FieldRVA and \c FieldMarshal tables.
5788 * Either of \p offset, \p rva and \p marshal_spec can be NULL if you're not interested
5789 * in the data.
5791 void
5792 mono_metadata_field_info (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
5793 MonoMarshalSpec **marshal_spec)
5795 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, FALSE);
5798 void
5799 mono_metadata_field_info_with_mempool (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
5800 MonoMarshalSpec **marshal_spec)
5802 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, TRUE);
5805 static void
5806 mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
5807 MonoMarshalSpec **marshal_spec, gboolean alloc_from_image)
5809 MonoTableInfo *tdef;
5810 locator_t loc;
5812 loc.idx = index + 1;
5813 if (meta->uncompressed_metadata)
5814 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
5816 if (offset) {
5817 tdef = &meta->tables [MONO_TABLE_FIELDLAYOUT];
5819 loc.col_idx = MONO_FIELD_LAYOUT_FIELD;
5820 loc.t = tdef;
5822 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
5823 *offset = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_LAYOUT_OFFSET);
5824 } else {
5825 *offset = (guint32)-1;
5828 if (rva) {
5829 tdef = &meta->tables [MONO_TABLE_FIELDRVA];
5831 loc.col_idx = MONO_FIELD_RVA_FIELD;
5832 loc.t = tdef;
5834 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
5836 * LAMESPEC: There is no signature, no nothing, just the raw data.
5838 *rva = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_RVA_RVA);
5839 } else {
5840 *rva = 0;
5843 if (marshal_spec) {
5844 const char *p;
5846 if ((p = mono_metadata_get_marshal_info (meta, index, TRUE))) {
5847 *marshal_spec = mono_metadata_parse_marshal_spec_full (alloc_from_image ? meta : NULL, meta, p);
5854 * mono_metadata_get_constant_index:
5855 * \param meta the Image the field is defined in
5856 * \param index the token that may have a row defined in the constants table
5857 * \param hint possible position for the row
5859 * \p token must be a \c FieldDef, \c ParamDef or \c PropertyDef token.
5861 * \returns the index into the \c Constants table or 0 if not found.
5863 guint32
5864 mono_metadata_get_constant_index (MonoImage *meta, guint32 token, guint32 hint)
5866 MonoTableInfo *tdef;
5867 locator_t loc;
5868 guint32 index = mono_metadata_token_index (token);
5870 tdef = &meta->tables [MONO_TABLE_CONSTANT];
5871 index <<= MONO_HASCONSTANT_BITS;
5872 switch (mono_metadata_token_table (token)) {
5873 case MONO_TABLE_FIELD:
5874 index |= MONO_HASCONSTANT_FIEDDEF;
5875 break;
5876 case MONO_TABLE_PARAM:
5877 index |= MONO_HASCONSTANT_PARAM;
5878 break;
5879 case MONO_TABLE_PROPERTY:
5880 index |= MONO_HASCONSTANT_PROPERTY;
5881 break;
5882 default:
5883 g_warning ("Not a valid token for the constant table: 0x%08x", token);
5884 return 0;
5886 loc.idx = index;
5887 loc.col_idx = MONO_CONSTANT_PARENT;
5888 loc.t = tdef;
5890 /* FIXME: Index translation */
5892 if ((hint > 0) && (hint < tdef->rows) && (mono_metadata_decode_row_col (tdef, hint - 1, MONO_CONSTANT_PARENT) == index))
5893 return hint;
5895 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
5896 return loc.result + 1;
5898 return 0;
5902 * mono_metadata_events_from_typedef:
5903 * \param meta metadata context
5904 * \param index 0-based index (in the \c TypeDef table) describing a type
5905 * \returns the 0-based index in the \c Event table for the events in the
5906 * type. The last event that belongs to the type (plus 1) is stored
5907 * in the \p end_idx pointer.
5909 guint32
5910 mono_metadata_events_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
5912 locator_t loc;
5913 guint32 start, end;
5914 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_EVENTMAP];
5916 *end_idx = 0;
5918 if (!tdef->base)
5919 return 0;
5921 loc.t = tdef;
5922 loc.col_idx = MONO_EVENT_MAP_PARENT;
5923 loc.idx = index + 1;
5925 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5926 return 0;
5928 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_EVENT_MAP_EVENTLIST);
5929 if (loc.result + 1 < tdef->rows) {
5930 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_EVENT_MAP_EVENTLIST) - 1;
5931 } else {
5932 end = meta->tables [MONO_TABLE_EVENT].rows;
5935 *end_idx = end;
5936 return start - 1;
5940 * mono_metadata_methods_from_event:
5941 * \param meta metadata context
5942 * \param index 0-based index (in the \c Event table) describing a event
5943 * \returns the 0-based index in the \c MethodDef table for the methods in the
5944 * event. The last method that belongs to the event (plus 1) is stored
5945 * in the \p end_idx pointer.
5947 guint32
5948 mono_metadata_methods_from_event (MonoImage *meta, guint32 index, guint *end_idx)
5950 locator_t loc;
5951 guint start, end;
5952 guint32 cols [MONO_METHOD_SEMA_SIZE];
5953 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
5955 *end_idx = 0;
5956 if (!msemt->base)
5957 return 0;
5959 if (meta->uncompressed_metadata)
5960 index = search_ptr_table (meta, MONO_TABLE_EVENT_POINTER, index + 1) - 1;
5962 loc.t = msemt;
5963 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
5964 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT; /* Method association coded index */
5966 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
5967 return 0;
5969 start = loc.result;
5971 * We may end up in the middle of the rows...
5973 while (start > 0) {
5974 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
5975 start--;
5976 else
5977 break;
5979 end = start + 1;
5980 while (end < msemt->rows) {
5981 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
5982 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
5983 break;
5984 ++end;
5986 *end_idx = end;
5987 return start;
5991 * mono_metadata_properties_from_typedef:
5992 * \param meta metadata context
5993 * \param index 0-based index (in the \c TypeDef table) describing a type
5994 * \returns the 0-based index in the \c Property table for the properties in the
5995 * type. The last property that belongs to the type (plus 1) is stored
5996 * in the \p end_idx pointer.
5998 guint32
5999 mono_metadata_properties_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
6001 locator_t loc;
6002 guint32 start, end;
6003 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_PROPERTYMAP];
6005 *end_idx = 0;
6007 if (!tdef->base)
6008 return 0;
6010 loc.t = tdef;
6011 loc.col_idx = MONO_PROPERTY_MAP_PARENT;
6012 loc.idx = index + 1;
6014 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6015 return 0;
6017 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_PROPERTY_MAP_PROPERTY_LIST);
6018 if (loc.result + 1 < tdef->rows) {
6019 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_PROPERTY_MAP_PROPERTY_LIST) - 1;
6020 } else {
6021 end = meta->tables [MONO_TABLE_PROPERTY].rows;
6024 *end_idx = end;
6025 return start - 1;
6029 * mono_metadata_methods_from_property:
6030 * \param meta metadata context
6031 * \param index 0-based index (in the \c PropertyDef table) describing a property
6032 * \returns the 0-based index in the \c MethodDef table for the methods in the
6033 * property. The last method that belongs to the property (plus 1) is stored
6034 * in the \p end_idx pointer.
6036 guint32
6037 mono_metadata_methods_from_property (MonoImage *meta, guint32 index, guint *end_idx)
6039 locator_t loc;
6040 guint start, end;
6041 guint32 cols [MONO_METHOD_SEMA_SIZE];
6042 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
6044 *end_idx = 0;
6045 if (!msemt->base)
6046 return 0;
6048 if (meta->uncompressed_metadata)
6049 index = search_ptr_table (meta, MONO_TABLE_PROPERTY_POINTER, index + 1) - 1;
6051 loc.t = msemt;
6052 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
6053 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY; /* Method association coded index */
6055 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
6056 return 0;
6058 start = loc.result;
6060 * We may end up in the middle of the rows...
6062 while (start > 0) {
6063 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
6064 start--;
6065 else
6066 break;
6068 end = start + 1;
6069 while (end < msemt->rows) {
6070 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
6071 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
6072 break;
6073 ++end;
6075 *end_idx = end;
6076 return start;
6080 * mono_metadata_implmap_from_method:
6082 guint32
6083 mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx)
6085 locator_t loc;
6086 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_IMPLMAP];
6088 if (!tdef->base)
6089 return 0;
6091 /* No index translation seems to be needed */
6093 loc.t = tdef;
6094 loc.col_idx = MONO_IMPLMAP_MEMBER;
6095 loc.idx = ((method_idx + 1) << MONO_MEMBERFORWD_BITS) | MONO_MEMBERFORWD_METHODDEF;
6097 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6098 return 0;
6100 return loc.result + 1;
6104 * mono_type_create_from_typespec:
6105 * \param image context where the image is created
6106 * \param type_spec typespec token
6107 * \deprecated use \c mono_type_create_from_typespec_checked that has proper error handling
6109 * Creates a \c MonoType representing the \c TypeSpec indexed by the \p type_spec
6110 * token.
6112 MonoType *
6113 mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
6115 ERROR_DECL (error);
6116 MonoType *type = mono_type_create_from_typespec_checked (image, type_spec, error);
6117 if (!type)
6118 g_error ("Could not create typespec %x due to %s", type_spec, mono_error_get_message (error));
6119 return type;
6122 MonoType *
6123 mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, MonoError *error)
6126 guint32 idx = mono_metadata_token_index (type_spec);
6127 MonoTableInfo *t;
6128 guint32 cols [MONO_TYPESPEC_SIZE];
6129 const char *ptr;
6130 MonoType *type, *type2;
6132 error_init (error);
6134 type = (MonoType *)mono_conc_hashtable_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
6135 if (type)
6136 return type;
6138 t = &image->tables [MONO_TABLE_TYPESPEC];
6140 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
6141 ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
6143 if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, error))
6144 return NULL;
6146 mono_metadata_decode_value (ptr, &ptr);
6148 type = mono_metadata_parse_type_checked (image, NULL, 0, TRUE, ptr, &ptr, error);
6149 if (!type)
6150 return NULL;
6152 type2 = mono_metadata_type_dup (image, type);
6153 mono_metadata_free_type (type);
6155 mono_image_lock (image);
6157 /* We might leak some data in the image mempool if found */
6158 type = (MonoType*)mono_conc_hashtable_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
6159 if (!type)
6160 type = type2;
6162 mono_image_unlock (image);
6164 return type;
6168 static char*
6169 mono_image_strndup (MonoImage *image, const char *data, guint len)
6171 char *res;
6172 if (!image)
6173 return g_strndup (data, len);
6174 res = (char *)mono_image_alloc (image, len + 1);
6175 memcpy (res, data, len);
6176 res [len] = 0;
6177 return res;
6181 * mono_metadata_parse_marshal_spec:
6183 MonoMarshalSpec *
6184 mono_metadata_parse_marshal_spec (MonoImage *image, const char *ptr)
6186 return mono_metadata_parse_marshal_spec_full (NULL, image, ptr);
6190 * If IMAGE is non-null, memory will be allocated from its mempool, otherwise it will be allocated using malloc.
6191 * PARENT_IMAGE is the image containing the marshal spec.
6193 MonoMarshalSpec *
6194 mono_metadata_parse_marshal_spec_full (MonoImage *image, MonoImage *parent_image, const char *ptr)
6196 MonoMarshalSpec *res;
6197 int len;
6198 const char *start = ptr;
6200 /* fixme: this is incomplete, but I cant find more infos in the specs */
6202 if (image)
6203 res = (MonoMarshalSpec *)mono_image_alloc0 (image, sizeof (MonoMarshalSpec));
6204 else
6205 res = g_new0 (MonoMarshalSpec, 1);
6207 len = mono_metadata_decode_value (ptr, &ptr);
6208 res->native = (MonoMarshalNative)*ptr++;
6210 if (res->native == MONO_NATIVE_LPARRAY) {
6211 res->data.array_data.param_num = -1;
6212 res->data.array_data.num_elem = -1;
6213 res->data.array_data.elem_mult = -1;
6215 if (ptr - start <= len)
6216 res->data.array_data.elem_type = (MonoMarshalNative)*ptr++;
6217 if (ptr - start <= len)
6218 res->data.array_data.param_num = mono_metadata_decode_value (ptr, &ptr);
6219 if (ptr - start <= len)
6220 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6221 if (ptr - start <= len) {
6223 * LAMESPEC: Older spec versions say this parameter comes before
6224 * num_elem. Never spec versions don't talk about elem_mult at
6225 * all, but csc still emits it, and it is used to distinguish
6226 * between param_num being 0, and param_num being omitted.
6227 * So if (param_num == 0) && (num_elem > 0), then
6228 * elem_mult == 0 -> the array size is num_elem
6229 * elem_mult == 1 -> the array size is @param_num + num_elem
6231 res->data.array_data.elem_mult = mono_metadata_decode_value (ptr, &ptr);
6235 if (res->native == MONO_NATIVE_BYVALTSTR) {
6236 if (ptr - start <= len)
6237 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6240 if (res->native == MONO_NATIVE_BYVALARRAY) {
6241 if (ptr - start <= len)
6242 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6245 if (res->native == MONO_NATIVE_CUSTOM) {
6246 /* skip unused type guid */
6247 len = mono_metadata_decode_value (ptr, &ptr);
6248 ptr += len;
6249 /* skip unused native type name */
6250 len = mono_metadata_decode_value (ptr, &ptr);
6251 ptr += len;
6252 /* read custom marshaler type name */
6253 len = mono_metadata_decode_value (ptr, &ptr);
6254 res->data.custom_data.custom_name = mono_image_strndup (image, ptr, len);
6255 ptr += len;
6256 /* read cookie string */
6257 len = mono_metadata_decode_value (ptr, &ptr);
6258 res->data.custom_data.cookie = mono_image_strndup (image, ptr, len);
6259 res->data.custom_data.image = parent_image;
6262 if (res->native == MONO_NATIVE_SAFEARRAY) {
6263 res->data.safearray_data.elem_type = (MonoMarshalVariant)0;
6264 res->data.safearray_data.num_elem = 0;
6265 if (ptr - start <= len)
6266 res->data.safearray_data.elem_type = (MonoMarshalVariant)*ptr++;
6267 if (ptr - start <= len)
6268 res->data.safearray_data.num_elem = *ptr++;
6270 return res;
6274 * mono_metadata_free_marshal_spec:
6276 void
6277 mono_metadata_free_marshal_spec (MonoMarshalSpec *spec)
6279 if (!spec)
6280 return;
6282 if (spec->native == MONO_NATIVE_CUSTOM) {
6283 g_free (spec->data.custom_data.custom_name);
6284 g_free (spec->data.custom_data.cookie);
6286 g_free (spec);
6290 * mono_type_to_unmanaged:
6291 * The value pointed to by \p conv will contain the kind of marshalling required for this
6292 * particular type one of the \c MONO_MARSHAL_CONV_ enumeration values.
6293 * \returns A \c MonoMarshalNative enumeration value (<code>MONO_NATIVE_</code>) value
6294 * describing the underlying native reprensetation of the type.
6296 guint32 // FIXMEcxx MonoMarshalNative
6297 mono_type_to_unmanaged (MonoType *type, MonoMarshalSpec *mspec, gboolean as_field,
6298 gboolean unicode, MonoMarshalConv *conv)
6300 MonoMarshalConv dummy_conv;
6301 int t = type->type;
6303 if (!conv)
6304 conv = &dummy_conv;
6306 *conv = MONO_MARSHAL_CONV_NONE;
6308 if (type->byref)
6309 return MONO_NATIVE_UINT;
6311 handle_enum:
6312 switch (t) {
6313 case MONO_TYPE_BOOLEAN:
6314 if (mspec) {
6315 switch (mspec->native) {
6316 case MONO_NATIVE_VARIANTBOOL:
6317 *conv = MONO_MARSHAL_CONV_BOOL_VARIANTBOOL;
6318 return MONO_NATIVE_VARIANTBOOL;
6319 case MONO_NATIVE_BOOLEAN:
6320 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6321 return MONO_NATIVE_BOOLEAN;
6322 case MONO_NATIVE_I1:
6323 case MONO_NATIVE_U1:
6324 return mspec->native;
6325 default:
6326 g_error ("cant marshal bool to native type %02x", mspec->native);
6329 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6330 return MONO_NATIVE_BOOLEAN;
6331 case MONO_TYPE_CHAR:
6332 if (mspec) {
6333 switch (mspec->native) {
6334 case MONO_NATIVE_U2:
6335 case MONO_NATIVE_U1:
6336 return mspec->native;
6337 default:
6338 g_error ("cant marshal char to native type %02x", mspec->native);
6341 return unicode ? MONO_NATIVE_U2 : MONO_NATIVE_U1;
6342 case MONO_TYPE_I1: return MONO_NATIVE_I1;
6343 case MONO_TYPE_U1: return MONO_NATIVE_U1;
6344 case MONO_TYPE_I2: return MONO_NATIVE_I2;
6345 case MONO_TYPE_U2: return MONO_NATIVE_U2;
6346 case MONO_TYPE_I4: return MONO_NATIVE_I4;
6347 case MONO_TYPE_U4: return MONO_NATIVE_U4;
6348 case MONO_TYPE_I8: return MONO_NATIVE_I8;
6349 case MONO_TYPE_U8: return MONO_NATIVE_U8;
6350 case MONO_TYPE_R4: return MONO_NATIVE_R4;
6351 case MONO_TYPE_R8: return MONO_NATIVE_R8;
6352 case MONO_TYPE_STRING:
6353 if (mspec) {
6354 switch (mspec->native) {
6355 case MONO_NATIVE_BSTR:
6356 *conv = MONO_MARSHAL_CONV_STR_BSTR;
6357 return MONO_NATIVE_BSTR;
6358 case MONO_NATIVE_LPSTR:
6359 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6360 return MONO_NATIVE_LPSTR;
6361 case MONO_NATIVE_LPWSTR:
6362 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6363 return MONO_NATIVE_LPWSTR;
6364 case MONO_NATIVE_LPTSTR:
6365 *conv = MONO_MARSHAL_CONV_STR_LPTSTR;
6366 return MONO_NATIVE_LPTSTR;
6367 case MONO_NATIVE_ANSIBSTR:
6368 *conv = MONO_MARSHAL_CONV_STR_ANSIBSTR;
6369 return MONO_NATIVE_ANSIBSTR;
6370 case MONO_NATIVE_TBSTR:
6371 *conv = MONO_MARSHAL_CONV_STR_TBSTR;
6372 return MONO_NATIVE_TBSTR;
6373 case MONO_NATIVE_UTF8STR:
6374 *conv = MONO_MARSHAL_CONV_STR_UTF8STR;
6375 return MONO_NATIVE_UTF8STR;
6376 case MONO_NATIVE_BYVALTSTR:
6377 if (unicode)
6378 *conv = MONO_MARSHAL_CONV_STR_BYVALWSTR;
6379 else
6380 *conv = MONO_MARSHAL_CONV_STR_BYVALSTR;
6381 return MONO_NATIVE_BYVALTSTR;
6382 default:
6383 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);
6386 if (unicode) {
6387 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6388 return MONO_NATIVE_LPWSTR;
6390 else {
6391 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6392 return MONO_NATIVE_LPSTR;
6394 case MONO_TYPE_PTR: return MONO_NATIVE_UINT;
6395 case MONO_TYPE_VALUETYPE: /*FIXME*/
6396 if (m_class_is_enumtype (type->data.klass)) {
6397 t = mono_class_enum_basetype_internal (type->data.klass)->type;
6398 goto handle_enum;
6400 if (type->data.klass == mono_class_try_get_handleref_class ()){
6401 *conv = MONO_MARSHAL_CONV_HANDLEREF;
6402 return MONO_NATIVE_INT;
6404 return MONO_NATIVE_STRUCT;
6405 case MONO_TYPE_SZARRAY:
6406 case MONO_TYPE_ARRAY:
6407 if (mspec) {
6408 switch (mspec->native) {
6409 case MONO_NATIVE_BYVALARRAY:
6410 if ((m_class_get_element_class (type->data.klass) == mono_defaults.char_class) && !unicode)
6411 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY;
6412 else
6413 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALARRAY;
6414 return MONO_NATIVE_BYVALARRAY;
6415 case MONO_NATIVE_SAFEARRAY:
6416 *conv = MONO_MARSHAL_CONV_ARRAY_SAVEARRAY;
6417 return MONO_NATIVE_SAFEARRAY;
6418 case MONO_NATIVE_LPARRAY:
6419 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6420 return MONO_NATIVE_LPARRAY;
6421 default:
6422 g_error ("cant marshal array as native type %02x", mspec->native);
6426 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6427 return MONO_NATIVE_LPARRAY;
6428 case MONO_TYPE_I: return MONO_NATIVE_INT;
6429 case MONO_TYPE_U: return MONO_NATIVE_UINT;
6430 case MONO_TYPE_CLASS:
6431 case MONO_TYPE_OBJECT: {
6432 /* FIXME : we need to handle ArrayList and StringBuilder here, probably */
6433 if (mspec) {
6434 switch (mspec->native) {
6435 case MONO_NATIVE_STRUCT:
6436 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6437 return MONO_NATIVE_STRUCT;
6438 case MONO_NATIVE_CUSTOM:
6439 return MONO_NATIVE_CUSTOM;
6440 case MONO_NATIVE_INTERFACE:
6441 *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
6442 return MONO_NATIVE_INTERFACE;
6443 case MONO_NATIVE_IDISPATCH:
6444 *conv = MONO_MARSHAL_CONV_OBJECT_IDISPATCH;
6445 return MONO_NATIVE_IDISPATCH;
6446 case MONO_NATIVE_IUNKNOWN:
6447 *conv = MONO_MARSHAL_CONV_OBJECT_IUNKNOWN;
6448 return MONO_NATIVE_IUNKNOWN;
6449 case MONO_NATIVE_FUNC:
6450 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6451 type->data.klass == mono_defaults.delegate_class ||
6452 m_class_get_parent (type->data.klass) == mono_defaults.multicastdelegate_class)) {
6453 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6454 return MONO_NATIVE_FUNC;
6456 /* Fall through */
6457 default:
6458 g_error ("cant marshal object as native type %02x", mspec->native);
6461 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6462 type->data.klass == mono_defaults.delegate_class ||
6463 m_class_get_parent (type->data.klass) == mono_defaults.multicastdelegate_class)) {
6464 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6465 return MONO_NATIVE_FUNC;
6467 if (mono_class_try_get_safehandle_class () && type->data.klass == mono_class_try_get_safehandle_class ()){
6468 *conv = MONO_MARSHAL_CONV_SAFEHANDLE;
6469 return MONO_NATIVE_INT;
6471 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6472 return MONO_NATIVE_STRUCT;
6474 case MONO_TYPE_FNPTR: return MONO_NATIVE_FUNC;
6475 case MONO_TYPE_GENERICINST:
6476 type = m_class_get_byval_arg (type->data.generic_class->container_class);
6477 t = type->type;
6478 goto handle_enum;
6479 case MONO_TYPE_TYPEDBYREF:
6480 default:
6481 g_error ("type 0x%02x not handled in marshal", t);
6483 return MONO_NATIVE_MAX;
6487 * mono_metadata_get_marshal_info:
6489 const char*
6490 mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field)
6492 locator_t loc;
6493 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_FIELDMARSHAL];
6495 if (!tdef->base)
6496 return NULL;
6498 loc.t = tdef;
6499 loc.col_idx = MONO_FIELD_MARSHAL_PARENT;
6500 loc.idx = ((idx + 1) << MONO_HAS_FIELD_MARSHAL_BITS) | (is_field? MONO_HAS_FIELD_MARSHAL_FIELDSREF: MONO_HAS_FIELD_MARSHAL_PARAMDEF);
6502 /* FIXME: Index translation */
6504 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6505 return NULL;
6507 return mono_metadata_blob_heap (meta, mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_MARSHAL_NATIVE_TYPE));
6510 MonoMethod*
6511 mono_method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context, MonoError *error)
6513 MonoMethod *result = NULL;
6514 guint32 idx = tok >> MONO_METHODDEFORREF_BITS;
6516 error_init (error);
6518 switch (tok & MONO_METHODDEFORREF_MASK) {
6519 case MONO_METHODDEFORREF_METHODDEF:
6520 result = mono_get_method_checked (m, MONO_TOKEN_METHOD_DEF | idx, NULL, context, error);
6521 break;
6522 case MONO_METHODDEFORREF_METHODREF:
6523 result = mono_get_method_checked (m, MONO_TOKEN_MEMBER_REF | idx, NULL, context, error);
6524 break;
6525 default:
6526 mono_error_set_bad_image (error, m, "Invalid MethodDefOfRef token %x", tok);
6529 return result;
6533 * mono_class_get_overrides_full:
6535 * Compute the method overrides belonging to class @type_token in @overrides, and the number of overrides in @num_overrides.
6538 void
6539 mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides, MonoGenericContext *generic_context, MonoError *error)
6541 locator_t loc;
6542 MonoTableInfo *tdef = &image->tables [MONO_TABLE_METHODIMPL];
6543 guint32 start, end;
6544 gint32 i, num;
6545 guint32 cols [MONO_METHODIMPL_SIZE];
6546 MonoMethod **result;
6548 error_init (error);
6550 *overrides = NULL;
6551 if (num_overrides)
6552 *num_overrides = 0;
6554 if (!tdef->base)
6555 return;
6557 loc.t = tdef;
6558 loc.col_idx = MONO_METHODIMPL_CLASS;
6559 loc.idx = mono_metadata_token_index (type_token);
6561 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6562 return;
6564 start = loc.result;
6565 end = start + 1;
6567 * We may end up in the middle of the rows...
6569 while (start > 0) {
6570 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_METHODIMPL_CLASS))
6571 start--;
6572 else
6573 break;
6575 while (end < tdef->rows) {
6576 if (loc.idx == mono_metadata_decode_row_col (tdef, end, MONO_METHODIMPL_CLASS))
6577 end++;
6578 else
6579 break;
6581 num = end - start;
6582 result = g_new (MonoMethod*, num * 2);
6583 for (i = 0; i < num; ++i) {
6584 MonoMethod *method;
6586 if (!mono_verifier_verify_methodimpl_row (image, start + i, error))
6587 break;
6589 mono_metadata_decode_row (tdef, start + i, cols, MONO_METHODIMPL_SIZE);
6590 method = mono_method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_DECLARATION], generic_context, error);
6591 if (!method)
6592 break;
6594 result [i * 2] = method;
6595 method = mono_method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_BODY], generic_context, error);
6596 if (!method)
6597 break;
6599 result [i * 2 + 1] = method;
6602 if (!is_ok (error)) {
6603 g_free (result);
6604 *overrides = NULL;
6605 if (num_overrides)
6606 *num_overrides = 0;
6607 } else {
6608 *overrides = result;
6609 if (num_overrides)
6610 *num_overrides = num;
6615 * mono_guid_to_string:
6617 * Converts a 16 byte Microsoft GUID to the standard string representation.
6619 char *
6620 mono_guid_to_string (const guint8 *guid)
6622 return g_strdup_printf ("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
6623 guid[3], guid[2], guid[1], guid[0],
6624 guid[5], guid[4],
6625 guid[7], guid[6],
6626 guid[8], guid[9],
6627 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
6631 * mono_guid_to_string_minimal:
6633 * Converts a 16 byte Microsoft GUID to lower case no '-' representation..
6635 char *
6636 mono_guid_to_string_minimal (const guint8 *guid)
6638 return g_strdup_printf ("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
6639 guid[3], guid[2], guid[1], guid[0],
6640 guid[5], guid[4],
6641 guid[7], guid[6],
6642 guid[8], guid[9],
6643 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
6645 static gboolean
6646 get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGenericContainer *container, MonoError *error)
6648 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
6649 guint32 cols [MONO_GENPARCONSTRAINT_SIZE];
6650 guint32 i, token, found;
6651 MonoClass *klass, **res;
6652 GSList *cons = NULL, *tmp;
6653 MonoGenericContext *context = &container->context;
6655 error_init (error);
6657 *constraints = NULL;
6658 found = 0;
6659 for (i = 0; i < tdef->rows; ++i) {
6660 mono_metadata_decode_row (tdef, i, cols, MONO_GENPARCONSTRAINT_SIZE);
6661 if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) {
6662 token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]);
6663 klass = mono_class_get_and_inflate_typespec_checked (image, token, context, error);
6664 if (!klass) {
6665 g_slist_free (cons);
6666 return FALSE;
6668 cons = g_slist_append (cons, klass);
6669 ++found;
6670 } else {
6671 /* contiguous list finished */
6672 if (found)
6673 break;
6676 if (!found)
6677 return TRUE;
6678 res = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * (found + 1));
6679 for (i = 0, tmp = cons; i < found; ++i, tmp = tmp->next) {
6680 res [i] = (MonoClass *)tmp->data;
6682 g_slist_free (cons);
6683 *constraints = res;
6684 return TRUE;
6688 * mono_metadata_get_generic_param_row:
6690 * @image:
6691 * @token: TypeOrMethodDef token, owner for GenericParam
6692 * @owner: coded token, set on return
6694 * Returns: 1-based row-id in the GenericParam table whose
6695 * owner is @token. 0 if not found.
6697 guint32
6698 mono_metadata_get_generic_param_row (MonoImage *image, guint32 token, guint32 *owner)
6700 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
6701 locator_t loc;
6703 g_assert (owner);
6704 if (!tdef->base)
6705 return 0;
6707 if (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
6708 *owner = MONO_TYPEORMETHOD_TYPE;
6709 else if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
6710 *owner = MONO_TYPEORMETHOD_METHOD;
6711 else {
6712 g_error ("wrong token %x to get_generic_param_row", token);
6713 return 0;
6715 *owner |= mono_metadata_token_index (token) << MONO_TYPEORMETHOD_BITS;
6717 loc.idx = *owner;
6718 loc.col_idx = MONO_GENERICPARAM_OWNER;
6719 loc.t = tdef;
6721 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6722 return 0;
6724 /* Find the first entry by searching backwards */
6725 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_GENERICPARAM_OWNER) == loc.idx))
6726 loc.result --;
6728 return loc.result + 1;
6731 gboolean
6732 mono_metadata_has_generic_params (MonoImage *image, guint32 token)
6734 guint32 owner;
6735 return mono_metadata_get_generic_param_row (image, token, &owner);
6739 * Memory is allocated from IMAGE's mempool.
6741 gboolean
6742 mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token,
6743 MonoGenericContainer *container, MonoError *error)
6746 guint32 start_row, i, owner;
6747 error_init (error);
6749 if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner)))
6750 return TRUE;
6751 for (i = 0; i < container->type_argc; i++) {
6752 if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container, error)) {
6753 return FALSE;
6756 return TRUE;
6760 * mono_metadata_load_generic_params:
6762 * Load the type parameters from the type or method definition @token.
6764 * Use this method after parsing a type or method definition to figure out whether it's a generic
6765 * type / method. When parsing a method definition, @parent_container points to the generic container
6766 * of the current class, if any.
6768 * Note: This method does not load the constraints: for typedefs, this has to be done after fully
6769 * creating the type.
6771 * Returns: NULL if @token is not a generic type or method definition or the new generic container.
6773 * LOCKING: Acquires the loader lock
6776 MonoGenericContainer *
6777 mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericContainer *parent_container, gpointer real_owner)
6779 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
6780 guint32 cols [MONO_GENERICPARAM_SIZE];
6781 guint32 i, owner = 0, n;
6782 MonoGenericContainer *container;
6783 MonoGenericParamFull *params;
6784 MonoGenericContext *context;
6785 gboolean is_method = mono_metadata_token_table (token) == MONO_TABLE_METHOD;
6786 gboolean is_anonymous = real_owner == NULL;
6788 if (!(i = mono_metadata_get_generic_param_row (image, token, &owner)))
6789 return NULL;
6790 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
6791 params = NULL;
6792 n = 0;
6793 container = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
6794 container->is_anonymous = is_anonymous;
6795 if (is_anonymous) {
6796 container->owner.image = image;
6797 } else {
6798 if (is_method)
6799 container->owner.method = (MonoMethod*)real_owner;
6800 else
6801 container->owner.klass = (MonoClass*)real_owner;
6803 do {
6804 n++;
6805 params = (MonoGenericParamFull *)g_realloc (params, sizeof (MonoGenericParamFull) * n);
6806 memset (&params [n - 1], 0, sizeof (MonoGenericParamFull));
6807 params [n - 1].owner = container;
6808 params [n - 1].num = cols [MONO_GENERICPARAM_NUMBER];
6809 params [n - 1].info.token = i | MONO_TOKEN_GENERIC_PARAM;
6810 params [n - 1].info.flags = cols [MONO_GENERICPARAM_FLAGS];
6811 params [n - 1].info.name = mono_metadata_string_heap (image, cols [MONO_GENERICPARAM_NAME]);
6812 if (params [n - 1].num != n - 1)
6813 g_warning ("GenericParam table unsorted or hole in generic param sequence: token %d", i);
6814 if (++i > tdef->rows)
6815 break;
6816 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
6817 } while (cols [MONO_GENERICPARAM_OWNER] == owner);
6819 container->type_argc = n;
6820 container->type_params = (MonoGenericParamFull *)mono_image_alloc0 (image, sizeof (MonoGenericParamFull) * n);
6821 memcpy (container->type_params, params, sizeof (MonoGenericParamFull) * n);
6822 g_free (params);
6823 container->parent = parent_container;
6825 if (is_method)
6826 container->is_method = 1;
6828 g_assert (container->parent == NULL || container->is_method);
6830 context = &container->context;
6831 if (container->is_method) {
6832 context->class_inst = container->parent ? container->parent->context.class_inst : NULL;
6833 context->method_inst = mono_get_shared_generic_inst (container);
6834 } else {
6835 context->class_inst = mono_get_shared_generic_inst (container);
6838 return container;
6841 MonoGenericInst *
6842 mono_get_shared_generic_inst (MonoGenericContainer *container)
6844 MonoType **type_argv;
6845 MonoType *helper;
6846 MonoGenericInst *nginst;
6847 int i;
6849 type_argv = g_new0 (MonoType *, container->type_argc);
6850 helper = g_new0 (MonoType, container->type_argc);
6852 for (i = 0; i < container->type_argc; i++) {
6853 MonoType *t = &helper [i];
6855 t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
6856 t->data.generic_param = mono_generic_container_get_param (container, i);
6858 type_argv [i] = t;
6861 nginst = mono_metadata_get_generic_inst (container->type_argc, type_argv);
6863 g_free (type_argv);
6864 g_free (helper);
6866 return nginst;
6870 * mono_type_is_byref:
6871 * \param type the \c MonoType operated on
6872 * \returns TRUE if \p type represents a type passed by reference,
6873 * FALSE otherwise.
6875 mono_bool
6876 mono_type_is_byref (MonoType *type)
6878 mono_bool result;
6879 MONO_ENTER_GC_UNSAFE;
6880 result = type->byref;
6881 MONO_EXIT_GC_UNSAFE;
6882 return result;
6886 * mono_type_get_type:
6887 * \param type the \c MonoType operated on
6888 * \returns the IL type value for \p type. This is one of the \c MonoTypeEnum
6889 * enum members like \c MONO_TYPE_I4 or \c MONO_TYPE_STRING.
6892 mono_type_get_type (MonoType *type)
6894 return type->type;
6898 * mono_type_get_signature:
6899 * \param type the \c MonoType operated on
6900 * It is only valid to call this function if \p type is a \c MONO_TYPE_FNPTR .
6901 * \returns the \c MonoMethodSignature pointer that describes the signature
6902 * of the function pointer \p type represents.
6904 MonoMethodSignature*
6905 mono_type_get_signature (MonoType *type)
6907 g_assert (type->type == MONO_TYPE_FNPTR);
6908 return type->data.method;
6912 * mono_type_get_class:
6913 * \param type the \c MonoType operated on
6914 * It is only valid to call this function if \p type is a \c MONO_TYPE_CLASS or a
6915 * \c MONO_TYPE_VALUETYPE . For more general functionality, use \c mono_class_from_mono_type_internal,
6916 * instead.
6917 * \returns the \c MonoClass pointer that describes the class that \p type represents.
6919 MonoClass*
6920 mono_type_get_class (MonoType *type)
6922 /* FIXME: review the runtime users before adding the assert here */
6923 return type->data.klass;
6927 * mono_type_get_array_type:
6928 * \param type the \c MonoType operated on
6929 * It is only valid to call this function if \p type is a \c MONO_TYPE_ARRAY .
6930 * \returns a \c MonoArrayType struct describing the array type that \p type
6931 * represents. The info includes details such as rank, array element type
6932 * and the sizes and bounds of multidimensional arrays.
6934 MonoArrayType*
6935 mono_type_get_array_type (MonoType *type)
6937 return type->data.array;
6941 * mono_type_get_ptr_type:
6942 * \pararm type the \c MonoType operated on
6943 * It is only valid to call this function if \p type is a \c MONO_TYPE_PTR .
6944 * \returns the \c MonoType pointer that describes the type that \p type
6945 * represents a pointer to.
6947 MonoType*
6948 mono_type_get_ptr_type (MonoType *type)
6950 g_assert (type->type == MONO_TYPE_PTR);
6951 return type->data.type;
6955 * mono_type_get_modifiers:
6957 MonoClass*
6958 mono_type_get_modifiers (MonoType *type, gboolean *is_required, gpointer *iter)
6960 /* FIXME: implement */
6961 return NULL;
6965 * mono_type_is_struct:
6966 * \param type the \c MonoType operated on
6967 * \returns TRUE if \p type is a struct, that is a \c ValueType but not an enum
6968 * or a basic type like \c System.Int32 . FALSE otherwise.
6970 mono_bool
6971 mono_type_is_struct (MonoType *type)
6973 return (!type->byref && ((type->type == MONO_TYPE_VALUETYPE &&
6974 !m_class_is_enumtype (type->data.klass)) || (type->type == MONO_TYPE_TYPEDBYREF) ||
6975 ((type->type == MONO_TYPE_GENERICINST) &&
6976 mono_metadata_generic_class_is_valuetype (type->data.generic_class) &&
6977 !m_class_is_enumtype (type->data.generic_class->container_class))));
6981 * mono_type_is_void:
6982 * \param type the \c MonoType operated on
6983 * \returns TRUE if \p type is \c System.Void . FALSE otherwise.
6985 mono_bool
6986 mono_type_is_void (MonoType *type)
6988 return (type && (type->type == MONO_TYPE_VOID) && !type->byref);
6992 * mono_type_is_pointer:
6993 * \param type the \c MonoType operated on
6994 * \returns TRUE if \p type is a managed or unmanaged pointer type. FALSE otherwise.
6996 mono_bool
6997 mono_type_is_pointer (MonoType *type)
6999 return (type && ((type->byref || (type->type == MONO_TYPE_I) || type->type == MONO_TYPE_STRING)
7000 || (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
7001 (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_OBJECT) ||
7002 (type->type == MONO_TYPE_ARRAY) || (type->type == MONO_TYPE_PTR) ||
7003 (type->type == MONO_TYPE_FNPTR)));
7007 * mono_type_is_reference:
7008 * \param type the \c MonoType operated on
7009 * \returns TRUE if \p type represents an object reference. FALSE otherwise.
7011 mono_bool
7012 mono_type_is_reference (MonoType *type)
7014 return (type && (((type->type == MONO_TYPE_STRING) ||
7015 (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
7016 (type->type == MONO_TYPE_OBJECT) || (type->type == MONO_TYPE_ARRAY)) ||
7017 ((type->type == MONO_TYPE_GENERICINST) &&
7018 !mono_metadata_generic_class_is_valuetype (type->data.generic_class))));
7021 mono_bool
7022 mono_type_is_generic_parameter (MonoType *type)
7024 return !type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR);
7028 * mono_signature_get_return_type:
7029 * \param sig the method signature inspected
7030 * \returns the return type of the method signature \p sig
7032 MonoType*
7033 mono_signature_get_return_type (MonoMethodSignature *sig)
7035 MonoType *result;
7036 MONO_ENTER_GC_UNSAFE;
7037 result = sig->ret;
7038 MONO_EXIT_GC_UNSAFE;
7039 return result;
7043 * mono_signature_get_params:
7044 * \param sig the method signature inspected
7045 * \param iter pointer to an iterator
7046 * Iterates over the parameters for the method signature \p sig.
7047 * A \c void* pointer must be initialized to NULL to start the iteration
7048 * and its address is passed to this function repeteadly until it returns
7049 * NULL.
7050 * \returns the next parameter type of the method signature \p sig,
7051 * NULL when finished.
7053 MonoType*
7054 mono_signature_get_params (MonoMethodSignature *sig, gpointer *iter)
7056 MonoType *result;
7057 MONO_ENTER_GC_UNSAFE;
7058 result = mono_signature_get_params_internal (sig, iter);
7059 MONO_EXIT_GC_UNSAFE;
7060 return result;
7063 MonoType*
7064 mono_signature_get_params_internal (MonoMethodSignature *sig, gpointer *iter)
7066 MonoType** type;
7067 if (!iter)
7068 return NULL;
7069 if (!*iter) {
7070 /* start from the first */
7071 if (sig->param_count) {
7072 *iter = &sig->params [0];
7073 return sig->params [0];
7074 } else {
7075 /* no method */
7076 return NULL;
7079 type = (MonoType **)*iter;
7080 type++;
7081 if (type < &sig->params [sig->param_count]) {
7082 *iter = type;
7083 return *type;
7085 return NULL;
7089 * mono_signature_get_param_count:
7090 * \param sig the method signature inspected
7091 * \returns the number of parameters in the method signature \p sig.
7093 guint32
7094 mono_signature_get_param_count (MonoMethodSignature *sig)
7096 return sig->param_count;
7100 * mono_signature_get_call_conv:
7101 * \param sig the method signature inspected
7102 * \returns the call convention of the method signature \p sig.
7104 guint32
7105 mono_signature_get_call_conv (MonoMethodSignature *sig)
7107 return sig->call_convention;
7111 * mono_signature_vararg_start:
7112 * \param sig the method signature inspected
7113 * \returns the number of the first vararg parameter in the
7114 * method signature \param sig. \c -1 if this is not a vararg signature.
7117 mono_signature_vararg_start (MonoMethodSignature *sig)
7119 return sig->sentinelpos;
7123 * mono_signature_is_instance:
7124 * \param sig the method signature inspected
7125 * \returns TRUE if this the method signature \p sig has an implicit
7126 * first instance argument. FALSE otherwise.
7128 gboolean
7129 mono_signature_is_instance (MonoMethodSignature *sig)
7131 return sig->hasthis;
7135 * mono_signature_param_is_out
7136 * \param sig the method signature inspected
7137 * \param param_num the 0-based index of the inspected parameter
7138 * \returns TRUE if the parameter is an out parameter, FALSE
7139 * otherwise.
7141 mono_bool
7142 mono_signature_param_is_out (MonoMethodSignature *sig, int param_num)
7144 g_assert (param_num >= 0 && param_num < sig->param_count);
7145 return (sig->params [param_num]->attrs & PARAM_ATTRIBUTE_OUT) != 0;
7149 * mono_signature_explicit_this:
7150 * \param sig the method signature inspected
7151 * \returns TRUE if this the method signature \p sig has an explicit
7152 * instance argument. FALSE otherwise.
7154 gboolean
7155 mono_signature_explicit_this (MonoMethodSignature *sig)
7157 return sig->explicit_this;
7160 /* for use with allocated memory blocks (assumes alignment is to 8 bytes) */
7161 guint
7162 mono_aligned_addr_hash (gconstpointer ptr)
7164 /* Same hashing we use for objects */
7165 return (GPOINTER_TO_UINT (ptr) >> 3) * 2654435761u;
7169 * If @field belongs to an inflated generic class, return the corresponding field of the
7170 * generic type definition class.
7172 MonoClassField*
7173 mono_metadata_get_corresponding_field_from_generic_type_definition (MonoClassField *field)
7175 MonoClass *gtd;
7176 int offset;
7178 if (!mono_class_is_ginst (field->parent))
7179 return field;
7181 gtd = mono_class_get_generic_class (field->parent)->container_class;
7182 offset = field - m_class_get_fields (field->parent);
7183 return m_class_get_fields (gtd) + offset;
7187 * If @event belongs to an inflated generic class, return the corresponding event of the
7188 * generic type definition class.
7190 MonoEvent*
7191 mono_metadata_get_corresponding_event_from_generic_type_definition (MonoEvent *event)
7193 MonoClass *gtd;
7194 int offset;
7196 if (!mono_class_is_ginst (event->parent))
7197 return event;
7199 gtd = mono_class_get_generic_class (event->parent)->container_class;
7200 offset = event - mono_class_get_event_info (event->parent)->events;
7201 return mono_class_get_event_info (gtd)->events + offset;
7205 * If @property belongs to an inflated generic class, return the corresponding property of the
7206 * generic type definition class.
7208 MonoProperty*
7209 mono_metadata_get_corresponding_property_from_generic_type_definition (MonoProperty *property)
7211 MonoClassPropertyInfo *info;
7212 MonoClass *gtd;
7213 int offset;
7215 if (!mono_class_is_ginst (property->parent))
7216 return property;
7218 info = mono_class_get_property_info (property->parent);
7219 gtd = mono_class_get_generic_class (property->parent)->container_class;
7220 offset = property - info->properties;
7221 return mono_class_get_property_info (gtd)->properties + offset;
7224 MonoWrapperCaches*
7225 mono_method_get_wrapper_cache (MonoMethod *method)
7227 if (method->is_inflated) {
7228 MonoMethodInflated *imethod = (MonoMethodInflated *)method;
7229 return &imethod->owner->wrapper_caches;
7230 } else {
7231 return &m_class_get_image (method->klass)->wrapper_caches;
7235 // 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.
7238 * mono_find_image_set_owner:
7240 * Find the imageset, if any, which a given pointer is located in the memory of.
7242 MonoImageSet *
7243 mono_find_image_set_owner (void *ptr)
7245 MonoImageSet *owner = NULL;
7246 int i;
7248 image_sets_lock ();
7250 if (image_sets)
7252 for (i = 0; !owner && i < image_sets->len; ++i) {
7253 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
7254 if (mono_mempool_contains_addr (set->mempool, ptr))
7255 owner = set;
7259 image_sets_unlock ();
7261 return owner;
7264 void
7265 mono_loader_set_strict_strong_names (gboolean enabled)
7267 check_strong_names_strictly = enabled;
7270 gboolean
7271 mono_loader_get_strict_strong_names (void)
7273 return check_strong_names_strictly;
7277 MonoCustomModContainer *
7278 mono_type_get_cmods (const MonoType *t)
7280 if (!t->has_cmods)
7281 return NULL;
7283 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7285 return &full->cmods;
7288 size_t
7289 mono_sizeof_type_with_mods (uint8_t num_mods)
7291 size_t accum = 0;
7292 accum += sizeof (MonoType);
7293 if (num_mods == 0)
7294 return accum;
7296 accum += offsetof (struct _MonoCustomModContainer, modifiers);
7297 accum += sizeof (MonoCustomMod) * num_mods;
7298 return accum;
7301 size_t
7302 mono_sizeof_type (const MonoType *ty)
7304 MonoCustomModContainer *cmods = mono_type_get_cmods (ty);
7305 if (cmods)
7306 return mono_sizeof_type_with_mods (cmods->count);
7307 else
7308 return sizeof (MonoType);