1 /**
2 * \file
3 * Routines for accessing the metadata
4 *
5 * Authors:
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
8 *
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.
12 */
13
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/utils/mono-error-internals.h>
32 #include <mono/utils/bsearch.h>
33 #include <mono/utils/atomic.h>
34 #include <mono/utils/unlocked.h>
35 #include <mono/utils/mono-counters.h>
36
37 static gint32 img_set_cache_hit, img_set_cache_miss, img_set_count;
38
39
40 /* Auxiliary structure used for caching inflated signatures */
41 typedef struct {
42 MonoMethodSignature *sig;
43 MonoGenericContext context;
44 } MonoInflatedMethodSignature;
45
46 static gboolean do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container, gboolean transient,
47 const char *ptr, const char **rptr, MonoError *error);
48
49 static gboolean do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only);
50 static gboolean mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only);
51 static gboolean mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only);
52 static gboolean _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2,
53 gboolean signature_only);
54 static void free_generic_inst (MonoGenericInst *ginst);
55 static void free_generic_class (MonoGenericClass *ginst);
56 static void free_inflated_method (MonoMethodInflated *method);
57 static void free_inflated_signature (MonoInflatedMethodSignature *sig);
58 static void mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva, MonoMarshalSpec **marshal_spec, gboolean alloc_from_image);
59
60 /*
61 * This enumeration is used to describe the data types in the metadata
62 * tables
63 */
64 enum {
65 MONO_MT_END,
66
67 /* Sized elements */
68 MONO_MT_UINT32,
69 MONO_MT_UINT16,
70 MONO_MT_UINT8,
71
72 /* Index into Blob heap */
73 MONO_MT_BLOB_IDX,
74
75 /* Index into String heap */
76 MONO_MT_STRING_IDX,
77
78 /* GUID index */
79 MONO_MT_GUID_IDX,
80
81 /* Pointer into a table */
82 MONO_MT_TABLE_IDX,
83
84 /* HasConstant:Parent pointer (Param, Field or Property) */
85 MONO_MT_CONST_IDX,
86
87 /* HasCustomAttribute index. Indexes any table except CustomAttribute */
88 MONO_MT_HASCAT_IDX,
89
90 /* CustomAttributeType encoded index */
91 MONO_MT_CAT_IDX,
92
93 /* HasDeclSecurity index: TypeDef Method or Assembly */
94 MONO_MT_HASDEC_IDX,
95
96 /* Implementation coded index: File, Export AssemblyRef */
97 MONO_MT_IMPL_IDX,
98
99 /* HasFieldMarshal coded index: Field or Param table */
100 MONO_MT_HFM_IDX,
101
102 /* MemberForwardedIndex: Field or Method */
103 MONO_MT_MF_IDX,
104
105 /* TypeDefOrRef coded index: typedef, typeref, typespec */
106 MONO_MT_TDOR_IDX,
107
108 /* MemberRefParent coded index: typeref, moduleref, method, memberref, typesepc, typedef */
109 MONO_MT_MRP_IDX,
110
111 /* MethodDefOrRef coded index: Method or Member Ref table */
112 MONO_MT_MDOR_IDX,
113
114 /* HasSemantic coded index: Event or Property */
115 MONO_MT_HS_IDX,
116
117 /* ResolutionScope coded index: Module, ModuleRef, AssemblytRef, TypeRef */
118 MONO_MT_RS_IDX,
119
120 /* CustomDebugInformation parent encoded index */
121 MONO_MT_HASCUSTDEBUG_IDX
122 };
123
124 const static unsigned char TableSchemas [] = {
125 #define ASSEMBLY_SCHEMA_OFFSET 0
126 MONO_MT_UINT32, /* "HashId" }, */
127 MONO_MT_UINT16, /* "Major" }, */
128 MONO_MT_UINT16, /* "Minor" }, */
129 MONO_MT_UINT16, /* "BuildNumber" }, */
130 MONO_MT_UINT16, /* "RevisionNumber" }, */
131 MONO_MT_UINT32, /* "Flags" }, */
132 MONO_MT_BLOB_IDX, /* "PublicKey" }, */
133 MONO_MT_STRING_IDX, /* "Name" }, */
134 MONO_MT_STRING_IDX, /* "Culture" }, */
135 MONO_MT_END,
136
137 #define ASSEMBLYOS_SCHEMA_OFFSET ASSEMBLY_SCHEMA_OFFSET + 10
138 MONO_MT_UINT32, /* "OSPlatformID" }, */
139 MONO_MT_UINT32, /* "OSMajor" }, */
140 MONO_MT_UINT32, /* "OSMinor" }, */
141 MONO_MT_END,
142
143 #define ASSEMBLYPROC_SCHEMA_OFFSET ASSEMBLYOS_SCHEMA_OFFSET + 4
144 MONO_MT_UINT32, /* "Processor" }, */
145 MONO_MT_END,
146
147 #define ASSEMBLYREF_SCHEMA_OFFSET ASSEMBLYPROC_SCHEMA_OFFSET + 2
148 MONO_MT_UINT16, /* "Major" }, */
149 MONO_MT_UINT16, /* "Minor" }, */
150 MONO_MT_UINT16, /* "Build" }, */
151 MONO_MT_UINT16, /* "Revision" }, */
152 MONO_MT_UINT32, /* "Flags" }, */
153 MONO_MT_BLOB_IDX, /* "PublicKeyOrToken" }, */
154 MONO_MT_STRING_IDX, /* "Name" }, */
155 MONO_MT_STRING_IDX, /* "Culture" }, */
156 MONO_MT_BLOB_IDX, /* "HashValue" }, */
157 MONO_MT_END,
158
159 #define ASSEMBLYREFOS_SCHEMA_OFFSET ASSEMBLYREF_SCHEMA_OFFSET + 10
160 MONO_MT_UINT32, /* "OSPlatformID" }, */
161 MONO_MT_UINT32, /* "OSMajorVersion" }, */
162 MONO_MT_UINT32, /* "OSMinorVersion" }, */
163 MONO_MT_TABLE_IDX, /* "AssemblyRef:AssemblyRef" }, */
164 MONO_MT_END,
165
166 #define ASSEMBLYREFPROC_SCHEMA_OFFSET ASSEMBLYREFOS_SCHEMA_OFFSET + 5
167 MONO_MT_UINT32, /* "Processor" }, */
168 MONO_MT_TABLE_IDX, /* "AssemblyRef:AssemblyRef" }, */
169 MONO_MT_END,
170
171 #define CLASS_LAYOUT_SCHEMA_OFFSET ASSEMBLYREFPROC_SCHEMA_OFFSET + 3
172 MONO_MT_UINT16, /* "PackingSize" }, */
173 MONO_MT_UINT32, /* "ClassSize" }, */
174 MONO_MT_TABLE_IDX, /* "Parent:TypeDef" }, */
175 MONO_MT_END,
176
177 #define CONSTANT_SCHEMA_OFFSET CLASS_LAYOUT_SCHEMA_OFFSET + 4
178 MONO_MT_UINT8, /* "Type" }, */
179 MONO_MT_UINT8, /* "PaddingZero" }, */
180 MONO_MT_CONST_IDX, /* "Parent" }, */
181 MONO_MT_BLOB_IDX, /* "Value" }, */
182 MONO_MT_END,
183
184 #define CUSTOM_ATTR_SCHEMA_OFFSET CONSTANT_SCHEMA_OFFSET + 5
185 MONO_MT_HASCAT_IDX, /* "Parent" }, */
186 MONO_MT_CAT_IDX, /* "Type" }, */
187 MONO_MT_BLOB_IDX, /* "Value" }, */
188 MONO_MT_END,
189
190 #define DECL_SEC_SCHEMA_OFFSET CUSTOM_ATTR_SCHEMA_OFFSET + 4
191 MONO_MT_UINT16, /* "Action" }, */
192 MONO_MT_HASDEC_IDX, /* "Parent" }, */
193 MONO_MT_BLOB_IDX, /* "PermissionSet" }, */
194 MONO_MT_END,
195
196 #define EVENTMAP_SCHEMA_OFFSET DECL_SEC_SCHEMA_OFFSET + 4
197 MONO_MT_TABLE_IDX, /* "Parent:TypeDef" }, */
198 MONO_MT_TABLE_IDX, /* "EventList:Event" }, */
199 MONO_MT_END,
200
201 #define EVENT_SCHEMA_OFFSET EVENTMAP_SCHEMA_OFFSET + 3
202 MONO_MT_UINT16, /* "EventFlags#EventAttribute" }, */
203 MONO_MT_STRING_IDX, /* "Name" }, */
204 MONO_MT_TDOR_IDX, /* "EventType" }, TypeDef or TypeRef or TypeSpec */
205 MONO_MT_END,
206
207 #define EVENT_POINTER_SCHEMA_OFFSET EVENT_SCHEMA_OFFSET + 4
208 MONO_MT_TABLE_IDX, /* "Event" }, */
209 MONO_MT_END,
210
211 #define EXPORTED_TYPE_SCHEMA_OFFSET EVENT_POINTER_SCHEMA_OFFSET + 2
212 MONO_MT_UINT32, /* "Flags" }, */
213 MONO_MT_TABLE_IDX, /* "TypeDefId" }, */
214 MONO_MT_STRING_IDX, /* "TypeName" }, */
215 MONO_MT_STRING_IDX, /* "TypeNameSpace" }, */
216 MONO_MT_IMPL_IDX, /* "Implementation" }, */
217 MONO_MT_END,
218
219 #define FIELD_SCHEMA_OFFSET EXPORTED_TYPE_SCHEMA_OFFSET + 6
220 MONO_MT_UINT16, /* "Flags" }, */
221 MONO_MT_STRING_IDX, /* "Name" }, */
222 MONO_MT_BLOB_IDX, /* "Signature" }, */
223 MONO_MT_END,
224
225 #define FIELD_LAYOUT_SCHEMA_OFFSET FIELD_SCHEMA_OFFSET + 4
226 MONO_MT_UINT32, /* "Offset" }, */
227 MONO_MT_TABLE_IDX, /* "Field:Field" }, */
228 MONO_MT_END,
229
230 #define FIELD_MARSHAL_SCHEMA_OFFSET FIELD_LAYOUT_SCHEMA_OFFSET + 3
231 MONO_MT_HFM_IDX, /* "Parent" }, */
232 MONO_MT_BLOB_IDX, /* "NativeType" }, */
233 MONO_MT_END,
234
235 #define FIELD_RVA_SCHEMA_OFFSET FIELD_MARSHAL_SCHEMA_OFFSET + 3
236 MONO_MT_UINT32, /* "RVA" }, */
237 MONO_MT_TABLE_IDX, /* "Field:Field" }, */
238 MONO_MT_END,
239
240 #define FIELD_POINTER_SCHEMA_OFFSET FIELD_RVA_SCHEMA_OFFSET + 3
241 MONO_MT_TABLE_IDX, /* "Field" }, */
242 MONO_MT_END,
243
244 #define FILE_SCHEMA_OFFSET FIELD_POINTER_SCHEMA_OFFSET + 2
245 MONO_MT_UINT32, /* "Flags" }, */
246 MONO_MT_STRING_IDX, /* "Name" }, */
247 MONO_MT_BLOB_IDX, /* "Value" }, */
248 MONO_MT_END,
249
250 #define IMPLMAP_SCHEMA_OFFSET FILE_SCHEMA_OFFSET + 4
251 MONO_MT_UINT16, /* "MappingFlag" }, */
252 MONO_MT_MF_IDX, /* "MemberForwarded" }, */
253 MONO_MT_STRING_IDX, /* "ImportName" }, */
254 MONO_MT_TABLE_IDX, /* "ImportScope:ModuleRef" }, */
255 MONO_MT_END,
256
257 #define IFACEMAP_SCHEMA_OFFSET IMPLMAP_SCHEMA_OFFSET + 5
258 MONO_MT_TABLE_IDX, /* "Class:TypeDef" }, */
259 MONO_MT_TDOR_IDX, /* "Interface=TypeDefOrRef" }, */
260 MONO_MT_END,
261
262 #define MANIFEST_SCHEMA_OFFSET IFACEMAP_SCHEMA_OFFSET + 3
263 MONO_MT_UINT32, /* "Offset" }, */
264 MONO_MT_UINT32, /* "Flags" }, */
265 MONO_MT_STRING_IDX, /* "Name" }, */
266 MONO_MT_IMPL_IDX, /* "Implementation" }, */
267 MONO_MT_END,
268
269 #define MEMBERREF_SCHEMA_OFFSET MANIFEST_SCHEMA_OFFSET + 5
270 MONO_MT_MRP_IDX, /* "Class" }, */
271 MONO_MT_STRING_IDX, /* "Name" }, */
272 MONO_MT_BLOB_IDX, /* "Signature" }, */
273 MONO_MT_END,
274
275 #define METHOD_SCHEMA_OFFSET MEMBERREF_SCHEMA_OFFSET + 4
276 MONO_MT_UINT32, /* "RVA" }, */
277 MONO_MT_UINT16, /* "ImplFlags#MethodImplAttributes" }, */
278 MONO_MT_UINT16, /* "Flags#MethodAttribute" }, */
279 MONO_MT_STRING_IDX, /* "Name" }, */
280 MONO_MT_BLOB_IDX, /* "Signature" }, */
281 MONO_MT_TABLE_IDX, /* "ParamList:Param" }, */
282 MONO_MT_END,
283
284 #define METHOD_IMPL_SCHEMA_OFFSET METHOD_SCHEMA_OFFSET + 7
285 MONO_MT_TABLE_IDX, /* "Class:TypeDef" }, */
286 MONO_MT_MDOR_IDX, /* "MethodBody" }, */
287 MONO_MT_MDOR_IDX, /* "MethodDeclaration" }, */
288 MONO_MT_END,
289
290 #define METHOD_SEMA_SCHEMA_OFFSET METHOD_IMPL_SCHEMA_OFFSET + 4
291 MONO_MT_UINT16, /* "MethodSemantic" }, */
292 MONO_MT_TABLE_IDX, /* "Method:Method" }, */
293 MONO_MT_HS_IDX, /* "Association" }, */
294 MONO_MT_END,
295
296 #define METHOD_POINTER_SCHEMA_OFFSET METHOD_SEMA_SCHEMA_OFFSET + 4
297 MONO_MT_TABLE_IDX, /* "Method" }, */
298 MONO_MT_END,
299
300 #define MODULE_SCHEMA_OFFSET METHOD_POINTER_SCHEMA_OFFSET + 2
301 MONO_MT_UINT16, /* "Generation" }, */
302 MONO_MT_STRING_IDX, /* "Name" }, */
303 MONO_MT_GUID_IDX, /* "MVID" }, */
304 MONO_MT_GUID_IDX, /* "EncID" }, */
305 MONO_MT_GUID_IDX, /* "EncBaseID" }, */
306 MONO_MT_END,
307
308 #define MODULEREF_SCHEMA_OFFSET MODULE_SCHEMA_OFFSET + 6
309 MONO_MT_STRING_IDX, /* "Name" }, */
310 MONO_MT_END,
311
312 #define NESTED_CLASS_SCHEMA_OFFSET MODULEREF_SCHEMA_OFFSET + 2
313 MONO_MT_TABLE_IDX, /* "NestedClass:TypeDef" }, */
314 MONO_MT_TABLE_IDX, /* "EnclosingClass:TypeDef" }, */
315 MONO_MT_END,
316
317 #define PARAM_SCHEMA_OFFSET NESTED_CLASS_SCHEMA_OFFSET + 3
318 MONO_MT_UINT16, /* "Flags" }, */
319 MONO_MT_UINT16, /* "Sequence" }, */
320 MONO_MT_STRING_IDX, /* "Name" }, */
321 MONO_MT_END,
322
323 #define PARAM_POINTER_SCHEMA_OFFSET PARAM_SCHEMA_OFFSET + 4
324 MONO_MT_TABLE_IDX, /* "Param" }, */
325 MONO_MT_END,
326
327 #define PROPERTY_SCHEMA_OFFSET PARAM_POINTER_SCHEMA_OFFSET + 2
328 MONO_MT_UINT16, /* "Flags" }, */
329 MONO_MT_STRING_IDX, /* "Name" }, */
330 MONO_MT_BLOB_IDX, /* "Type" }, */
331 MONO_MT_END,
332
333 #define PROPERTY_POINTER_SCHEMA_OFFSET PROPERTY_SCHEMA_OFFSET + 4
334 MONO_MT_TABLE_IDX, /* "Property" }, */
335 MONO_MT_END,
336
337 #define PROPERTY_MAP_SCHEMA_OFFSET PROPERTY_POINTER_SCHEMA_OFFSET + 2
338 MONO_MT_TABLE_IDX, /* "Parent:TypeDef" }, */
339 MONO_MT_TABLE_IDX, /* "PropertyList:Property" }, */
340 MONO_MT_END,
341
342 #define STDALON_SIG_SCHEMA_OFFSET PROPERTY_MAP_SCHEMA_OFFSET + 3
343 MONO_MT_BLOB_IDX, /* "Signature" }, */
344 MONO_MT_END,
345
346 #define TYPEDEF_SCHEMA_OFFSET STDALON_SIG_SCHEMA_OFFSET + 2
347 MONO_MT_UINT32, /* "Flags" }, */
348 MONO_MT_STRING_IDX, /* "Name" }, */
349 MONO_MT_STRING_IDX, /* "Namespace" }, */
350 MONO_MT_TDOR_IDX, /* "Extends" }, */
351 MONO_MT_TABLE_IDX, /* "FieldList:Field" }, */
352 MONO_MT_TABLE_IDX, /* "MethodList:Method" }, */
353 MONO_MT_END,
354
355 #define TYPEREF_SCHEMA_OFFSET TYPEDEF_SCHEMA_OFFSET + 7
356 MONO_MT_RS_IDX, /* "ResolutionScope=ResolutionScope" }, */
357 MONO_MT_STRING_IDX, /* "Name" }, */
358 MONO_MT_STRING_IDX, /* "Namespace" }, */
359 MONO_MT_END,
360
361 #define TYPESPEC_SCHEMA_OFFSET TYPEREF_SCHEMA_OFFSET + 4
362 MONO_MT_BLOB_IDX, /* "Signature" }, */
363 MONO_MT_END,
364
365 #define GENPARAM_SCHEMA_OFFSET TYPESPEC_SCHEMA_OFFSET + 2
366 MONO_MT_UINT16, /* "Number" }, */
367 MONO_MT_UINT16, /* "Flags" }, */
368 MONO_MT_TABLE_IDX, /* "Owner" }, TypeDef or MethodDef */
369 MONO_MT_STRING_IDX, /* "Name" }, */
370 MONO_MT_END,
371
372 #define METHOD_SPEC_SCHEMA_OFFSET GENPARAM_SCHEMA_OFFSET + 5
373 MONO_MT_MDOR_IDX, /* "Method" }, */
374 MONO_MT_BLOB_IDX, /* "Signature" }, */
375 MONO_MT_END,
376
377 #define GEN_CONSTRAINT_SCHEMA_OFFSET METHOD_SPEC_SCHEMA_OFFSET + 3
378 MONO_MT_TABLE_IDX, /* "GenericParam" }, */
379 MONO_MT_TDOR_IDX, /* "Constraint" }, */
380 MONO_MT_END,
381
382 #define DOCUMENT_SCHEMA_OFFSET GEN_CONSTRAINT_SCHEMA_OFFSET + 3
383 MONO_MT_BLOB_IDX, /* Name */
384 MONO_MT_GUID_IDX, /* HashAlgorithm */
385 MONO_MT_BLOB_IDX, /* Hash */
386 MONO_MT_GUID_IDX, /* Language */
387 MONO_MT_END,
388
389 #define METHODBODY_SCHEMA_OFFSET DOCUMENT_SCHEMA_OFFSET + 5
390 MONO_MT_TABLE_IDX, /* Document */
391 MONO_MT_BLOB_IDX, /* SequencePoints */
392 MONO_MT_END,
393
394 #define LOCALSCOPE_SCHEMA_OFFSET METHODBODY_SCHEMA_OFFSET + 3
395 MONO_MT_TABLE_IDX, /* Method */
396 MONO_MT_TABLE_IDX, /* ImportScope */
397 MONO_MT_TABLE_IDX, /* VariableList */
398 MONO_MT_TABLE_IDX, /* ConstantList */
399 MONO_MT_UINT32, /* StartOffset */
400 MONO_MT_UINT32, /* Length */
401 MONO_MT_END,
402
403 #define LOCALVARIABLE_SCHEMA_OFFSET LOCALSCOPE_SCHEMA_OFFSET + 7
404 MONO_MT_UINT16, /* Attributes */
405 MONO_MT_UINT16, /* Index */
406 MONO_MT_STRING_IDX, /* Name */
407 MONO_MT_END,
408
409 #define LOCALCONSTANT_SCHEMA_OFFSET LOCALVARIABLE_SCHEMA_OFFSET + 4
410 MONO_MT_STRING_IDX, /* Name (String heap index) */
411 MONO_MT_BLOB_IDX, /* Signature (Blob heap index, LocalConstantSig blob) */
412 MONO_MT_END,
413
414 #define IMPORTSCOPE_SCHEMA_OFFSET LOCALCONSTANT_SCHEMA_OFFSET + 3
415 MONO_MT_TABLE_IDX, /* Parent (ImportScope row id or nil) */
416 MONO_MT_BLOB_IDX, /* Imports (Blob index, encoding: Imports blob) */
417 MONO_MT_END,
418
419 #define ASYNCMETHOD_SCHEMA_OFFSET IMPORTSCOPE_SCHEMA_OFFSET + 3
420 MONO_MT_TABLE_IDX, /* MoveNextMethod (MethodDef row id) */
421 MONO_MT_TABLE_IDX, /* KickoffMethod (MethodDef row id) */
422 MONO_MT_END,
423
424 #define CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET ASYNCMETHOD_SCHEMA_OFFSET + 3
425 MONO_MT_HASCUSTDEBUG_IDX, /* Parent (HasCustomDebugInformation coded index) */
426 MONO_MT_GUID_IDX, /* Kind (Guid heap index) */
427 MONO_MT_BLOB_IDX, /* Value (Blob heap index) */
428 MONO_MT_END,
429
430 #define NULL_SCHEMA_OFFSET CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET + 4
431 MONO_MT_END
432 };
433
434 /* Must be the same order as MONO_TABLE_* */
435 const static unsigned char
436 table_description [] = {
437 MODULE_SCHEMA_OFFSET,
438 TYPEREF_SCHEMA_OFFSET,
439 TYPEDEF_SCHEMA_OFFSET,
440 FIELD_POINTER_SCHEMA_OFFSET,
441 FIELD_SCHEMA_OFFSET,
442 METHOD_POINTER_SCHEMA_OFFSET,
443 METHOD_SCHEMA_OFFSET,
444 PARAM_POINTER_SCHEMA_OFFSET,
445 PARAM_SCHEMA_OFFSET,
446 IFACEMAP_SCHEMA_OFFSET,
447 MEMBERREF_SCHEMA_OFFSET, /* 0xa */
448 CONSTANT_SCHEMA_OFFSET,
449 CUSTOM_ATTR_SCHEMA_OFFSET,
450 FIELD_MARSHAL_SCHEMA_OFFSET,
451 DECL_SEC_SCHEMA_OFFSET,
452 CLASS_LAYOUT_SCHEMA_OFFSET,
453 FIELD_LAYOUT_SCHEMA_OFFSET, /* 0x10 */
454 STDALON_SIG_SCHEMA_OFFSET,
455 EVENTMAP_SCHEMA_OFFSET,
456 EVENT_POINTER_SCHEMA_OFFSET,
457 EVENT_SCHEMA_OFFSET,
458 PROPERTY_MAP_SCHEMA_OFFSET,
459 PROPERTY_POINTER_SCHEMA_OFFSET,
460 PROPERTY_SCHEMA_OFFSET,
461 METHOD_SEMA_SCHEMA_OFFSET,
462 METHOD_IMPL_SCHEMA_OFFSET,
463 MODULEREF_SCHEMA_OFFSET, /* 0x1a */
464 TYPESPEC_SCHEMA_OFFSET,
465 IMPLMAP_SCHEMA_OFFSET,
466 FIELD_RVA_SCHEMA_OFFSET,
467 NULL_SCHEMA_OFFSET,
468 NULL_SCHEMA_OFFSET,
469 ASSEMBLY_SCHEMA_OFFSET, /* 0x20 */
470 ASSEMBLYPROC_SCHEMA_OFFSET,
471 ASSEMBLYOS_SCHEMA_OFFSET,
472 ASSEMBLYREF_SCHEMA_OFFSET,
473 ASSEMBLYREFPROC_SCHEMA_OFFSET,
474 ASSEMBLYREFOS_SCHEMA_OFFSET,
475 FILE_SCHEMA_OFFSET,
476 EXPORTED_TYPE_SCHEMA_OFFSET,
477 MANIFEST_SCHEMA_OFFSET,
478 NESTED_CLASS_SCHEMA_OFFSET,
479 GENPARAM_SCHEMA_OFFSET, /* 0x2a */
480 METHOD_SPEC_SCHEMA_OFFSET,
481 GEN_CONSTRAINT_SCHEMA_OFFSET,
482 NULL_SCHEMA_OFFSET,
483 NULL_SCHEMA_OFFSET,
484 NULL_SCHEMA_OFFSET,
485 DOCUMENT_SCHEMA_OFFSET, /* 0x30 */
486 METHODBODY_SCHEMA_OFFSET,
487 LOCALSCOPE_SCHEMA_OFFSET,
488 LOCALVARIABLE_SCHEMA_OFFSET,
489 LOCALCONSTANT_SCHEMA_OFFSET,
490 IMPORTSCOPE_SCHEMA_OFFSET,
491 ASYNCMETHOD_SCHEMA_OFFSET,
492 CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET
493 };
494
495 #ifdef HAVE_ARRAY_ELEM_INIT
496 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
497 #define MSGSTRFIELD1(line) str##line
498 static const struct msgstr_t {
499 #define TABLEDEF(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
500 #include "mono/cil/tables.def"
501 #undef TABLEDEF
502 } tablestr = {
503 #define TABLEDEF(a,b) b,
504 #include "mono/cil/tables.def"
505 #undef TABLEDEF
506 };
507 static const gint16 tableidx [] = {
508 #define TABLEDEF(a,b) [a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
509 #include "mono/cil/tables.def"
510 #undef TABLEDEF
511 };
512
513 #else
514 #define TABLEDEF(a,b) b,
515 static const char* const
516 mono_tables_names [] = {
517 #include "mono/cil/tables.def"
518 NULL
519 };
520
521 #endif
522
523 /* If TRUE (but also see DISABLE_STICT_STRONG_NAMES #define), Mono will check
524 * that the public key token, culture and version of a candidate assembly matches
525 * the requested strong name. If FALSE, as long as the name matches, the candidate
526 * will be allowed.
527 */
528 static gboolean check_strong_names_strictly = FALSE;
529
530 // Amount initially reserved in each imageset's mempool.
531 // FIXME: This number is arbitrary, a more practical number should be found
532 #define INITIAL_IMAGE_SET_SIZE 1024
533
534 /**
535 * mono_meta_table_name:
536 * \param table table index
537 *
538 * Returns the name of the given ECMA metadata logical format table
539 * as described in ECMA 335, Partition II, Section 22.
540 *
541 * \returns the name for the \p table index
542 */
543 const char *
mono_meta_table_name(int table)544 mono_meta_table_name (int table)
545 {
546 if ((table < 0) || (table > MONO_TABLE_LAST))
547 return "";
548
549 #ifdef HAVE_ARRAY_ELEM_INIT
550 return (const char*)&tablestr + tableidx [table];
551 #else
552 return mono_tables_names [table];
553 #endif
554 }
555
556 /* The guy who wrote the spec for this should not be allowed near a
557 * computer again.
558
559 If e is a coded token(see clause 23.1.7) that points into table ti out of n possible tables t0, .. tn-1,
560 then it is stored as e << (log n) & tag{ t0, .. tn-1}[ ti] using 2 bytes if the maximum number of
561 rows of tables t0, ..tn-1, is less than 2^16 - (log n), and using 4 bytes otherwise. The family of
562 finite maps tag{ t0, ..tn-1} is defined below. Note that to decode a physical row, you need the
563 inverse of this mapping.
564
565 */
566 #define rtsize(meta,s,b) (((s) < (1 << (b)) ? 2 : 4))
567
568 static inline int
idx_size(MonoImage * meta,int tableidx)569 idx_size (MonoImage *meta, int tableidx)
570 {
571 if (meta->referenced_tables && (meta->referenced_tables & ((guint64)1 << tableidx)))
572 return meta->referenced_table_rows [tableidx] < 65536 ? 2 : 4;
573 else
574 return meta->tables [tableidx].rows < 65536 ? 2 : 4;
575 }
576
577 static inline int
get_nrows(MonoImage * meta,int tableidx)578 get_nrows (MonoImage *meta, int tableidx)
579 {
580 if (meta->referenced_tables && (meta->referenced_tables & ((guint64)1 << tableidx)))
581 return meta->referenced_table_rows [tableidx];
582 else
583 return meta->tables [tableidx].rows;
584 }
585
586 /* Reference: Partition II - 23.2.6 */
587 /**
588 * mono_metadata_compute_size:
589 * \param meta metadata context
590 * \param tableindex metadata table number
591 * \param result_bitfield pointer to \c guint32 where to store additional info
592 *
593 * \c mono_metadata_compute_size computes the length in bytes of a single
594 * row in a metadata table. The size of each column is encoded in the
595 * \p result_bitfield return value along with the number of columns in the table.
596 * the resulting bitfield should be handed to the \c mono_metadata_table_size
597 * and \c mono_metadata_table_count macros.
598 * This is a Mono runtime internal only function.
599 */
600 int
mono_metadata_compute_size(MonoImage * meta,int tableindex,guint32 * result_bitfield)601 mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bitfield)
602 {
603 guint32 bitfield = 0;
604 int size = 0, field_size = 0;
605 int i, n, code;
606 int shift = 0;
607 const unsigned char *description = TableSchemas + table_description [tableindex];
608
609 for (i = 0; (code = description [i]) != MONO_MT_END; i++){
610 switch (code){
611 case MONO_MT_UINT32:
612 field_size = 4; break;
613
614 case MONO_MT_UINT16:
615 field_size = 2; break;
616
617 case MONO_MT_UINT8:
618 field_size = 1; break;
619
620 case MONO_MT_BLOB_IDX:
621 field_size = meta->idx_blob_wide ? 4 : 2; break;
622
623 case MONO_MT_STRING_IDX:
624 field_size = meta->idx_string_wide ? 4 : 2; break;
625
626 case MONO_MT_GUID_IDX:
627 field_size = meta->idx_guid_wide ? 4 : 2; break;
628
629 case MONO_MT_TABLE_IDX:
630 /* Uhm, a table index can point to other tables besides the current one
631 * so, it's not correct to use the rowcount of the current table to
632 * get the size for this column - lupus
633 */
634 switch (tableindex) {
635 case MONO_TABLE_ASSEMBLYREFOS:
636 g_assert (i == 3);
637 field_size = idx_size (meta, MONO_TABLE_ASSEMBLYREF); break;
638 case MONO_TABLE_ASSEMBLYREFPROCESSOR:
639 g_assert (i == 1);
640 field_size = idx_size (meta, MONO_TABLE_ASSEMBLYREF); break;
641 case MONO_TABLE_CLASSLAYOUT:
642 g_assert (i == 2);
643 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
644 case MONO_TABLE_EVENTMAP:
645 g_assert (i == 0 || i == 1);
646 field_size = i ? idx_size (meta, MONO_TABLE_EVENT):
647 idx_size (meta, MONO_TABLE_TYPEDEF);
648 break;
649 case MONO_TABLE_EVENT_POINTER:
650 g_assert (i == 0);
651 field_size = idx_size (meta, MONO_TABLE_EVENT); break;
652 case MONO_TABLE_EXPORTEDTYPE:
653 g_assert (i == 1);
654 /* the index is in another metadata file, so it must be 4 */
655 field_size = 4; break;
656 case MONO_TABLE_FIELDLAYOUT:
657 g_assert (i == 1);
658 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
659 case MONO_TABLE_FIELDRVA:
660 g_assert (i == 1);
661 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
662 case MONO_TABLE_FIELD_POINTER:
663 g_assert (i == 0);
664 field_size = idx_size (meta, MONO_TABLE_FIELD); break;
665 case MONO_TABLE_IMPLMAP:
666 g_assert (i == 3);
667 field_size = idx_size (meta, MONO_TABLE_MODULEREF); break;
668 case MONO_TABLE_INTERFACEIMPL:
669 g_assert (i == 0);
670 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
671 case MONO_TABLE_METHOD:
672 g_assert (i == 5);
673 field_size = idx_size (meta, MONO_TABLE_PARAM); break;
674 case MONO_TABLE_METHODIMPL:
675 g_assert (i == 0);
676 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
677 case MONO_TABLE_METHODSEMANTICS:
678 g_assert (i == 1);
679 field_size = idx_size (meta, MONO_TABLE_METHOD); break;
680 case MONO_TABLE_METHOD_POINTER:
681 g_assert (i == 0);
682 field_size = idx_size (meta, MONO_TABLE_METHOD); break;
683 case MONO_TABLE_NESTEDCLASS:
684 g_assert (i == 0 || i == 1);
685 field_size = idx_size (meta, MONO_TABLE_TYPEDEF); break;
686 case MONO_TABLE_PARAM_POINTER:
687 g_assert (i == 0);
688 field_size = idx_size (meta, MONO_TABLE_PARAM); break;
689 case MONO_TABLE_PROPERTYMAP:
690 g_assert (i == 0 || i == 1);
691 field_size = i ? idx_size (meta, MONO_TABLE_PROPERTY):
692 idx_size (meta, MONO_TABLE_TYPEDEF);
693 break;
694 case MONO_TABLE_PROPERTY_POINTER:
695 g_assert (i == 0);
696 field_size = idx_size (meta, MONO_TABLE_PROPERTY); break;
697 case MONO_TABLE_TYPEDEF:
698 g_assert (i == 4 || i == 5);
699 field_size = i == 4 ? idx_size (meta, MONO_TABLE_FIELD):
700 idx_size (meta, MONO_TABLE_METHOD);
701 break;
702 case MONO_TABLE_GENERICPARAM:
703 g_assert (i == 2);
704 n = MAX (get_nrows (meta, MONO_TABLE_METHOD), get_nrows (meta, MONO_TABLE_TYPEDEF));
705 /*This is a coded token for 2 tables, so takes 1 bit */
706 field_size = rtsize (meta, n, 16 - MONO_TYPEORMETHOD_BITS);
707 break;
708 case MONO_TABLE_GENERICPARAMCONSTRAINT:
709 g_assert (i == 0);
710 field_size = idx_size (meta, MONO_TABLE_GENERICPARAM);
711 break;
712 case MONO_TABLE_LOCALSCOPE:
713 switch (i) {
714 case 0:
715 // FIXME: This table is in another file
716 field_size = idx_size (meta, MONO_TABLE_METHOD);
717 break;
718 case 1:
719 field_size = idx_size (meta, MONO_TABLE_IMPORTSCOPE);
720 break;
721 case 2:
722 field_size = idx_size (meta, MONO_TABLE_LOCALVARIABLE);
723 break;
724 case 3:
725 field_size = idx_size (meta, MONO_TABLE_LOCALCONSTANT);
726 break;
727 default:
728 g_assert_not_reached ();
729 break;
730 }
731 break;
732 case MONO_TABLE_METHODBODY:
733 g_assert (i == 0);
734 field_size = idx_size (meta, MONO_TABLE_DOCUMENT); break;
735 case MONO_TABLE_IMPORTSCOPE:
736 g_assert(i == 0);
737 field_size = idx_size (meta, MONO_TABLE_IMPORTSCOPE); break;
738 case MONO_TABLE_STATEMACHINEMETHOD:
739 g_assert(i == 0 || i == 1);
740 field_size = idx_size(meta, MONO_TABLE_METHOD); break;
741 default:
742 g_error ("Can't handle MONO_MT_TABLE_IDX for table %d element %d", tableindex, i);
743 }
744 break;
745
746 /*
747 * HasConstant: ParamDef, FieldDef, Property
748 */
749 case MONO_MT_CONST_IDX:
750 n = MAX (get_nrows (meta, MONO_TABLE_PARAM),
751 get_nrows (meta, MONO_TABLE_FIELD));
752 n = MAX (n, get_nrows (meta, MONO_TABLE_PROPERTY));
753
754 /* 2 bits to encode tag */
755 field_size = rtsize (meta, n, 16-2);
756 break;
757
758 /*
759 * HasCustomAttribute: points to any table but
760 * itself.
761 */
762 case MONO_MT_HASCAT_IDX:
763 /*
764 * We believe that since the signature and
765 * permission are indexing the Blob heap,
766 * we should consider the blob size first
767 */
768 /* I'm not a believer - lupus
769 if (meta->idx_blob_wide){
770 field_size = 4;
771 break;
772 }*/
773
774 n = MAX (get_nrows (meta, MONO_TABLE_METHOD),
775 get_nrows (meta, MONO_TABLE_FIELD));
776 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPEREF));
777 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPEDEF));
778 n = MAX (n, get_nrows (meta, MONO_TABLE_PARAM));
779 n = MAX (n, get_nrows (meta, MONO_TABLE_INTERFACEIMPL));
780 n = MAX (n, get_nrows (meta, MONO_TABLE_MEMBERREF));
781 n = MAX (n, get_nrows (meta, MONO_TABLE_MODULE));
782 n = MAX (n, get_nrows (meta, MONO_TABLE_DECLSECURITY));
783 n = MAX (n, get_nrows (meta, MONO_TABLE_PROPERTY));
784 n = MAX (n, get_nrows (meta, MONO_TABLE_EVENT));
785 n = MAX (n, get_nrows (meta, MONO_TABLE_STANDALONESIG));
786 n = MAX (n, get_nrows (meta, MONO_TABLE_MODULEREF));
787 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPESPEC));
788 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLY));
789 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
790 n = MAX (n, get_nrows (meta, MONO_TABLE_FILE));
791 n = MAX (n, get_nrows (meta, MONO_TABLE_EXPORTEDTYPE));
792 n = MAX (n, get_nrows (meta, MONO_TABLE_MANIFESTRESOURCE));
793 n = MAX (n, get_nrows (meta, MONO_TABLE_GENERICPARAM));
794 n = MAX (n, get_nrows (meta, MONO_TABLE_GENERICPARAMCONSTRAINT));
795 n = MAX (n, get_nrows (meta, MONO_TABLE_METHODSPEC));
796
797 /* 5 bits to encode */
798 field_size = rtsize (meta, n, 16-5);
799 break;
800
801 /*
802 * HasCustomAttribute: points to any table but
803 * itself.
804 */
805
806 case MONO_MT_HASCUSTDEBUG_IDX:
807 n = MAX(get_nrows (meta, MONO_TABLE_METHOD),
808 get_nrows (meta, MONO_TABLE_FIELD));
809 n = MAX(n, get_nrows (meta, MONO_TABLE_TYPEREF));
810 n = MAX(n, get_nrows (meta, MONO_TABLE_TYPEDEF));
811 n = MAX(n, get_nrows (meta, MONO_TABLE_PARAM));
812 n = MAX(n, get_nrows (meta, MONO_TABLE_INTERFACEIMPL));
813 n = MAX(n, get_nrows (meta, MONO_TABLE_MEMBERREF));
814 n = MAX(n, get_nrows (meta, MONO_TABLE_MODULE));
815 n = MAX(n, get_nrows (meta, MONO_TABLE_DECLSECURITY));
816 n = MAX(n, get_nrows (meta, MONO_TABLE_PROPERTY));
817 n = MAX(n, get_nrows (meta, MONO_TABLE_EVENT));
818 n = MAX(n, get_nrows (meta, MONO_TABLE_STANDALONESIG));
819 n = MAX(n, get_nrows (meta, MONO_TABLE_MODULEREF));
820 n = MAX(n, get_nrows (meta, MONO_TABLE_TYPESPEC));
821 n = MAX(n, get_nrows (meta, MONO_TABLE_ASSEMBLY));
822 n = MAX(n, get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
823 n = MAX(n, get_nrows (meta, MONO_TABLE_FILE));
824 n = MAX(n, get_nrows (meta, MONO_TABLE_EXPORTEDTYPE));
825 n = MAX(n, get_nrows (meta, MONO_TABLE_MANIFESTRESOURCE));
826 n = MAX(n, get_nrows (meta, MONO_TABLE_GENERICPARAM));
827 n = MAX(n, get_nrows (meta, MONO_TABLE_GENERICPARAMCONSTRAINT));
828 n = MAX(n, get_nrows (meta, MONO_TABLE_METHODSPEC));
829 n = MAX(n, get_nrows (meta, MONO_TABLE_DOCUMENT));
830 n = MAX(n, get_nrows (meta, MONO_TABLE_LOCALSCOPE));
831 n = MAX(n, get_nrows (meta, MONO_TABLE_LOCALVARIABLE));
832 n = MAX(n, get_nrows (meta, MONO_TABLE_LOCALCONSTANT));
833 n = MAX(n, get_nrows (meta, MONO_TABLE_IMPORTSCOPE));
834
835 /* 5 bits to encode */
836 field_size = rtsize(meta, n, 16 - 5);
837 break;
838
839 /*
840 * CustomAttributeType: MethodDef, MemberRef.
841 */
842 case MONO_MT_CAT_IDX:
843 n = MAX (get_nrows (meta, MONO_TABLE_METHOD),
844 get_nrows (meta, MONO_TABLE_MEMBERREF));
845
846 /* 3 bits to encode */
847 field_size = rtsize (meta, n, 16-3);
848 break;
849
850 /*
851 * HasDeclSecurity: Typedef, MethodDef, Assembly
852 */
853 case MONO_MT_HASDEC_IDX:
854 n = MAX (get_nrows (meta, MONO_TABLE_TYPEDEF),
855 get_nrows (meta, MONO_TABLE_METHOD));
856 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLY));
857
858 /* 2 bits to encode */
859 field_size = rtsize (meta, n, 16-2);
860 break;
861
862 /*
863 * Implementation: File, AssemblyRef, ExportedType
864 */
865 case MONO_MT_IMPL_IDX:
866 n = MAX (get_nrows (meta, MONO_TABLE_FILE),
867 get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
868 n = MAX (n, get_nrows (meta, MONO_TABLE_EXPORTEDTYPE));
869
870 /* 2 bits to encode tag */
871 field_size = rtsize (meta, n, 16-2);
872 break;
873
874 /*
875 * HasFieldMarshall: FieldDef, ParamDef
876 */
877 case MONO_MT_HFM_IDX:
878 n = MAX (get_nrows (meta, MONO_TABLE_FIELD),
879 get_nrows (meta, MONO_TABLE_PARAM));
880
881 /* 1 bit used to encode tag */
882 field_size = rtsize (meta, n, 16-1);
883 break;
884
885 /*
886 * MemberForwarded: FieldDef, MethodDef
887 */
888 case MONO_MT_MF_IDX:
889 n = MAX (get_nrows (meta, MONO_TABLE_FIELD),
890 get_nrows (meta, MONO_TABLE_METHOD));
891
892 /* 1 bit used to encode tag */
893 field_size = rtsize (meta, n, 16-1);
894 break;
895
896 /*
897 * TypeDefOrRef: TypeDef, ParamDef, TypeSpec
898 * LAMESPEC
899 * It is TypeDef, _TypeRef_, TypeSpec, instead.
900 */
901 case MONO_MT_TDOR_IDX:
902 n = MAX (get_nrows (meta, MONO_TABLE_TYPEDEF),
903 get_nrows (meta, MONO_TABLE_TYPEREF));
904 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPESPEC));
905
906 /* 2 bits to encode */
907 field_size = rtsize (meta, n, 16-2);
908 break;
909
910 /*
911 * MemberRefParent: TypeDef, TypeRef, MethodDef, ModuleRef, TypeSpec, MemberRef
912 */
913 case MONO_MT_MRP_IDX:
914 n = MAX (get_nrows (meta, MONO_TABLE_TYPEDEF),
915 get_nrows (meta, MONO_TABLE_TYPEREF));
916 n = MAX (n, get_nrows (meta, MONO_TABLE_METHOD));
917 n = MAX (n, get_nrows (meta, MONO_TABLE_MODULEREF));
918 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPESPEC));
919
920 /* 3 bits to encode */
921 field_size = rtsize (meta, n, 16 - 3);
922 break;
923
924 /*
925 * MethodDefOrRef: MethodDef, MemberRef
926 */
927 case MONO_MT_MDOR_IDX:
928 n = MAX (get_nrows (meta, MONO_TABLE_METHOD),
929 get_nrows (meta, MONO_TABLE_MEMBERREF));
930
931 /* 1 bit used to encode tag */
932 field_size = rtsize (meta, n, 16-1);
933 break;
934
935 /*
936 * HasSemantics: Property, Event
937 */
938 case MONO_MT_HS_IDX:
939 n = MAX (get_nrows (meta, MONO_TABLE_PROPERTY),
940 get_nrows (meta, MONO_TABLE_EVENT));
941
942 /* 1 bit used to encode tag */
943 field_size = rtsize (meta, n, 16-1);
944 break;
945
946 /*
947 * ResolutionScope: Module, ModuleRef, AssemblyRef, TypeRef
948 */
949 case MONO_MT_RS_IDX:
950 n = MAX (get_nrows (meta, MONO_TABLE_MODULE),
951 get_nrows (meta, MONO_TABLE_MODULEREF));
952 n = MAX (n, get_nrows (meta, MONO_TABLE_ASSEMBLYREF));
953 n = MAX (n, get_nrows (meta, MONO_TABLE_TYPEREF));
954
955 /* 2 bits used to encode tag (ECMA spec claims 3) */
956 field_size = rtsize (meta, n, 16 - 2);
957 break;
958 }
959
960 /*
961 * encode field size as follows (we just need to
962 * distinguish them).
963 *
964 * 4 -> 3
965 * 2 -> 1
966 * 1 -> 0
967 */
968 bitfield |= (field_size-1) << shift;
969 shift += 2;
970 size += field_size;
971 /*g_print ("table %02x field %d size %d\n", tableindex, i, field_size);*/
972 }
973
974 *result_bitfield = (i << 24) | bitfield;
975 return size;
976 }
977
978 /**
979 * mono_metadata_compute_table_bases:
980 * \param meta metadata context to compute table values
981 *
982 * Computes the table bases for the metadata structure.
983 * This is an internal function used by the image loader code.
984 */
985 void
mono_metadata_compute_table_bases(MonoImage * meta)986 mono_metadata_compute_table_bases (MonoImage *meta)
987 {
988 int i;
989 const char *base = meta->tables_base;
990
991 for (i = 0; i < MONO_TABLE_NUM; i++) {
992 MonoTableInfo *table = &meta->tables [i];
993 if (table->rows == 0)
994 continue;
995
996 table->row_size = mono_metadata_compute_size (meta, i, &table->size_bitfield);
997 table->base = base;
998 base += table->rows * table->row_size;
999 }
1000 }
1001
1002 /**
1003 * mono_metadata_locate:
1004 * \param meta metadata context
1005 * \param table table code.
1006 * \param idx index of element to retrieve from \p table.
1007 *
1008 * \returns a pointer to the \p idx element in the metadata table
1009 * whose code is \p table.
1010 */
1011 const char *
mono_metadata_locate(MonoImage * meta,int table,int idx)1012 mono_metadata_locate (MonoImage *meta, int table, int idx)
1013 {
1014 /* idx == 0 refers always to NULL */
1015 g_return_val_if_fail (idx > 0 && idx <= meta->tables [table].rows, ""); /*FIXME shouldn't we return NULL here?*/
1016
1017 return meta->tables [table].base + (meta->tables [table].row_size * (idx - 1));
1018 }
1019
1020 /**
1021 * mono_metadata_locate_token:
1022 * \param meta metadata context
1023 * \param token metadata token
1024 *
1025 * \returns a pointer to the data in the metadata represented by the
1026 * token \p token .
1027 */
1028 const char *
mono_metadata_locate_token(MonoImage * meta,guint32 token)1029 mono_metadata_locate_token (MonoImage *meta, guint32 token)
1030 {
1031 return mono_metadata_locate (meta, token >> 24, token & 0xffffff);
1032 }
1033
1034 /**
1035 * mono_metadata_string_heap:
1036 * \param meta metadata context
1037 * \param index index into the string heap.
1038 * \returns an in-memory pointer to the \p index in the string heap.
1039 */
1040 const char *
mono_metadata_string_heap(MonoImage * meta,guint32 index)1041 mono_metadata_string_heap (MonoImage *meta, guint32 index)
1042 {
1043 g_assert (index < meta->heap_strings.size);
1044 g_return_val_if_fail (index < meta->heap_strings.size, "");
1045 return meta->heap_strings.data + index;
1046 }
1047
1048 /**
1049 * mono_metadata_user_string:
1050 * \param meta metadata context
1051 * \param index index into the user string heap.
1052 * \returns an in-memory pointer to the \p index in the user string heap (<code>#US</code>).
1053 */
1054 const char *
mono_metadata_user_string(MonoImage * meta,guint32 index)1055 mono_metadata_user_string (MonoImage *meta, guint32 index)
1056 {
1057 g_assert (index < meta->heap_us.size);
1058 g_return_val_if_fail (index < meta->heap_us.size, "");
1059 return meta->heap_us.data + index;
1060 }
1061
1062 /**
1063 * mono_metadata_blob_heap:
1064 * \param meta metadata context
1065 * \param index index into the blob.
1066 * \returns an in-memory pointer to the \p index in the Blob heap.
1067 */
1068 const char *
mono_metadata_blob_heap(MonoImage * meta,guint32 index)1069 mono_metadata_blob_heap (MonoImage *meta, guint32 index)
1070 {
1071 g_assert (index < meta->heap_blob.size);
1072 g_return_val_if_fail (index < meta->heap_blob.size, "");/*FIXME shouldn't we return NULL and check for index == 0?*/
1073 return meta->heap_blob.data + index;
1074 }
1075
1076 /**
1077 * mono_metadata_guid_heap:
1078 * \param meta metadata context
1079 * \param index index into the guid heap.
1080 * \returns an in-memory pointer to the \p index in the guid heap.
1081 */
1082 const char *
mono_metadata_guid_heap(MonoImage * meta,guint32 index)1083 mono_metadata_guid_heap (MonoImage *meta, guint32 index)
1084 {
1085 --index;
1086 index *= 16; /* adjust for guid size and 1-based index */
1087 g_return_val_if_fail (index < meta->heap_guid.size, "");
1088 return meta->heap_guid.data + index;
1089 }
1090
1091 static const unsigned char *
dword_align(const unsigned char * ptr)1092 dword_align (const unsigned char *ptr)
1093 {
1094 #if SIZEOF_VOID_P == 8
1095 return (const unsigned char *) (((guint64) (ptr + 3)) & ~3);
1096 #else
1097 return (const unsigned char *) (((guint32) (ptr + 3)) & ~3);
1098 #endif
1099 }
1100
1101 /**
1102 * mono_metadata_decode_row:
1103 * \param t table to extract information from.
1104 * \param idx index in table.
1105 * \param res array of \p res_size cols to store the results in
1106 *
1107 * This decompresses the metadata element \p idx in table \p t
1108 * into the \c guint32 \p res array that has \p res_size elements
1109 */
1110 void
mono_metadata_decode_row(const MonoTableInfo * t,int idx,guint32 * res,int res_size)1111 mono_metadata_decode_row (const MonoTableInfo *t, int idx, guint32 *res, int res_size)
1112 {
1113 guint32 bitfield = t->size_bitfield;
1114 int i, count = mono_metadata_table_count (bitfield);
1115 const char *data;
1116
1117 g_assert (idx < t->rows);
1118 g_assert (idx >= 0);
1119 data = t->base + idx * t->row_size;
1120
1121 g_assert (res_size == count);
1122
1123 for (i = 0; i < count; i++) {
1124 int n = mono_metadata_table_size (bitfield, i);
1125
1126 switch (n){
1127 case 1:
1128 res [i] = *data; break;
1129 case 2:
1130 res [i] = read16 (data); break;
1131 case 4:
1132 res [i] = read32 (data); break;
1133 default:
1134 g_assert_not_reached ();
1135 }
1136 data += n;
1137 }
1138 }
1139
1140 /**
1141 * mono_metadata_decode_row_col:
1142 * \param t table to extract information from.
1143 * \param idx index for row in table.
1144 * \param col column in the row.
1145 *
1146 * This function returns the value of column \p col from the \p idx
1147 * row in the table \p t .
1148 */
1149 guint32
mono_metadata_decode_row_col(const MonoTableInfo * t,int idx,guint col)1150 mono_metadata_decode_row_col (const MonoTableInfo *t, int idx, guint col)
1151 {
1152 guint32 bitfield = t->size_bitfield;
1153 int i;
1154 register const char *data;
1155 register int n;
1156
1157 g_assert (idx < t->rows);
1158 g_assert (col < mono_metadata_table_count (bitfield));
1159 data = t->base + idx * t->row_size;
1160
1161 n = mono_metadata_table_size (bitfield, 0);
1162 for (i = 0; i < col; ++i) {
1163 data += n;
1164 n = mono_metadata_table_size (bitfield, i + 1);
1165 }
1166 switch (n) {
1167 case 1:
1168 return *data;
1169 case 2:
1170 return read16 (data);
1171 case 4:
1172 return read32 (data);
1173 default:
1174 g_assert_not_reached ();
1175 }
1176 return 0;
1177 }
1178
1179 /**
1180 * mono_metadata_decode_blob_size:
1181 * \param ptr pointer to a blob object
1182 * \param rptr the new position of the pointer
1183 *
1184 * This decodes a compressed size as described by 24.2.4 (#US and #Blob a blob or user string object)
1185 *
1186 * \returns the size of the blob object
1187 */
1188 guint32
mono_metadata_decode_blob_size(const char * xptr,const char ** rptr)1189 mono_metadata_decode_blob_size (const char *xptr, const char **rptr)
1190 {
1191 const unsigned char *ptr = (const unsigned char *)xptr;
1192 guint32 size;
1193
1194 if ((*ptr & 0x80) == 0){
1195 size = ptr [0] & 0x7f;
1196 ptr++;
1197 } else if ((*ptr & 0x40) == 0){
1198 size = ((ptr [0] & 0x3f) << 8) + ptr [1];
1199 ptr += 2;
1200 } else {
1201 size = ((ptr [0] & 0x1f) << 24) +
1202 (ptr [1] << 16) +
1203 (ptr [2] << 8) +
1204 ptr [3];
1205 ptr += 4;
1206 }
1207 if (rptr)
1208 *rptr = (char*)ptr;
1209 return size;
1210 }
1211
1212 /**
1213 * mono_metadata_decode_value:
1214 * \param ptr pointer to decode from
1215 * \param rptr the new position of the pointer
1216 *
1217 * This routine decompresses 32-bit values as specified in the "Blob and
1218 * Signature" section (23.2)
1219 *
1220 * \returns the decoded value
1221 */
1222 guint32
mono_metadata_decode_value(const char * _ptr,const char ** rptr)1223 mono_metadata_decode_value (const char *_ptr, const char **rptr)
1224 {
1225 const unsigned char *ptr = (const unsigned char *) _ptr;
1226 unsigned char b = *ptr;
1227 guint32 len;
1228
1229 if ((b & 0x80) == 0){
1230 len = b;
1231 ++ptr;
1232 } else if ((b & 0x40) == 0){
1233 len = ((b & 0x3f) << 8 | ptr [1]);
1234 ptr += 2;
1235 } else {
1236 len = ((b & 0x1f) << 24) |
1237 (ptr [1] << 16) |
1238 (ptr [2] << 8) |
1239 ptr [3];
1240 ptr += 4;
1241 }
1242 if (rptr)
1243 *rptr = (char*)ptr;
1244
1245 return len;
1246 }
1247
1248 /**
1249 * mono_metadata_decode_signed_value:
1250 * \param ptr pointer to decode from
1251 * \param rptr the new position of the pointer
1252 *
1253 * This routine decompresses 32-bit signed values
1254 * (not specified in the spec)
1255 *
1256 * \returns the decoded value
1257 */
1258 gint32
mono_metadata_decode_signed_value(const char * ptr,const char ** rptr)1259 mono_metadata_decode_signed_value (const char *ptr, const char **rptr)
1260 {
1261 guint32 uval = mono_metadata_decode_value (ptr, rptr);
1262 gint32 ival = uval >> 1;
1263 if (!(uval & 1))
1264 return ival;
1265 /* ival is a truncated 2's complement negative number. */
1266 if (ival < 0x40)
1267 /* 6 bits = 7 bits for compressed representation (top bit is '0') - 1 sign bit */
1268 return ival - 0x40;
1269 if (ival < 0x2000)
1270 /* 13 bits = 14 bits for compressed representation (top bits are '10') - 1 sign bit */
1271 return ival - 0x2000;
1272 if (ival < 0x10000000)
1273 /* 28 bits = 29 bits for compressed representation (top bits are '110') - 1 sign bit */
1274 return ival - 0x10000000;
1275 g_assert (ival < 0x20000000);
1276 g_warning ("compressed signed value appears to use 29 bits for compressed representation: %x (raw: %8x)", ival, uval);
1277 return ival - 0x20000000;
1278 }
1279
1280 /**
1281 * mono_metadata_translate_token_index:
1282 * Translates the given 1-based index into the \c Method, \c Field, \c Event, or \c Param tables
1283 * using the \c *Ptr tables in uncompressed metadata, if they are available.
1284 *
1285 * FIXME: The caller is not forced to call this function, which is error-prone, since
1286 * forgetting to call it would only show up as a bug on uncompressed metadata.
1287 */
1288 guint32
mono_metadata_translate_token_index(MonoImage * image,int table,guint32 idx)1289 mono_metadata_translate_token_index (MonoImage *image, int table, guint32 idx)
1290 {
1291 if (!image->uncompressed_metadata)
1292 return idx;
1293
1294 switch (table) {
1295 case MONO_TABLE_METHOD:
1296 if (image->tables [MONO_TABLE_METHOD_POINTER].rows)
1297 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_METHOD_POINTER], idx - 1, MONO_METHOD_POINTER_METHOD);
1298 else
1299 return idx;
1300 case MONO_TABLE_FIELD:
1301 if (image->tables [MONO_TABLE_FIELD_POINTER].rows)
1302 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_FIELD_POINTER], idx - 1, MONO_FIELD_POINTER_FIELD);
1303 else
1304 return idx;
1305 case MONO_TABLE_EVENT:
1306 if (image->tables [MONO_TABLE_EVENT_POINTER].rows)
1307 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_EVENT_POINTER], idx - 1, MONO_EVENT_POINTER_EVENT);
1308 else
1309 return idx;
1310 case MONO_TABLE_PROPERTY:
1311 if (image->tables [MONO_TABLE_PROPERTY_POINTER].rows)
1312 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_PROPERTY_POINTER], idx - 1, MONO_PROPERTY_POINTER_PROPERTY);
1313 else
1314 return idx;
1315 case MONO_TABLE_PARAM:
1316 if (image->tables [MONO_TABLE_PARAM_POINTER].rows)
1317 return mono_metadata_decode_row_col (&image->tables [MONO_TABLE_PARAM_POINTER], idx - 1, MONO_PARAM_POINTER_PARAM);
1318 else
1319 return idx;
1320 default:
1321 return idx;
1322 }
1323 }
1324
1325 /**
1326 * mono_metadata_decode_table_row:
1327 *
1328 * Same as \c mono_metadata_decode_row, but takes an \p image + \p table ID pair, and takes
1329 * uncompressed metadata into account, so it should be used to access the
1330 * \c Method, \c Field, \c Param and \c Event tables when the access is made from metadata, i.e.
1331 * \p idx is retrieved from a metadata table, like \c MONO_TYPEDEF_FIELD_LIST.
1332 */
1333 void
mono_metadata_decode_table_row(MonoImage * image,int table,int idx,guint32 * res,int res_size)1334 mono_metadata_decode_table_row (MonoImage *image, int table, int idx, guint32 *res, int res_size)
1335 {
1336 if (image->uncompressed_metadata)
1337 idx = mono_metadata_translate_token_index (image, table, idx + 1) - 1;
1338
1339 mono_metadata_decode_row (&image->tables [table], idx, res, res_size);
1340 }
1341
1342 /**
1343 * mono_metadata_decode_table_row_col:
1344 *
1345 * Same as \c mono_metadata_decode_row_col, but takes an \p image + \p table ID pair, and takes
1346 * uncompressed metadata into account, so it should be used to access the
1347 * \c Method, \c Field, \c Param and \c Event tables.
1348 */
mono_metadata_decode_table_row_col(MonoImage * image,int table,int idx,guint col)1349 guint32 mono_metadata_decode_table_row_col (MonoImage *image, int table, int idx, guint col)
1350 {
1351 if (image->uncompressed_metadata)
1352 idx = mono_metadata_translate_token_index (image, table, idx + 1) - 1;
1353
1354 return mono_metadata_decode_row_col (&image->tables [table], idx, col);
1355 }
1356
1357 /**
1358 * mono_metadata_parse_typedef_or_ref:
1359 * \param m a metadata context.
1360 * \param ptr a pointer to an encoded TypedefOrRef in \p m
1361 * \param rptr pointer updated to match the end of the decoded stream
1362 * \returns a token valid in the \p m metadata decoded from
1363 * the compressed representation.
1364 */
1365 guint32
mono_metadata_parse_typedef_or_ref(MonoImage * m,const char * ptr,const char ** rptr)1366 mono_metadata_parse_typedef_or_ref (MonoImage *m, const char *ptr, const char **rptr)
1367 {
1368 guint32 token;
1369 token = mono_metadata_decode_value (ptr, &ptr);
1370 if (rptr)
1371 *rptr = ptr;
1372 return mono_metadata_token_from_dor (token);
1373 }
1374
1375 /**
1376 * mono_metadata_parse_custom_mod:
1377 * \param m a metadata context.
1378 * \param dest storage where the info about the custom modifier is stored (may be NULL)
1379 * \param ptr a pointer to (possibly) the start of a custom modifier list
1380 * \param rptr pointer updated to match the end of the decoded stream
1381 *
1382 * Checks if \p ptr points to a type custom modifier compressed representation.
1383 *
1384 * \returns TRUE if a custom modifier was found, FALSE if not.
1385 */
1386 int
mono_metadata_parse_custom_mod(MonoImage * m,MonoCustomMod * dest,const char * ptr,const char ** rptr)1387 mono_metadata_parse_custom_mod (MonoImage *m, MonoCustomMod *dest, const char *ptr, const char **rptr)
1388 {
1389 MonoCustomMod local;
1390 if ((*ptr == MONO_TYPE_CMOD_OPT) || (*ptr == MONO_TYPE_CMOD_REQD)) {
1391 if (!dest)
1392 dest = &local;
1393 dest->required = *ptr == MONO_TYPE_CMOD_REQD ? 1 : 0;
1394 dest->token = mono_metadata_parse_typedef_or_ref (m, ptr + 1, rptr);
1395 return TRUE;
1396 }
1397 return FALSE;
1398 }
1399
1400 /*
1401 * mono_metadata_parse_array_internal:
1402 * @m: a metadata context.
1403 * @transient: whenever to allocate data from the heap
1404 * @ptr: a pointer to an encoded array description.
1405 * @rptr: pointer updated to match the end of the decoded stream
1406 *
1407 * Decodes the compressed array description found in the metadata @m at @ptr.
1408 *
1409 * Returns: a #MonoArrayType structure describing the array type
1410 * and dimensions. Memory is allocated from the heap or from the image mempool, depending
1411 * on the value of @transient.
1412 *
1413 * LOCKING: Acquires the loader lock
1414 */
1415 static MonoArrayType *
mono_metadata_parse_array_internal(MonoImage * m,MonoGenericContainer * container,gboolean transient,const char * ptr,const char ** rptr,MonoError * error)1416 mono_metadata_parse_array_internal (MonoImage *m, MonoGenericContainer *container,
1417 gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1418 {
1419 int i;
1420 MonoArrayType *array;
1421 MonoType *etype;
1422
1423 etype = mono_metadata_parse_type_checked (m, container, 0, FALSE, ptr, &ptr, error); //FIXME this doesn't respect @transient
1424 if (!etype)
1425 return NULL;
1426
1427 array = transient ? (MonoArrayType *)g_malloc0 (sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (m, sizeof (MonoArrayType));
1428 array->eklass = mono_class_from_mono_type (etype);
1429 array->rank = mono_metadata_decode_value (ptr, &ptr);
1430
1431 array->numsizes = mono_metadata_decode_value (ptr, &ptr);
1432 if (array->numsizes)
1433 array->sizes = transient ? (int *)g_malloc0 (sizeof (int) * array->numsizes) : (int *)mono_image_alloc0 (m, sizeof (int) * array->numsizes);
1434 for (i = 0; i < array->numsizes; ++i)
1435 array->sizes [i] = mono_metadata_decode_value (ptr, &ptr);
1436
1437 array->numlobounds = mono_metadata_decode_value (ptr, &ptr);
1438 if (array->numlobounds)
1439 array->lobounds = transient ? (int *)g_malloc0 (sizeof (int) * array->numlobounds) : (int *)mono_image_alloc0 (m, sizeof (int) * array->numlobounds);
1440 for (i = 0; i < array->numlobounds; ++i)
1441 array->lobounds [i] = mono_metadata_decode_signed_value (ptr, &ptr);
1442
1443 if (rptr)
1444 *rptr = ptr;
1445 return array;
1446 }
1447
1448 /**
1449 * mono_metadata_parse_array:
1450 */
1451 MonoArrayType *
mono_metadata_parse_array(MonoImage * m,const char * ptr,const char ** rptr)1452 mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
1453 {
1454 MonoError error;
1455 MonoArrayType *ret = mono_metadata_parse_array_internal (m, NULL, FALSE, ptr, rptr, &error);
1456 mono_error_cleanup (&error);
1457
1458 return ret;
1459 }
1460
1461 /**
1462 * mono_metadata_free_array:
1463 * \param array array description
1464 *
1465 * Frees the array description returned from \c mono_metadata_parse_array.
1466 */
1467 void
mono_metadata_free_array(MonoArrayType * array)1468 mono_metadata_free_array (MonoArrayType *array)
1469 {
1470 g_free (array->sizes);
1471 g_free (array->lobounds);
1472 g_free (array);
1473 }
1474
1475 /*
1476 * need to add common field and param attributes combinations:
1477 * [out] param
1478 * public static
1479 * public static literal
1480 * private
1481 * private static
1482 * private static literal
1483 */
1484 static const MonoType
1485 builtin_types[] = {
1486 /* data, attrs, type, nmods, byref, pinned */
1487 {{NULL}, 0, MONO_TYPE_VOID, 0, 0, 0},
1488 {{NULL}, 0, MONO_TYPE_BOOLEAN, 0, 0, 0},
1489 {{NULL}, 0, MONO_TYPE_BOOLEAN, 0, 1, 0},
1490 {{NULL}, 0, MONO_TYPE_CHAR, 0, 0, 0},
1491 {{NULL}, 0, MONO_TYPE_CHAR, 0, 1, 0},
1492 {{NULL}, 0, MONO_TYPE_I1, 0, 0, 0},
1493 {{NULL}, 0, MONO_TYPE_I1, 0, 1, 0},
1494 {{NULL}, 0, MONO_TYPE_U1, 0, 0, 0},
1495 {{NULL}, 0, MONO_TYPE_U1, 0, 1, 0},
1496 {{NULL}, 0, MONO_TYPE_I2, 0, 0, 0},
1497 {{NULL}, 0, MONO_TYPE_I2, 0, 1, 0},
1498 {{NULL}, 0, MONO_TYPE_U2, 0, 0, 0},
1499 {{NULL}, 0, MONO_TYPE_U2, 0, 1, 0},
1500 {{NULL}, 0, MONO_TYPE_I4, 0, 0, 0},
1501 {{NULL}, 0, MONO_TYPE_I4, 0, 1, 0},
1502 {{NULL}, 0, MONO_TYPE_U4, 0, 0, 0},
1503 {{NULL}, 0, MONO_TYPE_U4, 0, 1, 0},
1504 {{NULL}, 0, MONO_TYPE_I8, 0, 0, 0},
1505 {{NULL}, 0, MONO_TYPE_I8, 0, 1, 0},
1506 {{NULL}, 0, MONO_TYPE_U8, 0, 0, 0},
1507 {{NULL}, 0, MONO_TYPE_U8, 0, 1, 0},
1508 {{NULL}, 0, MONO_TYPE_R4, 0, 0, 0},
1509 {{NULL}, 0, MONO_TYPE_R4, 0, 1, 0},
1510 {{NULL}, 0, MONO_TYPE_R8, 0, 0, 0},
1511 {{NULL}, 0, MONO_TYPE_R8, 0, 1, 0},
1512 {{NULL}, 0, MONO_TYPE_STRING, 0, 0, 0},
1513 {{NULL}, 0, MONO_TYPE_STRING, 0, 1, 0},
1514 {{NULL}, 0, MONO_TYPE_OBJECT, 0, 0, 0},
1515 {{NULL}, 0, MONO_TYPE_OBJECT, 0, 1, 0},
1516 {{NULL}, 0, MONO_TYPE_TYPEDBYREF, 0, 0, 0},
1517 {{NULL}, 0, MONO_TYPE_I, 0, 0, 0},
1518 {{NULL}, 0, MONO_TYPE_I, 0, 1, 0},
1519 {{NULL}, 0, MONO_TYPE_U, 0, 0, 0},
1520 {{NULL}, 0, MONO_TYPE_U, 0, 1, 0},
1521 };
1522
1523 #define NBUILTIN_TYPES() (sizeof (builtin_types) / sizeof (builtin_types [0]))
1524
1525 static GHashTable *type_cache = NULL;
1526 static gint32 next_generic_inst_id = 0;
1527
1528 /* Protected by image_sets_mutex */
1529 static MonoImageSet *mscorlib_image_set;
1530 /* Protected by image_sets_mutex */
1531 static GPtrArray *image_sets;
1532 static mono_mutex_t image_sets_mutex;
1533
1534 static guint mono_generic_class_hash (gconstpointer data);
1535
1536 /*
1537 * MonoTypes with modifies are never cached, so we never check or use that field.
1538 */
1539 static guint
mono_type_hash(gconstpointer data)1540 mono_type_hash (gconstpointer data)
1541 {
1542 const MonoType *type = (const MonoType *) data;
1543 if (type->type == MONO_TYPE_GENERICINST)
1544 return mono_generic_class_hash (type->data.generic_class);
1545 else
1546 return type->type | (type->byref << 8) | (type->attrs << 9);
1547 }
1548
1549 static gint
mono_type_equal(gconstpointer ka,gconstpointer kb)1550 mono_type_equal (gconstpointer ka, gconstpointer kb)
1551 {
1552 const MonoType *a = (const MonoType *) ka;
1553 const MonoType *b = (const MonoType *) kb;
1554
1555 if (a->type != b->type || a->byref != b->byref || a->attrs != b->attrs || a->pinned != b->pinned)
1556 return 0;
1557 /* need other checks */
1558 return 1;
1559 }
1560
1561 guint
mono_metadata_generic_inst_hash(gconstpointer data)1562 mono_metadata_generic_inst_hash (gconstpointer data)
1563 {
1564 const MonoGenericInst *ginst = (const MonoGenericInst *) data;
1565 guint hash = 0;
1566 int i;
1567
1568 for (i = 0; i < ginst->type_argc; ++i) {
1569 hash *= 13;
1570 hash += mono_metadata_type_hash (ginst->type_argv [i]);
1571 }
1572
1573 return hash ^ (ginst->is_open << 8);
1574 }
1575
1576 static gboolean
mono_generic_inst_equal_full(const MonoGenericInst * a,const MonoGenericInst * b,gboolean signature_only)1577 mono_generic_inst_equal_full (const MonoGenericInst *a, const MonoGenericInst *b, gboolean signature_only)
1578 {
1579 int i;
1580
1581 // An optimization: if the ids of two insts are the same, we know they are the same inst and don't check contents.
1582 // Furthermore, because we perform early de-duping, if the ids differ, we know the contents differ.
1583 #ifndef MONO_SMALL_CONFIG // Optimization does not work in MONO_SMALL_CONFIG: There are no IDs
1584 if (a->id && b->id) { // "id 0" means "object has no id"-- de-duping hasn't been performed yet, must check contents.
1585 if (a->id == b->id)
1586 return TRUE;
1587 // In signature-comparison mode id equality implies object equality, but this is not true for inequality.
1588 // Two separate objects could have signature-equavalent contents.
1589 if (!signature_only)
1590 return FALSE;
1591 }
1592 #endif
1593
1594 if (a->is_open != b->is_open || a->type_argc != b->type_argc)
1595 return FALSE;
1596 for (i = 0; i < a->type_argc; ++i) {
1597 if (!do_mono_metadata_type_equal (a->type_argv [i], b->type_argv [i], signature_only))
1598 return FALSE;
1599 }
1600 return TRUE;
1601 }
1602
1603 gboolean
mono_metadata_generic_inst_equal(gconstpointer ka,gconstpointer kb)1604 mono_metadata_generic_inst_equal (gconstpointer ka, gconstpointer kb)
1605 {
1606 const MonoGenericInst *a = (const MonoGenericInst *) ka;
1607 const MonoGenericInst *b = (const MonoGenericInst *) kb;
1608
1609 return mono_generic_inst_equal_full (a, b, FALSE);
1610 }
1611
1612 static guint
mono_generic_class_hash(gconstpointer data)1613 mono_generic_class_hash (gconstpointer data)
1614 {
1615 const MonoGenericClass *gclass = (const MonoGenericClass *) data;
1616 guint hash = mono_metadata_type_hash (&gclass->container_class->byval_arg);
1617
1618 hash *= 13;
1619 hash += gclass->is_tb_open;
1620 hash += mono_metadata_generic_context_hash (&gclass->context);
1621
1622 return hash;
1623 }
1624
1625 static gboolean
mono_generic_class_equal(gconstpointer ka,gconstpointer kb)1626 mono_generic_class_equal (gconstpointer ka, gconstpointer kb)
1627 {
1628 const MonoGenericClass *a = (const MonoGenericClass *) ka;
1629 const MonoGenericClass *b = (const MonoGenericClass *) kb;
1630
1631 return _mono_metadata_generic_class_equal (a, b, FALSE);
1632 }
1633
1634 /**
1635 * mono_metadata_init:
1636 *
1637 * Initialize the global variables of this module.
1638 * This is a Mono runtime internal function.
1639 */
1640 void
mono_metadata_init(void)1641 mono_metadata_init (void)
1642 {
1643 int i;
1644
1645 /* We guard against double initialization due to how pedump in verification mode works.
1646 Until runtime initialization is properly factored to work with what it needs we need workarounds like this.
1647 FIXME: https://bugzilla.xamarin.com/show_bug.cgi?id=58793
1648 */
1649 static gboolean inited;
1650
1651 if (inited)
1652 return;
1653 inited = TRUE;
1654
1655 type_cache = g_hash_table_new (mono_type_hash, mono_type_equal);
1656
1657 for (i = 0; i < NBUILTIN_TYPES (); ++i)
1658 g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]);
1659
1660 mono_os_mutex_init_recursive (&image_sets_mutex);
1661
1662 mono_counters_register ("ImgSet Cache Hit", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_hit);
1663 mono_counters_register ("ImgSet Cache Miss", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_miss);
1664 mono_counters_register ("ImgSet Count", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_count);
1665 }
1666
1667 /**
1668 * mono_metadata_cleanup:
1669 *
1670 * Free all resources used by this module.
1671 * This is a Mono runtime internal function.
1672 */
1673 void
mono_metadata_cleanup(void)1674 mono_metadata_cleanup (void)
1675 {
1676 g_hash_table_destroy (type_cache);
1677 type_cache = NULL;
1678 g_ptr_array_free (image_sets, TRUE);
1679 image_sets = NULL;
1680 mono_os_mutex_destroy (&image_sets_mutex);
1681 }
1682
1683 /**
1684 * mono_metadata_parse_type:
1685 * \param m metadata context
1686 * \param mode kind of type that may be found at \p ptr
1687 * \param opt_attrs optional attributes to store in the returned type
1688 * \param ptr pointer to the type representation
1689 * \param rptr pointer updated to match the end of the decoded stream
1690 * \param transient whenever to allocate the result from the heap or from a mempool
1691 *
1692 * Decode a compressed type description found at \p ptr in \p m .
1693 * \p mode can be one of \c MONO_PARSE_MOD_TYPE, \c MONO_PARSE_PARAM, \c MONO_PARSE_RET,
1694 * \c MONO_PARSE_FIELD, \c MONO_PARSE_LOCAL, \c MONO_PARSE_TYPE.
1695 * This function can be used to decode type descriptions in method signatures,
1696 * field signatures, locals signatures etc.
1697 *
1698 * To parse a generic type, \c generic_container points to the current class'es
1699 * (the \c generic_container field in the <code>MonoClass</code>) or the current generic method's
1700 * (stored in <code>image->property_hash</code>) generic container.
1701 * When we encounter a \c MONO_TYPE_VAR or \c MONO_TYPE_MVAR, it's looked up in
1702 * this \c MonoGenericContainer.
1703 *
1704 * LOCKING: Acquires the loader lock.
1705 *
1706 * \returns a \c MonoType structure representing the decoded type.
1707 */
1708 static MonoType*
mono_metadata_parse_type_internal(MonoImage * m,MonoGenericContainer * container,short opt_attrs,gboolean transient,const char * ptr,const char ** rptr,MonoError * error)1709 mono_metadata_parse_type_internal (MonoImage *m, MonoGenericContainer *container,
1710 short opt_attrs, gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1711 {
1712 MonoType *type, *cached;
1713 MonoType stype;
1714 gboolean byref = FALSE;
1715 gboolean pinned = FALSE;
1716 const char *tmp_ptr;
1717 int count = 0; // Number of mod arguments
1718 gboolean found;
1719
1720 error_init (error);
1721
1722 /*
1723 * According to the spec, custom modifiers should come before the byref
1724 * flag, but the IL produced by ilasm from the following signature:
1725 * object modopt(...) &
1726 * starts with a byref flag, followed by the modifiers. (bug #49802)
1727 * Also, this type seems to be different from 'object & modopt(...)'. Maybe
1728 * it would be better to treat byref as real type constructor instead of
1729 * a modifier...
1730 * Also, pinned should come before anything else, but some MSV++ produced
1731 * assemblies violate this (#bug 61990).
1732 */
1733
1734 /* Count the modifiers first */
1735 tmp_ptr = ptr;
1736 found = TRUE;
1737 while (found) {
1738 switch (*tmp_ptr) {
1739 case MONO_TYPE_PINNED:
1740 case MONO_TYPE_BYREF:
1741 ++tmp_ptr;
1742 break;
1743 case MONO_TYPE_CMOD_REQD:
1744 case MONO_TYPE_CMOD_OPT:
1745 count ++;
1746 mono_metadata_parse_custom_mod (m, NULL, tmp_ptr, &tmp_ptr);
1747 break;
1748 default:
1749 found = FALSE;
1750 }
1751 }
1752
1753 if (count) { // There are mods, so the MonoType will be of nonstandard size.
1754 int size;
1755
1756 size = MONO_SIZEOF_TYPE + ((gint32)count) * sizeof (MonoCustomMod);
1757 type = transient ? (MonoType *)g_malloc0 (size) : (MonoType *)mono_image_alloc0 (m, size);
1758 type->num_mods = count;
1759 if (count > 64) {
1760 mono_error_set_bad_image (error, m, "Invalid type with more than 64 modifiers");
1761 return NULL;
1762 }
1763 } else { // The type is of standard size, so we can allocate it on the stack.
1764 type = &stype;
1765 memset (type, 0, MONO_SIZEOF_TYPE);
1766 }
1767
1768 /* Iterate again, but now parse pinned, byref and custom modifiers */
1769 found = TRUE;
1770 count = 0;
1771 while (found) {
1772 switch (*ptr) {
1773 case MONO_TYPE_PINNED:
1774 pinned = TRUE;
1775 ++ptr;
1776 break;
1777 case MONO_TYPE_BYREF:
1778 byref = TRUE;
1779 ++ptr;
1780 break;
1781 case MONO_TYPE_CMOD_REQD:
1782 case MONO_TYPE_CMOD_OPT:
1783 mono_metadata_parse_custom_mod (m, &(type->modifiers [count]), ptr, &ptr);
1784 count ++;
1785 break;
1786 default:
1787 found = FALSE;
1788 }
1789 }
1790
1791 type->attrs = opt_attrs;
1792 type->byref = byref;
1793 type->pinned = pinned ? 1 : 0;
1794
1795 if (!do_mono_metadata_parse_type (type, m, container, transient, ptr, &ptr, error))
1796 return NULL;
1797
1798 if (rptr)
1799 *rptr = ptr;
1800
1801 // Possibly we can return an already-allocated type instead of the one we decoded
1802 if (!type->num_mods && !transient) {
1803 /* no need to free type here, because it is on the stack */
1804 if ((type->type == MONO_TYPE_CLASS || type->type == MONO_TYPE_VALUETYPE) && !type->pinned && !type->attrs) {
1805 MonoType *ret = type->byref ? &type->data.klass->this_arg : &type->data.klass->byval_arg;
1806
1807 /* Consider the case:
1808
1809 class Foo<T> { class Bar {} }
1810 class Test : Foo<Test>.Bar {}
1811
1812 When Foo<Test> is being expanded, 'Test' isn't yet initialized. It's actually in
1813 a really pristine state: it doesn't even know whether 'Test' is a reference or a value type.
1814
1815 We ensure that the MonoClass is in a state that we can canonicalize to:
1816
1817 klass->byval_arg.data.klass == klass
1818 klass->this_arg.data.klass == klass
1819
1820 If we can't canonicalize 'type', it doesn't matter, since later users of 'type' will do it.
1821
1822 LOCKING: even though we don't explicitly hold a lock, in the problematic case 'ret' is a field
1823 of a MonoClass which currently holds the loader lock. 'type' is local.
1824 */
1825 if (ret->data.klass == type->data.klass) {
1826 return ret;
1827 }
1828 }
1829 /* No need to use locking since nobody is modifying the hash table */
1830 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type))) {
1831 return cached;
1832 }
1833 }
1834
1835 /* printf ("%x %x %c %s\n", type->attrs, type->num_mods, type->pinned ? 'p' : ' ', mono_type_full_name (type)); */
1836
1837 if (type == &stype) { // Type was allocated on the stack, so we need to copy it to safety
1838 type = transient ? (MonoType *)g_malloc (MONO_SIZEOF_TYPE) : (MonoType *)mono_image_alloc (m, MONO_SIZEOF_TYPE);
1839 memcpy (type, &stype, MONO_SIZEOF_TYPE);
1840 }
1841 return type;
1842 }
1843
1844
1845 MonoType*
mono_metadata_parse_type_checked(MonoImage * m,MonoGenericContainer * container,short opt_attrs,gboolean transient,const char * ptr,const char ** rptr,MonoError * error)1846 mono_metadata_parse_type_checked (MonoImage *m, MonoGenericContainer *container,
1847 short opt_attrs, gboolean transient, const char *ptr, const char **rptr, MonoError *error)
1848 {
1849 return mono_metadata_parse_type_internal (m, container, opt_attrs, transient, ptr, rptr, error);
1850 }
1851
1852 /*
1853 * LOCKING: Acquires the loader lock.
1854 */
1855 MonoType*
mono_metadata_parse_type(MonoImage * m,MonoParseTypeMode mode,short opt_attrs,const char * ptr,const char ** rptr)1856 mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
1857 const char *ptr, const char **rptr)
1858 {
1859 MonoError error;
1860 MonoType * type = mono_metadata_parse_type_internal (m, NULL, opt_attrs, FALSE, ptr, rptr, &error);
1861 mono_error_cleanup (&error);
1862 return type;
1863 }
1864
1865 gboolean
mono_metadata_method_has_param_attrs(MonoImage * m,int def)1866 mono_metadata_method_has_param_attrs (MonoImage *m, int def)
1867 {
1868 MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM];
1869 MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD];
1870 guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST);
1871
1872 if (def < methodt->rows)
1873 lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
1874 else
1875 lastp = m->tables [MONO_TABLE_PARAM].rows + 1;
1876
1877 for (i = param_index; i < lastp; ++i) {
1878 guint32 flags = mono_metadata_decode_row_col (paramt, i - 1, MONO_PARAM_FLAGS);
1879 if (flags)
1880 return TRUE;
1881 }
1882
1883 return FALSE;
1884 }
1885
1886 /*
1887 * mono_metadata_get_param_attrs:
1888 *
1889 * @m The image to loader parameter attributes from
1890 * @def method def token (one based)
1891 * @param_count number of params to decode including the return value
1892 *
1893 * Return the parameter attributes for the method whose MethodDef index is DEF. The
1894 * returned memory needs to be freed by the caller. If all the param attributes are
1895 * 0, then NULL is returned.
1896 */
1897 int*
mono_metadata_get_param_attrs(MonoImage * m,int def,int param_count)1898 mono_metadata_get_param_attrs (MonoImage *m, int def, int param_count)
1899 {
1900 MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM];
1901 MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD];
1902 guint32 cols [MONO_PARAM_SIZE];
1903 guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST);
1904 int *pattrs = NULL;
1905
1906 if (def < methodt->rows)
1907 lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
1908 else
1909 lastp = paramt->rows + 1;
1910
1911 for (i = param_index; i < lastp; ++i) {
1912 mono_metadata_decode_row (paramt, i - 1, cols, MONO_PARAM_SIZE);
1913 if (cols [MONO_PARAM_FLAGS]) {
1914 if (!pattrs)
1915 pattrs = g_new0 (int, param_count);
1916 /* at runtime we just ignore this kind of malformed file:
1917 * the verifier can signal the error to the user
1918 */
1919 if (cols [MONO_PARAM_SEQUENCE] >= param_count)
1920 continue;
1921 pattrs [cols [MONO_PARAM_SEQUENCE]] = cols [MONO_PARAM_FLAGS];
1922 }
1923 }
1924
1925 return pattrs;
1926 }
1927
1928
1929 /**
1930 * mono_metadata_parse_signature:
1931 * \param image metadata context
1932 * \param token metadata token
1933 *
1934 * Decode a method signature stored in the \c StandAloneSig table
1935 *
1936 * \returns a \c MonoMethodSignature describing the signature.
1937 */
1938 MonoMethodSignature*
mono_metadata_parse_signature(MonoImage * image,guint32 token)1939 mono_metadata_parse_signature (MonoImage *image, guint32 token)
1940 {
1941 MonoError error;
1942 MonoMethodSignature *ret;
1943 ret = mono_metadata_parse_signature_checked (image, token, &error);
1944 mono_error_cleanup (&error);
1945 return ret;
1946 }
1947
1948 /*
1949 * mono_metadata_parse_signature_checked:
1950 * @image: metadata context
1951 * @token: metadata token
1952 * @error: set on error
1953 *
1954 * Decode a method signature stored in the STANDALONESIG table
1955 *
1956 * Returns: a MonoMethodSignature describing the signature. On failure
1957 * returns NULL and sets @error.
1958 */
1959 MonoMethodSignature*
mono_metadata_parse_signature_checked(MonoImage * image,guint32 token,MonoError * error)1960 mono_metadata_parse_signature_checked (MonoImage *image, guint32 token, MonoError *error)
1961 {
1962
1963 error_init (error);
1964 MonoTableInfo *tables = image->tables;
1965 guint32 idx = mono_metadata_token_index (token);
1966 guint32 sig;
1967 const char *ptr;
1968
1969 if (image_is_dynamic (image)) {
1970 return (MonoMethodSignature *)mono_lookup_dynamic_token (image, token, NULL, error);
1971 }
1972
1973 g_assert (mono_metadata_token_table(token) == MONO_TABLE_STANDALONESIG);
1974
1975 sig = mono_metadata_decode_row_col (&tables [MONO_TABLE_STANDALONESIG], idx - 1, 0);
1976
1977 ptr = mono_metadata_blob_heap (image, sig);
1978 mono_metadata_decode_blob_size (ptr, &ptr);
1979
1980 return mono_metadata_parse_method_signature_full (image, NULL, 0, ptr, NULL, error);
1981 }
1982
1983 /**
1984 * mono_metadata_signature_alloc:
1985 * \param image metadata context
1986 * \param nparams number of parameters in the signature
1987 *
1988 * Allocate a \c MonoMethodSignature structure with the specified number of params.
1989 * The return type and the params types need to be filled later.
1990 * This is a Mono runtime internal function.
1991 *
1992 * LOCKING: Assumes the loader lock is held.
1993 *
1994 * \returns the new \c MonoMethodSignature structure.
1995 */
1996 MonoMethodSignature*
mono_metadata_signature_alloc(MonoImage * m,guint32 nparams)1997 mono_metadata_signature_alloc (MonoImage *m, guint32 nparams)
1998 {
1999 MonoMethodSignature *sig;
2000
2001 sig = (MonoMethodSignature *)mono_image_alloc0 (m, MONO_SIZEOF_METHOD_SIGNATURE + ((gint32)nparams) * sizeof (MonoType*));
2002 sig->param_count = nparams;
2003 sig->sentinelpos = -1;
2004
2005 return sig;
2006 }
2007
2008 static MonoMethodSignature*
mono_metadata_signature_dup_internal_with_padding(MonoImage * image,MonoMemPool * mp,MonoMethodSignature * sig,size_t padding)2009 mono_metadata_signature_dup_internal_with_padding (MonoImage *image, MonoMemPool *mp, MonoMethodSignature *sig, size_t padding)
2010 {
2011 int sigsize, sig_header_size;
2012 MonoMethodSignature *ret;
2013 sigsize = sig_header_size = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *) + padding;
2014 if (sig->ret)
2015 sigsize += MONO_SIZEOF_TYPE;
2016
2017 if (image) {
2018 ret = (MonoMethodSignature *)mono_image_alloc (image, sigsize);
2019 } else if (mp) {
2020 ret = (MonoMethodSignature *)mono_mempool_alloc (mp, sigsize);
2021 } else {
2022 ret = (MonoMethodSignature *)g_malloc (sigsize);
2023 }
2024
2025 memcpy (ret, sig, sig_header_size - padding);
2026
2027 // Copy return value because of ownership semantics.
2028 if (sig->ret) {
2029 // Danger! Do not alter padding use without changing the dup_add_this below
2030 intptr_t end_of_header = (intptr_t)( (char*)(ret) + sig_header_size);
2031 ret->ret = (MonoType *)end_of_header;
2032 memcpy (ret->ret, sig->ret, MONO_SIZEOF_TYPE);
2033 }
2034
2035 return ret;
2036 }
2037
2038 static MonoMethodSignature*
mono_metadata_signature_dup_internal(MonoImage * image,MonoMemPool * mp,MonoMethodSignature * sig)2039 mono_metadata_signature_dup_internal (MonoImage *image, MonoMemPool *mp, MonoMethodSignature *sig)
2040 {
2041 return mono_metadata_signature_dup_internal_with_padding (image, mp, sig, 0);
2042 }
2043 /*
2044 * signature_dup_add_this:
2045 *
2046 * Make a copy of @sig, adding an explicit this argument.
2047 */
2048 MonoMethodSignature*
mono_metadata_signature_dup_add_this(MonoImage * image,MonoMethodSignature * sig,MonoClass * klass)2049 mono_metadata_signature_dup_add_this (MonoImage *image, MonoMethodSignature *sig, MonoClass *klass)
2050 {
2051 MonoMethodSignature *ret;
2052 ret = mono_metadata_signature_dup_internal_with_padding (image, NULL, sig, sizeof (MonoType *));
2053
2054 ret->param_count = sig->param_count + 1;
2055 ret->hasthis = FALSE;
2056
2057 for (int i = sig->param_count - 1; i >= 0; i --)
2058 ret->params [i + 1] = sig->params [i];
2059 ret->params [0] = klass->valuetype ? &klass->this_arg : &klass->byval_arg;
2060
2061 for (int i = sig->param_count - 1; i >= 0; i --)
2062 g_assert(ret->params [i + 1]->type == sig->params [i]->type && ret->params [i+1]->type != MONO_TYPE_END);
2063 g_assert (ret->ret->type == sig->ret->type && ret->ret->type != MONO_TYPE_END);
2064
2065 return ret;
2066 }
2067
2068
2069
2070 MonoMethodSignature*
mono_metadata_signature_dup_full(MonoImage * image,MonoMethodSignature * sig)2071 mono_metadata_signature_dup_full (MonoImage *image, MonoMethodSignature *sig)
2072 {
2073 MonoMethodSignature *ret = mono_metadata_signature_dup_internal (image, NULL, sig);
2074
2075 for (int i = 0 ; i < sig->param_count; i ++)
2076 g_assert(ret->params [i]->type == sig->params [i]->type);
2077 g_assert (ret->ret->type == sig->ret->type);
2078
2079 return ret;
2080 }
2081
2082 /*The mempool is accessed without synchronization*/
2083 MonoMethodSignature*
mono_metadata_signature_dup_mempool(MonoMemPool * mp,MonoMethodSignature * sig)2084 mono_metadata_signature_dup_mempool (MonoMemPool *mp, MonoMethodSignature *sig)
2085 {
2086 return mono_metadata_signature_dup_internal (NULL, mp, sig);
2087 }
2088
2089 /**
2090 * mono_metadata_signature_dup:
2091 * \param sig method signature
2092 *
2093 * Duplicate an existing \c MonoMethodSignature so it can be modified.
2094 * This is a Mono runtime internal function.
2095 *
2096 * \returns the new \c MonoMethodSignature structure.
2097 */
2098 MonoMethodSignature*
mono_metadata_signature_dup(MonoMethodSignature * sig)2099 mono_metadata_signature_dup (MonoMethodSignature *sig)
2100 {
2101 return mono_metadata_signature_dup_full (NULL, sig);
2102 }
2103
2104 /*
2105 * mono_metadata_signature_size:
2106 *
2107 * Return the amount of memory allocated to SIG.
2108 */
2109 guint32
mono_metadata_signature_size(MonoMethodSignature * sig)2110 mono_metadata_signature_size (MonoMethodSignature *sig)
2111 {
2112 return MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
2113 }
2114
2115 /*
2116 * mono_metadata_parse_method_signature:
2117 * @m: metadata context
2118 * @generic_container: generics container
2119 * @def: the MethodDef index or 0 for Ref signatures.
2120 * @ptr: pointer to the signature metadata representation
2121 * @rptr: pointer updated to match the end of the decoded stream
2122 *
2123 * Decode a method signature stored at @ptr.
2124 * This is a Mono runtime internal function.
2125 *
2126 * LOCKING: Assumes the loader lock is held.
2127 *
2128 * Returns: a MonoMethodSignature describing the signature.
2129 */
2130 MonoMethodSignature *
mono_metadata_parse_method_signature_full(MonoImage * m,MonoGenericContainer * container,int def,const char * ptr,const char ** rptr,MonoError * error)2131 mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *container,
2132 int def, const char *ptr, const char **rptr, MonoError *error)
2133 {
2134 MonoMethodSignature *method;
2135 int i, *pattrs = NULL;
2136 guint32 hasthis = 0, explicit_this = 0, call_convention, param_count;
2137 guint32 gen_param_count = 0;
2138 gboolean is_open = FALSE;
2139
2140 error_init (error);
2141
2142 if (*ptr & 0x10)
2143 gen_param_count = 1;
2144 if (*ptr & 0x20)
2145 hasthis = 1;
2146 if (*ptr & 0x40)
2147 explicit_this = 1;
2148 call_convention = *ptr & 0x0F;
2149 ptr++;
2150 if (gen_param_count)
2151 gen_param_count = mono_metadata_decode_value (ptr, &ptr);
2152 param_count = mono_metadata_decode_value (ptr, &ptr);
2153
2154 if (def)
2155 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 */
2156
2157 method = mono_metadata_signature_alloc (m, param_count);
2158 method->hasthis = hasthis;
2159 method->explicit_this = explicit_this;
2160 method->call_convention = call_convention;
2161 method->generic_param_count = gen_param_count;
2162
2163 if (call_convention != 0xa) {
2164 method->ret = mono_metadata_parse_type_checked (m, container, pattrs ? pattrs [0] : 0, FALSE, ptr, &ptr, error);
2165 if (!method->ret) {
2166 mono_metadata_free_method_signature (method);
2167 g_free (pattrs);
2168 return NULL;
2169 }
2170 is_open = mono_class_is_open_constructed_type (method->ret);
2171 }
2172
2173 for (i = 0; i < method->param_count; ++i) {
2174 if (*ptr == MONO_TYPE_SENTINEL) {
2175 if (method->call_convention != MONO_CALL_VARARG || def) {
2176 mono_error_set_bad_image (error, m, "Found sentinel for methoddef or no vararg");
2177 g_free (pattrs);
2178 return NULL;
2179 }
2180 if (method->sentinelpos >= 0) {
2181 mono_error_set_bad_image (error, m, "Found sentinel twice in the same signature.");
2182 g_free (pattrs);
2183 return NULL;
2184 }
2185 method->sentinelpos = i;
2186 ptr++;
2187 }
2188 method->params [i] = mono_metadata_parse_type_checked (m, container, pattrs ? pattrs [i+1] : 0, FALSE, ptr, &ptr, error);
2189 if (!method->params [i]) {
2190 mono_metadata_free_method_signature (method);
2191 g_free (pattrs);
2192 return NULL;
2193 }
2194 if (!is_open)
2195 is_open = mono_class_is_open_constructed_type (method->params [i]);
2196 }
2197
2198 /* The sentinel could be missing if the caller does not pass any additional arguments */
2199 if (!def && method->call_convention == MONO_CALL_VARARG && method->sentinelpos < 0)
2200 method->sentinelpos = method->param_count;
2201
2202 method->has_type_parameters = is_open;
2203
2204 if (def && (method->call_convention == MONO_CALL_VARARG))
2205 method->sentinelpos = method->param_count;
2206
2207 g_free (pattrs);
2208
2209 if (rptr)
2210 *rptr = ptr;
2211 /*
2212 * Add signature to a cache and increase ref count...
2213 */
2214
2215 return method;
2216 }
2217
2218 /**
2219 * mono_metadata_parse_method_signature:
2220 * \param m metadata context
2221 * \param def the \c MethodDef index or 0 for \c Ref signatures.
2222 * \param ptr pointer to the signature metadata representation
2223 * \param rptr pointer updated to match the end of the decoded stream
2224 *
2225 * Decode a method signature stored at \p ptr.
2226 * This is a Mono runtime internal function.
2227 *
2228 * LOCKING: Assumes the loader lock is held.
2229 *
2230 * \returns a \c MonoMethodSignature describing the signature.
2231 */
2232 MonoMethodSignature *
mono_metadata_parse_method_signature(MonoImage * m,int def,const char * ptr,const char ** rptr)2233 mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, const char **rptr)
2234 {
2235 /*
2236 * This function MUST NOT be called by runtime code as it does error handling incorrectly.
2237 * Use mono_metadata_parse_method_signature_full instead.
2238 * It's ok to asser on failure as we no longer use it.
2239 */
2240 MonoError error;
2241 MonoMethodSignature *ret;
2242 ret = mono_metadata_parse_method_signature_full (m, NULL, def, ptr, rptr, &error);
2243 g_assert (mono_error_ok (&error));
2244
2245 return ret;
2246 }
2247
2248 /**
2249 * mono_metadata_free_method_signature:
2250 * \param sig signature to destroy
2251 *
2252 * Free the memory allocated in the signature \p sig.
2253 * This method needs to be robust and work also on partially-built
2254 * signatures, so it does extra checks.
2255 */
2256 void
mono_metadata_free_method_signature(MonoMethodSignature * sig)2257 mono_metadata_free_method_signature (MonoMethodSignature *sig)
2258 {
2259 /* Everything is allocated from mempools */
2260 /*
2261 int i;
2262 if (sig->ret)
2263 mono_metadata_free_type (sig->ret);
2264 for (i = 0; i < sig->param_count; ++i) {
2265 if (sig->params [i])
2266 mono_metadata_free_type (sig->params [i]);
2267 }
2268 */
2269 }
2270
2271 void
mono_metadata_free_inflated_signature(MonoMethodSignature * sig)2272 mono_metadata_free_inflated_signature (MonoMethodSignature *sig)
2273 {
2274 int i;
2275
2276 /* Allocated in inflate_generic_signature () */
2277 if (sig->ret)
2278 mono_metadata_free_type (sig->ret);
2279 for (i = 0; i < sig->param_count; ++i) {
2280 if (sig->params [i])
2281 mono_metadata_free_type (sig->params [i]);
2282 }
2283 g_free (sig);
2284 }
2285
2286 static gboolean
inflated_method_equal(gconstpointer a,gconstpointer b)2287 inflated_method_equal (gconstpointer a, gconstpointer b)
2288 {
2289 const MonoMethodInflated *ma = (const MonoMethodInflated *)a;
2290 const MonoMethodInflated *mb = (const MonoMethodInflated *)b;
2291 if (ma->declaring != mb->declaring)
2292 return FALSE;
2293 return mono_metadata_generic_context_equal (&ma->context, &mb->context);
2294 }
2295
2296 static guint
inflated_method_hash(gconstpointer a)2297 inflated_method_hash (gconstpointer a)
2298 {
2299 const MonoMethodInflated *ma = (const MonoMethodInflated *)a;
2300 return (mono_metadata_generic_context_hash (&ma->context) ^ mono_aligned_addr_hash (ma->declaring));
2301 }
2302
2303 static gboolean
inflated_signature_equal(gconstpointer a,gconstpointer b)2304 inflated_signature_equal (gconstpointer a, gconstpointer b)
2305 {
2306 const MonoInflatedMethodSignature *sig1 = (const MonoInflatedMethodSignature *)a;
2307 const MonoInflatedMethodSignature *sig2 = (const MonoInflatedMethodSignature *)b;
2308
2309 /* sig->sig is assumed to be canonized */
2310 if (sig1->sig != sig2->sig)
2311 return FALSE;
2312 /* The generic instances are canonized */
2313 return mono_metadata_generic_context_equal (&sig1->context, &sig2->context);
2314 }
2315
2316 static guint
inflated_signature_hash(gconstpointer a)2317 inflated_signature_hash (gconstpointer a)
2318 {
2319 const MonoInflatedMethodSignature *sig = (const MonoInflatedMethodSignature *)a;
2320
2321 /* sig->sig is assumed to be canonized */
2322 return mono_metadata_generic_context_hash (&sig->context) ^ mono_aligned_addr_hash (sig->sig);
2323 }
2324
2325 /*static void
2326 dump_ginst (MonoGenericInst *ginst)
2327 {
2328 int i;
2329 char *name;
2330
2331 g_print ("Ginst: <");
2332 for (i = 0; i < ginst->type_argc; ++i) {
2333 if (i != 0)
2334 g_print (", ");
2335 name = mono_type_get_name (ginst->type_argv [i]);
2336 g_print ("%s", name);
2337 g_free (name);
2338 }
2339 g_print (">");
2340 }*/
2341
2342 static gboolean type_in_image (MonoType *type, MonoImage *image);
2343
2344 static gboolean
signature_in_image(MonoMethodSignature * sig,MonoImage * image)2345 signature_in_image (MonoMethodSignature *sig, MonoImage *image)
2346 {
2347 gpointer iter = NULL;
2348 MonoType *p;
2349
2350 while ((p = mono_signature_get_params (sig, &iter)) != NULL)
2351 if (type_in_image (p, image))
2352 return TRUE;
2353
2354 return type_in_image (mono_signature_get_return_type (sig), image);
2355 }
2356
2357 static gboolean
ginst_in_image(MonoGenericInst * ginst,MonoImage * image)2358 ginst_in_image (MonoGenericInst *ginst, MonoImage *image)
2359 {
2360 int i;
2361
2362 for (i = 0; i < ginst->type_argc; ++i) {
2363 if (type_in_image (ginst->type_argv [i], image))
2364 return TRUE;
2365 }
2366
2367 return FALSE;
2368 }
2369
2370 static gboolean
gclass_in_image(MonoGenericClass * gclass,MonoImage * image)2371 gclass_in_image (MonoGenericClass *gclass, MonoImage *image)
2372 {
2373 return gclass->container_class->image == image ||
2374 ginst_in_image (gclass->context.class_inst, image);
2375 }
2376
2377 static gboolean
type_in_image(MonoType * type,MonoImage * image)2378 type_in_image (MonoType *type, MonoImage *image)
2379 {
2380 retry:
2381 switch (type->type) {
2382 case MONO_TYPE_GENERICINST:
2383 return gclass_in_image (type->data.generic_class, image);
2384 case MONO_TYPE_PTR:
2385 type = type->data.type;
2386 goto retry;
2387 case MONO_TYPE_SZARRAY:
2388 type = &type->data.klass->byval_arg;
2389 goto retry;
2390 case MONO_TYPE_ARRAY:
2391 type = &type->data.array->eklass->byval_arg;
2392 goto retry;
2393 case MONO_TYPE_FNPTR:
2394 return signature_in_image (type->data.method, image);
2395 case MONO_TYPE_VAR:
2396 case MONO_TYPE_MVAR:
2397 return image == get_image_for_generic_param (type->data.generic_param);
2398 default:
2399 /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type () */
2400 return image == mono_class_from_mono_type (type)->image;
2401 }
2402 }
2403
2404 static inline void
image_sets_lock(void)2405 image_sets_lock (void)
2406 {
2407 mono_os_mutex_lock (&image_sets_mutex);
2408 }
2409
2410 static inline void
image_sets_unlock(void)2411 image_sets_unlock (void)
2412 {
2413 mono_os_mutex_unlock (&image_sets_mutex);
2414 }
2415
2416 static int
compare_pointers(const void * a,const void * b)2417 compare_pointers (const void *a, const void *b)
2418 {
2419 return (size_t)a - (size_t)b;
2420 }
2421
2422 //1103, 1327, 1597
2423 #define HASH_TABLE_SIZE 1103
2424 static MonoImageSet *img_set_cache [HASH_TABLE_SIZE];
2425
2426 static guint32
mix_hash(uintptr_t source)2427 mix_hash (uintptr_t source)
2428 {
2429 unsigned int hash = source;
2430
2431 // Actual hash
2432 hash = (((hash * 215497) >> 16) ^ ((hash * 1823231) + hash));
2433
2434 // Mix in highest bits on 64-bit systems only
2435 if (sizeof (source) > 4)
2436 hash = hash ^ (source >> 32);
2437
2438 return hash;
2439 }
2440
2441 static guint32
hash_images(MonoImage ** images,int nimages)2442 hash_images (MonoImage **images, int nimages)
2443 {
2444 guint32 res = 0;
2445 int i;
2446 for (i = 0; i < nimages; ++i)
2447 res += mix_hash ((size_t)images [i]);
2448
2449 return res;
2450 }
2451
2452 static gboolean
compare_img_set(MonoImageSet * set,MonoImage ** images,int nimages)2453 compare_img_set (MonoImageSet *set, MonoImage **images, int nimages)
2454 {
2455 int j, k;
2456
2457 if (set->nimages != nimages)
2458 return FALSE;
2459
2460 for (j = 0; j < nimages; ++j) {
2461 for (k = 0; k < nimages; ++k)
2462 if (set->images [k] == images [j])
2463 break; // Break on match
2464
2465 // If we iterated all the way through set->images, images[j] was *not* found.
2466 if (k == nimages)
2467 break; // Break on "image not found"
2468 }
2469
2470 // If we iterated all the way through images without breaking, all items in images were found in set->images
2471 return j == nimages;
2472 }
2473
2474
2475 static MonoImageSet*
img_set_cache_get(MonoImage ** images,int nimages)2476 img_set_cache_get (MonoImage **images, int nimages)
2477 {
2478 guint32 hash_code = hash_images (images, nimages);
2479 int index = hash_code % HASH_TABLE_SIZE;
2480 MonoImageSet *img = img_set_cache [index];
2481 if (!img || !compare_img_set (img, images, nimages)) {
2482 UnlockedIncrement (&img_set_cache_miss);
2483 return NULL;
2484 }
2485 UnlockedIncrement (&img_set_cache_hit);
2486 return img;
2487 }
2488
2489 static void
img_set_cache_add(MonoImageSet * set)2490 img_set_cache_add (MonoImageSet *set)
2491 {
2492 guint32 hash_code = hash_images (set->images, set->nimages);
2493 int index = hash_code % HASH_TABLE_SIZE;
2494 img_set_cache [index] = set;
2495 }
2496
2497 static void
img_set_cache_remove(MonoImageSet * is)2498 img_set_cache_remove (MonoImageSet *is)
2499 {
2500 guint32 hash_code = hash_images (is->images, is->nimages);
2501 int index = hash_code % HASH_TABLE_SIZE;
2502 if (img_set_cache [index] == is)
2503 img_set_cache [index] = NULL;
2504 }
2505 /*
2506 * get_image_set:
2507 *
2508 * Return a MonoImageSet representing the set of images in IMAGES.
2509 */
2510 static MonoImageSet*
get_image_set(MonoImage ** images,int nimages)2511 get_image_set (MonoImage **images, int nimages)
2512 {
2513 int i, j, k;
2514 MonoImageSet *set;
2515 GSList *l;
2516
2517 /* Common case: Image set contains corlib only. If we've seen that case before, we cached the set. */
2518 if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set)
2519 return mscorlib_image_set;
2520
2521 /* Happens with empty generic instances */
2522 // 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.
2523 if (nimages == 0)
2524 return mscorlib_image_set;
2525
2526 set = img_set_cache_get (images, nimages);
2527 if (set)
2528 return set;
2529
2530 image_sets_lock ();
2531
2532 if (!image_sets)
2533 image_sets = g_ptr_array_new ();
2534
2535 // Before we go on, we should check to see whether a MonoImageSet with these images already exists.
2536 // We can search the referred-by imagesets of any one of our images to do this. Arbitrarily pick one here:
2537 if (images [0] == mono_defaults.corlib && nimages > 1)
2538 l = images [1]->image_sets; // Prefer not to search the imagesets of corlib-- that will be a long list.
2539 else
2540 l = images [0]->image_sets;
2541
2542 set = NULL;
2543 while (l) // Iterate over selected list, looking for an imageset with members equal to our target one
2544 {
2545 set = (MonoImageSet *)l->data;
2546
2547 if (set->nimages == nimages) { // Member count differs, this can't be it
2548 // Compare all members to all members-- order might be different
2549 for (j = 0; j < nimages; ++j) {
2550 for (k = 0; k < nimages; ++k)
2551 if (set->images [k] == images [j])
2552 break; // Break on match
2553
2554 // If we iterated all the way through set->images, images[j] was *not* found.
2555 if (k == nimages)
2556 break; // Break on "image not found"
2557 }
2558
2559 // If we iterated all the way through images without breaking, all items in images were found in set->images
2560 if (j == nimages) {
2561 // Break on "found a set with equal members".
2562 // This happens in case of a hash collision with a previously cached set.
2563 break;
2564 }
2565 }
2566
2567 l = l->next;
2568 }
2569
2570 // If we iterated all the way through l without breaking, the imageset does not already exist and we should create it
2571 if (!l) {
2572 set = g_new0 (MonoImageSet, 1);
2573 set->nimages = nimages;
2574 set->images = g_new0 (MonoImage*, nimages);
2575 mono_os_mutex_init_recursive (&set->lock);
2576 for (i = 0; i < nimages; ++i)
2577 set->images [i] = images [i];
2578 set->gclass_cache = mono_conc_hashtable_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
2579 set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
2580 set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
2581 set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
2582
2583 set->szarray_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2584 set->array_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL);
2585
2586 for (i = 0; i < nimages; ++i)
2587 set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set);
2588
2589 g_ptr_array_add (image_sets, set);
2590 UnlockedIncrement (&img_set_count); /* locked by image_sets_lock () */
2591 }
2592
2593 /* Cache the set. If there was a cache collision, the previously cached value will be replaced. */
2594 img_set_cache_add (set);
2595
2596 if (nimages == 1 && images [0] == mono_defaults.corlib) {
2597 mono_memory_barrier ();
2598 mscorlib_image_set = set;
2599 }
2600
2601 image_sets_unlock ();
2602
2603 return set;
2604 }
2605
2606 static void
delete_image_set(MonoImageSet * set)2607 delete_image_set (MonoImageSet *set)
2608 {
2609 int i;
2610
2611 mono_conc_hashtable_destroy (set->gclass_cache);
2612 g_hash_table_destroy (set->ginst_cache);
2613 g_hash_table_destroy (set->gmethod_cache);
2614 g_hash_table_destroy (set->gsignature_cache);
2615
2616 g_hash_table_destroy (set->szarray_cache);
2617 g_hash_table_destroy (set->array_cache);
2618 if (set->ptr_cache)
2619 g_hash_table_destroy (set->ptr_cache);
2620
2621 mono_wrapper_caches_free (&set->wrapper_caches);
2622
2623 image_sets_lock ();
2624
2625 for (i = 0; i < set->nimages; ++i)
2626 set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set);
2627
2628 g_ptr_array_remove (image_sets, set);
2629
2630 image_sets_unlock ();
2631
2632 img_set_cache_remove (set);
2633
2634 if (set->mempool)
2635 mono_mempool_destroy (set->mempool);
2636 g_free (set->images);
2637 mono_os_mutex_destroy (&set->lock);
2638 g_free (set);
2639 }
2640
2641 void
mono_image_set_lock(MonoImageSet * set)2642 mono_image_set_lock (MonoImageSet *set)
2643 {
2644 mono_os_mutex_lock (&set->lock);
2645 }
2646
2647 void
mono_image_set_unlock(MonoImageSet * set)2648 mono_image_set_unlock (MonoImageSet *set)
2649 {
2650 mono_os_mutex_unlock (&set->lock);
2651 }
2652
2653 gpointer
mono_image_set_alloc(MonoImageSet * set,guint size)2654 mono_image_set_alloc (MonoImageSet *set, guint size)
2655 {
2656 gpointer res;
2657
2658 mono_image_set_lock (set);
2659 if (!set->mempool)
2660 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2661 res = mono_mempool_alloc (set->mempool, size);
2662 mono_image_set_unlock (set);
2663
2664 return res;
2665 }
2666
2667 gpointer
mono_image_set_alloc0(MonoImageSet * set,guint size)2668 mono_image_set_alloc0 (MonoImageSet *set, guint size)
2669 {
2670 gpointer res;
2671
2672 mono_image_set_lock (set);
2673 if (!set->mempool)
2674 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2675 res = mono_mempool_alloc0 (set->mempool, size);
2676 mono_image_set_unlock (set);
2677
2678 return res;
2679 }
2680
2681 char*
mono_image_set_strdup(MonoImageSet * set,const char * s)2682 mono_image_set_strdup (MonoImageSet *set, const char *s)
2683 {
2684 char *res;
2685
2686 mono_image_set_lock (set);
2687 if (!set->mempool)
2688 set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE);
2689 res = mono_mempool_strdup (set->mempool, s);
2690 mono_image_set_unlock (set);
2691
2692 return res;
2693 }
2694
2695 // Get a descriptive string for a MonoImageSet
2696 // Callers are obligated to free buffer with g_free after use
2697 char *
mono_image_set_description(MonoImageSet * set)2698 mono_image_set_description (MonoImageSet *set)
2699 {
2700 GString *result = g_string_new (NULL);
2701 int img;
2702 g_string_append (result, "[");
2703 for (img = 0; img < set->nimages; img++)
2704 {
2705 if (img > 0)
2706 g_string_append (result, ", ");
2707 g_string_append (result, set->images[img]->name);
2708 }
2709 g_string_append (result, "]");
2710 return g_string_free (result, FALSE);
2711 }
2712
2713 /*
2714 * Structure used by the collect_..._images functions to store the image list.
2715 */
2716 typedef struct {
2717 MonoImage *image_buf [64];
2718 MonoImage **images;
2719 int nimages, images_len;
2720 } CollectData;
2721
2722 static void
collect_data_init(CollectData * data)2723 collect_data_init (CollectData *data)
2724 {
2725 data->images = data->image_buf;
2726 data->images_len = 64;
2727 data->nimages = 0;
2728 }
2729
2730 static void
collect_data_free(CollectData * data)2731 collect_data_free (CollectData *data)
2732 {
2733 if (data->images != data->image_buf)
2734 g_free (data->images);
2735 }
2736
2737 static void
enlarge_data(CollectData * data)2738 enlarge_data (CollectData *data)
2739 {
2740 int new_len = data->images_len < 16 ? 16 : data->images_len * 2;
2741 MonoImage **d = g_new (MonoImage *, new_len);
2742
2743 // FIXME: test this
2744 g_assert_not_reached ();
2745 memcpy (d, data->images, data->images_len);
2746 if (data->images != data->image_buf)
2747 g_free (data->images);
2748 data->images = d;
2749 data->images_len = new_len;
2750 }
2751
2752 static inline void
add_image(MonoImage * image,CollectData * data)2753 add_image (MonoImage *image, CollectData *data)
2754 {
2755 int i;
2756
2757 /* The arrays are small, so use a linear search instead of a hash table */
2758 for (i = 0; i < data->nimages; ++i)
2759 if (data->images [i] == image)
2760 return;
2761
2762 if (data->nimages == data->images_len)
2763 enlarge_data (data);
2764
2765 data->images [data->nimages ++] = image;
2766 }
2767
2768 static void
2769 collect_type_images (MonoType *type, CollectData *data);
2770
2771 static void
collect_ginst_images(MonoGenericInst * ginst,CollectData * data)2772 collect_ginst_images (MonoGenericInst *ginst, CollectData *data)
2773 {
2774 int i;
2775
2776 for (i = 0; i < ginst->type_argc; ++i) {
2777 collect_type_images (ginst->type_argv [i], data);
2778 }
2779 }
2780
2781 static void
collect_gclass_images(MonoGenericClass * gclass,CollectData * data)2782 collect_gclass_images (MonoGenericClass *gclass, CollectData *data)
2783 {
2784 add_image (gclass->container_class->image, data);
2785 if (gclass->context.class_inst)
2786 collect_ginst_images (gclass->context.class_inst, data);
2787 }
2788
2789 static void
collect_signature_images(MonoMethodSignature * sig,CollectData * data)2790 collect_signature_images (MonoMethodSignature *sig, CollectData *data)
2791 {
2792 gpointer iter = NULL;
2793 MonoType *p;
2794
2795 collect_type_images (mono_signature_get_return_type (sig), data);
2796 while ((p = mono_signature_get_params (sig, &iter)) != NULL)
2797 collect_type_images (p, data);
2798 }
2799
2800 static void
collect_inflated_signature_images(MonoInflatedMethodSignature * sig,CollectData * data)2801 collect_inflated_signature_images (MonoInflatedMethodSignature *sig, CollectData *data)
2802 {
2803 collect_signature_images (sig->sig, data);
2804 if (sig->context.class_inst)
2805 collect_ginst_images (sig->context.class_inst, data);
2806 if (sig->context.method_inst)
2807 collect_ginst_images (sig->context.method_inst, data);
2808 }
2809
2810 static void
collect_method_images(MonoMethodInflated * method,CollectData * data)2811 collect_method_images (MonoMethodInflated *method, CollectData *data)
2812 {
2813 MonoMethod *m = method->declaring;
2814
2815 add_image (method->declaring->klass->image, data);
2816 if (method->context.class_inst)
2817 collect_ginst_images (method->context.class_inst, data);
2818 if (method->context.method_inst)
2819 collect_ginst_images (method->context.method_inst, data);
2820 /*
2821 * Dynamic assemblies have no references, so the images they depend on can be unloaded before them.
2822 */
2823 if (image_is_dynamic (m->klass->image))
2824 collect_signature_images (mono_method_signature (m), data);
2825 }
2826
2827 static void
collect_type_images(MonoType * type,CollectData * data)2828 collect_type_images (MonoType *type, CollectData *data)
2829 {
2830 retry:
2831 switch (type->type) {
2832 case MONO_TYPE_GENERICINST:
2833 collect_gclass_images (type->data.generic_class, data);
2834 break;
2835 case MONO_TYPE_PTR:
2836 type = type->data.type;
2837 goto retry;
2838 case MONO_TYPE_SZARRAY:
2839 type = &type->data.klass->byval_arg;
2840 goto retry;
2841 case MONO_TYPE_ARRAY:
2842 type = &type->data.array->eklass->byval_arg;
2843 goto retry;
2844 case MONO_TYPE_FNPTR:
2845 //return signature_in_image (type->data.method, image);
2846 g_assert_not_reached ();
2847 case MONO_TYPE_VAR:
2848 case MONO_TYPE_MVAR:
2849 {
2850 MonoImage *image = get_image_for_generic_param (type->data.generic_param);
2851 add_image (image, data);
2852 break;
2853 }
2854 case MONO_TYPE_CLASS:
2855 case MONO_TYPE_VALUETYPE:
2856 add_image (mono_class_from_mono_type (type)->image, data);
2857 break;
2858 default:
2859 add_image (mono_defaults.corlib, data);
2860 }
2861 }
2862
2863 typedef struct {
2864 MonoImage *image;
2865 GSList *list;
2866 } CleanForImageUserData;
2867
2868 static gboolean
steal_gclass_in_image(gpointer key,gpointer value,gpointer data)2869 steal_gclass_in_image (gpointer key, gpointer value, gpointer data)
2870 {
2871 MonoGenericClass *gclass = (MonoGenericClass *)key;
2872 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
2873
2874 g_assert (gclass_in_image (gclass, user_data->image));
2875
2876 user_data->list = g_slist_prepend (user_data->list, gclass);
2877 return TRUE;
2878 }
2879
2880 static gboolean
steal_ginst_in_image(gpointer key,gpointer value,gpointer data)2881 steal_ginst_in_image (gpointer key, gpointer value, gpointer data)
2882 {
2883 MonoGenericInst *ginst = (MonoGenericInst *)key;
2884 CleanForImageUserData *user_data = (CleanForImageUserData *)data;
2885
2886 // This doesn't work during corlib compilation
2887 //g_assert (ginst_in_image (ginst, user_data->image));
2888
2889 user_data->list = g_slist_prepend (user_data->list, ginst);
2890 return TRUE;
2891 }
2892
2893 static gboolean
inflated_method_in_image(gpointer key,gpointer value,gpointer data)2894 inflated_method_in_image (gpointer key, gpointer value, gpointer data)
2895 {
2896 MonoImage *image = (MonoImage *)data;
2897 MonoMethodInflated *method = (MonoMethodInflated *)key;
2898
2899 // FIXME:
2900 // https://bugzilla.novell.com/show_bug.cgi?id=458168
2901 g_assert (method->declaring->klass->image == image ||
2902 (method->context.class_inst && ginst_in_image (method->context.class_inst, image)) ||
2903 (method->context.method_inst && ginst_in_image (method->context.method_inst, image)) || (((MonoMethod*)method)->signature && signature_in_image (mono_method_signature ((MonoMethod*)method), image)));
2904
2905 return TRUE;
2906 }
2907
2908 static gboolean
inflated_signature_in_image(gpointer key,gpointer value,gpointer data)2909 inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
2910 {
2911 MonoImage *image = (MonoImage *)data;
2912 MonoInflatedMethodSignature *sig = (MonoInflatedMethodSignature *)key;
2913
2914 return signature_in_image (sig->sig, image) ||
2915 (sig->context.class_inst && ginst_in_image (sig->context.class_inst, image)) ||
2916 (sig->context.method_inst && ginst_in_image (sig->context.method_inst, image));
2917 }
2918
2919 static gboolean
class_in_image(gpointer key,gpointer value,gpointer data)2920 class_in_image (gpointer key, gpointer value, gpointer data)
2921 {
2922 MonoImage *image = (MonoImage *)data;
2923 MonoClass *klass = (MonoClass *)key;
2924
2925 g_assert (type_in_image (&klass->byval_arg, image));
2926
2927 return TRUE;
2928 }
2929
2930 static void
check_gmethod(gpointer key,gpointer value,gpointer data)2931 check_gmethod (gpointer key, gpointer value, gpointer data)
2932 {
2933 MonoMethodInflated *method = (MonoMethodInflated *)key;
2934 MonoImage *image = (MonoImage *)data;
2935
2936 if (method->context.class_inst)
2937 g_assert (!ginst_in_image (method->context.class_inst, image));
2938 if (method->context.method_inst)
2939 g_assert (!ginst_in_image (method->context.method_inst, image));
2940 if (((MonoMethod*)method)->signature)
2941 g_assert (!signature_in_image (mono_method_signature ((MonoMethod*)method), image));
2942 }
2943
2944 /*
2945 * check_image_sets:
2946 *
2947 * Run a consistency check on the image set data structures.
2948 */
2949 static G_GNUC_UNUSED void
check_image_sets(MonoImage * image)2950 check_image_sets (MonoImage *image)
2951 {
2952 int i;
2953 GSList *l = image->image_sets;
2954
2955 if (!image_sets)
2956 return;
2957
2958 for (i = 0; i < image_sets->len; ++i) {
2959 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
2960
2961 if (!g_slist_find (l, set)) {
2962 g_hash_table_foreach (set->gmethod_cache, check_gmethod, image);
2963 }
2964 }
2965 }
2966
2967 void
mono_metadata_clean_for_image(MonoImage * image)2968 mono_metadata_clean_for_image (MonoImage *image)
2969 {
2970 CleanForImageUserData ginst_data, gclass_data;
2971 GSList *l, *set_list;
2972
2973 //check_image_sets (image);
2974
2975 /*
2976 * The data structures could reference each other so we delete them in two phases.
2977 * This is required because of the hashing functions in gclass/ginst_cache.
2978 */
2979 ginst_data.image = gclass_data.image = image;
2980 ginst_data.list = gclass_data.list = NULL;
2981
2982 /* Collect the items to delete */
2983 /* delete_image_set () modifies the lists so make a copy */
2984 for (l = image->image_sets; l; l = l->next) {
2985 MonoImageSet *set = (MonoImageSet *)l->data;
2986
2987 mono_image_set_lock (set);
2988 mono_conc_hashtable_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data);
2989 g_hash_table_foreach_steal (set->ginst_cache, steal_ginst_in_image, &ginst_data);
2990 g_hash_table_foreach_remove (set->gmethod_cache, inflated_method_in_image, image);
2991 g_hash_table_foreach_remove (set->gsignature_cache, inflated_signature_in_image, image);
2992
2993 g_hash_table_foreach_steal (set->szarray_cache, class_in_image, image);
2994 g_hash_table_foreach_steal (set->array_cache, class_in_image, image);
2995 if (set->ptr_cache)
2996 g_hash_table_foreach_steal (set->ptr_cache, class_in_image, image);
2997 mono_image_set_unlock (set);
2998 }
2999
3000 /* Delete the removed items */
3001 for (l = ginst_data.list; l; l = l->next)
3002 free_generic_inst ((MonoGenericInst *)l->data);
3003 for (l = gclass_data.list; l; l = l->next)
3004 free_generic_class ((MonoGenericClass *)l->data);
3005 g_slist_free (ginst_data.list);
3006 g_slist_free (gclass_data.list);
3007 /* delete_image_set () modifies the lists so make a copy */
3008 set_list = g_slist_copy (image->image_sets);
3009 for (l = set_list; l; l = l->next) {
3010 MonoImageSet *set = (MonoImageSet *)l->data;
3011
3012 delete_image_set (set);
3013 }
3014 g_slist_free (set_list);
3015 }
3016
3017 static void
free_inflated_method(MonoMethodInflated * imethod)3018 free_inflated_method (MonoMethodInflated *imethod)
3019 {
3020 MonoMethod *method = (MonoMethod*)imethod;
3021
3022 if (method->signature)
3023 mono_metadata_free_inflated_signature (method->signature);
3024
3025 if (method->wrapper_type)
3026 g_free (((MonoMethodWrapper*)method)->method_data);
3027
3028 g_free (method);
3029 }
3030
3031 static void
free_generic_inst(MonoGenericInst * ginst)3032 free_generic_inst (MonoGenericInst *ginst)
3033 {
3034 int i;
3035
3036 /* The ginst itself is allocated from the image set mempool */
3037 for (i = 0; i < ginst->type_argc; ++i)
3038 mono_metadata_free_type (ginst->type_argv [i]);
3039 }
3040
3041 static void
free_generic_class(MonoGenericClass * gclass)3042 free_generic_class (MonoGenericClass *gclass)
3043 {
3044 /* The gclass itself is allocated from the image set mempool */
3045 if (gclass->cached_class && gclass->cached_class->interface_id)
3046 mono_unload_interface_id (gclass->cached_class);
3047 }
3048
3049 static void
free_inflated_signature(MonoInflatedMethodSignature * sig)3050 free_inflated_signature (MonoInflatedMethodSignature *sig)
3051 {
3052 mono_metadata_free_inflated_signature (sig->sig);
3053 g_free (sig);
3054 }
3055
3056 /*
3057 * mono_metadata_get_inflated_signature:
3058 *
3059 * Given an inflated signature and a generic context, return a canonical copy of the
3060 * signature. The returned signature might be equal to SIG or it might be a cached copy.
3061 */
3062 MonoMethodSignature *
mono_metadata_get_inflated_signature(MonoMethodSignature * sig,MonoGenericContext * context)3063 mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericContext *context)
3064 {
3065 MonoInflatedMethodSignature helper;
3066 MonoInflatedMethodSignature *res;
3067 CollectData data;
3068 MonoImageSet *set;
3069
3070 helper.sig = sig;
3071 helper.context.class_inst = context->class_inst;
3072 helper.context.method_inst = context->method_inst;
3073
3074 collect_data_init (&data);
3075
3076 collect_inflated_signature_images (&helper, &data);
3077
3078 set = get_image_set (data.images, data.nimages);
3079
3080 collect_data_free (&data);
3081
3082 mono_image_set_lock (set);
3083
3084 res = (MonoInflatedMethodSignature *)g_hash_table_lookup (set->gsignature_cache, &helper);
3085 if (!res) {
3086 res = g_new0 (MonoInflatedMethodSignature, 1);
3087 res->sig = sig;
3088 res->context.class_inst = context->class_inst;
3089 res->context.method_inst = context->method_inst;
3090 g_hash_table_insert (set->gsignature_cache, res, res);
3091 }
3092
3093 mono_image_set_unlock (set);
3094
3095 return res->sig;
3096 }
3097
3098 MonoImageSet *
mono_metadata_get_image_set_for_class(MonoClass * klass)3099 mono_metadata_get_image_set_for_class (MonoClass *klass)
3100 {
3101 MonoImageSet *set;
3102 CollectData image_set_data;
3103
3104 collect_data_init (&image_set_data);
3105 collect_type_images (&klass->byval_arg, &image_set_data);
3106 set = get_image_set (image_set_data.images, image_set_data.nimages);
3107 collect_data_free (&image_set_data);
3108
3109 return set;
3110 }
3111
3112 MonoImageSet *
mono_metadata_get_image_set_for_method(MonoMethodInflated * method)3113 mono_metadata_get_image_set_for_method (MonoMethodInflated *method)
3114 {
3115 MonoImageSet *set;
3116 CollectData image_set_data;
3117
3118 collect_data_init (&image_set_data);
3119 collect_method_images (method, &image_set_data);
3120 set = get_image_set (image_set_data.images, image_set_data.nimages);
3121 collect_data_free (&image_set_data);
3122
3123 return set;
3124 }
3125
3126 static gboolean
type_is_gtd(MonoType * type)3127 type_is_gtd (MonoType *type)
3128 {
3129 switch (type->type) {
3130 case MONO_TYPE_CLASS:
3131 case MONO_TYPE_VALUETYPE:
3132 return mono_class_is_gtd (type->data.klass);
3133 default:
3134 return FALSE;
3135 }
3136 }
3137
3138 /*
3139 * mono_metadata_get_generic_inst:
3140 *
3141 * Given a list of types, return a MonoGenericInst that represents that list.
3142 * The returned MonoGenericInst has its own copy of the list of types. The list
3143 * passed in the argument can be freed, modified or disposed of.
3144 *
3145 */
3146 MonoGenericInst *
mono_metadata_get_generic_inst(int type_argc,MonoType ** type_argv)3147 mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
3148 {
3149 MonoGenericInst *ginst;
3150 gboolean is_open;
3151 int i;
3152 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3153
3154 for (i = 0; i < type_argc; ++i)
3155 if (mono_class_is_open_constructed_type (type_argv [i]))
3156 break;
3157 is_open = (i < type_argc);
3158
3159 ginst = (MonoGenericInst *)g_alloca (size);
3160 memset (ginst, 0, sizeof (MonoGenericInst));
3161 ginst->is_open = is_open;
3162 ginst->type_argc = type_argc;
3163 memcpy (ginst->type_argv, type_argv, type_argc * sizeof (MonoType *));
3164
3165 for (i = 0; i < type_argc; ++i) {
3166 MonoType *t = ginst->type_argv [i];
3167 if (type_is_gtd (t)) {
3168 ginst->type_argv [i] = mono_class_gtd_get_canonical_inst (t->data.klass);
3169 }
3170 }
3171
3172 return mono_metadata_get_canonical_generic_inst (ginst);
3173 }
3174
3175
3176 /**
3177 * mono_metadata_get_canonical_generic_inst:
3178 * \param candidate an arbitrary generic instantiation
3179 *
3180 * \returns the canonical generic instantiation that represents the given
3181 * candidate by identifying the image set for the candidate instantiation and
3182 * finding the instance in the image set or adding a copy of the given instance
3183 * to the image set.
3184 *
3185 * The returned MonoGenericInst has its own copy of the list of types. The list
3186 * passed in the argument can be freed, modified or disposed of.
3187 *
3188 */
3189 MonoGenericInst *
mono_metadata_get_canonical_generic_inst(MonoGenericInst * candidate)3190 mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate)
3191 {
3192 CollectData data;
3193 int type_argc = candidate->type_argc;
3194 gboolean is_open = candidate->is_open;
3195 MonoImageSet *set;
3196
3197 collect_data_init (&data);
3198
3199 collect_ginst_images (candidate, &data);
3200
3201 set = get_image_set (data.images, data.nimages);
3202
3203 collect_data_free (&data);
3204
3205 mono_image_set_lock (set);
3206
3207 MonoGenericInst *ginst = (MonoGenericInst *)g_hash_table_lookup (set->ginst_cache, candidate);
3208 if (!ginst) {
3209 int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
3210 ginst = (MonoGenericInst *)mono_image_set_alloc0 (set, size);
3211 #ifndef MONO_SMALL_CONFIG
3212 ginst->id = mono_atomic_inc_i32 (&next_generic_inst_id);
3213 #endif
3214 ginst->is_open = is_open;
3215 ginst->type_argc = type_argc;
3216
3217 for (int i = 0; i < type_argc; ++i)
3218 ginst->type_argv [i] = mono_metadata_type_dup (NULL, candidate->type_argv [i]);
3219
3220 g_hash_table_insert (set->ginst_cache, ginst, ginst);
3221 }
3222
3223 mono_image_set_unlock (set);
3224 return ginst;
3225 }
3226
3227 static gboolean
mono_metadata_is_type_builder_generic_type_definition(MonoClass * container_class,MonoGenericInst * inst,gboolean is_dynamic)3228 mono_metadata_is_type_builder_generic_type_definition (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3229 {
3230 MonoGenericContainer *container = mono_class_get_generic_container (container_class);
3231
3232 if (!is_dynamic || container_class->wastypebuilder || container->type_argc != inst->type_argc)
3233 return FALSE;
3234 return inst == container->context.class_inst;
3235 }
3236
3237 /*
3238 * mono_metadata_lookup_generic_class:
3239 *
3240 * Returns a MonoGenericClass with the given properties.
3241 *
3242 */
3243 MonoGenericClass *
mono_metadata_lookup_generic_class(MonoClass * container_class,MonoGenericInst * inst,gboolean is_dynamic)3244 mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
3245 {
3246 MonoGenericClass *gclass;
3247 MonoGenericClass helper;
3248 gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic);
3249 MonoImageSet *set;
3250 CollectData data;
3251
3252 g_assert (mono_class_get_generic_container (container_class)->type_argc == inst->type_argc);
3253
3254 memset (&helper, 0, sizeof(helper)); // act like g_new0
3255 helper.container_class = container_class;
3256 helper.context.class_inst = inst;
3257 helper.is_dynamic = is_dynamic; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
3258 helper.is_tb_open = is_tb_open;
3259
3260 collect_data_init (&data);
3261
3262 collect_gclass_images (&helper, &data);
3263
3264 set = get_image_set (data.images, data.nimages);
3265
3266 collect_data_free (&data);
3267
3268 gclass = (MonoGenericClass *)mono_conc_hashtable_lookup (set->gclass_cache, &helper);
3269
3270 /* A tripwire just to keep us honest */
3271 g_assert (!helper.cached_class);
3272
3273 if (gclass)
3274 return gclass;
3275
3276 gclass = mono_image_set_new0 (set, MonoGenericClass, 1);
3277 if (is_dynamic)
3278 gclass->is_dynamic = 1;
3279
3280 gclass->is_tb_open = is_tb_open;
3281 gclass->container_class = container_class;
3282 gclass->context.class_inst = inst;
3283 gclass->context.method_inst = NULL;
3284 gclass->owner = set;
3285 if (inst == mono_class_get_generic_container (container_class)->context.class_inst && !is_tb_open)
3286 gclass->cached_class = container_class;
3287
3288 mono_image_set_lock (set);
3289
3290 MonoGenericClass *gclass2 = mono_conc_hashtable_insert (set->gclass_cache, gclass, gclass);
3291 if (!gclass2)
3292 gclass2 = gclass;
3293
3294 // g_hash_table_insert (set->gclass_cache, gclass, gclass);
3295
3296 mono_image_set_unlock (set);
3297
3298 return gclass2;
3299 }
3300
3301 /*
3302 * mono_metadata_inflate_generic_inst:
3303 *
3304 * Instantiate the generic instance @ginst with the context @context.
3305 * Check @error for success.
3306 *
3307 */
3308 MonoGenericInst *
mono_metadata_inflate_generic_inst(MonoGenericInst * ginst,MonoGenericContext * context,MonoError * error)3309 mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context, MonoError *error)
3310 {
3311 MonoType **type_argv;
3312 MonoGenericInst *nginst = NULL;
3313 int i, count = 0;
3314
3315 error_init (error);
3316
3317 if (!ginst->is_open)
3318 return ginst;
3319
3320 type_argv = g_new0 (MonoType*, ginst->type_argc);
3321
3322 for (i = 0; i < ginst->type_argc; i++) {
3323 type_argv [i] = mono_class_inflate_generic_type_checked (ginst->type_argv [i], context, error);
3324 if (!mono_error_ok (error))
3325 goto cleanup;
3326 ++count;
3327 }
3328
3329 nginst = mono_metadata_get_generic_inst (ginst->type_argc, type_argv);
3330
3331 cleanup:
3332 for (i = 0; i < count; i++)
3333 mono_metadata_free_type (type_argv [i]);
3334 g_free (type_argv);
3335
3336 return nginst;
3337 }
3338
3339 MonoGenericInst *
mono_metadata_parse_generic_inst(MonoImage * m,MonoGenericContainer * container,int count,const char * ptr,const char ** rptr,MonoError * error)3340 mono_metadata_parse_generic_inst (MonoImage *m, MonoGenericContainer *container,
3341 int count, const char *ptr, const char **rptr, MonoError *error)
3342 {
3343 MonoType **type_argv;
3344 MonoGenericInst *ginst;
3345 int i;
3346
3347 error_init (error);
3348 type_argv = g_new0 (MonoType*, count);
3349
3350 for (i = 0; i < count; i++) {
3351 MonoType *t = mono_metadata_parse_type_checked (m, container, 0, FALSE, ptr, &ptr, error);
3352 if (!t) {
3353 g_free (type_argv);
3354 return NULL;
3355 }
3356 type_argv [i] = t;
3357 }
3358
3359 if (rptr)
3360 *rptr = ptr;
3361
3362 ginst = mono_metadata_get_generic_inst (count, type_argv);
3363
3364 g_free (type_argv);
3365
3366 return ginst;
3367 }
3368
3369 static gboolean
do_mono_metadata_parse_generic_class(MonoType * type,MonoImage * m,MonoGenericContainer * container,const char * ptr,const char ** rptr,MonoError * error)3370 do_mono_metadata_parse_generic_class (MonoType *type, MonoImage *m, MonoGenericContainer *container,
3371 const char *ptr, const char **rptr, MonoError *error)
3372 {
3373 MonoGenericInst *inst;
3374 MonoClass *gklass;
3375 MonoType *gtype;
3376 int count;
3377
3378 error_init (error);
3379
3380 // XXX how about transient?
3381 gtype = mono_metadata_parse_type_checked (m, NULL, 0, FALSE, ptr, &ptr, error);
3382 if (gtype == NULL)
3383 return FALSE;
3384
3385 gklass = mono_class_from_mono_type (gtype);
3386 if (!mono_class_is_gtd (gklass)) {
3387 mono_error_set_bad_image (error, m, "Generic instance with non-generic definition");
3388 return FALSE;
3389 }
3390
3391 count = mono_metadata_decode_value (ptr, &ptr);
3392 inst = mono_metadata_parse_generic_inst (m, container, count, ptr, &ptr, error);
3393 if (inst == NULL)
3394 return FALSE;
3395
3396 if (rptr)
3397 *rptr = ptr;
3398
3399 type->data.generic_class = mono_metadata_lookup_generic_class (gklass, inst, FALSE);
3400 return TRUE;
3401 }
3402
3403 /*
3404 * select_container:
3405 * @gc: The generic container to normalize
3406 * @type: The kind of generic parameters the resulting generic-container should contain
3407 */
3408
3409 static MonoGenericContainer *
select_container(MonoGenericContainer * gc,MonoTypeEnum type)3410 select_container (MonoGenericContainer *gc, MonoTypeEnum type)
3411 {
3412 gboolean is_var = (type == MONO_TYPE_VAR);
3413 if (!gc)
3414 return NULL;
3415
3416 g_assert (is_var || type == MONO_TYPE_MVAR);
3417
3418 if (is_var) {
3419 if (gc->is_method || gc->parent)
3420 /*
3421 * The current MonoGenericContainer is a generic method -> its `parent'
3422 * points to the containing class'es container.
3423 */
3424 return gc->parent;
3425 }
3426
3427 return gc;
3428 }
3429
3430 MonoGenericContainer *
get_anonymous_container_for_image(MonoImage * image,gboolean is_mvar)3431 get_anonymous_container_for_image (MonoImage *image, gboolean is_mvar)
3432 {
3433 MonoGenericContainer **container_pointer;
3434 if (is_mvar)
3435 container_pointer = &image->anonymous_generic_method_container;
3436 else
3437 container_pointer = &image->anonymous_generic_class_container;
3438 MonoGenericContainer *result = *container_pointer;
3439
3440 // This container has never been created; make it now.
3441 if (!result)
3442 {
3443 // Note this is never deallocated anywhere-- it exists for the lifetime of the image it's allocated from
3444 result = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
3445 result->owner.image = image;
3446 result->is_anonymous = TRUE;
3447 result->is_small_param = TRUE;
3448 result->is_method = is_mvar;
3449
3450 // If another thread already made a container, use that and leak this new one.
3451 // (Technically it would currently be safe to just assign instead of CASing.)
3452 MonoGenericContainer *exchange = (MonoGenericContainer *)mono_atomic_cas_ptr ((volatile gpointer *)container_pointer, result, NULL);
3453 if (exchange)
3454 result = exchange;
3455 }
3456 return result;
3457 }
3458
3459 /*
3460 * mono_metadata_parse_generic_param:
3461 * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
3462 * see mono_metadata_parse_type_checked() for details.
3463 * Internal routine to parse a generic type parameter.
3464 * LOCKING: Acquires the loader lock
3465 */
3466 static MonoGenericParam *
mono_metadata_parse_generic_param(MonoImage * m,MonoGenericContainer * generic_container,MonoTypeEnum type,const char * ptr,const char ** rptr,MonoError * error)3467 mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_container,
3468 MonoTypeEnum type, const char *ptr, const char **rptr, MonoError *error)
3469 {
3470 int index = mono_metadata_decode_value (ptr, &ptr);
3471 if (rptr)
3472 *rptr = ptr;
3473
3474 error_init (error);
3475
3476 generic_container = select_container (generic_container, type);
3477 if (!generic_container) {
3478 gboolean is_mvar = FALSE;
3479 switch (type)
3480 {
3481 case MONO_TYPE_VAR:
3482 break;
3483 case MONO_TYPE_MVAR:
3484 is_mvar = TRUE;
3485 break;
3486 default:
3487 g_error ("Cerating generic param object with invalid MonoType"); // This is not a generic param
3488 }
3489
3490 /* Create dummy MonoGenericParam */
3491 MonoGenericParam *param;
3492
3493 param = (MonoGenericParam *)mono_image_alloc0 (m, sizeof (MonoGenericParam));
3494 param->num = index;
3495 param->owner = get_anonymous_container_for_image (m, is_mvar);
3496
3497 return param;
3498 }
3499
3500 if (index >= generic_container->type_argc) {
3501 mono_error_set_bad_image (error, m, "Invalid generic %s parameter index %d, max index is %d",
3502 generic_container->is_method ? "method" : "type",
3503 index, generic_container->type_argc);
3504 return NULL;
3505 }
3506
3507 //This can't return NULL
3508 return mono_generic_container_get_param (generic_container, index);
3509 }
3510
3511 /*
3512 * mono_metadata_get_shared_type:
3513 *
3514 * Return a shared instance of TYPE, if available, NULL otherwise.
3515 * Shared MonoType instances help save memory. Their contents should not be modified
3516 * by the caller. They do not need to be freed as their lifetime is bound by either
3517 * the lifetime of the runtime (builtin types), or the lifetime of the MonoClass
3518 * instance they are embedded in. If they are freed, they should be freed using
3519 * mono_metadata_free_type () instead of g_free ().
3520 */
3521 MonoType*
mono_metadata_get_shared_type(MonoType * type)3522 mono_metadata_get_shared_type (MonoType *type)
3523 {
3524 MonoType *cached;
3525
3526 /* No need to use locking since nobody is modifying the hash table */
3527 if ((cached = (MonoType *)g_hash_table_lookup (type_cache, type)))
3528 return cached;
3529
3530 switch (type->type){
3531 case MONO_TYPE_CLASS:
3532 case MONO_TYPE_VALUETYPE:
3533 if (type == &type->data.klass->byval_arg)
3534 return type;
3535 if (type == &type->data.klass->this_arg)
3536 return type;
3537 break;
3538 default:
3539 break;
3540 }
3541
3542 return NULL;
3543 }
3544
3545 static gboolean
compare_type_literals(MonoImage * image,int class_type,int type_type,MonoError * error)3546 compare_type_literals (MonoImage *image, int class_type, int type_type, MonoError *error)
3547 {
3548 error_init (error);
3549
3550 /* byval_arg.type can be zero if we're decoding a type that references a class been loading.
3551 * See mcs/test/gtest-440. and #650936.
3552 * FIXME This better be moved to the metadata verifier as it can catch more cases.
3553 */
3554 if (!class_type)
3555 return TRUE;
3556 /* NET 1.1 assemblies might encode string and object in a denormalized way.
3557 * See #675464.
3558 */
3559 if (class_type == type_type)
3560 return TRUE;
3561
3562 if (type_type == MONO_TYPE_CLASS) {
3563 if (class_type == MONO_TYPE_STRING || class_type == MONO_TYPE_OBJECT)
3564 return TRUE;
3565 //XXX stringify this argument
3566 mono_error_set_bad_image (error, image, "Expected reference type but got type kind %d", class_type);
3567 return FALSE;
3568 }
3569
3570 g_assert (type_type == MONO_TYPE_VALUETYPE);
3571 switch (class_type) {
3572 case MONO_TYPE_BOOLEAN:
3573 case MONO_TYPE_CHAR:
3574 case MONO_TYPE_I1:
3575 case MONO_TYPE_U1:
3576 case MONO_TYPE_I2:
3577 case MONO_TYPE_U2:
3578 case MONO_TYPE_I4:
3579 case MONO_TYPE_U4:
3580 case MONO_TYPE_I8:
3581 case MONO_TYPE_U8:
3582 case MONO_TYPE_R4:
3583 case MONO_TYPE_R8:
3584 case MONO_TYPE_I:
3585 case MONO_TYPE_U:
3586 case MONO_TYPE_CLASS:
3587 return TRUE;
3588 default:
3589 //XXX stringify this argument
3590 mono_error_set_bad_image (error, image, "Expected value type but got type kind %d", class_type);
3591 return FALSE;
3592 }
3593 }
3594
3595 static gboolean
verify_var_type_and_container(MonoImage * image,int var_type,MonoGenericContainer * container,MonoError * error)3596 verify_var_type_and_container (MonoImage *image, int var_type, MonoGenericContainer *container, MonoError *error)
3597 {
3598 error_init (error);
3599 if (var_type == MONO_TYPE_MVAR) {
3600 if (!container->is_method) { //MVAR and a method container
3601 mono_error_set_bad_image (error, image, "MVAR parsed in a context without a method container");
3602 return FALSE;
3603 }
3604 } else {
3605 if (!(!container->is_method || //VAR and class container
3606 (container->is_method && container->parent))) { //VAR and method container with parent
3607 mono_error_set_bad_image (error, image, "VAR parsed in a context without a class container");
3608 return FALSE;
3609 }
3610 }
3611 return TRUE;
3612 }
3613
3614 /*
3615 * do_mono_metadata_parse_type:
3616 * @type: MonoType to be filled in with the return value
3617 * @m: image context
3618 * @generic_context: generics_context
3619 * @transient: whenever to allocate data from the heap
3620 * @ptr: pointer to the encoded type
3621 * @rptr: pointer where the end of the encoded type is saved
3622 *
3623 * Internal routine used to "fill" the contents of @type from an
3624 * allocated pointer. This is done this way to avoid doing too
3625 * many mini-allocations (particularly for the MonoFieldType which
3626 * most of the time is just a MonoType, but sometimes might be augmented).
3627 *
3628 * This routine is used by mono_metadata_parse_type and
3629 * mono_metadata_parse_field_type
3630 *
3631 * This extracts a Type as specified in Partition II (22.2.12)
3632 *
3633 * Returns: FALSE if the type could not be loaded
3634 */
3635 static gboolean
do_mono_metadata_parse_type(MonoType * type,MonoImage * m,MonoGenericContainer * container,gboolean transient,const char * ptr,const char ** rptr,MonoError * error)3636 do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container,
3637 gboolean transient, const char *ptr, const char **rptr, MonoError *error)
3638 {
3639 error_init (error);
3640
3641 type->type = (MonoTypeEnum)mono_metadata_decode_value (ptr, &ptr);
3642
3643 switch (type->type){
3644 case MONO_TYPE_VOID:
3645 case MONO_TYPE_BOOLEAN:
3646 case MONO_TYPE_CHAR:
3647 case MONO_TYPE_I1:
3648 case MONO_TYPE_U1:
3649 case MONO_TYPE_I2:
3650 case MONO_TYPE_U2:
3651 case MONO_TYPE_I4:
3652 case MONO_TYPE_U4:
3653 case MONO_TYPE_I8:
3654 case MONO_TYPE_U8:
3655 case MONO_TYPE_R4:
3656 case MONO_TYPE_R8:
3657 case MONO_TYPE_I:
3658 case MONO_TYPE_U:
3659 case MONO_TYPE_STRING:
3660 case MONO_TYPE_OBJECT:
3661 case MONO_TYPE_TYPEDBYREF:
3662 break;
3663 case MONO_TYPE_VALUETYPE:
3664 case MONO_TYPE_CLASS: {
3665 guint32 token;
3666 MonoClass *klass;
3667 token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr);
3668 klass = mono_class_get_checked (m, token, error);
3669 type->data.klass = klass;
3670 if (!klass)
3671 return FALSE;
3672
3673 if (!compare_type_literals (m, klass->byval_arg.type, type->type, error))
3674 return FALSE;
3675
3676 break;
3677 }
3678 case MONO_TYPE_SZARRAY: {
3679 MonoType *etype = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
3680 if (!etype)
3681 return FALSE;
3682
3683 type->data.klass = mono_class_from_mono_type (etype);
3684
3685 if (transient)
3686 mono_metadata_free_type (etype);
3687
3688 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.
3689 break;
3690 }
3691 case MONO_TYPE_PTR: {
3692 type->data.type = mono_metadata_parse_type_checked (m, container, 0, transient, ptr, &ptr, error);
3693 if (!type->data.type)
3694 return FALSE;
3695 break;
3696 }
3697 case MONO_TYPE_FNPTR: {
3698 type->data.method = mono_metadata_parse_method_signature_full (m, container, 0, ptr, &ptr, error);
3699 if (!type->data.method)
3700 return FALSE;
3701 break;
3702 }
3703 case MONO_TYPE_ARRAY: {
3704 type->data.array = mono_metadata_parse_array_internal (m, container, transient, ptr, &ptr, error);
3705 if (!type->data.array)
3706 return FALSE;
3707 break;
3708 }
3709 case MONO_TYPE_MVAR:
3710 case MONO_TYPE_VAR: {
3711 if (container && !verify_var_type_and_container (m, type->type, container, error))
3712 return FALSE;
3713
3714 type->data.generic_param = mono_metadata_parse_generic_param (m, container, type->type, ptr, &ptr, error);
3715 if (!type->data.generic_param)
3716 return FALSE;
3717
3718 break;
3719 }
3720 case MONO_TYPE_GENERICINST: {
3721 if (!do_mono_metadata_parse_generic_class (type, m, container, ptr, &ptr, error))
3722 return FALSE;
3723 break;
3724 }
3725 default:
3726 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);
3727 return FALSE;
3728 }
3729
3730 if (rptr)
3731 *rptr = ptr;
3732 return TRUE;
3733 }
3734
3735 /**
3736 * mono_metadata_free_type:
3737 * \param type type to free
3738 *
3739 * Free the memory allocated for type \p type which is allocated on the heap.
3740 */
3741 void
mono_metadata_free_type(MonoType * type)3742 mono_metadata_free_type (MonoType *type)
3743 {
3744 if (type >= builtin_types && type < builtin_types + NBUILTIN_TYPES ())
3745 return;
3746
3747 switch (type->type){
3748 case MONO_TYPE_OBJECT:
3749 case MONO_TYPE_STRING:
3750 if (!type->data.klass)
3751 break;
3752 /* fall through */
3753 case MONO_TYPE_CLASS:
3754 case MONO_TYPE_VALUETYPE:
3755 if (type == &type->data.klass->byval_arg || type == &type->data.klass->this_arg)
3756 return;
3757 break;
3758 case MONO_TYPE_PTR:
3759 mono_metadata_free_type (type->data.type);
3760 break;
3761 case MONO_TYPE_FNPTR:
3762 mono_metadata_free_method_signature (type->data.method);
3763 break;
3764 case MONO_TYPE_ARRAY:
3765 mono_metadata_free_array (type->data.array);
3766 break;
3767 default:
3768 break;
3769 }
3770
3771 g_free (type);
3772 }
3773
3774 #if 0
3775 static void
3776 hex_dump (const char *buffer, int base, int count)
3777 {
3778 int show_header = 1;
3779 int i;
3780
3781 if (count < 0){
3782 count = -count;
3783 show_header = 0;
3784 }
3785
3786 for (i = 0; i < count; i++){
3787 if (show_header)
3788 if ((i % 16) == 0)
3789 printf ("\n0x%08x: ", (unsigned char) base + i);
3790
3791 printf ("%02x ", (unsigned char) (buffer [i]));
3792 }
3793 fflush (stdout);
3794 }
3795 #endif
3796
3797 /**
3798 * @ptr: Points to the beginning of the Section Data (25.3)
3799 */
3800 static MonoExceptionClause*
parse_section_data(MonoImage * m,int * num_clauses,const unsigned char * ptr,MonoError * error)3801 parse_section_data (MonoImage *m, int *num_clauses, const unsigned char *ptr, MonoError *error)
3802 {
3803 unsigned char sect_data_flags;
3804 int is_fat;
3805 guint32 sect_data_len;
3806 MonoExceptionClause* clauses = NULL;
3807
3808 error_init (error);
3809
3810 while (1) {
3811 /* align on 32-bit boundary */
3812 ptr = dword_align (ptr);
3813 sect_data_flags = *ptr;
3814 ptr++;
3815
3816 is_fat = sect_data_flags & METHOD_HEADER_SECTION_FAT_FORMAT;
3817 if (is_fat) {
3818 sect_data_len = (ptr [2] << 16) | (ptr [1] << 8) | ptr [0];
3819 ptr += 3;
3820 } else {
3821 sect_data_len = ptr [0];
3822 ++ptr;
3823 }
3824
3825 if (sect_data_flags & METHOD_HEADER_SECTION_EHTABLE) {
3826 const unsigned char *p = dword_align (ptr);
3827 int i;
3828 *num_clauses = is_fat ? sect_data_len / 24: sect_data_len / 12;
3829 /* we could just store a pointer if we don't need to byteswap */
3830 clauses = (MonoExceptionClause *)g_malloc0 (sizeof (MonoExceptionClause) * (*num_clauses));
3831 for (i = 0; i < *num_clauses; ++i) {
3832 MonoExceptionClause *ec = &clauses [i];
3833 guint32 tof_value;
3834 if (is_fat) {
3835 ec->flags = read32 (p);
3836 ec->try_offset = read32 (p + 4);
3837 ec->try_len = read32 (p + 8);
3838 ec->handler_offset = read32 (p + 12);
3839 ec->handler_len = read32 (p + 16);
3840 tof_value = read32 (p + 20);
3841 p += 24;
3842 } else {
3843 ec->flags = read16 (p);
3844 ec->try_offset = read16 (p + 2);
3845 ec->try_len = *(p + 4);
3846 ec->handler_offset = read16 (p + 5);
3847 ec->handler_len = *(p + 7);
3848 tof_value = read32 (p + 8);
3849 p += 12;
3850 }
3851 if (ec->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3852 ec->data.filter_offset = tof_value;
3853 } else if (ec->flags == MONO_EXCEPTION_CLAUSE_NONE) {
3854 ec->data.catch_class = NULL;
3855 if (tof_value) {
3856 ec->data.catch_class = mono_class_get_checked (m, tof_value, error);
3857 if (!is_ok (error)) {
3858 g_free (clauses);
3859 return NULL;
3860 }
3861 }
3862 } else {
3863 ec->data.catch_class = NULL;
3864 }
3865 /* g_print ("try %d: %x %04x-%04x %04x\n", i, ec->flags, ec->try_offset, ec->try_offset+ec->try_len, ec->try_len); */
3866 }
3867
3868 }
3869 if (sect_data_flags & METHOD_HEADER_SECTION_MORE_SECTS)
3870 ptr += sect_data_len - 4; /* LAMESPEC: it seems the size includes the header */
3871 else
3872 return clauses;
3873 }
3874 }
3875
3876 /*
3877 * mono_method_get_header_summary:
3878 * @method: The method to get the header.
3879 * @summary: Where to store the header
3880 *
3881 *
3882 * Returns: TRUE if the header was properly decoded.
3883 */
3884 gboolean
mono_method_get_header_summary(MonoMethod * method,MonoMethodHeaderSummary * summary)3885 mono_method_get_header_summary (MonoMethod *method, MonoMethodHeaderSummary *summary)
3886 {
3887 int idx;
3888 guint32 rva;
3889 MonoImage* img;
3890 const char *ptr;
3891 unsigned char flags, format;
3892 guint16 fat_flags;
3893
3894 /*Only the GMD has a pointer to the metadata.*/
3895 while (method->is_inflated)
3896 method = ((MonoMethodInflated*)method)->declaring;
3897
3898 summary->code_size = 0;
3899 summary->has_clauses = FALSE;
3900
3901 /*FIXME extract this into a MACRO and share it with mono_method_get_header*/
3902 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))
3903 return FALSE;
3904
3905 if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
3906 MonoMethodHeader *header = ((MonoMethodWrapper *)method)->header;
3907 if (!header)
3908 return FALSE;
3909 summary->code_size = header->code_size;
3910 summary->has_clauses = header->num_clauses > 0;
3911 return TRUE;
3912 }
3913
3914
3915 idx = mono_metadata_token_index (method->token);
3916 img = method->klass->image;
3917 rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
3918
3919 /*We must run the verifier since we'll be decoding it.*/
3920 if (!mono_verifier_verify_method_header (img, rva, NULL))
3921 return FALSE;
3922
3923 ptr = mono_image_rva_map (img, rva);
3924 if (!ptr)
3925 return FALSE;
3926
3927 flags = *(const unsigned char *)ptr;
3928 format = flags & METHOD_HEADER_FORMAT_MASK;
3929
3930 switch (format) {
3931 case METHOD_HEADER_TINY_FORMAT:
3932 ptr++;
3933 summary->code_size = flags >> 2;
3934 break;
3935 case METHOD_HEADER_FAT_FORMAT:
3936 fat_flags = read16 (ptr);
3937 ptr += 4;
3938 summary->code_size = read32 (ptr);
3939 if (fat_flags & METHOD_HEADER_MORE_SECTS)
3940 summary->has_clauses = TRUE;
3941 break;
3942 default:
3943 return FALSE;
3944 }
3945 return TRUE;
3946 }
3947
3948 /*
3949 * mono_metadata_parse_mh_full:
3950 * @m: metadata context
3951 * @generic_context: generics context
3952 * @ptr: pointer to the method header.
3953 *
3954 * Decode the method header at @ptr, including pointer to the IL code,
3955 * info about local variables and optional exception tables.
3956 * This is a Mono runtime internal function.
3957 *
3958 * LOCKING: Acquires the loader lock.
3959 *
3960 * Returns: a transient MonoMethodHeader allocated from the heap.
3961 */
3962 MonoMethodHeader *
mono_metadata_parse_mh_full(MonoImage * m,MonoGenericContainer * container,const char * ptr,MonoError * error)3963 mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, const char *ptr, MonoError *error)
3964 {
3965 MonoMethodHeader *mh = NULL;
3966 unsigned char flags = *(const unsigned char *) ptr;
3967 unsigned char format = flags & METHOD_HEADER_FORMAT_MASK;
3968 guint16 fat_flags;
3969 guint32 local_var_sig_tok, max_stack, code_size, init_locals;
3970 const unsigned char *code;
3971 MonoExceptionClause* clauses = NULL;
3972 int num_clauses = 0;
3973 MonoTableInfo *t = &m->tables [MONO_TABLE_STANDALONESIG];
3974 guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
3975
3976 error_init (error);
3977
3978 if (!ptr) {
3979 mono_error_set_bad_image (error, m, "Method header with null pointer");
3980 return NULL;
3981 }
3982
3983 switch (format) {
3984 case METHOD_HEADER_TINY_FORMAT:
3985 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER);
3986 ptr++;
3987 mh->max_stack = 8;
3988 mh->is_transient = TRUE;
3989 local_var_sig_tok = 0;
3990 mh->code_size = flags >> 2;
3991 mh->code = (unsigned char*)ptr;
3992 return mh;
3993 case METHOD_HEADER_FAT_FORMAT:
3994 fat_flags = read16 (ptr);
3995 ptr += 2;
3996 max_stack = read16 (ptr);
3997 ptr += 2;
3998 code_size = read32 (ptr);
3999 ptr += 4;
4000 local_var_sig_tok = read32 (ptr);
4001 ptr += 4;
4002
4003 if (fat_flags & METHOD_HEADER_INIT_LOCALS)
4004 init_locals = 1;
4005 else
4006 init_locals = 0;
4007
4008 code = (unsigned char*)ptr;
4009
4010 if (!(fat_flags & METHOD_HEADER_MORE_SECTS))
4011 break;
4012
4013 /*
4014 * There are more sections
4015 */
4016 ptr = (char*)code + code_size;
4017 break;
4018 default:
4019 mono_error_set_bad_image (error, m, "Invalid method header format %d", format);
4020 return NULL;
4021 }
4022
4023 if (local_var_sig_tok) {
4024 int idx = (local_var_sig_tok & 0xffffff)-1;
4025 if (idx >= t->rows || idx < 0) {
4026 mono_error_set_bad_image (error, m, "Invalid method header local vars signature token 0x%8x", idx);
4027 goto fail;
4028 }
4029 mono_metadata_decode_row (t, idx, cols, 1);
4030
4031 if (!mono_verifier_verify_standalone_signature (m, cols [MONO_STAND_ALONE_SIGNATURE], NULL)) {
4032 mono_error_set_bad_image (error, m, "Method header locals signature 0x%8x verification failed", idx);
4033 goto fail;
4034 }
4035 }
4036 if (fat_flags & METHOD_HEADER_MORE_SECTS) {
4037 clauses = parse_section_data (m, &num_clauses, (const unsigned char*)ptr, error);
4038 goto_if_nok (error, fail);
4039 }
4040 if (local_var_sig_tok) {
4041 const char *locals_ptr;
4042 int len=0, i;
4043
4044 locals_ptr = mono_metadata_blob_heap (m, cols [MONO_STAND_ALONE_SIGNATURE]);
4045 mono_metadata_decode_blob_size (locals_ptr, &locals_ptr);
4046 if (*locals_ptr != 0x07)
4047 g_warning ("wrong signature for locals blob");
4048 locals_ptr++;
4049 len = mono_metadata_decode_value (locals_ptr, &locals_ptr);
4050 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + len * sizeof (MonoType*) + num_clauses * sizeof (MonoExceptionClause));
4051 mh->num_locals = len;
4052 for (i = 0; i < len; ++i) {
4053 mh->locals [i] = mono_metadata_parse_type_internal (m, container, 0, TRUE, locals_ptr, &locals_ptr, error);
4054 goto_if_nok (error, fail);
4055 }
4056 } else {
4057 mh = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + num_clauses * sizeof (MonoExceptionClause));
4058 }
4059 mh->code = code;
4060 mh->code_size = code_size;
4061 mh->max_stack = max_stack;
4062 mh->is_transient = TRUE;
4063 mh->init_locals = init_locals;
4064 if (clauses) {
4065 MonoExceptionClause* clausesp = (MonoExceptionClause*)&mh->locals [mh->num_locals];
4066 memcpy (clausesp, clauses, num_clauses * sizeof (MonoExceptionClause));
4067 g_free (clauses);
4068 mh->clauses = clausesp;
4069 mh->num_clauses = num_clauses;
4070 }
4071 return mh;
4072 fail:
4073 g_free (clauses);
4074 g_free (mh);
4075 return NULL;
4076
4077 }
4078
4079 /**
4080 * mono_metadata_parse_mh:
4081 * \param generic_context generics context
4082 * \param ptr pointer to the method header.
4083 *
4084 * Decode the method header at \p ptr, including pointer to the IL code,
4085 * info about local variables and optional exception tables.
4086 *
4087 * \returns a transient \c MonoMethodHeader allocated from the heap.
4088 */
4089 MonoMethodHeader *
mono_metadata_parse_mh(MonoImage * m,const char * ptr)4090 mono_metadata_parse_mh (MonoImage *m, const char *ptr)
4091 {
4092 MonoError error;
4093 MonoMethodHeader *header = mono_metadata_parse_mh_full (m, NULL, ptr, &error);
4094 mono_error_cleanup (&error);
4095 return header;
4096 }
4097
4098 /**
4099 * mono_metadata_free_mh:
4100 * \param mh a method header
4101 *
4102 * Free the memory allocated for the method header.
4103 */
4104 void
mono_metadata_free_mh(MonoMethodHeader * mh)4105 mono_metadata_free_mh (MonoMethodHeader *mh)
4106 {
4107 int i;
4108
4109 /* If it is not transient it means it's part of a wrapper method,
4110 * or a SRE-generated method, so the lifetime in that case is
4111 * dictated by the method's own lifetime
4112 */
4113 if (mh->is_transient) {
4114 for (i = 0; i < mh->num_locals; ++i)
4115 mono_metadata_free_type (mh->locals [i]);
4116 g_free (mh);
4117 }
4118 }
4119
4120 /**
4121 * mono_method_header_get_code:
4122 * \param header a \c MonoMethodHeader pointer
4123 * \param code_size memory location for returning the code size
4124 * \param max_stack memory location for returning the max stack
4125 *
4126 * Method header accessor to retreive info about the IL code properties:
4127 * a pointer to the IL code itself, the size of the code and the max number
4128 * of stack slots used by the code.
4129 *
4130 * \returns pointer to the IL code represented by the method header.
4131 */
4132 const unsigned char*
mono_method_header_get_code(MonoMethodHeader * header,guint32 * code_size,guint32 * max_stack)4133 mono_method_header_get_code (MonoMethodHeader *header, guint32* code_size, guint32* max_stack)
4134 {
4135 if (code_size)
4136 *code_size = header->code_size;
4137 if (max_stack)
4138 *max_stack = header->max_stack;
4139 return header->code;
4140 }
4141
4142 /**
4143 * mono_method_header_get_locals:
4144 * \param header a \c MonoMethodHeader pointer
4145 * \param num_locals memory location for returning the number of local variables
4146 * \param init_locals memory location for returning the init_locals flag
4147 *
4148 * Method header accessor to retreive info about the local variables:
4149 * an array of local types, the number of locals and whether the locals
4150 * are supposed to be initialized to 0 on method entry
4151 *
4152 * \returns pointer to an array of types of the local variables
4153 */
4154 MonoType**
mono_method_header_get_locals(MonoMethodHeader * header,guint32 * num_locals,gboolean * init_locals)4155 mono_method_header_get_locals (MonoMethodHeader *header, guint32* num_locals, gboolean *init_locals)
4156 {
4157 if (num_locals)
4158 *num_locals = header->num_locals;
4159 if (init_locals)
4160 *init_locals = header->init_locals;
4161 return header->locals;
4162 }
4163
4164 /*
4165 * mono_method_header_get_num_clauses:
4166 * @header: a MonoMethodHeader pointer
4167 *
4168 * Method header accessor to retreive the number of exception clauses.
4169 *
4170 * Returns: the number of exception clauses present
4171 */
4172 int
mono_method_header_get_num_clauses(MonoMethodHeader * header)4173 mono_method_header_get_num_clauses (MonoMethodHeader *header)
4174 {
4175 return header->num_clauses;
4176 }
4177
4178 /**
4179 * mono_method_header_get_clauses:
4180 * \param header a \c MonoMethodHeader pointer
4181 * \param method \c MonoMethod the header belongs to
4182 * \param iter pointer to a iterator
4183 * \param clause pointer to a \c MonoExceptionClause structure which will be filled with the info
4184 *
4185 * Get the info about the exception clauses in the method. Set \c *iter to NULL to
4186 * initiate the iteration, then call the method repeatedly until it returns FALSE.
4187 * At each iteration, the structure pointed to by clause if filled with the
4188 * exception clause information.
4189 *
4190 * \returns TRUE if clause was filled with info, FALSE if there are no more exception
4191 * clauses.
4192 */
4193 int
mono_method_header_get_clauses(MonoMethodHeader * header,MonoMethod * method,gpointer * iter,MonoExceptionClause * clause)4194 mono_method_header_get_clauses (MonoMethodHeader *header, MonoMethod *method, gpointer *iter, MonoExceptionClause *clause)
4195 {
4196 MonoExceptionClause *sc;
4197 /* later we'll be able to use this interface to parse the clause info on demand,
4198 * without allocating anything.
4199 */
4200 if (!iter || !header->num_clauses)
4201 return FALSE;
4202 if (!*iter) {
4203 *iter = sc = header->clauses;
4204 *clause = *sc;
4205 return TRUE;
4206 }
4207 sc = (MonoExceptionClause *)*iter;
4208 sc++;
4209 if (sc < header->clauses + header->num_clauses) {
4210 *iter = sc;
4211 *clause = *sc;
4212 return TRUE;
4213 }
4214 return FALSE;
4215 }
4216
4217 /**
4218 * mono_metadata_parse_field_type:
4219 * \param m metadata context to extract information from
4220 * \param ptr pointer to the field signature
4221 * \param rptr pointer updated to match the end of the decoded stream
4222 *
4223 * Parses the field signature, and returns the type information for it.
4224 *
4225 * \returns The \c MonoType that was extracted from \p ptr .
4226 */
4227 MonoType *
mono_metadata_parse_field_type(MonoImage * m,short field_flags,const char * ptr,const char ** rptr)4228 mono_metadata_parse_field_type (MonoImage *m, short field_flags, const char *ptr, const char **rptr)
4229 {
4230 MonoError error;
4231 MonoType * type = mono_metadata_parse_type_internal (m, NULL, field_flags, FALSE, ptr, rptr, &error);
4232 mono_error_cleanup (&error);
4233 return type;
4234 }
4235
4236 /**
4237 * mono_metadata_parse_param:
4238 * \param m metadata context to extract information from
4239 * \param ptr pointer to the param signature
4240 * \param rptr pointer updated to match the end of the decoded stream
4241 *
4242 * Parses the param signature, and returns the type information for it.
4243 *
4244 * \returns The \c MonoType that was extracted from \p ptr .
4245 */
4246 MonoType *
mono_metadata_parse_param(MonoImage * m,const char * ptr,const char ** rptr)4247 mono_metadata_parse_param (MonoImage *m, const char *ptr, const char **rptr)
4248 {
4249 MonoError error;
4250 MonoType * type = mono_metadata_parse_type_internal (m, NULL, 0, FALSE, ptr, rptr, &error);
4251 mono_error_cleanup (&error);
4252 return type;
4253 }
4254
4255 /**
4256 * mono_metadata_token_from_dor:
4257 * \param dor_token A \c TypeDefOrRef coded index
4258 *
4259 * \p dor_token is a \c TypeDefOrRef coded index: it contains either
4260 * a \c TypeDef, \c TypeRef or \c TypeSpec in the lower bits, and the upper
4261 * bits contain an index into the table.
4262 *
4263 * \returns an expanded token
4264 */
4265 guint32
mono_metadata_token_from_dor(guint32 dor_index)4266 mono_metadata_token_from_dor (guint32 dor_index)
4267 {
4268 guint32 table, idx;
4269
4270 table = dor_index & 0x03;
4271 idx = dor_index >> 2;
4272
4273 switch (table){
4274 case 0: /* TypeDef */
4275 return MONO_TOKEN_TYPE_DEF | idx;
4276 case 1: /* TypeRef */
4277 return MONO_TOKEN_TYPE_REF | idx;
4278 case 2: /* TypeSpec */
4279 return MONO_TOKEN_TYPE_SPEC | idx;
4280 default:
4281 g_assert_not_reached ();
4282 }
4283
4284 return 0;
4285 }
4286
4287 /*
4288 * We use this to pass context information to the row locator
4289 */
4290 typedef struct {
4291 int idx; /* The index that we are trying to locate */
4292 int col_idx; /* The index in the row where idx may be stored */
4293 MonoTableInfo *t; /* pointer to the table */
4294 guint32 result;
4295 } locator_t;
4296
4297 /*
4298 * How the row locator works.
4299 *
4300 * Table A
4301 * ___|___
4302 * ___|___ Table B
4303 * ___|___------> _______
4304 * ___|___ _______
4305 *
4306 * A column in the rows of table A references an index in table B.
4307 * For example A may be the TYPEDEF table and B the METHODDEF table.
4308 *
4309 * Given an index in table B we want to get the row in table A
4310 * where the column n references our index in B.
4311 *
4312 * In the locator_t structure:
4313 * t is table A
4314 * col_idx is the column number
4315 * index is the index in table B
4316 * result will be the index in table A
4317 *
4318 * Examples:
4319 * Table A Table B column (in table A)
4320 * TYPEDEF METHODDEF MONO_TYPEDEF_METHOD_LIST
4321 * TYPEDEF FIELD MONO_TYPEDEF_FIELD_LIST
4322 * PROPERTYMAP PROPERTY MONO_PROPERTY_MAP_PROPERTY_LIST
4323 * INTERFIMPL TYPEDEF MONO_INTERFACEIMPL_CLASS
4324 * METHODSEM PROPERTY ASSOCIATION (encoded index)
4325 *
4326 * Note that we still don't support encoded indexes.
4327 *
4328 */
4329 static int
typedef_locator(const void * a,const void * b)4330 typedef_locator (const void *a, const void *b)
4331 {
4332 locator_t *loc = (locator_t *) a;
4333 const char *bb = (const char *) b;
4334 int typedef_index = (bb - loc->t->base) / loc->t->row_size;
4335 guint32 col, col_next;
4336
4337 col = mono_metadata_decode_row_col (loc->t, typedef_index, loc->col_idx);
4338
4339 if (loc->idx < col)
4340 return -1;
4341
4342 /*
4343 * Need to check that the next row is valid.
4344 */
4345 if (typedef_index + 1 < loc->t->rows) {
4346 col_next = mono_metadata_decode_row_col (loc->t, typedef_index + 1, loc->col_idx);
4347 if (loc->idx >= col_next)
4348 return 1;
4349
4350 if (col == col_next)
4351 return 1;
4352 }
4353
4354 loc->result = typedef_index;
4355
4356 return 0;
4357 }
4358
4359 static int
table_locator(const void * a,const void * b)4360 table_locator (const void *a, const void *b)
4361 {
4362 locator_t *loc = (locator_t *) a;
4363 const char *bb = (const char *) b;
4364 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4365 guint32 col;
4366
4367 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4368
4369 if (loc->idx == col) {
4370 loc->result = table_index;
4371 return 0;
4372 }
4373 if (loc->idx < col)
4374 return -1;
4375 else
4376 return 1;
4377 }
4378
4379 static int
declsec_locator(const void * a,const void * b)4380 declsec_locator (const void *a, const void *b)
4381 {
4382 locator_t *loc = (locator_t *) a;
4383 const char *bb = (const char *) b;
4384 guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
4385 guint32 col;
4386
4387 col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
4388
4389 if (loc->idx == col) {
4390 loc->result = table_index;
4391 return 0;
4392 }
4393 if (loc->idx < col)
4394 return -1;
4395 else
4396 return 1;
4397 }
4398
4399 /**
4400 * search_ptr_table:
4401 *
4402 * Return the 1-based row index in TABLE, which must be one of the *Ptr tables,
4403 * which contains IDX.
4404 */
4405 static guint32
search_ptr_table(MonoImage * image,int table,int idx)4406 search_ptr_table (MonoImage *image, int table, int idx)
4407 {
4408 MonoTableInfo *ptrdef = &image->tables [table];
4409 int i;
4410
4411 /* Use a linear search to find our index in the table */
4412 for (i = 0; i < ptrdef->rows; i ++)
4413 /* All the Ptr tables have the same structure */
4414 if (mono_metadata_decode_row_col (ptrdef, i, 0) == idx)
4415 break;
4416
4417 if (i < ptrdef->rows)
4418 return i + 1;
4419 else
4420 return idx;
4421 }
4422
4423 /**
4424 * mono_metadata_typedef_from_field:
4425 * \param meta metadata context
4426 * \param index FieldDef token
4427 *
4428 * \returns the 1-based index into the \c TypeDef table of the type that
4429 * declared the field described by \p index, or 0 if not found.
4430 */
4431 guint32
mono_metadata_typedef_from_field(MonoImage * meta,guint32 index)4432 mono_metadata_typedef_from_field (MonoImage *meta, guint32 index)
4433 {
4434 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4435 locator_t loc;
4436
4437 if (!tdef->base)
4438 return 0;
4439
4440 loc.idx = mono_metadata_token_index (index);
4441 loc.col_idx = MONO_TYPEDEF_FIELD_LIST;
4442 loc.t = tdef;
4443
4444 if (meta->uncompressed_metadata)
4445 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
4446
4447 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4448 return 0;
4449
4450 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4451 return loc.result + 1;
4452 }
4453
4454 /**
4455 * mono_metadata_typedef_from_method:
4456 * \param meta metadata context
4457 * \param index \c MethodDef token
4458 * \returns the 1-based index into the \c TypeDef table of the type that
4459 * declared the method described by \p index. 0 if not found.
4460 */
4461 guint32
mono_metadata_typedef_from_method(MonoImage * meta,guint32 index)4462 mono_metadata_typedef_from_method (MonoImage *meta, guint32 index)
4463 {
4464 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_TYPEDEF];
4465 locator_t loc;
4466
4467 if (!tdef->base)
4468 return 0;
4469
4470 loc.idx = mono_metadata_token_index (index);
4471 loc.col_idx = MONO_TYPEDEF_METHOD_LIST;
4472 loc.t = tdef;
4473
4474 if (meta->uncompressed_metadata)
4475 loc.idx = search_ptr_table (meta, MONO_TABLE_METHOD_POINTER, loc.idx);
4476
4477 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator))
4478 return 0;
4479
4480 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4481 return loc.result + 1;
4482 }
4483
4484 /*
4485 * mono_metadata_interfaces_from_typedef_full:
4486 * @meta: metadata context
4487 * @index: typedef token
4488 * @interfaces: Out parameter used to store the interface array
4489 * @count: Out parameter used to store the number of interfaces
4490 * @heap_alloc_result: if TRUE the result array will be g_malloc'd
4491 * @context: The generic context
4492 *
4493 * The array of interfaces that the @index typedef token implements is returned in
4494 * @interfaces. The number of elements in the array is returned in @count.
4495 *
4496
4497 * Returns: TRUE on success, FALSE on failure.
4498 */
4499 gboolean
mono_metadata_interfaces_from_typedef_full(MonoImage * meta,guint32 index,MonoClass *** interfaces,guint * count,gboolean heap_alloc_result,MonoGenericContext * context,MonoError * error)4500 mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, MonoClass ***interfaces, guint *count, gboolean heap_alloc_result, MonoGenericContext *context, MonoError *error)
4501 {
4502 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_INTERFACEIMPL];
4503 locator_t loc;
4504 guint32 start, pos;
4505 guint32 cols [MONO_INTERFACEIMPL_SIZE];
4506 MonoClass **result;
4507
4508 *interfaces = NULL;
4509 *count = 0;
4510
4511 error_init (error);
4512
4513 if (!tdef->base)
4514 return TRUE;
4515
4516 loc.idx = mono_metadata_token_index (index);
4517 loc.col_idx = MONO_INTERFACEIMPL_CLASS;
4518 loc.t = tdef;
4519
4520 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4521 return TRUE;
4522
4523 start = loc.result;
4524 /*
4525 * We may end up in the middle of the rows...
4526 */
4527 while (start > 0) {
4528 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_INTERFACEIMPL_CLASS))
4529 start--;
4530 else
4531 break;
4532 }
4533 pos = start;
4534 while (pos < tdef->rows) {
4535 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4536 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4537 break;
4538 ++pos;
4539 }
4540
4541 if (heap_alloc_result)
4542 result = g_new0 (MonoClass*, pos - start);
4543 else
4544 result = (MonoClass **)mono_image_alloc0 (meta, sizeof (MonoClass*) * (pos - start));
4545
4546 pos = start;
4547 while (pos < tdef->rows) {
4548 MonoClass *iface;
4549
4550 mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
4551 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
4552 break;
4553 iface = mono_class_get_and_inflate_typespec_checked (
4554 meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context, error);
4555 if (iface == NULL)
4556 return FALSE;
4557 result [pos - start] = iface;
4558 ++pos;
4559 }
4560 *count = pos - start;
4561 *interfaces = result;
4562 return TRUE;
4563 }
4564
4565 /**
4566 * mono_metadata_interfaces_from_typedef:
4567 * \param meta metadata context
4568 * \param index typedef token
4569 * \param count Out parameter used to store the number of interfaces
4570 *
4571 * The array of interfaces that the \p index typedef token implements is returned in
4572 * \p interfaces. The number of elements in the array is returned in \p count. The returned
4573 * array is allocated with \c g_malloc and the caller must free it.
4574 *
4575 * LOCKING: Acquires the loader lock .
4576 *
4577 * \returns the interface array on success, NULL on failure.
4578 */
4579 MonoClass**
mono_metadata_interfaces_from_typedef(MonoImage * meta,guint32 index,guint * count)4580 mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *count)
4581 {
4582 MonoError error;
4583 MonoClass **interfaces = NULL;
4584 gboolean rv;
4585
4586 rv = mono_metadata_interfaces_from_typedef_full (meta, index, &interfaces, count, TRUE, NULL, &error);
4587 g_assert (mono_error_ok (&error)); /* FIXME dont swallow the error */
4588 if (rv)
4589 return interfaces;
4590 else
4591 return NULL;
4592 }
4593
4594 /**
4595 * mono_metadata_nested_in_typedef:
4596 * \param meta metadata context
4597 * \param index typedef token
4598 * \returns the 1-based index into the TypeDef table of the type
4599 * where the type described by \p index is nested.
4600 * Returns 0 if \p index describes a non-nested type.
4601 */
4602 guint32
mono_metadata_nested_in_typedef(MonoImage * meta,guint32 index)4603 mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index)
4604 {
4605 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
4606 locator_t loc;
4607
4608 if (!tdef->base)
4609 return 0;
4610
4611 loc.idx = mono_metadata_token_index (index);
4612 loc.col_idx = MONO_NESTED_CLASS_NESTED;
4613 loc.t = tdef;
4614
4615 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4616 return 0;
4617
4618 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4619 return mono_metadata_decode_row_col (tdef, loc.result, MONO_NESTED_CLASS_ENCLOSING) | MONO_TOKEN_TYPE_DEF;
4620 }
4621
4622 /**
4623 * mono_metadata_nesting_typedef:
4624 * \param meta metadata context
4625 * \param index typedef token
4626 * \returns the 1-based index into the \c TypeDef table of the first type
4627 * that is nested inside the type described by \p index. The search starts at
4628 * \p start_index. Returns 0 if no such type is found.
4629 */
4630 guint32
mono_metadata_nesting_typedef(MonoImage * meta,guint32 index,guint32 start_index)4631 mono_metadata_nesting_typedef (MonoImage *meta, guint32 index, guint32 start_index)
4632 {
4633 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS];
4634 guint32 start;
4635 guint32 class_index = mono_metadata_token_index (index);
4636
4637 if (!tdef->base)
4638 return 0;
4639
4640 start = start_index;
4641
4642 while (start <= tdef->rows) {
4643 if (class_index == mono_metadata_decode_row_col (tdef, start - 1, MONO_NESTED_CLASS_ENCLOSING))
4644 break;
4645 else
4646 start++;
4647 }
4648
4649 if (start > tdef->rows)
4650 return 0;
4651 else
4652 return start;
4653 }
4654
4655 /**
4656 * mono_metadata_packing_from_typedef:
4657 * \param meta metadata context
4658 * \param index token representing a type
4659 * \returns the info stored in the \c ClassLayout table for the given typedef token
4660 * into the \p packing and \p size pointers.
4661 * Returns 0 if the info is not found.
4662 */
4663 guint32
mono_metadata_packing_from_typedef(MonoImage * meta,guint32 index,guint32 * packing,guint32 * size)4664 mono_metadata_packing_from_typedef (MonoImage *meta, guint32 index, guint32 *packing, guint32 *size)
4665 {
4666 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CLASSLAYOUT];
4667 locator_t loc;
4668 guint32 cols [MONO_CLASS_LAYOUT_SIZE];
4669
4670 if (!tdef->base)
4671 return 0;
4672
4673 loc.idx = mono_metadata_token_index (index);
4674 loc.col_idx = MONO_CLASS_LAYOUT_PARENT;
4675 loc.t = tdef;
4676
4677 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4678 return 0;
4679
4680 mono_metadata_decode_row (tdef, loc.result, cols, MONO_CLASS_LAYOUT_SIZE);
4681 if (packing)
4682 *packing = cols [MONO_CLASS_LAYOUT_PACKING_SIZE];
4683 if (size)
4684 *size = cols [MONO_CLASS_LAYOUT_CLASS_SIZE];
4685
4686 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4687 return loc.result + 1;
4688 }
4689
4690 /**
4691 * mono_metadata_custom_attrs_from_index:
4692 * \param meta metadata context
4693 * \param index token representing the parent
4694 * \returns: the 1-based index into the \c CustomAttribute table of the first
4695 * attribute which belongs to the metadata object described by \p index.
4696 * Returns 0 if no such attribute is found.
4697 */
4698 guint32
mono_metadata_custom_attrs_from_index(MonoImage * meta,guint32 index)4699 mono_metadata_custom_attrs_from_index (MonoImage *meta, guint32 index)
4700 {
4701 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CUSTOMATTRIBUTE];
4702 locator_t loc;
4703
4704 if (!tdef->base)
4705 return 0;
4706
4707 loc.idx = index;
4708 loc.col_idx = MONO_CUSTOM_ATTR_PARENT;
4709 loc.t = tdef;
4710
4711 /* FIXME: Index translation */
4712
4713 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4714 return 0;
4715
4716 /* Find the first entry by searching backwards */
4717 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_CUSTOM_ATTR_PARENT) == index))
4718 loc.result --;
4719
4720 /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
4721 return loc.result + 1;
4722 }
4723
4724 /**
4725 * mono_metadata_declsec_from_index:
4726 * \param meta metadata context
4727 * \param index token representing the parent
4728 * \returns the 0-based index into the \c DeclarativeSecurity table of the first
4729 * attribute which belongs to the metadata object described by \p index.
4730 * Returns \c -1 if no such attribute is found.
4731 */
4732 guint32
mono_metadata_declsec_from_index(MonoImage * meta,guint32 index)4733 mono_metadata_declsec_from_index (MonoImage *meta, guint32 index)
4734 {
4735 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_DECLSECURITY];
4736 locator_t loc;
4737
4738 if (!tdef->base)
4739 return -1;
4740
4741 loc.idx = index;
4742 loc.col_idx = MONO_DECL_SECURITY_PARENT;
4743 loc.t = tdef;
4744
4745 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, declsec_locator))
4746 return -1;
4747
4748 /* Find the first entry by searching backwards */
4749 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_DECL_SECURITY_PARENT) == index))
4750 loc.result --;
4751
4752 return loc.result;
4753 }
4754
4755 /*
4756 * mono_metadata_localscope_from_methoddef:
4757 * @meta: metadata context
4758 * @index: methoddef index
4759 *
4760 * Returns: the 1-based index into the LocalScope table of the first
4761 * scope which belongs to the method described by @index.
4762 * Returns 0 if no such row is found.
4763 */
4764 guint32
mono_metadata_localscope_from_methoddef(MonoImage * meta,guint32 index)4765 mono_metadata_localscope_from_methoddef (MonoImage *meta, guint32 index)
4766 {
4767 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_LOCALSCOPE];
4768 locator_t loc;
4769
4770 if (!tdef->base)
4771 return 0;
4772
4773 loc.idx = index;
4774 loc.col_idx = MONO_LOCALSCOPE_METHOD;
4775 loc.t = tdef;
4776
4777 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
4778 return 0;
4779
4780 /* Find the first entry by searching backwards */
4781 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_LOCALSCOPE_METHOD) == index))
4782 loc.result --;
4783
4784 return loc.result + 1;
4785 }
4786
4787 #ifdef DEBUG
4788 static void
mono_backtrace(int limit)4789 mono_backtrace (int limit)
4790 {
4791 void *array[limit];
4792 char **names;
4793 int i;
4794 backtrace (array, limit);
4795 names = backtrace_symbols (array, limit);
4796 for (i =0; i < limit; ++i) {
4797 g_print ("\t%s\n", names [i]);
4798 }
4799 g_free (names);
4800 }
4801 #endif
4802
4803 static int i8_align;
4804
4805 /*
4806 * mono_type_set_alignment:
4807 *
4808 * Set the alignment used by runtime to layout fields etc. of type TYPE to ALIGN.
4809 * This should only be used in AOT mode since the resulting layout will not match the
4810 * host abi layout.
4811 */
4812 void
mono_type_set_alignment(MonoTypeEnum type,int align)4813 mono_type_set_alignment (MonoTypeEnum type, int align)
4814 {
4815 /* Support only a few types whose alignment is abi dependent */
4816 switch (type) {
4817 case MONO_TYPE_I8:
4818 i8_align = align;
4819 break;
4820 default:
4821 g_assert_not_reached ();
4822 break;
4823 }
4824 }
4825
4826 /**
4827 * mono_type_size:
4828 * \param t the type to return the size of
4829 * \returns The number of bytes required to hold an instance of this
4830 * type in memory
4831 */
4832 int
mono_type_size(MonoType * t,int * align)4833 mono_type_size (MonoType *t, int *align)
4834 {
4835 MonoTypeEnum simple_type;
4836
4837 if (!t) {
4838 *align = 1;
4839 return 0;
4840 }
4841 if (t->byref) {
4842 *align = MONO_ABI_ALIGNOF (gpointer);
4843 return MONO_ABI_SIZEOF (gpointer);
4844 }
4845
4846 simple_type = t->type;
4847 again:
4848 switch (simple_type) {
4849 case MONO_TYPE_VOID:
4850 *align = 1;
4851 return 0;
4852 case MONO_TYPE_BOOLEAN:
4853 *align = MONO_ABI_ALIGNOF (gint8);
4854 return 1;
4855 case MONO_TYPE_I1:
4856 case MONO_TYPE_U1:
4857 *align = MONO_ABI_ALIGNOF (gint8);
4858 return 1;
4859 case MONO_TYPE_CHAR:
4860 case MONO_TYPE_I2:
4861 case MONO_TYPE_U2:
4862 *align = MONO_ABI_ALIGNOF (gint16);
4863 return 2;
4864 case MONO_TYPE_I4:
4865 case MONO_TYPE_U4:
4866 *align = MONO_ABI_ALIGNOF (gint32);
4867 return 4;
4868 case MONO_TYPE_R4:
4869 *align = MONO_ABI_ALIGNOF (float);
4870 return 4;
4871 case MONO_TYPE_I8:
4872 case MONO_TYPE_U8:
4873 *align = MONO_ABI_ALIGNOF (gint64);
4874 return 8;
4875 case MONO_TYPE_R8:
4876 *align = MONO_ABI_ALIGNOF (double);
4877 return 8;
4878 case MONO_TYPE_I:
4879 case MONO_TYPE_U:
4880 *align = MONO_ABI_ALIGNOF (gpointer);
4881 return MONO_ABI_SIZEOF (gpointer);
4882 case MONO_TYPE_VALUETYPE: {
4883 if (t->data.klass->enumtype)
4884 return mono_type_size (mono_class_enum_basetype (t->data.klass), align);
4885 else
4886 return mono_class_value_size (t->data.klass, (guint32*)align);
4887 }
4888 case MONO_TYPE_STRING:
4889 case MONO_TYPE_OBJECT:
4890 case MONO_TYPE_CLASS:
4891 case MONO_TYPE_SZARRAY:
4892 case MONO_TYPE_PTR:
4893 case MONO_TYPE_FNPTR:
4894 case MONO_TYPE_ARRAY:
4895 *align = MONO_ABI_ALIGNOF (gpointer);
4896 return MONO_ABI_SIZEOF (gpointer);
4897 case MONO_TYPE_TYPEDBYREF:
4898 return mono_class_value_size (mono_defaults.typed_reference_class, (guint32*)align);
4899 case MONO_TYPE_GENERICINST: {
4900 MonoGenericClass *gclass = t->data.generic_class;
4901 MonoClass *container_class = gclass->container_class;
4902
4903 // g_assert (!gclass->inst->is_open);
4904
4905 if (container_class->valuetype) {
4906 if (container_class->enumtype)
4907 return mono_type_size (mono_class_enum_basetype (container_class), align);
4908 else
4909 return mono_class_value_size (mono_class_from_mono_type (t), (guint32*)align);
4910 } else {
4911 *align = MONO_ABI_ALIGNOF (gpointer);
4912 return MONO_ABI_SIZEOF (gpointer);
4913 }
4914 }
4915 case MONO_TYPE_VAR:
4916 case MONO_TYPE_MVAR:
4917 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
4918 *align = MONO_ABI_ALIGNOF (gpointer);
4919 return MONO_ABI_SIZEOF (gpointer);
4920 } else {
4921 /* The gparam can only match types given by gshared_constraint */
4922 return mono_type_size (t->data.generic_param->gshared_constraint, align);
4923 goto again;
4924 }
4925 default:
4926 g_error ("mono_type_size: type 0x%02x unknown", t->type);
4927 }
4928 return 0;
4929 }
4930
4931 /**
4932 * mono_type_stack_size:
4933 * \param t the type to return the size it uses on the stack
4934 * \returns The number of bytes required to hold an instance of this
4935 * type on the runtime stack
4936 */
4937 int
mono_type_stack_size(MonoType * t,int * align)4938 mono_type_stack_size (MonoType *t, int *align)
4939 {
4940 return mono_type_stack_size_internal (t, align, FALSE);
4941 }
4942
4943 int
mono_type_stack_size_internal(MonoType * t,int * align,gboolean allow_open)4944 mono_type_stack_size_internal (MonoType *t, int *align, gboolean allow_open)
4945 {
4946 int tmp;
4947 MonoTypeEnum simple_type;
4948 #if SIZEOF_VOID_P == SIZEOF_REGISTER
4949 int stack_slot_size = MONO_ABI_SIZEOF (gpointer);
4950 int stack_slot_align = MONO_ABI_ALIGNOF (gpointer);
4951 #elif SIZEOF_VOID_P < SIZEOF_REGISTER
4952 int stack_slot_size = SIZEOF_REGISTER;
4953 int stack_slot_align = SIZEOF_REGISTER;
4954 #endif
4955
4956 g_assert (t != NULL);
4957
4958 if (!align)
4959 align = &tmp;
4960
4961 if (t->byref) {
4962 *align = stack_slot_align;
4963 return stack_slot_size;
4964 }
4965
4966 simple_type = t->type;
4967 switch (simple_type) {
4968 case MONO_TYPE_BOOLEAN:
4969 case MONO_TYPE_CHAR:
4970 case MONO_TYPE_I1:
4971 case MONO_TYPE_U1:
4972 case MONO_TYPE_I2:
4973 case MONO_TYPE_U2:
4974 case MONO_TYPE_I4:
4975 case MONO_TYPE_U4:
4976 case MONO_TYPE_I:
4977 case MONO_TYPE_U:
4978 case MONO_TYPE_STRING:
4979 case MONO_TYPE_OBJECT:
4980 case MONO_TYPE_CLASS:
4981 case MONO_TYPE_SZARRAY:
4982 case MONO_TYPE_PTR:
4983 case MONO_TYPE_FNPTR:
4984 case MONO_TYPE_ARRAY:
4985 *align = stack_slot_align;
4986 return stack_slot_size;
4987 case MONO_TYPE_VAR:
4988 case MONO_TYPE_MVAR:
4989 g_assert (allow_open);
4990 if (!t->data.generic_param->gshared_constraint || t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE) {
4991 *align = stack_slot_align;
4992 return stack_slot_size;
4993 } else {
4994 /* The gparam can only match types given by gshared_constraint */
4995 return mono_type_stack_size_internal (t->data.generic_param->gshared_constraint, align, allow_open);
4996 }
4997 case MONO_TYPE_TYPEDBYREF:
4998 *align = stack_slot_align;
4999 return stack_slot_size * 3;
5000 case MONO_TYPE_R4:
5001 *align = MONO_ABI_ALIGNOF (float);
5002 return sizeof (float);
5003 case MONO_TYPE_I8:
5004 case MONO_TYPE_U8:
5005 *align = MONO_ABI_ALIGNOF (gint64);
5006 return sizeof (gint64);
5007 case MONO_TYPE_R8:
5008 *align = MONO_ABI_ALIGNOF (double);
5009 return sizeof (double);
5010 case MONO_TYPE_VALUETYPE: {
5011 guint32 size;
5012
5013 if (t->data.klass->enumtype)
5014 return mono_type_stack_size_internal (mono_class_enum_basetype (t->data.klass), align, allow_open);
5015 else {
5016 size = mono_class_value_size (t->data.klass, (guint32*)align);
5017
5018 *align = *align + stack_slot_align - 1;
5019 *align &= ~(stack_slot_align - 1);
5020
5021 size += stack_slot_size - 1;
5022 size &= ~(stack_slot_size - 1);
5023
5024 return size;
5025 }
5026 }
5027 case MONO_TYPE_GENERICINST: {
5028 MonoGenericClass *gclass = t->data.generic_class;
5029 MonoClass *container_class = gclass->container_class;
5030
5031 if (!allow_open)
5032 g_assert (!gclass->context.class_inst->is_open);
5033
5034 if (container_class->valuetype) {
5035 if (container_class->enumtype)
5036 return mono_type_stack_size_internal (mono_class_enum_basetype (container_class), align, allow_open);
5037 else {
5038 guint32 size = mono_class_value_size (mono_class_from_mono_type (t), (guint32*)align);
5039
5040 *align = *align + stack_slot_align - 1;
5041 *align &= ~(stack_slot_align - 1);
5042
5043 size += stack_slot_size - 1;
5044 size &= ~(stack_slot_size - 1);
5045
5046 return size;
5047 }
5048 } else {
5049 *align = stack_slot_align;
5050 return stack_slot_size;
5051 }
5052 }
5053 default:
5054 g_error ("type 0x%02x unknown", t->type);
5055 }
5056 return 0;
5057 }
5058
5059 gboolean
mono_type_generic_inst_is_valuetype(MonoType * type)5060 mono_type_generic_inst_is_valuetype (MonoType *type)
5061 {
5062 g_assert (type->type == MONO_TYPE_GENERICINST);
5063 return type->data.generic_class->container_class->valuetype;
5064 }
5065
5066 /**
5067 * mono_metadata_generic_class_is_valuetype:
5068 */
5069 gboolean
mono_metadata_generic_class_is_valuetype(MonoGenericClass * gclass)5070 mono_metadata_generic_class_is_valuetype (MonoGenericClass *gclass)
5071 {
5072 return gclass->container_class->valuetype;
5073 }
5074
5075 static gboolean
_mono_metadata_generic_class_equal(const MonoGenericClass * g1,const MonoGenericClass * g2,gboolean signature_only)5076 _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only)
5077 {
5078 MonoGenericInst *i1 = g1->context.class_inst;
5079 MonoGenericInst *i2 = g2->context.class_inst;
5080
5081 if (g1->is_dynamic != g2->is_dynamic)
5082 return FALSE;
5083 if (!mono_metadata_class_equal (g1->container_class, g2->container_class, signature_only))
5084 return FALSE;
5085 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5086 return FALSE;
5087 return g1->is_tb_open == g2->is_tb_open;
5088 }
5089
5090 static gboolean
_mono_metadata_generic_class_container_equal(const MonoGenericClass * g1,MonoClass * c2,gboolean signature_only)5091 _mono_metadata_generic_class_container_equal (const MonoGenericClass *g1, MonoClass *c2, gboolean signature_only)
5092 {
5093 MonoGenericInst *i1 = g1->context.class_inst;
5094 MonoGenericInst *i2 = mono_class_get_generic_container (c2)->context.class_inst;
5095
5096 if (!mono_metadata_class_equal (g1->container_class, c2, signature_only))
5097 return FALSE;
5098 if (!mono_generic_inst_equal_full (i1, i2, signature_only))
5099 return FALSE;
5100 return !g1->is_tb_open;
5101 }
5102
5103 guint
mono_metadata_generic_context_hash(const MonoGenericContext * context)5104 mono_metadata_generic_context_hash (const MonoGenericContext *context)
5105 {
5106 /* FIXME: check if this seed is good enough */
5107 guint hash = 0xc01dfee7;
5108 if (context->class_inst)
5109 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->class_inst);
5110 if (context->method_inst)
5111 hash = ((hash << 5) - hash) ^ mono_metadata_generic_inst_hash (context->method_inst);
5112 return hash;
5113 }
5114
5115 gboolean
mono_metadata_generic_context_equal(const MonoGenericContext * g1,const MonoGenericContext * g2)5116 mono_metadata_generic_context_equal (const MonoGenericContext *g1, const MonoGenericContext *g2)
5117 {
5118 return g1->class_inst == g2->class_inst && g1->method_inst == g2->method_inst;
5119 }
5120
5121 /*
5122 * mono_metadata_str_hash:
5123 *
5124 * This should be used instead of g_str_hash for computing hash codes visible
5125 * outside this module, since g_str_hash () is not guaranteed to be stable
5126 * (its not the same in eglib for example).
5127 */
5128 guint
mono_metadata_str_hash(gconstpointer v1)5129 mono_metadata_str_hash (gconstpointer v1)
5130 {
5131 /* Same as g_str_hash () in glib */
5132 char *p = (char *) v1;
5133 guint hash = *p;
5134
5135 while (*p++) {
5136 if (*p)
5137 hash = (hash << 5) - hash + *p;
5138 }
5139
5140 return hash;
5141 }
5142
5143 /**
5144 * mono_metadata_type_hash:
5145 * \param t1 a type
5146 * Computes a hash value for \p t1 to be used in \c GHashTable.
5147 * The returned hash is guaranteed to be the same across executions.
5148 */
5149 guint
mono_metadata_type_hash(MonoType * t1)5150 mono_metadata_type_hash (MonoType *t1)
5151 {
5152 guint hash = t1->type;
5153
5154 hash |= t1->byref << 6; /* do not collide with t1->type values */
5155 switch (t1->type) {
5156 case MONO_TYPE_VALUETYPE:
5157 case MONO_TYPE_CLASS:
5158 case MONO_TYPE_SZARRAY: {
5159 MonoClass *klass = t1->data.klass;
5160 /*
5161 * Dynamic classes must not be hashed on their type since it can change
5162 * during runtime. For example, if we hash a reference type that is
5163 * later made into a valuetype.
5164 *
5165 * This is specially problematic with generic instances since they are
5166 * inserted in a bunch of hash tables before been finished.
5167 */
5168 if (image_is_dynamic (klass->image))
5169 return (t1->byref << 6) | mono_metadata_str_hash (klass->name);
5170 return ((hash << 5) - hash) ^ mono_metadata_str_hash (klass->name);
5171 }
5172 case MONO_TYPE_PTR:
5173 return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
5174 case MONO_TYPE_ARRAY:
5175 return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
5176 case MONO_TYPE_GENERICINST:
5177 return ((hash << 5) - hash) ^ mono_generic_class_hash (t1->data.generic_class);
5178 case MONO_TYPE_VAR:
5179 case MONO_TYPE_MVAR:
5180 return ((hash << 5) - hash) ^ mono_metadata_generic_param_hash (t1->data.generic_param);
5181 default:
5182 return hash;
5183 }
5184 }
5185
5186 guint
mono_metadata_generic_param_hash(MonoGenericParam * p)5187 mono_metadata_generic_param_hash (MonoGenericParam *p)
5188 {
5189 guint hash;
5190 MonoGenericParamInfo *info;
5191
5192 hash = (mono_generic_param_num (p) << 2);
5193 if (p->gshared_constraint)
5194 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->gshared_constraint);
5195 info = mono_generic_param_info (p);
5196 /* Can't hash on the owner klass/method, since those might not be set when this is called */
5197 if (info)
5198 hash = ((hash << 5) - hash) ^ info->token;
5199 return hash;
5200 }
5201
5202 static gboolean
mono_metadata_generic_param_equal_internal(MonoGenericParam * p1,MonoGenericParam * p2,gboolean signature_only)5203 mono_metadata_generic_param_equal_internal (MonoGenericParam *p1, MonoGenericParam *p2, gboolean signature_only)
5204 {
5205 if (p1 == p2)
5206 return TRUE;
5207 if (mono_generic_param_num (p1) != mono_generic_param_num (p2))
5208 return FALSE;
5209 if (p1->gshared_constraint && p2->gshared_constraint) {
5210 if (!mono_metadata_type_equal (p1->gshared_constraint, p2->gshared_constraint))
5211 return FALSE;
5212 } else {
5213 if (p1->gshared_constraint != p2->gshared_constraint)
5214 return FALSE;
5215 }
5216
5217 /*
5218 * We have to compare the image as well because if we didn't,
5219 * the generic_inst_cache lookup wouldn't care about the image
5220 * of generic params, so what could happen is that a generic
5221 * inst with params from image A is put into the cache, then
5222 * image B gets that generic inst from the cache, image A is
5223 * unloaded, so the inst is deleted, but image B still retains
5224 * a pointer to it.
5225 */
5226 if (mono_generic_param_owner (p1) == mono_generic_param_owner (p2))
5227 return TRUE;
5228
5229 /*
5230 * If `signature_only' is true, we're comparing two (method) signatures.
5231 * In this case, the owner of two type parameters doesn't need to match.
5232 */
5233
5234 return signature_only;
5235 }
5236
5237 gboolean
mono_metadata_generic_param_equal(MonoGenericParam * p1,MonoGenericParam * p2)5238 mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2)
5239 {
5240 return mono_metadata_generic_param_equal_internal (p1, p2, TRUE);
5241 }
5242
5243 static gboolean
mono_metadata_class_equal(MonoClass * c1,MonoClass * c2,gboolean signature_only)5244 mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only)
5245 {
5246 if (c1 == c2)
5247 return TRUE;
5248 if (mono_class_is_ginst (c1) && mono_class_is_ginst (c2))
5249 return _mono_metadata_generic_class_equal (mono_class_get_generic_class (c1), mono_class_get_generic_class (c2), signature_only);
5250 if (mono_class_is_ginst (c1) && mono_class_is_gtd (c2))
5251 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c1), c2, signature_only);
5252 if (mono_class_is_gtd (c1) && mono_class_is_ginst (c2))
5253 return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c2), c1, signature_only);
5254 if ((c1->byval_arg.type == MONO_TYPE_VAR) && (c2->byval_arg.type == MONO_TYPE_VAR))
5255 return mono_metadata_generic_param_equal_internal (
5256 c1->byval_arg.data.generic_param, c2->byval_arg.data.generic_param, signature_only);
5257 if ((c1->byval_arg.type == MONO_TYPE_MVAR) && (c2->byval_arg.type == MONO_TYPE_MVAR))
5258 return mono_metadata_generic_param_equal_internal (
5259 c1->byval_arg.data.generic_param, c2->byval_arg.data.generic_param, signature_only);
5260 if (signature_only &&
5261 (c1->byval_arg.type == MONO_TYPE_SZARRAY) && (c2->byval_arg.type == MONO_TYPE_SZARRAY))
5262 return mono_metadata_class_equal (c1->byval_arg.data.klass, c2->byval_arg.data.klass, signature_only);
5263 if (signature_only &&
5264 (c1->byval_arg.type == MONO_TYPE_ARRAY) && (c2->byval_arg.type == MONO_TYPE_ARRAY))
5265 return do_mono_metadata_type_equal (&c1->byval_arg, &c2->byval_arg, signature_only);
5266 return FALSE;
5267 }
5268
5269 static gboolean
mono_metadata_fnptr_equal(MonoMethodSignature * s1,MonoMethodSignature * s2,gboolean signature_only)5270 mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only)
5271 {
5272 gpointer iter1 = 0, iter2 = 0;
5273
5274 if (s1 == s2)
5275 return TRUE;
5276 if (s1->call_convention != s2->call_convention)
5277 return FALSE;
5278 if (s1->sentinelpos != s2->sentinelpos)
5279 return FALSE;
5280 if (s1->hasthis != s2->hasthis)
5281 return FALSE;
5282 if (s1->explicit_this != s2->explicit_this)
5283 return FALSE;
5284 if (! do_mono_metadata_type_equal (s1->ret, s2->ret, signature_only))
5285 return FALSE;
5286 if (s1->param_count != s2->param_count)
5287 return FALSE;
5288
5289 while (TRUE) {
5290 MonoType *t1 = mono_signature_get_params (s1, &iter1);
5291 MonoType *t2 = mono_signature_get_params (s2, &iter2);
5292
5293 if (t1 == NULL || t2 == NULL)
5294 return (t1 == t2);
5295 if (! do_mono_metadata_type_equal (t1, t2, signature_only))
5296 return FALSE;
5297 }
5298 }
5299
5300 /*
5301 * mono_metadata_type_equal:
5302 * @t1: a type
5303 * @t2: another type
5304 * @signature_only: If true, treat ginsts as equal which are instantiated separately but have equal positional value
5305 *
5306 * Determine if @t1 and @t2 represent the same type.
5307 * Returns: #TRUE if @t1 and @t2 are equal.
5308 */
5309 static gboolean
do_mono_metadata_type_equal(MonoType * t1,MonoType * t2,gboolean signature_only)5310 do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only)
5311 {
5312 if (t1->type != t2->type || t1->byref != t2->byref)
5313 return FALSE;
5314
5315 switch (t1->type) {
5316 case MONO_TYPE_VOID:
5317 case MONO_TYPE_BOOLEAN:
5318 case MONO_TYPE_CHAR:
5319 case MONO_TYPE_I1:
5320 case MONO_TYPE_U1:
5321 case MONO_TYPE_I2:
5322 case MONO_TYPE_U2:
5323 case MONO_TYPE_I4:
5324 case MONO_TYPE_U4:
5325 case MONO_TYPE_I8:
5326 case MONO_TYPE_U8:
5327 case MONO_TYPE_R4:
5328 case MONO_TYPE_R8:
5329 case MONO_TYPE_STRING:
5330 case MONO_TYPE_I:
5331 case MONO_TYPE_U:
5332 case MONO_TYPE_OBJECT:
5333 case MONO_TYPE_TYPEDBYREF:
5334 return TRUE;
5335 case MONO_TYPE_VALUETYPE:
5336 case MONO_TYPE_CLASS:
5337 case MONO_TYPE_SZARRAY:
5338 return mono_metadata_class_equal (t1->data.klass, t2->data.klass, signature_only);
5339 case MONO_TYPE_PTR:
5340 return do_mono_metadata_type_equal (t1->data.type, t2->data.type, signature_only);
5341 case MONO_TYPE_ARRAY:
5342 if (t1->data.array->rank != t2->data.array->rank)
5343 return FALSE;
5344 return mono_metadata_class_equal (t1->data.array->eklass, t2->data.array->eklass, signature_only);
5345 case MONO_TYPE_GENERICINST:
5346 return _mono_metadata_generic_class_equal (
5347 t1->data.generic_class, t2->data.generic_class, signature_only);
5348 case MONO_TYPE_VAR:
5349 return mono_metadata_generic_param_equal_internal (
5350 t1->data.generic_param, t2->data.generic_param, signature_only);
5351 case MONO_TYPE_MVAR:
5352 return mono_metadata_generic_param_equal_internal (
5353 t1->data.generic_param, t2->data.generic_param, signature_only);
5354 case MONO_TYPE_FNPTR:
5355 return mono_metadata_fnptr_equal (t1->data.method, t2->data.method, signature_only);
5356 default:
5357 g_error ("implement type compare for %0x!", t1->type);
5358 return FALSE;
5359 }
5360
5361 return FALSE;
5362 }
5363
5364 /**
5365 * mono_metadata_type_equal:
5366 */
5367 gboolean
mono_metadata_type_equal(MonoType * t1,MonoType * t2)5368 mono_metadata_type_equal (MonoType *t1, MonoType *t2)
5369 {
5370 return do_mono_metadata_type_equal (t1, t2, FALSE);
5371 }
5372
5373 /**
5374 * mono_metadata_type_equal_full:
5375 * \param t1 a type
5376 * \param t2 another type
5377 * \param signature_only if signature only comparison should be made
5378 *
5379 * Determine if \p t1 and \p t2 are signature compatible if \p signature_only is TRUE, otherwise
5380 * behaves the same way as mono_metadata_type_equal.
5381 * The function mono_metadata_type_equal(a, b) is just a shortcut for mono_metadata_type_equal_full(a, b, FALSE).
5382 * \returns TRUE if \p t1 and \p t2 are equal taking \p signature_only into account.
5383 */
5384 gboolean
mono_metadata_type_equal_full(MonoType * t1,MonoType * t2,gboolean signature_only)5385 mono_metadata_type_equal_full (MonoType *t1, MonoType *t2, gboolean signature_only)
5386 {
5387 return do_mono_metadata_type_equal (t1, t2, signature_only);
5388 }
5389
5390 /**
5391 * mono_metadata_signature_equal:
5392 * \param sig1 a signature
5393 * \param sig2 another signature
5394 *
5395 * Determine if \p sig1 and \p sig2 represent the same signature, with the
5396 * same number of arguments and the same types.
5397 * \returns TRUE if \p sig1 and \p sig2 are equal.
5398 */
5399 gboolean
mono_metadata_signature_equal(MonoMethodSignature * sig1,MonoMethodSignature * sig2)5400 mono_metadata_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
5401 {
5402 int i;
5403
5404 if (sig1->hasthis != sig2->hasthis || sig1->param_count != sig2->param_count)
5405 return FALSE;
5406
5407 if (sig1->generic_param_count != sig2->generic_param_count)
5408 return FALSE;
5409
5410 /*
5411 * We're just comparing the signatures of two methods here:
5412 *
5413 * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
5414 * U and V are equal here.
5415 *
5416 * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
5417 */
5418
5419 for (i = 0; i < sig1->param_count; i++) {
5420 MonoType *p1 = sig1->params[i];
5421 MonoType *p2 = sig2->params[i];
5422
5423 /* if (p1->attrs != p2->attrs)
5424 return FALSE;
5425 */
5426 if (!do_mono_metadata_type_equal (p1, p2, TRUE))
5427 return FALSE;
5428 }
5429
5430 if (!do_mono_metadata_type_equal (sig1->ret, sig2->ret, TRUE))
5431 return FALSE;
5432 return TRUE;
5433 }
5434
5435 /**
5436 * mono_metadata_type_dup:
5437 * \param image image to alloc memory from
5438 * \param original type to duplicate
5439 * \returns copy of type allocated from the image's mempool (or from the heap, if \p image is null).
5440 */
5441 MonoType *
mono_metadata_type_dup(MonoImage * image,const MonoType * o)5442 mono_metadata_type_dup (MonoImage *image, const MonoType *o)
5443 {
5444 MonoType *r = NULL;
5445 int sizeof_o = MONO_SIZEOF_TYPE;
5446 if (o->num_mods)
5447 sizeof_o += o->num_mods * sizeof (MonoCustomMod);
5448
5449 r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_o) : (MonoType *)g_malloc (sizeof_o);
5450
5451 memcpy (r, o, sizeof_o);
5452
5453 if (o->type == MONO_TYPE_PTR) {
5454 r->data.type = mono_metadata_type_dup (image, o->data.type);
5455 } else if (o->type == MONO_TYPE_ARRAY) {
5456 r->data.array = mono_dup_array_type (image, o->data.array);
5457 } else if (o->type == MONO_TYPE_FNPTR) {
5458 /*FIXME the dup'ed signature is leaked mono_metadata_free_type*/
5459 r->data.method = mono_metadata_signature_deep_dup (image, o->data.method);
5460 }
5461 return r;
5462 }
5463
5464 /**
5465 * mono_signature_hash:
5466 */
5467 guint
mono_signature_hash(MonoMethodSignature * sig)5468 mono_signature_hash (MonoMethodSignature *sig)
5469 {
5470 guint i, res = sig->ret->type;
5471
5472 for (i = 0; i < sig->param_count; i++)
5473 res = (res << 5) - res + mono_type_hash (sig->params[i]);
5474
5475 return res;
5476 }
5477
5478 /*
5479 * mono_metadata_encode_value:
5480 * @value: value to encode
5481 * @buf: buffer where to write the compressed representation
5482 * @endbuf: pointer updated to point at the end of the encoded output
5483 *
5484 * Encodes the value @value in the compressed representation used
5485 * in metadata and stores the result in @buf. @buf needs to be big
5486 * enough to hold the data (4 bytes).
5487 */
5488 void
mono_metadata_encode_value(guint32 value,char * buf,char ** endbuf)5489 mono_metadata_encode_value (guint32 value, char *buf, char **endbuf)
5490 {
5491 char *p = buf;
5492
5493 if (value < 0x80)
5494 *p++ = value;
5495 else if (value < 0x4000) {
5496 p [0] = 0x80 | (value >> 8);
5497 p [1] = value & 0xff;
5498 p += 2;
5499 } else {
5500 p [0] = (value >> 24) | 0xc0;
5501 p [1] = (value >> 16) & 0xff;
5502 p [2] = (value >> 8) & 0xff;
5503 p [3] = value & 0xff;
5504 p += 4;
5505 }
5506 if (endbuf)
5507 *endbuf = p;
5508 }
5509
5510 /**
5511 * mono_metadata_field_info:
5512 * \param meta the Image the field is defined in
5513 * \param index the index in the field table representing the field
5514 * \param offset a pointer to an integer where to store the offset that may have been specified for the field in a FieldLayout table
5515 * \param rva a pointer to the RVA of the field data in the image that may have been defined in a \c FieldRVA table
5516 * \param marshal_spec a pointer to the marshal spec that may have been defined for the field in a \c FieldMarshal table.
5517 *
5518 * Gather info for field \p index that may have been defined in the \c FieldLayout,
5519 * \c FieldRVA and \c FieldMarshal tables.
5520 * Either of \p offset, \p rva and \p marshal_spec can be NULL if you're not interested
5521 * in the data.
5522 */
5523 void
mono_metadata_field_info(MonoImage * meta,guint32 index,guint32 * offset,guint32 * rva,MonoMarshalSpec ** marshal_spec)5524 mono_metadata_field_info (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
5525 MonoMarshalSpec **marshal_spec)
5526 {
5527 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, FALSE);
5528 }
5529
5530 void
mono_metadata_field_info_with_mempool(MonoImage * meta,guint32 index,guint32 * offset,guint32 * rva,MonoMarshalSpec ** marshal_spec)5531 mono_metadata_field_info_with_mempool (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
5532 MonoMarshalSpec **marshal_spec)
5533 {
5534 mono_metadata_field_info_full (meta, index, offset, rva, marshal_spec, TRUE);
5535 }
5536
5537 static void
mono_metadata_field_info_full(MonoImage * meta,guint32 index,guint32 * offset,guint32 * rva,MonoMarshalSpec ** marshal_spec,gboolean alloc_from_image)5538 mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva,
5539 MonoMarshalSpec **marshal_spec, gboolean alloc_from_image)
5540 {
5541 MonoTableInfo *tdef;
5542 locator_t loc;
5543
5544 loc.idx = index + 1;
5545 if (meta->uncompressed_metadata)
5546 loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx);
5547
5548 if (offset) {
5549 tdef = &meta->tables [MONO_TABLE_FIELDLAYOUT];
5550
5551 loc.col_idx = MONO_FIELD_LAYOUT_FIELD;
5552 loc.t = tdef;
5553
5554 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
5555 *offset = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_LAYOUT_OFFSET);
5556 } else {
5557 *offset = (guint32)-1;
5558 }
5559 }
5560 if (rva) {
5561 tdef = &meta->tables [MONO_TABLE_FIELDRVA];
5562
5563 loc.col_idx = MONO_FIELD_RVA_FIELD;
5564 loc.t = tdef;
5565
5566 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
5567 /*
5568 * LAMESPEC: There is no signature, no nothing, just the raw data.
5569 */
5570 *rva = mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_RVA_RVA);
5571 } else {
5572 *rva = 0;
5573 }
5574 }
5575 if (marshal_spec) {
5576 const char *p;
5577
5578 if ((p = mono_metadata_get_marshal_info (meta, index, TRUE))) {
5579 *marshal_spec = mono_metadata_parse_marshal_spec_full (alloc_from_image ? meta : NULL, meta, p);
5580 }
5581 }
5582
5583 }
5584
5585 /**
5586 * mono_metadata_get_constant_index:
5587 * \param meta the Image the field is defined in
5588 * \param index the token that may have a row defined in the constants table
5589 * \param hint possible position for the row
5590 *
5591 * \p token must be a \c FieldDef, \c ParamDef or \c PropertyDef token.
5592 *
5593 * \returns the index into the \c Constants table or 0 if not found.
5594 */
5595 guint32
mono_metadata_get_constant_index(MonoImage * meta,guint32 token,guint32 hint)5596 mono_metadata_get_constant_index (MonoImage *meta, guint32 token, guint32 hint)
5597 {
5598 MonoTableInfo *tdef;
5599 locator_t loc;
5600 guint32 index = mono_metadata_token_index (token);
5601
5602 tdef = &meta->tables [MONO_TABLE_CONSTANT];
5603 index <<= MONO_HASCONSTANT_BITS;
5604 switch (mono_metadata_token_table (token)) {
5605 case MONO_TABLE_FIELD:
5606 index |= MONO_HASCONSTANT_FIEDDEF;
5607 break;
5608 case MONO_TABLE_PARAM:
5609 index |= MONO_HASCONSTANT_PARAM;
5610 break;
5611 case MONO_TABLE_PROPERTY:
5612 index |= MONO_HASCONSTANT_PROPERTY;
5613 break;
5614 default:
5615 g_warning ("Not a valid token for the constant table: 0x%08x", token);
5616 return 0;
5617 }
5618 loc.idx = index;
5619 loc.col_idx = MONO_CONSTANT_PARENT;
5620 loc.t = tdef;
5621
5622 /* FIXME: Index translation */
5623
5624 if ((hint > 0) && (hint < tdef->rows) && (mono_metadata_decode_row_col (tdef, hint - 1, MONO_CONSTANT_PARENT) == index))
5625 return hint;
5626
5627 if (tdef->base && mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) {
5628 return loc.result + 1;
5629 }
5630 return 0;
5631 }
5632
5633 /**
5634 * mono_metadata_events_from_typedef:
5635 * \param meta metadata context
5636 * \param index 0-based index (in the \c TypeDef table) describing a type
5637 * \returns the 0-based index in the \c Event table for the events in the
5638 * type. The last event that belongs to the type (plus 1) is stored
5639 * in the \p end_idx pointer.
5640 */
5641 guint32
mono_metadata_events_from_typedef(MonoImage * meta,guint32 index,guint * end_idx)5642 mono_metadata_events_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
5643 {
5644 locator_t loc;
5645 guint32 start, end;
5646 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_EVENTMAP];
5647
5648 *end_idx = 0;
5649
5650 if (!tdef->base)
5651 return 0;
5652
5653 loc.t = tdef;
5654 loc.col_idx = MONO_EVENT_MAP_PARENT;
5655 loc.idx = index + 1;
5656
5657 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5658 return 0;
5659
5660 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_EVENT_MAP_EVENTLIST);
5661 if (loc.result + 1 < tdef->rows) {
5662 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_EVENT_MAP_EVENTLIST) - 1;
5663 } else {
5664 end = meta->tables [MONO_TABLE_EVENT].rows;
5665 }
5666
5667 *end_idx = end;
5668 return start - 1;
5669 }
5670
5671 /**
5672 * mono_metadata_methods_from_event:
5673 * \param meta metadata context
5674 * \param index 0-based index (in the \c Event table) describing a event
5675 * \returns the 0-based index in the \c MethodDef table for the methods in the
5676 * event. The last method that belongs to the event (plus 1) is stored
5677 * in the \p end_idx pointer.
5678 */
5679 guint32
mono_metadata_methods_from_event(MonoImage * meta,guint32 index,guint * end_idx)5680 mono_metadata_methods_from_event (MonoImage *meta, guint32 index, guint *end_idx)
5681 {
5682 locator_t loc;
5683 guint start, end;
5684 guint32 cols [MONO_METHOD_SEMA_SIZE];
5685 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
5686
5687 *end_idx = 0;
5688 if (!msemt->base)
5689 return 0;
5690
5691 if (meta->uncompressed_metadata)
5692 index = search_ptr_table (meta, MONO_TABLE_EVENT_POINTER, index + 1) - 1;
5693
5694 loc.t = msemt;
5695 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
5696 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT; /* Method association coded index */
5697
5698 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
5699 return 0;
5700
5701 start = loc.result;
5702 /*
5703 * We may end up in the middle of the rows...
5704 */
5705 while (start > 0) {
5706 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
5707 start--;
5708 else
5709 break;
5710 }
5711 end = start + 1;
5712 while (end < msemt->rows) {
5713 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
5714 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
5715 break;
5716 ++end;
5717 }
5718 *end_idx = end;
5719 return start;
5720 }
5721
5722 /**
5723 * mono_metadata_properties_from_typedef:
5724 * \param meta metadata context
5725 * \param index 0-based index (in the \c TypeDef table) describing a type
5726 * \returns the 0-based index in the \c Property table for the properties in the
5727 * type. The last property that belongs to the type (plus 1) is stored
5728 * in the \p end_idx pointer.
5729 */
5730 guint32
mono_metadata_properties_from_typedef(MonoImage * meta,guint32 index,guint * end_idx)5731 mono_metadata_properties_from_typedef (MonoImage *meta, guint32 index, guint *end_idx)
5732 {
5733 locator_t loc;
5734 guint32 start, end;
5735 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_PROPERTYMAP];
5736
5737 *end_idx = 0;
5738
5739 if (!tdef->base)
5740 return 0;
5741
5742 loc.t = tdef;
5743 loc.col_idx = MONO_PROPERTY_MAP_PARENT;
5744 loc.idx = index + 1;
5745
5746 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5747 return 0;
5748
5749 start = mono_metadata_decode_row_col (tdef, loc.result, MONO_PROPERTY_MAP_PROPERTY_LIST);
5750 if (loc.result + 1 < tdef->rows) {
5751 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_PROPERTY_MAP_PROPERTY_LIST) - 1;
5752 } else {
5753 end = meta->tables [MONO_TABLE_PROPERTY].rows;
5754 }
5755
5756 *end_idx = end;
5757 return start - 1;
5758 }
5759
5760 /**
5761 * mono_metadata_methods_from_property:
5762 * \param meta metadata context
5763 * \param index 0-based index (in the \c PropertyDef table) describing a property
5764 * \returns the 0-based index in the \c MethodDef table for the methods in the
5765 * property. The last method that belongs to the property (plus 1) is stored
5766 * in the \p end_idx pointer.
5767 */
5768 guint32
mono_metadata_methods_from_property(MonoImage * meta,guint32 index,guint * end_idx)5769 mono_metadata_methods_from_property (MonoImage *meta, guint32 index, guint *end_idx)
5770 {
5771 locator_t loc;
5772 guint start, end;
5773 guint32 cols [MONO_METHOD_SEMA_SIZE];
5774 MonoTableInfo *msemt = &meta->tables [MONO_TABLE_METHODSEMANTICS];
5775
5776 *end_idx = 0;
5777 if (!msemt->base)
5778 return 0;
5779
5780 if (meta->uncompressed_metadata)
5781 index = search_ptr_table (meta, MONO_TABLE_PROPERTY_POINTER, index + 1) - 1;
5782
5783 loc.t = msemt;
5784 loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
5785 loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY; /* Method association coded index */
5786
5787 if (!mono_binary_search (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
5788 return 0;
5789
5790 start = loc.result;
5791 /*
5792 * We may end up in the middle of the rows...
5793 */
5794 while (start > 0) {
5795 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
5796 start--;
5797 else
5798 break;
5799 }
5800 end = start + 1;
5801 while (end < msemt->rows) {
5802 mono_metadata_decode_row (msemt, end, cols, MONO_METHOD_SEMA_SIZE);
5803 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
5804 break;
5805 ++end;
5806 }
5807 *end_idx = end;
5808 return start;
5809 }
5810
5811 /**
5812 * mono_metadata_implmap_from_method:
5813 */
5814 guint32
mono_metadata_implmap_from_method(MonoImage * meta,guint32 method_idx)5815 mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx)
5816 {
5817 locator_t loc;
5818 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_IMPLMAP];
5819
5820 if (!tdef->base)
5821 return 0;
5822
5823 /* No index translation seems to be needed */
5824
5825 loc.t = tdef;
5826 loc.col_idx = MONO_IMPLMAP_MEMBER;
5827 loc.idx = ((method_idx + 1) << MONO_MEMBERFORWD_BITS) | MONO_MEMBERFORWD_METHODDEF;
5828
5829 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
5830 return 0;
5831
5832 return loc.result + 1;
5833 }
5834
5835 /**
5836 * mono_type_create_from_typespec:
5837 * \param image context where the image is created
5838 * \param type_spec typespec token
5839 * \deprecated use \c mono_type_create_from_typespec_checked that has proper error handling
5840 *
5841 * Creates a \c MonoType representing the \c TypeSpec indexed by the \p type_spec
5842 * token.
5843 */
5844 MonoType *
mono_type_create_from_typespec(MonoImage * image,guint32 type_spec)5845 mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
5846 {
5847 MonoError error;
5848 MonoType *type = mono_type_create_from_typespec_checked (image, type_spec, &error);
5849 if (!type)
5850 g_error ("Could not create typespec %x due to %s", type_spec, mono_error_get_message (&error));
5851 return type;
5852 }
5853
5854 MonoType *
mono_type_create_from_typespec_checked(MonoImage * image,guint32 type_spec,MonoError * error)5855 mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, MonoError *error)
5856
5857 {
5858 guint32 idx = mono_metadata_token_index (type_spec);
5859 MonoTableInfo *t;
5860 guint32 cols [MONO_TYPESPEC_SIZE];
5861 const char *ptr;
5862 MonoType *type, *type2;
5863
5864 error_init (error);
5865
5866 type = (MonoType *)mono_conc_hashtable_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
5867 if (type)
5868 return type;
5869
5870 t = &image->tables [MONO_TABLE_TYPESPEC];
5871
5872 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
5873 ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
5874
5875 if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, NULL)) {
5876 mono_error_set_bad_image (error, image, "Could not verify type spec %08x.", type_spec);
5877 return NULL;
5878 }
5879
5880 mono_metadata_decode_value (ptr, &ptr);
5881
5882 type = mono_metadata_parse_type_checked (image, NULL, 0, TRUE, ptr, &ptr, error);
5883 if (!type)
5884 return NULL;
5885
5886 type2 = mono_metadata_type_dup (image, type);
5887 mono_metadata_free_type (type);
5888
5889 mono_image_lock (image);
5890
5891 /* We might leak some data in the image mempool if found */
5892 type = mono_conc_hashtable_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
5893 if (!type)
5894 type = type2;
5895
5896 mono_image_unlock (image);
5897
5898 return type;
5899 }
5900
5901
5902 static char*
mono_image_strndup(MonoImage * image,const char * data,guint len)5903 mono_image_strndup (MonoImage *image, const char *data, guint len)
5904 {
5905 char *res;
5906 if (!image)
5907 return g_strndup (data, len);
5908 res = (char *)mono_image_alloc (image, len + 1);
5909 memcpy (res, data, len);
5910 res [len] = 0;
5911 return res;
5912 }
5913
5914 /**
5915 * mono_metadata_parse_marshal_spec:
5916 */
5917 MonoMarshalSpec *
mono_metadata_parse_marshal_spec(MonoImage * image,const char * ptr)5918 mono_metadata_parse_marshal_spec (MonoImage *image, const char *ptr)
5919 {
5920 return mono_metadata_parse_marshal_spec_full (NULL, image, ptr);
5921 }
5922
5923 /*
5924 * If IMAGE is non-null, memory will be allocated from its mempool, otherwise it will be allocated using malloc.
5925 * PARENT_IMAGE is the image containing the marshal spec.
5926 */
5927 MonoMarshalSpec *
mono_metadata_parse_marshal_spec_full(MonoImage * image,MonoImage * parent_image,const char * ptr)5928 mono_metadata_parse_marshal_spec_full (MonoImage *image, MonoImage *parent_image, const char *ptr)
5929 {
5930 MonoMarshalSpec *res;
5931 int len;
5932 const char *start = ptr;
5933
5934 /* fixme: this is incomplete, but I cant find more infos in the specs */
5935
5936 if (image)
5937 res = (MonoMarshalSpec *)mono_image_alloc0 (image, sizeof (MonoMarshalSpec));
5938 else
5939 res = g_new0 (MonoMarshalSpec, 1);
5940
5941 len = mono_metadata_decode_value (ptr, &ptr);
5942 res->native = (MonoMarshalNative)*ptr++;
5943
5944 if (res->native == MONO_NATIVE_LPARRAY) {
5945 res->data.array_data.param_num = -1;
5946 res->data.array_data.num_elem = -1;
5947 res->data.array_data.elem_mult = -1;
5948
5949 if (ptr - start <= len)
5950 res->data.array_data.elem_type = (MonoMarshalNative)*ptr++;
5951 if (ptr - start <= len)
5952 res->data.array_data.param_num = mono_metadata_decode_value (ptr, &ptr);
5953 if (ptr - start <= len)
5954 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
5955 if (ptr - start <= len) {
5956 /*
5957 * LAMESPEC: Older spec versions say this parameter comes before
5958 * num_elem. Never spec versions don't talk about elem_mult at
5959 * all, but csc still emits it, and it is used to distinguish
5960 * between param_num being 0, and param_num being omitted.
5961 * So if (param_num == 0) && (num_elem > 0), then
5962 * elem_mult == 0 -> the array size is num_elem
5963 * elem_mult == 1 -> the array size is @param_num + num_elem
5964 */
5965 res->data.array_data.elem_mult = mono_metadata_decode_value (ptr, &ptr);
5966 }
5967 }
5968
5969 if (res->native == MONO_NATIVE_BYVALTSTR) {
5970 if (ptr - start <= len)
5971 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
5972 }
5973
5974 if (res->native == MONO_NATIVE_BYVALARRAY) {
5975 if (ptr - start <= len)
5976 res->data.array_data.num_elem = mono_metadata_decode_value (ptr, &ptr);
5977 }
5978
5979 if (res->native == MONO_NATIVE_CUSTOM) {
5980 /* skip unused type guid */
5981 len = mono_metadata_decode_value (ptr, &ptr);
5982 ptr += len;
5983 /* skip unused native type name */
5984 len = mono_metadata_decode_value (ptr, &ptr);
5985 ptr += len;
5986 /* read custom marshaler type name */
5987 len = mono_metadata_decode_value (ptr, &ptr);
5988 res->data.custom_data.custom_name = mono_image_strndup (image, ptr, len);
5989 ptr += len;
5990 /* read cookie string */
5991 len = mono_metadata_decode_value (ptr, &ptr);
5992 res->data.custom_data.cookie = mono_image_strndup (image, ptr, len);
5993 res->data.custom_data.image = parent_image;
5994 }
5995
5996 if (res->native == MONO_NATIVE_SAFEARRAY) {
5997 res->data.safearray_data.elem_type = (MonoMarshalVariant)0;
5998 res->data.safearray_data.num_elem = 0;
5999 if (ptr - start <= len)
6000 res->data.safearray_data.elem_type = (MonoMarshalVariant)*ptr++;
6001 if (ptr - start <= len)
6002 res->data.safearray_data.num_elem = *ptr++;
6003 }
6004 return res;
6005 }
6006
6007 /**
6008 * mono_metadata_free_marshal_spec:
6009 */
6010 void
mono_metadata_free_marshal_spec(MonoMarshalSpec * spec)6011 mono_metadata_free_marshal_spec (MonoMarshalSpec *spec)
6012 {
6013 if (spec->native == MONO_NATIVE_CUSTOM) {
6014 g_free (spec->data.custom_data.custom_name);
6015 g_free (spec->data.custom_data.cookie);
6016 }
6017 g_free (spec);
6018 }
6019
6020 /**
6021 * mono_type_to_unmanaged:
6022 * The value pointed to by \p conv will contain the kind of marshalling required for this
6023 * particular type one of the \c MONO_MARSHAL_CONV_ enumeration values.
6024 * \returns A \c MonoMarshalNative enumeration value (<code>MONO_NATIVE_</code>) value
6025 * describing the underlying native reprensetation of the type.
6026 */
6027 guint32
mono_type_to_unmanaged(MonoType * type,MonoMarshalSpec * mspec,gboolean as_field,gboolean unicode,MonoMarshalConv * conv)6028 mono_type_to_unmanaged (MonoType *type, MonoMarshalSpec *mspec, gboolean as_field,
6029 gboolean unicode, MonoMarshalConv *conv)
6030 {
6031 MonoMarshalConv dummy_conv;
6032 int t = type->type;
6033
6034 if (!conv)
6035 conv = &dummy_conv;
6036
6037 *conv = MONO_MARSHAL_CONV_NONE;
6038
6039 if (type->byref)
6040 return MONO_NATIVE_UINT;
6041
6042 handle_enum:
6043 switch (t) {
6044 case MONO_TYPE_BOOLEAN:
6045 if (mspec) {
6046 switch (mspec->native) {
6047 case MONO_NATIVE_VARIANTBOOL:
6048 *conv = MONO_MARSHAL_CONV_BOOL_VARIANTBOOL;
6049 return MONO_NATIVE_VARIANTBOOL;
6050 case MONO_NATIVE_BOOLEAN:
6051 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6052 return MONO_NATIVE_BOOLEAN;
6053 case MONO_NATIVE_I1:
6054 case MONO_NATIVE_U1:
6055 return mspec->native;
6056 default:
6057 g_error ("cant marshal bool to native type %02x", mspec->native);
6058 }
6059 }
6060 *conv = MONO_MARSHAL_CONV_BOOL_I4;
6061 return MONO_NATIVE_BOOLEAN;
6062 case MONO_TYPE_CHAR:
6063 if (mspec) {
6064 switch (mspec->native) {
6065 case MONO_NATIVE_U2:
6066 case MONO_NATIVE_U1:
6067 return mspec->native;
6068 default:
6069 g_error ("cant marshal char to native type %02x", mspec->native);
6070 }
6071 }
6072 return unicode ? MONO_NATIVE_U2 : MONO_NATIVE_U1;
6073 case MONO_TYPE_I1: return MONO_NATIVE_I1;
6074 case MONO_TYPE_U1: return MONO_NATIVE_U1;
6075 case MONO_TYPE_I2: return MONO_NATIVE_I2;
6076 case MONO_TYPE_U2: return MONO_NATIVE_U2;
6077 case MONO_TYPE_I4: return MONO_NATIVE_I4;
6078 case MONO_TYPE_U4: return MONO_NATIVE_U4;
6079 case MONO_TYPE_I8: return MONO_NATIVE_I8;
6080 case MONO_TYPE_U8: return MONO_NATIVE_U8;
6081 case MONO_TYPE_R4: return MONO_NATIVE_R4;
6082 case MONO_TYPE_R8: return MONO_NATIVE_R8;
6083 case MONO_TYPE_STRING:
6084 if (mspec) {
6085 switch (mspec->native) {
6086 case MONO_NATIVE_BSTR:
6087 *conv = MONO_MARSHAL_CONV_STR_BSTR;
6088 return MONO_NATIVE_BSTR;
6089 case MONO_NATIVE_LPSTR:
6090 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6091 return MONO_NATIVE_LPSTR;
6092 case MONO_NATIVE_LPWSTR:
6093 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6094 return MONO_NATIVE_LPWSTR;
6095 case MONO_NATIVE_LPTSTR:
6096 *conv = MONO_MARSHAL_CONV_STR_LPTSTR;
6097 return MONO_NATIVE_LPTSTR;
6098 case MONO_NATIVE_ANSIBSTR:
6099 *conv = MONO_MARSHAL_CONV_STR_ANSIBSTR;
6100 return MONO_NATIVE_ANSIBSTR;
6101 case MONO_NATIVE_TBSTR:
6102 *conv = MONO_MARSHAL_CONV_STR_TBSTR;
6103 return MONO_NATIVE_TBSTR;
6104 case MONO_NATIVE_UTF8STR:
6105 *conv = MONO_MARSHAL_CONV_STR_UTF8STR;
6106 return MONO_NATIVE_UTF8STR;
6107 case MONO_NATIVE_BYVALTSTR:
6108 if (unicode)
6109 *conv = MONO_MARSHAL_CONV_STR_BYVALWSTR;
6110 else
6111 *conv = MONO_MARSHAL_CONV_STR_BYVALSTR;
6112 return MONO_NATIVE_BYVALTSTR;
6113 default:
6114 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);
6115 }
6116 }
6117 if (unicode) {
6118 *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
6119 return MONO_NATIVE_LPWSTR;
6120 }
6121 else {
6122 *conv = MONO_MARSHAL_CONV_STR_LPSTR;
6123 return MONO_NATIVE_LPSTR;
6124 }
6125 case MONO_TYPE_PTR: return MONO_NATIVE_UINT;
6126 case MONO_TYPE_VALUETYPE: /*FIXME*/
6127 if (type->data.klass->enumtype) {
6128 t = mono_class_enum_basetype (type->data.klass)->type;
6129 goto handle_enum;
6130 }
6131 if (type->data.klass == mono_defaults.handleref_class){
6132 *conv = MONO_MARSHAL_CONV_HANDLEREF;
6133 return MONO_NATIVE_INT;
6134 }
6135 return MONO_NATIVE_STRUCT;
6136 case MONO_TYPE_SZARRAY:
6137 case MONO_TYPE_ARRAY:
6138 if (mspec) {
6139 switch (mspec->native) {
6140 case MONO_NATIVE_BYVALARRAY:
6141 if ((type->data.klass->element_class == mono_defaults.char_class) && !unicode)
6142 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY;
6143 else
6144 *conv = MONO_MARSHAL_CONV_ARRAY_BYVALARRAY;
6145 return MONO_NATIVE_BYVALARRAY;
6146 case MONO_NATIVE_SAFEARRAY:
6147 *conv = MONO_MARSHAL_CONV_ARRAY_SAVEARRAY;
6148 return MONO_NATIVE_SAFEARRAY;
6149 case MONO_NATIVE_LPARRAY:
6150 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6151 return MONO_NATIVE_LPARRAY;
6152 default:
6153 g_error ("cant marshal array as native type %02x", mspec->native);
6154 }
6155 }
6156
6157 *conv = MONO_MARSHAL_CONV_ARRAY_LPARRAY;
6158 return MONO_NATIVE_LPARRAY;
6159 case MONO_TYPE_I: return MONO_NATIVE_INT;
6160 case MONO_TYPE_U: return MONO_NATIVE_UINT;
6161 case MONO_TYPE_CLASS:
6162 case MONO_TYPE_OBJECT: {
6163 /* FIXME : we need to handle ArrayList and StringBuilder here, probably */
6164 if (mspec) {
6165 switch (mspec->native) {
6166 case MONO_NATIVE_STRUCT:
6167 return MONO_NATIVE_STRUCT;
6168 case MONO_NATIVE_CUSTOM:
6169 return MONO_NATIVE_CUSTOM;
6170 case MONO_NATIVE_INTERFACE:
6171 *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
6172 return MONO_NATIVE_INTERFACE;
6173 case MONO_NATIVE_IDISPATCH:
6174 *conv = MONO_MARSHAL_CONV_OBJECT_IDISPATCH;
6175 return MONO_NATIVE_IDISPATCH;
6176 case MONO_NATIVE_IUNKNOWN:
6177 *conv = MONO_MARSHAL_CONV_OBJECT_IUNKNOWN;
6178 return MONO_NATIVE_IUNKNOWN;
6179 case MONO_NATIVE_FUNC:
6180 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6181 type->data.klass == mono_defaults.delegate_class ||
6182 type->data.klass->parent == mono_defaults.multicastdelegate_class)) {
6183 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6184 return MONO_NATIVE_FUNC;
6185 }
6186 /* Fall through */
6187 default:
6188 g_error ("cant marshal object as native type %02x", mspec->native);
6189 }
6190 }
6191 if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
6192 type->data.klass == mono_defaults.delegate_class ||
6193 type->data.klass->parent == mono_defaults.multicastdelegate_class)) {
6194 *conv = MONO_MARSHAL_CONV_DEL_FTN;
6195 return MONO_NATIVE_FUNC;
6196 }
6197 if (mono_class_try_get_safehandle_class () && type->data.klass == mono_class_try_get_safehandle_class ()){
6198 *conv = MONO_MARSHAL_CONV_SAFEHANDLE;
6199 return MONO_NATIVE_INT;
6200 }
6201 *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
6202 return MONO_NATIVE_STRUCT;
6203 }
6204 case MONO_TYPE_FNPTR: return MONO_NATIVE_FUNC;
6205 case MONO_TYPE_GENERICINST:
6206 type = &type->data.generic_class->container_class->byval_arg;
6207 t = type->type;
6208 goto handle_enum;
6209 case MONO_TYPE_TYPEDBYREF:
6210 default:
6211 g_error ("type 0x%02x not handled in marshal", t);
6212 }
6213 return MONO_NATIVE_MAX;
6214 }
6215
6216 /**
6217 * mono_metadata_get_marshal_info:
6218 */
6219 const char*
mono_metadata_get_marshal_info(MonoImage * meta,guint32 idx,gboolean is_field)6220 mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field)
6221 {
6222 locator_t loc;
6223 MonoTableInfo *tdef = &meta->tables [MONO_TABLE_FIELDMARSHAL];
6224
6225 if (!tdef->base)
6226 return NULL;
6227
6228 loc.t = tdef;
6229 loc.col_idx = MONO_FIELD_MARSHAL_PARENT;
6230 loc.idx = ((idx + 1) << MONO_HAS_FIELD_MARSHAL_BITS) | (is_field? MONO_HAS_FIELD_MARSHAL_FIELDSREF: MONO_HAS_FIELD_MARSHAL_PARAMDEF);
6231
6232 /* FIXME: Index translation */
6233
6234 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6235 return NULL;
6236
6237 return mono_metadata_blob_heap (meta, mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_MARSHAL_NATIVE_TYPE));
6238 }
6239
6240 MonoMethod*
method_from_method_def_or_ref(MonoImage * m,guint32 tok,MonoGenericContext * context,MonoError * error)6241 method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context, MonoError *error)
6242 {
6243 MonoMethod *result = NULL;
6244 guint32 idx = tok >> MONO_METHODDEFORREF_BITS;
6245
6246 error_init (error);
6247
6248 switch (tok & MONO_METHODDEFORREF_MASK) {
6249 case MONO_METHODDEFORREF_METHODDEF:
6250 result = mono_get_method_checked (m, MONO_TOKEN_METHOD_DEF | idx, NULL, context, error);
6251 break;
6252 case MONO_METHODDEFORREF_METHODREF:
6253 result = mono_get_method_checked (m, MONO_TOKEN_MEMBER_REF | idx, NULL, context, error);
6254 break;
6255 default:
6256 mono_error_set_bad_image (error, m, "Invalid MethodDefOfRef token %x", tok);
6257 }
6258
6259 return result;
6260 }
6261
6262 /*
6263 * mono_class_get_overrides_full:
6264 *
6265 * Return the method overrides belonging to class @type_token in @overrides, and
6266 * the number of overrides in @num_overrides.
6267 *
6268 * Returns: TRUE on success, FALSE on failure.
6269 */
6270 gboolean
mono_class_get_overrides_full(MonoImage * image,guint32 type_token,MonoMethod *** overrides,gint32 * num_overrides,MonoGenericContext * generic_context)6271 mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides,
6272 MonoGenericContext *generic_context)
6273 {
6274 MonoError error;
6275 locator_t loc;
6276 MonoTableInfo *tdef = &image->tables [MONO_TABLE_METHODIMPL];
6277 guint32 start, end;
6278 gint32 i, num;
6279 guint32 cols [MONO_METHODIMPL_SIZE];
6280 MonoMethod **result;
6281 gint32 ok = TRUE;
6282
6283 *overrides = NULL;
6284 if (num_overrides)
6285 *num_overrides = 0;
6286
6287 if (!tdef->base)
6288 return TRUE;
6289
6290 loc.t = tdef;
6291 loc.col_idx = MONO_METHODIMPL_CLASS;
6292 loc.idx = mono_metadata_token_index (type_token);
6293
6294 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6295 return TRUE;
6296
6297 start = loc.result;
6298 end = start + 1;
6299 /*
6300 * We may end up in the middle of the rows...
6301 */
6302 while (start > 0) {
6303 if (loc.idx == mono_metadata_decode_row_col (tdef, start - 1, MONO_METHODIMPL_CLASS))
6304 start--;
6305 else
6306 break;
6307 }
6308 while (end < tdef->rows) {
6309 if (loc.idx == mono_metadata_decode_row_col (tdef, end, MONO_METHODIMPL_CLASS))
6310 end++;
6311 else
6312 break;
6313 }
6314 num = end - start;
6315 result = g_new (MonoMethod*, num * 2);
6316 for (i = 0; i < num; ++i) {
6317 MonoMethod *method;
6318
6319 if (!mono_verifier_verify_methodimpl_row (image, start + i, &error)) {
6320 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6321 ok = FALSE;
6322 break;
6323 }
6324
6325 mono_metadata_decode_row (tdef, start + i, cols, MONO_METHODIMPL_SIZE);
6326 method = method_from_method_def_or_ref (
6327 image, cols [MONO_METHODIMPL_DECLARATION], generic_context, &error);
6328 if (method == NULL) {
6329 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6330 ok = FALSE;
6331 }
6332 result [i * 2] = method;
6333 method = method_from_method_def_or_ref (
6334 image, cols [MONO_METHODIMPL_BODY], generic_context, &error);
6335 if (method == NULL) {
6336 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6337 ok = FALSE;
6338 }
6339 result [i * 2 + 1] = method;
6340 }
6341
6342 *overrides = result;
6343 if (num_overrides)
6344 *num_overrides = num;
6345 return ok;
6346 }
6347
6348 /**
6349 * mono_guid_to_string:
6350 *
6351 * Converts a 16 byte Microsoft GUID to the standard string representation.
6352 */
6353 char *
mono_guid_to_string(const guint8 * guid)6354 mono_guid_to_string (const guint8 *guid)
6355 {
6356 return g_strdup_printf ("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
6357 guid[3], guid[2], guid[1], guid[0],
6358 guid[5], guid[4],
6359 guid[7], guid[6],
6360 guid[8], guid[9],
6361 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
6362 }
6363
6364 /**
6365 * mono_guid_to_string_minimal:
6366 *
6367 * Converts a 16 byte Microsoft GUID to lower case no '-' representation..
6368 */
6369 char *
mono_guid_to_string_minimal(const guint8 * guid)6370 mono_guid_to_string_minimal (const guint8 *guid)
6371 {
6372 return g_strdup_printf ("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
6373 guid[3], guid[2], guid[1], guid[0],
6374 guid[5], guid[4],
6375 guid[7], guid[6],
6376 guid[8], guid[9],
6377 guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
6378 }
6379 static gboolean
get_constraints(MonoImage * image,int owner,MonoClass *** constraints,MonoGenericContainer * container,MonoError * error)6380 get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGenericContainer *container, MonoError *error)
6381 {
6382 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
6383 guint32 cols [MONO_GENPARCONSTRAINT_SIZE];
6384 guint32 i, token, found;
6385 MonoClass *klass, **res;
6386 GSList *cons = NULL, *tmp;
6387 MonoGenericContext *context = &container->context;
6388
6389 error_init (error);
6390
6391 *constraints = NULL;
6392 found = 0;
6393 for (i = 0; i < tdef->rows; ++i) {
6394 mono_metadata_decode_row (tdef, i, cols, MONO_GENPARCONSTRAINT_SIZE);
6395 if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) {
6396 token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]);
6397 klass = mono_class_get_and_inflate_typespec_checked (image, token, context, error);
6398 if (!klass) {
6399 g_slist_free (cons);
6400 return FALSE;
6401 }
6402 cons = g_slist_append (cons, klass);
6403 ++found;
6404 } else {
6405 /* contiguous list finished */
6406 if (found)
6407 break;
6408 }
6409 }
6410 if (!found)
6411 return TRUE;
6412 res = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * (found + 1));
6413 for (i = 0, tmp = cons; i < found; ++i, tmp = tmp->next) {
6414 res [i] = (MonoClass *)tmp->data;
6415 }
6416 g_slist_free (cons);
6417 *constraints = res;
6418 return TRUE;
6419 }
6420
6421 /*
6422 * mono_metadata_get_generic_param_row:
6423 *
6424 * @image:
6425 * @token: TypeOrMethodDef token, owner for GenericParam
6426 * @owner: coded token, set on return
6427 *
6428 * Returns: 1-based row-id in the GenericParam table whose
6429 * owner is @token. 0 if not found.
6430 */
6431 guint32
mono_metadata_get_generic_param_row(MonoImage * image,guint32 token,guint32 * owner)6432 mono_metadata_get_generic_param_row (MonoImage *image, guint32 token, guint32 *owner)
6433 {
6434 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
6435 locator_t loc;
6436
6437 g_assert (owner);
6438 if (!tdef->base)
6439 return 0;
6440
6441 if (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
6442 *owner = MONO_TYPEORMETHOD_TYPE;
6443 else if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
6444 *owner = MONO_TYPEORMETHOD_METHOD;
6445 else {
6446 g_error ("wrong token %x to get_generic_param_row", token);
6447 return 0;
6448 }
6449 *owner |= mono_metadata_token_index (token) << MONO_TYPEORMETHOD_BITS;
6450
6451 loc.idx = *owner;
6452 loc.col_idx = MONO_GENERICPARAM_OWNER;
6453 loc.t = tdef;
6454
6455 if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
6456 return 0;
6457
6458 /* Find the first entry by searching backwards */
6459 while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_GENERICPARAM_OWNER) == loc.idx))
6460 loc.result --;
6461
6462 return loc.result + 1;
6463 }
6464
6465 gboolean
mono_metadata_has_generic_params(MonoImage * image,guint32 token)6466 mono_metadata_has_generic_params (MonoImage *image, guint32 token)
6467 {
6468 guint32 owner;
6469 return mono_metadata_get_generic_param_row (image, token, &owner);
6470 }
6471
6472 /*
6473 * Memory is allocated from IMAGE's mempool.
6474 */
6475 gboolean
mono_metadata_load_generic_param_constraints_checked(MonoImage * image,guint32 token,MonoGenericContainer * container,MonoError * error)6476 mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token,
6477 MonoGenericContainer *container, MonoError *error)
6478 {
6479
6480 guint32 start_row, i, owner;
6481 error_init (error);
6482
6483 if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner)))
6484 return TRUE;
6485 for (i = 0; i < container->type_argc; i++) {
6486 if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container, error)) {
6487 return FALSE;
6488 }
6489 }
6490 return TRUE;
6491 }
6492
6493 /*
6494 * mono_metadata_load_generic_params:
6495 *
6496 * Load the type parameters from the type or method definition @token.
6497 *
6498 * Use this method after parsing a type or method definition to figure out whether it's a generic
6499 * type / method. When parsing a method definition, @parent_container points to the generic container
6500 * of the current class, if any.
6501 *
6502 * Note: This method does not load the constraints: for typedefs, this has to be done after fully
6503 * creating the type.
6504 *
6505 * Returns: NULL if @token is not a generic type or method definition or the new generic container.
6506 *
6507 * LOCKING: Acquires the loader lock
6508 *
6509 */
6510 MonoGenericContainer *
mono_metadata_load_generic_params(MonoImage * image,guint32 token,MonoGenericContainer * parent_container)6511 mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericContainer *parent_container)
6512 {
6513 MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
6514 guint32 cols [MONO_GENERICPARAM_SIZE];
6515 guint32 i, owner = 0, n;
6516 MonoGenericContainer *container;
6517 MonoGenericParamFull *params;
6518 MonoGenericContext *context;
6519
6520 if (!(i = mono_metadata_get_generic_param_row (image, token, &owner)))
6521 return NULL;
6522 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
6523 params = NULL;
6524 n = 0;
6525 container = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
6526 container->owner.image = image; // Temporarily mark as anonymous, but this will be overriden by caller
6527 container->is_anonymous = TRUE;
6528 do {
6529 n++;
6530 params = (MonoGenericParamFull *)g_realloc (params, sizeof (MonoGenericParamFull) * n);
6531 memset (¶ms [n - 1], 0, sizeof (MonoGenericParamFull));
6532 params [n - 1].param.owner = container;
6533 params [n - 1].param.num = cols [MONO_GENERICPARAM_NUMBER];
6534 params [n - 1].info.token = i | MONO_TOKEN_GENERIC_PARAM;
6535 params [n - 1].info.flags = cols [MONO_GENERICPARAM_FLAGS];
6536 params [n - 1].info.name = mono_metadata_string_heap (image, cols [MONO_GENERICPARAM_NAME]);
6537 if (params [n - 1].param.num != n - 1)
6538 g_warning ("GenericParam table unsorted or hole in generic param sequence: token %d", i);
6539 if (++i > tdef->rows)
6540 break;
6541 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
6542 } while (cols [MONO_GENERICPARAM_OWNER] == owner);
6543
6544 container->type_argc = n;
6545 container->type_params = (MonoGenericParamFull *)mono_image_alloc0 (image, sizeof (MonoGenericParamFull) * n);
6546 memcpy (container->type_params, params, sizeof (MonoGenericParamFull) * n);
6547 g_free (params);
6548 container->parent = parent_container;
6549
6550 if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
6551 container->is_method = 1;
6552
6553 g_assert (container->parent == NULL || container->is_method);
6554
6555 context = &container->context;
6556 if (container->is_method) {
6557 context->class_inst = container->parent ? container->parent->context.class_inst : NULL;
6558 context->method_inst = mono_get_shared_generic_inst (container);
6559 } else {
6560 context->class_inst = mono_get_shared_generic_inst (container);
6561 }
6562
6563 return container;
6564 }
6565
6566 MonoGenericInst *
mono_get_shared_generic_inst(MonoGenericContainer * container)6567 mono_get_shared_generic_inst (MonoGenericContainer *container)
6568 {
6569 MonoType **type_argv;
6570 MonoType *helper;
6571 MonoGenericInst *nginst;
6572 int i;
6573
6574 type_argv = g_new0 (MonoType *, container->type_argc);
6575 helper = g_new0 (MonoType, container->type_argc);
6576
6577 for (i = 0; i < container->type_argc; i++) {
6578 MonoType *t = &helper [i];
6579
6580 t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
6581 t->data.generic_param = mono_generic_container_get_param (container, i);
6582
6583 type_argv [i] = t;
6584 }
6585
6586 nginst = mono_metadata_get_generic_inst (container->type_argc, type_argv);
6587
6588 g_free (type_argv);
6589 g_free (helper);
6590
6591 return nginst;
6592 }
6593
6594 /**
6595 * mono_type_is_byref:
6596 * \param type the \c MonoType operated on
6597 * \returns TRUE if \p type represents a type passed by reference,
6598 * FALSE otherwise.
6599 */
6600 gboolean
mono_type_is_byref(MonoType * type)6601 mono_type_is_byref (MonoType *type)
6602 {
6603 return type->byref;
6604 }
6605
6606 /**
6607 * mono_type_get_type:
6608 * \param type the \c MonoType operated on
6609 * \returns the IL type value for \p type. This is one of the \c MonoTypeEnum
6610 * enum members like \c MONO_TYPE_I4 or \c MONO_TYPE_STRING.
6611 */
6612 int
mono_type_get_type(MonoType * type)6613 mono_type_get_type (MonoType *type)
6614 {
6615 return type->type;
6616 }
6617
6618 /**
6619 * mono_type_get_signature:
6620 * \param type the \c MonoType operated on
6621 * It is only valid to call this function if \p type is a \c MONO_TYPE_FNPTR .
6622 * \returns the \c MonoMethodSignature pointer that describes the signature
6623 * of the function pointer \p type represents.
6624 */
6625 MonoMethodSignature*
mono_type_get_signature(MonoType * type)6626 mono_type_get_signature (MonoType *type)
6627 {
6628 g_assert (type->type == MONO_TYPE_FNPTR);
6629 return type->data.method;
6630 }
6631
6632 /**
6633 * mono_type_get_class:
6634 * \param type the \c MonoType operated on
6635 * It is only valid to call this function if \p type is a \c MONO_TYPE_CLASS or a
6636 * \c MONO_TYPE_VALUETYPE . For more general functionality, use \c mono_class_from_mono_type,
6637 * instead.
6638 * \returns the \c MonoClass pointer that describes the class that \p type represents.
6639 */
6640 MonoClass*
mono_type_get_class(MonoType * type)6641 mono_type_get_class (MonoType *type)
6642 {
6643 /* FIXME: review the runtime users before adding the assert here */
6644 return type->data.klass;
6645 }
6646
6647 /**
6648 * mono_type_get_array_type:
6649 * \param type the \c MonoType operated on
6650 * It is only valid to call this function if \p type is a \c MONO_TYPE_ARRAY .
6651 * \returns a \c MonoArrayType struct describing the array type that \p type
6652 * represents. The info includes details such as rank, array element type
6653 * and the sizes and bounds of multidimensional arrays.
6654 */
6655 MonoArrayType*
mono_type_get_array_type(MonoType * type)6656 mono_type_get_array_type (MonoType *type)
6657 {
6658 return type->data.array;
6659 }
6660
6661 /**
6662 * mono_type_get_ptr_type:
6663 * \pararm type the \c MonoType operated on
6664 * It is only valid to call this function if \p type is a \c MONO_TYPE_PTR .
6665 * \returns the \c MonoType pointer that describes the type that \p type
6666 * represents a pointer to.
6667 */
6668 MonoType*
mono_type_get_ptr_type(MonoType * type)6669 mono_type_get_ptr_type (MonoType *type)
6670 {
6671 g_assert (type->type == MONO_TYPE_PTR);
6672 return type->data.type;
6673 }
6674
6675 /**
6676 * mono_type_get_modifiers:
6677 */
6678 MonoClass*
mono_type_get_modifiers(MonoType * type,gboolean * is_required,gpointer * iter)6679 mono_type_get_modifiers (MonoType *type, gboolean *is_required, gpointer *iter)
6680 {
6681 /* FIXME: implement */
6682 return NULL;
6683 }
6684
6685 /**
6686 * mono_type_is_struct:
6687 * \param type the \c MonoType operated on
6688 * \returns TRUE if \p type is a struct, that is a \c ValueType but not an enum
6689 * or a basic type like \c System.Int32 . FALSE otherwise.
6690 */
6691 mono_bool
mono_type_is_struct(MonoType * type)6692 mono_type_is_struct (MonoType *type)
6693 {
6694 return (!type->byref && ((type->type == MONO_TYPE_VALUETYPE &&
6695 !type->data.klass->enumtype) || (type->type == MONO_TYPE_TYPEDBYREF) ||
6696 ((type->type == MONO_TYPE_GENERICINST) &&
6697 mono_metadata_generic_class_is_valuetype (type->data.generic_class) &&
6698 !type->data.generic_class->container_class->enumtype)));
6699 }
6700
6701 /**
6702 * mono_type_is_void:
6703 * \param type the \c MonoType operated on
6704 * \returns TRUE if \p type is \c System.Void . FALSE otherwise.
6705 */
6706 mono_bool
mono_type_is_void(MonoType * type)6707 mono_type_is_void (MonoType *type)
6708 {
6709 return (type && (type->type == MONO_TYPE_VOID) && !type->byref);
6710 }
6711
6712 /**
6713 * mono_type_is_pointer:
6714 * \param type the \c MonoType operated on
6715 * \returns TRUE if \p type is a managed or unmanaged pointer type. FALSE otherwise.
6716 */
6717 mono_bool
mono_type_is_pointer(MonoType * type)6718 mono_type_is_pointer (MonoType *type)
6719 {
6720 return (type && ((type->byref || (type->type == MONO_TYPE_I) || type->type == MONO_TYPE_STRING)
6721 || (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
6722 (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_OBJECT) ||
6723 (type->type == MONO_TYPE_ARRAY) || (type->type == MONO_TYPE_PTR) ||
6724 (type->type == MONO_TYPE_FNPTR)));
6725 }
6726
6727 /**
6728 * mono_type_is_reference:
6729 * \param type the \c MonoType operated on
6730 * \returns TRUE if \p type represents an object reference. FALSE otherwise.
6731 */
6732 mono_bool
mono_type_is_reference(MonoType * type)6733 mono_type_is_reference (MonoType *type)
6734 {
6735 return (type && (((type->type == MONO_TYPE_STRING) ||
6736 (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
6737 (type->type == MONO_TYPE_OBJECT) || (type->type == MONO_TYPE_ARRAY)) ||
6738 ((type->type == MONO_TYPE_GENERICINST) &&
6739 !mono_metadata_generic_class_is_valuetype (type->data.generic_class))));
6740 }
6741
6742 mono_bool
mono_type_is_generic_parameter(MonoType * type)6743 mono_type_is_generic_parameter (MonoType *type)
6744 {
6745 return !type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR);
6746 }
6747
6748 /**
6749 * mono_signature_get_return_type:
6750 * \param sig the method signature inspected
6751 * \returns the return type of the method signature \p sig
6752 */
6753 MonoType*
mono_signature_get_return_type(MonoMethodSignature * sig)6754 mono_signature_get_return_type (MonoMethodSignature *sig)
6755 {
6756 return sig->ret;
6757 }
6758
6759 /**
6760 * mono_signature_get_params:
6761 * \param sig the method signature inspected
6762 * \param iter pointer to an iterator
6763 * Iterates over the parameters for the method signature \p sig.
6764 * A \c void* pointer must be initialized to NULL to start the iteration
6765 * and its address is passed to this function repeteadly until it returns
6766 * NULL.
6767 * \returns the next parameter type of the method signature \p sig,
6768 * NULL when finished.
6769 */
6770 MonoType*
mono_signature_get_params(MonoMethodSignature * sig,gpointer * iter)6771 mono_signature_get_params (MonoMethodSignature *sig, gpointer *iter)
6772 {
6773 MonoType** type;
6774 if (!iter)
6775 return NULL;
6776 if (!*iter) {
6777 /* start from the first */
6778 if (sig->param_count) {
6779 *iter = &sig->params [0];
6780 return sig->params [0];
6781 } else {
6782 /* no method */
6783 return NULL;
6784 }
6785 }
6786 type = (MonoType **)*iter;
6787 type++;
6788 if (type < &sig->params [sig->param_count]) {
6789 *iter = type;
6790 return *type;
6791 }
6792 return NULL;
6793 }
6794
6795 /**
6796 * mono_signature_get_param_count:
6797 * \param sig the method signature inspected
6798 * \returns the number of parameters in the method signature \p sig.
6799 */
6800 guint32
mono_signature_get_param_count(MonoMethodSignature * sig)6801 mono_signature_get_param_count (MonoMethodSignature *sig)
6802 {
6803 return sig->param_count;
6804 }
6805
6806 /**
6807 * mono_signature_get_call_conv:
6808 * \param sig the method signature inspected
6809 * \returns the call convention of the method signature \p sig.
6810 */
6811 guint32
mono_signature_get_call_conv(MonoMethodSignature * sig)6812 mono_signature_get_call_conv (MonoMethodSignature *sig)
6813 {
6814 return sig->call_convention;
6815 }
6816
6817 /**
6818 * mono_signature_vararg_start:
6819 * \param sig the method signature inspected
6820 * \returns the number of the first vararg parameter in the
6821 * method signature \param sig. \c -1 if this is not a vararg signature.
6822 */
6823 int
mono_signature_vararg_start(MonoMethodSignature * sig)6824 mono_signature_vararg_start (MonoMethodSignature *sig)
6825 {
6826 return sig->sentinelpos;
6827 }
6828
6829 /**
6830 * mono_signature_is_instance:
6831 * \param sig the method signature inspected
6832 * \returns TRUE if this the method signature \p sig has an implicit
6833 * first instance argument. FALSE otherwise.
6834 */
6835 gboolean
mono_signature_is_instance(MonoMethodSignature * sig)6836 mono_signature_is_instance (MonoMethodSignature *sig)
6837 {
6838 return sig->hasthis;
6839 }
6840
6841 /**
6842 * mono_signature_param_is_out
6843 * \param sig the method signature inspected
6844 * \param param_num the 0-based index of the inspected parameter
6845 * \returns TRUE if the parameter is an out parameter, FALSE
6846 * otherwise.
6847 */
6848 mono_bool
mono_signature_param_is_out(MonoMethodSignature * sig,int param_num)6849 mono_signature_param_is_out (MonoMethodSignature *sig, int param_num)
6850 {
6851 g_assert (param_num >= 0 && param_num < sig->param_count);
6852 return (sig->params [param_num]->attrs & PARAM_ATTRIBUTE_OUT) != 0;
6853 }
6854
6855 /**
6856 * mono_signature_explicit_this:
6857 * \param sig the method signature inspected
6858 * \returns TRUE if this the method signature \p sig has an explicit
6859 * instance argument. FALSE otherwise.
6860 */
6861 gboolean
mono_signature_explicit_this(MonoMethodSignature * sig)6862 mono_signature_explicit_this (MonoMethodSignature *sig)
6863 {
6864 return sig->explicit_this;
6865 }
6866
6867 /* for use with allocated memory blocks (assumes alignment is to 8 bytes) */
6868 guint
mono_aligned_addr_hash(gconstpointer ptr)6869 mono_aligned_addr_hash (gconstpointer ptr)
6870 {
6871 /* Same hashing we use for objects */
6872 return (GPOINTER_TO_UINT (ptr) >> 3) * 2654435761u;
6873 }
6874
6875 /*
6876 * If @field belongs to an inflated generic class, return the corresponding field of the
6877 * generic type definition class.
6878 */
6879 MonoClassField*
mono_metadata_get_corresponding_field_from_generic_type_definition(MonoClassField * field)6880 mono_metadata_get_corresponding_field_from_generic_type_definition (MonoClassField *field)
6881 {
6882 MonoClass *gtd;
6883 int offset;
6884
6885 if (!mono_class_is_ginst (field->parent))
6886 return field;
6887
6888 gtd = mono_class_get_generic_class (field->parent)->container_class;
6889 offset = field - field->parent->fields;
6890 return gtd->fields + offset;
6891 }
6892
6893 /*
6894 * If @event belongs to an inflated generic class, return the corresponding event of the
6895 * generic type definition class.
6896 */
6897 MonoEvent*
mono_metadata_get_corresponding_event_from_generic_type_definition(MonoEvent * event)6898 mono_metadata_get_corresponding_event_from_generic_type_definition (MonoEvent *event)
6899 {
6900 MonoClass *gtd;
6901 int offset;
6902
6903 if (!mono_class_is_ginst (event->parent))
6904 return event;
6905
6906 gtd = mono_class_get_generic_class (event->parent)->container_class;
6907 offset = event - mono_class_get_event_info (event->parent)->events;
6908 return mono_class_get_event_info (gtd)->events + offset;
6909 }
6910
6911 /*
6912 * If @property belongs to an inflated generic class, return the corresponding property of the
6913 * generic type definition class.
6914 */
6915 MonoProperty*
mono_metadata_get_corresponding_property_from_generic_type_definition(MonoProperty * property)6916 mono_metadata_get_corresponding_property_from_generic_type_definition (MonoProperty *property)
6917 {
6918 MonoClassPropertyInfo *info;
6919 MonoClass *gtd;
6920 int offset;
6921
6922 if (!mono_class_is_ginst (property->parent))
6923 return property;
6924
6925 info = mono_class_get_property_info (property->parent);
6926 gtd = mono_class_get_generic_class (property->parent)->container_class;
6927 offset = property - info->properties;
6928 return mono_class_get_property_info (gtd)->properties + offset;
6929 }
6930
6931 MonoWrapperCaches*
mono_method_get_wrapper_cache(MonoMethod * method)6932 mono_method_get_wrapper_cache (MonoMethod *method)
6933 {
6934 if (method->is_inflated) {
6935 MonoMethodInflated *imethod = (MonoMethodInflated *)method;
6936 return &imethod->owner->wrapper_caches;
6937 } else {
6938 return &method->klass->image->wrapper_caches;
6939 }
6940 }
6941
6942 // 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.
6943
6944 /**
6945 * mono_find_image_set_owner:
6946 *
6947 * Find the imageset, if any, which a given pointer is located in the memory of.
6948 */
6949 MonoImageSet *
mono_find_image_set_owner(void * ptr)6950 mono_find_image_set_owner (void *ptr)
6951 {
6952 MonoImageSet *owner = NULL;
6953 int i;
6954
6955 image_sets_lock ();
6956
6957 if (image_sets)
6958 {
6959 for (i = 0; !owner && i < image_sets->len; ++i) {
6960 MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i);
6961 if (mono_mempool_contains_addr (set->mempool, ptr))
6962 owner = set;
6963 }
6964 }
6965
6966 image_sets_unlock ();
6967
6968 return owner;
6969 }
6970
6971 void
mono_loader_set_strict_strong_names(gboolean enabled)6972 mono_loader_set_strict_strong_names (gboolean enabled)
6973 {
6974 check_strong_names_strictly = enabled;
6975 }
6976
6977 gboolean
mono_loader_get_strict_strong_names(void)6978 mono_loader_get_strict_strong_names (void)
6979 {
6980 return check_strong_names_strictly;
6981 }
6982