Reduce TLS accesses. (#11487)
[mono-project.git] / mono / metadata / metadata.c
blob20ef15e681c7b7fd42dc54e43e6d6e827d3c753a
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 tableidx)
562 if (meta->referenced_tables && (meta->referenced_tables & ((guint64)1 << tableidx)))
563 return meta->referenced_table_rows [tableidx] < 65536 ? 2 : 4;
564 else
565 return meta->tables [tableidx].rows < 65536 ? 2 : 4;
568 static inline int
569 get_nrows (MonoImage *meta, int tableidx)
571 if (meta->referenced_tables && (meta->referenced_tables & ((guint64)1 << tableidx)))
572 return meta->referenced_table_rows [tableidx];
573 else
574 return meta->tables [tableidx].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 #if SIZEOF_VOID_P == 8
1122 return (const unsigned char *) (((guint64) (ptr + 3)) & ~3);
1123 #else
1124 return (const unsigned char *) (((guint32) (ptr + 3)) & ~3);
1125 #endif
1129 * mono_metadata_decode_row:
1130 * \param t table to extract information from.
1131 * \param idx index in table.
1132 * \param res array of \p res_size cols to store the results in
1134 * This decompresses the metadata element \p idx in table \p t
1135 * into the \c guint32 \p res array that has \p res_size elements
1137 void
1138 mono_metadata_decode_row (const MonoTableInfo *t, int idx, guint32 *res, int res_size)
1140 guint32 bitfield = t->size_bitfield;
1141 int i, count = mono_metadata_table_count (bitfield);
1142 const char *data;
1144 g_assert (idx < t->rows);
1145 g_assert (idx >= 0);
1146 data = t->base + idx * t->row_size;
1148 g_assert (res_size == count);
1150 for (i = 0; i < count; i++) {
1151 int n = mono_metadata_table_size (bitfield, i);
1153 switch (n){
1154 case 1:
1155 res [i] = *data; break;
1156 case 2:
1157 res [i] = read16 (data); break;
1158 case 4:
1159 res [i] = read32 (data); break;
1160 default:
1161 g_assert_not_reached ();
1163 data += n;
1168 * mono_metadata_decode_row_checked:
1169 * \param image the \c MonoImage the table belongs to
1170 * \param t table to extract information from.
1171 * \param idx index in the table.
1172 * \param res array of \p res_size cols to store the results in
1173 * \param error set on bounds error
1176 * This decompresses the metadata element \p idx in the table \p t
1177 * into the \c guint32 \p res array that has \p res_size elements.
1179 * \returns TRUE if the read succeeded. Otherwise sets \p error and returns FALSE.
1181 gboolean
1182 mono_metadata_decode_row_checked (const MonoImage *image, const MonoTableInfo *t, int idx, guint32 *res, int res_size, MonoError *error)
1184 guint32 bitfield = t->size_bitfield;
1185 int i, count = mono_metadata_table_count (bitfield);
1187 const char *image_name = image && image->name ? image->name : "unknown image";
1189 if (G_UNLIKELY (! (idx < t->rows && idx >= 0))) {
1190 mono_error_set_bad_image_by_name (error, image_name, "row index %d out of bounds: %d rows", idx, t->rows);
1191 return FALSE;
1193 const char *data = t->base + idx * t->row_size;
1195 if (G_UNLIKELY (res_size != count)) {
1196 mono_error_set_bad_image_by_name (error, image_name, "res_size %d != count %d", res_size, count);
1197 return FALSE;
1200 for (i = 0; i < count; i++) {
1201 int n = mono_metadata_table_size (bitfield, i);
1203 switch (n) {
1204 case 1:
1205 res [i] = *data; break;
1206 case 2:
1207 res [i] = read16 (data); break;
1208 case 4:
1209 res [i] = read32 (data); break;
1210 default:
1211 mono_error_set_bad_image_by_name (error, image_name, "unexpected table [%d] size %d", i, n);
1212 return FALSE;
1214 data += n;
1217 return TRUE;
1221 * mono_metadata_decode_row_col:
1222 * \param t table to extract information from.
1223 * \param idx index for row in table.
1224 * \param col column in the row.
1226 * This function returns the value of column \p col from the \p idx
1227 * row in the table \p t .
1229 guint32
1230 mono_metadata_decode_row_col (const MonoTableInfo *t, int idx, guint col)
1232 guint32 bitfield = t->size_bitfield;
1233 int i;
1234 const char *data;
1235 int n;
1237 g_assert (idx < t->rows);
1238 g_assert (col < mono_metadata_table_count (bitfield));
1239 data = t->base + idx * t->row_size;
1241 n = mono_metadata_table_size (bitfield, 0);
1242 for (i = 0; i < col; ++i) {
1243 data += n;
1244 n = mono_metadata_table_size (bitfield, i + 1);
1246 switch (n) {
1247 case 1:
1248 return *data;
1249 case 2:
1250 return read16 (data);
1251 case 4:
1252 return read32 (data);
1253 default:
1254 g_assert_not_reached ();
1256 return 0;
1260 * mono_metadata_decode_blob_size:
1261 * \param ptr pointer to a blob object
1262 * \param rptr the new position of the pointer
1264 * This decodes a compressed size as described by 24.2.4 (#US and #Blob a blob or user string object)
1266 * \returns the size of the blob object
1268 guint32
1269 mono_metadata_decode_blob_size (const char *xptr, const char **rptr)
1271 const unsigned char *ptr = (const unsigned char *)xptr;
1272 guint32 size;
1274 if ((*ptr & 0x80) == 0){
1275 size = ptr [0] & 0x7f;
1276 ptr++;
1277 } else if ((*ptr & 0x40) == 0){
1278 size = ((ptr [0] & 0x3f) << 8) + ptr [1];
1279 ptr += 2;
1280 } else {
1281 size = ((ptr [0] & 0x1f) << 24) +
1282 (ptr [1] << 16) +
1283 (ptr [2] << 8) +
1284 ptr [3];
1285 ptr += 4;
1287 if (rptr)
1288 *rptr = (char*)ptr;
1289 return size;
1293 * mono_metadata_decode_value:
1294 * \param ptr pointer to decode from
1295 * \param rptr the new position of the pointer
1297 * This routine decompresses 32-bit values as specified in the "Blob and
1298 * Signature" section (23.2)
1300 * \returns the decoded value
1302 guint32
1303 mono_metadata_decode_value (const char *_ptr, const char **rptr)
1305 const unsigned char *ptr = (const unsigned char *) _ptr;
1306 unsigned char b = *ptr;
1307 guint32 len;
1309 if ((b & 0x80) == 0){
1310 len = b;
1311 ++ptr;
1312 } else if ((b & 0x40) == 0){
1313 len = ((b & 0x3f) << 8 | ptr [1]);
1314 ptr += 2;
1315 } else {
1316 len = ((b & 0x1f) << 24) |
1317 (ptr [1] << 16) |
1318 (ptr [2] << 8) |
1319 ptr [3];
1320 ptr += 4;
1322 if (rptr)
1323 *rptr = (char*)ptr;
1325 return len;
1329 * mono_metadata_decode_signed_value:
1330 * \param ptr pointer to decode from
1331 * \param rptr the new position of the pointer
1333 * This routine decompresses 32-bit signed values
1334 * (not specified in the spec)
1336 * \returns the decoded value
1338 gint32
1339 mono_metadata_decode_signed_value (const char *ptr, const char **rptr)
1341 guint32 uval = mono_metadata_decode_value (ptr, rptr);
1342 gint32 ival = uval >> 1;
1343 if (!(uval & 1))
1344 return ival;
1345 /* ival is a truncated 2's complement negative number. */
1346 if (ival < 0x40)
1347 /* 6 bits = 7 bits for compressed representation (top bit is '0') - 1 sign bit */
1348 return ival - 0x40;
1349 if (ival < 0x2000)
1350 /* 13 bits = 14 bits for compressed representation (top bits are '10') - 1 sign bit */
1351 return ival - 0x2000;
1352 if (ival < 0x10000000)
1353 /* 28 bits = 29 bits for compressed representation (top bits are '110') - 1 sign bit */
1354 return ival - 0x10000000;
1355 g_assert (ival < 0x20000000);
1356 g_warning ("compressed signed value appears to use 29 bits for compressed representation: %x (raw: %8x)", ival, uval);
1357 return ival - 0x20000000;
1361 * mono_metadata_translate_token_index:
1362 * Translates the given 1-based index into the \c Method, \c Field, \c Event, or \c Param tables
1363 * using the \c *Ptr tables in uncompressed metadata, if they are available.
1365 * FIXME: The caller is not forced to call this function, which is error-prone, since
1366 * forgetting to call it would only show up as a bug on uncompressed metadata.
1368 guint32
1369 mono_metadata_translate_token_index (MonoImage *image, int table, guint32 idx)
1371 if (!image->uncompressed_metadata)
1372 return idx;
1374 switch (table) {
1375 case MONO_TABLE_METHOD:
1376 if (image->tables [MONO_TABLE_METHOD_POINTER].rows)
1377 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_METHOD_POINTER], idx - 1, MONO_METHOD_POINTER_METHOD);
1378 else
1379 return idx;
1380 case MONO_TABLE_FIELD:
1381 if (image->tables [MONO_TABLE_FIELD_POINTER].rows)
1382 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_FIELD_POINTER], idx - 1, MONO_FIELD_POINTER_FIELD);
1383 else
1384 return idx;
1385 case MONO_TABLE_EVENT:
1386 if (image->tables [MONO_TABLE_EVENT_POINTER].rows)
1387 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_EVENT_POINTER], idx - 1, MONO_EVENT_POINTER_EVENT);
1388 else
1389 return idx;
1390 case MONO_TABLE_PROPERTY:
1391 if (image->tables [MONO_TABLE_PROPERTY_POINTER].rows)
1392 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_PROPERTY_POINTER], idx - 1, MONO_PROPERTY_POINTER_PROPERTY);
1393 else
1394 return idx;
1395 case MONO_TABLE_PARAM:
1396 if (image->tables [MONO_TABLE_PARAM_POINTER].rows)
1397 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_PARAM_POINTER], idx - 1, MONO_PARAM_POINTER_PARAM);
1398 else
1399 return idx;
1400 default:
1401 return idx;
1406 * mono_metadata_decode_table_row:
1408 * Same as \c mono_metadata_decode_row, but takes an \p image + \p table ID pair, and takes
1409 * uncompressed metadata into account, so it should be used to access the
1410 * \c Method, \c Field, \c Param and \c Event tables when the access is made from metadata, i.e.
1411 * \p idx is retrieved from a metadata table, like \c MONO_TYPEDEF_FIELD_LIST.
1413 void
1414 mono_metadata_decode_table_row (MonoImage *image, int table, int idx, guint32 *res, int res_size)
1416 if (image->uncompressed_metadata)
1417 idx = mono_metadata_translate_token_index (image, table, idx + 1) - 1;
1419 mono_metadata_decode_row (&image->tables [table], idx, res, res_size);
1423 * mono_metadata_decode_table_row_col:
1425 * Same as \c mono_metadata_decode_row_col, but takes an \p image + \p table ID pair, and takes
1426 * uncompressed metadata into account, so it should be used to access the
1427 * \c Method, \c Field, \c Param and \c Event tables.
1429 guint32 mono_metadata_decode_table_row_col (MonoImage *image, int table, int idx, guint col)
1431 if (image->uncompressed_metadata)
1432 idx = mono_metadata_translate_token_index (image, table, idx + 1) - 1;
1434 return mono_metadata_decode_row_col (&image->tables [table], idx, col);
1438 * mono_metadata_parse_typedef_or_ref:
1439 * \param m a metadata context.
1440 * \param ptr a pointer to an encoded TypedefOrRef in \p m
1441 * \param rptr pointer updated to match the end of the decoded stream
1442 * \returns a token valid in the \p m metadata decoded from
1443 * the compressed representation.
1445 guint32
1446 mono_metadata_parse_typedef_or_ref (MonoImage *m, const char *ptr, const char **rptr)
1448 guint32 token;
1449 token = mono_metadata_decode_value (ptr, &ptr);
1450 if (rptr)
1451 *rptr = ptr;
1452 return mono_metadata_token_from_dor (token);
1456 * mono_metadata_parse_custom_mod:
1457 * \param m a metadata context.
1458 * \param dest storage where the info about the custom modifier is stored (may be NULL)
1459 * \param ptr a pointer to (possibly) the start of a custom modifier list
1460 * \param rptr pointer updated to match the end of the decoded stream
1462 * Checks if \p ptr points to a type custom modifier compressed representation.
1464 * \returns TRUE if a custom modifier was found, FALSE if not.
1467 mono_metadata_parse_custom_mod (MonoImage *m, MonoCustomMod *dest, const char *ptr, const char **rptr)
1469 MonoCustomMod local;
1470 if ((*ptr == MONO_TYPE_CMOD_OPT) || (*ptr == MONO_TYPE_CMOD_REQD)) {
1471 if (!dest)
1472 dest = &local;
1473 dest->required = *ptr == MONO_TYPE_CMOD_REQD ? 1 : 0;
1474 dest->token = mono_metadata_parse_typedef_or_ref (m, ptr + 1, rptr);
1475 return TRUE;
1477 return FALSE;
1481 * mono_metadata_parse_array_internal:
1482 * @m: a metadata context.
1483 * @transient: whenever to allocate data from the heap
1484 * @ptr: a pointer to an encoded array description.
1485 * @rptr: pointer updated to match the end of the decoded stream
1487 * Decodes the compressed array description found in the metadata @m at @ptr.
1489 * Returns: a #MonoArrayType structure describing the array type
1490 * and dimensions. Memory is allocated from the heap or from the image mempool, depending
1491 * on the value of @transient.
1493 * LOCKING: Acquires the loader lock
1495 static MonoArrayType *
1496 mono_metadata_parse_array_internal (MonoImage *m, MonoGenericContainer *container,
1497 gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1499 int i;
1500 MonoArrayType *array;
1501 MonoType *etype;
1503 etype = mono_metadata_parse_type_checked (m, container, 0, FALSE, ptr, &ptr, error); //FIXME this doesn't respect @transient
1504 if (!etype)
1505 return NULL;
1507 array = transient ? (MonoArrayType *)g_malloc0 (sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (m, sizeof (MonoArrayType));
1508 array->eklass = mono_class_from_mono_type_internal (etype);
1509 array->rank = mono_metadata_decode_value (ptr, &ptr);
1511 array->numsizes = mono_metadata_decode_value (ptr, &ptr);
1512 if (array->numsizes)
1513 array->sizes = transient ? (int *)g_malloc0 (sizeof (int) * array->numsizes) : (int *)mono_image_alloc0 (m, sizeof (int) * array->numsizes);
1514 for (i = 0; i < array->numsizes; ++i)
1515 array->sizes [i] = mono_metadata_decode_value (ptr, &ptr);
1517 array->numlobounds = mono_metadata_decode_value (ptr, &ptr);
1518 if (array->numlobounds)
1519 array->lobounds = transient ? (int *)g_malloc0 (sizeof (int) * array->numlobounds) : (int *)mono_image_alloc0 (m, sizeof (int) * array->numlobounds);
1520 for (i = 0; i < array->numlobounds; ++i)
1521 array->lobounds [i] = mono_metadata_decode_signed_value (ptr, &ptr);
1523 if (rptr)
1524 *rptr = ptr;
1525 return array;
1529 * mono_metadata_parse_array:
1531 MonoArrayType *
1532 mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
1534 ERROR_DECL (error);
1535 MonoArrayType *ret = mono_metadata_parse_array_internal (m, NULL, FALSE, ptr, rptr, error);
1536 mono_error_cleanup (error);
1538 return ret;
1542 * mono_metadata_free_array:
1543 * \param array array description
1545 * Frees the array description returned from \c mono_metadata_parse_array.
1547 void
1548 mono_metadata_free_array (MonoArrayType *array)
1550 g_free (array->sizes);
1551 g_free (array->lobounds);
1552 g_free (array);
1556 * need to add common field and param attributes combinations:
1557 * [out] param
1558 * public static
1559 * public static literal
1560 * private
1561 * private static
1562 * private static literal
1564 static const MonoType
1565 builtin_types[] = {
1566 /* data, attrs, type, nmods, byref, pinned */
1567 {{NULL}, 0, MONO_TYPE_VOID, 0, 0, 0},
1568 {{NULL}, 0, MONO_TYPE_BOOLEAN, 0, 0, 0},
1569 {{NULL}, 0, MONO_TYPE_BOOLEAN, 0, 1, 0},
1570 {{NULL}, 0, MONO_TYPE_CHAR, 0, 0, 0},
1571 {{NULL}, 0, MONO_TYPE_CHAR, 0, 1, 0},
1572 {{NULL}, 0, MONO_TYPE_I1, 0, 0, 0},
1573 {{NULL}, 0, MONO_TYPE_I1, 0, 1, 0},
1574 {{NULL}, 0, MONO_TYPE_U1, 0, 0, 0},
1575 {{NULL}, 0, MONO_TYPE_U1, 0, 1, 0},
1576 {{NULL}, 0, MONO_TYPE_I2, 0, 0, 0},
1577 {{NULL}, 0, MONO_TYPE_I2, 0, 1, 0},
1578 {{NULL}, 0, MONO_TYPE_U2, 0, 0, 0},
1579 {{NULL}, 0, MONO_TYPE_U2, 0, 1, 0},
1580 {{NULL}, 0, MONO_TYPE_I4, 0, 0, 0},
1581 {{NULL}, 0, MONO_TYPE_I4, 0, 1, 0},
1582 {{NULL}, 0, MONO_TYPE_U4, 0, 0, 0},
1583 {{NULL}, 0, MONO_TYPE_U4, 0, 1, 0},
1584 {{NULL}, 0, MONO_TYPE_I8, 0, 0, 0},
1585 {{NULL}, 0, MONO_TYPE_I8, 0, 1, 0},
1586 {{NULL}, 0, MONO_TYPE_U8, 0, 0, 0},
1587 {{NULL}, 0, MONO_TYPE_U8, 0, 1, 0},
1588 {{NULL}, 0, MONO_TYPE_R4, 0, 0, 0},
1589 {{NULL}, 0, MONO_TYPE_R4, 0, 1, 0},
1590 {{NULL}, 0, MONO_TYPE_R8, 0, 0, 0},
1591 {{NULL}, 0, MONO_TYPE_R8, 0, 1, 0},
1592 {{NULL}, 0, MONO_TYPE_STRING, 0, 0, 0},
1593 {{NULL}, 0, MONO_TYPE_STRING, 0, 1, 0},
1594 {{NULL}, 0, MONO_TYPE_OBJECT, 0, 0, 0},
1595 {{NULL}, 0, MONO_TYPE_OBJECT, 0, 1, 0},
1596 {{NULL}, 0, MONO_TYPE_TYPEDBYREF, 0, 0, 0},
1597 {{NULL}, 0, MONO_TYPE_I, 0, 0, 0},
1598 {{NULL}, 0, MONO_TYPE_I, 0, 1, 0},
1599 {{NULL}, 0, MONO_TYPE_U, 0, 0, 0},
1600 {{NULL}, 0, MONO_TYPE_U, 0, 1, 0},
1603 #define NBUILTIN_TYPES() (sizeof (builtin_types) / sizeof (builtin_types [0]))
1605 static GHashTable *type_cache = NULL;
1606 static gint32 next_generic_inst_id = 0;
1608 /* Protected by image_sets_mutex */
1609 static MonoImageSet *mscorlib_image_set;
1610 /* Protected by image_sets_mutex */
1611 static GPtrArray *image_sets;
1612 static mono_mutex_t image_sets_mutex;
1614 static guint mono_generic_class_hash (gconstpointer data);
1617 * MonoTypes with modifies are never cached, so we never check or use that field.
1619 static guint
1620 mono_type_hash (gconstpointer data)
1622 const MonoType *type = (const MonoType *) data;
1623 if (type->type == MONO_TYPE_GENERICINST)
1624 return mono_generic_class_hash (type->data.generic_class);
1625 else
1626 return type->type | (type->byref << 8) | (type->attrs << 9);
1629 static gint
1630 mono_type_equal (gconstpointer ka, gconstpointer kb)
1632 const MonoType *a = (const MonoType *) ka;
1633 const MonoType *b = (const MonoType *) kb;
1635 if (a->type != b->type || a->byref != b->byref || a->attrs != b->attrs || a->pinned != b->pinned)
1636 return 0;
1637 /* need other checks */
1638 return 1;
1641 guint
1642 mono_metadata_generic_inst_hash (gconstpointer data)
1644 const MonoGenericInst *ginst = (const MonoGenericInst *) data;
1645 guint hash = 0;
1646 int i;
1647 g_assert (ginst);
1648 g_assert (ginst->type_argv);
1650 for (i = 0; i < ginst->type_argc; ++i) {
1651 hash *= 13;
1652 g_assert (ginst->type_argv [i]);
1653 hash += mono_metadata_type_hash (ginst->type_argv [i]);
1656 return hash ^ (ginst->is_open << 8);
1659 static gboolean
1660 mono_generic_inst_equal_full (const MonoGenericInst *a, const MonoGenericInst *b, gboolean signature_only)
1662 int i;
1664 // An optimization: if the ids of two insts are the same, we know they are the same inst and don't check contents.
1665 // Furthermore, because we perform early de-duping, if the ids differ, we know the contents differ.
1666 #ifndef MONO_SMALL_CONFIG // Optimization does not work in MONO_SMALL_CONFIG: There are no IDs
1667 if (a->id && b->id) { // "id 0" means "object has no id"-- de-duping hasn't been performed yet, must check contents.
1668 if (a->id == b->id)
1669 return TRUE;
1670 // In signature-comparison mode id equality implies object equality, but this is not true for inequality.
1671 // Two separate objects could have signature-equavalent contents.
1672 if (!signature_only)
1673 return FALSE;
1675 #endif
1677 if (a->is_open != b->is_open || a->type_argc != b->type_argc)
1678 return FALSE;
1679 for (i = 0; i < a->type_argc; ++i) {
1680 if (!do_mono_metadata_type_equal (a->type_argv [i], b->type_argv [i], signature_only))
1681 return FALSE;
1683 return TRUE;
1686 gboolean
1687 mono_metadata_generic_inst_equal (gconstpointer ka, gconstpointer kb)
1689 const MonoGenericInst *a = (const MonoGenericInst *) ka;
1690 const MonoGenericInst *b = (const MonoGenericInst *) kb;
1692 return mono_generic_inst_equal_full (a, b, FALSE);
1695 static guint
1696 mono_generic_class_hash (gconstpointer data)
1698 const MonoGenericClass *gclass = (const MonoGenericClass *) data;
1699 guint hash = mono_metadata_type_hash (m_class_get_byval_arg (gclass->container_class));
1701 hash *= 13;
1702 hash += gclass->is_tb_open;
1703 hash += mono_metadata_generic_context_hash (&gclass->context);
1705 return hash;
1708 static gboolean
1709 mono_generic_class_equal (gconstpointer ka, gconstpointer kb)
1711 const MonoGenericClass *a = (const MonoGenericClass *) ka;
1712 const MonoGenericClass *b = (const MonoGenericClass *) kb;
1714 return _mono_metadata_generic_class_equal (a, b, FALSE);
1718 * mono_metadata_init:
1720 * Initialize the global variables of this module.
1721 * This is a Mono runtime internal function.
1723 void
1724 mono_metadata_init (void)
1726 int i;
1728 /* We guard against double initialization due to how pedump in verification mode works.
1729 Until runtime initialization is properly factored to work with what it needs we need workarounds like this.
1730 FIXME: https://bugzilla.xamarin.com/show_bug.cgi?id=58793
1732 static gboolean inited;
1734 if (inited)
1735 return;
1736 inited = TRUE;
1738 type_cache = g_hash_table_new (mono_type_hash, mono_type_equal);
1740 for (i = 0; i < NBUILTIN_TYPES (); ++i)
1741 g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]);
1743 mono_os_mutex_init_recursive (&image_sets_mutex);
1745 mono_counters_register ("ImgSet Cache Hit", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_hit);
1746 mono_counters_register ("ImgSet Cache Miss", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_miss);
1747 mono_counters_register ("ImgSet Count", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_count);
1751 * mono_metadata_cleanup:
1753 * Free all resources used by this module.
1754 * This is a Mono runtime internal function.
1756 void
1757 mono_metadata_cleanup (void)
1759 g_hash_table_destroy (type_cache);
1760 type_cache = NULL;
1761 g_ptr_array_free (image_sets, TRUE);
1762 image_sets = NULL;
1763 mono_os_mutex_destroy (&image_sets_mutex);
1767 * mono_metadata_parse_type:
1768 * \param m metadata context
1769 * \param mode kind of type that may be found at \p ptr
1770 * \param opt_attrs optional attributes to store in the returned type
1771 * \param ptr pointer to the type representation
1772 * \param rptr pointer updated to match the end of the decoded stream
1773 * \param transient whenever to allocate the result from the heap or from a mempool
1775 * Decode a compressed type description found at \p ptr in \p m .
1776 * \p mode can be one of \c MONO_PARSE_MOD_TYPE, \c MONO_PARSE_PARAM, \c MONO_PARSE_RET,
1777 * \c MONO_PARSE_FIELD, \c MONO_PARSE_LOCAL, \c MONO_PARSE_TYPE.
1778 * This function can be used to decode type descriptions in method signatures,
1779 * field signatures, locals signatures etc.
1781 * To parse a generic type, \c generic_container points to the current class'es
1782 * (the \c generic_container field in the <code>MonoClass</code>) or the current generic method's
1783 * (stored in <code>image->property_hash</code>) generic container.
1784 * When we encounter a \c MONO_TYPE_VAR or \c MONO_TYPE_MVAR, it's looked up in
1785 * this \c MonoGenericContainer.
1787 * LOCKING: Acquires the loader lock.
1789 * \returns a \c MonoType structure representing the decoded type.
1791 static MonoType*
1792 mono_metadata_parse_type_internal (MonoImage *m, MonoGenericContainer *container,
1793 short opt_attrs, gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1795 MonoType *type, *cached;
1796 MonoType stype;
1797 gboolean byref = FALSE;
1798 gboolean pinned = FALSE;
1799 const char *tmp_ptr;
1800 int count = 0; // Number of mod arguments
1801 gboolean found;
1803 error_init (error);
1806 * According to the spec, custom modifiers should come before the byref
1807 * flag, but the IL produced by ilasm from the following signature:
1808 * object modopt(...) &
1809 * starts with a byref flag, followed by the modifiers. (bug #49802)
1810 * Also, this type seems to be different from 'object & modopt(...)'. Maybe
1811 * it would be better to treat byref as real type constructor instead of
1812 * a modifier...
1813 * Also, pinned should come before anything else, but some MSV++ produced
1814 * assemblies violate this (#bug 61990).
1817 /* Count the modifiers first */
1818 tmp_ptr = ptr;
1819 found = TRUE;
1820 while (found) {
1821 switch (*tmp_ptr) {
1822 case MONO_TYPE_PINNED:
1823 case MONO_TYPE_BYREF:
1824 ++tmp_ptr;
1825 break;
1826 case MONO_TYPE_CMOD_REQD:
1827 case MONO_TYPE_CMOD_OPT:
1828 count ++;
1829 mono_metadata_parse_custom_mod (m, NULL, tmp_ptr, &tmp_ptr);
1830 break;
1831 default:
1832 found = FALSE;
1836 MonoCustomModContainer *cmods = NULL;
1838 if (count) { // There are mods, so the MonoType will be of nonstandard size.
1839 if (count > 64) {
1840 mono_error_set_bad_image (error, m, "Invalid type with more than 64 modifiers");
1841 return NULL;
1844 size_t size = mono_sizeof_type_with_mods (count);
1845 type = transient ? (MonoType *)g_malloc0 (size) : (MonoType *)mono_image_alloc0 (m, size);
1846 type->has_cmods = TRUE;
1848 cmods = mono_type_get_cmods (type);
1849 cmods->count = count;
1850 cmods->image = m;
1851 } else { // The type is of standard size, so we can allocate it on the stack.
1852 type = &stype;
1853 memset (type, 0, MONO_SIZEOF_TYPE);
1856 /* Iterate again, but now parse pinned, byref and custom modifiers */
1857 found = TRUE;
1858 count = 0;
1859 while (found) {
1860 switch (*ptr) {
1861 case MONO_TYPE_PINNED:
1862 pinned = TRUE;
1863 ++ptr;
1864 break;
1865 case MONO_TYPE_BYREF:
1866 byref = TRUE;
1867 ++ptr;
1868 break;
1869 case MONO_TYPE_CMOD_REQD:
1870 case MONO_TYPE_CMOD_OPT:
1871 mono_metadata_parse_custom_mod (m, &(cmods->modifiers [count]), ptr, &ptr);
1872 count ++;
1873 break;
1874 default:
1875 found = FALSE;
1879 type->attrs = opt_attrs;
1880 type->byref = byref;
1881 type->pinned = pinned ? 1 : 0;
1883 if (!do_mono_metadata_parse_type (type, m, container, transient, ptr, &ptr, error))
1884 return NULL;
1886 if (rptr)
1887 *rptr = ptr;
1889 // Possibly we can return an already-allocated type instead of the one we decoded
1890 if (!type->has_cmods && !transient) {
1891 /* no need to free type here, because it is on the stack */
1892 if ((type->type == MONO_TYPE_CLASS || type->type == MONO_TYPE_VALUETYPE) && !type->pinned && !type->attrs) {
1893 MonoType *ret = type->byref ? m_class_get_this_arg (type->data.klass) : m_class_get_byval_arg (type->data.klass);
1895 /* Consider the case:
1897 class Foo<T> { class Bar {} }
1898 class Test : Foo<Test>.Bar {}
1900 When Foo<Test> is being expanded, 'Test' isn't yet initialized. It's actually in
1901 a really pristine state: it doesn't even know whether 'Test' is a reference or a value type.
1903 We ensure that the MonoClass is in a state that we can canonicalize to:
1905 klass->_byval_arg.data.klass == klass
1906 klass->this_arg.data.klass == klass
1908 If we can't canonicalize 'type', it doesn't matter, since later users of 'type' will do it.
1910 LOCKING: even though we don't explicitly hold a lock, in the problematic case 'ret' is a field
1911 of a MonoClass which currently holds the loader lock. 'type' is local.
1913 if (ret->data.klass == type->data.klass) {
1914 return ret;
1917 /* No need to use locking since nobody is modifying the hash table */
1918 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type))) {
1919 return cached;
1923 /* printf ("%x %x %c %s\n", type->attrs, type->num_mods, type->pinned ? 'p' : ' ', mono_type_full_name (type)); */
1925 if (type == &stype) { // Type was allocated on the stack, so we need to copy it to safety
1926 type = transient ? (MonoType *)g_malloc (MONO_SIZEOF_TYPE) : (MonoType *)mono_image_alloc (m, MONO_SIZEOF_TYPE);
1927 memcpy (type, &stype, MONO_SIZEOF_TYPE);
1929 return type;
1933 MonoType*
1934 mono_metadata_parse_type_checked (MonoImage *m, MonoGenericContainer *container,
1935 short opt_attrs, gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1937 return mono_metadata_parse_type_internal (m, container, opt_attrs, transient, ptr, rptr, error);
1941 * LOCKING: Acquires the loader lock.
1943 MonoType*
1944 mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
1945 const char *ptr, const char **rptr)
1947 ERROR_DECL (error);
1948 MonoType * type = mono_metadata_parse_type_internal (m, NULL, opt_attrs, FALSE, ptr, rptr, error);
1949 mono_error_cleanup (error);
1950 return type;
1953 gboolean
1954 mono_metadata_method_has_param_attrs (MonoImage *m, int def)
1956 MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM];
1957 MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD];
1958 guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST);
1960 if (def < methodt->rows)
1961 lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
1962 else
1963 lastp = m->tables [MONO_TABLE_PARAM].rows + 1;
1965 for (i = param_index; i < lastp; ++i) {
1966 guint32 flags = mono_metadata_decode_row_col (paramt, i - 1, MONO_PARAM_FLAGS);
1967 if (flags)
1968 return TRUE;
1971 return FALSE;
1975 * mono_metadata_get_param_attrs:
1977 * @m The image to loader parameter attributes from
1978 * @def method def token (one based)
1979 * @param_count number of params to decode including the return value
1981 * Return the parameter attributes for the method whose MethodDef index is DEF. The
1982 * returned memory needs to be freed by the caller. If all the param attributes are
1983 * 0, then NULL is returned.
1985 int*
1986 mono_metadata_get_param_attrs (MonoImage *m, int def, int param_count)
1988 MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM];
1989 MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD];
1990 guint32 cols [MONO_PARAM_SIZE];
1991 guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST);
1992 int *pattrs = NULL;
1994 if (def < methodt->rows)
1995 lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
1996 else
1997 lastp = paramt->rows + 1;
1999 for (i = param_index; i < lastp; ++i) {
2000 mono_metadata_decode_row (paramt, i - 1, cols, MONO_PARAM_SIZE);
2001 if (cols [MONO_PARAM_FLAGS]) {
2002 if (!pattrs)
2003 pattrs = g_new0 (int, param_count);
2004 /* at runtime we just ignore this kind of malformed file:
2005 * the verifier can signal the error to the user
2007 if (cols [MONO_PARAM_SEQUENCE] >= param_count)
2008 continue;
2009 pattrs [cols [MONO_PARAM_SEQUENCE]] = cols [MONO_PARAM_FLAGS];
2013 return pattrs;
2018 * mono_metadata_parse_signature:
2019 * \param image metadata context
2020 * \param token metadata token
2022 * Decode a method signature stored in the \c StandAloneSig table
2024 * \returns a \c MonoMethodSignature describing the signature.
2026 MonoMethodSignature*
2027 mono_metadata_parse_signature (MonoImage *image, guint32 token)
2029 ERROR_DECL (error);
2030 MonoMethodSignature *ret;
2031 ret = mono_metadata_parse_signature_checked (image, token, error);
2032 mono_error_cleanup (error);
2033 return ret;
2037 * mono_metadata_parse_signature_checked:
2038 * @image: metadata context
2039 * @token: metadata token
2040 * @error: set on error
2042 * Decode a method signature stored in the STANDALONESIG table
2044 * Returns: a MonoMethodSignature describing the signature. On failure
2045 * returns NULL and sets @error.
2047 MonoMethodSignature*
2048 mono_metadata_parse_signature_checked (MonoImage *image, guint32 token, MonoError *error)
2051 error_init (error);
2052 MonoTableInfo *tables = image->tables;
2053 guint32 idx = mono_metadata_token_index (token);
2054 guint32 sig;
2055 const char *ptr;
2057 if (image_is_dynamic (image)) {
2058 return (MonoMethodSignature *)mono_lookup_dynamic_token (image, token, NULL, error);
2061 g_assert (mono_metadata_token_table(token) == MONO_TABLE_STANDALONESIG);
2063 sig = mono_metadata_decode_row_col (&tables [MONO_TABLE_STANDALONESIG], idx - 1, 0);
2065 ptr = mono_metadata_blob_heap (image, sig);
2066 mono_metadata_decode_blob_size (ptr, &ptr);
2068 return mono_metadata_parse_method_signature_full (image, NULL, 0, ptr, NULL, error);
2072 * mono_metadata_signature_alloc:
2073 * \param image metadata context
2074 * \param nparams number of parameters in the signature
2076 * Allocate a \c MonoMethodSignature structure with the specified number of params.
2077 * The return type and the params types need to be filled later.
2078 * This is a Mono runtime internal function.
2080 * LOCKING: Assumes the loader lock is held.
2082 * \returns the new \c MonoMethodSignature structure.
2084 MonoMethodSignature*
2085 mono_metadata_signature_alloc (MonoImage *m, guint32 nparams)
2087 MonoMethodSignature *sig;
2089 sig = (MonoMethodSignature *)mono_image_alloc0 (m, MONO_SIZEOF_METHOD_SIGNATURE + ((gint32)nparams) * sizeof (MonoType*));
2090 sig->param_count = nparams;
2091 sig->sentinelpos = -1;
2093 return sig;
2096 static MonoMethodSignature*
2097 mono_metadata_signature_dup_internal_with_padding (MonoImage *image, MonoMemPool *mp, MonoMethodSignature *sig, size_t padding)
2099 int sigsize, sig_header_size;
2100 MonoMethodSignature *ret;
2101 sigsize = sig_header_size = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *) + padding;
2102 if (sig->ret)
2103 sigsize += mono_sizeof_type (sig->ret);
2105 if (image) {
2106 ret = (MonoMethodSignature *)mono_image_alloc (image, sigsize);
2107 } else if (mp) {
2108 ret = (MonoMethodSignature *)mono_mempool_alloc (mp, sigsize);
2109 } else {
2110 ret = (MonoMethodSignature *)g_malloc (sigsize);
2113 memcpy (ret, sig, sig_header_size - padding);
2115 // Copy return value because of ownership semantics.
2116 if (sig->ret) {
2117 // Danger! Do not alter padding use without changing the dup_add_this below
2118 intptr_t end_of_header = (intptr_t)( (char*)(ret) + sig_header_size);
2119 ret->ret = (MonoType *)end_of_header;
2120 memcpy (ret->ret, sig->ret, mono_sizeof_type (sig->ret));
2123 return ret;
2126 static MonoMethodSignature*
2127 mono_metadata_signature_dup_internal (MonoImage *image, MonoMemPool *mp, MonoMethodSignature *sig)
2129 return mono_metadata_signature_dup_internal_with_padding (image, mp, sig, 0);
2132 * signature_dup_add_this:
2134 * Make a copy of @sig, adding an explicit this argument.
2136 MonoMethodSignature*
2137 mono_metadata_signature_dup_add_this (MonoImage *image, MonoMethodSignature *sig, MonoClass *klass)
2139 MonoMethodSignature *ret;
2140 ret = mono_metadata_signature_dup_internal_with_padding (image, NULL, sig, sizeof (MonoType *));
2142 ret->param_count = sig->param_count + 1;
2143 ret->hasthis = FALSE;
2145 for (int i = sig->param_count - 1; i >= 0; i --)
2146 ret->params [i + 1] = sig->params [i];
2147 ret->params [0] = m_class_is_valuetype (klass) ? m_class_get_this_arg (klass) : m_class_get_byval_arg (klass);
2149 for (int i = sig->param_count - 1; i >= 0; i --)
2150 g_assert(ret->params [i + 1]->type == sig->params [i]->type && ret->params [i+1]->type != MONO_TYPE_END);
2151 g_assert (ret->ret->type == sig->ret->type && ret->ret->type != MONO_TYPE_END);
2153 return ret;
2158 MonoMethodSignature*
2159 mono_metadata_signature_dup_full (MonoImage *image, MonoMethodSignature *sig)
2161 MonoMethodSignature *ret = mono_metadata_signature_dup_internal (image, NULL, sig);
2163 for (int i = 0 ; i < sig->param_count; i ++)
2164 g_assert(ret->params [i]->type == sig->params [i]->type);
2165 g_assert (ret->ret->type == sig->ret->type);
2167 return ret;
2170 /*The mempool is accessed without synchronization*/
2171 MonoMethodSignature*
2172 mono_metadata_signature_dup_mempool (MonoMemPool *mp, MonoMethodSignature *sig)
2174 return mono_metadata_signature_dup_internal (NULL, mp, sig);
2178 * mono_metadata_signature_dup:
2179 * \param sig method signature
2181 * Duplicate an existing \c MonoMethodSignature so it can be modified.
2182 * This is a Mono runtime internal function.
2184 * \returns the new \c MonoMethodSignature structure.
2186 MonoMethodSignature*
2187 mono_metadata_signature_dup (MonoMethodSignature *sig)
2189 return mono_metadata_signature_dup_full (NULL, sig);
2193 * mono_metadata_signature_size:
2195 * Return the amount of memory allocated to SIG.
2197 guint32
2198 mono_metadata_signature_size (MonoMethodSignature *sig)
2200 return MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
2204 * mono_metadata_parse_method_signature_full:
2205 * \param m metadata context
2206 * \param generic_container: generics container
2207 * \param def the \c MethodDef index or 0 for \c Ref signatures.
2208 * \param ptr pointer to the signature metadata representation
2209 * \param rptr pointer updated to match the end of the decoded stream
2210 * \param error set on error
2213 * Decode a method signature stored at \p ptr.
2214 * This is a Mono runtime internal function.
2216 * LOCKING: Assumes the loader lock is held.
2218 * \returns a \c MonoMethodSignature describing the signature. On error sets
2219 * \p error and returns \c NULL.
2221 MonoMethodSignature *
2222 mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *container,
2223 int def, const char *ptr, const char **rptr, MonoError *error)
2225 MonoMethodSignature *method;
2226 int i, *pattrs = NULL;
2227 guint32 hasthis = 0, explicit_this = 0, call_convention, param_count;
2228 guint32 gen_param_count = 0;
2229 gboolean is_open = FALSE;
2231 error_init (error);
2233 if (*ptr & 0x10)
2234 gen_param_count = 1;
2235 if (*ptr & 0x20)
2236 hasthis = 1;
2237 if (*ptr & 0x40)
2238 explicit_this = 1;
2239 call_convention = *ptr & 0x0F;
2240 ptr++;
2241 if (gen_param_count)
2242 gen_param_count = mono_metadata_decode_value (ptr, &ptr);
2243 param_count = mono_metadata_decode_value (ptr, &ptr);
2245 if (def)
2246 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 */
2248 method = mono_metadata_signature_alloc (m, param_count);
2249 method->hasthis = hasthis;
2250 method->explicit_this = explicit_this;
2251 method->call_convention = call_convention;
2252 method->generic_param_count = gen_param_count;
2254 if (call_convention != 0xa) {
2255 method->ret = mono_metadata_parse_type_checked (m, container, pattrs ? pattrs [0] : 0, FALSE, ptr, &ptr, error);
2256 if (!method->ret) {
2257 mono_metadata_free_method_signature (method);
2258 g_free (pattrs);
2259 return NULL;
2261 is_open = mono_class_is_open_constructed_type (method->ret);
2264 for (i = 0; i < method->param_count; ++i) {
2265 if (*ptr == MONO_TYPE_SENTINEL) {
2266 if (method->call_convention != MONO_CALL_VARARG || def) {
2267 mono_error_set_bad_image (error, m, "Found sentinel for methoddef or no vararg");
2268 g_free (pattrs);
2269 return NULL;
2271 if (method->sentinelpos >= 0) {
2272 mono_error_set_bad_image (error, m, "Found sentinel twice in the same signature.");
2273 g_free (pattrs);
2274 return NULL;
2276 method->sentinelpos = i;
2277 ptr++;
2279 method->params [i] = mono_metadata_parse_type_checked (m, container, pattrs ? pattrs [i+1] : 0, FALSE, ptr, &ptr, error);
2280 if (!method->params [i]) {
2281 mono_metadata_free_method_signature (method);
2282 g_free (pattrs);
2283 return NULL;
2285 if (!is_open)
2286 is_open = mono_class_is_open_constructed_type (method->params [i]);
2289 /* The sentinel could be missing if the caller does not pass any additional arguments */
2290 if (!def && method->call_convention == MONO_CALL_VARARG && method->sentinelpos < 0)
2291 method->sentinelpos = method->param_count;
2293 method->has_type_parameters = is_open;
2295 if (def && (method->call_convention == MONO_CALL_VARARG))
2296 method->sentinelpos = method->param_count;
2298 g_free (pattrs);
2300 if (rptr)
2301 *rptr = ptr;
2303 * Add signature to a cache and increase ref count...
2306 return method;
2310 * mono_metadata_parse_method_signature:
2311 * \param m metadata context
2312 * \param def the \c MethodDef index or 0 for \c Ref signatures.
2313 * \param ptr pointer to the signature metadata representation
2314 * \param rptr pointer updated to match the end of the decoded stream
2316 * Decode a method signature stored at \p ptr.
2317 * This is a Mono runtime internal function.
2319 * LOCKING: Assumes the loader lock is held.
2321 * \returns a \c MonoMethodSignature describing the signature.
2323 MonoMethodSignature *
2324 mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, const char **rptr)
2327 * This function MUST NOT be called by runtime code as it does error handling incorrectly.
2328 * Use mono_metadata_parse_method_signature_full instead.
2329 * It's ok to asser on failure as we no longer use it.
2331 ERROR_DECL (error);
2332 MonoMethodSignature *ret;
2333 ret = mono_metadata_parse_method_signature_full (m, NULL, def, ptr, rptr, error);
2334 mono_error_assert_ok (error);
2336 return ret;
2340 * mono_metadata_free_method_signature:
2341 * \param sig signature to destroy
2343 * Free the memory allocated in the signature \p sig.
2344 * This method needs to be robust and work also on partially-built
2345 * signatures, so it does extra checks.
2347 void
2348 mono_metadata_free_method_signature (MonoMethodSignature *sig)
2350 /* Everything is allocated from mempools */
2352 int i;
2353 if (sig->ret)
2354 mono_metadata_free_type (sig->ret);
2355 for (i = 0; i < sig->param_count; ++i) {
2356 if (sig->params [i])
2357 mono_metadata_free_type (sig->params [i]);
2362 void
2363 mono_metadata_free_inflated_signature (MonoMethodSignature *sig)
2365 int i;
2367 /* Allocated in inflate_generic_signature () */
2368 if (sig->ret)
2369 mono_metadata_free_type (sig->ret);
2370 for (i = 0; i < sig->param_count; ++i) {
2371 if (sig->params [i])
2372 mono_metadata_free_type (sig->params [i]);
2374 g_free (sig);
2377 static gboolean
2378 inflated_method_equal (gconstpointer a, gconstpointer b)
2380 const MonoMethodInflated *ma = (const MonoMethodInflated *)a;
2381 const MonoMethodInflated *mb = (const MonoMethodInflated *)b;
2382 if (ma->declaring != mb->declaring)
2383 return FALSE;
2384 return mono_metadata_generic_context_equal (&ma->context, &mb->context);
2387 static guint
2388 inflated_method_hash (gconstpointer a)
2390 const MonoMethodInflated *ma = (const MonoMethodInflated *)a;
2391 return (mono_metadata_generic_context_hash (&ma->context) ^ mono_aligned_addr_hash (ma->declaring));
2394 static gboolean
2395 inflated_signature_equal (gconstpointer a, gconstpointer b)
2397 const MonoInflatedMethodSignature *sig1 = (const MonoInflatedMethodSignature *)a;
2398 const MonoInflatedMethodSignature *sig2 = (const MonoInflatedMethodSignature *)b;
2400 /* sig->sig is assumed to be canonized */
2401 if (sig1->sig != sig2->sig)
2402 return FALSE;
2403 /* The generic instances are canonized */
2404 return mono_metadata_generic_context_equal (&sig1->context, &sig2->context);
2407 static guint
2408 inflated_signature_hash (gconstpointer a)
2410 const MonoInflatedMethodSignature *sig = (const MonoInflatedMethodSignature *)a;
2412 /* sig->sig is assumed to be canonized */
2413 return mono_metadata_generic_context_hash (&sig->context) ^ mono_aligned_addr_hash (sig->sig);
2416 /*static void
2417 dump_ginst (MonoGenericInst *ginst)
2419 int i;
2420 char *name;
2422 g_print ("Ginst: <");
2423 for (i = 0; i < ginst->type_argc; ++i) {
2424 if (i != 0)
2425 g_print (", ");
2426 name = mono_type_get_name (ginst->type_argv [i]);
2427 g_print ("%s", name);
2428 g_free (name);
2430 g_print (">");
2433 static gboolean type_in_image (MonoType *type, MonoImage *image);
2435 static gboolean
2436 signature_in_image (MonoMethodSignature *sig, MonoImage *image)
2438 gpointer iter = NULL;
2439 MonoType *p;
2441 while ((p = mono_signature_get_params (sig, &iter)) != NULL)
2442 if (type_in_image (p, image))
2443 return TRUE;
2445 return type_in_image (mono_signature_get_return_type (sig), image);
2448 static gboolean
2449 ginst_in_image (MonoGenericInst *ginst, MonoImage *image)
2451 int i;
2453 for (i = 0; i < ginst->type_argc; ++i) {
2454 if (type_in_image (ginst->type_argv [i], image))
2455 return TRUE;
2458 return FALSE;
2461 static gboolean
2462 gclass_in_image (MonoGenericClass *gclass, MonoImage *image)
2464 return m_class_get_image (gclass->container_class) == image ||
2465 ginst_in_image (gclass->context.class_inst, image);
2468 static gboolean
2469 type_in_image (MonoType *type, MonoImage *image)
2471 retry:
2472 switch (type->type) {
2473 case MONO_TYPE_GENERICINST:
2474 return gclass_in_image (type->data.generic_class, image);
2475 case MONO_TYPE_PTR:
2476 type = type->data.type;
2477 goto retry;
2478 case MONO_TYPE_SZARRAY:
2479 type = m_class_get_byval_arg (type->data.klass);
2480 goto retry;
2481 case MONO_TYPE_ARRAY:
2482 type = m_class_get_byval_arg (type->data.array->eklass);
2483 goto retry;
2484 case MONO_TYPE_FNPTR:
2485 return signature_in_image (type->data.method, image);
2486 case MONO_TYPE_VAR:
2487 case MONO_TYPE_MVAR:
2488 return image == mono_get_image_for_generic_param (type->data.generic_param);
2489 default:
2490 /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type_internal () */
2491 return image == m_class_get_image (mono_class_from_mono_type_internal (type));
2495 gboolean
2496 mono_type_in_image (MonoType *type, MonoImage *image)
2498 return type_in_image (type, image);
2501 static inline void
2502 image_sets_lock (void)
2504 mono_os_mutex_lock (&image_sets_mutex);
2507 static inline void
2508 image_sets_unlock (void)
2510 mono_os_mutex_unlock (&image_sets_mutex);
2513 static int
2514 compare_pointers (const void *a, const void *b)
2516 return (size_t)a - (size_t)b;
2519 //1103, 1327, 1597
2520 #define HASH_TABLE_SIZE 1103
2521 static MonoImageSet *img_set_cache [HASH_TABLE_SIZE];
2523 static guint32
2524 mix_hash (uintptr_t source)
2526 unsigned int hash = source;
2528 // Actual hash
2529 hash = (((hash * 215497) >> 16) ^ ((hash * 1823231) + hash));
2531 // Mix in highest bits on 64-bit systems only
2532 if (sizeof (source) > 4)
2533 hash = hash ^ (source >> 32);
2535 return hash;
2538 static guint32
2539 hash_images (MonoImage **images, int nimages)
2541 guint32 res = 0;
2542 int i;
2543 for (i = 0; i < nimages; ++i)
2544 res += mix_hash ((size_t)images [i]);
2546 return res;
2549 static gboolean
2550 compare_img_set (MonoImageSet *set, MonoImage **images, int nimages)
2552 int j, k;
2554 if (set->nimages != nimages)
2555 return FALSE;
2557 for (j = 0; j < nimages; ++j) {
2558 for (k = 0; k < nimages; ++k)
2559 if (set->images [k] == images [j])
2560 break; // Break on match
2562 // If we iterated all the way through set->images, images[j] was *not* found.
2563 if (k == nimages)
2564 break; // Break on "image not found"
2567 // If we iterated all the way through images without breaking, all items in images were found in set->images
2568 return j == nimages;
2572 static MonoImageSet*
2573 img_set_cache_get (MonoImage **images, int nimages)
2575 guint32 hash_code = hash_images (images, nimages);
2576 int index = hash_code % HASH_TABLE_SIZE;
2577 MonoImageSet *img = img_set_cache [index];
2578 if (!img || !compare_img_set (img, images, nimages)) {
2579 UnlockedIncrement (&img_set_cache_miss);
2580 return NULL;
2582 UnlockedIncrement (&img_set_cache_hit);
2583 return img;
2586 static void
2587 img_set_cache_add (MonoImageSet *set)
2589 guint32 hash_code = hash_images (set->images, set->nimages);
2590 int index = hash_code % HASH_TABLE_SIZE;
2591 img_set_cache [index] = set;
2594 static void
2595 img_set_cache_remove (MonoImageSet *is)
2597 guint32 hash_code = hash_images (is->images, is->nimages);
2598 int index = hash_code % HASH_TABLE_SIZE;
2599 if (img_set_cache [index] == is)
2600 img_set_cache [index] = NULL;
2603 * get_image_set:
2605 * Return a MonoImageSet representing the set of images in IMAGES.
2607 static MonoImageSet*
2608 get_image_set (MonoImage **images, int nimages)
2610 int i, j, k;
2611 MonoImageSet *set;
2612 GSList *l;
2614 /* Common case: Image set contains corlib only. If we've seen that case before, we cached the set. */
2615 if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set)
2616 return mscorlib_image_set;
2618 /* Happens with empty generic instances */
2619 // 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.
2620 if (nimages == 0)
2621 return mscorlib_image_set;
2623 set = img_set_cache_get (images, nimages);
2624 if (set)
2625 return set;
2627 image_sets_lock ();
2629 if (!image_sets)
2630 image_sets = g_ptr_array_new ();
2632 // Before we go on, we should check to see whether a MonoImageSet with these images already exists.
2633 // We can search the referred-by imagesets of any one of our images to do this. Arbitrarily pick one here:
2634 if (images [0] == mono_defaults.corlib && nimages > 1)
2635 l = images [1]->image_sets; // Prefer not to search the imagesets of corlib-- that will be a long list.
2636 else
2637 l = images [0]->image_sets;
2639 set = NULL;
2640 while (l) // Iterate over selected list, looking for an imageset with members equal to our target one
2642 set = (MonoImageSet *)l->data;
2644 if (set->nimages == nimages) { // Member count differs, this can't be it
2645 // Compare all members to all members-- order might be different
2646 for (j = 0; j < nimages; ++j) {
2647 for (k = 0; k < nimages; ++k)
2648 if (set->images [k] == images [j])
2649 break; // Break on match
2651 // If we iterated all the way through set->images, images[j] was *not* found.
2652 if (k == nimages)
2653 break; // Break on "image not found"
2656 // If we iterated all the way through images without breaking, all items in images were found in set->images
2657 if (j == nimages) {
2658 // Break on "found a set with equal members".
2659 // This happens in case of a hash collision with a previously cached set.
2660 break;
2664 l = l->next;
2667 // If we iterated all the way through l without breaking, the imageset does not already exist and we should create it
2668 if (!l) {
2669 set = g_new0 (MonoImageSet, 1);
2670 set->nimages = nimages;
2671 set->images = g_new0 (MonoImage*, nimages);
2672 mono_os_mutex_init_recursive (&set->lock);
2673 for (i = 0; i < nimages; ++i)
2674 set->images [i] = images [i];
2675 set->gclass_cache = mono_conc_hashtable_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
2676 set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
2677 set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
2678 set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
2680 set->szarray_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2681 set->array_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2683 for (i = 0; i < nimages; ++i)
2684 set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set);
2686 g_ptr_array_add (image_sets, set);
2687 UnlockedIncrement (&img_set_count); /* locked by image_sets_lock () */
2690 /* Cache the set. If there was a cache collision, the previously cached value will be replaced. */
2691 img_set_cache_add (set);
2693 if (nimages == 1 && images [0] == mono_defaults.corlib) {
2694 mono_memory_barrier ();
2695 mscorlib_image_set = set;
2698 image_sets_unlock ();
2700 return set;
2703 static void
2704 delete_image_set (MonoImageSet *set)
2706 int i;
2708 mono_conc_hashtable_destroy (set->gclass_cache);
2709 g_hash_table_destroy (set->ginst_cache);
2710 g_hash_table_destroy (set->gmethod_cache);
2711 g_hash_table_destroy (set->gsignature_cache);
2713 g_hash_table_destroy (set->szarray_cache);
2714 g_hash_table_destroy (set->array_cache);
2715 if (set->ptr_cache)
2716 g_hash_table_destroy (set->ptr_cache);
2718 mono_wrapper_caches_free (&set->wrapper_caches);
2720 image_sets_lock ();
2722 for (i = 0; i < set->nimages; ++i)
2723 set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set);
2725 g_ptr_array_remove (image_sets, set);
2727 image_sets_unlock ();
2729 img_set_cache_remove (set);
2731 if (set->mempool)
2732 mono_mempool_destroy (set->mempool);
2733 g_free (set->images);
2734 mono_os_mutex_destroy (&set->lock);
2735 g_free (set);
2738 void
2739 mono_image_set_lock (MonoImageSet *set)
2741 mono_os_mutex_lock (&set->lock);
2744 void
2745 mono_image_set_unlock (MonoImageSet *set)
2747 mono_os_mutex_unlock (&set->lock);
2750 gpointer
2751 mono_image_set_alloc (MonoImageSet *set, guint size)
2753 gpointer res;
2755 mono_image_set_lock (set);
2756 if (!set->mempool)
2757 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2758 res = mono_mempool_alloc (set->mempool, size);
2759 mono_image_set_unlock (set);
2761 return res;
2764 gpointer
2765 mono_image_set_alloc0 (MonoImageSet *set, guint size)
2767 gpointer res;
2769 mono_image_set_lock (set);
2770 if (!set->mempool)
2771 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2772 res = mono_mempool_alloc0 (set->mempool, size);
2773 mono_image_set_unlock (set);
2775 return res;
2778 char*
2779 mono_image_set_strdup (MonoImageSet *set, const char *s)
2781 char *res;
2783 mono_image_set_lock (set);
2784 if (!set->mempool)
2785 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2786 res = mono_mempool_strdup (set->mempool, s);
2787 mono_image_set_unlock (set);
2789 return res;
2792 // Get a descriptive string for a MonoImageSet
2793 // Callers are obligated to free buffer with g_free after use
2794 char *
2795 mono_image_set_description (MonoImageSet *set)
2797 GString *result = g_string_new (NULL);
2798 int img;
2799 g_string_append (result, "[");
2800 for (img = 0; img < set->nimages; img++)
2802 if (img > 0)
2803 g_string_append (result, ", ");
2804 g_string_append (result, set->images[img]->name);
2806 g_string_append (result, "]");
2807 return g_string_free (result, FALSE);
2811 * Structure used by the collect_..._images functions to store the image list.
2813 typedef struct {
2814 MonoImage *image_buf [64];
2815 MonoImage **images;
2816 int nimages, images_len;
2817 } CollectData;
2819 static void
2820 collect_data_init (CollectData *data)
2822 data->images = data->image_buf;
2823 data->images_len = 64;
2824 data->nimages = 0;
2827 static void
2828 collect_data_free (CollectData *data)
2830 if (data->images != data->image_buf)
2831 g_free (data->images);
2834 static void
2835 enlarge_data (CollectData *data)
2837 int new_len = data->images_len < 16 ? 16 : data->images_len * 2;
2838 MonoImage **d = g_new (MonoImage *, new_len);
2840 // FIXME: test this
2841 g_assert_not_reached ();
2842 memcpy (d, data->images, data->images_len);
2843 if (data->images != data->image_buf)
2844 g_free (data->images);
2845 data->images = d;
2846 data->images_len = new_len;
2849 static inline void
2850 add_image (MonoImage *image, CollectData *data)
2852 int i;
2854 /* The arrays are small, so use a linear search instead of a hash table */
2855 for (i = 0; i < data->nimages; ++i)
2856 if (data->images [i] == image)
2857 return;
2859 if (data->nimages == data->images_len)
2860 enlarge_data (data);
2862 data->images [data->nimages ++] = image;
2865 static void
2866 collect_type_images (MonoType *type, CollectData *data);
2868 static void
2869 collect_ginst_images (MonoGenericInst *ginst, CollectData *data)
2871 int i;
2873 for (i = 0; i < ginst->type_argc; ++i) {
2874 collect_type_images (ginst->type_argv [i], data);
2878 static void
2879 collect_gclass_images (MonoGenericClass *gclass, CollectData *data)
2881 add_image (m_class_get_image (gclass->container_class), data);
2882 if (gclass->context.class_inst)
2883 collect_ginst_images (gclass->context.class_inst, data);
2886 static void
2887 collect_signature_images (MonoMethodSignature *sig, CollectData *data)
2889 gpointer iter = NULL;
2890 MonoType *p;
2892 collect_type_images (mono_signature_get_return_type (sig), data);
2893 while ((p = mono_signature_get_params (sig, &iter)) != NULL)
2894 collect_type_images (p, data);
2897 static void
2898 collect_inflated_signature_images (MonoInflatedMethodSignature *sig, CollectData *data)
2900 collect_signature_images (sig->sig, data);
2901 if (sig->context.class_inst)
2902 collect_ginst_images (sig->context.class_inst, data);
2903 if (sig->context.method_inst)
2904 collect_ginst_images (sig->context.method_inst, data);
2907 static void
2908 collect_method_images (MonoMethodInflated *method, CollectData *data)
2910 MonoMethod *m = method->declaring;
2912 add_image (m_class_get_image (method->declaring->klass), data);
2913 if (method->context.class_inst)
2914 collect_ginst_images (method->context.class_inst, data);
2915 if (method->context.method_inst)
2916 collect_ginst_images (method->context.method_inst, data);
2918 * Dynamic assemblies have no references, so the images they depend on can be unloaded before them.
2920 if (image_is_dynamic (m_class_get_image (m->klass)))
2921 collect_signature_images (mono_method_signature_internal (m), data);
2924 static void
2925 collect_type_images (MonoType *type, CollectData *data)
2927 retry:
2928 switch (type->type) {
2929 case MONO_TYPE_GENERICINST:
2930 collect_gclass_images (type->data.generic_class, data);
2931 break;
2932 case MONO_TYPE_PTR:
2933 type = type->data.type;
2934 goto retry;
2935 case MONO_TYPE_SZARRAY:
2936 type = m_class_get_byval_arg (type->data.klass);
2937 goto retry;
2938 case MONO_TYPE_ARRAY:
2939 type = m_class_get_byval_arg (type->data.array->eklass);
2940 goto retry;
2941 case MONO_TYPE_FNPTR:
2942 //return signature_in_image (type->data.method, image);
2943 g_assert_not_reached ();
2944 case MONO_TYPE_VAR:
2945 case MONO_TYPE_MVAR:
2947 MonoImage *image = mono_get_image_for_generic_param (type->data.generic_param);
2948 add_image (image, data);
2949 break;
2951 case MONO_TYPE_CLASS:
2952 case MONO_TYPE_VALUETYPE:
2953 add_image (m_class_get_image (mono_class_from_mono_type_internal (type)), data);
2954 break;
2955 default:
2956 add_image (mono_defaults.corlib, data);
2960 typedef struct {
2961 MonoImage *image;
2962 GSList *list;
2963 } CleanForImageUserData;
2965 static gboolean
2966 steal_gclass_in_image (gpointer key, gpointer value, gpointer data)
2968 MonoGenericClass *gclass = (MonoGenericClass *)key;
2969 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
2971 g_assert (gclass_in_image (gclass, user_data->image));
2973 user_data->list = g_slist_prepend (user_data->list, gclass);
2974 return TRUE;
2977 static gboolean
2978 steal_ginst_in_image (gpointer key, gpointer value, gpointer data)
2980 MonoGenericInst *ginst = (MonoGenericInst *)key;
2981 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
2983 // This doesn't work during corlib compilation
2984 //g_assert (ginst_in_image (ginst, user_data->image));
2986 user_data->list = g_slist_prepend (user_data->list, ginst);
2987 return TRUE;
2990 static gboolean
2991 inflated_method_in_image (gpointer key, gpointer value, gpointer data)
2993 MonoImage *image = (MonoImage *)data;
2994 MonoMethodInflated *method = (MonoMethodInflated *)key;
2996 // FIXME:
2997 // https://bugzilla.novell.com/show_bug.cgi?id=458168
2998 g_assert (m_class_get_image (method->declaring->klass) == image ||
2999 (method->context.class_inst && ginst_in_image (method->context.class_inst, image)) ||
3000 (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)));
3002 return TRUE;
3005 static gboolean
3006 inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
3008 MonoImage *image = (MonoImage *)data;
3009 MonoInflatedMethodSignature *sig = (MonoInflatedMethodSignature *)key;
3011 return signature_in_image (sig->sig, image) ||
3012 (sig->context.class_inst && ginst_in_image (sig->context.class_inst, image)) ||
3013 (sig->context.method_inst && ginst_in_image (sig->context.method_inst, image));
3016 static gboolean
3017 class_in_image (gpointer key, gpointer value, gpointer data)
3019 MonoImage *image = (MonoImage *)data;
3020 MonoClass *klass = (MonoClass *)key;
3022 g_assert (type_in_image (m_class_get_byval_arg (klass), image));
3024 return TRUE;
3027 static void
3028 check_gmethod (gpointer key, gpointer value, gpointer data)
3030 MonoMethodInflated *method = (MonoMethodInflated *)key;
3031 MonoImage *image = (MonoImage *)data;
3033 if (method->context.class_inst)
3034 g_assert (!ginst_in_image (method->context.class_inst, image));
3035 if (method->context.method_inst)
3036 g_assert (!ginst_in_image (method->context.method_inst, image));
3037 if (((MonoMethod*)method)->signature)
3038 g_assert (!signature_in_image (mono_method_signature_internal ((MonoMethod*)method), image));
3042 * check_image_sets:
3044 * Run a consistency check on the image set data structures.
3046 static G_GNUC_UNUSED void
3047 check_image_sets (MonoImage *image)
3049 int i;
3050 GSList *l = image->image_sets;
3052 if (!image_sets)
3053 return;
3055 for (i = 0; i < image_sets->len; ++i) {
3056 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
3058 if (!g_slist_find (l, set)) {
3059 g_hash_table_foreach (set->gmethod_cache, check_gmethod, image);
3064 void
3065 mono_metadata_clean_for_image (MonoImage *image)
3067 CleanForImageUserData ginst_data, gclass_data;
3068 GSList *l, *set_list;
3070 //check_image_sets (image);
3073 * The data structures could reference each other so we delete them in two phases.
3074 * This is required because of the hashing functions in gclass/ginst_cache.
3076 ginst_data.image = gclass_data.image = image;
3077 ginst_data.list = gclass_data.list = NULL;
3079 /* Collect the items to delete */
3080 /* delete_image_set () modifies the lists so make a copy */
3081 for (l = image->image_sets; l; l = l->next) {
3082 MonoImageSet *set = (MonoImageSet *)l->data;
3084 mono_image_set_lock (set);
3085 mono_conc_hashtable_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data);
3086 g_hash_table_foreach_steal (set->ginst_cache, steal_ginst_in_image, &ginst_data);
3087 g_hash_table_foreach_remove (set->gmethod_cache, inflated_method_in_image, image);
3088 g_hash_table_foreach_remove (set->gsignature_cache, inflated_signature_in_image, image);
3090 g_hash_table_foreach_steal (set->szarray_cache, class_in_image, image);
3091 g_hash_table_foreach_steal (set->array_cache, class_in_image, image);
3092 if (set->ptr_cache)
3093 g_hash_table_foreach_steal (set->ptr_cache, class_in_image, image);
3094 mono_image_set_unlock (set);
3097 /* Delete the removed items */
3098 for (l = ginst_data.list; l; l = l->next)
3099 free_generic_inst ((MonoGenericInst *)l->data);
3100 for (l = gclass_data.list; l; l = l->next)
3101 free_generic_class ((MonoGenericClass *)l->data);
3102 g_slist_free (ginst_data.list);
3103 g_slist_free (gclass_data.list);
3104 /* delete_image_set () modifies the lists so make a copy */
3105 set_list = g_slist_copy (image->image_sets);
3106 for (l = set_list; l; l = l->next) {
3107 MonoImageSet *set = (MonoImageSet *)l->data;
3109 delete_image_set (set);
3111 g_slist_free (set_list);
3114 static void
3115 free_inflated_method (MonoMethodInflated *imethod)
3117 MonoMethod *method = (MonoMethod*)imethod;
3119 if (method->signature)
3120 mono_metadata_free_inflated_signature (method->signature);
3122 if (method->wrapper_type)
3123 g_free (((MonoMethodWrapper*)method)->method_data);
3125 g_free (method);
3128 static void
3129 free_generic_inst (MonoGenericInst *ginst)
3131 int i;
3133 /* The ginst itself is allocated from the image set mempool */
3134 for (i = 0; i < ginst->type_argc; ++i)
3135 mono_metadata_free_type (ginst->type_argv [i]);
3138 static void
3139 free_generic_class (MonoGenericClass *gclass)
3141 /* The gclass itself is allocated from the image set mempool */
3142 if (gclass->cached_class && m_class_get_interface_id (gclass->cached_class))
3143 mono_unload_interface_id (gclass->cached_class);
3146 static void
3147 free_inflated_signature (MonoInflatedMethodSignature *sig)
3149 mono_metadata_free_inflated_signature (sig->sig);
3150 g_free (sig);
3154 * mono_metadata_get_inflated_signature:
3156 * Given an inflated signature and a generic context, return a canonical copy of the
3157 * signature. The returned signature might be equal to SIG or it might be a cached copy.
3159 MonoMethodSignature *
3160 mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericContext *context)
3162 MonoInflatedMethodSignature helper;
3163 MonoInflatedMethodSignature *res;
3164 CollectData data;
3165 MonoImageSet *set;
3167 helper.sig = sig;
3168 helper.context.class_inst = context->class_inst;
3169 helper.context.method_inst = context->method_inst;
3171 collect_data_init (&data);
3173 collect_inflated_signature_images (&helper, &data);
3175 set = get_image_set (data.images, data.nimages);
3177 collect_data_free (&data);
3179 mono_image_set_lock (set);
3181 res = (MonoInflatedMethodSignature *)g_hash_table_lookup (set->gsignature_cache, &helper);
3182 if (!res) {
3183 res = g_new0 (MonoInflatedMethodSignature, 1);
3184 res->sig = sig;
3185 res->context.class_inst = context->class_inst;
3186 res->context.method_inst = context->method_inst;
3187 g_hash_table_insert (set->gsignature_cache, res, res);
3190 mono_image_set_unlock (set);
3192 return res->sig;
3195 MonoImageSet *
3196 mono_metadata_get_image_set_for_class (MonoClass *klass)
3198 MonoImageSet *set;
3199 CollectData image_set_data;
3201 collect_data_init (&image_set_data);
3202 collect_type_images (m_class_get_byval_arg (klass), &image_set_data);
3203 set = get_image_set (image_set_data.images, image_set_data.nimages);
3204 collect_data_free (&image_set_data);
3206 return set;
3209 MonoImageSet *
3210 mono_metadata_get_image_set_for_method (MonoMethodInflated *method)
3212 MonoImageSet *set;
3213 CollectData image_set_data;
3215 collect_data_init (&image_set_data);
3216 collect_method_images (method, &image_set_data);
3217 set = get_image_set (image_set_data.images, image_set_data.nimages);
3218 collect_data_free (&image_set_data);
3220 return set;
3223 static gboolean
3224 type_is_gtd (MonoType *type)
3226 switch (type->type) {
3227 case MONO_TYPE_CLASS:
3228 case MONO_TYPE_VALUETYPE:
3229 return mono_class_is_gtd (type->data.klass);
3230 default:
3231 return FALSE;
3236 * mono_metadata_get_generic_inst:
3238 * Given a list of types, return a MonoGenericInst that represents that list.
3239 * The returned MonoGenericInst has its own copy of the list of types. The list
3240 * passed in the argument can be freed, modified or disposed of.
3243 MonoGenericInst *
3244 mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
3246 MonoGenericInst *ginst;
3247 gboolean is_open;
3248 int i;
3249 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3251 for (i = 0; i < type_argc; ++i)
3252 if (mono_class_is_open_constructed_type (type_argv [i]))
3253 break;
3254 is_open = (i < type_argc);
3256 ginst = (MonoGenericInst *)g_alloca (size);
3257 memset (ginst, 0, sizeof (MonoGenericInst));
3258 ginst->is_open = is_open;
3259 ginst->type_argc = type_argc;
3260 memcpy (ginst->type_argv, type_argv, type_argc * sizeof (MonoType *));
3262 for (i = 0; i < type_argc; ++i) {
3263 MonoType *t = ginst->type_argv [i];
3264 if (type_is_gtd (t)) {
3265 ginst->type_argv [i] = mono_class_gtd_get_canonical_inst (t->data.klass);
3269 return mono_metadata_get_canonical_generic_inst (ginst);
3274 * mono_metadata_get_canonical_generic_inst:
3275 * \param candidate an arbitrary generic instantiation
3277 * \returns the canonical generic instantiation that represents the given
3278 * candidate by identifying the image set for the candidate instantiation and
3279 * finding the instance in the image set or adding a copy of the given instance
3280 * to the image set.
3282 * The returned MonoGenericInst has its own copy of the list of types. The list
3283 * passed in the argument can be freed, modified or disposed of.
3286 MonoGenericInst *
3287 mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate)
3289 CollectData data;
3290 int type_argc = candidate->type_argc;
3291 gboolean is_open = candidate->is_open;
3292 MonoImageSet *set;
3294 collect_data_init (&data);
3296 collect_ginst_images (candidate, &data);
3298 set = get_image_set (data.images, data.nimages);
3300 collect_data_free (&data);
3302 mono_image_set_lock (set);
3304 MonoGenericInst *ginst = (MonoGenericInst *)g_hash_table_lookup (set->ginst_cache, candidate);
3305 if (!ginst) {
3306 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3307 ginst = (MonoGenericInst *)mono_image_set_alloc0 (set, size);
3308 #ifndef MONO_SMALL_CONFIG
3309 ginst->id = mono_atomic_inc_i32 (&next_generic_inst_id);
3310 #endif
3311 ginst->is_open = is_open;
3312 ginst->type_argc = type_argc;
3314 for (int i = 0; i < type_argc; ++i)
3315 ginst->type_argv [i] = mono_metadata_type_dup (NULL, candidate->type_argv [i]);
3317 g_hash_table_insert (set->ginst_cache, ginst, ginst);
3320 mono_image_set_unlock (set);
3321 return ginst;
3324 static gboolean
3325 mono_metadata_is_type_builder_generic_type_definition (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3327 MonoGenericContainer *container = mono_class_get_generic_container (container_class);
3329 if (!is_dynamic || m_class_was_typebuilder (container_class) || container->type_argc != inst->type_argc)
3330 return FALSE;
3331 return inst == container->context.class_inst;
3335 * mono_metadata_lookup_generic_class:
3337 * Returns a MonoGenericClass with the given properties.
3340 MonoGenericClass *
3341 mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3343 MonoGenericClass *gclass;
3344 MonoGenericClass helper;
3345 gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic);
3346 MonoImageSet *set;
3347 CollectData data;
3349 g_assert (mono_class_get_generic_container (container_class)->type_argc == inst->type_argc);
3351 memset (&helper, 0, sizeof(helper)); // act like g_new0
3352 helper.container_class = container_class;
3353 helper.context.class_inst = inst;
3354 helper.is_dynamic = is_dynamic; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
3355 helper.is_tb_open = is_tb_open;
3357 collect_data_init (&data);
3359 collect_gclass_images (&helper, &data);
3361 set = get_image_set (data.images, data.nimages);
3363 collect_data_free (&data);
3365 gclass = (MonoGenericClass *)mono_conc_hashtable_lookup (set->gclass_cache, &helper);
3367 /* A tripwire just to keep us honest */
3368 g_assert (!helper.cached_class);
3370 if (gclass)
3371 return gclass;
3373 gclass = mono_image_set_new0 (set, MonoGenericClass, 1);
3374 if (is_dynamic)
3375 gclass->is_dynamic = 1;
3377 gclass->is_tb_open = is_tb_open;
3378 gclass->container_class = container_class;
3379 gclass->context.class_inst = inst;
3380 gclass->context.method_inst = NULL;
3381 gclass->owner = set;
3382 if (inst == mono_class_get_generic_container (container_class)->context.class_inst && !is_tb_open)
3383 gclass->cached_class = container_class;
3385 mono_image_set_lock (set);
3387 MonoGenericClass *gclass2 = (MonoGenericClass*)mono_conc_hashtable_insert (set->gclass_cache, gclass, gclass);
3388 if (!gclass2)
3389 gclass2 = gclass;
3391 // g_hash_table_insert (set->gclass_cache, gclass, gclass);
3393 mono_image_set_unlock (set);
3395 return gclass2;
3399 * mono_metadata_inflate_generic_inst:
3401 * Instantiate the generic instance @ginst with the context @context.
3402 * Check @error for success.
3405 MonoGenericInst *
3406 mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context, MonoError *error)
3408 MonoType **type_argv;
3409 MonoGenericInst *nginst = NULL;
3410 int i, count = 0;
3412 error_init (error);
3414 if (!ginst->is_open)
3415 return ginst;
3417 type_argv = g_new0 (MonoType*, ginst->type_argc);
3419 for (i = 0; i < ginst->type_argc; i++) {
3420 type_argv [i] = mono_class_inflate_generic_type_checked (ginst->type_argv [i], context, error);
3421 if (!mono_error_ok (error))
3422 goto cleanup;
3423 ++count;
3426 nginst = mono_metadata_get_generic_inst (ginst->type_argc, type_argv);
3428 cleanup:
3429 for (i = 0; i < count; i++)
3430 mono_metadata_free_type (type_argv [i]);
3431 g_free (type_argv);
3433 return nginst;
3436 MonoGenericInst *
3437 mono_metadata_parse_generic_inst (MonoImage *m, MonoGenericContainer *container,
3438 int count, const char *ptr, const char **rptr, MonoError *error)
3440 MonoType **type_argv;
3441 MonoGenericInst *ginst = NULL;
3442 int i, parse_count = 0;
3444 error_init (error);
3445 type_argv = g_new0 (MonoType*, count);
3447 for (i = 0; i < count; i++) {
3448 /* this can be a transient type, mono_metadata_get_generic_inst will allocate
3449 * a canonical one, if needed.
3451 MonoType *t = mono_metadata_parse_type_checked (m, container, 0, TRUE, ptr, &ptr, error);
3452 if (!t)
3453 goto cleanup;
3454 type_argv [i] = t;
3455 parse_count++;
3458 if (rptr)
3459 *rptr = ptr;
3461 g_assert (parse_count == count);
3462 ginst = mono_metadata_get_generic_inst (count, type_argv);
3464 cleanup:
3465 for (i = 0; i < parse_count; i++)
3466 mono_metadata_free_type (type_argv [i]);
3467 g_free (type_argv);
3469 return ginst;
3472 static gboolean
3473 do_mono_metadata_parse_generic_class (MonoType *type, MonoImage *m, MonoGenericContainer *container,
3474 const char *ptr, const char **rptr, MonoError *error)
3476 MonoGenericInst *inst;
3477 MonoClass *gklass;
3478 MonoType *gtype;
3479 int count;
3481 error_init (error);
3483 // XXX how about transient?
3484 gtype = mono_metadata_parse_type_checked (m, NULL, 0, FALSE, ptr, &ptr, error);
3485 if (gtype == NULL)
3486 return FALSE;
3488 gklass = mono_class_from_mono_type_internal (gtype);
3489 if (!mono_class_is_gtd (gklass)) {
3490 mono_error_set_bad_image (error, m, "Generic instance with non-generic definition");
3491 return FALSE;
3494 count = mono_metadata_decode_value (ptr, &ptr);
3495 inst = mono_metadata_parse_generic_inst (m, container, count, ptr, &ptr, error);
3496 if (inst == NULL)
3497 return FALSE;
3499 if (rptr)
3500 *rptr = ptr;
3502 type->data.generic_class = mono_metadata_lookup_generic_class (gklass, inst, FALSE);
3503 return TRUE;
3507 * select_container:
3508 * @gc: The generic container to normalize
3509 * @type: The kind of generic parameters the resulting generic-container should contain
3512 static MonoGenericContainer *
3513 select_container (MonoGenericContainer *gc, MonoTypeEnum type)
3515 gboolean is_var = (type == MONO_TYPE_VAR);
3516 if (!gc)
3517 return NULL;
3519 g_assert (is_var || type == MONO_TYPE_MVAR);
3521 if (is_var) {
3522 if (gc->is_method || gc->parent)
3524 * The current MonoGenericContainer is a generic method -> its `parent'
3525 * points to the containing class'es container.
3527 return gc->parent;
3530 return gc;
3533 MonoGenericContainer *
3534 mono_get_anonymous_container_for_image (MonoImage *image, gboolean is_mvar)
3536 MonoGenericContainer **container_pointer;
3537 if (is_mvar)
3538 container_pointer = &image->anonymous_generic_method_container;
3539 else
3540 container_pointer = &image->anonymous_generic_class_container;
3541 MonoGenericContainer *result = *container_pointer;
3543 // This container has never been created; make it now.
3544 if (!result)
3546 // Note this is never deallocated anywhere-- it exists for the lifetime of the image it's allocated from
3547 result = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
3548 result->owner.image = image;
3549 result->is_anonymous = TRUE;
3550 result->is_method = is_mvar;
3552 // If another thread already made a container, use that and leak this new one.
3553 // (Technically it would currently be safe to just assign instead of CASing.)
3554 MonoGenericContainer *exchange = (MonoGenericContainer *)mono_atomic_cas_ptr ((volatile gpointer *)container_pointer, result, NULL);
3555 if (exchange)
3556 result = exchange;
3558 return result;
3561 #define FAST_GPARAM_CACHE_SIZE 16
3563 static MonoGenericParam*
3564 lookup_anon_gparam (MonoImage *image, MonoGenericContainer *container, gint32 param_num, gboolean is_mvar)
3566 if (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE) {
3567 MonoGenericParam *cache = is_mvar ? image->mvar_gparam_cache_fast : image->var_gparam_cache_fast;
3568 if (!cache)
3569 return NULL;
3570 return &cache[param_num];
3571 } else {
3572 MonoGenericParam key;
3573 memset (&key, 0, sizeof (key));
3574 key.owner = container;
3575 key.num = param_num;
3576 key.gshared_constraint = NULL;
3577 MonoConcurrentHashTable *cache = is_mvar ? image->mvar_gparam_cache : image->var_gparam_cache;
3578 if (!cache)
3579 return NULL;
3580 return (MonoGenericParam*)mono_conc_hashtable_lookup (cache, &key);
3584 static MonoGenericParam*
3585 publish_anon_gparam_fast (MonoImage *image, MonoGenericContainer *container, gint32 param_num)
3587 g_assert (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE);
3588 MonoGenericParam **cache = container->is_method ? &image->mvar_gparam_cache_fast : &image->var_gparam_cache_fast;
3589 if (!*cache) {
3590 mono_image_lock (image);
3591 if (!*cache) {
3592 *cache = (MonoGenericParam*)mono_image_alloc0 (image, sizeof (MonoGenericParam) * FAST_GPARAM_CACHE_SIZE);
3593 for (gint32 i = 0; i < FAST_GPARAM_CACHE_SIZE; ++i) {
3594 MonoGenericParam *param = &(*cache)[i];
3595 param->owner = container;
3596 param->num = i;
3599 mono_image_unlock (image);
3601 return &(*cache)[param_num];
3605 * publish_anon_gparam_slow:
3607 * Publish \p gparam anonymous generic parameter to the anon gparam cache for \p image.
3609 * LOCKING: takes the image lock.
3611 static MonoGenericParam*
3612 publish_anon_gparam_slow (MonoImage *image, MonoGenericParam *gparam)
3614 MonoConcurrentHashTable **cache = gparam->owner->is_method ? &image->mvar_gparam_cache : &image->var_gparam_cache;
3615 if (!*cache) {
3616 mono_image_lock (image);
3617 if (!*cache) {
3618 MonoConcurrentHashTable *ht = mono_conc_hashtable_new ((GHashFunc)mono_metadata_generic_param_hash,
3619 (GEqualFunc) mono_metadata_generic_param_equal);
3620 mono_atomic_store_release (cache, ht);
3622 mono_image_unlock (image);
3624 MonoGenericParam *other = (MonoGenericParam*)mono_conc_hashtable_insert (*cache, gparam, gparam);
3625 // If another thread published first return their param, otherwise return ours.
3626 return other ? other : gparam;
3630 * mono_metadata_create_anon_gparam:
3631 * \param image the MonoImage that owns the anonymous generic parameter
3632 * \param param_num the parameter number
3633 * \param is_mvar TRUE if this is a method generic parameter, FALSE if it's a class generic parameter.
3635 * Returns: a new, or exisisting \c MonoGenericParam for an anonymous generic parameter with the given properties.
3637 * LOCKING: takes the image lock.
3639 MonoGenericParam*
3640 mono_metadata_create_anon_gparam (MonoImage *image, gint32 param_num, gboolean is_mvar)
3642 MonoGenericContainer *container = mono_get_anonymous_container_for_image (image, is_mvar);
3643 MonoGenericParam *gparam = lookup_anon_gparam (image, container, param_num, is_mvar);
3644 if (gparam)
3645 return gparam;
3646 if (param_num >= 0 && param_num < FAST_GPARAM_CACHE_SIZE) {
3647 return publish_anon_gparam_fast (image, container, param_num);
3648 } else {
3649 // Create a candidate generic param and try to insert it in the cache.
3650 // If multiple threads both try to publish the same param, all but one
3651 // will leak, but that's okay.
3652 gparam = (MonoGenericParam*)mono_image_alloc0 (image, sizeof (MonoGenericParam));
3653 gparam->owner = container;
3654 gparam->num = param_num;
3656 return publish_anon_gparam_slow (image, gparam);
3661 * mono_metadata_parse_generic_param:
3662 * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
3663 * see mono_metadata_parse_type_checked() for details.
3664 * Internal routine to parse a generic type parameter.
3665 * LOCKING: Acquires the loader lock
3667 static MonoGenericParam *
3668 mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_container,
3669 MonoTypeEnum type, const char *ptr, const char **rptr, MonoError *error)
3671 int index = mono_metadata_decode_value (ptr, &ptr);
3672 if (rptr)
3673 *rptr = ptr;
3675 error_init (error);
3677 generic_container = select_container (generic_container, type);
3678 if (!generic_container) {
3679 gboolean is_mvar = FALSE;
3680 switch (type)
3682 case MONO_TYPE_VAR:
3683 break;
3684 case MONO_TYPE_MVAR:
3685 is_mvar = TRUE;
3686 break;
3687 default:
3688 g_error ("Cerating generic param object with invalid MonoType"); // This is not a generic param
3691 return mono_metadata_create_anon_gparam (m, index, is_mvar);
3694 if (index >= generic_container->type_argc) {
3695 mono_error_set_bad_image (error, m, "Invalid generic %s parameter index %d, max index is %d",
3696 generic_container->is_method ? "method" : "type",
3697 index, generic_container->type_argc);
3698 return NULL;
3701 //This can't return NULL
3702 return mono_generic_container_get_param (generic_container, index);
3706 * mono_metadata_get_shared_type:
3708 * Return a shared instance of TYPE, if available, NULL otherwise.
3709 * Shared MonoType instances help save memory. Their contents should not be modified
3710 * by the caller. They do not need to be freed as their lifetime is bound by either
3711 * the lifetime of the runtime (builtin types), or the lifetime of the MonoClass
3712 * instance they are embedded in. If they are freed, they should be freed using
3713 * mono_metadata_free_type () instead of g_free ().
3715 MonoType*
3716 mono_metadata_get_shared_type (MonoType *type)
3718 MonoType *cached;
3720 /* No need to use locking since nobody is modifying the hash table */
3721 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type)))
3722 return cached;
3724 switch (type->type){
3725 case MONO_TYPE_CLASS:
3726 case MONO_TYPE_VALUETYPE:
3727 if (type == m_class_get_byval_arg (type->data.klass))
3728 return type;
3729 if (type == m_class_get_this_arg (type->data.klass))
3730 return type;
3731 break;
3732 default:
3733 break;
3736 return NULL;
3739 static gboolean
3740 compare_type_literals (MonoImage *image, int class_type, int type_type, MonoError *error)
3742 error_init (error);
3744 /* _byval_arg.type can be zero if we're decoding a type that references a class been loading.
3745 * See mcs/test/gtest-440. and #650936.
3746 * FIXME This better be moved to the metadata verifier as it can catch more cases.
3748 if (!class_type)
3749 return TRUE;
3750 /* NET 1.1 assemblies might encode string and object in a denormalized way.
3751 * See #675464.
3753 if (class_type == type_type)
3754 return TRUE;
3756 if (type_type == MONO_TYPE_CLASS) {
3757 if (class_type == MONO_TYPE_STRING || class_type == MONO_TYPE_OBJECT)
3758 return TRUE;
3759 //XXX stringify this argument
3760 mono_error_set_bad_image (error, image, "Expected reference type but got type kind %d", class_type);
3761 return FALSE;
3764 g_assert (type_type == MONO_TYPE_VALUETYPE);
3765 switch (class_type) {
3766 case MONO_TYPE_BOOLEAN:
3767 case MONO_TYPE_CHAR:
3768 case MONO_TYPE_I1:
3769 case MONO_TYPE_U1:
3770 case MONO_TYPE_I2:
3771 case MONO_TYPE_U2:
3772 case MONO_TYPE_I4:
3773 case MONO_TYPE_U4:
3774 case MONO_TYPE_I8:
3775 case MONO_TYPE_U8:
3776 case MONO_TYPE_R4:
3777 case MONO_TYPE_R8:
3778 case MONO_TYPE_I:
3779 case MONO_TYPE_U:
3780 case MONO_TYPE_CLASS:
3781 return TRUE;
3782 default:
3783 //XXX stringify this argument
3784 mono_error_set_bad_image (error, image, "Expected value type but got type kind %d", class_type);
3785 return FALSE;
3789 static gboolean
3790 verify_var_type_and_container (MonoImage *image, int var_type, MonoGenericContainer *container, MonoError *error)
3792 error_init (error);
3793 if (var_type == MONO_TYPE_MVAR) {
3794 if (!container->is_method) { //MVAR and a method container
3795 mono_error_set_bad_image (error, image, "MVAR parsed in a context without a method container");
3796 return FALSE;
3798 } else {
3799 if (!(!container->is_method || //VAR and class container
3800 (container->is_method && container->parent))) { //VAR and method container with parent
3801 mono_error_set_bad_image (error, image, "VAR parsed in a context without a class container");
3802 return FALSE;
3805 return TRUE;
3809 * do_mono_metadata_parse_type:
3810 * @type: MonoType to be filled in with the return value
3811 * @m: image context
3812 * @generic_context: generics_context
3813 * @transient: whenever to allocate data from the heap
3814 * @ptr: pointer to the encoded type
3815 * @rptr: pointer where the end of the encoded type is saved
3817 * Internal routine used to "fill" the contents of @type from an
3818 * allocated pointer. This is done this way to avoid doing too
3819 * many mini-allocations (particularly for the MonoFieldType which
3820 * most of the time is just a MonoType, but sometimes might be augmented).
3822 * This routine is used by mono_metadata_parse_type and
3823 * mono_metadata_parse_field_type
3825 * This extracts a Type as specified in Partition II (22.2.12)
3827 * Returns: FALSE if the type could not be loaded
3829 static gboolean
3830 do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container,
3831 gboolean transient, const char *ptr, const char **rptr, MonoError *error)
3833 error_init (error);
3835 type->type = (MonoTypeEnum)mono_metadata_decode_value (ptr, &ptr);
3837 switch (type->type){
3838 case MONO_TYPE_VOID:
3839 case MONO_TYPE_BOOLEAN:
3840 case MONO_TYPE_CHAR:
3841 case MONO_TYPE_I1:
3842 case MONO_TYPE_U1:
3843 case MONO_TYPE_I2:
3844 case MONO_TYPE_U2:
3845 case MONO_TYPE_I4:
3846 case MONO_TYPE_U4:
3847 case MONO_TYPE_I8:
3848 case MONO_TYPE_U8:
3849 case MONO_TYPE_R4:
3850 case MONO_TYPE_R8:
3851 case MONO_TYPE_I:
3852 case MONO_TYPE_U:
3853 case MONO_TYPE_STRING:
3854 case MONO_TYPE_OBJECT:
3855 case MONO_TYPE_TYPEDBYREF:
3856 break;
3857 case MONO_TYPE_VALUETYPE:
3858 case MONO_TYPE_CLASS: {
3859 guint32 token;
3860 MonoClass *klass;
3861 token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr);
3862 klass = mono_class_get_checked (m, token, error);
3863 type->data.klass = klass;
3864 if (!klass)
3865 return FALSE;
3867 if (!compare_type_literals (m, m_class_get_byval_arg (klass)->type, type->type, error))
3868 return FALSE;
3870 break;
3872 case MONO_TYPE_SZARRAY: {
3873 MonoType *etype = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
3874 if (!etype)
3875 return FALSE;
3877 type->data.klass = mono_class_from_mono_type_internal (etype);
3879 if (transient)
3880 mono_metadata_free_type (etype);
3882 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.
3883 break;
3885 case MONO_TYPE_PTR: {
3886 type->data.type = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
3887 if (!type->data.type)
3888 return FALSE;
3889 break;
3891 case MONO_TYPE_FNPTR: {
3892 type->data.method = mono_metadata_parse_method_signature_full (m, container, 0, ptr, &ptr, error);
3893 if (!type->data.method)
3894 return FALSE;
3895 break;
3897 case MONO_TYPE_ARRAY: {
3898 type->data.array = mono_metadata_parse_array_internal (m, container, transient, ptr, &ptr, error);
3899 if (!type->data.array)
3900 return FALSE;
3901 break;
3903 case MONO_TYPE_MVAR:
3904 case MONO_TYPE_VAR: {
3905 if (container && !verify_var_type_and_container (m, type->type, container, error))
3906 return FALSE;
3908 type->data.generic_param = mono_metadata_parse_generic_param (m, container, type->type, ptr, &ptr, error);
3909 if (!type->data.generic_param)
3910 return FALSE;
3912 break;
3914 case MONO_TYPE_GENERICINST: {
3915 if (!do_mono_metadata_parse_generic_class (type, m, container, ptr, &ptr, error))
3916 return FALSE;
3917 break;
3919 default:
3920 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);
3921 return FALSE;
3924 if (rptr)
3925 *rptr = ptr;
3926 return TRUE;
3930 * mono_metadata_free_type:
3931 * \param type type to free
3933 * Free the memory allocated for type \p type which is allocated on the heap.
3935 void
3936 mono_metadata_free_type (MonoType *type)
3938 if (type >= builtin_types && type < builtin_types + NBUILTIN_TYPES ())
3939 return;
3941 switch (type->type){
3942 case MONO_TYPE_OBJECT:
3943 case MONO_TYPE_STRING:
3944 if (!type->data.klass)
3945 break;
3946 /* fall through */
3947 case MONO_TYPE_CLASS:
3948 case MONO_TYPE_VALUETYPE:
3949 if (type == m_class_get_byval_arg (type->data.klass) || type == m_class_get_this_arg (type->data.klass))
3950 return;
3951 break;
3952 case MONO_TYPE_PTR:
3953 mono_metadata_free_type (type->data.type);
3954 break;
3955 case MONO_TYPE_FNPTR:
3956 mono_metadata_free_method_signature (type->data.method);
3957 break;
3958 case MONO_TYPE_ARRAY:
3959 mono_metadata_free_array (type->data.array);
3960 break;
3961 default:
3962 break;
3965 g_free (type);
3968 #if 0
3969 static void
3970 hex_dump (const char *buffer, int base, int count)
3972 int show_header = 1;
3973 int i;
3975 if (count < 0){
3976 count = -count;
3977 show_header = 0;
3980 for (i = 0; i < count; i++){
3981 if (show_header)
3982 if ((i % 16) == 0)
3983 printf ("\n0x%08x: ", (unsigned char) base + i);
3985 printf ("%02x ", (unsigned char) (buffer [i]));
3987 fflush (stdout);
3989 #endif
3991 /**
3992 * @ptr: Points to the beginning of the Section Data (25.3)
3994 static MonoExceptionClause*
3995 parse_section_data (MonoImage *m, int *num_clauses, const unsigned char *ptr, MonoError *error)
3997 unsigned char sect_data_flags;
3998 int is_fat;
3999 guint32 sect_data_len;
4000 MonoExceptionClause* clauses = NULL;
4002 error_init (error);
4004 while (1) {
4005 /* align on 32-bit boundary */
4006 ptr = dword_align (ptr);
4007 sect_data_flags = *ptr;
4008 ptr++;
4010 is_fat = sect_data_flags & METHOD_HEADER_SECTION_FAT_FORMAT;
4011 if (is_fat) {
4012 sect_data_len = (ptr [2] << 16) | (ptr [1] << 8) | ptr [0];
4013 ptr += 3;
4014 } else {
4015 sect_data_len = ptr [0];
4016 ++ptr;
4019 if (sect_data_flags & METHOD_HEADER_SECTION_EHTABLE) {
4020 const unsigned char *p = dword_align (ptr);
4021 int i;
4022 *num_clauses = is_fat ? sect_data_len / 24: sect_data_len / 12;
4023 /* we could just store a pointer if we don't need to byteswap */
4024 clauses = (MonoExceptionClause *)g_malloc0 (sizeof (MonoExceptionClause) * (*num_clauses));
4025 for (i = 0; i < *num_clauses; ++i) {
4026 MonoExceptionClause *ec = &clauses [i];
4027 guint32 tof_value;
4028 if (is_fat) {
4029 ec->flags = read32 (p);
4030 ec->try_offset = read32 (p + 4);
4031 ec->try_len = read32 (p + 8);
4032 ec->handler_offset = read32 (p + 12);
4033 ec->handler_len = read32 (p + 16);
4034 tof_value = read32 (p + 20);
4035 p += 24;
4036 } else {
4037 ec->flags = read16 (p);
4038 ec->try_offset = read16 (p + 2);
4039 ec->try_len = *(p + 4);
4040 ec->handler_offset = read16 (p + 5);
4041 ec->handler_len = *(p + 7);
4042 tof_value = read32 (p + 8);
4043 p += 12;
4045 if (ec->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4046 ec->data.filter_offset = tof_value;
4047 } else if (ec->flags == MONO_EXCEPTION_CLAUSE_NONE) {
4048 ec->data.catch_class = NULL;
4049 if (tof_value) {
4050 ec->data.catch_class = mono_class_get_checked (m, tof_value, error);
4051 if (!is_ok (error)) {
4052 g_free (clauses);
4053 return NULL;
4056 } else {
4057 ec->data.catch_class = NULL;
4059 /* g_print ("try %d: %x %04x-%04x %04x\n", i, ec->flags, ec->try_offset, ec->try_offset+ec->try_len, ec->try_len); */
4063 if (sect_data_flags & METHOD_HEADER_SECTION_MORE_SECTS)
4064 ptr += sect_data_len - 4; /* LAMESPEC: it seems the size includes the header */
4065 else
4066 return clauses;
4071 * mono_method_get_header_summary:
4072 * @method: The method to get the header.
4073 * @summary: Where to store the header
4076 * Returns: TRUE if the header was properly decoded.
4078 gboolean
4079 mono_method_get_header_summary (MonoMethod *method, MonoMethodHeaderSummary *summary)
4081 int idx;
4082 guint32 rva;
4083 MonoImage* img;
4084 const char *ptr;
4085 unsigned char flags, format;
4086 guint16 fat_flags;
4087 ERROR_DECL (error);
4089 /*Only the GMD has a pointer to the metadata.*/
4090 while (method->is_inflated)
4091 method = ((MonoMethodInflated*)method)->declaring;
4093 summary->code = NULL;
4094 summary->code_size = 0;
4095 summary->max_stack = 0;
4096 summary->has_clauses = FALSE;
4097 summary->has_locals = FALSE;
4099 /*FIXME extract this into a MACRO and share it with mono_method_get_header*/
4100 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))
4101 return FALSE;
4103 if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
4104 MonoMethodHeader *header = ((MonoMethodWrapper *)method)->header;
4105 if (!header)
4106 return FALSE;
4107 summary->code = header->code;
4108 summary->code_size = header->code_size;
4109 summary->max_stack = header->max_stack;
4110 summary->has_clauses = header->num_clauses > 0;
4111 summary->has_locals = header->num_locals > 0;
4112 return TRUE;
4116 idx = mono_metadata_token_index (method->token);
4117 img = m_class_get_image (method->klass);
4118 rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
4120 /*We must run the verifier since we'll be decoding it.*/
4121 if (!mono_verifier_verify_method_header (img, rva, error)) {
4122 mono_error_cleanup (error);
4123 return FALSE;
4126 ptr = mono_image_rva_map (img, rva);
4127 if (!ptr)
4128 return FALSE;
4130 flags = *(const unsigned char *)ptr;
4131 format = flags & METHOD_HEADER_FORMAT_MASK;
4133 switch (format) {
4134 case METHOD_HEADER_TINY_FORMAT:
4135 ptr++;
4136 summary->max_stack = 8;
4137 summary->code = (unsigned char *) ptr;
4138 summary->code_size = flags >> 2;
4139 break;
4140 case METHOD_HEADER_FAT_FORMAT:
4141 fat_flags = read16 (ptr);
4142 ptr += 2;
4143 summary->max_stack = read16 (ptr);
4144 ptr += 2;
4145 summary->code_size = read32 (ptr);
4146 ptr += 4;
4147 summary->has_locals = !!read32 (ptr);
4148 ptr += 4;
4149 if (fat_flags & METHOD_HEADER_MORE_SECTS)
4150 summary->has_clauses = TRUE;
4151 summary->code = (unsigned char *) ptr;
4152 break;
4153 default:
4154 return FALSE;
4156 return TRUE;
4160 * mono_metadata_parse_mh_full:
4161 * @m: metadata context
4162 * @generic_context: generics context
4163 * @ptr: pointer to the method header.
4165 * Decode the method header at @ptr, including pointer to the IL code,
4166 * info about local variables and optional exception tables.
4167 * This is a Mono runtime internal function.
4169 * LOCKING: Acquires the loader lock.
4171 * Returns: a transient MonoMethodHeader allocated from the heap.
4173 MonoMethodHeader *
4174 mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, const char *ptr, MonoError *error)
4176 MonoMethodHeader *mh = NULL;
4177 unsigned char flags = *(const unsigned char *) ptr;
4178 unsigned char format = flags & METHOD_HEADER_FORMAT_MASK;
4179 guint16 fat_flags;
4180 guint32 local_var_sig_tok, max_stack, code_size, init_locals;
4181 const unsigned char *code;
4182 MonoExceptionClause* clauses = NULL;
4183 int num_clauses = 0;
4184 MonoTableInfo *t = &m->tables [MONO_TABLE_STANDALONESIG];
4185 guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
4187 error_init (error);
4189 if (!ptr) {
4190 mono_error_set_bad_image (error, m, "Method header with null pointer");
4191 return NULL;
4194 switch (format) {
4195 case METHOD_HEADER_TINY_FORMAT:
4196 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER);
4197 ptr++;
4198 mh->max_stack = 8;
4199 mh->is_transient = TRUE;
4200 local_var_sig_tok = 0;
4201 mh->code_size = flags >> 2;
4202 mh->code = (unsigned char*)ptr;
4203 return mh;
4204 case METHOD_HEADER_FAT_FORMAT:
4205 fat_flags = read16 (ptr);
4206 ptr += 2;
4207 max_stack = read16 (ptr);
4208 ptr += 2;
4209 code_size = read32 (ptr);
4210 ptr += 4;
4211 local_var_sig_tok = read32 (ptr);
4212 ptr += 4;
4214 if (fat_flags & METHOD_HEADER_INIT_LOCALS)
4215 init_locals = 1;
4216 else
4217 init_locals = 0;
4219 code = (unsigned char*)ptr;
4221 if (!(fat_flags & METHOD_HEADER_MORE_SECTS))
4222 break;
4225 * There are more sections
4227 ptr = (char*)code + code_size;
4228 break;
4229 default:
4230 mono_error_set_bad_image (error, m, "Invalid method header format %d", format);
4231 return NULL;
4234 if (local_var_sig_tok) {
4235 int idx = (local_var_sig_tok & 0xffffff)-1;
4236 if (idx >= t->rows || idx < 0) {
4237 mono_error_set_bad_image (error, m, "Invalid method header local vars signature token 0x%8x", idx);
4238 goto fail;
4240 mono_metadata_decode_row (t, idx, cols, 1);
4242 if (!mono_verifier_verify_standalone_signature (m, cols [MONO_STAND_ALONE_SIGNATURE], error))
4243 goto fail;
4245 if (fat_flags & METHOD_HEADER_MORE_SECTS) {
4246 clauses = parse_section_data (m, &num_clauses, (const unsigned char*)ptr, error);
4247 goto_if_nok (error, fail);
4249 if (local_var_sig_tok) {
4250 const char *locals_ptr;
4251 int len=0, i;
4253 locals_ptr = mono_metadata_blob_heap (m, cols [MONO_STAND_ALONE_SIGNATURE]);
4254 mono_metadata_decode_blob_size (locals_ptr, &locals_ptr);
4255 if (*locals_ptr != 0x07)
4256 g_warning ("wrong signature for locals blob");
4257 locals_ptr++;
4258 len = mono_metadata_decode_value (locals_ptr, &locals_ptr);
4259 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + len * sizeof (MonoType*) + num_clauses * sizeof (MonoExceptionClause));
4260 mh->num_locals = len;
4261 for (i = 0; i < len; ++i) {
4262 mh->locals [i] = mono_metadata_parse_type_internal (m, container, 0, TRUE, locals_ptr, &locals_ptr, error);
4263 goto_if_nok (error, fail);
4265 } else {
4266 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + num_clauses * sizeof (MonoExceptionClause));
4268 mh->code = code;
4269 mh->code_size = code_size;
4270 mh->max_stack = max_stack;
4271 mh->is_transient = TRUE;
4272 mh->init_locals = init_locals;
4273 if (clauses) {
4274 MonoExceptionClause* clausesp = (MonoExceptionClause*)&mh->locals [mh->num_locals];
4275 memcpy (clausesp, clauses, num_clauses * sizeof (MonoExceptionClause));
4276 g_free (clauses);
4277 mh->clauses = clausesp;
4278 mh->num_clauses = num_clauses;
4280 return mh;
4281 fail:
4282 g_free (clauses);
4283 g_free (mh);
4284 return NULL;
4289 * mono_metadata_parse_mh:
4290 * \param generic_context generics context
4291 * \param ptr pointer to the method header.
4293 * Decode the method header at \p ptr, including pointer to the IL code,
4294 * info about local variables and optional exception tables.
4296 * \returns a transient \c MonoMethodHeader allocated from the heap.
4298 MonoMethodHeader *
4299 mono_metadata_parse_mh (MonoImage *m, const char *ptr)
4301 ERROR_DECL (error);
4302 MonoMethodHeader *header = mono_metadata_parse_mh_full (m, NULL, ptr, error);
4303 mono_error_cleanup (error);
4304 return header;
4308 * mono_metadata_free_mh:
4309 * \param mh a method header
4311 * Free the memory allocated for the method header.
4313 void
4314 mono_metadata_free_mh (MonoMethodHeader *mh)
4316 int i;
4318 /* If it is not transient it means it's part of a wrapper method,
4319 * or a SRE-generated method, so the lifetime in that case is
4320 * dictated by the method's own lifetime
4322 if (mh && mh->is_transient) {
4323 for (i = 0; i < mh->num_locals; ++i)
4324 mono_metadata_free_type (mh->locals [i]);
4325 g_free (mh);
4330 * mono_method_header_get_code:
4331 * \param header a \c MonoMethodHeader pointer
4332 * \param code_size memory location for returning the code size
4333 * \param max_stack memory location for returning the max stack
4335 * Method header accessor to retreive info about the IL code properties:
4336 * a pointer to the IL code itself, the size of the code and the max number
4337 * of stack slots used by the code.
4339 * \returns pointer to the IL code represented by the method header.
4341 const unsigned char*
4342 mono_method_header_get_code (MonoMethodHeader *header, guint32* code_size, guint32* max_stack)
4344 if (code_size)
4345 *code_size = header->code_size;
4346 if (max_stack)
4347 *max_stack = header->max_stack;
4348 return header->code;
4352 * mono_method_header_get_locals:
4353 * \param header a \c MonoMethodHeader pointer
4354 * \param num_locals memory location for returning the number of local variables
4355 * \param init_locals memory location for returning the init_locals flag
4357 * Method header accessor to retreive info about the local variables:
4358 * an array of local types, the number of locals and whether the locals
4359 * are supposed to be initialized to 0 on method entry
4361 * \returns pointer to an array of types of the local variables
4363 MonoType**
4364 mono_method_header_get_locals (MonoMethodHeader *header, guint32* num_locals, gboolean *init_locals)
4366 if (num_locals)
4367 *num_locals = header->num_locals;
4368 if (init_locals)
4369 *init_locals = header->init_locals;
4370 return header->locals;
4374 * mono_method_header_get_num_clauses:
4375 * @header: a MonoMethodHeader pointer
4377 * Method header accessor to retreive the number of exception clauses.
4379 * Returns: the number of exception clauses present
4382 mono_method_header_get_num_clauses (MonoMethodHeader *header)
4384 return header->num_clauses;
4388 * mono_method_header_get_clauses:
4389 * \param header a \c MonoMethodHeader pointer
4390 * \param method \c MonoMethod the header belongs to
4391 * \param iter pointer to a iterator
4392 * \param clause pointer to a \c MonoExceptionClause structure which will be filled with the info
4394 * Get the info about the exception clauses in the method. Set \c *iter to NULL to
4395 * initiate the iteration, then call the method repeatedly until it returns FALSE.
4396 * At each iteration, the structure pointed to by clause if filled with the
4397 * exception clause information.
4399 * \returns TRUE if clause was filled with info, FALSE if there are no more exception
4400 * clauses.
4403 mono_method_header_get_clauses (MonoMethodHeader *header, MonoMethod *method, gpointer *iter, MonoExceptionClause *clause)
4405 MonoExceptionClause *sc;
4406 /* later we'll be able to use this interface to parse the clause info on demand,
4407 * without allocating anything.
4409 if (!iter || !header->num_clauses)
4410 return FALSE;
4411 if (!*iter) {
4412 *iter = sc = header->clauses;
4413 *clause = *sc;
4414 return TRUE;
4416 sc = (MonoExceptionClause *)*iter;
4417 sc++;
4418 if (sc < header->clauses + header->num_clauses) {
4419 *iter = sc;
4420 *clause = *sc;
4421 return TRUE;
4423 return FALSE;
4427 * mono_metadata_parse_field_type:
4428 * \param m metadata context to extract information from
4429 * \param ptr pointer to the field signature
4430 * \param rptr pointer updated to match the end of the decoded stream
4432 * Parses the field signature, and returns the type information for it.
4434 * \returns The \c MonoType that was extracted from \p ptr .
4436 MonoType *
4437 mono_metadata_parse_field_type (MonoImage *m, short field_flags, const char *ptr, const char **rptr)
4439 ERROR_DECL (error);
4440 MonoType * type = mono_metadata_parse_type_internal (m, NULL, field_flags, FALSE, ptr, rptr, error);
4441 mono_error_cleanup (error);
4442 return type;
4446 * mono_metadata_parse_param:
4447 * \param m metadata context to extract information from
4448 * \param ptr pointer to the param signature
4449 * \param rptr pointer updated to match the end of the decoded stream
4451 * Parses the param signature, and returns the type information for it.
4453 * \returns The \c MonoType that was extracted from \p ptr .
4455 MonoType *
4456 mono_metadata_parse_param (MonoImage *m, const char *ptr, const char **rptr)
4458 ERROR_DECL (error);
4459 MonoType * type = mono_metadata_parse_type_internal (m, NULL, 0, FALSE, ptr, rptr, error);
4460 mono_error_cleanup (error);
4461 return type;
4465 * mono_metadata_token_from_dor:
4466 * \param dor_token A \c TypeDefOrRef coded index
4468 * \p dor_token is a \c TypeDefOrRef coded index: it contains either
4469 * a \c TypeDef, \c TypeRef or \c TypeSpec in the lower bits, and the upper
4470 * bits contain an index into the table.
4472 * \returns an expanded token
4474 guint32
4475 mono_metadata_token_from_dor (guint32 dor_index)
4477 guint32 table, idx;
4479 table = dor_index & 0x03;
4480 idx = dor_index >> 2;
4482 switch (table){
4483 case 0: /* TypeDef */
4484 return MONO_TOKEN_TYPE_DEF | idx;
4485 case 1: /* TypeRef */
4486 return MONO_TOKEN_TYPE_REF | idx;
4487 case 2: /* TypeSpec */
4488 return MONO_TOKEN_TYPE_SPEC | idx;
4489 default:
4490 g_assert_not_reached ();
4493 return 0;
4497 * We use this to pass context information to the row locator
4499 typedef struct {
4500 int idx; /* The index that we are trying to locate */
4501 int col_idx; /* The index in the row where idx may be stored */
4502 MonoTableInfo *t; /* pointer to the table */
4503 guint32 result;
4504 } locator_t;
4507 * How the row locator works.
4509 * Table A
4510 * ___|___
4511 * ___|___ Table B
4512 * ___|___------> _______
4513 * ___|___ _______
4515 * A column in the rows of table A references an index in table B.
4516 * For example A may be the TYPEDEF table and B the METHODDEF table.
4518 * Given an index in table B we want to get the row in table A
4519 * where the column n references our index in B.
4521 * In the locator_t structure:
4522 * t is table A
4523 * col_idx is the column number
4524 * index is the index in table B
4525 * result will be the index in table A
4527 * Examples:
4528 * Table A Table B column (in table A)
4529 * TYPEDEF METHODDEF MONO_TYPEDEF_METHOD_LIST
4530 * TYPEDEF FIELD MONO_TYPEDEF_FIELD_LIST
4531 * PROPERTYMAP PROPERTY MONO_PROPERTY_MAP_PROPERTY_LIST
4532 * INTERFIMPL TYPEDEF MONO_INTERFACEIMPL_CLASS
4533 * METHODSEM PROPERTY ASSOCIATION (encoded index)
4535 * Note that we still don't support encoded indexes.
4538 static int
4539 typedef_locator (const void *a, const void *b)
4541 locator_t *loc = (locator_t *) a;
4542 const char *bb = (const char *) b;
4543 int typedef_index = (bb - loc->t->base) / loc->t->row_size;
4544 guint32 col, col_next;
4546 col = mono_metadata_decode_row_col (loc->t, typedef_index, loc->col_idx);
4548 if (loc->idx < col)
4549 return -1;
4552 * Need to check that the next row is valid.
4554 if (typedef_index + 1 < loc->t->rows) {
4555 col_next = mono_metadata_decode_row_col (loc->t, typedef_index + 1, loc->col_idx);
4556 if (loc->idx >= col_next)
4557 return 1;
4559 if (col == col_next)
4560 return 1;
4563 loc->result = typedef_index;
4565 return 0;
4568 static int
4569 table_locator (const void *a, const void *b)
4571 locator_t *loc = (locator_t *) a;
4572 const char *bb = (const char *) b;
4573 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4574 guint32 col;
4576 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4578 if (loc->idx == col) {
4579 loc->result = table_index;
4580 return 0;
4582 if (loc->idx < col)
4583 return -1;
4584 else
4585 return 1;
4588 static int
4589 declsec_locator (const void *a, const void *b)
4591 locator_t *loc = (locator_t *) a;
4592 const char *bb = (const char *) b;
4593 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4594 guint32 col;
4596 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4598 if (loc->idx == col) {
4599 loc->result = table_index;
4600 return 0;
4602 if (loc->idx < col)
4603 return -1;
4604 else
4605 return 1;
4609 * search_ptr_table:
4611 * Return the 1-based row index in TABLE, which must be one of the *Ptr tables,
4612 * which contains IDX.
4614 static guint32
4615 search_ptr_table (MonoImage *image, int table, int idx)
4617 MonoTableInfo *ptrdef = &image->tables [table];
4618 int i;
4620 /* Use a linear search to find our index in the table */
4621 for (i = 0; i < ptrdef->rows; i ++)
4622 /* All the Ptr tables have the same structure */
4623 if (mono_metadata_decode_row_col (ptrdef, i, 0) == idx)
4624 break;
4626 if (i < ptrdef->rows)
4627 return i + 1;
4628 else
4629 return idx;
4633 * mono_metadata_typedef_from_field:
4634 * \param meta metadata context
4635 * \param index FieldDef token
4637 * \returns the 1-based index into the \c TypeDef table of the type that
4638 * declared the field described by \p index, or 0 if not found.
4640 guint32
4641 mono_metadata_typedef_from_field (MonoImage *meta, guint32 index)
4643 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4644 locator_t loc;
4646 if (!tdef->base)
4647 return 0;
4649 loc.idx = mono_metadata_token_index (index);
4650 loc.col_idx = MONO_TYPEDEF_FIELD_LIST;
4651 loc.t = tdef;
4653 if (meta->uncompressed_metadata)
4654 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
4656 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4657 return 0;
4659 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4660 return loc.result + 1;
4664 * mono_metadata_typedef_from_method:
4665 * \param meta metadata context
4666 * \param index \c MethodDef token
4667 * \returns the 1-based index into the \c TypeDef table of the type that
4668 * declared the method described by \p index. 0 if not found.
4670 guint32
4671 mono_metadata_typedef_from_method (MonoImage *meta, guint32 index)
4673 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4674 locator_t loc;
4676 if (!tdef->base)
4677 return 0;
4679 loc.idx = mono_metadata_token_index (index);
4680 loc.col_idx = MONO_TYPEDEF_METHOD_LIST;
4681 loc.t = tdef;
4683 if (meta->uncompressed_metadata)
4684 loc.idx = search_ptr_table (meta, MONO_TABLE_METHOD_POINTER, loc.idx);
4686 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4687 return 0;
4689 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4690 return loc.result + 1;
4694 * mono_metadata_interfaces_from_typedef_full:
4695 * \param meta metadata context
4696 * \param index typedef token
4697 * \param interfaces Out parameter used to store the interface array
4698 * \param count Out parameter used to store the number of interfaces
4699 * \param heap_alloc_result if TRUE the result array will be \c g_malloc'd
4700 * \param context The generic context
4701 * \param error set on error
4703 * The array of interfaces that the \p index typedef token implements is returned in
4704 * \p interfaces. The number of elements in the array is returned in \p count.
4706 * \returns \c TRUE on success, \c FALSE on failure and sets \p error.
4708 gboolean
4709 mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, MonoClass ***interfaces, guint *count, gboolean heap_alloc_result, MonoGenericContext *context, MonoError *error)
4711 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_INTERFACEIMPL];
4712 locator_t loc;
4713 guint32 start, pos;
4714 guint32 cols [MONO_INTERFACEIMPL_SIZE];
4715 MonoClass **result;
4717 *interfaces = NULL;
4718 *count = 0;
4720 error_init (error);
4722 if (!tdef->base)
4723 return TRUE;
4725 loc.idx = mono_metadata_token_index (index);
4726 loc.col_idx = MONO_INTERFACEIMPL_CLASS;
4727 loc.t = tdef;
4729 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4730 return TRUE;
4732 start = loc.result;
4734 * We may end up in the middle of the rows...
4736 while (start > 0) {
4737 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_INTERFACEIMPL_CLASS))
4738 start--;
4739 else
4740 break;
4742 pos = start;
4743 while (pos < tdef->rows) {
4744 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4745 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4746 break;
4747 ++pos;
4750 if (heap_alloc_result)
4751 result = g_new0 (MonoClass*, pos - start);
4752 else
4753 result = (MonoClass **)mono_image_alloc0 (meta, sizeof (MonoClass*) * (pos - start));
4755 pos = start;
4756 while (pos < tdef->rows) {
4757 MonoClass *iface;
4759 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4760 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4761 break;
4762 iface = mono_class_get_and_inflate_typespec_checked (
4763 meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context, error);
4764 if (iface == NULL)
4765 return FALSE;
4766 result [pos - start] = iface;
4767 ++pos;
4769 *count = pos - start;
4770 *interfaces = result;
4771 return TRUE;
4775 * mono_metadata_interfaces_from_typedef:
4776 * \param meta metadata context
4777 * \param index typedef token
4778 * \param count Out parameter used to store the number of interfaces
4780 * The array of interfaces that the \p index typedef token implements is returned in
4781 * \p interfaces. The number of elements in the array is returned in \p count. The returned
4782 * array is allocated with \c g_malloc and the caller must free it.
4784 * LOCKING: Acquires the loader lock .
4786 * \returns the interface array on success, NULL on failure.
4788 MonoClass**
4789 mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *count)
4791 ERROR_DECL (error);
4792 MonoClass **interfaces = NULL;
4793 gboolean rv;
4795 rv = mono_metadata_interfaces_from_typedef_full (meta, index, &interfaces, count, TRUE, NULL, error);
4796 mono_error_assert_ok (error);
4797 if (rv)
4798 return interfaces;
4799 else
4800 return NULL;
4804 * mono_metadata_nested_in_typedef:
4805 * \param meta metadata context
4806 * \param index typedef token
4807 * \returns the 1-based index into the TypeDef table of the type
4808 * where the type described by \p index is nested.
4809 * Returns 0 if \p index describes a non-nested type.
4811 guint32
4812 mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index)
4814 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
4815 locator_t loc;
4817 if (!tdef->base)
4818 return 0;
4820 loc.idx = mono_metadata_token_index (index);
4821 loc.col_idx = MONO_NESTED_CLASS_NESTED;
4822 loc.t = tdef;
4824 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4825 return 0;
4827 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4828 return mono_metadata_decode_row_col (tdef, loc.result, MONO_NESTED_CLASS_ENCLOSING) | MONO_TOKEN_TYPE_DEF;
4832 * mono_metadata_nesting_typedef:
4833 * \param meta metadata context
4834 * \param index typedef token
4835 * \returns the 1-based index into the \c TypeDef table of the first type
4836 * that is nested inside the type described by \p index. The search starts at
4837 * \p start_index. Returns 0 if no such type is found.
4839 guint32
4840 mono_metadata_nesting_typedef (MonoImage *meta, guint32 index, guint32 start_index)
4842 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
4843 guint32 start;
4844 guint32 class_index = mono_metadata_token_index (index);
4846 if (!tdef->base)
4847 return 0;
4849 start = start_index;
4851 while (start <= tdef->rows) {
4852 if (class_index == mono_metadata_decode_row_col (tdef, start - 1, MONO_NESTED_CLASS_ENCLOSING))
4853 break;
4854 else
4855 start++;
4858 if (start > tdef->rows)
4859 return 0;
4860 else
4861 return start;
4865 * mono_metadata_packing_from_typedef:
4866 * \param meta metadata context
4867 * \param index token representing a type
4868 * \returns the info stored in the \c ClassLayout table for the given typedef token
4869 * into the \p packing and \p size pointers.
4870 * Returns 0 if the info is not found.
4872 guint32
4873 mono_metadata_packing_from_typedef (MonoImage *meta, guint32 index, guint32 *packing, guint32 *size)
4875 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CLASSLAYOUT];
4876 locator_t loc;
4877 guint32 cols [MONO_CLASS_LAYOUT_SIZE];
4879 if (!tdef->base)
4880 return 0;
4882 loc.idx = mono_metadata_token_index (index);
4883 loc.col_idx = MONO_CLASS_LAYOUT_PARENT;
4884 loc.t = tdef;
4886 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4887 return 0;
4889 mono_metadata_decode_row (tdef, loc.result, cols, MONO_CLASS_LAYOUT_SIZE);
4890 if (packing)
4891 *packing = cols [MONO_CLASS_LAYOUT_PACKING_SIZE];
4892 if (size)
4893 *size = cols [MONO_CLASS_LAYOUT_CLASS_SIZE];
4895 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4896 return loc.result + 1;
4900 * mono_metadata_custom_attrs_from_index:
4901 * \param meta metadata context
4902 * \param index token representing the parent
4903 * \returns: the 1-based index into the \c CustomAttribute table of the first
4904 * attribute which belongs to the metadata object described by \p index.
4905 * Returns 0 if no such attribute is found.
4907 guint32
4908 mono_metadata_custom_attrs_from_index (MonoImage *meta, guint32 index)
4910 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CUSTOMATTRIBUTE];
4911 locator_t loc;
4913 if (!tdef->base)
4914 return 0;
4916 loc.idx = index;
4917 loc.col_idx = MONO_CUSTOM_ATTR_PARENT;
4918 loc.t = tdef;
4920 /* FIXME: Index translation */
4922 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4923 return 0;
4925 /* Find the first entry by searching backwards */
4926 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_CUSTOM_ATTR_PARENT) == index))
4927 loc.result --;
4929 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4930 return loc.result + 1;
4934 * mono_metadata_declsec_from_index:
4935 * \param meta metadata context
4936 * \param index token representing the parent
4937 * \returns the 0-based index into the \c DeclarativeSecurity table of the first
4938 * attribute which belongs to the metadata object described by \p index.
4939 * Returns \c -1 if no such attribute is found.
4941 guint32
4942 mono_metadata_declsec_from_index (MonoImage *meta, guint32 index)
4944 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_DECLSECURITY];
4945 locator_t loc;
4947 if (!tdef->base)
4948 return -1;
4950 loc.idx = index;
4951 loc.col_idx = MONO_DECL_SECURITY_PARENT;
4952 loc.t = tdef;
4954 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, declsec_locator))
4955 return -1;
4957 /* Find the first entry by searching backwards */
4958 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_DECL_SECURITY_PARENT) == index))
4959 loc.result --;
4961 return loc.result;
4965 * mono_metadata_localscope_from_methoddef:
4966 * @meta: metadata context
4967 * @index: methoddef index
4969 * Returns: the 1-based index into the LocalScope table of the first
4970 * scope which belongs to the method described by @index.
4971 * Returns 0 if no such row is found.
4973 guint32
4974 mono_metadata_localscope_from_methoddef (MonoImage *meta, guint32 index)
4976 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_LOCALSCOPE];
4977 locator_t loc;
4979 if (!tdef->base)
4980 return 0;
4982 loc.idx = index;
4983 loc.col_idx = MONO_LOCALSCOPE_METHOD;
4984 loc.t = tdef;
4986 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4987 return 0;
4989 /* Find the first entry by searching backwards */
4990 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_LOCALSCOPE_METHOD) == index))
4991 loc.result --;
4993 return loc.result + 1;
4996 #ifdef DEBUG
4997 static void
4998 mono_backtrace (int limit)
5000 void *array[limit];
5001 char **names;
5002 int i;
5003 backtrace (array, limit);
5004 names = backtrace_symbols (array, limit);
5005 for (i =0; i < limit; ++i) {
5006 g_print ("\t%s\n", names [i]);
5008 g_free (names);
5010 #endif
5012 static int i8_align;
5015 * mono_type_set_alignment:
5017 * Set the alignment used by runtime to layout fields etc. of type TYPE to ALIGN.
5018 * This should only be used in AOT mode since the resulting layout will not match the
5019 * host abi layout.
5021 void
5022 mono_type_set_alignment (MonoTypeEnum type, int align)
5024 /* Support only a few types whose alignment is abi dependent */
5025 switch (type) {
5026 case MONO_TYPE_I8:
5027 i8_align = align;
5028 break;
5029 default:
5030 g_assert_not_reached ();
5031 break;
5036 * mono_type_size:
5037 * \param t the type to return the size of
5038 * \returns The number of bytes required to hold an instance of this
5039 * type in memory
5042 mono_type_size (MonoType *t, int *align)
5044 MonoTypeEnum simple_type;
5046 if (!t) {
5047 *align = 1;
5048 return 0;
5050 if (t->byref) {
5051 *align = MONO_ABI_ALIGNOF (gpointer);
5052 return MONO_ABI_SIZEOF (gpointer);
5055 simple_type = t->type;
5056 again:
5057 switch (simple_type) {
5058 case MONO_TYPE_VOID:
5059 *align = 1;
5060 return 0;
5061 case MONO_TYPE_BOOLEAN:
5062 *align = MONO_ABI_ALIGNOF (gint8);
5063 return 1;
5064 case MONO_TYPE_I1:
5065 case MONO_TYPE_U1:
5066 *align = MONO_ABI_ALIGNOF (gint8);
5067 return 1;
5068 case MONO_TYPE_CHAR:
5069 case MONO_TYPE_I2:
5070 case MONO_TYPE_U2:
5071 *align = MONO_ABI_ALIGNOF (gint16);
5072 return 2;
5073 case MONO_TYPE_I4:
5074 case MONO_TYPE_U4:
5075 *align = MONO_ABI_ALIGNOF (gint32);
5076 return 4;
5077 case MONO_TYPE_R4:
5078 *align = MONO_ABI_ALIGNOF (float);
5079 return 4;
5080 case MONO_TYPE_I8:
5081 case MONO_TYPE_U8:
5082 *align = MONO_ABI_ALIGNOF (gint64);
5083 return 8;
5084 case MONO_TYPE_R8:
5085 *align = MONO_ABI_ALIGNOF (double);
5086 return 8;
5087 case MONO_TYPE_I:
5088 case MONO_TYPE_U:
5089 *align = MONO_ABI_ALIGNOF (gpointer);
5090 return MONO_ABI_SIZEOF (gpointer);
5091 case MONO_TYPE_VALUETYPE: {
5092 if (m_class_is_enumtype (t->data.klass))
5093 return mono_type_size (mono_class_enum_basetype_internal (t->data.klass), align);
5094 else
5095 return mono_class_value_size (t->data.klass, (guint32*)align);
5097 case MONO_TYPE_STRING:
5098 case MONO_TYPE_OBJECT:
5099 case MONO_TYPE_CLASS:
5100 case MONO_TYPE_SZARRAY:
5101 case MONO_TYPE_PTR:
5102 case MONO_TYPE_FNPTR:
5103 case MONO_TYPE_ARRAY:
5104 *align = MONO_ABI_ALIGNOF (gpointer);
5105 return MONO_ABI_SIZEOF (gpointer);
5106 case MONO_TYPE_TYPEDBYREF:
5107 return mono_class_value_size (mono_defaults.typed_reference_class, (guint32*)align);
5108 case MONO_TYPE_GENERICINST: {
5109 MonoGenericClass *gclass = t->data.generic_class;
5110 MonoClass *container_class = gclass->container_class;
5112 // g_assert (!gclass->inst->is_open);
5114 if (m_class_is_valuetype (container_class)) {
5115 if (m_class_is_enumtype (container_class))
5116 return mono_type_size (mono_class_enum_basetype_internal (container_class), align);
5117 else
5118 return mono_class_value_size (mono_class_from_mono_type_internal (t), (guint32*)align);
5119 } else {
5120 *align = MONO_ABI_ALIGNOF (gpointer);
5121 return MONO_ABI_SIZEOF (gpointer);
5124 case MONO_TYPE_VAR:
5125 case MONO_TYPE_MVAR:
5126 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
5127 *align = MONO_ABI_ALIGNOF (gpointer);
5128 return MONO_ABI_SIZEOF (gpointer);
5129 } else {
5130 /* The gparam can only match types given by gshared_constraint */
5131 return mono_type_size (t->data.generic_param->gshared_constraint, align);
5132 goto again;
5134 default:
5135 g_error ("mono_type_size: type 0x%02x unknown", t->type);
5137 return 0;
5141 * mono_type_stack_size:
5142 * \param t the type to return the size it uses on the stack
5143 * \returns The number of bytes required to hold an instance of this
5144 * type on the runtime stack
5147 mono_type_stack_size (MonoType *t, int *align)
5149 return mono_type_stack_size_internal (t, align, FALSE);
5153 mono_type_stack_size_internal (MonoType *t, int *align, gboolean allow_open)
5155 int tmp;
5156 MonoTypeEnum simple_type;
5157 #if TARGET_SIZEOF_VOID_P == SIZEOF_REGISTER
5158 int stack_slot_size = MONO_ABI_SIZEOF (gpointer);
5159 int stack_slot_align = MONO_ABI_ALIGNOF (gpointer);
5160 #elif TARGET_SIZEOF_VOID_P < SIZEOF_REGISTER
5161 int stack_slot_size = SIZEOF_REGISTER;
5162 int stack_slot_align = SIZEOF_REGISTER;
5163 #endif
5165 g_assert (t != NULL);
5167 if (!align)
5168 align = &tmp;
5170 if (t->byref) {
5171 *align = stack_slot_align;
5172 return stack_slot_size;
5175 simple_type = t->type;
5176 switch (simple_type) {
5177 case MONO_TYPE_BOOLEAN:
5178 case MONO_TYPE_CHAR:
5179 case MONO_TYPE_I1:
5180 case MONO_TYPE_U1:
5181 case MONO_TYPE_I2:
5182 case MONO_TYPE_U2:
5183 case MONO_TYPE_I4:
5184 case MONO_TYPE_U4:
5185 case MONO_TYPE_I:
5186 case MONO_TYPE_U:
5187 case MONO_TYPE_STRING:
5188 case MONO_TYPE_OBJECT:
5189 case MONO_TYPE_CLASS:
5190 case MONO_TYPE_SZARRAY:
5191 case MONO_TYPE_PTR:
5192 case MONO_TYPE_FNPTR:
5193 case MONO_TYPE_ARRAY:
5194 *align = stack_slot_align;
5195 return stack_slot_size;
5196 case MONO_TYPE_VAR:
5197 case MONO_TYPE_MVAR:
5198 g_assert (allow_open);
5199 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
5200 *align = stack_slot_align;
5201 return stack_slot_size;
5202 } else {
5203 /* The gparam can only match types given by gshared_constraint */
5204 return mono_type_stack_size_internal (t->data.generic_param->gshared_constraint, align, allow_open);
5206 case MONO_TYPE_TYPEDBYREF:
5207 *align = stack_slot_align;
5208 return stack_slot_size * 3;
5209 case MONO_TYPE_R4:
5210 *align = MONO_ABI_ALIGNOF (float);
5211 return sizeof (float);
5212 case MONO_TYPE_I8:
5213 case MONO_TYPE_U8:
5214 *align = MONO_ABI_ALIGNOF (gint64);
5215 return sizeof (gint64);
5216 case MONO_TYPE_R8:
5217 *align = MONO_ABI_ALIGNOF (double);
5218 return sizeof (double);
5219 case MONO_TYPE_VALUETYPE: {
5220 guint32 size;
5222 if (m_class_is_enumtype (t->data.klass))
5223 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (t->data.klass), align, allow_open);
5224 else {
5225 size = mono_class_value_size (t->data.klass, (guint32*)align);
5227 *align = *align + stack_slot_align - 1;
5228 *align &= ~(stack_slot_align - 1);
5230 size += stack_slot_size - 1;
5231 size &= ~(stack_slot_size - 1);
5233 return size;
5236 case MONO_TYPE_GENERICINST: {
5237 MonoGenericClass *gclass = t->data.generic_class;
5238 MonoClass *container_class = gclass->container_class;
5240 if (!allow_open)
5241 g_assert (!gclass->context.class_inst->is_open);
5243 if (m_class_is_valuetype (container_class)) {
5244 if (m_class_is_enumtype (container_class))
5245 return mono_type_stack_size_internal (mono_class_enum_basetype_internal (container_class), align, allow_open);
5246 else {
5247 guint32 size = mono_class_value_size (mono_class_from_mono_type_internal (t), (guint32*)align);
5249 *align = *align + stack_slot_align - 1;
5250 *align &= ~(stack_slot_align - 1);
5252 size += stack_slot_size - 1;
5253 size &= ~(stack_slot_size - 1);
5255 return size;
5257 } else {
5258 *align = stack_slot_align;
5259 return stack_slot_size;
5262 default:
5263 g_error ("type 0x%02x unknown", t->type);
5265 return 0;
5268 gboolean
5269 mono_type_generic_inst_is_valuetype (MonoType *type)
5271 g_assert (type->type == MONO_TYPE_GENERICINST);
5272 return m_class_is_valuetype (type->data.generic_class->container_class);
5276 * mono_metadata_generic_class_is_valuetype:
5278 gboolean
5279 mono_metadata_generic_class_is_valuetype (MonoGenericClass *gclass)
5281 return m_class_is_valuetype (gclass->container_class);
5284 static gboolean
5285 _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only)
5287 MonoGenericInst *i1 = g1->context.class_inst;
5288 MonoGenericInst *i2 = g2->context.class_inst;
5290 if (g1->is_dynamic != g2->is_dynamic)
5291 return FALSE;
5292 if (!mono_metadata_class_equal (g1->container_class, g2->container_class, signature_only))
5293 return FALSE;
5294 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5295 return FALSE;
5296 return g1->is_tb_open == g2->is_tb_open;
5299 static gboolean
5300 _mono_metadata_generic_class_container_equal (const MonoGenericClass *g1, MonoClass *c2, gboolean signature_only)
5302 MonoGenericInst *i1 = g1->context.class_inst;
5303 MonoGenericInst *i2 = mono_class_get_generic_container (c2)->context.class_inst;
5305 if (!mono_metadata_class_equal (g1->container_class, c2, signature_only))
5306 return FALSE;
5307 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5308 return FALSE;
5309 return !g1->is_tb_open;
5312 guint
5313 mono_metadata_generic_context_hash (const MonoGenericContext *context)
5315 /* FIXME: check if this seed is good enough */
5316 guint hash = 0xc01dfee7;
5317 if (context->class_inst)
5318 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->class_inst);
5319 if (context->method_inst)
5320 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->method_inst);
5321 return hash;
5324 gboolean
5325 mono_metadata_generic_context_equal (const MonoGenericContext *g1, const MonoGenericContext *g2)
5327 return g1->class_inst == g2->class_inst && g1->method_inst == g2->method_inst;
5331 * mono_metadata_str_hash:
5333 * This should be used instead of g_str_hash for computing hash codes visible
5334 * outside this module, since g_str_hash () is not guaranteed to be stable
5335 * (its not the same in eglib for example).
5337 guint
5338 mono_metadata_str_hash (gconstpointer v1)
5340 /* Same as g_str_hash () in glib */
5341 char *p = (char *) v1;
5342 guint hash = *p;
5344 while (*p++) {
5345 if (*p)
5346 hash = (hash << 5) - hash + *p;
5349 return hash;
5353 * mono_metadata_type_hash:
5354 * \param t1 a type
5355 * Computes a hash value for \p t1 to be used in \c GHashTable.
5356 * The returned hash is guaranteed to be the same across executions.
5358 guint
5359 mono_metadata_type_hash (MonoType *t1)
5361 guint hash = t1->type;
5363 hash |= t1->byref << 6; /* do not collide with t1->type values */
5364 switch (t1->type) {
5365 case MONO_TYPE_VALUETYPE:
5366 case MONO_TYPE_CLASS:
5367 case MONO_TYPE_SZARRAY: {
5368 MonoClass *klass = t1->data.klass;
5370 * Dynamic classes must not be hashed on their type since it can change
5371 * during runtime. For example, if we hash a reference type that is
5372 * later made into a valuetype.
5374 * This is specially problematic with generic instances since they are
5375 * inserted in a bunch of hash tables before been finished.
5377 if (image_is_dynamic (m_class_get_image (klass)))
5378 return (t1->byref << 6) | mono_metadata_str_hash (m_class_get_name (klass));
5379 return ((hash << 5) - hash) ^ mono_metadata_str_hash (m_class_get_name (klass));
5381 case MONO_TYPE_PTR:
5382 return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
5383 case MONO_TYPE_ARRAY:
5384 return ((hash << 5) - hash) ^ mono_metadata_type_hash (m_class_get_byval_arg (t1->data.array->eklass));
5385 case MONO_TYPE_GENERICINST:
5386 return ((hash << 5) - hash) ^ mono_generic_class_hash (t1->data.generic_class);
5387 case MONO_TYPE_VAR:
5388 case MONO_TYPE_MVAR:
5389 return ((hash << 5) - hash) ^ mono_metadata_generic_param_hash (t1->data.generic_param);
5390 default:
5391 return hash;
5395 guint
5396 mono_metadata_generic_param_hash (MonoGenericParam *p)
5398 guint hash;
5399 MonoGenericParamInfo *info;
5401 hash = (mono_generic_param_num (p) << 2);
5402 if (p->gshared_constraint)
5403 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->gshared_constraint);
5404 info = mono_generic_param_info (p);
5405 /* Can't hash on the owner klass/method, since those might not be set when this is called */
5406 if (!p->owner->is_anonymous)
5407 hash = ((hash << 5) - hash) ^ info->token;
5408 return hash;
5411 static gboolean
5412 mono_metadata_generic_param_equal_internal (MonoGenericParam *p1, MonoGenericParam *p2, gboolean signature_only)
5414 if (p1 == p2)
5415 return TRUE;
5416 if (mono_generic_param_num (p1) != mono_generic_param_num (p2))
5417 return FALSE;
5418 if (p1->gshared_constraint && p2->gshared_constraint) {
5419 if (!mono_metadata_type_equal (p1->gshared_constraint, p2->gshared_constraint))
5420 return FALSE;
5421 } else {
5422 if (p1->gshared_constraint != p2->gshared_constraint)
5423 return FALSE;
5427 * We have to compare the image as well because if we didn't,
5428 * the generic_inst_cache lookup wouldn't care about the image
5429 * of generic params, so what could happen is that a generic
5430 * inst with params from image A is put into the cache, then
5431 * image B gets that generic inst from the cache, image A is
5432 * unloaded, so the inst is deleted, but image B still retains
5433 * a pointer to it.
5435 if (mono_generic_param_owner (p1) == mono_generic_param_owner (p2))
5436 return TRUE;
5439 * If `signature_only' is true, we're comparing two (method) signatures.
5440 * In this case, the owner of two type parameters doesn't need to match.
5443 return signature_only;
5446 gboolean
5447 mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2)
5449 return mono_metadata_generic_param_equal_internal (p1, p2, TRUE);
5452 static gboolean
5453 mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only)
5455 if (c1 == c2)
5456 return TRUE;
5457 if (mono_class_is_ginst (c1) && mono_class_is_ginst (c2))
5458 return _mono_metadata_generic_class_equal (mono_class_get_generic_class (c1), mono_class_get_generic_class (c2), signature_only);
5459 if (mono_class_is_ginst (c1) && mono_class_is_gtd (c2))
5460 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c1), c2, signature_only);
5461 if (mono_class_is_gtd (c1) && mono_class_is_ginst (c2))
5462 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c2), c1, signature_only);
5463 MonoType *c1_type = m_class_get_byval_arg (c1);
5464 MonoType *c2_type = m_class_get_byval_arg (c2);
5465 if ((c1_type->type == MONO_TYPE_VAR) && (c2_type->type == MONO_TYPE_VAR))
5466 return mono_metadata_generic_param_equal_internal (
5467 c1_type->data.generic_param, c2_type->data.generic_param, signature_only);
5468 if ((c1_type->type == MONO_TYPE_MVAR) && (c2_type->type == MONO_TYPE_MVAR))
5469 return mono_metadata_generic_param_equal_internal (
5470 c1_type->data.generic_param, c2_type->data.generic_param, signature_only);
5471 if (signature_only &&
5472 (c1_type->type == MONO_TYPE_SZARRAY) && (c2_type->type == MONO_TYPE_SZARRAY))
5473 return mono_metadata_class_equal (c1_type->data.klass, c2_type->data.klass, signature_only);
5474 if (signature_only &&
5475 (c1_type->type == MONO_TYPE_ARRAY) && (c2_type->type == MONO_TYPE_ARRAY))
5476 return do_mono_metadata_type_equal (c1_type, c2_type, signature_only);
5477 return FALSE;
5480 static gboolean
5481 mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only)
5483 gpointer iter1 = 0, iter2 = 0;
5485 if (s1 == s2)
5486 return TRUE;
5487 if (s1->call_convention != s2->call_convention)
5488 return FALSE;
5489 if (s1->sentinelpos != s2->sentinelpos)
5490 return FALSE;
5491 if (s1->hasthis != s2->hasthis)
5492 return FALSE;
5493 if (s1->explicit_this != s2->explicit_this)
5494 return FALSE;
5495 if (! do_mono_metadata_type_equal (s1->ret, s2->ret, signature_only))
5496 return FALSE;
5497 if (s1->param_count != s2->param_count)
5498 return FALSE;
5500 while (TRUE) {
5501 MonoType *t1 = mono_signature_get_params (s1, &iter1);
5502 MonoType *t2 = mono_signature_get_params (s2, &iter2);
5504 if (t1 == NULL || t2 == NULL)
5505 return (t1 == t2);
5506 if (! do_mono_metadata_type_equal (t1, t2, signature_only))
5507 return FALSE;
5512 * mono_metadata_type_equal:
5513 * @t1: a type
5514 * @t2: another type
5515 * @signature_only: If true, treat ginsts as equal which are instantiated separately but have equal positional value
5517 * Determine if @t1 and @t2 represent the same type.
5518 * Returns: #TRUE if @t1 and @t2 are equal.
5520 static gboolean
5521 do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only)
5523 if (t1->type != t2->type || t1->byref != t2->byref)
5524 return FALSE;
5526 gboolean cmod_reject = FALSE;
5528 gboolean is_pointer = (t1->type == MONO_TYPE_PTR);
5530 if (t1->has_cmods != t2->has_cmods)
5531 cmod_reject = TRUE;
5532 else if (t1->has_cmods && t2->has_cmods) {
5533 MonoCustomModContainer *cm1 = mono_type_get_cmods (t1);
5534 MonoCustomModContainer *cm2 = mono_type_get_cmods (t2);
5536 g_assert (cm1);
5537 g_assert (cm2);
5539 // ECMA 335, 7.1.1:
5540 // The CLI itself shall treat required and optional modifiers in the same manner.
5541 // Two signatures that differ only by the addition of a custom modifier
5542 // (required or optional) shall not be considered to match.
5543 if (cm1->count != cm2->count) {
5544 cmod_reject = TRUE;
5545 } else for (int i=0; i < cm1->count; i++) {
5546 if (cm1->modifiers[i].required != cm2->modifiers[i].required) {
5547 cmod_reject = TRUE;
5548 break;
5551 // FIXME: propagate error to caller
5552 ERROR_DECL (error);
5553 MonoClass *c1 = mono_class_get_checked (cm1->image, cm1->modifiers [i].token, error);
5554 mono_error_assert_ok (error);
5555 MonoClass *c2 = mono_class_get_checked (cm2->image, cm2->modifiers [i].token, error);
5556 mono_error_assert_ok (error);
5558 if (c1 != c2) {
5559 cmod_reject = TRUE;
5560 break;
5565 gboolean result = FALSE;
5567 switch (t1->type) {
5568 case MONO_TYPE_VOID:
5569 case MONO_TYPE_BOOLEAN:
5570 case MONO_TYPE_CHAR:
5571 case MONO_TYPE_I1:
5572 case MONO_TYPE_U1:
5573 case MONO_TYPE_I2:
5574 case MONO_TYPE_U2:
5575 case MONO_TYPE_I4:
5576 case MONO_TYPE_U4:
5577 case MONO_TYPE_I8:
5578 case MONO_TYPE_U8:
5579 case MONO_TYPE_R4:
5580 case MONO_TYPE_R8:
5581 case MONO_TYPE_STRING:
5582 case MONO_TYPE_I:
5583 case MONO_TYPE_U:
5584 case MONO_TYPE_OBJECT:
5585 case MONO_TYPE_TYPEDBYREF:
5586 result = TRUE;
5587 break;
5588 case MONO_TYPE_VALUETYPE:
5589 case MONO_TYPE_CLASS:
5590 case MONO_TYPE_SZARRAY:
5591 result = mono_metadata_class_equal (t1->data.klass, t2->data.klass, signature_only);
5592 break;
5593 case MONO_TYPE_PTR:
5594 result = do_mono_metadata_type_equal (t1->data.type, t2->data.type, signature_only);
5595 break;
5596 case MONO_TYPE_ARRAY:
5597 if (t1->data.array->rank != t2->data.array->rank)
5598 result = FALSE;
5599 else
5600 result = mono_metadata_class_equal (t1->data.array->eklass, t2->data.array->eklass, signature_only);
5601 break;
5602 case MONO_TYPE_GENERICINST:
5603 result = _mono_metadata_generic_class_equal (
5604 t1->data.generic_class, t2->data.generic_class, signature_only);
5605 break;
5606 case MONO_TYPE_VAR:
5607 result = mono_metadata_generic_param_equal_internal (
5608 t1->data.generic_param, t2->data.generic_param, signature_only);
5609 break;
5610 case MONO_TYPE_MVAR:
5611 result = mono_metadata_generic_param_equal_internal (
5612 t1->data.generic_param, t2->data.generic_param, signature_only);
5613 break;
5614 case MONO_TYPE_FNPTR:
5615 result = mono_metadata_fnptr_equal (t1->data.method, t2->data.method, signature_only);
5616 break;
5617 default:
5618 g_error ("implement type compare for %0x!", t1->type);
5619 return FALSE;
5622 if (cmod_reject && is_pointer)
5623 return FALSE;
5625 return result;
5629 * mono_metadata_type_equal:
5631 gboolean
5632 mono_metadata_type_equal (MonoType *t1, MonoType *t2)
5634 return do_mono_metadata_type_equal (t1, t2, FALSE);
5638 * mono_metadata_type_equal_full:
5639 * \param t1 a type
5640 * \param t2 another type
5641 * \param signature_only if signature only comparison should be made
5643 * Determine if \p t1 and \p t2 are signature compatible if \p signature_only is TRUE, otherwise
5644 * behaves the same way as mono_metadata_type_equal.
5645 * The function mono_metadata_type_equal(a, b) is just a shortcut for mono_metadata_type_equal_full(a, b, FALSE).
5646 * \returns TRUE if \p t1 and \p t2 are equal taking \p signature_only into account.
5648 gboolean
5649 mono_metadata_type_equal_full (MonoType *t1, MonoType *t2, gboolean signature_only)
5651 return do_mono_metadata_type_equal (t1, t2, signature_only);
5655 * mono_metadata_signature_equal:
5656 * \param sig1 a signature
5657 * \param sig2 another signature
5659 * Determine if \p sig1 and \p sig2 represent the same signature, with the
5660 * same number of arguments and the same types.
5661 * \returns TRUE if \p sig1 and \p sig2 are equal.
5663 gboolean
5664 mono_metadata_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
5666 int i;
5668 if (sig1->hasthis != sig2->hasthis || sig1->param_count != sig2->param_count)
5669 return FALSE;
5671 if (sig1->generic_param_count != sig2->generic_param_count)
5672 return FALSE;
5675 * We're just comparing the signatures of two methods here:
5677 * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
5678 * U and V are equal here.
5680 * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
5683 for (i = 0; i < sig1->param_count; i++) {
5684 MonoType *p1 = sig1->params[i];
5685 MonoType *p2 = sig2->params[i];
5687 /* if (p1->attrs != p2->attrs)
5688 return FALSE;
5690 if (!do_mono_metadata_type_equal (p1, p2, TRUE))
5691 return FALSE;
5694 if (!do_mono_metadata_type_equal (sig1->ret, sig2->ret, TRUE))
5695 return FALSE;
5696 return TRUE;
5700 * mono_metadata_type_dup:
5701 * \param image image to alloc memory from
5702 * \param original type to duplicate
5703 * \returns copy of type allocated from the image's mempool (or from the heap, if \p image is null).
5705 MonoType *
5706 mono_metadata_type_dup (MonoImage *image, const MonoType *o)
5708 return mono_metadata_type_dup_with_cmods (image, o, o);
5712 * Works the same way as mono_metadata_type_dup but pick cmods from @cmods_source
5714 MonoType *
5715 mono_metadata_type_dup_with_cmods (MonoImage *image, const MonoType *o, const MonoType *cmods_source)
5717 MonoType *r = NULL;
5718 size_t sizeof_o = mono_sizeof_type (cmods_source);
5720 r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_o) : (MonoType *)g_malloc (sizeof_o);
5722 if (cmods_source->has_cmods) {
5723 g_assert (!image || image == mono_type_get_cmods (cmods_source)->image);
5724 memcpy (r, cmods_source, sizeof_o);
5727 memcpy (r, o, sizeof (MonoType));
5728 r->has_cmods = cmods_source->has_cmods;
5730 if (o->type == MONO_TYPE_PTR) {
5731 r->data.type = mono_metadata_type_dup (image, o->data.type);
5732 } else if (o->type == MONO_TYPE_ARRAY) {
5733 r->data.array = mono_dup_array_type (image, o->data.array);
5734 } else if (o->type == MONO_TYPE_FNPTR) {
5735 /*FIXME the dup'ed signature is leaked mono_metadata_free_type*/
5736 r->data.method = mono_metadata_signature_deep_dup (image, o->data.method);
5738 return r;
5742 * mono_signature_hash:
5744 guint
5745 mono_signature_hash (MonoMethodSignature *sig)
5747 guint i, res = sig->ret->type;
5749 for (i = 0; i < sig->param_count; i++)
5750 res = (res << 5) - res + mono_type_hash (sig->params[i]);
5752 return res;
5756 * mono_metadata_encode_value:
5757 * @value: value to encode
5758 * @buf: buffer where to write the compressed representation
5759 * @endbuf: pointer updated to point at the end of the encoded output
5761 * Encodes the value @value in the compressed representation used
5762 * in metadata and stores the result in @buf. @buf needs to be big
5763 * enough to hold the data (4 bytes).
5765 void
5766 mono_metadata_encode_value (guint32 value, char *buf, char **endbuf)
5768 char *p = buf;
5770 if (value < 0x80)
5771 *p++ = value;
5772 else if (value < 0x4000) {
5773 p [0] = 0x80 | (value >> 8);
5774 p [1] = value & 0xff;
5775 p += 2;
5776 } else {
5777 p [0] = (value >> 24) | 0xc0;
5778 p [1] = (value >> 16) & 0xff;
5779 p [2] = (value >> 8) & 0xff;
5780 p [3] = value & 0xff;
5781 p += 4;
5783 if (endbuf)
5784 *endbuf = p;
5788 * mono_metadata_field_info:
5789 * \param meta the Image the field is defined in
5790 * \param index the index in the field table representing the field
5791 * \param offset a pointer to an integer where to store the offset that may have been specified for the field in a FieldLayout table
5792 * \param rva a pointer to the RVA of the field data in the image that may have been defined in a \c FieldRVA table
5793 * \param marshal_spec a pointer to the marshal spec that may have been defined for the field in a \c FieldMarshal table.
5795 * Gather info for field \p index that may have been defined in the \c FieldLayout,
5796 * \c FieldRVA and \c FieldMarshal tables.
5797 * Either of \p offset, \p rva and \p marshal_spec can be NULL if you're not interested
5798 * in the data.
5800 void
5801 mono_metadata_field_info (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
5802 MonoMarshalSpec **marshal_spec)
5804 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, FALSE);
5807 void
5808 mono_metadata_field_info_with_mempool (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
5809 MonoMarshalSpec **marshal_spec)
5811 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, TRUE);
5814 static void
5815 mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
5816 MonoMarshalSpec **marshal_spec, gboolean alloc_from_image)
5818 MonoTableInfo *tdef;
5819 locator_t loc;
5821 loc.idx = index + 1;
5822 if (meta->uncompressed_metadata)
5823 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
5825 if (offset) {
5826 tdef = &meta->tables [MONO_TABLE_FIELDLAYOUT];
5828 loc.col_idx = MONO_FIELD_LAYOUT_FIELD;
5829 loc.t = tdef;
5831 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
5832 *offset = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_LAYOUT_OFFSET);
5833 } else {
5834 *offset = (guint32)-1;
5837 if (rva) {
5838 tdef = &meta->tables [MONO_TABLE_FIELDRVA];
5840 loc.col_idx = MONO_FIELD_RVA_FIELD;
5841 loc.t = tdef;
5843 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
5845 * LAMESPEC: There is no signature, no nothing, just the raw data.
5847 *rva = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_RVA_RVA);
5848 } else {
5849 *rva = 0;
5852 if (marshal_spec) {
5853 const char *p;
5855 if ((p = mono_metadata_get_marshal_info (meta, index, TRUE))) {
5856 *marshal_spec = mono_metadata_parse_marshal_spec_full (alloc_from_image ? meta : NULL, meta, p);
5863 * mono_metadata_get_constant_index:
5864 * \param meta the Image the field is defined in
5865 * \param index the token that may have a row defined in the constants table
5866 * \param hint possible position for the row
5868 * \p token must be a \c FieldDef, \c ParamDef or \c PropertyDef token.
5870 * \returns the index into the \c Constants table or 0 if not found.
5872 guint32
5873 mono_metadata_get_constant_index (MonoImage *meta, guint32 token, guint32 hint)
5875 MonoTableInfo *tdef;
5876 locator_t loc;
5877 guint32 index = mono_metadata_token_index (token);
5879 tdef = &meta->tables [MONO_TABLE_CONSTANT];
5880 index <<= MONO_HASCONSTANT_BITS;
5881 switch (mono_metadata_token_table (token)) {
5882 case MONO_TABLE_FIELD:
5883 index |= MONO_HASCONSTANT_FIEDDEF;
5884 break;
5885 case MONO_TABLE_PARAM:
5886 index |= MONO_HASCONSTANT_PARAM;
5887 break;
5888 case MONO_TABLE_PROPERTY:
5889 index |= MONO_HASCONSTANT_PROPERTY;
5890 break;
5891 default:
5892 g_warning ("Not a valid token for the constant table: 0x%08x", token);
5893 return 0;
5895 loc.idx = index;
5896 loc.col_idx = MONO_CONSTANT_PARENT;
5897 loc.t = tdef;
5899 /* FIXME: Index translation */
5901 if ((hint > 0) && (hint < tdef->rows) && (mono_metadata_decode_row_col (tdef, hint - 1, MONO_CONSTANT_PARENT) == index))
5902 return hint;
5904 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
5905 return loc.result + 1;
5907 return 0;
5911 * mono_metadata_events_from_typedef:
5912 * \param meta metadata context
5913 * \param index 0-based index (in the \c TypeDef table) describing a type
5914 * \returns the 0-based index in the \c Event table for the events in the
5915 * type. The last event that belongs to the type (plus 1) is stored
5916 * in the \p end_idx pointer.
5918 guint32
5919 mono_metadata_events_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
5921 locator_t loc;
5922 guint32 start, end;
5923 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_EVENTMAP];
5925 *end_idx = 0;
5927 if (!tdef->base)
5928 return 0;
5930 loc.t = tdef;
5931 loc.col_idx = MONO_EVENT_MAP_PARENT;
5932 loc.idx = index + 1;
5934 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5935 return 0;
5937 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_EVENT_MAP_EVENTLIST);
5938 if (loc.result + 1 < tdef->rows) {
5939 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_EVENT_MAP_EVENTLIST) - 1;
5940 } else {
5941 end = meta->tables [MONO_TABLE_EVENT].rows;
5944 *end_idx = end;
5945 return start - 1;
5949 * mono_metadata_methods_from_event:
5950 * \param meta metadata context
5951 * \param index 0-based index (in the \c Event table) describing a event
5952 * \returns the 0-based index in the \c MethodDef table for the methods in the
5953 * event. The last method that belongs to the event (plus 1) is stored
5954 * in the \p end_idx pointer.
5956 guint32
5957 mono_metadata_methods_from_event (MonoImage *meta, guint32 index, guint *end_idx)
5959 locator_t loc;
5960 guint start, end;
5961 guint32 cols [MONO_METHOD_SEMA_SIZE];
5962 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
5964 *end_idx = 0;
5965 if (!msemt->base)
5966 return 0;
5968 if (meta->uncompressed_metadata)
5969 index = search_ptr_table (meta, MONO_TABLE_EVENT_POINTER, index + 1) - 1;
5971 loc.t = msemt;
5972 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
5973 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT; /* Method association coded index */
5975 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
5976 return 0;
5978 start = loc.result;
5980 * We may end up in the middle of the rows...
5982 while (start > 0) {
5983 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
5984 start--;
5985 else
5986 break;
5988 end = start + 1;
5989 while (end < msemt->rows) {
5990 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
5991 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
5992 break;
5993 ++end;
5995 *end_idx = end;
5996 return start;
6000 * mono_metadata_properties_from_typedef:
6001 * \param meta metadata context
6002 * \param index 0-based index (in the \c TypeDef table) describing a type
6003 * \returns the 0-based index in the \c Property table for the properties in the
6004 * type. The last property that belongs to the type (plus 1) is stored
6005 * in the \p end_idx pointer.
6007 guint32
6008 mono_metadata_properties_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
6010 locator_t loc;
6011 guint32 start, end;
6012 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_PROPERTYMAP];
6014 *end_idx = 0;
6016 if (!tdef->base)
6017 return 0;
6019 loc.t = tdef;
6020 loc.col_idx = MONO_PROPERTY_MAP_PARENT;
6021 loc.idx = index + 1;
6023 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6024 return 0;
6026 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_PROPERTY_MAP_PROPERTY_LIST);
6027 if (loc.result + 1 < tdef->rows) {
6028 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_PROPERTY_MAP_PROPERTY_LIST) - 1;
6029 } else {
6030 end = meta->tables [MONO_TABLE_PROPERTY].rows;
6033 *end_idx = end;
6034 return start - 1;
6038 * mono_metadata_methods_from_property:
6039 * \param meta metadata context
6040 * \param index 0-based index (in the \c PropertyDef table) describing a property
6041 * \returns the 0-based index in the \c MethodDef table for the methods in the
6042 * property. The last method that belongs to the property (plus 1) is stored
6043 * in the \p end_idx pointer.
6045 guint32
6046 mono_metadata_methods_from_property (MonoImage *meta, guint32 index, guint *end_idx)
6048 locator_t loc;
6049 guint start, end;
6050 guint32 cols [MONO_METHOD_SEMA_SIZE];
6051 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
6053 *end_idx = 0;
6054 if (!msemt->base)
6055 return 0;
6057 if (meta->uncompressed_metadata)
6058 index = search_ptr_table (meta, MONO_TABLE_PROPERTY_POINTER, index + 1) - 1;
6060 loc.t = msemt;
6061 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
6062 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY; /* Method association coded index */
6064 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
6065 return 0;
6067 start = loc.result;
6069 * We may end up in the middle of the rows...
6071 while (start > 0) {
6072 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
6073 start--;
6074 else
6075 break;
6077 end = start + 1;
6078 while (end < msemt->rows) {
6079 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
6080 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
6081 break;
6082 ++end;
6084 *end_idx = end;
6085 return start;
6089 * mono_metadata_implmap_from_method:
6091 guint32
6092 mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx)
6094 locator_t loc;
6095 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_IMPLMAP];
6097 if (!tdef->base)
6098 return 0;
6100 /* No index translation seems to be needed */
6102 loc.t = tdef;
6103 loc.col_idx = MONO_IMPLMAP_MEMBER;
6104 loc.idx = ((method_idx + 1) << MONO_MEMBERFORWD_BITS) | MONO_MEMBERFORWD_METHODDEF;
6106 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6107 return 0;
6109 return loc.result + 1;
6113 * mono_type_create_from_typespec:
6114 * \param image context where the image is created
6115 * \param type_spec typespec token
6116 * \deprecated use \c mono_type_create_from_typespec_checked that has proper error handling
6118 * Creates a \c MonoType representing the \c TypeSpec indexed by the \p type_spec
6119 * token.
6121 MonoType *
6122 mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
6124 ERROR_DECL (error);
6125 MonoType *type = mono_type_create_from_typespec_checked (image, type_spec, error);
6126 if (!type)
6127 g_error ("Could not create typespec %x due to %s", type_spec, mono_error_get_message (error));
6128 return type;
6131 MonoType *
6132 mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, MonoError *error)
6135 guint32 idx = mono_metadata_token_index (type_spec);
6136 MonoTableInfo *t;
6137 guint32 cols [MONO_TYPESPEC_SIZE];
6138 const char *ptr;
6139 MonoType *type, *type2;
6141 error_init (error);
6143 type = (MonoType *)mono_conc_hashtable_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
6144 if (type)
6145 return type;
6147 t = &image->tables [MONO_TABLE_TYPESPEC];
6149 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
6150 ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
6152 if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, error))
6153 return NULL;
6155 mono_metadata_decode_value (ptr, &ptr);
6157 type = mono_metadata_parse_type_checked (image, NULL, 0, TRUE, ptr, &ptr, error);
6158 if (!type)
6159 return NULL;
6161 type2 = mono_metadata_type_dup (image, type);
6162 mono_metadata_free_type (type);
6164 mono_image_lock (image);
6166 /* We might leak some data in the image mempool if found */
6167 type = (MonoType*)mono_conc_hashtable_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
6168 if (!type)
6169 type = type2;
6171 mono_image_unlock (image);
6173 return type;
6177 static char*
6178 mono_image_strndup (MonoImage *image, const char *data, guint len)
6180 char *res;
6181 if (!image)
6182 return g_strndup (data, len);
6183 res = (char *)mono_image_alloc (image, len + 1);
6184 memcpy (res, data, len);
6185 res [len] = 0;
6186 return res;
6190 * mono_metadata_parse_marshal_spec:
6192 MonoMarshalSpec *
6193 mono_metadata_parse_marshal_spec (MonoImage *image, const char *ptr)
6195 return mono_metadata_parse_marshal_spec_full (NULL, image, ptr);
6199 * If IMAGE is non-null, memory will be allocated from its mempool, otherwise it will be allocated using malloc.
6200 * PARENT_IMAGE is the image containing the marshal spec.
6202 MonoMarshalSpec *
6203 mono_metadata_parse_marshal_spec_full (MonoImage *image, MonoImage *parent_image, const char *ptr)
6205 MonoMarshalSpec *res;
6206 int len;
6207 const char *start = ptr;
6209 /* fixme: this is incomplete, but I cant find more infos in the specs */
6211 if (image)
6212 res = (MonoMarshalSpec *)mono_image_alloc0 (image, sizeof (MonoMarshalSpec));
6213 else
6214 res = g_new0 (MonoMarshalSpec, 1);
6216 len = mono_metadata_decode_value (ptr, &ptr);
6217 res->native = (MonoMarshalNative)*ptr++;
6219 if (res->native == MONO_NATIVE_LPARRAY) {
6220 res->data.array_data.param_num = -1;
6221 res->data.array_data.num_elem = -1;
6222 res->data.array_data.elem_mult = -1;
6224 if (ptr - start <= len)
6225 res->data.array_data.elem_type = (MonoMarshalNative)*ptr++;
6226 if (ptr - start <= len)
6227 res->data.array_data.param_num = mono_metadata_decode_value (ptr, &ptr);
6228 if (ptr - start <= len)
6229 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6230 if (ptr - start <= len) {
6232 * LAMESPEC: Older spec versions say this parameter comes before
6233 * num_elem. Never spec versions don't talk about elem_mult at
6234 * all, but csc still emits it, and it is used to distinguish
6235 * between param_num being 0, and param_num being omitted.
6236 * So if (param_num == 0) && (num_elem > 0), then
6237 * elem_mult == 0 -> the array size is num_elem
6238 * elem_mult == 1 -> the array size is @param_num + num_elem
6240 res->data.array_data.elem_mult = mono_metadata_decode_value (ptr, &ptr);
6244 if (res->native == MONO_NATIVE_BYVALTSTR) {
6245 if (ptr - start <= len)
6246 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6249 if (res->native == MONO_NATIVE_BYVALARRAY) {
6250 if (ptr - start <= len)
6251 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
6254 if (res->native == MONO_NATIVE_CUSTOM) {
6255 /* skip unused type guid */
6256 len = mono_metadata_decode_value (ptr, &ptr);
6257 ptr += len;
6258 /* skip unused native type name */
6259 len = mono_metadata_decode_value (ptr, &ptr);
6260 ptr += len;
6261 /* read custom marshaler type name */
6262 len = mono_metadata_decode_value (ptr, &ptr);
6263 res->data.custom_data.custom_name = mono_image_strndup (image, ptr, len);
6264 ptr += len;
6265 /* read cookie string */
6266 len = mono_metadata_decode_value (ptr, &ptr);
6267 res->data.custom_data.cookie = mono_image_strndup (image, ptr, len);
6268 res->data.custom_data.image = parent_image;
6271 if (res->native == MONO_NATIVE_SAFEARRAY) {
6272 res->data.safearray_data.elem_type = (MonoMarshalVariant)0;
6273 res->data.safearray_data.num_elem = 0;
6274 if (ptr - start <= len)
6275 res->data.safearray_data.elem_type = (MonoMarshalVariant)*ptr++;
6276 if (ptr - start <= len)
6277 res->data.safearray_data.num_elem = *ptr++;
6279 return res;
6283 * mono_metadata_free_marshal_spec:
6285 void
6286 mono_metadata_free_marshal_spec (MonoMarshalSpec *spec)
6288 if (!spec)
6289 return;
6291 if (spec->native == MONO_NATIVE_CUSTOM) {
6292 g_free (spec->data.custom_data.custom_name);
6293 g_free (spec->data.custom_data.cookie);
6295 g_free (spec);
6299 * mono_type_to_unmanaged:
6300 * The value pointed to by \p conv will contain the kind of marshalling required for this
6301 * particular type one of the \c MONO_MARSHAL_CONV_ enumeration values.
6302 * \returns A \c MonoMarshalNative enumeration value (<code>MONO_NATIVE_</code>) value
6303 * describing the underlying native reprensetation of the type.
6305 guint32 // FIXMEcxx MonoMarshalNative
6306 mono_type_to_unmanaged (MonoType *type, MonoMarshalSpec *mspec, gboolean as_field,
6307 gboolean unicode, MonoMarshalConv *conv)
6309 MonoMarshalConv dummy_conv;
6310 int t = type->type;
6312 if (!conv)
6313 conv = &dummy_conv;
6315 *conv = MONO_MARSHAL_CONV_NONE;
6317 if (type->byref)
6318 return MONO_NATIVE_UINT;
6320 handle_enum:
6321 switch (t) {
6322 case MONO_TYPE_BOOLEAN:
6323 if (mspec) {
6324 switch (mspec->native) {
6325 case MONO_NATIVE_VARIANTBOOL:
6326 *conv = MONO_MARSHAL_CONV_BOOL_VARIANTBOOL;
6327 return MONO_NATIVE_VARIANTBOOL;
6328 case MONO_NATIVE_BOOLEAN:
6329 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6330 return MONO_NATIVE_BOOLEAN;
6331 case MONO_NATIVE_I1:
6332 case MONO_NATIVE_U1:
6333 return mspec->native;
6334 default:
6335 g_error ("cant marshal bool to native type %02x", mspec->native);
6338 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6339 return MONO_NATIVE_BOOLEAN;
6340 case MONO_TYPE_CHAR:
6341 if (mspec) {
6342 switch (mspec->native) {
6343 case MONO_NATIVE_U2:
6344 case MONO_NATIVE_U1:
6345 return mspec->native;
6346 default:
6347 g_error ("cant marshal char to native type %02x", mspec->native);
6350 return unicode ? MONO_NATIVE_U2 : MONO_NATIVE_U1;
6351 case MONO_TYPE_I1: return MONO_NATIVE_I1;
6352 case MONO_TYPE_U1: return MONO_NATIVE_U1;
6353 case MONO_TYPE_I2: return MONO_NATIVE_I2;
6354 case MONO_TYPE_U2: return MONO_NATIVE_U2;
6355 case MONO_TYPE_I4: return MONO_NATIVE_I4;
6356 case MONO_TYPE_U4: return MONO_NATIVE_U4;
6357 case MONO_TYPE_I8: return MONO_NATIVE_I8;
6358 case MONO_TYPE_U8: return MONO_NATIVE_U8;
6359 case MONO_TYPE_R4: return MONO_NATIVE_R4;
6360 case MONO_TYPE_R8: return MONO_NATIVE_R8;
6361 case MONO_TYPE_STRING:
6362 if (mspec) {
6363 switch (mspec->native) {
6364 case MONO_NATIVE_BSTR:
6365 *conv = MONO_MARSHAL_CONV_STR_BSTR;
6366 return MONO_NATIVE_BSTR;
6367 case MONO_NATIVE_LPSTR:
6368 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6369 return MONO_NATIVE_LPSTR;
6370 case MONO_NATIVE_LPWSTR:
6371 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6372 return MONO_NATIVE_LPWSTR;
6373 case MONO_NATIVE_LPTSTR:
6374 *conv = MONO_MARSHAL_CONV_STR_LPTSTR;
6375 return MONO_NATIVE_LPTSTR;
6376 case MONO_NATIVE_ANSIBSTR:
6377 *conv = MONO_MARSHAL_CONV_STR_ANSIBSTR;
6378 return MONO_NATIVE_ANSIBSTR;
6379 case MONO_NATIVE_TBSTR:
6380 *conv = MONO_MARSHAL_CONV_STR_TBSTR;
6381 return MONO_NATIVE_TBSTR;
6382 case MONO_NATIVE_UTF8STR:
6383 *conv = MONO_MARSHAL_CONV_STR_UTF8STR;
6384 return MONO_NATIVE_UTF8STR;
6385 case MONO_NATIVE_BYVALTSTR:
6386 if (unicode)
6387 *conv = MONO_MARSHAL_CONV_STR_BYVALWSTR;
6388 else
6389 *conv = MONO_MARSHAL_CONV_STR_BYVALSTR;
6390 return MONO_NATIVE_BYVALTSTR;
6391 default:
6392 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);
6395 if (unicode) {
6396 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6397 return MONO_NATIVE_LPWSTR;
6399 else {
6400 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6401 return MONO_NATIVE_LPSTR;
6403 case MONO_TYPE_PTR: return MONO_NATIVE_UINT;
6404 case MONO_TYPE_VALUETYPE: /*FIXME*/
6405 if (m_class_is_enumtype (type->data.klass)) {
6406 t = mono_class_enum_basetype_internal (type->data.klass)->type;
6407 goto handle_enum;
6409 if (type->data.klass == mono_class_try_get_handleref_class ()){
6410 *conv = MONO_MARSHAL_CONV_HANDLEREF;
6411 return MONO_NATIVE_INT;
6413 return MONO_NATIVE_STRUCT;
6414 case MONO_TYPE_SZARRAY:
6415 case MONO_TYPE_ARRAY:
6416 if (mspec) {
6417 switch (mspec->native) {
6418 case MONO_NATIVE_BYVALARRAY:
6419 if ((m_class_get_element_class (type->data.klass) == mono_defaults.char_class) && !unicode)
6420 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY;
6421 else
6422 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALARRAY;
6423 return MONO_NATIVE_BYVALARRAY;
6424 case MONO_NATIVE_SAFEARRAY:
6425 *conv = MONO_MARSHAL_CONV_ARRAY_SAVEARRAY;
6426 return MONO_NATIVE_SAFEARRAY;
6427 case MONO_NATIVE_LPARRAY:
6428 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6429 return MONO_NATIVE_LPARRAY;
6430 default:
6431 g_error ("cant marshal array as native type %02x", mspec->native);
6435 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6436 return MONO_NATIVE_LPARRAY;
6437 case MONO_TYPE_I: return MONO_NATIVE_INT;
6438 case MONO_TYPE_U: return MONO_NATIVE_UINT;
6439 case MONO_TYPE_CLASS:
6440 case MONO_TYPE_OBJECT: {
6441 /* FIXME : we need to handle ArrayList and StringBuilder here, probably */
6442 if (mspec) {
6443 switch (mspec->native) {
6444 case MONO_NATIVE_STRUCT:
6445 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6446 return MONO_NATIVE_STRUCT;
6447 case MONO_NATIVE_CUSTOM:
6448 return MONO_NATIVE_CUSTOM;
6449 case MONO_NATIVE_INTERFACE:
6450 *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
6451 return MONO_NATIVE_INTERFACE;
6452 case MONO_NATIVE_IDISPATCH:
6453 *conv = MONO_MARSHAL_CONV_OBJECT_IDISPATCH;
6454 return MONO_NATIVE_IDISPATCH;
6455 case MONO_NATIVE_IUNKNOWN:
6456 *conv = MONO_MARSHAL_CONV_OBJECT_IUNKNOWN;
6457 return MONO_NATIVE_IUNKNOWN;
6458 case MONO_NATIVE_FUNC:
6459 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6460 type->data.klass == mono_defaults.delegate_class ||
6461 m_class_get_parent (type->data.klass) == mono_defaults.multicastdelegate_class)) {
6462 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6463 return MONO_NATIVE_FUNC;
6465 /* Fall through */
6466 default:
6467 g_error ("cant marshal object as native type %02x", mspec->native);
6470 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6471 type->data.klass == mono_defaults.delegate_class ||
6472 m_class_get_parent (type->data.klass) == mono_defaults.multicastdelegate_class)) {
6473 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6474 return MONO_NATIVE_FUNC;
6476 if (mono_class_try_get_safehandle_class () && type->data.klass == mono_class_try_get_safehandle_class ()){
6477 *conv = MONO_MARSHAL_CONV_SAFEHANDLE;
6478 return MONO_NATIVE_INT;
6480 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6481 return MONO_NATIVE_STRUCT;
6483 case MONO_TYPE_FNPTR: return MONO_NATIVE_FUNC;
6484 case MONO_TYPE_GENERICINST:
6485 type = m_class_get_byval_arg (type->data.generic_class->container_class);
6486 t = type->type;
6487 goto handle_enum;
6488 case MONO_TYPE_TYPEDBYREF:
6489 default:
6490 g_error ("type 0x%02x not handled in marshal", t);
6492 return MONO_NATIVE_MAX;
6496 * mono_metadata_get_marshal_info:
6498 const char*
6499 mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field)
6501 locator_t loc;
6502 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_FIELDMARSHAL];
6504 if (!tdef->base)
6505 return NULL;
6507 loc.t = tdef;
6508 loc.col_idx = MONO_FIELD_MARSHAL_PARENT;
6509 loc.idx = ((idx + 1) << MONO_HAS_FIELD_MARSHAL_BITS) | (is_field? MONO_HAS_FIELD_MARSHAL_FIELDSREF: MONO_HAS_FIELD_MARSHAL_PARAMDEF);
6511 /* FIXME: Index translation */
6513 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6514 return NULL;
6516 return mono_metadata_blob_heap (meta, mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_MARSHAL_NATIVE_TYPE));
6519 MonoMethod*
6520 mono_method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context, MonoError *error)
6522 MonoMethod *result = NULL;
6523 guint32 idx = tok >> MONO_METHODDEFORREF_BITS;
6525 error_init (error);
6527 switch (tok & MONO_METHODDEFORREF_MASK) {
6528 case MONO_METHODDEFORREF_METHODDEF:
6529 result = mono_get_method_checked (m, MONO_TOKEN_METHOD_DEF | idx, NULL, context, error);
6530 break;
6531 case MONO_METHODDEFORREF_METHODREF:
6532 result = mono_get_method_checked (m, MONO_TOKEN_MEMBER_REF | idx, NULL, context, error);
6533 break;
6534 default:
6535 mono_error_set_bad_image (error, m, "Invalid MethodDefOfRef token %x", tok);
6538 return result;
6542 * mono_class_get_overrides_full:
6544 * Compute the method overrides belonging to class @type_token in @overrides, and the number of overrides in @num_overrides.
6547 void
6548 mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides, MonoGenericContext *generic_context, MonoError *error)
6550 locator_t loc;
6551 MonoTableInfo *tdef = &image->tables [MONO_TABLE_METHODIMPL];
6552 guint32 start, end;
6553 gint32 i, num;
6554 guint32 cols [MONO_METHODIMPL_SIZE];
6555 MonoMethod **result;
6557 error_init (error);
6559 *overrides = NULL;
6560 if (num_overrides)
6561 *num_overrides = 0;
6563 if (!tdef->base)
6564 return;
6566 loc.t = tdef;
6567 loc.col_idx = MONO_METHODIMPL_CLASS;
6568 loc.idx = mono_metadata_token_index (type_token);
6570 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6571 return;
6573 start = loc.result;
6574 end = start + 1;
6576 * We may end up in the middle of the rows...
6578 while (start > 0) {
6579 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_METHODIMPL_CLASS))
6580 start--;
6581 else
6582 break;
6584 while (end < tdef->rows) {
6585 if (loc.idx == mono_metadata_decode_row_col (tdef, end, MONO_METHODIMPL_CLASS))
6586 end++;
6587 else
6588 break;
6590 num = end - start;
6591 result = g_new (MonoMethod*, num * 2);
6592 for (i = 0; i < num; ++i) {
6593 MonoMethod *method;
6595 if (!mono_verifier_verify_methodimpl_row (image, start + i, error))
6596 break;
6598 mono_metadata_decode_row (tdef, start + i, cols, MONO_METHODIMPL_SIZE);
6599 method = mono_method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_DECLARATION], generic_context, error);
6600 if (!method)
6601 break;
6603 result [i * 2] = method;
6604 method = mono_method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_BODY], generic_context, error);
6605 if (!method)
6606 break;
6608 result [i * 2 + 1] = method;
6611 if (!is_ok (error)) {
6612 g_free (result);
6613 *overrides = NULL;
6614 if (num_overrides)
6615 *num_overrides = 0;
6616 } else {
6617 *overrides = result;
6618 if (num_overrides)
6619 *num_overrides = num;
6624 * mono_guid_to_string:
6626 * Converts a 16 byte Microsoft GUID to the standard string representation.
6628 char *
6629 mono_guid_to_string (const guint8 *guid)
6631 return g_strdup_printf ("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
6632 guid[3], guid[2], guid[1], guid[0],
6633 guid[5], guid[4],
6634 guid[7], guid[6],
6635 guid[8], guid[9],
6636 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
6640 * mono_guid_to_string_minimal:
6642 * Converts a 16 byte Microsoft GUID to lower case no '-' representation..
6644 char *
6645 mono_guid_to_string_minimal (const guint8 *guid)
6647 return g_strdup_printf ("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
6648 guid[3], guid[2], guid[1], guid[0],
6649 guid[5], guid[4],
6650 guid[7], guid[6],
6651 guid[8], guid[9],
6652 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
6654 static gboolean
6655 get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGenericContainer *container, MonoError *error)
6657 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
6658 guint32 cols [MONO_GENPARCONSTRAINT_SIZE];
6659 guint32 i, token, found;
6660 MonoClass *klass, **res;
6661 GSList *cons = NULL, *tmp;
6662 MonoGenericContext *context = &container->context;
6664 error_init (error);
6666 *constraints = NULL;
6667 found = 0;
6668 for (i = 0; i < tdef->rows; ++i) {
6669 mono_metadata_decode_row (tdef, i, cols, MONO_GENPARCONSTRAINT_SIZE);
6670 if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) {
6671 token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]);
6672 klass = mono_class_get_and_inflate_typespec_checked (image, token, context, error);
6673 if (!klass) {
6674 g_slist_free (cons);
6675 return FALSE;
6677 cons = g_slist_append (cons, klass);
6678 ++found;
6679 } else {
6680 /* contiguous list finished */
6681 if (found)
6682 break;
6685 if (!found)
6686 return TRUE;
6687 res = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * (found + 1));
6688 for (i = 0, tmp = cons; i < found; ++i, tmp = tmp->next) {
6689 res [i] = (MonoClass *)tmp->data;
6691 g_slist_free (cons);
6692 *constraints = res;
6693 return TRUE;
6697 * mono_metadata_get_generic_param_row:
6699 * @image:
6700 * @token: TypeOrMethodDef token, owner for GenericParam
6701 * @owner: coded token, set on return
6703 * Returns: 1-based row-id in the GenericParam table whose
6704 * owner is @token. 0 if not found.
6706 guint32
6707 mono_metadata_get_generic_param_row (MonoImage *image, guint32 token, guint32 *owner)
6709 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
6710 locator_t loc;
6712 g_assert (owner);
6713 if (!tdef->base)
6714 return 0;
6716 if (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
6717 *owner = MONO_TYPEORMETHOD_TYPE;
6718 else if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
6719 *owner = MONO_TYPEORMETHOD_METHOD;
6720 else {
6721 g_error ("wrong token %x to get_generic_param_row", token);
6722 return 0;
6724 *owner |= mono_metadata_token_index (token) << MONO_TYPEORMETHOD_BITS;
6726 loc.idx = *owner;
6727 loc.col_idx = MONO_GENERICPARAM_OWNER;
6728 loc.t = tdef;
6730 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6731 return 0;
6733 /* Find the first entry by searching backwards */
6734 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_GENERICPARAM_OWNER) == loc.idx))
6735 loc.result --;
6737 return loc.result + 1;
6740 gboolean
6741 mono_metadata_has_generic_params (MonoImage *image, guint32 token)
6743 guint32 owner;
6744 return mono_metadata_get_generic_param_row (image, token, &owner);
6748 * Memory is allocated from IMAGE's mempool.
6750 gboolean
6751 mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token,
6752 MonoGenericContainer *container, MonoError *error)
6755 guint32 start_row, i, owner;
6756 error_init (error);
6758 if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner)))
6759 return TRUE;
6760 for (i = 0; i < container->type_argc; i++) {
6761 if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container, error)) {
6762 return FALSE;
6765 return TRUE;
6769 * mono_metadata_load_generic_params:
6771 * Load the type parameters from the type or method definition @token.
6773 * Use this method after parsing a type or method definition to figure out whether it's a generic
6774 * type / method. When parsing a method definition, @parent_container points to the generic container
6775 * of the current class, if any.
6777 * Note: This method does not load the constraints: for typedefs, this has to be done after fully
6778 * creating the type.
6780 * Returns: NULL if @token is not a generic type or method definition or the new generic container.
6782 * LOCKING: Acquires the loader lock
6785 MonoGenericContainer *
6786 mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericContainer *parent_container, gpointer real_owner)
6788 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
6789 guint32 cols [MONO_GENERICPARAM_SIZE];
6790 guint32 i, owner = 0, n;
6791 MonoGenericContainer *container;
6792 MonoGenericParamFull *params;
6793 MonoGenericContext *context;
6794 gboolean is_method = mono_metadata_token_table (token) == MONO_TABLE_METHOD;
6795 gboolean is_anonymous = real_owner == NULL;
6797 if (!(i = mono_metadata_get_generic_param_row (image, token, &owner)))
6798 return NULL;
6799 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
6800 params = NULL;
6801 n = 0;
6802 container = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
6803 container->is_anonymous = is_anonymous;
6804 if (is_anonymous) {
6805 container->owner.image = image;
6806 } else {
6807 if (is_method)
6808 container->owner.method = (MonoMethod*)real_owner;
6809 else
6810 container->owner.klass = (MonoClass*)real_owner;
6812 do {
6813 n++;
6814 params = (MonoGenericParamFull *)g_realloc (params, sizeof (MonoGenericParamFull) * n);
6815 memset (&params [n - 1], 0, sizeof (MonoGenericParamFull));
6816 params [n - 1].owner = container;
6817 params [n - 1].num = cols [MONO_GENERICPARAM_NUMBER];
6818 params [n - 1].info.token = i | MONO_TOKEN_GENERIC_PARAM;
6819 params [n - 1].info.flags = cols [MONO_GENERICPARAM_FLAGS];
6820 params [n - 1].info.name = mono_metadata_string_heap (image, cols [MONO_GENERICPARAM_NAME]);
6821 if (params [n - 1].num != n - 1)
6822 g_warning ("GenericParam table unsorted or hole in generic param sequence: token %d", i);
6823 if (++i > tdef->rows)
6824 break;
6825 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
6826 } while (cols [MONO_GENERICPARAM_OWNER] == owner);
6828 container->type_argc = n;
6829 container->type_params = (MonoGenericParamFull *)mono_image_alloc0 (image, sizeof (MonoGenericParamFull) * n);
6830 memcpy (container->type_params, params, sizeof (MonoGenericParamFull) * n);
6831 g_free (params);
6832 container->parent = parent_container;
6834 if (is_method)
6835 container->is_method = 1;
6837 g_assert (container->parent == NULL || container->is_method);
6839 context = &container->context;
6840 if (container->is_method) {
6841 context->class_inst = container->parent ? container->parent->context.class_inst : NULL;
6842 context->method_inst = mono_get_shared_generic_inst (container);
6843 } else {
6844 context->class_inst = mono_get_shared_generic_inst (container);
6847 return container;
6850 MonoGenericInst *
6851 mono_get_shared_generic_inst (MonoGenericContainer *container)
6853 MonoType **type_argv;
6854 MonoType *helper;
6855 MonoGenericInst *nginst;
6856 int i;
6858 type_argv = g_new0 (MonoType *, container->type_argc);
6859 helper = g_new0 (MonoType, container->type_argc);
6861 for (i = 0; i < container->type_argc; i++) {
6862 MonoType *t = &helper [i];
6864 t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
6865 t->data.generic_param = mono_generic_container_get_param (container, i);
6867 type_argv [i] = t;
6870 nginst = mono_metadata_get_generic_inst (container->type_argc, type_argv);
6872 g_free (type_argv);
6873 g_free (helper);
6875 return nginst;
6879 * mono_type_is_byref:
6880 * \param type the \c MonoType operated on
6881 * \returns TRUE if \p type represents a type passed by reference,
6882 * FALSE otherwise.
6884 mono_bool
6885 mono_type_is_byref (MonoType *type)
6887 mono_bool result;
6888 MONO_ENTER_GC_UNSAFE;
6889 result = type->byref;
6890 MONO_EXIT_GC_UNSAFE;
6891 return result;
6895 * mono_type_get_type:
6896 * \param type the \c MonoType operated on
6897 * \returns the IL type value for \p type. This is one of the \c MonoTypeEnum
6898 * enum members like \c MONO_TYPE_I4 or \c MONO_TYPE_STRING.
6901 mono_type_get_type (MonoType *type)
6903 return type->type;
6907 * mono_type_get_signature:
6908 * \param type the \c MonoType operated on
6909 * It is only valid to call this function if \p type is a \c MONO_TYPE_FNPTR .
6910 * \returns the \c MonoMethodSignature pointer that describes the signature
6911 * of the function pointer \p type represents.
6913 MonoMethodSignature*
6914 mono_type_get_signature (MonoType *type)
6916 g_assert (type->type == MONO_TYPE_FNPTR);
6917 return type->data.method;
6921 * mono_type_get_class:
6922 * \param type the \c MonoType operated on
6923 * It is only valid to call this function if \p type is a \c MONO_TYPE_CLASS or a
6924 * \c MONO_TYPE_VALUETYPE . For more general functionality, use \c mono_class_from_mono_type_internal,
6925 * instead.
6926 * \returns the \c MonoClass pointer that describes the class that \p type represents.
6928 MonoClass*
6929 mono_type_get_class (MonoType *type)
6931 /* FIXME: review the runtime users before adding the assert here */
6932 return type->data.klass;
6936 * mono_type_get_array_type:
6937 * \param type the \c MonoType operated on
6938 * It is only valid to call this function if \p type is a \c MONO_TYPE_ARRAY .
6939 * \returns a \c MonoArrayType struct describing the array type that \p type
6940 * represents. The info includes details such as rank, array element type
6941 * and the sizes and bounds of multidimensional arrays.
6943 MonoArrayType*
6944 mono_type_get_array_type (MonoType *type)
6946 return type->data.array;
6950 * mono_type_get_ptr_type:
6951 * \pararm type the \c MonoType operated on
6952 * It is only valid to call this function if \p type is a \c MONO_TYPE_PTR .
6953 * \returns the \c MonoType pointer that describes the type that \p type
6954 * represents a pointer to.
6956 MonoType*
6957 mono_type_get_ptr_type (MonoType *type)
6959 g_assert (type->type == MONO_TYPE_PTR);
6960 return type->data.type;
6964 * mono_type_get_modifiers:
6966 MonoClass*
6967 mono_type_get_modifiers (MonoType *type, gboolean *is_required, gpointer *iter)
6969 /* FIXME: implement */
6970 return NULL;
6974 * mono_type_is_struct:
6975 * \param type the \c MonoType operated on
6976 * \returns TRUE if \p type is a struct, that is a \c ValueType but not an enum
6977 * or a basic type like \c System.Int32 . FALSE otherwise.
6979 mono_bool
6980 mono_type_is_struct (MonoType *type)
6982 return (!type->byref && ((type->type == MONO_TYPE_VALUETYPE &&
6983 !m_class_is_enumtype (type->data.klass)) || (type->type == MONO_TYPE_TYPEDBYREF) ||
6984 ((type->type == MONO_TYPE_GENERICINST) &&
6985 mono_metadata_generic_class_is_valuetype (type->data.generic_class) &&
6986 !m_class_is_enumtype (type->data.generic_class->container_class))));
6990 * mono_type_is_void:
6991 * \param type the \c MonoType operated on
6992 * \returns TRUE if \p type is \c System.Void . FALSE otherwise.
6994 mono_bool
6995 mono_type_is_void (MonoType *type)
6997 return (type && (type->type == MONO_TYPE_VOID) && !type->byref);
7001 * mono_type_is_pointer:
7002 * \param type the \c MonoType operated on
7003 * \returns TRUE if \p type is a managed or unmanaged pointer type. FALSE otherwise.
7005 mono_bool
7006 mono_type_is_pointer (MonoType *type)
7008 return (type && ((type->byref || (type->type == MONO_TYPE_I) || type->type == MONO_TYPE_STRING)
7009 || (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
7010 (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_OBJECT) ||
7011 (type->type == MONO_TYPE_ARRAY) || (type->type == MONO_TYPE_PTR) ||
7012 (type->type == MONO_TYPE_FNPTR)));
7016 * mono_type_is_reference:
7017 * \param type the \c MonoType operated on
7018 * \returns TRUE if \p type represents an object reference. FALSE otherwise.
7020 mono_bool
7021 mono_type_is_reference (MonoType *type)
7023 return (type && (((type->type == MONO_TYPE_STRING) ||
7024 (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
7025 (type->type == MONO_TYPE_OBJECT) || (type->type == MONO_TYPE_ARRAY)) ||
7026 ((type->type == MONO_TYPE_GENERICINST) &&
7027 !mono_metadata_generic_class_is_valuetype (type->data.generic_class))));
7030 mono_bool
7031 mono_type_is_generic_parameter (MonoType *type)
7033 return !type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR);
7037 * mono_signature_get_return_type:
7038 * \param sig the method signature inspected
7039 * \returns the return type of the method signature \p sig
7041 MonoType*
7042 mono_signature_get_return_type (MonoMethodSignature *sig)
7044 MonoType *result;
7045 MONO_ENTER_GC_UNSAFE;
7046 result = sig->ret;
7047 MONO_EXIT_GC_UNSAFE;
7048 return result;
7052 * mono_signature_get_params:
7053 * \param sig the method signature inspected
7054 * \param iter pointer to an iterator
7055 * Iterates over the parameters for the method signature \p sig.
7056 * A \c void* pointer must be initialized to NULL to start the iteration
7057 * and its address is passed to this function repeteadly until it returns
7058 * NULL.
7059 * \returns the next parameter type of the method signature \p sig,
7060 * NULL when finished.
7062 MonoType*
7063 mono_signature_get_params (MonoMethodSignature *sig, gpointer *iter)
7065 MonoType *result;
7066 MONO_ENTER_GC_UNSAFE;
7067 result = mono_signature_get_params_internal (sig, iter);
7068 MONO_EXIT_GC_UNSAFE;
7069 return result;
7072 MonoType*
7073 mono_signature_get_params_internal (MonoMethodSignature *sig, gpointer *iter)
7075 MonoType** type;
7076 if (!iter)
7077 return NULL;
7078 if (!*iter) {
7079 /* start from the first */
7080 if (sig->param_count) {
7081 *iter = &sig->params [0];
7082 return sig->params [0];
7083 } else {
7084 /* no method */
7085 return NULL;
7088 type = (MonoType **)*iter;
7089 type++;
7090 if (type < &sig->params [sig->param_count]) {
7091 *iter = type;
7092 return *type;
7094 return NULL;
7098 * mono_signature_get_param_count:
7099 * \param sig the method signature inspected
7100 * \returns the number of parameters in the method signature \p sig.
7102 guint32
7103 mono_signature_get_param_count (MonoMethodSignature *sig)
7105 return sig->param_count;
7109 * mono_signature_get_call_conv:
7110 * \param sig the method signature inspected
7111 * \returns the call convention of the method signature \p sig.
7113 guint32
7114 mono_signature_get_call_conv (MonoMethodSignature *sig)
7116 return sig->call_convention;
7120 * mono_signature_vararg_start:
7121 * \param sig the method signature inspected
7122 * \returns the number of the first vararg parameter in the
7123 * method signature \param sig. \c -1 if this is not a vararg signature.
7126 mono_signature_vararg_start (MonoMethodSignature *sig)
7128 return sig->sentinelpos;
7132 * mono_signature_is_instance:
7133 * \param sig the method signature inspected
7134 * \returns TRUE if this the method signature \p sig has an implicit
7135 * first instance argument. FALSE otherwise.
7137 gboolean
7138 mono_signature_is_instance (MonoMethodSignature *sig)
7140 return sig->hasthis;
7144 * mono_signature_param_is_out
7145 * \param sig the method signature inspected
7146 * \param param_num the 0-based index of the inspected parameter
7147 * \returns TRUE if the parameter is an out parameter, FALSE
7148 * otherwise.
7150 mono_bool
7151 mono_signature_param_is_out (MonoMethodSignature *sig, int param_num)
7153 g_assert (param_num >= 0 && param_num < sig->param_count);
7154 return (sig->params [param_num]->attrs & PARAM_ATTRIBUTE_OUT) != 0;
7158 * mono_signature_explicit_this:
7159 * \param sig the method signature inspected
7160 * \returns TRUE if this the method signature \p sig has an explicit
7161 * instance argument. FALSE otherwise.
7163 gboolean
7164 mono_signature_explicit_this (MonoMethodSignature *sig)
7166 return sig->explicit_this;
7169 /* for use with allocated memory blocks (assumes alignment is to 8 bytes) */
7170 guint
7171 mono_aligned_addr_hash (gconstpointer ptr)
7173 /* Same hashing we use for objects */
7174 return (GPOINTER_TO_UINT (ptr) >> 3) * 2654435761u;
7178 * If @field belongs to an inflated generic class, return the corresponding field of the
7179 * generic type definition class.
7181 MonoClassField*
7182 mono_metadata_get_corresponding_field_from_generic_type_definition (MonoClassField *field)
7184 MonoClass *gtd;
7185 int offset;
7187 if (!mono_class_is_ginst (field->parent))
7188 return field;
7190 gtd = mono_class_get_generic_class (field->parent)->container_class;
7191 offset = field - m_class_get_fields (field->parent);
7192 return m_class_get_fields (gtd) + offset;
7196 * If @event belongs to an inflated generic class, return the corresponding event of the
7197 * generic type definition class.
7199 MonoEvent*
7200 mono_metadata_get_corresponding_event_from_generic_type_definition (MonoEvent *event)
7202 MonoClass *gtd;
7203 int offset;
7205 if (!mono_class_is_ginst (event->parent))
7206 return event;
7208 gtd = mono_class_get_generic_class (event->parent)->container_class;
7209 offset = event - mono_class_get_event_info (event->parent)->events;
7210 return mono_class_get_event_info (gtd)->events + offset;
7214 * If @property belongs to an inflated generic class, return the corresponding property of the
7215 * generic type definition class.
7217 MonoProperty*
7218 mono_metadata_get_corresponding_property_from_generic_type_definition (MonoProperty *property)
7220 MonoClassPropertyInfo *info;
7221 MonoClass *gtd;
7222 int offset;
7224 if (!mono_class_is_ginst (property->parent))
7225 return property;
7227 info = mono_class_get_property_info (property->parent);
7228 gtd = mono_class_get_generic_class (property->parent)->container_class;
7229 offset = property - info->properties;
7230 return mono_class_get_property_info (gtd)->properties + offset;
7233 MonoWrapperCaches*
7234 mono_method_get_wrapper_cache (MonoMethod *method)
7236 if (method->is_inflated) {
7237 MonoMethodInflated *imethod = (MonoMethodInflated *)method;
7238 return &imethod->owner->wrapper_caches;
7239 } else {
7240 return &m_class_get_image (method->klass)->wrapper_caches;
7244 // 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.
7247 * mono_find_image_set_owner:
7249 * Find the imageset, if any, which a given pointer is located in the memory of.
7251 MonoImageSet *
7252 mono_find_image_set_owner (void *ptr)
7254 MonoImageSet *owner = NULL;
7255 int i;
7257 image_sets_lock ();
7259 if (image_sets)
7261 for (i = 0; !owner && i < image_sets->len; ++i) {
7262 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
7263 if (mono_mempool_contains_addr (set->mempool, ptr))
7264 owner = set;
7268 image_sets_unlock ();
7270 return owner;
7273 void
7274 mono_loader_set_strict_strong_names (gboolean enabled)
7276 check_strong_names_strictly = enabled;
7279 gboolean
7280 mono_loader_get_strict_strong_names (void)
7282 return check_strong_names_strictly;
7286 MonoCustomModContainer *
7287 mono_type_get_cmods (const MonoType *t)
7289 if (!t->has_cmods)
7290 return NULL;
7292 MonoTypeWithModifiers *full = (MonoTypeWithModifiers *)t;
7294 return &full->cmods;
7297 size_t
7298 mono_sizeof_type_with_mods (uint8_t num_mods)
7300 size_t accum = 0;
7301 accum += sizeof (MonoType);
7302 if (num_mods == 0)
7303 return accum;
7305 accum += offsetof (struct _MonoCustomModContainer, modifiers);
7306 accum += sizeof (MonoCustomMod) * num_mods;
7307 return accum;
7310 size_t
7311 mono_sizeof_type (const MonoType *ty)
7313 MonoCustomModContainer *cmods = mono_type_get_cmods (ty);
7314 if (cmods)
7315 return mono_sizeof_type_with_mods (cmods->count);
7316 else
7317 return sizeof (MonoType);